Autor Thema: Paging funktioniert nicht  (Gelesen 5274 mal)

OsDevNewbie

  • Beiträge: 282
    • Profil anzeigen
    • YourOS Kernel
Gespeichert
« am: 02. July 2012, 01:01 »
Hallo,
beim Initialisieren der Pagingstrukturen gibt es ein Problem. Der Eintrag in die PML4 Table wird zwar richtig geschrieben, aber dann, wenn setPDP aufgerufen wird, ist die PML4 wieder auf null zurückgesetzt und ich weis nicht wieso.
Die Funktionen (paging.c):
Code: (C) [Auswählen]
void setPML4Entry(uint8_t i, uint8_t Present, uint8_t RW, uint8_t US, uint8_t PWT,
uint8_t PCD, uint8_t A, uint16_t AVL, uint8_t NX, uint64_t Address)
{
PML4.PML4E[i] = 0;
PML4.PML4E[i] = (Present & 1);
PML4.PML4E[i] |= (RW & 1) << 1;
PML4.PML4E[i] |= (US & 1) << 2;
PML4.PML4E[i] |= (PWT & 1) << 3;
PML4.PML4E[i] |= (PCD & 1) << 4;
PML4.PML4E[i] |= (A & 1) << 5;
PML4.PML4E[i] |= (AVL & 0x7LL) << 9;
PML4.PML4E[i] |= (Address & 0xFFFFFFFFFFLL) << 12;
PML4.PML4E[i] |= ((AVL >> 3) & 0x7FFLL) <<52;
PML4.PML4E[i] |= (NX & 1LL) << 63;
}

void setPDPEntry(uint8_t i, PDP_t *PDP, uint8_t Present, uint8_t RW, uint8_t US, uint8_t PWT,
uint8_t PCD, uint8_t A, uint16_t AVL, uint8_t NX, uint64_t Address)
{
PDP->PDPE[i] = 0;
PDP->PDPE[i] = (Present & 1);
PDP->PDPE[i] |= (RW & 1) << 1;
PDP->PDPE[i] |= (US & 1) << 2;
PDP->PDPE[i] |= (PWT & 1) << 3;
PDP->PDPE[i] |= (PCD & 1) << 4;
PDP->PDPE[i] |= (A & 1) << 5;
PDP->PDPE[i] |= (AVL & 0x7LL) << 9;
PDP->PDPE[i] |= (Address & 0xFFFFFFFFFFLL) << 12;
PDP->PDPE[i] |= ((AVL >> 3) & 0x7FFLL) <<52;
PDP->PDPE[i] |= (NX & 1LL) << 63;
}

void setPDEntry(uint8_t i, PD_t *PD, uint8_t Present, uint8_t RW, uint8_t US, uint8_t PWT,
uint8_t PCD, uint8_t A, uint16_t AVL, uint8_t NX, uint64_t Address)
{
PD->PDE[i] = 0;
PD->PDE[i] = (Present & 1);
PD->PDE[i] |= (RW & 1) << 1;
PD->PDE[i] |= (US & 1) << 2;
PD->PDE[i] |= (PWT & 1) << 3;
PD->PDE[i] |= (PCD & 1) << 4;
PD->PDE[i] |= (A & 1) << 5;
PD->PDE[i] |= (AVL & 0x7LL) << 9;
PD->PDE[i] |= (Address & 0xFFFFFFFFFFLL) << 12;
PD->PDE[i] |= ((AVL >> 3) & 0x7FFLL) <<52;
PD->PDE[i] |= (NX & 1LL) << 63;
}

void setPTEntry(uint8_t i, PT_t *PT, uint8_t Present, uint8_t RW, uint8_t US, uint8_t PWT,
uint8_t PCD, uint8_t A, uint8_t D, uint8_t G, uint16_t AVL,
uint8_t PAT, uint8_t NX, uint64_t Address)
{
PT->PTE[i] = 0;
PT->PTE[i] = (Present & 1);
PT->PTE[i] |= (RW & 1) << 1;
PT->PTE[i] |= (US & 1) << 2;
PT->PTE[i] |= (PWT & 1) << 3;
PT->PTE[i] |= (PCD & 1) << 4;
PT->PTE[i] |= (A & 1) << 5;
PT->PTE[i] |= (D & 1) << 6;
PT->PTE[i] |= (PAT & 1) << 7;
PT->PTE[i] |= (G & 1LL) << 8;
PT->PTE[i] |= (AVL & 0x7LL) << 9;
PT->PTE[i] |= (Address & 0xFFFFFFFFFFLL) << 12;
PT->PTE[i] |= ((AVL >> 3) & 0x7FFLL) << 52;
PT->PTE[i] |= (NX & 1LL) << 63;
}

Die Definitionen (paging.h):
Code: (C) [Auswählen]
#define MAP 3 //Anzahl der zu mappenden MBs. Mehrfaches von 2MB, d.h. 3*2MB werden gemappt; Max 1GB
#define PAGE_ENTRIES 512

static struct{
uint64_t PML4E[PAGE_ENTRIES];
}PML4;

typedef struct{
uint64_t PDPE[PAGE_ENTRIES];
}PDP_t;

typedef struct{
uint64_t PDE[PAGE_ENTRIES];
}PD_t;

typedef struct{
uint64_t PTE[PAGE_ENTRIES];
}PT_t;

Und hier die Intialisierung (im Hauptprogramm):
Code: (C) [Auswählen]
static PDP_t PDP;
static PD_t PD;
static PT_t PT[MAP];

//Erste 6MB mappen

setPML4Entry(0, 1, 1, 0, 1, 0, 0, 0, 0, (uint64_t)&PDP);
for(i = 1; i < PAGE_ENTRIES; i++)
setPML4Entry(i, 0, 0, 0, 0, 0, 0, 0, 0, 0);

setPDPEntry(0, &PDP, 1, 1, 0, 1, 0, 0, 0, 0, (uint64_t)&PD);
for(i = 1; i < PAGE_ENTRIES; i++)
setPDPEntry(i, &PDP, 0, 0, 0, 0, 0, 0, 0, 0, 0);

for(i = 0; i < MAP; i++)
setPDEntry(i, &PD, 1, 1, 0, 1, 0, 0, 0, 0, (uint64_t)&PT[i]);
for(i = MAP; i < PAGE_ENTRIES; i++) //Rest mit nullen auffüllen
setPDEntry(i, &PD, 0, 0, 0, 0, 0, 0, 0, 0, 0);

register int j;
for(i = 0; i < MAP; i++)
for(j = 0; j < PAGE_ENTRIES; j++)
setPTEntry(j, &PT[i], 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, (j * 4096) + (i * 512 * 4096));
asm(
"mov %0,%%eax;"
"mov %%eax,%%cr3;"
: : "r" (&PML4)
);

Ich hoffe ihr könnt mir helfen.
Viele Grüsse
OsDevNewbie

Ein Computer ohne Betriebsystem ist nicht mehr wert als ein Haufen Schrott.
Ein Computer ist eine Maschine, die einem Lebewesen das kostbarste klaut, was sie selber nicht hat:
DIE ZEIT DES LEBENS

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 02. July 2012, 01:54 »
Was verstehst du darunter, dass PML4 wieder auf null zurückgesetzt wird? Ich vermute mal, dir fehlen ein paar invlpg. Außerdem sind deine Adressen falsch.
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

OsDevNewbie

  • Beiträge: 282
    • Profil anzeigen
    • YourOS Kernel
Gespeichert
« Antwort #2 am: 02. July 2012, 11:57 »
Hallo,
was meinst du mit invlpg und was für Addressen sind falsch?
Viele Grüsse
OsDevNewbie

Ein Computer ohne Betriebsystem ist nicht mehr wert als ein Haufen Schrott.
Ein Computer ist eine Maschine, die einem Lebewesen das kostbarste klaut, was sie selber nicht hat:
DIE ZEIT DES LEBENS

SHyx0rmZ

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 02. July 2012, 12:13 »
Mit dem Befehl INVLPG sorgst du dafür, dass die CPU die Änderungen auch übernimmt (wenn du am aktuellen Kontext rummanipulierst).

Und
PML4.PML4E[i] |= (Address & 0xFFFFFFFFFFLL) << 12;müsste meines Erachtens
PML4.PML4E[i] |= (Address & 0xFFFFFFFFF000LL);sein.
« Letzte Änderung: 02. July 2012, 14:46 von SHyx0rmZ »
@X="krJhbuaesrytre c a cnR.ohut";while@X[/(..)(.)/];@X=@X[3..-1]+$1;print$2;end
"Scheiß auf Perl, wir haben Kekse" - Emperor Ruby

OsDevNewbie

  • Beiträge: 282
    • Profil anzeigen
    • YourOS Kernel
Gespeichert
« Antwort #4 am: 02. July 2012, 16:21 »
Ich habe dies jetzt mal gefixt, aber es funktioniert immer noch nicht, also habe ich trotzdem noch nicht gefixt. :|
Ich habe bemerkt, dass schon die Funktion irgendwie nichts in diese Tabelle hineinschreibt, d.h. sie schreibt immer nullen in die Tabelle schon beim ersten Aufruf (irgendwie komisch, denn ich übergebe das Present Bit als 1 und intern, also in der Funktion werden die Parameter wieder verschoben und erst dann wird geschrieben und oder gerechnet, aber dann ist im Present Bit nur noch eine null).
Ich habe zudem noch angepasst, dass sie immer an einer 4kb aligned Adresse steht. Hier nochmal der überarbeitete Code und auch die überarbeitete Funktion:
Code: (C) [Auswählen]
void setPML4Entry(uint8_t i, PML4_t *PML4, uint8_t Present, uint8_t RW, uint8_t US, uint8_t PWT,
uint8_t PCD, uint8_t A, uint16_t AVL, uint8_t NX, uint64_t Address)
{
PML4->PML4E[i] = 0;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] = (Present & 1);
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= (RW & 1) << 1;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= (US & 1) << 2;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= (PWT & 1) << 3;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= (PCD & 1) << 4;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= (A & 1) << 5;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= (AVL & 0x7LL) << 9;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= Address & 0xFFFFFFFFFF000LL;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= ((AVL >> 3) & 0x7FFLL) <<52;
asm("invlpg %0": :"m" (*PML4));
PML4->PML4E[i] |= (NX & 1LL) << 63;
}

Code: (C) [Auswählen]
static struct{
uint64_t speicher[PAGE_ENTRIES * 2];
}Speicher[3 + MAP];
PML4_t *PML4;
PDP_t *PDP;
PD_t *PD;
PT_t *PT;

//Adressen für die Tabellen ausfindig machen: müssen 4kb aligned sein
register uintptr_t Adresse;
Adresse = (uintptr_t)Speicher;
Adresse += 0x1000 - (Adresse & 0xFFF);
PML4 = (PML4_t*)Adresse;
PDP = (PDP_t*)(Adresse + 0x1000);
PD = (PD_t*)(Adresse + 2 * 0x1000);
PT = (PT_t*)(Adresse + 3 * 0x1000);

//Erste 6MB mappen

setPML4Entry(0, PML4, 1, 1, 0, 1, 0, 0, 0, 0, (uint64_t)(uint32_t)PDP);  //(uint32_t) ist nur da, damit der
                                                                                                             //Compiler kein Fehler ausgibt
for(i = 1; i < PAGE_ENTRIES; i++)
setPML4Entry(i, PML4, 0, 0, 0, 0, 0, 0, 0, 0, 0);

setPDPEntry(0, PDP, 1, 1, 0, 1, 0, 0, 0, 0, (uint64_t)(uint32_t)PD);
for(i = 1; i < PAGE_ENTRIES; i++)
setPDPEntry(i, PDP, 0, 0, 0, 0, 0, 0, 0, 0, 0);

for(i = 0; i < MAP; i++)
setPDEntry(i, PD, 1, 1, 0, 1, 0, 0, 0, 0, (uint64_t)(uint32_t)(PT + i));
for(i = MAP; i < PAGE_ENTRIES; i++) //Rest mit nullen auffüllen
setPDEntry(i, PD, 0, 0, 0, 0, 0, 0, 0, 0, 0);

register int j;
for(i = 0; i < MAP; i++)
for(j = 0; j < PAGE_ENTRIES; j++)
setPTEntry(j, PT + i, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, (j * 4096) + (i * 512 * 4096));

Ich hoffe ihr könnt mir helfen.
Viele Grüsse
OsDevNewbie

Ein Computer ohne Betriebsystem ist nicht mehr wert als ein Haufen Schrott.
Ein Computer ist eine Maschine, die einem Lebewesen das kostbarste klaut, was sie selber nicht hat:
DIE ZEIT DES LEBENS

 

Einloggen