More odd page faults
Posted: Sun Jul 19, 2009 12:02 am
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:
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:
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?
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));
}
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