About the ESP0 field...

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.
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 »

Well ATM I've redirected my scheduler to a new work in progress to do some quick testing. I've found some interesting things, mainly that it works well (with function calls :D) but after a couple of seconds I get an invalid opcode error... Any ideas why?
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

So you basicly call your scheduler something like below?

Code: Select all

    printf("ok going to call scheduler\n");
    schedule();
    printf("ok I got scheduled again\n");
edit: actually that's what Voix did in the clock interrupts interrupt handler until recently, without the prints ofcourse. Now there's a slightly more advanced scheme where you aren't allowed to call scheduler from interrupt/deferred context, but instead just mark that it should be called as soon as it's allowed again...
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 »

No, it works via the clock interrupt. And inside the scheduler is where the text is printed.

I currently have a simple loop:

Code: Select all

while( true );
Without any multitasking (but interrupts enabled) this will throw an invalid opcode instruction. Any ideas why?

Woah... If I take out the timer install function (ie. no timer interrupt) I have no problems. Now I have to figure out why.
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

This is a bit lengthy so I will just attach it:

I tried to cut out as much of the code that is irrelevant to basic multitasking as possible but some may still be in there. Also I hope that it is easy to understand but if not just ask more questions.
Attachments
help.txt
(9.46 KiB) Downloaded 97 times
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 »

Could I have a look at the struct you use for your processes?

Edit: oops, the comments made it hard to see :D
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 »

Hey, wow, thanks! This code works really well, apart from one thing. I still can't use function calls inside functions (at least not if they get preempted by the IRQ).

For instance, the following task will execute without any problems:

Code: Select all

void task()
{
    while( true )
        *(unsigned short*) ( 0xB8000 + ( 79 * 2 ) ) = ( 0x1F << 8 ) | 'M';
}
But this code will throw a GPF after each process has run and it's back to the first process again:

Code: Select all

void task()
{
	while( true )
	{
		kprintf( "a" );
	}
}
It'll print out lots of 'a' characters then die with a GPF. Bochs log at time of crash:

Code: Select all

00043354249e[CPU0 ] fetch_raw_descriptor: GDT: index (a407)1480 > limit (77)
00107478000p[WGUI ] >>PANIC<< POWER button turned off.
00107478000i[SYS  ] Last time is 1177919982
00107478000i[CPU0 ] protected mode
00107478000i[CPU0 ] CS.d_b = 32 bit
00107478000i[CPU0 ] SS.d_b = 32 bit
00107478000i[CPU0 ] | EAX=00000016  EBX=00157d07  ECX=000b8f28  EDX=870003d5
00107478000i[CPU0 ] | ESP=00157caf  EBP=00157cb7  ESI=00000000  EDI=00000000
00107478000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af PF cf
00107478000i[CPU0 ] | SEG selector     base    limit G D
00107478000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00107478000i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00107478000i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00107478000i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00107478000i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00107478000i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00107478000i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00107478000i[CPU0 ] | EIP=00107b0a (00107b0a)
00107478000i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00107478000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00107478000i[CPU0 ] >> jmp .+0xfffffffe (0x00107b0a) : EBFE
00107478000i[     ] restoring default signal behavior
00107478000i[CTRL ] quit_sim called with exit code 1
Any ideas why this happens?

Edit: wait. It seems to be fixed :? ... I don't get it.
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

You probably aren't restoring ESP correctly. If you inline the printing, it won't need ESP, whereas a function call obviously needs a return address, which is probably where it fails.
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 »

Well, I just did a test and I found that the timeslice I was giving each process was massive, and once I reduced it the problem went away (I think).

One question, how do I setup another function to be called when the task itself exits?
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Post by mystran »

pcmattman wrote:Well, I just did a test and I found that the timeslice I was giving each process was massive, and once I reduced it the problem went away (I think).

One question, how do I setup another function to be called when the task itself exits?
For kernel threads or for user threads?

For kernel threads, make a function like die() or something that kills the currently running thread. It can be a bit tricky as you can't free the stack while you still need it, so easiest thing is to have a separate "killer task" or something, and have die() send it a message that the task should be killed. You don't want die() to take any parameters if you want to have it called automatically upon return.

For user threads, add a system call like _exit() which calls die() internally.

For kernel threads then, if you want them to automatically return when the function they run returns, just build a suitable stack before starting the thread: put the address for die() as the return address. As long as die() needs no parameters, this'll work, even if it sounds funny. You can then put any parameters to your thread-function below the return address, if you want.
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 »

I did that, it worked perfectly.

One more question I have: where do I push arguments in this code:

Code: Select all

	// return addy
	esp--;
	*esp-- = 0x10;
	*esp-- = ( unsigned int ) userstack1 + 1024; // not sure this is necessary...
	*esp-- = 0x0202;
	*esp-- = 0x08;
	*esp-- = (unsigned int) &die; // kills the process
/** arguments pushed here? **/
	*esp-- = 0x0202;
	*esp-- = 0x08;
	*esp-- = (unsigned int) &task;
/** arguments pushed here? **/

/** registers pushed on stack, segments etc... **/
I think the arguments may have to be pushed after the line

Code: Select all

*esp-- = (unsigned int) &task;
Am I 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 »

OK, I still haven't figured out the whole arguments thing... But I'm getting there :D

The good news is, everything that didn't work in my old multitasker is working now! Thanks everyone for all your help, especially mystran and frank - your code really helped!

As a test, I setup a thread in my kernel called 'udp:4000' as a udp server on port 4000 that sends 'woot' back to anyone who sends it data. The other thread is the system procedure that prints an 'M' in the top right corner.

It didn't crash :D
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

I am always happy to see that I could help someone. If you still can't get the argument thing down then just holler and I will see if I can help you.
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 »

Yeah, I've been testing the whole argument thing and it turns out that if I run a task that takes two arguments, the two arguments I receive are the CS and EFLAGS pushed onto the stack before EIP...

Code: Select all

// base of the task
*esp-- = EFLAGS_IF | EFLAGS_IOPL0 | EFLAGS_ALWAYS1; // second?
*esp-- = 0x08; // task thinks this is first argument
*esp-- = base;
Any ideas why?
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Is this a user level task and are you putting the arguments on the user 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 »

It's a kernel thread.

Is that why, in your code, you do this?

Code: Select all

*esp-- = 32 + 3;    // user stack segment
*esp-- = (DWORD)user_stack;
Edit:
I did this:

Code: Select all

// user stack
*esp-- = 0x10;
*esp-- = ptable[i].ustack;

// base of the task
*esp-- = EFLAGS_IF | EFLAGS_IOPL0 | EFLAGS_ALWAYS1;
*esp-- = 0x08;
*esp-- = base;
And then when I got the argument from my task, it came out as 0x10? Why is it the stack segment, and not the actual data?
Post Reply