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.
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:
Misschien is een 64-bits structuur voor deze tijden geschikter, het is een vertraging om de 8086 te blijven gebruiken.
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
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
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!
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.