Ugledanje na Linusa Torvaldsa: Stvorite svoj vlastiti operativni sistem od nule (IV)

Dobrodošli nazad u ovu seriju postova pod nazivom “Emulating Linus Torvalds”. Danas ćemo vidjeti GDT. Prvo moramo vidjeti šta je GDT. Prema Wikipediji:

The Globalna tablica deskriptora or GDT je struktura podataka koju koristi Intel X86-porodica procesora počevši od 80286 kako bi se definirale karakteristike različitih memorijskih područja koja se koriste tokom izvršavanja programa, uključujući osnovnu adresu, veličinu i privilegije pristupa kao što su izvršnost i mogućnost pisanja

Što bi prevedeno bila tabela globalnih deskriptora, struktura podataka koja se koristi u Intel x86 procesorima od 80286 za definisanje karakteristika različitih memorijskih oblasti koje se koriste tokom izvršavanja programa.

Ukratko, ako smo na Intel x86 procesoru, moramo definirati GDT za ispravnu upotrebu memorije. Nećemo to previše komplicirati i definirat ćemo 3 unosa u tabeli:

  • NULL unos, potreban za sve tabele.
  • Unos za sekciju podaci, koristićemo maksimum, koji u 32 bita iznosi 4 GB.
  • Unos za sekciju kod, koristićemo maksimum, koji u 32 bita iznosi 4 GB.

Kao što vidite, podaci i kod će koristiti isti prostor. U redu, hajde da to implementiramo. Za ovo ćemo koristiti dvije strukture, prva će biti odgovorna za sadržavanje pokazivača na stvarne podatke našeg GDT-a. A drugi će biti niz sa GDT unosima. Prvo hajde da ih definišemo

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));

Primijetit ćete znatiželjan __attribute__((packed)) na kraju struktura. Ovo govori GCC-u da ne optimizira strukture jer ono što želimo je da proslijeđujemo podatke kao što jesu procesoru. Sada ćemo napraviti funkciju za instalaciju GDT-a. Prije smo trebali deklarirati strukture, sada ćemo ih inicijalizirati.

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;
}

Ovako uspevamo da izgradimo pokazivač koji ide na našu tabelu sa 3 unosa.

Ako kompajlirate koristeći 64-bitnu, ovdje će najvjerovatnije propasti. To je zato što su pokazivači na 64-bitnim sistemima očigledno 64-bitni i ovdje koristimo 32-bitne tipove. Korištenje -m32 opcije za sada može pomoći.
Sada definiramo uobičajenu funkciju za stavljanje podataka u ulaze

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;
}

I zovemo ga 3 puta iz install funkcije

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 */

Na kraju moramo reći procesoru da imamo GDT, tako da ga učita, au našem slučaju kada učitavamo kernel sa GRUB-om, prepišemo GDT od GRUB-a. Za učitavanje GDT-a postoji instrukcija u asm-u koja se zove lgdt (ili lgdtl ovisno o sintaksi), upotrijebimo je.

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"
);

Pa, kada ovo završimo, naš sistem će već imati GDT. U sljedećem poglavlju ćemo vidjeti IDT, tabelu vrlo sličnu GDT-u, ali sa prekidima. Stavio sam neke statusne i potvrdne poruke sa GDT-om tako da NextDivel sada izgleda ovako:

NextDivel-GDT


Ostavite komentar

Vaša e-mail adresa neće biti objavljena. Obavezna polja su označena sa *

*

*

  1. Za podatke odgovoran: Miguel Ángel Gatón
  2. Svrha podataka: Kontrola neželjene pošte, upravljanje komentarima.
  3. Legitimacija: Vaš pristanak
  4. Komunikacija podataka: Podaci se neće dostavljati trećim stranama, osim po zakonskoj obavezi.
  5. Pohrana podataka: Baza podataka koju hostuje Occentus Networks (EU)
  6. Prava: U bilo kojem trenutku možete ograničiti, oporaviti i izbrisati svoje podatke.

  1.   saeron rekao je

    Možda je 64-bitna struktura prikladnija za trenutna vremena, kašnjenje je za nastavak korištenja 8086.

    1.    AdrianArroyoStreet rekao je

      Tražio sam informacije o GDT-u na x86_64 i mislim da prati stari model sa posebnom zastavicom. I dalje se koristi 32-bitna adresa. Sada ne znam tačno kako da to uradim ispravno. Neki linkovi:
      http://wiki.osdev.org/Entering_Long_Mode_Directly
      http://f.osdev.org/viewtopic.php?f=1&t=16275

  2.   geronimo rekao je

    Prije svega, vaši doprinosi su jako dobri, ali mislim da bi naslov trebao biti
    "imitirajući Richarda Stallmana" ili barem ja tako mislim,,,
    Saludos

    1.    abimaelmartell rekao je

      Linus je kreirao Linux kernel, Stallman je kreirao GNU, koji su Unix alati i komande.

      Naslov je prikladan jer stvaraju jezgro.

      Hvala!

  3.   Rubin rekao je

    Hvala vam puno na odgovorima na sva moja pitanja i strpljenju sa mnom, znam samo osnove asemblera i skoro nista o C, ali mi se mnogo dopada, sad sam malo zbunjen sa GDT-om, da vidimo da li razumeti.

    Hoće li GDT imati globalne 'deskriptore' kojima uvijek može pristupiti bilo koji program, a ovi deskriptori upućuju na dijelove u kojima će se (program) izvršiti? ili je to drugi način.