Linus Torvalds emuleren: maak uw eigen besturingssysteem vanaf nul (IV)

Welkom terug bij deze reeks berichten met de titel "Linus Torvalds emuleren". Vandaag zullen we de GDT zien. Eerst moeten we zien wat de GDT is. Volgens Wikipedia:

De Globale descriptortabel or GDT is een gegevensstructuur die wordt gebruikt door Intel x86-familieprocessors die beginnen met de 80286 om de kenmerken te definiëren van de verschillende geheugengebieden die worden gebruikt tijdens de uitvoering van het programma, inclusief het basisadres, de grootte en toegangsrechten zoals uitvoerbaarheid en schrijfbaarheid

Wat zou worden vertaald, zou een Global Descriptor Table zijn, een gegevensstructuur die sinds 86 in Intel x80286-processors wordt gebruikt om de kenmerken te definiëren van verschillende geheugengebieden die worden gebruikt tijdens de uitvoering van het programma.

Samenvattend, als we een Intel x86-processor gebruiken, moeten we een GDT definiëren voor correct geheugengebruik. We gaan niet veel complicaties doen en we gaan 3 items in de tabel definiëren:

  • Een NULL-invoer, vereist voor alle tabellen.
  • Een kaartje voor de sectie gegevens, zullen we het maximum gebruiken, dat in 32 bits 4 GB is.
  • Een kaartje voor de sectie code, zullen we het maximum gebruiken, dat in 32 bits 4 GB is.

Zoals u kunt zien, gebruiken gegevens en code dezelfde ruimte. Ok, nu gaan we het implementeren. Hiervoor zullen we twee structuren gebruiken, de eerste zal verantwoordelijk zijn voor het bevatten van een verwijzing naar de echte gegevens van onze GDT. En de tweede is een array met de GDT-vermeldingen. Laten we ze eerst definiëren

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

Je hebt misschien een merkwaardig __attribuut __ ((verpakt)) opgemerkt aan het einde van de structuren. Dit vertelt de GCC om de structuren niet te optimaliseren, omdat we willen dat de gegevens ongewijzigd aan de processor worden doorgegeven. Nu gaan we een functie maken om de GDT te installeren. Voordat we de structuren hadden moeten declareren, gaan we ze nu initialiseren.

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

Zo kunnen we de aanwijzer bouwen die naar onze 3-invoertabel gaat.

Als je compileert met 64 bits, zal het hier waarschijnlijk niet lukken. Dit komt omdat verwijzingen op 64-bits systemen duidelijk 64-bits zijn en we hier 32-bits typen gebruiken. Het gebruik van de optie -m32 kan voorlopig helpen
Nu definiëren we een algemene functie om de gegevens in de invoer te plaatsen

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

En we noemen het 3 keer vanuit de installatiefunctie

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

Ten slotte moeten we de processor vertellen dat we een GDT hebben, zodat deze het kan laden, en in ons geval, wanneer de kernel met GRUB wordt geladen, de GRUB GDT overschrijven. Om de GDT te laden is er een instructie in asm genaamd lgdt (of lgdtl afhankelijk van de syntaxis), we gaan deze gebruiken.

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

Als we dit eenmaal hebben voltooid, heeft ons systeem al GDT. In het volgende hoofdstuk zullen we de IDT zien, een tabel die erg lijkt op de GDT maar met onderbrekingen. Ik heb enkele status- en bevestigingsberichten bij de GDT geplaatst, dus NextDivel ziet er nu als volgt uit:

VolgendeDivel-GDT


Laat je reactie achter

Uw e-mailadres wordt niet gepubliceerd. Verplichte velden zijn gemarkeerd met *

*

*

  1. Verantwoordelijk voor de gegevens: Miguel Ángel Gatón
  2. Doel van de gegevens: Controle SPAM, commentaarbeheer.
  3. Legitimatie: uw toestemming
  4. Mededeling van de gegevens: De gegevens worden niet aan derden meegedeeld, behalve op grond van wettelijke verplichting.
  5. Gegevensopslag: database gehost door Occentus Networks (EU)
  6. Rechten: u kunt uw gegevens op elk moment beperken, herstellen en verwijderen.

  1.   Saëron zei

    Misschien is een 64-bits structuur voor deze tijden geschikter, het is een vertraging om de 8086 te blijven gebruiken.

    1.    AdrianArroyoStreet zei

      Ik ben op zoek geweest naar informatie over GDT in x86_64 en ik denk dat het het oude model volgt met een speciale vlag. Een 32-bits adres wordt nog steeds gebruikt. Nu weet ik niet precies hoe ik het correct moet doen. Enkele links:
      http://wiki.osdev.org/Entering_Long_Mode_Directly
      http://f.osdev.org/viewtopic.php?f=1&t=16275

  2.   geronimo zei

    Allereerst zijn uw bijdragen erg goed, maar ik denk dat de titel dat zou moeten zijn
    "Emuleren Richard Stallman" of dat denk ik tenminste ,,,
    groeten

    1.    abimaelmartell zei

      Linus heeft de Linux-kernel gemaakt, Stallman heeft GNU gemaakt, de Unix-tools en -opdrachten.

      De titel is geschikt omdat je een kern creëert.

      Groeten!

  3.   Ruby zei

    Heel erg bedankt voor het beantwoorden van al mijn vragen en geduld, als assembler ken ik alleen de basis en als C bijna niets, maar ik vind het echt leuk, nu ben ik een beetje in de war met de GDT, laten we eens kijken of ik het begrijp.

    De GDT zal de globale 'descriptors' hebben die altijd toegankelijk zijn voor elk programma, en deze descriptors verwijzen naar de secties waar (het programma) zal worden uitgevoerd? of het is anders.