С возвращением в серию статей, озаглавленную «Подражая Линусу Торвальдсу». Сегодня мы увидим 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;
}
Таким образом, мы можем построить указатель, который переходит в нашу таблицу с тремя входами.
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 теперь выглядит так:
Возможно, для этого времени больше подходит 64-битная структура, это отставание от продолжения использования 8086.
Я искал информацию о GDT в x86_64, и я думаю, что он следует старой модели со специальным флагом. По-прежнему используется 32-битный адрес. Сейчас не знаю, как правильно это делать. Некоторые ссылки:
http://wiki.osdev.org/Entering_Long_Mode_Directly
http://f.osdev.org/viewtopic.php?f=1&t=16275
Прежде всего, ваш вклад очень хорош, но я думаю, что название должно быть
"Подражая Ричарду Столмену" или, по крайней мере, я так думаю ,,,
привет
Линус создал ядро Linux, Столлман создал GNU, которые представляют собой инструменты и команды Unix.
Название подходящее, потому что вы создаете ядро.
Приветик!
Большое спасибо за ответы на все мои вопросы и проявленное терпение, я знаю только основы как ассемблер и почти ничего не знаю о C, но мне это очень нравится, теперь я немного запутался с GDT, давайте посмотрим, смогу ли я понять.
GDT будет иметь глобальные «дескрипторы», к которым всегда может получить доступ любая программа, и эти дескрипторы указывают на разделы, в которых (программа) будет выполняться? или иначе.