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
Ensuring Kernel-Space Consistency
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.
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.
Re: Ensuring Kernel-Space Consistency
Hi,
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
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).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?
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.
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
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
- Happy Egghead
- Member
- Posts: 32
- Joined: Thu Oct 19, 2006 5:25 am
- Location: Adelaide, Australia
- Contact:
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)-
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.
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)
}
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..
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.
@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
@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