Ласкаво просимо до цієї серії публікацій під назвою "Емуляція Лінуса Торвальда". Сьогодні ми побачимо 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));
Можливо, ви помітили цікавий __атрибут __ ((упакований)) в кінці структур. Це говорить 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;
}
Отже, ми можемо побудувати покажчик, який переходить до нашої таблиці з 3 входами.
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, перезаписати GUB GDT GRUB. Для завантаження 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 будуть глобальні «дескриптори», до яких завжди може отримати доступ будь-яка програма, і ці дескриптори вказують на розділи, де (програма) буде виконана? або це інакше.