Virtual memory manager - revisited
Posted: Thu Jan 22, 2015 6:59 pm
I set out this week to finish my virtual memory manager. After realizing the chicken-and-egg scenario, I looked up possible solutions on the forum and found fractal mapping. It seemed very promising so I followed this example: http://www.rohitab.com/discuss/index.ph ... opic=31139 (btw thanks xWeasel!). I am using the mapping routines shown in the example. This is my initialization routine:
The map / unmap routines:
The code to initialize the manager works fine. I checked all the tables and everything is working as far as mapping. My kboot.asm file contains a routine that identity maps the first 4mb, and maps the kernel to 0xc0100000. The initialization routine obviously copies those tables. All of this is working fine. The problem is when I try to map a second block. The kernel contains code similar to this:
The problem is, the memory access creates a page fault. I have run the bochs debugger to the ground trying to track the issue. The tables get set up correctly, the processor simply does not access the page. It throws a page fault. I tried adding the following to the end of my vmmngr_map_page ():
to flush the TLB, but I still get the page fault. Does anyone see anything I did incorrectly, or need further info to help me? Thanks all!
Code: Select all
static unsigned int *_page_directory = 0;
static unsigned int *_page_directory_phys = 0;
int vmmngr_initialize () {
// allocate a new block for the new page directory
unsigned int *_new_page_dir = (unsigned int *) pmmngr_alloc_block ();
// get the ptr to the virtual and physical address of the original page directory (set up in kboot.asm)
_page_directory = (unsigned int *) 0xfffff000;
_page_directory_phys = (unsigned int *) (_page_directory[1023] &~ 0xfff);
// temporarily map the new page directory so we can modify it
if (vmmngr_map_page ((physical_addr) _new_page_dir, (virtual_addr) 0xD0000000) == -1)
return -1;
// copy the contents of the original directory to the new directory
memcpy ((void *) 0xD0000000, _page_directory, 1024*sizeof(unsigned int));
// map the last entry of the new directory to itself
_new_page_dir[1023] = (unsigned int) _new_page_dir | 3;
// place the new page directory into the pdbr
vmmngr_set_pdbr (_new_page_dir);
_page_directory_phys = _new_page_dir;
// now point the page directory * to the virtual addr of the pdir
_page_directory = (unsigned int *) 0xfffff000;
// unmap the temporary page and quit
vmmngr_unmap_page ((virtual_addr) 0xD0000000);
return 0;
}
Code: Select all
int vmmngr_map_page (physical_addr phys, virtual_addr virt) {
pageinf page_data = vmmngr_virt_to_page_index (virt);
// if the page is already allocated, just map it
if (_page_directory[page_data.ptable] & 1) {
unsigned int *p_table = (unsigned int *) (0xffc00000 + (page_data.ptable * 0x1000));
// if the page isn't mapped, map it
if (!(p_table[page_data.page] & 1))
p_table [page_data.page] = phys | 3;
else
return -1;
}
// otherwise, allocate a new page table then map
else {
unsigned int *p_table = (unsigned int *) pmmngr_alloc_block ();
unsigned int *new_entry = (unsigned int *) (0xffc00000 + (page_data.ptable * 0x1000));
_page_directory[page_data.ptable] = (unsigned int) p_table | 3;
new_entry[page_data.page] = phys | 3;
}
return 0;
}
physical_addr vmmngr_unmap_page (virtual_addr virt) {
pageinf page_data = vmmngr_virt_to_page_index (virt);
physical_addr phys = (physical_addr) 0;
// if the directory entry is mapped
if (_page_directory[page_data.ptable] & 1) {
unsigned int *p_table = (unsigned int *) (0xffc00000 + (page_data.ptable * 0x1000));
// the page is mapped, unmap it
if (ptable[page_data.page] & 1) {
phys = (physical_addr) (p_table[page_data.page] &~ 0xfff); // mask the lower bits
p_table[page_data.page] = 0x00;
}
int i;
// check for more ptes
for (i = 0; i < 1024; i++)
if (p_table[i] & 1)
break;
// if there were no ptes in the table, deallocate the table
if (i >= 1024) {
pmmngr_free_block ((void *) (_page_directory[page_data.ptable] & 0xfffff000));
_page_directory[page_data.ptable] = 0x00;
}
}
return phys;
}
Code: Select all
vmmngr_initialize () // it succeeds and everything works
char *block = (char *) pmmngr_alloc_block ();
if (block) {
vmmngr_map_page ((physical_addr) block, (virtual_addr) 0xD0000000);
char *block2 = (char *) 0xD0000000;
*block2 = 'H'; // PF here!!
}
Code: Select all
vmmngr_set_pdbr (_page_directory_phys);