Page 1 of 1

Scheduler interupt problem

Posted: Sun Mar 19, 2006 8:44 am
by 0Scoder
Ok, I have an (almost) working scheduler. However after the first task is started, the timer interrupt is mysteriously never called again. That is however, unless I include an 'sti' statement in each task's code, in which case is works fine (ie tasks keep scheduling)! I'm setting eflags (on the stack to be popped off by the iret) to 0x206 (that is IF enabled), so I do not think that is the problem.

Can anyone offer some suggestions as to why this is not working, based on what I have said? I'll post the code later if need be, but no point making the post any bigger if it can be solved without it!

Thankyou very much in advance,
OScoder

Re:Scheduler interupt problem

Posted: Sun Mar 19, 2006 8:58 am
by paulbarker
When you do an IRET, the EFLAGS register is restored, as well as CS and EIP.

Chances are the EFLAGS you are restoring does not have IF set. In the code that creates a stack frame, TSS or whatever you are using to describe each task, you want to ensure that the tasks EFLAGS register will have IF set as needed.

I hope that makes sense I can't really say any more without seeing the code.

Re:Scheduler interupt problem

Posted: Mon Mar 20, 2006 7:29 am
by OZ
Do you send an EOI (end of interrupt) to the master pic just before you iret? Otherwise the pic doesn't know that you finished your interrupt routine and won't start sending interrupts again!

Code: Select all

mov al,20h
out 20h,al
look into the FAQ (click the banner above) for a more precise/correct explanation if needed.

Re:Scheduler interupt problem

Posted: Mon Mar 20, 2006 11:13 am
by 0Scoder
I've checked what's on the stack just before the iret, and eflags is set to 0x206 which, I think at least, contains the IF bit? Also, I do send an EOI. Any other things I could be doing wrong?

Asm code is here:
note - stack filler and scheduler to not restore or save registers apart from those used in the iret (for the the moment at least)...

Code: Select all

[BITS 32]
[GLOBAL _current_task_descriptor]
[GLOBAL _test_mockup]
[GLOBAL _fill_stack]

 _current_task_descriptor dd 0x00

_test_mockup:
;save current stack pointer
 mov ebx, [_current_task_descriptor]
 mov [ebx + 4], esp
 mov ecx, [ebx + 4]

;mov on to next task:
 mov ebx, [_current_task_descriptor]      ;make ebx point to task descriptor
 mov eax, [ebx]               ;make task descriptor point to first value in current task descriptor (which
 mov DWORD [_current_task_descriptor], eax   ;is the pointer to the next task on the list, if you get my drift...)

;get stack pointer of next task
 mov ebx, [_current_task_descriptor]
 mov eax, DWORD [ebx + 4]      ;put second value in the now current task descriptor (stack pointer) into eax
 mov esp, eax

;Tell the PIC that we have handled the interrupt
 mov al, 0x20
 out 0x20, al
iret

_fill_stack:
 mov edx, esp
 mov eax, [edx+4]
 mov ebx, [edx+8]
 mov ecx, esp
 mov esp, eax

 mov eax, 0x206
 push eax
 mov ax, 0x08
 push ax
 push ebx

 mov esp, ecx ;EIP = 11a5
ret
Also the c code:

Code: Select all

extern void fill_stack(ulong address, ulong eip);

struct task_descriptor tasknull;
struct task_descriptor task1;
struct task_descriptor task2;

ushort scheduler_init()
{
   idt_add_gate(   (unsigned long)&test_mockup,   /*Address of our handler*/
               _DPL_0 | _DESCRIPTOR_PRESENT | _DESCRIPTOR_INT_GATE,
               0x08 & 0xFFF8,   /*Decide selector from current code segment we are in*/
               _IRQ_0);      /*Interupt number - equal to irq0*/
   return(0);
}

ushort scheduler_test()
{
 /*Set up the stacks for our 'processes'*/
   task1.esp0=0x100500;
   task2.esp0=0x100400;
   fill_stack(task1.esp0, (unsigned long)&task1_function);
   fill_stack(task2.esp0, (unsigned long)&task2_function);
 /*Update esp0's*/
   task1.esp0=0x1004F6;
   task2.esp0=0x1003F6;
 /*Link tasks together so they can multitask*/
   tasknull.next=(unsigned long) &task1;
   task1.next=(unsigned long)&task2;
   task2.next=(unsigned long)&task1;
 /*Set current task descriptor as our first task*/
   current_task_descriptor=(unsigned long)&tasknull;
 /*Ok, now this is set up we just enable INTs, switch stacks and wait...*/
   enable_irq(0);
   asm("sti");
   asm("hlt");
}

void task1_function()
{
 _print("Task1",0xDF,1);
 asm("hlt");
}

void task2_function()
{
 _print("Task2",0xDF,2);
 asm("hlt");
}
The tasks are stored in a linked list, if that makes any difference...

Thanks for your help so far,
OScoder

Re:Scheduler interupt problem

Posted: Mon Mar 20, 2006 8:58 pm
by Brendan
Hi,
OScoder wrote: I've checked what's on the stack just before the iret, and eflags is set to 0x206 which, I think at least, contains the IF bit? Also, I do send an EOI. Any other things I could be doing wrong?
You must send the EOI before you do the task switch.

Otherwise "task A" would recieve the IRQ and switch to "task B", and "task B" might not send the EOI at all. If "task A" gets the CPU back in 3 days time (for e.g.) then the EOI it sends will be 3 days late.


Cheers,

Brendan

Re:Scheduler interupt problem

Posted: Wed Mar 22, 2006 4:01 am
by _OScoder
How do you mean? I moved the EOI to the beggining of the handler (before I do anything else), and it seems to have made no difference....

Re:Scheduler interupt problem

Posted: Wed Mar 22, 2006 5:31 am
by Brendan
Hi,
_OScoder wrote:How do you mean? I moved the EOI to the beggining of the handler (before I do anything else), and it seems to have made no difference....
That is what I meant, but unfortunately sometimes there's 2 bugs and fixing one of them might not make a difference...

Have you tried single-stepping through everything with Bochs?


Cheers,

Brendan