Page 1 of 1

Cloning page directory not working

Posted: Sun Jul 05, 2009 4:51 pm
by alethiophile
I am following James Molloy's kernel-development tutorial, working on multitasking. When I try to switch page directories to a directory that I made using the clone_directory call, I get a triple fault. I have isolated the fault to the switch_page_directory function, below.

Code: Select all

/* Set the page directory. */
void switch_page_directory(page_directory_t *dir) {
  current_directory = dir;
  /* Tell the CPU where the pagedir is. */
  asm volatile ("mov %0, %%cr3" : : "r" (dir->tablesPhysical));
  u32int cr0;
  /* Make sure paging is enabled. */
  asm volatile ("mov %%cr0, %0" : "=r" (cr0));
  cr0 |= 0x80000000; // enable paging bit                                                                                                                    
  asm volatile ("mov %0, %%cr0" : : "r" (cr0));
}
This is line-for-line like the one in the tutorial. When I put an infinite loop in the init_paging function, just after this call, it still triple faults, but when I put the loop immediately after the last inline asm in this function, it does not. My conjecture is that the new directory does not map the original stack (though it should), and hence when I try to return, it page faults, and the page fault code accesses the stack, so it double faults, et cetera. My clone_directory code is below:

Code: Select all

/* Clones a page directory, linking those tables that are used by the kernel and copying those
   not.
*/
page_directory_t *clone_directory(page_directory_t *src) {
  u32int phys;
  page_directory_t *new_dir = (page_directory_t *) kmalloc_ap(sizeof(page_directory_t), &phys);
  memset(new_dir, 0, sizeof(page_directory_t));

  u32int off = (u32int) new_dir->tablesPhysical - (u32int) new_dir;

  new_dir->physicalAddr = phys + off;

  u32int i;
  for (i = 0; i < 1024; i++) {
    if (!src->tables[i])
      continue;
    if (kernel_directory->tables[i] == src->tables[i]) { // If it's kernel, then link it.
      new_dir->tables[i] = src->tables[i];
      new_dir->tablesPhysical[i] = src->tablesPhysical[i];
    }
    else { // Else, copy it.
      u32int np;
      new_dir->tables[i] = clone_table(src->tables[i], &np);
      new_dir->tablesPhysical[i] = np | 0x07;
    }
  }
  return new_dir;
}

/* Clones a page table. */
page_table_t *clone_table(page_table_t *src, u32int *phys) {
  page_table_t *new_table = (page_table_t *) kmalloc_ap(sizeof(page_table_t), phys);
  memset(new_table, 0, sizeof(page_table_t));
  u32int i;
  for (i = 0; i < 1024; i++) {
    // If it's not allocated, than don't bother
    if (src->pages[i].frame) {
      // Allocate space for page
      alloc_frame(&new_table->pages[i], 0, 0);
      // Copy attributes of page
      if (src->pages[i].present) new_table->pages[i].present = 1;
      if (src->pages[i].rw) new_table->pages[i].rw = 1;
      if (src->pages[i].user) new_table->pages[i].user = 1;
      if (src->pages[i].accessed) new_table->pages[i].accessed = 1;
      if (src->pages[i].dirty) new_table->pages[i].dirty = 1;
      // Copy page data
      copy_frame(src->pages[i].frame * 0x1000, new_table->pages[i].frame * 0x1000);
    }
  }
  return new_table;
}
This is pretty much line-for-line like the tutorial. However, I have successfully built and run the tutorial, and it works fine. Does anyone have any insight into why there is this difference?

Re: Cloning page directory not working

Posted: Sun Jul 05, 2009 5:33 pm
by frank
There are some differences between the code in the tutorial and the downloadable code. The downloads get updated more often, so you should rely on the code in those.

Re: Cloning page directory not working

Posted: Sun Jul 05, 2009 5:58 pm
by alethiophile
I am comparing with the downloaded code.

Re: Cloning page directory not working

Posted: Sun Jul 05, 2009 7:19 pm
by JamesM
Frank is correct - there are minor typographical errors on the website sample code that are rectified in the downloadable code.

I keep them there to deter copy-pasters.

Re: Cloning page directory not working

Posted: Mon Jul 06, 2009 3:55 am
by Creature
If it still won't work after that, it's most likely a problem with either:
  • Your paging setup.
  • Your heap or memory allocator (which is being used to create the cloned directory in) not correctly page-aligning the data.
I've had this problem too and it was always one of the above cases. It can also be something different, but I suggest you especially look out for mistakes in heap page-aligning code and wrong page-alignments and such.

Re: Cloning page directory not working

Posted: Wed Jul 29, 2009 2:55 am
by steve23
I'm having problems with chapter 9. Multitasking too.
Using the tar files from the end of each chapter, all the chapters up to chapter 8 compile and run fine on my PC. But the chapter 9 multitasking code gives a kernel panic:

Page fault! ( present ) at 0x0x106d7815 - EIP: 0x106d7815
PANIC(Page fault) at paging.c:230

So I think there is a bug in the tutorial.
Part of the code moves the stack, and modifies some values on the new stack.
That sounds dangerous to me.

Re: Cloning page directory not working

Posted: Wed Jul 29, 2009 6:22 pm
by alethiophile
The downloaded code works fine for me; I just have bugs in my version.

Re: Cloning page directory not working

Posted: Fri Jul 06, 2012 11:13 am
by Dominator
steve23 wrote:I'm having problems with chapter 9. Multitasking too.
Using the tar files from the end of each chapter, all the chapters up to chapter 8 compile and run fine on my PC. But the chapter 9 multitasking code gives a kernel panic:

Page fault! ( present ) at 0x0x106d7815 - EIP: 0x106d7815
PANIC(Page fault) at paging.c:230

So I think there is a bug in the tutorial.
Part of the code moves the stack, and modifies some values on the new stack.
That sounds dangerous to me.
I had the same problem. Then I added

Code: Select all

 __asm__ volatile("cli")
and

Code: Select all

 __asm__ volatile("sti")
around switch_task(), which makes sense. The kernel now runs fine when compiled with gcc at -O0, however any optimization seems to screw it up.

Update: Seems like a stable fix even with gcc -O2/O3. I guess I was having issues with bochs. Also tried some mutex/spinlock which worked as well.

Re: Cloning page directory not working

Posted: Fri Jul 06, 2012 11:15 am
by Dominator
alethiophile wrote:The downloaded code works fine for me; I just have bugs in my version.
The downloaded binary works, but the one recompiled with gcc 4.6.3 has kernel panics.

Re: Cloning page directory not working

Posted: Fri Jul 06, 2012 11:40 am
by Dominator
JamesM wrote:Frank is correct - there are minor typographical errors on the website sample code that are rectified in the downloadable code.

I keep them there to deter copy-pasters.
Hi James, thanks for those awesome tutorials! While I'm not sure if my fix was correct, should the entire switch_task() function be made atomic?

Re: Cloning page directory not working

Posted: Mon Jul 09, 2012 5:09 am
by JamesM
Yeah the code's generally a bit ****. I'm working on new versions (actively, and will full intent to release by September for the doubters among you)...

Re: Cloning page directory not working

Posted: Mon Jul 09, 2012 6:56 am
by jbemmel
alethiophile wrote: My clone_directory code is below:

Code: Select all

/* Clones a page directory, linking those tables that are used by the kernel and copying those
   not.
*/
page_directory_t *clone_directory(page_directory_t *src) {
  u32int phys;
  page_directory_t *new_dir = (page_directory_t *) kmalloc_ap(sizeof(page_directory_t), &phys);
  memset(new_dir, 0, sizeof(page_directory_t));

  u32int off = (u32int) new_dir->tablesPhysical - (u32int) new_dir;

  new_dir->physicalAddr = phys + off;
After the memset, new_dir->tablesPhysical should be 0 right? so new_dir->physicalAddr = phys - (u32int) new_dir. I don't follow what's going on here, seem to be mixing physical and linear addresses?