ESP0 problem [ recursive switches usermode / kernelmode ]
Posted: Thu Feb 15, 2007 1:03 pm
I just implemented simple pipes. My OS does not support real multitasking, but I use the following way:
If I callprocess <b> is started. When <b> calls a syscall to read a character from stdin the scheduler switches to process <a>. When <a> calls a syscall to write a character to stdout, this character is passed as return code to process <b> and process <b> gets active.
I use a very unclean implementation of that, but it works for simple examples, likeIf I try a more complex one, likemy kernel crashes because of a stack overflow ( "hexdump hw" calls more than a thausend times putc cause hw is statically linked to my libc-port ) .
Here are some excerpts from my syscalls. I know that they flood the stack, but I don't know how to fix that ...
Excerpt from syscall #0 ( putc )Excerpt from syscall #1 ( readkey )CProcess::go() changes currentProcess and perform a far jmp to the tss of the process, more to it later 'cause I think there is a line which is mainly important to the error.
So what happens is that:
I call "a | b" . <b> is activated and calls syscall 1 ( readkey ). My kernel activates process <a>. Process <a> calls syscall 0 ( putc ) . <a> is only active when the master has called readkey so it passes the character as return code to the master and re-activate the master.
Now to the problem, which is mainly caused by CProcess::go(). Everytime the kernel does a task switch, CProcess::go() is used.The problem of course is "tss.stack[0].esp = getESP()-12;" . I did not think much about it when I wrote it ... I knew that it would cause errors later but it worked for a while ^^ ( unclean I know but I wanted some success ... ) ... getESP() should be clear, -12 because of the call to the assembler routine farJmp: There will be three more dwords pushed on the stack, the two params ( tr and 0 ) followed by the return address.
Maybe you already see the problem, but I give an example:
So lets use " a | b ". b has called readkey, and a has called putc, so the (kernel) stack could look like:Some day farJmp will return and pop stack data but then currentProcess->tss.stack[0].esp is set to this position. I think there is a very simple solution but I think too complicated ...
If I call
Code: Select all
$ a | b
I use a very unclean implementation of that, but it works for simple examples, like
Code: Select all
$ hw | hexdump
00000000: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 20 21 0A
Code: Select all
$ hexdump hw | more
Here are some excerpts from my syscalls. I know that they flood the stack, but I don't know how to fix that ...
Excerpt from syscall #0 ( putc )
Code: Select all
/* ... */
/* there is a master process so pass the character x to it */
currentProcess->master->tss.eax = x; // return value;
currentProcess->master->go();
/* ... */
Code: Select all
/* ... */
/* there is a slave process so activate it and wait for the character */
return currentProcess->slave->go();
/* ... */
So what happens is that:
I call "a | b" . <b> is activated and calls syscall 1 ( readkey ). My kernel activates process <a>. Process <a> calls syscall 0 ( putc ) . <a> is only active when the master has called readkey so it passes the character as return code to the master and re-activate the master.
Now to the problem, which is mainly caused by CProcess::go(). Everytime the kernel does a task switch, CProcess::go() is used.
Code: Select all
unsigned int CProcess::go() {
currentProcess = this;
tss.stack[0].esp = getESP()-12; // tss means this->tss. It's a local member of CProcess
return farJmp(tr,0); // tr is a local member, too
}
Maybe you already see the problem, but I give an example:
So lets use " a | b ". b has called readkey, and a has called putc, so the (kernel) stack could look like:
Code: Select all
syscall1 (readkey) // called by b
processA->go // called by kernel
farJmp // called by kernel
syscall0 ( putc ) // called by a
processB->go // called by kernel
farJmp // called by kernel