More odd page faults

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
alethiophile
Member
Member
Posts: 90
Joined: Sat May 30, 2009 10:28 am

More odd page faults

Post by alethiophile »

I am working on multitasking in JamesM's tutorial. I have set up the test mostly as it is in the tutorial; it calls fork(), then prints out the return value and pid value, in the expectation that these will be printed twice, with appropriate values. When I run the code, it prints the data correctly the first time, then the timer interrupt fires and it executes the task switcher.
The code for task_switch is below:

Code: Select all

void task_switch() {
  if (!current_task)
    return;
  printf("Task switching\n"); // debug
  u32int ebp, esp, eip;
  // Get the ESP and EBP
  asm volatile ("mov %%esp, %0" : "=r" (esp));
  asm volatile ("mov %%ebp, %0" : "=r" (ebp));

  eip = read_eip();
  /* Here, we could be in one of two states:
     1. task_switch() was called, and read_eip just returned
     2. We just switched tasks, and the suspended task resumed execution
        right after read_eip
     If 2, than we need to return now. Therefore, we put a dummy value in eax
     (which is the return value) at the end of this function. If that value is 
     in eax (and hence the variable eip above), then we just switched tasks, 
     because it's not really read_eip returning, it's just jumping to the inst
     that it would return to.
  */
  if (eip == 0x1234) {
    printf("Done task switching\n"); // debug
    return;
  }
  current_task->eip = eip;
  current_task->esp = esp;
  current_task->ebp = ebp;

  printf("old data: eip: 0x%x, ebp: 0x%x, esp:0x%x\n", eip, ebp, esp); // more debug
  current_task = current_task->next;
  if (!current_task) current_task = ready_queue;

  esp = current_task->esp;
  ebp = current_task->ebp;
  eip = current_task->eip;

  current_directory = current_task->page_directory;

  printf("new data: eip: 0x%x, ebp: 0x%x, esp:0x%x\n", eip, ebp, esp); // yet more debug
  asm volatile (
		"cli\n\t"
		"mov %0, %%ecx\n\t"
		"mov %1, %%esp\n\t"
		"mov %2, %%ebp\n\t"
		"mov %3, %%cr3\n\t"
		"mov $0x1234, %%eax\n\t"
		"sti\n\t"
		"jmp *%%ecx"
		: : "r" (eip), "r" (esp), "r" (ebp), "r" (current_directory->physicalAddr));
}
If I understand the code correctly, what should happen is it runs through the function the first time, stores the correct esp/ebp/eip values, set current_task and the page directory, then execute the asm code, which sets registers then jumps back to the inst after the call to read_eip(), first setting eax to 0x1234 for identifiability. The code then executes again from read_eip(), sees the dummy value in eip and so returns. Instead, I get a page fault, at an address that at first glance I shouldn't be writing to. The output:

Code: Select all

Initializing descriptor tables...        Done                                   
Initializing simple heap...        Done                                         
Initializing timer...        Done                                               
Initializing keyboard listener...        Done                                   
Initializing paging and heap...        Done                                     
Initializing initrd...        Done                                              
Initializing multitasking...        Done                                        
Calling fork()...        Done                                                   
fork() returned 2 and getpid() returned 1                                       
Task switching                                                                  
old data: eip: 0x103387, ebp: 0xdfffff14, esp:0xdffffefc                        
new data: eip: 0x1032f4, ebp: 0xdfffffcc, esp:0xdfffffa4                        
Page fault: present, at address 0x105e1015 in process 2                         
physical address 0xf000f                                                        
Kernel panic: Page fault at file paging.c, line #180                            
Does anyone know why this would happen? In particular, shouldn't the old and new eip be the same? If I understand correctly, they should both simply be the inst after the call to read_eip() in task_switch(), and so be the same. Is this correct?
If I had an OS, there would be a link here.
User avatar
alethiophile
Member
Member
Posts: 90
Joined: Sat May 30, 2009 10:28 am

Re: More odd page faults

Post by alethiophile »

Update: It turns out that the child process should be returning to fork(), rather than task_switch(), since it hasn't been switched to yet. I put some code in fork()'s child-return block to print the address it would return to, and it appears that that is the address that is page faulting. Therefore, I suspect that the problem is in my clone_directory function, which I have already had problems with, and which is line for line like that in the tutorial. Sigh.
If I had an OS, there would be a link here.
Post Reply