Autor Thema: [gelöst] Warum will Paging nicht?  (Gelesen 2688 mal)

gcalctool

  • Beiträge: 29
    • Profil anzeigen
Gespeichert
« am: 14. January 2010, 12:49 »
Liebe Lowlevel Community!

Ich hab ein, hoffentlich kleines, Problem mit dem initialisieren von Paging.
StatusQuo:
  • Ich initialisiere eine GDT(ring0 code/datensegment[base 0, limit 0xfffff], ring3 code/datensegment[base 0, limit 0xfffff])
  • Ich habe eine physische Speicherverwaltung.
  • Mit der Funktion unsigned int getFreeMemory() gehe ich durch eine Bitmap und gib eine freihe Speicherstelle zurück die Speicherstellen sind immer in 4K abständen(0x0, 0x1000, 0x2000) etc...
  • Freier speicher wurde in der bitmap markiert (hab ich von GRUB). Die Adressen an denen der Kernel liegt wurden als belegt markiert.

Ich denke die Bitmap müsste soweit passen. So nun zu meinem eigentlichen Problem: Da ich nun die physische Speicherverwaltung soweit habe wollte ich Paging einschalten:

Meine Überlegung:
  • Ich will den gesamten Speicher Mappen.
  • Ein PageDirectory anlegen mit 1024 einträgen
  • Solange PageTables mit 1024 einträgen hinzufügen bis mir unsigned int getFreeMemory() sagt: "DA GIBBET KEINEN SPEICHER MEHR"

so habe ich das nun realisiert:

/*mein PageDirectory: muss 4K aligned sein deswegen: __attribute__((aligned (0x1000))); */
unsigned int pageDirectory[1024] __attribute__((aligned (0x1000)));

dies ist die Methode die Paging intitialisieren soll:
void initPaging(){
printf("adress of the paging directory %x\n", (unsigned int)&pageDirectory);
int i;

        if(((unsigned int)&pageDirectory % 4096) != 0){
printf("not align\n");
return;
}

for(i = 0; i < 1024; i++){
unsigned int pageTable = getPageTableEntry();

if(pageTable == -1){
printf("keinSpeicherMehr verfuegbar\n");
int j;
for(j = i; j < 1024; j++)
pageDirectory[j] = 0;
printf("rest Aufgefuellt\n");
break;
}

pageDirectory[i] = pageTable | MEMORY_PRESENT | PAGE_WRITEABLE | EVERYONE_ACCESSABLE;
}
printf("lade PageTable\n");

asm volatile("mov %0, %%cr3":: "b"(pageDirectory));
unsigned int cr0;
asm volatile("mov %%cr0, %0": "=b"(cr0));
cr0 |= 0x80000000;
asm volatile("mov %0, %%cr0":: "b"(cr0));

printf("geladen\n");
}

von dieser Methode aus wir die Methode getPageTableEntry() aufgerufen. Diese Methode sollte mir eine PageTable zusammenbauen:
unsigned int getPageTableEntry(){
unsigned int addr = getFreeMemory();
unsigned int *pageTable = addr;

if(addr == -1)
return -1;

if((addr % 4096) != 0){
printf("address not aligned\n");
}

int i;
for(i = 0; i < 1024; i++){
unsigned int p = getFreeMemory();

if(p == -1)
return -1;


pageTable[i] = p | MEMORY_PRESENT | PAGE_WRITEABLE | EVERYONE_ACCESSABLE;
}

return pageTable;
}

Ich bin mit meinem Latein einfach am Ende ich weiß nimmer wo mein Fehler liegt.
ich glaube er kommt bis nach printf("lade PageTable\n"); irgendwo, dann startet Bochs(oder der PC) immer neu. Vielleicht auch ganz intressant ist in welcher Reihenfolge ich das ganze initialisiere(kernel.c):
void kernel_init(struct multibootInfo *mbInfo)
{
   cls();
printf("MultibootInfoFlags: %x\n", mbInfo->flags);

printf("Initialisiere physisches MemoryManagement!\n");
initPhysMemManagement(mbInfo);

   kPrint("Initialisiere Globale Deskriptor Tabelle...");
   initGdt();
   kPrint("OK\n");
   kPrint("Lade Globale Deskriptor Tabelle...");
   loadGdt();
   kPrint("OK\n");

printf("Initialisiere Paging\n");
initPaging();

   kPrint("Lade Interrupts...");
   initInt();
kPrint("OK\n");

kPrint("Initialisiere keyboard...");
initKeyboard();
kPrint("OK\n\n");

printf("teste printf %d %c %x\n", 12346789, 'c', 123);
printf("starte interrupts\n");
asm volatile ("sti");

/*
printf("initialisiere Floppy!\n");
initFloppy();
readData(0);
*/


   while(1){
    //Do nothing
   }
}

Und noch ganz wichig BOCHS error:
00139631503i[CPU0 ] CPU is in protected mode (active)
00139631503i[CPU0 ] CS.d_b = 32 bit
00139631503i[CPU0 ] SS.d_b = 32 bit
00139631503i[CPU0 ] EFER   = 0x00000000
00139631503i[CPU0 ] | RAX=0000000000000000  RBX=00000000e0000011
00139631503i[CPU0 ] | RCX=00000000000000fd  RDX=00000000000b897a
00139631503i[CPU0 ] | RSP=0000000000001fac  RBP=0000000000001fd4
00139631503i[CPU0 ] | RSI=0000000000057987  RDI=000000000005798c
00139631503i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00139631503i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00139631503i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00139631503i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00139631503i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00139631503i[CPU0 ] | SEG selector     base    limit G D
00139631503i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00139631503i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00139631503i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00139631503i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00139631503i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00139631503i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00139631503i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00139631503i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00139631503i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00139631503i[CPU0 ] | RIP=00000000003fffff (00000000003fffff)
00139631503i[CPU0 ] | CR0=0xe0000011 CR1=0x0 CR2=0x0000000000400000
00139631503i[CPU0 ] | CR3=0x00136000 CR4=0x00000000
00139631503i[CPU0 ] (instruction unavailable) page split instruction
00139631503e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00139631503i[SYS  ] bx_pc_system_c::Reset(SOFTWARE) called
00139631503i[CPU0 ] cpu software reset
00139631503i[APIC0] local apic in CPU 0 initializing
00139634806i[BIOS ] $Revision: 1.209 $ $Date: 2008/06/02 20:08:10 $
00139952563i[KBD  ] reset-disable command received
00140080745i[VBIOS]
VGABios $Id: vgabios.c,v 1.67 2008/01/27 09:44:12 vruppert Exp $

00140080816i[VGA  ] VBE known Display Interface b0c0
00140080848i[VGA  ] VBE known Display Interface b0c4
00140083773i[VBIOS] VBE Bios $Id: vbe.c,v 1.60 2008/03/02 07:47:21 vruppert Exp $
00140400000i[XGUI ] charmap update. Font Height is 16
00140411561i[BIOS ] Starting rombios32
00140412227i[BIOS ] ram_size=0x00800000
00140511804i[BIOS ] Found 1 cpu(s)
00140533638i[BIOS ] bios_table_addr: 0x000fb778 end=0x000fcc00
00140533666i[PCI  ] 440FX PMC write to PAM register 59 (TLB Flush)
00140861362i[PCI  ] 440FX PMC write to PAM register 59 (TLB Flush)
00141190127i[BIOS ] PIIX3 init: elcr=00 0a
00141197645i[BIOS ] PCI: bus=0 devfn=0x00: vendor_id=0x8086 device_id=0x1237
00141199831i[BIOS ] PCI: bus=0 devfn=0x08: vendor_id=0x8086 device_id=0x7000
00141201856i[BIOS ] PCI: bus=0 devfn=0x09: vendor_id=0x8086 device_id=0x7010
00141202802i[BIOS ] region 4: 0x0000c000
00141212119i[BIOS ] MP table addr=0x000fb850 MPC table addr=0x000fb780 size=0xd0
00141213735i[BIOS ] SMBIOS table addr=0x000fb860
00141213774i[PCI  ] 440FX PMC write to PAM register 59 (TLB Flush)
00141214618i[BIOS ] bios_table_cur_addr: 0x000fb964
00173160000p[XGUI ] >>PANIC<< POWER button turned off.

Vl könnt ihr mir bei meinem Problem Helfen ich bin mit meiner "Weisheit" echt am Ende!

Vielen Dank!
lg
« Letzte Änderung: 24. January 2010, 11:42 von gcalctool »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 14. January 2010, 13:32 »
Da ich nun die physische Speicherverwaltung soweit habe wollte ich Paging einschalten:

Meine Überlegung:
  • Ich will den gesamten Speicher Mappen.
  • Ein PageDirectory anlegen mit 1024 einträgen
  • Solange PageTables mit 1024 einträgen hinzufügen bis mir unsigned int getFreeMemory() sagt: "DA GIBBET KEINEN SPEICHER MEHR"
Das solltest du so nicht tun. Dann mappst du den gesamten freien Speicher linear hintereinander. Ich gehe mal davon aus, dass dein Kernel ist in der Bitmap nicht als freier Speicher markiert ist. Der würde dann nicht gemappt werden.

Deine Methode getPageTableEntry ist vielleicht in abgewandelter Form brauchbar um einem Prozess eine Menge x an virtuellem Speicher zur Verfügung zu stellen, aber zur Initialisierung des Kernels taugt sich nicht.

Der Ablauf des Fehlers ist vermutlich in etwa so:
- du aktivierst Paging
- da du nur Seiten gemappt hast, die du mit getFreeMemory() bekommen hast, befindest sich an der Stelle von EIP nicht mehr der Code deines Kernels, sondern welche zufälligen Bytes
- die CPU führt diese unbeirrt weiter hintereinander aus, und landet irgendwann an der Adresse 0x3fffff (vermutlich waren diese Bytes alles Nullen)
- dann gibt es einen Page Fault, weil an der Adresse 0x3fffff eine mindestens 2 Byte große Instruktion steht. Das erkennt man im Bochslog:
Zitat
00139631503i[CPU0 ] | RIP=00000000003fffff (00000000003fffff)
00139631503i[CPU0 ] | CR0=0xe0000011 CR1=0x0 CR2=0x0000000000400000
00139631503i[CPU0 ] | CR3=0x00136000 CR4=0x00000000

Dass die Adresse 0x0000000000400000 nicht gemappt ist, bedeutet, dass beim Erstellen vom Page Directory vermutlich auch noch irgendwas schief gegangen ist. Was genau, kann ich auf die Schnelle nicht sagen.

Allerdings ist wie gesagt deine Idee, wie du den Speicher mappen willst, nicht korrekt. Du solltest für den Anfang den gesamten Speicher 1:1 mappen (identity mapping). So ungefähr könnte das aussehen:

void initPaging() {
...
    for (i = 0; i < 1024; i++) {
        unsigned int *pageTable = (unsigned int *)getFreeMemory();

        /* 4 MB beginnend an der physischen Adresse i * 4 MB mappen */
        for (j = 0; j < 1024; j++) {
            pageTable[j] = (i * 4096 * 1024  + j * 4096) | MEMORY_PRESENT | PAGE_WRITEABLE | EVERYONE_ACCESSABLE;
        }

        /* diese 4 MB an die virtuelle Adresse i * 4 MB mappen */
        pageDirectory[i] = (unsigned int)pageTable | MEMORY_PRESENT | PAGE_WRITEABLE | EVERYONE_ACCESSABLE;

    }

...
}

So sind alle virtuelle Adressen gleich den physischen Adressen.

Dieser Text wird unter jedem Beitrag angezeigt.

gcalctool

  • Beiträge: 29
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 14. January 2010, 15:01 »
Danke für deine Antwort!

Das ganze hat zum verständnis über Paging einiges beigetragen aber jetzt hab ich noch ein paar fragen:
  • 1. Wenn ich Paging einschalte kann ich nichtmehr auf die physischen Adressen zugreifen weil die MMU alles umwandelt! Verstehe ich das richtig? Dann muss ich ja zu allererst den Speicher wo der Kernel liegt mappen ist das richtig? Denn wenn ich dann Paging aktivieren würde, würden ja die Addressen des Kernels nichtmehr passen.
  • 2. Wie hängt Paging mit den Deskriptor Tabellen zusammen?
  • 3. Muss ich erst die Deskriptortabellen initialisieren oder zuerst Paging einschalten logisch wäre zuerst Paging einschalten.
  • 4. Ich ziehe die Daten für meine physische Speicherverwaltung vom GRUB somit weiß ich welche Speicherstellen frei sind und welche nicht. Auf welches Segment in meiner Global Deskriptor Tabelle bezieht sich das dann? Ich bin immer davon ausgegangen dass es das ring 0 segment ist da ich in dieses auch springe nachdem ich die GDT initialisiert habe. Aber was ist mit dem Ring3 segment wie kann ich auf das zugreifen bzw wie weiß ich in welchem Segment sich welche Speicheradresse befindet?

mir fehlen da irgendwie die zusammenhänge
« Letzte Änderung: 14. January 2010, 15:17 von gcalctool »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 14. January 2010, 16:02 »
1. Wenn ich Paging einschalte kann ich nichtmehr auf die physischen Adressen zugreifen weil die MMU alles umwandelt! Verstehe ich das richtig? Dann muss ich ja zu allererst den Speicher wo der Kernel liegt mappen ist das richtig? Denn wenn ich dann Paging aktivieren würde, würden ja die Addressen des Kernels nichtmehr passen.
Zweimal ja.

2. Wie hängt Paging mit den Deskriptor Tabellen zusammen?
Die Adressbildung durch Segmentierung erfolgt vor dem Paging.

Wenn du einen Speicherzugriff machst, dann gibst du ein Segmentselektor und ein Offset an. Beide zusammen sind die logische Adresse (auch Far Pointer genannt). Bei Zugriffen auf Daten wird (meistens) der Wert in DS implizit als Selektor verwendet. Die CPU schaut dann in der GDT nach, welche Basisadresse zum Selektor gehört, diese Basisadresse wird zum Offset addiert. Diese Adresse heißt bei Intel dann lineare Adresse. Meistens umgeht man die Segmentierung (im 64-Bit-Modus ist sie praktisch abgeschafft), und setzt die Basisadresse auf 0.

Wenn Paging aktiviert ist, wird die lineare Adresse über die Page Tables in die physische Adresse umgewandelt. Ist Paging deaktiviert, ist die lineare Adresse gleich der physischen Adresse.

3. Muss ich erst die Deskriptortabellen initialisieren oder zuerst Paging einschalten logisch wäre zuerst Paging einschalten.
Paging steht dir nur im Protected Mode (und Long Mode) zur Verfügung, und um dahin zu gelangen, musst du zuerst die Deskriptortabellen laden. Wenn du dich allerdings von GRUB laden lässt, bist du ja im Protected Mode. Dann ist die Reihenfolge egal.

4. Ich ziehe die Daten für meine physische Speicherverwaltung vom GRUB somit weiß ich welche Speicherstellen frei sind und welche nicht. Auf welches Segment in meiner Global Deskriptor Tabelle bezieht sich das dann?

Die Angaben beziehen sich auf physische Adressen, und hat nichts mit den Segmenten zu tun. Normalerweise lädt man die Segmentregister mit Selektoren mit Basis 0 und Limit 4GB, sodass der logische Adressraum gleich dem linearen ist. Dann kannst du von Ring 3 genauso auf die Memory Map zugreifen wie aus Ring 0.
« Letzte Änderung: 14. January 2010, 16:05 von PorkChicken »
Dieser Text wird unter jedem Beitrag angezeigt.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 14. January 2010, 16:29 »
Hallo,


mir fehlen da irgendwie die zusammenhänge
siehe http://duartes.org/gustavo/blog/post/memory-translation-and-segmentation

Die Fragen sind ja schon beantwortet.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

 

Einloggen