Autor Thema: Page-Fault trotz richtiger Tabelle  (Gelesen 2754 mal)

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« am: 11. February 2010, 23:49 »
Nabend zusammen,

habe gerade ein Problem mit der MMU.
Ich habe mir eine VMM geschrieben, die sich der MMU anpasst und verscuhe das System gerade an der i386-MMU.
Leider fliegt mir der Code, sobald ich Paging aktiviere (genau nach dem Befehl).
Habe mir alle Einträge angeschaut.
Die sehen gut aus.
Die Tabellen sind mit den Flags 0x3 gemappt und die Pages mit 0x103.
Müssten so ja stimmen für den Kernel-Space.

Hier mal der Code, der die Tabellen aufbaut:
index = kernel_space / level_info[1].managed_mem;
entries = 1;

//count the number of L1-table-entries to map the L1-table as a table
while((entries * level_info[1].level_entries) < level_info[0].level_entries)
entries++;

//map the L1-table as a table
for(i = 0; i < entries; i++){
l1_table[index - entries + i] =
((uint32_t)l1_table + i * level_info[1].managed_mem) | level_info[0].masks[FLAG_KRN_RW];
}

level_info[1].mapped_level_start = (void*)((index - entries) * level_info[1].managed_mem);

index -= entries + 1;

//create the table to map the L1-table
phys = (uint32_t)pmm_alloc((level_info[1].level_entries * sizeof(vmm_table_t)) / page_size , &errno);

//could not find enough memory for the table
if(errno == ERR_PMM_NO_FREE_MEM){
kprintf("PANIC: Could not find %#x, bytes for the L2-table to map the L1-table" , level_info[1].level_entries * sizeof(vmm_table_t));
while(1);
}

//FIXME: write code which supports unaligned memory
if((phys != 0) && ((phys % level_info[1].alignment) != 0)){
kprintf("PANIC: The VMM does not support wrong aligned memory\n");
kprintf("Tried to create the L2-table to map the L1-table\n");
kprintf("address: %p    alignment: %#x" , phys , level_info[1].alignment);
while(1);
}

memset((void*)phys , EMPTY , level_info[1].level_entries * sizeof(vmm_table_t));
l1_table[index] = phys | level_info[0].masks[FLAG_KRN_RW];
entries = 1;

while((entries * page_size) < (level_info[0].level_entries * sizeof(vmm_table_t)))
entries++;

for(i = 0; i < entries; i++){
((vmm_table_p)phys)[level_info[1].level_entries - entries + i] =
((uint32_t)l1_table + i * page_size) | level_info[1].masks[FLAG_KRN_RW];
}

level_info[0].mapped_level_start = (void*)((level_info[1].level_entries - entries) * page_size + (index * level_info[1].managed_mem));

#ifdef CONFIG_MAX_BOOT_STATUS
kprintf("\tmapped the L1-table at %p\n" , level_info[0].mapped_level_start);
kprintf("\tmapped the L2-table at %p\n" , level_info[1].mapped_level_start);
#endif /* CONFIG_MAX_BOOT_STATUS */

//create all tables
for(i = 0; i < index; i++){
phys = (uint32_t)pmm_alloc((level_info[1].level_entries * sizeof(vmm_table_t)) / page_size , &errno);

//could not find enough memory for the table
if(errno == ERR_PMM_NO_FREE_MEM){
kprintf("PANIC: Could not find %#x, bytes for the L2-table.\n" , level_info[1].level_entries * sizeof(vmm_table_t));
kprintf("Tried to map address %p -> %p" , level_info[1].managed_mem * i , level_info[1].managed_mem * i + level_info[1].managed_mem);
while(1);
}

//FIXME: write code which supports unaligned memory
if((phys != 0) && ((phys % level_info[1].alignment) != 0)){
kprintf("PANIC: The VMM does not support wrong aligned memory\n");
kprintf("Tried to create the L2-table to map the L1-table\n");
kprintf("address: %p    alignment: %#x" , phys , level_info[1].alignment);
while(1);
}

memset((void*)phys , EMPTY , level_info[1].level_entries * sizeof(vmm_table_t));

l1_table[i] = phys | level_info[0].masks[FLAG_KRN_RW];

Der Code mappt die L1- und L2-Tabellen und erstellt die Tabellen für den Kernel-Space.

Der folgende Code mappt einzelne Seiten:
//get the index of the L1-table
index = mmu_table_index((void*)((uint32_t)virt + i * page_size) , L1_TABLE , &errno);
//the L1-table is not supported
if(errno == ERR_MMU_UNSUPPORTED_TABLE){
kprintf("PANIC: the MMU does not support the L1-table");
while(1);
}

//it is not inside of the kernel space
if(l1_table[index] == EMPTY){
kprintf("PANIC: tried to map memory outside of the kernel-space\n");
kprintf("address: %p" , index * level_info[1].managed_mem + mmu_table_index((void*)((uint32_t)virt + i * page_size) , L2_TABLE , &errno) * page_size);
while(1);
}

l2_table = (vmm_table_p)(l1_table[index] & level_info[0].masks[FLAG_PHYS_ADDR]);

//get the index of the L2-table
index = mmu_table_index((void*)((uint32_t)virt + i * page_size) , L2_TABLE , &errno);
//the L2-table is not supported
if(errno == ERR_MMU_UNSUPPORTED_TABLE){
kprintf("PANIC: the MMU does not support the L2-table");
while(1);
}
l2_table[index] = ((uint32_t)phys + i * page_size) | level_info[1].masks[FLAG_KRN_RW];

Die index-Variable ist immer richtig gesetzt.

Woran kann es noch liegen, dass der Code fliegt?

Danke.

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

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 12. February 2010, 00:33 »
Ohne mir jetzt den Code angeschaut zu haben (morgen vielleicht), ist das ziemlich sicher ein Page Fault, den du bekommst. Der Emulator deines Vertrauens verrät dir genaueres: Zum einen wäre ein CPU-Dump, wenn die Exception fliegt, hilfreich (beim PF vor allem cr2 und der Errorcode; eip ist natürlich auch immer wichtig, aber das scheinst du ja schon zu kennen). Das andere, was du machen könntest, ist die VM direkt vor dem Fault anzuhalten und von Hand das fehlerhafte Mapping aufzulösen versuchen, indem du den Speicher des PD/der PT dumpst (in qemu geht der Registerdump mit info registers und der Speicherdump mit xp ). Wenn du den Fehler nicht findest, am besten mal die Ausgaben hier reinkopieren.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 12. February 2010, 18:55 »
Habe den Fehler gefunden, auch wenn ich nicht genau weiß, woran es liegt.

Hier ist der Fehlerhafte Code:
void mmu_switch_mm_context(void *context){
uint32_t cr3 , new_context = (uint32_t)context;

__asm__ __volatile__("mov %0 , %%cr3" : : "g" (cr3));
//PWT is set (Page-level Writes Transparent)
if(cr3 | (1 << 3)){
new_context |= (1 << 3);
}
//PCD is set (Page-level Cache Disabled)
if(cr3 | (1 << 4)){
new_context |= (1 << 4);
}

__asm__ __volatile__("mov %%cr3 , %0" : "=r" (new_context));
}

Es wird die Adresse von new_context in CR3 geschrieben.
Wie kann ich das beheben?
Außerdem ist mir aufgefallen, dass er die If-Abfragen nicht durchführt, sondern einfach die Bits setzt.
Woran liegt das?
Habe keine Optimierungen an.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 12. February 2010, 19:52 »
Es wird die Adresse von new_context in CR3 geschrieben.
Wie das? In deinem ganzen Code wird new_context nur geschrieben. Sein Wert (und erst recht seine Adresse) kann nie nach cr3 kommen.

Zitat
Außerdem ist mir aufgefallen, dass er die If-Abfragen nicht durchführt, sondern einfach die Bits setzt.
Woran liegt das?
Die Bedingungen sind immer wahr. In (cr | (1 << 4)) ist Bit 4 immer gesetzt, also ist der Wert ungleich null und damit wahr. Du meinst wahrscheinlich & statt |.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

rizor

  • Beiträge: 521
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 15. February 2010, 13:28 »
Danke, habe aus versehen die asm-Befehle vertauscht.
Nun funktioniert alles.
Programmiertechnik:
Vermeide in Assembler zu programmieren wann immer es geht.

 

Einloggen