Cloning page directory not working
Posted: Sun Jul 05, 2009 4:51 pm
I am following James Molloy's kernel-development tutorial, working on multitasking. When I try to switch page directories to a directory that I made using the clone_directory call, I get a triple fault. I have isolated the fault to the switch_page_directory function, below.
This is line-for-line like the one in the tutorial. When I put an infinite loop in the init_paging function, just after this call, it still triple faults, but when I put the loop immediately after the last inline asm in this function, it does not. My conjecture is that the new directory does not map the original stack (though it should), and hence when I try to return, it page faults, and the page fault code accesses the stack, so it double faults, et cetera. My clone_directory code is below:
This is pretty much line-for-line like the tutorial. However, I have successfully built and run the tutorial, and it works fine. Does anyone have any insight into why there is this difference?
Code: Select all
/* Set the page directory. */
void switch_page_directory(page_directory_t *dir) {
current_directory = dir;
/* Tell the CPU where the pagedir is. */
asm volatile ("mov %0, %%cr3" : : "r" (dir->tablesPhysical));
u32int cr0;
/* Make sure paging is enabled. */
asm volatile ("mov %%cr0, %0" : "=r" (cr0));
cr0 |= 0x80000000; // enable paging bit
asm volatile ("mov %0, %%cr0" : : "r" (cr0));
}
Code: Select all
/* Clones a page directory, linking those tables that are used by the kernel and copying those
not.
*/
page_directory_t *clone_directory(page_directory_t *src) {
u32int phys;
page_directory_t *new_dir = (page_directory_t *) kmalloc_ap(sizeof(page_directory_t), &phys);
memset(new_dir, 0, sizeof(page_directory_t));
u32int off = (u32int) new_dir->tablesPhysical - (u32int) new_dir;
new_dir->physicalAddr = phys + off;
u32int i;
for (i = 0; i < 1024; i++) {
if (!src->tables[i])
continue;
if (kernel_directory->tables[i] == src->tables[i]) { // If it's kernel, then link it.
new_dir->tables[i] = src->tables[i];
new_dir->tablesPhysical[i] = src->tablesPhysical[i];
}
else { // Else, copy it.
u32int np;
new_dir->tables[i] = clone_table(src->tables[i], &np);
new_dir->tablesPhysical[i] = np | 0x07;
}
}
return new_dir;
}
/* Clones a page table. */
page_table_t *clone_table(page_table_t *src, u32int *phys) {
page_table_t *new_table = (page_table_t *) kmalloc_ap(sizeof(page_table_t), phys);
memset(new_table, 0, sizeof(page_table_t));
u32int i;
for (i = 0; i < 1024; i++) {
// If it's not allocated, than don't bother
if (src->pages[i].frame) {
// Allocate space for page
alloc_frame(&new_table->pages[i], 0, 0);
// Copy attributes of page
if (src->pages[i].present) new_table->pages[i].present = 1;
if (src->pages[i].rw) new_table->pages[i].rw = 1;
if (src->pages[i].user) new_table->pages[i].user = 1;
if (src->pages[i].accessed) new_table->pages[i].accessed = 1;
if (src->pages[i].dirty) new_table->pages[i].dirty = 1;
// Copy page data
copy_frame(src->pages[i].frame * 0x1000, new_table->pages[i].frame * 0x1000);
}
}
return new_table;
}