Virtual memory manager - revisited

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
psychobeagle12
Member
Member
Posts: 41
Joined: Wed Oct 26, 2011 9:31 am

Virtual memory manager - revisited

Post by psychobeagle12 »

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:

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;
}
The map / unmap routines:

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;
}
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:

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!!
}

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 ():

Code: Select all


vmmngr_set_pdbr (_page_directory_phys);

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!
My i386-based kernel: https://github.com/bmelikant/missy-kernel
Picking a name for my kernel was harder than picking my wife, so I just used her name until I decide!
psychobeagle12
Member
Member
Posts: 41
Joined: Wed Oct 26, 2011 9:31 am

Re: Virtual memory manager - revisited

Post by psychobeagle12 »

Ok, I'm more confused now than I was, because this is working on real hardware, but not on bochs. Nobody has ANY ideas? :( I have spent days over this trying to figure out where I went wrong!
My i386-based kernel: https://github.com/bmelikant/missy-kernel
Picking a name for my kernel was harder than picking my wife, so I just used her name until I decide!
User avatar
Shaun
Member
Member
Posts: 43
Joined: Mon Sep 17, 2012 3:14 am
Contact:

Re: Virtual memory manager - revisited

Post by Shaun »

Hi,

what's the value of your cr3, _new_page_dir or _page_directory ?

btw, could you post the linear address and error code that trigger the PF?.
psychobeagle12
Member
Member
Posts: 41
Joined: Wed Oct 26, 2011 9:31 am

Re: Virtual memory manager - revisited

Post by psychobeagle12 »

The value of CR3 on PF is 0x200000, which is where my new page directory is being loaded in vmmngr_initialize (it may change depending on the pmmngr and where free memory starts). The value of CR2 on PF is 0xd0000000, and I will look into the error code. The physical address accessed would be 0x201000 according to my print statements on block allocation. The page directory table looks like (the page directory is mapped to itself starting at 0xfffff000):

Code: Select all

<bochs:2> x /10x 0xfffff000
[bochs]:
0xfffff000 <bogus+       0>:	0x00080023	0x00000000	0x00000000	0x00000000
0xfffff010 <bogus+      16>:	0x00000000	0x00000000	0x00000000	0x00000000
0xfffff020 <bogus+      32>:	0x00000000	0x00000000
I found something funny with the page table, but am not sure how it's happening:

Code: Select all

<bochs:6> x /10x 0x202000 
[bochs]:
0x00202000 <bogus+       0>:	0x00000000	0x00000000	0x00000000	0x00000000
0x00202010 <bogus+      16>:	0x00000000	0x00000000	0x00000000	0x00000000
0x00202020 <bogus+      32>:	0x00000000	0x00000000
<bochs:7> x /10x 0x201000
[bochs]:
0x00201000 <bogus+       0>:	0x00201003	0x00000000	0x00000000	0x00000000
0x00201010 <bogus+      16>:	0x00000000	0x00000000	0x00000000	0x00000000
0x00201020 <bogus+      32>:	0x00000000	0x00000000
<bochs:8> 
As you can see, physical address 0x202000 does not contain any PTEs, though it should. It should because I get the following output from running the OS:

Code: Select all

I will attempt to map block 0x201000 to 0xd0000000...
The page table for 0xd0000000 has not been mapped, mapping to 0x202000...
Allocated test block to 0xd0000000
PAGE FAULT MESSAGE HERE...
It's been a few days since I looked at the code, so I will try to find more relevant information and repost...
My i386-based kernel: https://github.com/bmelikant/missy-kernel
Picking a name for my kernel was harder than picking my wife, so I just used her name until I decide!
psychobeagle12
Member
Member
Posts: 41
Joined: Wed Oct 26, 2011 9:31 am

Re: Virtual memory manager - revisited

Post by psychobeagle12 »

Solution: I wasn't flushing the TLB after unmapping pages. Added the same code to the end of the unmapping routine and now it's fine!
My i386-based kernel: https://github.com/bmelikant/missy-kernel
Picking a name for my kernel was harder than picking my wife, so I just used her name until I decide!
Post Reply