Autor Thema: Probleme mit dem Tutorial (GDT)  (Gelesen 5821 mal)

JustJim

  • Beiträge: 20
    • Profil anzeigen
Gespeichert
« am: 27. November 2013, 10:30 »
Hey. Also ich hab Probleme mit der interpretation des Artikels
[1]http://www.lowlevel.eu/wiki/Teil_5_-_Interrupts ,sowie das dazu nötige
[2]http://www.lowlevel.eu/wiki/Global_Descriptor_Table

Aber zunächst eine generelle (vll auch doofe) Frage: Zeigen GDT's auf ein Daten/Code-Segment, oder ist dieses Segment im GDT enthalten?

Naja jedenfalls:
Im Artikel [1] werden ja über init_gdt(void) die GDT's gesetzt.
In dieser Funktion ist ein load_gdt();
Vorraussetzung für dies war der Artikel [2], indem die Funktion set_entry beschrieben wird, die zunächst benötigt wird.
Nur versteh ich die Form vom Struct nicht. Es besitzt weder Namen noch Variable-Beschreibung. (Ich kenne es als strucht bla{ /////}bla1,bla2;)
Wie wird also der Pointer auf das gerade eingerichtete GDT erstellt?
Und was hat es mit der nirgends definierten Funktion load_gdt(); zu tun, die am Ende von init_gdt aufgerufen wird?
Vielen Danke im Vorraus!

Ps.: Achja. Wenn ich den Befehl "make" in Linux aufrufe um das ganze zu builden (ich habe init_gdt(), set_entry() und die struct in eine externe .c datei gelagert und über header eingebunden) dann bekomm ich den Fehler, dass vor dem "volatile" doch bitte ein '(' zu stehen hat.
« Letzte Änderung: 27. November 2013, 10:32 von JustJim »
for(i=0; i<=length_of_ife; i++)
{
  learn(All);
}

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 27. November 2013, 11:50 »
Im Protected Mode kann der Programmierer selbst entscheiden, welche Segmente es gibt und wo diese im Speicher liegen. Genau diese Informationen stehen in der GDT. (Zum Vergleich: im Real Mode haben alle Segmente 64 KB Größe und liegen im 16 Byte-Abstand hintereinander, deswegen braucht man so eine Tabelle da nicht.)

Du kannst die GDT auch als Array aus GDT-Einträgen ("struct gdt_entry") betrachten, wenn du das möchtest. Der Code tut das nicht und betrachtet die Einträge einfach als 64 Bit-Integer (jeder Eintrag hat 64 Bit, passt also) und set_entry() schreibt die Einzelteile mit Hilfe von Bithifts rein. Statt "struct gdt_entry gdt[GDT_ENTRIES]" steht da einfach nur "uint64_t gdt[GDT_ENTRIES]".

Man braucht Strukturen keinen Namen geben, dann sind sie anonym. Oft kommen die im Zusammenhang mit Typdefinitionen vor, also "typedef struct { ... } meintyp_t". Eine Möglichkeit reicht meist aus, um auf den Datentyp zuzugreifen. Die Ladefunktion definiert eine anonyme Struktur und genau eine Variable davon - man braucht diesen Typ schließlich nie wieder.

Wenn der Compiler über dein "asm" meckert, probiere mal "__asm__" stattdessen.

JustJim

  • Beiträge: 20
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 27. November 2013, 12:11 »
naja mein compiler meckert mich an, dass load_gdt nicht definiert ist, genauso wie GDT_ENTRIES lol. Ich glaube ich stehe so aufm Schlauch dass ich was grundlegendes übersehe und wenn ich es sehe, denk ich "oh man... natürlich"
make
gcc -m32 -Wall -g -fno-stack-protector -c -o gdt/gdt.o gdt/gdt.c
gdt/gdt.c:13:21: error: ‘GDT_ENTRIES’ undeclared here (not in a function)
gdt/gdt.c:21:9: error: expected ‘(’ before ‘volatile’
gdt/gdt.c: In function ‘init_gdt’:
gdt/gdt.c:44:5: warning: implicit declaration of function ‘load_gdt’ [-Wimplicit-function-declaration]
gdt/gdt.c: At top level:
gdt/gdt.c:13:17: warning: ‘gdt’ defined but not used [-Wunused-variable]
make: *** [gdt/gdt.o] Error 1


Das ist das was ich bekomme, wenn ich kompiliere :(

So sieht mein Code aus:
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define GDT_FLAG_DATASEG 0x02
#define GDT_FLAG_CODESEG 0x0a
#define GDT_FLAG_TSS     0x09
#define GDT_FLAG_SEGMENT 0x10
#define GDT_FLAG_RING0   0x00
#define GDT_FLAG_RING3   0x60
#define GDT_FLAG_PRESENT 0x80
#define GDT_FLAG_4K_GRAN 0x800
#define GDT_FLAG_32_BIT  0x400
static uint64_t gdt[GDT_ENTRIES];
struct {
    uint16_t limit;
    void* pointer;
} __attribute__((packed)) gdtp = {
    .limit = GDT_ENTRIES * 8 - 1,
    .pointer = gdt,
};
__asm__ volatile("lgdt %0" : : "m" (gdtp));

static void set_entry(int i, unsigned int base, unsigned int limit, int flags)
{
    gdt[i] = limit & 0xffffLL;
    gdt[i] |= (base & 0xffffffLL) << 16;
    gdt[i] |= (flags & 0xffLL) << 40;
    gdt[i] |= ((limit >> 16) & 0xfLL) << 48;
    gdt[i] |= ((flags >> 8 )& 0xffLL) << 52;
    gdt[i] |= ((base >> 24) & 0xffLL) << 56;
}
void init_gdt(void)
{
    set_entry(0, 0, 0, 0);
    set_entry(1, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT |
        GDT_FLAG_CODESEG | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT);
    set_entry(2, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT |
        GDT_FLAG_DATASEG | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT);
    set_entry(3, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT |
        GDT_FLAG_CODESEG | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
    set_entry(4, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT |
        GDT_FLAG_DATASEG | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
 
    load_gdt();
}
« Letzte Änderung: 27. November 2013, 14:19 von JustJim »
for(i=0; i<=length_of_ife; i++)
{
  learn(All);
}

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 27. November 2013, 14:40 »
Tja, also, äh, GDT_ENTRIES definierst du wirklich nirgends und Code darf auch nicht außerhalb einer Funktion stehen.

JustJim

  • Beiträge: 20
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 27. November 2013, 15:22 »
Okay also doch selber definieren.
Deswegen war ich so verwirrt von dem dargestellten Code lol.
Demnach ist GDT_Entries = 5, weil es 0-5 Entries sind.
Aber was ist mit load_gdt();?
Wie wird die definiert? Wie gebe ich dem lgdt meine Sammlung an GDT's?
Und was ist mit der Variable gdt?
Sollte das Struct in die Funktion set_entry?
Oder sollte das Struct in die von mir dann selbst erstelle Funktion load_gdt();
Aber dann übergebe ich ja trotzdem nicht gdt :/
Weiterhin wird "asm" sowie "__asm__" nicht akzeptiert. er will immer ein '(' vor dem volatile :(
Ich glaub ich steh wirklich etwas neben mir :(
« Letzte Änderung: 27. November 2013, 15:47 von JustJim »
for(i=0; i<=length_of_ife; i++)
{
  learn(All);
}

JustJim

  • Beiträge: 20
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 27. November 2013, 15:34 »
Sooo. Ich habe mal etwas probiert.
Das Ergebnis (Bochs zeigt nur den Text an, den ich mittels meiner print Funktion anzeigen lasse) sollte eig. bedeutet, dass keine Probleme aufgetreten sind.

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define GDT_FLAG_DATASEG 0x02
#define GDT_FLAG_CODESEG 0x0a
#define GDT_FLAG_TSS     0x09
#define GDT_FLAG_SEGMENT 0x10
#define GDT_FLAG_RING0   0x00
#define GDT_FLAG_RING3   0x60
#define GDT_FLAG_PRESENT 0x80
#define GDT_FLAG_4K_GRAN 0x800
#define GDT_FLAG_32_BIT  0x400
#define GDT_ENTRIES 5

static uint64_t gdt[GDT_ENTRIES];
struct {
    uint16_t limit;
    void* pointer;
} __attribute__((packed)) gdtp = {
    .limit = GDT_ENTRIES * 8 - 1,
    .pointer = gdt,
};


static void set_entry(int i, unsigned int base, unsigned int limit, int flags)
{
    gdt[i] = limit & 0xffffLL;
    gdt[i] |= (base & 0xffffffLL) << 16;
    gdt[i] |= (flags & 0xffLL) << 40;
    gdt[i] |= ((limit >> 16) & 0xfLL) << 48;
    gdt[i] |= ((flags >> 8 )& 0xffLL) << 52;
    gdt[i] |= ((base >> 24) & 0xffLL) << 56;
}
void init_gdt(void)
{
    set_entry(0, 0, 0, 0);
    set_entry(1, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT |
        GDT_FLAG_CODESEG | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT);
    set_entry(2, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT |
        GDT_FLAG_DATASEG | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT);
    set_entry(3, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT |
        GDT_FLAG_CODESEG | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
    set_entry(4, 0, 0xfffff, GDT_FLAG_SEGMENT | GDT_FLAG_32_BIT |
        GDT_FLAG_DATASEG | GDT_FLAG_4K_GRAN | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
 
    load_gdt();
}
void load_gdt()
{
asm volatile("lgdt %0" : : "m" (gdtp));
}

Das ist die gdt.c Datei.
Kann mir jemand bestädigen das das operabel ist?
for(i=0; i<=length_of_ife; i++)
{
  learn(All);
}

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 27. November 2013, 16:10 »
Es sieht jedenfalls nicht offensichtlich falsch aus.

Okay also doch selber definieren.
Deswegen war ich so verwirrt von dem dargestellten Code lol.
Codebeispiele im Tutorial sind in der Regel nicht zum Abschreiben, sondern zum Verstehen gedacht. Dass du an passenden Stellen logische Ergänzungen oder Anpassungen machst, wird erwartet.

Zitat
Wie wird die definiert? Wie gebe ich dem lgdt meine Sammlung an GDT's?
Du hast genau eine GDT (Global Descriptor Table), deswegen heißt die auch global. Diese GDT ist eine Tabelle, die mehrere Deskriptoren enthält, die die Segmente beschreiben/definieren, die du haben willst.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

JustJim

  • Beiträge: 20
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 27. November 2013, 16:18 »
Ahh! damn okay jetzt hab ich es verstanden! Ich dachte ständig ich mache mehrere GDT's. Das war der Knoten, Danke.
Gut.
Achso, ja der Code aus meinem letzten Post ist natürlich unvollständig, ohne das Neuladen der Seg-Registers.
Das hab ich nach dem Inlinebefehl zum Laden des GDT ebenso in Inline gemacht.

void load_gdt()
{
asm volatile("lgdt %0" : : "m" (gdtp));
asm volatile("mov $0x10, %%ax;mov %%ax, %%ds;mov %%ax, %%es;mov %%ax, %%fs;mov %%ax, %%gs;mov %%ax, %%ss;" : : );
asm volatile("ljmp $0x8, $.1;.1:;" : : );
print("ola");
}

So sieht das dann aus.
Scheint auch zu funktionieren. Hab testhalber ein print("ola") hinzugefügt um zu sehen ob er bis zum Ende kommt oder vorher abbricht.
Aber nein, er schafft es :).
Soweit in meinem geposteten Codes keine Fehler gefunden werden (Ich hoffe mal, dass es jetzt richtig ist) kann das also als
beantwortet gesehen werden!
Danke nochmal!
for(i=0; i<=length_of_ife; i++)
{
  learn(All);
}

 

Einloggen