Емуляція Лінуса Торвальда: Створіть власну операційну систему з нуля (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));

Можливо, ви помітили цікавий __атрибут __ ((упакований)) в кінці структур. Це говорить 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 входами.

Якщо ви скомпілюєте, використовуючи 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, перезаписати 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 тепер виглядає так:

NextDivel-GDT


Залиште свій коментар

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

*

*

  1. Відповідальний за дані: Мігель Анхель Гатон
  2. Призначення даних: Контроль спаму, управління коментарями.
  3. Легітимація: Ваша згода
  4. Передача даних: Дані не передаватимуться третім особам, за винятком юридичних зобов’язань.
  5. Зберігання даних: База даних, розміщена в мережі Occentus Networks (ЄС)
  6. Права: Ви можете будь-коли обмежити, відновити та видалити свою інформацію.

  1.   Саерон - сказав він

    Можливо, для цих часів більше підходить 64-розрядна структура, це відставання для продовження використання 8086.

    1.    AdrianArroyoStreet - сказав він

      Я шукав інформацію про GDT у x86_64, і думаю, що вона відповідає старій моделі зі спеціальним прапором. 32-розрядна адреса все ще використовується. Зараз я точно не знаю, як це правильно зробити. Деякі посилання:
      http://wiki.osdev.org/Entering_Long_Mode_Directly
      http://f.osdev.org/viewtopic.php?f=1&t=16275

  2.   геронімо - сказав він

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

    1.    abimaelmartell - сказав він

      Лінус створив ядро ​​Linux, Столлман створив GNU, що є інструментами та командами Unix.

      Назва відповідна, тому що ви створюєте ядро.

      Привіт!

  3.   рубін - сказав він

    Щиро дякую за відповіді на всі мої запитання та терпіння, я знаю лише основи як асемблер і майже нічого не знаю про C, але мені це дуже подобається, зараз я трохи переплутався з GDT, давайте подивимось, чи я зрозуміти.

    У GDT будуть глобальні «дескриптори», до яких завжди може отримати доступ будь-яка програма, і ці дескриптори вказують на розділи, де (програма) буде виконана? або це інакше.