Autor Thema: Global Descriptor Table (GDT)  (Gelesen 9361 mal)

nnosdev

  • Beiträge: 61
    • Profil anzeigen
Gespeichert
« am: 23. March 2012, 15:16 »
Hallo Leute!

Ich hab da ein Problem mit der GDT.

static void Gdt_SetEntry(uint32 index, uint32 base, uint32 limit, uint8 access,
uint8 gran) {
gdt.entry[index].base_low = (base & 0xFFFF);
gdt.entry[index].base_middle = (base >> 16) & 0xFF;
gdt.entry[index].base_high = (base >> 24) & 0xFF;

gdt.entry[index].limit_low = (limit & 0xFFFF);
gdt.entry[index].granularity = (limit >> 16) & 0x0F;

gdt.entry[index].granularity |= gran & 0xF0;
gdt.entry[index].access = access;
}

static void Gdt_InstallEntries() {
gdt_ptr.limit = (sizeof(gdt_entry) * GDT_ENTRIES) - 1;
gdt_ptr.base = (int) &gdt.entry[0];

Gdt_SetEntry(0, 0, 0, 0, 0);
Gdt_SetEntry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
Gdt_SetEntry(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
Gdt_SetEntry(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
Gdt_SetEntry(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);

dprint("[GDT] sizeof gdt_entry %d Bytes", sizeof(gdt_entry));
dprint("[GDT] gdt_ptr.base 0x%X", gdt_ptr.base);
dprint("[GDT] gdt_ptr.limit 0x%X (GDT size %d Bytes)", gdt_ptr.limit, gdt_ptr.limit + 1);
dprint("[GDT] entry 1 0x%X", &gdt.entry[0]);
dprint("[GDT] entry 2 0x%X", &gdt.entry[1]);
dprint("[GDT] entry 3 0x%X", &gdt.entry[2]);
dprint("[GDT] entry 4 0x%X", &gdt.entry[3]);
dprint("[GDT] entry 5 0x%X", &gdt.entry[4]);

Gdt_Flush((uint32) &gdt_ptr);

dprint("[GDT] Returning from Gdt_Flush()");
}

global Gdt_Flush
Gdt_Flush:
mov eax, [esp+4] ; Get the pointer to the GDT, passed as parameter
lgdt [eax] ; Load new GDT Pointer

mov ax, 0x10 ; 0x10 is the offset in the GDT to out data segment
mov ds, ax ; Load all data segment selectors
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump
.flush:
ret


Output:
[GDT] Initializing GDT
[GDT] sizeof gdt_entry 8 Bytes
[GDT] gdt_ptr.base 0x102000
[GDT] gdt_ptr.limit 0x27 (GDT size 40 Bytes)
[GDT] entry 1 0x102000
[GDT] entry 2 0x102008
[GDT] entry 3 0x102010
[GDT] entry 4 0x102018
[GDT] entry 5 0x102020

Leider fehlt die letzte Zeile [GDT] Returning from Gdt_Flush(). Da dürfte
wohl etwas nicht funktioniert haben.

Da ich den Fehler nicht finden kann, wollte ich fragen ob jemand weiß was
ich falsch gemacht habe.

LG; nnosdev

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 23. March 2012, 16:42 »
Hallo,

wie hast du denn "gdt" definiert? Bist du sicher, dass die Elemente der "struct gdt.entry" auch im Speicher in der richtigen Reihenfolge und ohne Padding liegen (__attribute__((packed)))?

Gruß,
Svenska

nnosdev

  • Beiträge: 61
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 23. March 2012, 16:53 »
Hi Svenska,

ja ich hab darauf geachtet.
struct gdt_entry_struct {
uint16 limit_low;
uint16 base_low;
uint8 base_middle;
uint8 access;
uint8 granularity;
uint8 base_high;
}__attribute__ ((packed));
typedef struct gdt_entry_struct gdt_entry;


Aber mir kommt so vor, als ob das nicht ganz so mit der Tabelle übereinstimmt.
http://www.lowlevel.eu/wiki/Global_Descriptor_Table

Byte
6 Flags 0-3
6 Limit 16-19
7 Base 24-31

Für diesen Eintrag scheint man 32 Bit zu benötiegen jedoch sind
nur 2 Byte laut Tabelle dafür vorgesehen. Das kommt mir ein wenig Spanisch
vor.. ^^

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 23. March 2012, 17:15 »
Byte
6 Flags 0-3
6 Limit 16-19
7 Base 24-31

Für diesen Eintrag scheint man 32 Bit zu benötiegen jedoch sind
nur 2 Byte laut Tabelle dafür vorgesehen. Das kommt mir ein wenig Spanisch
vor.. ^^

Das ist anders gemeint. In das Byte 6 kommen die Bits 0-3 der Flags und die Bits 16 bis 19 des Limits. Macht zusammen 8 Bits. Ebenso kommen in Byte 7 die Bits 24 bis 31 der Base. Siehe auch die Grafik unter der Tabelle.

Hast du schon überprüft, ob eine Exception aufgetreten ist? Ich habe das gerade erst gestern in einem anderen Thread erklärt, falls du nicht weißt, wie das geht: http://forum.lowlevel.eu/index.php?topic=2999.msg34956#msg34956.
Dieser Text wird unter jedem Beitrag angezeigt.

nnosdev

  • Beiträge: 61
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 23. March 2012, 18:25 »
Danke für den Tipp!

Also ich hab in der qemu.log folgendes gefunden.

0: v=06 e=0000 i=0 cpl=0 IP=0008:00104094 pc=00104094 SP=0010:00103f8c EAX=00002029

Hat das einen Grund weshalb ich den  Eintrag mit "0: v= .." suchen soll?

Danach habe ich in der Dump-File die Adresse gesucht.
Aufgerufen hab ich objdump mit objdump --disassemble-all nnOS -M intel > nnOSdump


00104088 <gdt_ptr>:
...

An der Stelle an die der PC zeigt scheint sich mein GDT-Pointer zu befinden.
Interpretiere ich das richtig? Leider hilft mir das jetzt nicht viel.
Kann mir nur vorstellen, dass im PC nicht die Adresse der Base stehen sollte.

struct gdt_ptr_struct {
uint16 limit;
uint32 base;
} __attribute__ ((packed));

*EDIT:

Hab diesen Eintrag noch entdeckt in der Log

GDT=     000cb9ec 00000027

Also wenn 00000027 die Größe der Tabelle sein soll, dann ist das
ja schon mal nicht so schlecht.
Aber keine Ahnung wofür 000cb9ec steht.
Wenn das die Adresse der GDT sein soll, dann wirds wohl daran scheitern.
« Letzte Änderung: 23. March 2012, 18:28 von nnosdev »

nnosdev

  • Beiträge: 61
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 23. March 2012, 19:07 »
Okay,

ich hab im Grunde alles richtig gemacht.
Hab folgendes geändert:

Habe die Gdt_Flush()-Methode in ein eigenes File gelegt.
global _start
_start:

; ......

section .bss
resb 8192 ; 8kB stack
kernel_stack:

; Method for flushing the Global Descriptor Table
global Gdt_Flush
Gdt_Flush:
mov eax, [esp+4] ; Get the pointer to the GDT, passed as parameter
lgdt [eax] ; Load new GDT Pointer

mov ax, 0x10 ; 0x10 is the offset in the GDT to out data segment
mov ds, ax ; Load all data segment selectors
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump
.flush:
ret

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 23. March 2012, 21:51 »
Hat das einen Grund weshalb ich den  Eintrag mit "0: v= .." suchen soll?
Für alle Interrupts, die auftreten, werden Registerdumps in die Datei geschrieben und durchnummeriert. Der mit der "0" ist halt der erste Interrupt, der nach den SMM-Interrupts auftritt.

Zitat
An der Stelle an die der PC zeigt scheint sich mein GDT-Pointer zu befinden.
Interpretiere ich das richtig? Leider hilft mir das jetzt nicht viel.
Kann mir nur vorstellen, dass im PC nicht die Adresse der Base stehen sollte.
Das ist 12 Bytes hinter dem Anfang von gdt_ptr. Es könnte also schon der richtige Wert sein, wenn sich direkt hinter gdt_ptr eine Funktion befindet. Die Position von Gdt_Flush in deinem letzten Post deutet darauf hin, dass du es nicht so genau mit der Platzierung des Codes im Text-Segment nimmst (section .text fehlt vor der Definition von Gdt_Flush:). Es könnte sein, dass du an Adresse 00104094 auch einfach eine Funktion stehen hast. Der Wert v=06 spricht übrigen eher gegen diese Vermutung, weil 06 Invalid Opcode bedeutet.

Okay,

ich hab im Grunde alles richtig gemacht.
Hab folgendes geändert:

Das heißt es funktioniert jetzt?
Dieser Text wird unter jedem Beitrag angezeigt.

nnosdev

  • Beiträge: 61
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 24. March 2012, 11:07 »
+hehe+

Ja es funktioniert jetz :)
Es lag tatsächlich an der Platzierung der Funktion. Entweder ich habs strukturiert indem ich "section .my_section" angegeben
oder die Funktion ausgelagert habe in eine gdt.S Datei
Danke für die Hilfe.


nnosdev

  • Beiträge: 61
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 24. March 2012, 23:19 »
Ich hätte da doch noch eine Frage zum objdump..

Wie kann ich mir die folgenden Adressen und deren Einträge
ausgeben lassen? Keine Ahnung warum, aber genau diese hier
sind "auspunktiert".

Disassembly of section .bss:

00102000 <gdt>:
...
00102028 <gdt_ptr>:
...
00104030 <kernel_stack>:
...
00104040 <idt>:
...
00104840 <idt_ptr>:
...
00104860 <gdt>:
...
00104888 <gdt_ptr>:
...
001048a0 <idt>:
...
001050a0 <idt_ptr>:
...

oern

  • Beiträge: 44
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 25. March 2012, 14:03 »
Hallo,

wie "Disassembly of section .bss" sagt, liegen die Symbole in der .bss Section, die uninitialisierte Daten beinhaltet. Also werden sie erst zur Laufzeit mit Daten gefüllt, weshalb objdump nicht sagen kann, welche Werte dort liegen. Dies ist zum Beispiel in Binärformaten wie ELF nützlich, da dort nur die initialisierten Daten in der Datei liegen müssen und der Rest alloziiert und auf 0 gesetzt wird (kann man mit "readelf -l" sehen, dort ist in der zweiten LOAD-Sektion meistens filesz < memsz).

Grüße,
oern

nnosdev

  • Beiträge: 61
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 29. March 2012, 23:38 »
Ah, das macht natürlich Sinn! Hätte ich mir eigentlich denken können..

Also ich versuch die qemu.log stärker in meinen Alltag einzubauen, aber es ist
etwas mühsam wenn man nicht weiß was die Einträge bedeuten.

Kennt da jemand einen brauchbaren Link?

Keine Ahnung wie ich mit diesen Informationen umgehen soll.
0: v=03 e=0000 i=1 cpl=0 IP=0008:00100bab pc=00100bab SP=0010:00104000 EAX=00104840

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #11 am: 30. March 2012, 11:10 »
Hi,

einen Link hab ich nicht, aber ich kann dir zumindestens diesen Eintrag (großteils) erklären :)

v = Nummer des Interrupts
e = Fehlercode (vorallem bei Pagefaults nützlich ;))
i = ka :D
cpl = aktueller Ring in dem der Code ausgeführt wird - Ring 0 Kernel, Ring 3 Userspace etc.
IP = Segment:Adresse des aktuellen Befehls
pc= Adresse des aktuellen Befehls
SP = Segment:Adresse des Stackpointers
EAX = Wert von EAX ;)

Ich brauche meistens nur v, e, pc und vielleicht noch SP - das ist auch alles das, was ein vernünftiger Bluescreen wenigstens anzeigen sollte ;)

Ich hoffe ich konnte helfen :)

Grüße,
LittleFox

nnosdev

  • Beiträge: 61
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 04. April 2012, 11:36 »
Ja, das hilft schon sehr!
Danke :)

 

Einloggen