[SOLVED] Rewriting JamesM's Paging Code
Posted: Mon Feb 25, 2013 6:37 pm
After trying to use JamesM's code to help me implement paging in my kernel, I decided that it didn't completely fit my needs, so I decided to rewrite some portions of it. However, when I enable paging, there's an immediate triple fault.
I've looked at the disassembly, and it's definitely crashing on the line where paging gets enabled. Also, I've verified that the physical memory manager works and the page mapping function does what it's supposed to do to the page structure.
I've looked at the disassembly, and it's definitely crashing on the line where paging gets enabled. Also, I've verified that the physical memory manager works and the page mapping function does what it's supposed to do to the page structure.
Code: Select all
/* A bitmap of used and free pages */
unsigned int *pmm_pages;
unsigned int num_pmm_pages;
/* Allocate a physical memory page */
unsigned int pmm_alloc_page()
{
/* Find the first free page in physical memory */
unsigned int i, j;
for (i = 0; i < num_pmm_pages >> 5; i++)
{
for (j = 0; j < 32; j++)
{
/* If the bit is 0, set it to 1 and return the address */
if (!bit_test(pmm_pages[i], j))
{
pmm_pages[i] = bit_set(pmm_pages[i], j);
return (i << 17) + (j << 12);
}
}
}
}
/* Free a physical memory page */
void pmm_free_page(unsigned int address)
{
/* Find the bit that corresponds to the address and set it to 0 */
pmm_pages[address >> 5] = bit_clear(pmm_pages[address >> 5], address % 32);
}
/* Initialize the physical memory manager */
void init_pmm(unsigned int size)
{
/* Create the bitmap of used and free pages */
num_pmm_pages = size / 0x1000;
pmm_pages = (unsigned int*) kmalloc(num_pmm_pages >> 5);
}
Code: Select all
/* Map a virtual address to a physical address */
void map_page(page_directory_t *dir, unsigned int virtual_address, unsigned int physical_address, unsigned int flags)
{
/* Return the page that corresponds to the virtual address, creating it if it doesn't already exist */
page_t *page = get_page(dir, virtual_address, true, flags);
/* Map the page in the table to the physical address */
*((unsigned int*)page) = physical_address | flags | 0x01;
}
/* Unmap a virtual address */
void unmap_page(page_directory_t *dir, unsigned int virtual_address)
{
/* Return the page that corresponds to the virtual address */
page_t *page = get_page(dir, virtual_address, false, 0);
/* If the page already does not exist, return */
if (!page)
{
return;
}
/* Free the physical page and set the page to not present */
pmm_free_page(page->frame * 0x1000);
*((unsigned int*)page) = 0;
/* Invalidate the TLB entry */
asm volatile ("invlpg (%0)" :: "a" (virtual_address));
}
/* Map the kernel into a page directory */
void map_kernel(page_directory_t *dir)
{
unsigned int i, j;
/* If this is the kernel directory, we're initializing paging and need to allocate some pages from the physical memory manager */
if (dir == kernel_directory)
{
/* We need to identity map our kernel */
for (i = 0x100000; i < 0x400000; i += 0x1000)
{
map_page(dir, i, pmm_alloc_page(), 0x07);
}
}
}
/* Initialize paging and the kernel heap */
void init_vmm()
{
/* Create the kernel directory */
kernel_directory = (page_directory_t*) kmalloc_a(sizeof(page_directory_t));
memset(kernel_directory, 0, sizeof(page_directory_t));
kernel_directory->physicalAddr = (unsigned int)kernel_directory->tablesPhysical;
unsigned int i;
/* Identity map the first 1 MB of the address space, so that the VGA framebuffer and VM86 tasks will work */
for (i = 0; i < 0x100000; i += 0x1000)
{
map_page(kernel_directory, i, pmm_alloc_page(), 0x07);
}
/* Map our kernel into the kernel directory */
map_kernel(kernel_directory);
/* Switch to the the kernel directory */
switch_page_directory(kernel_directory);
/* Now, enable paging! */
unsigned int cr0;
asm volatile("mov %%cr0, %0" : "=r"(cr0));
cr0 |= 0x80000000;
asm volatile("mov %0, %%cr0" :: "r"(cr0));
}
/* Switch the current page directory to a new one */
void switch_page_directory(page_directory_t *dir)
{
current_directory = dir;
asm volatile("mov %0, %%cr3" :: "r"(dir->physicalAddr));
}