Next, I also decided to rewrite the kernel heap code that I was using (which was mostly from JamesM's tutorial). However, doing this also revealed several problems in my entire memory manager. It contained several circular dependencies, such as the PMM and VMM calling the heap to allocate their structures (once again, a result of basing my code on JamesM's tutorial). So I decided to rewrite those as well, first of all, I wrote code to allocate the bitmap used by the PMM not using the heap, but by reserving free pages from the BIOS memory. Once again, this worked fine.
After the PMM was rewritten, I started rewriting the VMM. In order to access my page tables, I used a recursive page directory when higher half was first enabled:
Code: Select all
/* Add the page tables into the page directory */
pd[0] = (unsigned int) pt_lower | PAGE_KERNEL;
pd[512] = (unsigned int) pt_higher | PAGE_KERNEL | PAGE_FLAG_GLOBAL;
pd[575] = (unsigned int) pt_bitmap | PAGE_KERNEL | PAGE_FLAG_GLOBAL;
pd[1022] = 0;
pd[1023] = (unsigned int) pd | PAGE_KERNEL;
Code: Select all
/* Get a page */
page_t *get_page(unsigned int dir, unsigned int virtual_address, bool make, bool present, bool rw, bool user, bool global)
{
/* Construct the page flags */
unsigned int flags = 0;
if (present)
{
flags |= PAGE_FLAG_PRESENT;
}
if (rw)
{
flags |= PAGE_FLAG_RW;
}
if (user)
{
flags |= PAGE_FLAG_USER;
}
if (global)
{
flags |= PAGE_FLAG_GLOBAL;
}
/* Find out which page the virtual address in in */
unsigned int page = virtual_address >> 12;
/* Now use that page index to find out the index of the page table */
unsigned int table_index = page >> 10;
/* Get the address of the recursive page directory and recursive page table */
page_directory_t *directory = &((page_directory_t*) PAGE_STRUCTURES_START)[1023];
page_table_t *table = &((page_table_t*) PAGE_STRUCTURES_START)[table_index];
/* The page directory is mapped as the recursive page directory */
if (PAGE_FRAME(directory->tables[1023]) == dir)
{
}
/* The page directory is mapped as the secondary recursive page directory */
else if (PAGE_FRAME(directory->tables[1022]) == dir)
{
/* Choose the secondary recursive page directory */
directory = &((page_directory_t*) PAGE_STRUCTURES_START)[1022];
}
/* The page directory is not mapped in */
else
{
/* Map it in as the secondary recursive page directory */
directory->tables[1022] = dir | PAGE_KERNEL; // Page fault here
/* Flush the entire TLB */
flush_tlb();
/* Choose the secondary recursive page directory */
directory = &((page_directory_t*) PAGE_STRUCTURES_START)[1022];
}
/* If the page table already exists, return the page */
if (directory->tables[table_index])
{
return &table->pages[page % 1024];
}
/* If the table does not already exist and we want to make the page, create and return it */
else if (make)
{
/* Create a new page table */
directory->tables[table_index] = pmm_alloc_page() | PAGE_KERNEL;
flush_tlb();
memset(table, 0, 0x1000);
/* Return the page */
return &table->pages[page % 1024];
}
/* Otherwise, return 0 */
else
{
return 0;
}
}
/* Map a virtual address to a physical address */
void map_page(unsigned int dir, unsigned int virtual_address, unsigned int physical_address, bool present, bool rw, bool user, bool global)
{
/* Construct the page flags */
unsigned int flags = 0;
if (present)
{
flags |= PAGE_FLAG_PRESENT;
}
if (rw)
{
flags |= PAGE_FLAG_RW;
}
if (user)
{
flags |= PAGE_FLAG_USER;
}
if (global)
{
flags |= PAGE_FLAG_GLOBAL;
}
/* 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, present, rw, user, global);
/* Map the page in the table to the physical address */
*((unsigned int*) page) = physical_address | flags; // Page fault here
/* Invalidate the TLB entry */
asm volatile ("invlpg (%0)" :: "a" (virtual_address));
}
/* Create a new blank page directory */
unsigned int create_page_directory()
{
/* Allocate a page directory */
unsigned int dir = pmm_alloc_page();
/* Get the address of the recursive page directory */
page_directory_t *directory = &((page_directory_t*) PAGE_STRUCTURES_START)[1023];
/* Map the page directory in as the secondary recursive page directory */
directory->tables[1022] = dir | PAGE_KERNEL;
/* Flush the entire TLB */
flush_tlb();
/* Choose the secondary recursive page directory */
directory = &((page_directory_t*) PAGE_STRUCTURES_START)[1022];
/* Clear the page directory */
memset(directory, 0, sizeof(page_directory_t));
/* Return the physical address of the page directory */
return dir;
}
/* Initialize paging */
void init_vmm()
{
/* Set the address of the current directory */
asm volatile ("mov %%cr3, %0" : "=r"(current_directory));
/* Create the kernel directory */
kernel_directory = create_page_directory();
page_directory_t *directory = &((page_directory_t*) PAGE_STRUCTURES_START)[1023];
directory->tables[1023] = directory->tables[1022];
/* Flush the entire TLB */
flush_tlb();
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, i, true, true, false, true);
}
/* Map our kernel into the kernel directory */
for (i = 0; i < KERNEL_PHYSICAL_SIZE; i += 0x1000)
{
map_page(kernel_directory, KERNEL_VIRTUAL_START + i, KERNEL_PHYSICAL_START + i, true, true, false, true);
}
/* 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));
}
I've done some testing, and the page directory is mapped correctly until flush_tlb() gets called in init_vmm(), meaning that when I set the value of the last page table to the value of the second-to-last page table, that messed something up. Both recursive page directories are no longer mapped.
Also, here's the information that my page fault handler provides:
Code: Select all
Unhandled Page Fault Exception at 0xfffffff8, error code 0x00000002
Present: no, Access: write, Mode: supervisor
Register Dump
EAX: 00121003 EBX: 00000000 ECX: 00000001 EDX: 00121000
ESI: fffff000 EDI: ffc00000 ESP: 00000000 EBP: 00000000
CS: 00000008 DS: 00000010 ES: 00000010
FS: 00000010 GS: 00000010 SS: 00000000
EIP: 80002936 EFLAGS: 00010006
CR0: e0000011 CR2: fffffff8 CR3: 0011a000 CR4: 00000080