Ensuring Kernel-Space Consistency

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
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Ensuring Kernel-Space Consistency

Post by AJ »

Hi All,

I'm using the relatively common system of mapping my kernel in to each process space, which is now working quite nicely, I think.

Doing this, of course, each process has its own version of the page directory and, for the kernel space, shares common page tables.

I'm just trying to get my head around the kernel memory space when this happens, though. What's the most efficient way of ensuring that kernel memory is the same in each page table? Should I copy to each page directory every time memory is assigned, should I have a process that occasionally verifies the top of each page directory or is there another, more efficient way?

Cheers,
Adam
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Post by ~ »

The way I plan to do it is to dynamically change the addresses in the binary so I can load them anywhere in memory. So, the binaries would start at address 0, and I think that would be favored by the 64-bit architecture.

Maybe using an API through a call gate (at least for IA32), in that way I think it would be easier and the kernel memory addresses could be presented more easily.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Ensuring Kernel-Space Consistency

Post by Brendan »

Hi,
AJ wrote:Doing this, of course, each process has its own version of the page directory and, for the kernel space, shares common page tables.

I'm just trying to get my head around the kernel memory space when this happens, though. What's the most efficient way of ensuring that kernel memory is the same in each page table? Should I copy to each page directory every time memory is assigned, should I have a process that occasionally verifies the top of each page directory or is there another, more efficient way?
In this case, the only way for the kernel's memory space to become inconsistant is if you've got inconsistant page directory entries (e.g. a kernel page table mapped in one process' page directory that isn't mapped the same in another process' page directory). The only thing you'd need to do is ensure that the page directory entries are consistant for kernel space (the page table entries will always be consistant because the same physical pages are used as a the kernel page tables in all processes).

The easiest way to do this is to map the physical page used for each process' page directory into a table in kernel space, so that when a page directory entry that corresponds to kernel space is changed you can change it in all processes at the same time.

Alternatively, some people allocate all kernel page tables during boot and never change kernel page directory entries after that. It's even easier, but less flexible and less efficient.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

Thanks for this.

I had always dismissed the last option as too inefficient. Thinking about it, it's only a hobby OS which I am running on my home PC which has 2GB RAM - so what's 1MB of wasted space :) .

Also, I wouldn't then have to worry about paging in and out when the kernel heap manager frees memory.

Thanks,
Adam
User avatar
Happy Egghead
Member
Member
Posts: 32
Joined: Thu Oct 19, 2006 5:25 am
Location: Adelaide, Australia
Contact:

Post by Happy Egghead »

I use the 'lazy update' scheme in my memory manager. Basically in addtion to all the tasks Page Directories I have a single master page directory for the kernel. When memory is allocated to the kernel I update this and the current task page directory.
When another task is switched to, the kernel page faults (if it tries to accesss that memory - it may not). It's in the page faulting code that the tasks PD is compared to the master kernel PD and if they differ the tasks PD is updated. On the other hand if both are zero then something has gone wrong in the kernel (accessing unallocated memory).

The code I'm using goes like this (please pardon the verbose commenting and debugging code)-

Code: Select all

void page_fault_handler(uint_t paging_error_reason)
{
	
	uint_t page_fault_address;
	uint_t dir_ent;
	
#ifdef debug
	kprintf("Paging fault.\n");
#endif	

	page_fault_address = (uint_t)read_cr2();

	dir_ent = (page_fault_address >> 22) + 1;

	
#ifdef debug
	kprintf("Page fault address = %x.\n", page_fault_address);
#endif

	switch (paging_error_reason)
	{
		case 0:
			// first we check the kernel page directory to see if this directory needs to be updated
			// if so, update and continue on
			// if not, something wrong with ALL the mapping :-(
			if ((PDmap[dir_ent] == 0) && (kernel_page_directory[dir_ent] != 0))
			{
				PDmap[dir_ent] = kernel_page_directory[dir_ent];
				return;
			}
#ifdef debug			
			kprintf("A program executing at supervisor privilege level attempted a read resulting\n");
			kprintf("in a page table or page not present condition.\n");
#endif			
			break;
		case 1:
			// first we check the kernel page directory to see if this directory needs to be updated
			// if so, update and continue on
			// if not, something wrong with ALL the mapping :-(
			if ((PDmap[dir_ent] == 0) && (kernel_page_directory[dir_ent] != 0))
			{
				PDmap[dir_ent] = kernel_page_directory[dir_ent];
				return;
			}
 .......... handle other faults here (more system and all user)
}
The good things I see is that only single 4k page is used and at most one page fault per application is needed to keep everything updated.
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

I used to simply keep a small static-array of page-directory entries for the kernel reserved address space. When I needed to map a page table in kernel, I'd just update the current context, and the static array. You'd always have either 0 or a valid entry in any given page directory, so just copy the entry from the static-array.

I'm not doing this anymore though. Now I just map page tables for the whole kernel at boot time. Since I map kernel pages as global, it potentially saves a page fault here and there. No idea if it makes a difference either way..
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

@brendan: Fantastic! My kernel service interrupts are working much more smoothly for having just lost that 1mb of physical ram to page tables. Thanks for reminding me that this way of doing it was a viable option.

@everyone else: Cheers for the various ways of doing things - i will certainly be giving them all a go - after all, I wrote my OS in order to learn stuff.

Thanks again,
Adam
Post Reply