Stack for new process? Multitasking Errors?

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
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Stack for new process? Multitasking Errors?

Post by pcmattman »

I'm rewriting my multitasker so that during initialization I can push/pop anything off it's stack.

At the moment, this is my stack initialization code:

Code: Select all


	// have some fun setting up the stack
	stackSpace--;	
	*stackSpace-- = 0x0202; // EFLAGS
	*stackSpace-- = 0x08; // cs for cleanup	
	*stackSpace-- = (unsigned int) &procret; // eip for cleanup
	// *stackSpace-- = (args); // args for main function would be pushed here;
	*stackSpace-- = 0x08; // cs for eip
	*stackSpace-- = (unsigned int) addr; // EIP	
	*stackSpace-- = 0; // ebp	
	*stackSpace-- = 0; // esp
	*stackSpace-- = 0; // edi
	*stackSpace-- = 0; // esi
	*stackSpace-- = 0; // edx
	*stackSpace-- = 0; // ecx
	*stackSpace-- = 0; // ebx
	*stackSpace-- = 0; // eax
	*stackSpace-- = 0x10; // ds
	*stackSpace-- = 0x10; // es
	*stackSpace-- = 0x10; // fs
	*stackSpace = 0x10; // gs
The problem is, my cleanup function never gets called, the procedure just crashes with an 'Invalid Opcode'...

The other thing is, often after 3 or 4 reschedules the system crashes with an Invalid Opcode error... this is really frustrating because everything looks correct. You can view my multitasker code on cvs at sourceforge (link in my sig) - it's in mt_lib.c.

Bochs log at time of crash:

Code: Select all

00059056454i[CPU0 ] LOCK prefix unallowed (op1=0x1be, attr=0x100, mod=0x40, nnn=0)
00238438000p[WGUI ] >>PANIC<< POWER button turned off.
00238438000i[SYS  ] Last time is 1176168683
00238438000i[CPU0 ] protected mode
00238438000i[CPU0 ] CS.d_b = 32 bit
00238438000i[CPU0 ] SS.d_b = 32 bit
00238438000i[CPU0 ] | EAX=00105e00  EBX=0010b000  ECX=000b836c  EDX=000003d5
00238438000i[CPU0 ] | ESP=0014fc6c  EBP=0014fca4  ESI=0002be8f  EDI=0002be94
00238438000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af PF cf
00238438000i[CPU0 ] | SEG selector     base    limit G D
00238438000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00238438000i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00238438000i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00238438000i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00238438000i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00238438000i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00238438000i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00238438000i[CPU0 ] | EIP=0010600d (0010600d)
00238438000i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00238438000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00238438000i[CPU0 ] >> jmp .+0xfffffffe (0x0010600d) : EBFE
00238438000i[     ] restoring default signal behavior
00238438000i[CTRL ] quit_sim called with exit code 1
Edit: just had a look at the wiki. From what I read, it seems I'm meant to pop all the old data off the stack and put that into the old process's structure, then after that push new values onto the stack?
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Never mind, I fixed the problems.

Now the only question I have is, how do I make sure that processes 'return' to a certain procedure? As I said earlier, mt_lib.c is on CVS on my sourceforge site, so if you can view that and give me an idea of how to let the processes do this properly then I would be very pleased.
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

As for your first post, well, depends.

If you are using one stack in kernel, you indeed need to store the values somewhere. As long as your stack is big enough, it's not so important whether you reuse the same space, or if you just push a new set of values, and return with those if you are returning to userspace.

Ofcourse many kernels (mine and Linux to name two) actually use one kernel stack per thread, in which case you essentially get to separate the two issues. You push values into stack on kernel entry, and pop then on kernel exit, and because the stack belongs to a single thread, you don't need to move them anywhere from there, because thread switching is now a separate issue, and is done simply by switching between stacks.

So it really depends on whether your kernel is multi-threaded on it's own, or just a glorified ISR. Either approach is valid.

As for your second post, I already wrote the above so I thought I'd share it anyway.

Now, for "return" in the sense of process exiting, the proper method is to have the process call exit() when it's done. You typically link in the beginning of a C program a file called crt0.S, which does something like this:

Code: Select all

   .text       // I actually use .section .startup to get it at the beginning, since my binaries are binary so far
   .global __start
__start:    // __start is the entry point given to linker
   jmp crtInit  // function that handles library initialization and what not
If you need to setup stack or do something other stuff like that, you put that before the jmp (or you could use call if you wanted) to crtInit.

Then you have something like this in crtInit:

Code: Select all

void _exit(int);
int main(void);

void crtInit(void) {
    _exit(main());
}
Ofcourse normally you'd do library init and whatever, and main() would take some arguments, but that demonstrates the point.

_exit() is then a system call (in my case with a wrapper in the library), that tells kernel "please destroy this process, here's the return value".
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

You can actually also structure it differently, and have separate init, and then call main() and then call exit() with main()'s return value, but .. you get the point.
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post by pcmattman »

Thankyou for your assistance. I'm going to implement something like that into the stdlib I'm developing so that it's safe and easy to create new processes.
Post Reply