Multitasking - Stack/Execution problem
Posted: Fri Sep 28, 2012 3:43 am
Hey guys
Currently i am implementing my multitasking system. The other things are working so far, the paging system is disabled as long as i cant figure out my problem described here.
I basically use the method from JamesM's kernel tutorial, except that I am not storing my process list as a linked list (i dont want to use kmalloc) but as a plain list in the memory starting at MEMLOC_PROCESS_LIST. So I declare constants for each area of my kernel memory specifying the use of that specific place.
So when the multitasking is initialized, the kernel first creates its own process. Then the first switchProcess() call occurs and the kernels esp/ebp/eip are stored in the process structure.
Then a new process is spawned by calling the fork() method and from then on my switchProcess() method should switch stack and instruction pointer on each call. But there seems to be a problem when restoring my stack: qemu crashes and tells me that I tried to execute code outside RAM.
qemu: fatal: Trying to execute code outside RAM or ROM at 0x6e726c4c
I guess this could be a problem with the stack switching causing the processor to interprete a value on the stack as a function pointer and trying to execute it.
EDIT On the beginning my kernel stack is moved to 0x300000, limit at 0x250000.
Paging::createUserspace(..., ...) creates a clone of the kernel directory and makes the given range accessible to user priviledged code, but this shouldn't be a problem here because paging is not enabled.
So this is my scheduler code:
This code is called by the kernel here:
Can anyone figure out my problem??
I've been looking in a lot of places but I just can't see whats wrong.
Thanks in advance!
Max
Currently i am implementing my multitasking system. The other things are working so far, the paging system is disabled as long as i cant figure out my problem described here.
I basically use the method from JamesM's kernel tutorial, except that I am not storing my process list as a linked list (i dont want to use kmalloc) but as a plain list in the memory starting at MEMLOC_PROCESS_LIST. So I declare constants for each area of my kernel memory specifying the use of that specific place.
So when the multitasking is initialized, the kernel first creates its own process. Then the first switchProcess() call occurs and the kernels esp/ebp/eip are stored in the process structure.
Then a new process is spawned by calling the fork() method and from then on my switchProcess() method should switch stack and instruction pointer on each call. But there seems to be a problem when restoring my stack: qemu crashes and tells me that I tried to execute code outside RAM.
qemu: fatal: Trying to execute code outside RAM or ROM at 0x6e726c4c
I guess this could be a problem with the stack switching causing the processor to interprete a value on the stack as a function pointer and trying to execute it.
EDIT On the beginning my kernel stack is moved to 0x300000, limit at 0x250000.
Paging::createUserspace(..., ...) creates a clone of the kernel directory and makes the given range accessible to user priviledged code, but this shouldn't be a problem here because paging is not enabled.
So this is my scheduler code:
Code: Select all
extern "C" unsigned int _readEIP();
Process* processListBase = (Process*) MEMLOC_PROCESSLIST;
Process* currentProcess = 0;
int processCount = 0;
int schedulingIndex = 0;
int nextProcessId = 1;
void Scheduler::initialize() {
asm volatile("cli");
Process* process = &processListBase[processCount++];
process->id = nextProcessId++;
process->esp = 0;
process->ebp = 0;
process->eip = 0;
process->pageDirectory = Paging::getKernelDirectory();
process->used = true;
currentProcess = process;
asm volatile("sti");
}
int Scheduler::fork(unsigned int startAddress, unsigned int endAddress) {
asm volatile("cli");
Process* parentProcess = currentProcess;
unsigned int *processDirectory = Paging::createUserspace(startAddress,
endAddress);
Process* newProcess = &processListBase[processCount++];
newProcess->id = nextProcessId++;
newProcess->esp = 0;
newProcess->ebp = 0;
newProcess->eip = 0;
newProcess->pageDirectory = processDirectory;
newProcess->used = true;
// Entry point
unsigned int eip = _readEIP();
if (currentProcess == parentProcess) {
unsigned int esp;
unsigned int ebp;
asm volatile("mov %%esp, %0" : "=r"(esp));
asm volatile("mov %%ebp, %0" : "=r"(ebp));
newProcess->esp = esp;
newProcess->ebp = ebp;
newProcess->eip = eip;
asm volatile("sti");
return newProcess->id;
} else {
return 0;
}
}
Process* Scheduler::nextProcess() {
schedulingIndex++;
if (schedulingIndex > processCount - 1) {
schedulingIndex = 0;
}
return &processListBase[schedulingIndex];
}
void Scheduler::switchProcess() {
if (processCount > 0) {
unsigned int eip;
unsigned int esp;
unsigned int ebp;
asm volatile("mov %%esp, %0" : "=r"(esp));
asm volatile("mov %%ebp, %0" : "=r"(ebp));
eip = _readEIP();
if (eip == 0x12345) {
return;
}
// Store registers
currentProcess->eip = eip;
currentProcess->esp = esp;
currentProcess->ebp = ebp;
// Schedule
currentProcess = nextProcess();
// Load registers
eip = currentProcess->eip;
esp = currentProcess->esp;
ebp = currentProcess->ebp;
unsigned int currentDirectory =
(unsigned int) currentProcess->pageDirectory;
asm volatile(" \
cli; \
mov %0, %%ecx; \
mov %1, %%esp; \
mov %2, %%ebp; \
mov %3, %%cr3; \
mov $0x12345, %%eax; \
sti; \
jmp *%%ecx "
: :
"r"(eip),
"r"(esp),
"r"(ebp),
"r"(currentDirectory));
}
}
int Scheduler::getPid() {
return currentProcess->id;
}
Code: Select all
Scheduler::initialize();
int pid = Scheduler::fork(0x10000000, 0x10100000);
cout.print("Fork returned ");
cout.println(Integer::toString(pid));
cout.print("I am process ");
cout.println(Integer::toString(Scheduler::getPid()));
I've been looking in a lot of places but I just can't see whats wrong.
Thanks in advance!
Max