Autor Thema: GDT-Alignment  (Gelesen 10334 mal)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« am: 06. January 2012, 22:41 »
Nabend zusammen,

ich habe derzeit ein komisches Problem.
Meine GDT funktioniert nur, wenn ich die GDT an die Page-Size ausrichte.
Habe alle GDT-Eintraege ueberprueft und die sind korrekt.
Wenn ich die GDT an 8-Byte ausrichte (laut Intel die optimale Position), bekomme ich einen GPF.
Woran kann das liegen?

Hier mal die Eintraege aus der GDT:

{{value = 0, mapping = {segment0 = 0, base0 = 0, accessed = 0,
      segment_r_rw = 0, direction = 0, exec = 0, segment = 0, privilege = 0,
      present = 0, segment1 = 0, zero = 0, size = 0, granularity = 0, base1 = 0}},
  {value = 58434644969848831, mapping = {segment0 = 65535, base0 = 0,
      accessed = 0, segment_r_rw = 1, direction = 0, exec = 1, segment = 1,
      privilege = 0, present = 1, segment1 = 15, zero = 0, size = 1,
      granularity = 1, base1 = 0}}, {value = 58425848876826623, mapping = {
      segment0 = 65535, base0 = 0, accessed = 0, segment_r_rw = 1, direction = 0,
      exec = 0, segment = 1, privilege = 0, present = 1, segment1 = 15, zero = 0,
      size = 1, granularity = 1, base1 = 0}}, {value = 58540198086115327,
    mapping = {segment0 = 65535, base0 = 0, accessed = 0, segment_r_rw = 1,
      direction = 0, exec = 1, segment = 1, privilege = 3, present = 1,
      segment1 = 15, zero = 0, size = 1, granularity = 1, base1 = 0}}, {
    value = 58531401993093119, mapping = {segment0 = 65535, base0 = 0,
      accessed = 0, segment_r_rw = 1, direction = 0, exec = 0, segment = 1,
      privilege = 3, present = 1, segment1 = 15, zero = 0, size = 1,
      granularity = 1, base1 = 0}}}

Danke.

Gruss,
rizor
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #1 am: 06. January 2012, 23:46 »
Wenn ich die GDT an 8-Byte ausrichte (laut Intel die optimale Position), bekomme ich einen GPF.
Einen GPF bei was bzw. wann? Und was sagen die gängigen Emulatoren zum Grund des GPF? Ist die Struktur auch im Speicher korrekt (direkt vor dem GPF)?

edit: Was ist das eigentlich für eine komische Struktur mit .value und .mapping?
« Letzte Änderung: 07. January 2012, 00:49 von bluecode »
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 06. January 2012, 23:55 »
Wie richtest du die GDT an 8 bzw. 4096 Byte aus?
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 07. January 2012, 01:57 »
QEmu meldet bei der der GPF als Error-Code 0x10und Bochs kann die GDT niht interpretieren.
Ich richte die GPF einmal an 0x1000 aus (dann klappt es) und dann an an 0x8 und dann klappt es nicht.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 07. January 2012, 02:00 »
Meine Frage hat darauf abgezielt, ob du zum Beispiel einen Allokator verwendest, um Speicher für die GDT zu reservieren, und diesem das Alignment als Parameter übergibst, oder ob du dafür Befehle des Assemblers und/oder Linkers verwendest.
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 07. January 2012, 02:56 »
Achso, das wird durch den Linker entschieden.
Der sorgt fuer das Alignment
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 07. January 2012, 12:30 »
Hm, das heißt du machst dir die Mühe eine einzelne Datenstruktur (im Gegensatz zur .data-Sektion) durch den Linker auszurichten? Das ist doch ziemlich kompliziert. Kannst du das mal zeigen?
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 07. January 2012, 12:44 »
Das ist an sich echt simpel.
Nur finde ich es sinnlos, extra jede Menge Speicher zu verschwenden damit der GDT laeuft, obwohl in der Intel-Spec. nichts ueber Pflichtalignment steht.

ENTRY(_start)
OUTPUT(elf32-i386)
OUTPUT_ARCH(i386:i386)

PAGE_SIZE = 0x1000;
PHYS_ADDR = 0x100000;
VIRT_ADDR = 0xC0000000;

SECTIONS
{
        . = PHYS_ADDR;

        __boot_start = .;
        .boot.text : AT(ADDR(.boot.text))
        {
                *(.multiboot)
                *(.boot.text)
                . = ALIGN(4096);
                *(.gdt)
        }
        .boot.data : AT(ADDR(.boot.data))
        {
                *(.boot.data);
                __export_start = .;
                *(.export)
                __export_end = .;
        }
        . = ALIGN(PAGE_SIZE);
        __boot_end = .;

        OFFSET = VIRT_ADDR - .;
        . = VIRT_ADDR;

        __rodata_pm_start = . - OFFSET;
        __rodata_vm_start = .;
        .text : AT(ADDR(.text) - OFFSET)
        {
                *(.text)
                *(.rodata)
        }
        . = ALIGN(PAGE_SIZE);
        __rodata_vm_end = .;
        __rodata_pm_end = . - OFFSET;

        __data_vm_start = .;
        __data_pm_start = . - OFFSET;
        .data : AT(ADDR(.data) - OFFSET)
        {
                __idt__ = . - OFFSET;
                *(.idt)
                *(.data)
                *(.bss)
        }
        . = ALIGN(PAGE_SIZE);
        __data_vm_end = .;
        __data_pm_end = . - OFFSET;

        /DISCARD/ :
         {
                *(.comment)
                *(.eh_frame)
         }
}

Momentan liegt die GDT zwar in der Boot-Sektion, das liegt aber daran, dass ich die GDT erst mal ohne MMU initialisieren moechte.

Hier noch der Code, der dafuer sorgt, dass die GDT an der richtigen Stelle liegt:

#define __gdt           __attribute__((section(".gdt")))
#define __idt           __attribute__((section(".idt")))

union gdt_entry __gdt gdt[GDT_SIZE] = {
        { .value = 0x0 },
        { .value = 0x0 },
        { .value = 0x0 },
        { .value = 0x0 },
        { .value = 0x0 }
};
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 07. January 2012, 13:35 »
Wie ist die union gdt_entry definiert? Und hast du schon mal im Debugger geschaut, ob das ganze im Speicher so aussieht, wie du es erwartest?

__attribute__((aligned(4096))) wäre übrigens einfacher als von Hand eine neue Section reinzubasteln...
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 07. January 2012, 13:46 »
Ja, der GDB sagt, dass alles gut aussieht (vom Speicherlayout her).
Allerdings kann Bochs das Ding nicht interpretieren, wenn es nicht an 0x1000 aligned ist.
Ansonsten kann er es.

Hier der Union:
struct gdt_mapping {
        uint64_t segment0 : 16;
        uint64_t base0 : 24;
        uint64_t accessed : 1;
        uint64_t segment_r_rw : 1;
        uint64_t direction : 1;
        uint64_t exec : 1;
        uint64_t segment : 1;
        uint64_t privilege : 2;
        uint64_t present : 1;
        uint64_t segment1 : 4;
        uint64_t zero : 2;
        uint64_t size : 1;
        uint64_t granularity : 1;
        uint64_t base1 : 8;
} packed;

union gdt_entry {
        uint64_t value;
        struct gdt_mapping mapping;
};

Der GDT wird nur ueber value beschrieben.
Der Rest soll nur zum Parsen dienen.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #10 am: 07. January 2012, 14:13 »
Ja, der GDB sagt, dass alles gut aussieht (vom Speicherlayout her).
Nur um das ganz genau geklärt zu haben: Du schaust im gdb auch direkt vor der Stelle an der es schief läuft? Ansonsten kannst du auch mal im bochs debugger dir das direkt davor ausgeben lassen. Ist das eigentlich noch im Realmode? Wie sehr freut sich denn die IVT da? Adresse 0 hat auch noch den Vorteil, dass man da um den Dreh bei einer Nullpointer-Dereferenzierung gerne mal hinschreibt. E_ALGIN_NOT_ADDRESS
« Letzte Änderung: 07. January 2012, 14:57 von bluecode »
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 07. January 2012, 14:36 »
Ich habe mir das Layout angeschaut nachdem der GDT mit lgdt in das Register geladen wird.
Da sieht alles gut aus.
Danach kann ich nicht mehr nachschauen, da QEmu und Bochs dann aussteigen (Aktualisierung der Segment-Register).

Nein, ich befinde mich schon im PMode. Moechte nur die GDT von GRUB ueberschreiben.

Bei Bochs lasse ich mir die GDT direkt anzeigen.
Wenn die Deskriptoren gegen 0x1000 aligned sind, sieht alles perfekt aus (auch unter QEmu). Wenn es nicht aligned ist, erhalte ich bei bochs folgende Ausgabe:

Global Descriptor Table (base=0x001003c8, limit=39):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x02]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x03]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x04]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, 32-bit
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 07. January 2012, 15:52 »
Ja, der GDB sagt, dass alles gut aussieht (vom Speicherlayout her).
Was genau hast du in gdb überprüft? Deine bochs-Debugausgabe sieht zumindest um drei Einträge verschoben aus (wenn es nicht Zufall ist, dass der vierte Eintrag was sinnvolles enthält).
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 07. January 2012, 15:56 »
Ich habe mir die GDT ausgegeben, nachdem alles initialisiert wurde (durch p gdt (siehe ersten Post)).
Da sieht alles gut aus.
Die Adressen, die in GDTR stehen, stimmen mit denen der GDT ueberein.
Wie kann es sein, dass die Teile verschoben werden?
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 07. January 2012, 16:01 »
Was du machen solltest, ist nicht die struct in gdb ausgeben zu lassen, sondern dir GDTR anzuschauen und die Speicherstelle dumpen lassen, auf die es zeigt (das geht sowohl in gdb als auch direkt im qemu-Monitor).

Hast du die kompletten Sourcen irgendwo online?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 07. January 2012, 16:19 »
Hier liegt der Code: https://github.com/rizor/nerdy

Habe das Problem aber geloest.
Habe nun das Alignment auf 8-Byte gemacht, indem ich __attribute__((aligned(8))) verwende.

Wieso funktioniert es, wenn der Compiler die Entscheidung ueber das Alignment trifft, aber wenn der Linker es macht, dann klappt es nicht?
« Letzte Änderung: 07. January 2012, 17:02 von rizor »
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 07. January 2012, 16:48 »
Wahrscheinlich hat das . = ALIGN(4096); mehr gemacht als du dachtest. Wenn ich die Änderungen in deinem Repository richtig überblicke, hast du ja auch mehr gemacht, als nur das Alignment geändert, und die GDT in eine andere Sektion verschoben. Vielleicht hat das ursprüngliche Alignment einen Bug verschleiert, zum Beispiel einen Buffer Overflow oder falsch aufgesetzte Page Tables.
Dieser Text wird unter jedem Beitrag angezeigt.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 07. January 2012, 17:03 »
Ich hatte bei den GDT-Tests noch kein aktives Paging.
Der Buffer-Overflow muesste an sich noch immer existieren, da ich an den Grenzen so nichts geandert habe.

Was macht LD denn noch, ausser die aktuellen Position der Zeiger zu veraendern, wenn man . = ALIGN(xxxx) macht?
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 07. January 2012, 17:29 »
Nichts. Der Kontext ist entscheidend. Aber ich habe schon genug spekuliert, nur um eine rhetorische Frage zu beantworten.
Dieser Text wird unter jedem Beitrag angezeigt.

 

Einloggen