Multiple Page directorys

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
spix
Member
Member
Posts: 128
Joined: Mon Jun 26, 2006 8:41 am
Location: Millicent, South Australia
Contact:

Multiple Page directorys

Post by spix »

Hi There,

I am having some trouble with my OS's memory, I think I have misunderstood paging. Currently my OS has just two tasks, the kernel task and a shell task running in ring 3.

I have 3 system memory areas, 0x0 - 0x0FFFFFFF is where the kernel is, 0x10000000 - 0x1FFFFFFF is where memory allocated for the kernel to use goes, 0x20000000 - 0x2FFFFFFF is where I buffer file system blocks.

When I set up the shell task, I use 0x40000000 - for the program and any extra memory it needs is added to that. I use the following code to create the tasks own page directory:

Code: Select all

uint32_t *phys_mem_new_page_dir() {
  uint32_t *new_page_dir;
  int i;
  int delta;
  // copy master page directory's layout
  delta = PAGE_SIZE;
  new_page_dir = (uint32_t *)phys_mem_blk_alloc();
  if (new_page_dir == NULL) return NULL;
    phys_map_mem((uint32_t)new_page_dir,(uint32_t)new_page_dir,3, PAGE_SIZE);
  // map the kernel area
  for (i=0;i<256;i++) {
    new_page_dir[i] = page_directory[i];
  }
  for (i=256;i<1023;i++) {
    new_page_dir[i] = 0 | 2;
  }
  new_page_dir[1023] = (uint32_t)new_page_dir | 3;
  return new_page_dir;

}
The problem is, when my buffer system needs more buffers while it is in user mode, it maps into the kernel's page directory but it seems to be unavailable in the application's page directory.

However my system page faults when trying to access the newly allocated buffers.

My operating system only reloads cr3 on a task switch, so, when an irq happens cr3 is loaded with the last applications page directory.

The idea of my code above was that by copying the first 256 page tables, if i mapped a new entry in any of those first 256 areas, it would instantly change all the page tables.

Should the above code work like that? I am not sure if it is correct, my bugs must be from some other cause.

Thanks..
chasetec

Re:Multiple Page directorys

Post by chasetec »

It's hard to tell with your code but are you setting the User/Supervisor bit to 1 in your table entries (0x4)?
User avatar
spix
Member
Member
Posts: 128
Joined: Mon Jun 26, 2006 8:41 am
Location: Millicent, South Australia
Contact:

Re:Multiple Page directorys

Post by spix »

Thanks for the help, I think I have fixed the problem..

I think when I was allocating new directory entries (that contained page table entries) I wasn't copying them to the correct page directory.

Anyway, things seem to be working now..

thanks.
User avatar
spix
Member
Member
Posts: 128
Joined: Mon Jun 26, 2006 8:41 am
Location: Millicent, South Australia
Contact:

Re:Multiple Page directorys

Post by spix »

Hi again...

I am having some more problems.. I just can't quite get my head around paging.

I'm trying to implement a fork() routine for my OS, originally I had this:

Code: Select all

  uint32_t *phys_mem_new_page_dir() {
  uint32_t *new_page_dir;
  uint32_t *old_page_dir;

  int i;

  new_page_dir = (uint32_t *)phys_mem_blk_alloc();
  old_page_dir = (uint32_t *)current->cr3;

  if (new_page_dir == NULL) return NULL;      
  phys_map_page(new_page_dir, new_page_dir, 3);
  // map the kernel area

  for (i=0;i<1023;i++) {
    new_page_dir[i] = old_page_dir[i];
  }

  new_page_dir[1023] = (uint32_t)new_page_dir | 3;
  return new_page_dir;

}
It worked ok. I could fork and execute another program.

Then I learnt that fork is supposed to provide a new address space. Whereas above I seem to be duplicating the entrys of the old page directory, not duplicating the table entrys?

if I understand correctly, page_directory[0...1024] contains 1024 page tables and each page table contains 1024 pages.

now in my implementation, i have the page directory mapped into itself. I have done this by setting page_directory[1024] = page_directory.

Now, in my OS, I use 0x40000000 ... for application memory, below that is reserved for the kernel, and I want to be the same for all processess.

To implement the fork command, I think I should copy the first 256 page_directory elements as above (it is kernel area that should be the same, and is shared) however for the rest, I think I should go through each page_directory elements (page tables), and if they exist, I should create a new page table and copy it's contents.

I'm having trouble doing this. I can't quite get my head around how to copy the entrys..

Maybe I just need to sleep on it.

Does what I have said make sense? Have I at least understood the problem?
chasetec

Re:Multiple Page directorys

Post by chasetec »

fork makes the process think that there are now 2 copies of a process, each with their own address space. Original implementations would have copied all the RSS of a process and make new page table directories & page tables.

Modern implementations typically make new page table directories & page tables but don't copy the RSS. Instead both processes would have their address spaces mapped on top of each other. Additional all the pages would be marked read only. When a write tries to occur the page handler would get invoked, make a duplicate of the page, edit one processes page table entry to the copy of the page, and mark that virtual address as writtable in both processes address space. If you did it very carefully you could probably even share some page tables. You could even have your fork keep the same pages and page tables/entires for pages that reside in RO segements and just always copy the areas like heap and stack and make new entries in the cloned process for those copied pages. Lots of options with fork and paging....
User avatar
spix
Member
Member
Posts: 128
Joined: Mon Jun 26, 2006 8:41 am
Location: Millicent, South Australia
Contact:

Re:Multiple Page directorys

Post by spix »

Modern implementations typically make new page table directories & page tables but don't copy the RSS. Instead both processes would have their address spaces mapped on top of each other. Additional all the pages would be marked read only. When a write tries to occur the page handler would get invoked, make a duplicate of the page, edit one processes page table entry to the copy of the page, and mark that virtual address as writable in both processes address space.
Thanks, that makes good sense. I've set up COW pages now in my forked tasks, I'm a little bit lost in the COW function.

ok, so this is where I am at:
  • fork() creates a new process with all the user memory in both the parent and the child proc as read only.
  • the pagefault routine detects that it was called because of a read-only user page and calls the COW function with the offending address..
  • the COW function copy's the data from the parent proc's page to a new page for the child proc and sets them both writable again.
It's the last step I'm a bit concerned about, what happens when we have something like this:

parent->child->subchild->subsubchild

and subchild calls a fault, child's memory is then copied to subchild and both set writable, what happens to subsubchild?

should step 3 propagate the changes not only to the parent and child, but also all the child's children?

Is that right?

Thanks again, you've been really helpful
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Multiple Page directorys

Post by Pype.Clicker »

the trick with COW is that you'll associate a "physical reference counter" with each pageframe. If you have e.g.

Code: Select all

parent->
   (child1->(subchild11)),
   (child2->(subchild21,subchild22))
and that noone has touch page X from the first fork, then page X is marked 'readonly' for everyone and has a reference count of 6.

Let's say subchild22 want to access it, it will get its own copy X'22 (1 ref) with and X has now refcount 5. If subchild22 now forks subsubchild 221, that one will have a ref to X'22 (now with 2 refs, and write-protected for both, of course).

Even if everyone but subchild11 has now a modified copy of X (e.g. we assume X has now decremented to 1 ref), the page is still write-protected for subchild11, but when subchild 11 try to modify it, it doesn't need to copy, because the fact X.refs==1 means we're now the only process to reference the initial version. So you can just set the "write" bit for the page and live happy.
Post Reply