Эмуляция Линуса Торвальдса: создайте свою собственную операционную систему с нуля (IV)

С возвращением в серию статей, озаглавленную «Подражая Линусу Торвальдсу». Сегодня мы увидим GDT. Сначала мы должны увидеть, что такое GDT. Согласно Википедии:

Ассоциация Глобальная таблица дескрипторов or GDT это структура данных, используемая Intel x86-семейные процессоры, начиная с 80286 для определения характеристик различных областей памяти, используемых во время выполнения программы, включая базовый адрес, размер и права доступа, такие как исполняемость и возможность записи

То, что было переведено, будет глобальной таблицей дескрипторов, структурой данных, используемой в процессорах Intel x86 с 80286 для определения характеристик различных областей памяти, используемых во время выполнения программы.

Короче говоря, если мы используем процессор Intel x86, мы должны определить GDT для правильного использования памяти. Мы не собираемся сильно усложнять, и мы собираемся определить 3 записи в таблице:

  • Запись NULL, необходимая для всех таблиц.
  • Билет в секцию данным, мы будем использовать максимум, который в 32 битах составляет 4 ГБ.
  • Билет в секцию код, мы будем использовать максимум, который в 32 битах составляет 4 ГБ.

Как видите, данные и код будут использовать одно и то же пространство. Хорошо, теперь мы его реализуем. Для этого мы будем использовать две структуры, первая будет отвечать за содержание указателя на реальные данные нашего GDT. А второй будет массивом с записями GDT. Давайте сначала определим их

struct Entry{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed));
struct Ptr{
uint16_t limit;
uint32_t base;
} __attribute__((packed));

Возможно, вы заметили любопытный __attribute __ ((pack)) в конце структур. Это говорит GCC не оптимизировать структуры, потому что мы хотим передавать данные процессору без изменений. Теперь мы собираемся выполнить функцию для установки GDT. Раньше мы должны были объявить структуры, теперь мы собираемся их инициализировать.

struct ND::GDT::Entry gdt[3];
struct ND::GDT::Ptr gp;
void ND::GDT::Install()
{
gp.limit=(sizeof(struct ND::GDT::Entry)*3)-1;
gp.base=(uint32_t)&gdt;
}

Таким образом, мы можем построить указатель, который переходит в нашу таблицу с тремя входами.

Если вы компилируете с использованием 64 бит, скорее всего, здесь произойдет сбой. Это связано с тем, что указатели в 64-битных системах, очевидно, являются 64-битными, и здесь мы используем 32-битные типы. На данный момент может помочь использование опции -m32
Теперь мы определяем общую функцию для ввода данных во входные данные.

void ND::GDT::SetGate(int num, uint32_t base, uint32_t limit, uint8_t access,uint8_t gran)
{
gdt[num].base_low=(base & 0xFFFF);
gdt[num].base_middle=(base >> 16) & 0xFF;
gdt[num].base_high=(base >> 24) & 0xFF;
gdt[num].limit_low=(limit & 0xFFFF);
gdt[num].granularity=(limit >> 16) & 0x0F;
gdt[num].granularity |= (gran & 0xF0);
gdt[num].access=access;
}

И вызываем его 3 раза из функции установки

ND::GDT::SetGate(0,0,0,0,0); /* NULL segmente entry */
ND::GDT::SetGate(1,0,0xFFFFFFFF,0x9A,0xCF); /* 4 GiB for Code Segment */
ND::GDT::SetGate(2,0,0xFFFFFFFF,0x92,0xCF); /* 4 GiB for Data segment */

Наконец, мы должны сообщить процессору, что у нас есть GDT, чтобы он мог его загрузить, и в нашем случае при загрузке ядра с помощью GRUB перезаписать GRUB GDT. Для загрузки GDT в asm есть инструкция lgdt (или lgdtl в зависимости от синтаксиса), мы собираемся ее использовать.

asm volatile("lgdtl (gp)");
asm volatile(
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movw %ax, %ss \n"
"ljmp $0x08, $next \n"
"next: \n"
);

Что ж, как только мы закончим с этим, в нашей системе уже будет GDT. В следующей главе мы увидим IDT, таблицу, очень похожую на GDT, но с прерываниями. Я поместил несколько сообщений о состоянии и подтверждения в GDT, поэтому NextDivel теперь выглядит так:

СледующийDivel-GDT


Оставьте свой комментарий

Ваш электронный адрес не будет опубликован. Обязательные для заполнения поля помечены *

*

*

  1. Ответственный за данные: Мигель Анхель Гатон
  2. Назначение данных: контроль спама, управление комментариями.
  3. Легитимация: ваше согласие
  4. Передача данных: данные не будут переданы третьим лицам, кроме как по закону.
  5. Хранение данных: база данных, размещенная в Occentus Networks (ЕС)
  6. Права: в любое время вы можете ограничить, восстановить и удалить свою информацию.

  1.   Саэрон сказал

    Возможно, для этого времени больше подходит 64-битная структура, это отставание от продолжения использования 8086.

    1.    АдрианАрройоУлица сказал

      Я искал информацию о GDT в x86_64, и я думаю, что он следует старой модели со специальным флагом. По-прежнему используется 32-битный адрес. Сейчас не знаю, как правильно это делать. Некоторые ссылки:
      http://wiki.osdev.org/Entering_Long_Mode_Directly
      http://f.osdev.org/viewtopic.php?f=1&t=16275

  2.   Geronimo сказал

    Прежде всего, ваш вклад очень хорош, но я думаю, что название должно быть
    "Подражая Ричарду Столмену" или, по крайней мере, я так думаю ,,,
    привет

    1.    Abimaelmartell сказал

      Линус создал ядро ​​Linux, Столлман создал GNU, которые представляют собой инструменты и команды Unix.

      Название подходящее, потому что вы создаете ядро.

      Приветик!

  3.   Ruby сказал

    Большое спасибо за ответы на все мои вопросы и проявленное терпение, я знаю только основы как ассемблер и почти ничего не знаю о C, но мне это очень нравится, теперь я немного запутался с GDT, давайте посмотрим, смогу ли я понять.

    GDT будет иметь глобальные «дескрипторы», к которым всегда может получить доступ любая программа, и эти дескрипторы указывают на разделы, в которых (программа) будет выполняться? или иначе.