OSDev.org
https://forum.osdev.org/

Troubles implementing multitasking
https://forum.osdev.org/viewtopic.php?f=1&t=33096
Page 1 of 3

Author:  frabert [ Wed Aug 01, 2018 2:15 pm ]
Post subject:  Troubles implementing multitasking

I'm having some troubles implementing supervisor multitasking...

Currently, my setup is as follows:
- A task is created:
- The memory manager allocates a new page directory, the kernel directory gets copied into the new one
- A new page gets allocated for the stack, and is mapped to a very high region (because the stack grows downwards I believe?)
- The task is initialized:
- The initial state is set so that the esp = ebp = bottom of the page that was allocated previously, eip = address of the routine to execute
- The task is enqueued.

Once the timer ticks, this happens:
- The interrupt handler is called, its argument is a pointer to the registers that were pushed by the processor
- The currently running task is updated with the state that is found on the registers, and then re-enqueued
- The new task is dequeued, the registers on the stack are updated with the state of the new task
- The handler returns

The problem is, the moment the handler returns, the OS starts executing random stuff, like launching interrupts, which makes me think it's executing instructions from random memory locations, which makes me believe I must be doing something wrong... Can anyone shed some light for me?

Author:  Schol-R-LEA [ Wed Aug 01, 2018 5:13 pm ]
Post subject:  Re: Troubles implementing multitasking

Do you have an repo on a site such as Github or Sorceforge which you could give us a link to, so we can review the code?

Or conversely, could you please post the relevant code from the interrupt handler, scheduler, and so forth? This would give us a chance to see if there is some bug in it you might have missed.

Author:  Brendan [ Wed Aug 01, 2018 11:19 pm ]
Post subject:  Re: Troubles implementing multitasking

Hi,

frabert wrote:
I'm having some troubles implementing supervisor multitasking...

Currently, my setup is as follows:
- A task is created:
- The memory manager allocates a new page directory, the kernel directory gets copied into the new one
- A new page gets allocated for the stack, and is mapped to a very high region (because the stack grows downwards I believe?)
- The task is initialized:
- The initial state is set so that the esp = ebp = bottom of the page that was allocated previously, eip = address of the routine to execute
- The task is enqueued.


The stack grows downwards, so you'd want "esp = top of the page that was allocated" so that the stack can grow down from the top.

frabert wrote:
The problem is, the moment the handler returns, the OS starts executing random stuff, like launching interrupts, which makes me think it's executing instructions from random memory locations, which makes me believe I must be doing something wrong... Can anyone shed some light for me?


I'd recommend using a debugger (e.g. single-step one instruction at a time in Bochs) to watch exactly what the CPU does at each step, starting from a breakpoint at the start of the low-level task switch code.


Cheers,

Brendan

Author:  frabert [ Thu Aug 02, 2018 1:26 am ]
Post subject:  Re: Troubles implementing multitasking

Schol-R-LEA wrote:
Do you have an repo on a site such as Github or Sorceforge which you could give us a link to, so we can review the code?

Here. I will now try and see stepping the code as Brendan suggested with Bochs

EDIT: I was able to fix the first of the issues, https://github.com/frabert/toy-os/blob/master/tasking.cpp#L82 should read (uintptr_t)m_func, not (uintptr_t)&m_func, though now I am able to only run two tasks, and I have to put an infinite loop at the end of the functions I call, but that's just because I am not setting up the stack with a proper return pad I guess. After a while the functions throw a page fault, so maybe now it's messing with the paging...

Author:  frabert [ Sat Aug 04, 2018 1:13 am ]
Post subject:  Re: Troubles implementing multitasking

Hey I managed to get it almost working! :D

But I have another problem now. Stepping through the code instruction by instruction, I noticed that when executing "iretd", the esp register does not get updated at the end of the interrupt handler... What's the correct way of setting a new stack for the tasks?

Attachments:
Screenshot from 2018-08-04 09-10-55.png
Screenshot from 2018-08-04 09-10-55.png [ 7.46 KiB | Viewed 2748 times ]

Author:  TheCool1Kevin [ Sun Aug 05, 2018 5:41 pm ]
Post subject:  Re: Troubles implementing multitasking

About your esp, iret does not change it. It's up to your OS to update the esp on a context switch. Don't forget the TSS too.

It's your OS so do whatever makes sense (but be warned, bad design decisions come back to haunt you).
In my IRQ handler, I had in order:
Code:
irq_return:
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8 ; Error code and other shenanigans
    iret
And so I set up the stack like:
Code:
uint32_t *stack = (uint32_t *)malloc(4096);
stack = (uint32_t *)((int)stack + 4096);
stack -= 16; // Padding
*--stack = 0x10;        // ss
*--stack = 0x00;        // esp
*--stack = 0x202;       // eflags
*--stack = 0x08;        // cs
*--stack = entry_point; // eip
*--stack = 0x00;        // err_code
*--stack = 0x00;        // int_no
/* pushad */
*--stack = 0xCAFEBABE; // eax
*--stack = 0x00;       // ecx
*--stack = 0x00;       // edx
*--stack = 0x00;       // ebx
*--stack = 0x00;       // esp_dummy
*--stack = 0x00;       // ebp
*--stack = 0x00;       // esi
*--stack = 0x00;       // edi
/* Push segment registers */
*--stack = 0x10; // ds
*--stack = 0x10; // es
*--stack = 0x10; // fs
*--stack = 0x10; // gs
proc->thread.regs.registers = (void *)stack; // Top of stack

Then to switch tasks, I switch the ESP/page directories and jump to "irq_return" and let the cpu handle the rest. And so to run the task, I set up the task's stack and queue it, where the scheduler then changes the stack and the cpu pops the return address and runs the code. Not sure if it's THE way, but it works and so far nothing bad has happened.
Looking at your code, you do almost the same thing, except that your "switchTasks" works differently. It can't be that bad.

Author:  frabert [ Mon Aug 06, 2018 8:24 am ]
Post subject:  Re: Troubles implementing multitasking

What I can't wrap my head around is how to change the esp _after_ the iret, since if I change it before it would break the iret behavior, right?
But, if I can't do it before, how am I going to tell the newly created task where to look for its fresh stack?

Author:  iansjack [ Mon Aug 06, 2018 9:14 am ]
Post subject:  Re: Troubles implementing multitasking

After a task switch where do you want the iret to return to? Think about it.

Author:  frabert [ Mon Aug 06, 2018 10:20 am ]
Post subject:  Re: Troubles implementing multitasking

Well, to the eip of the resumed task as it was saved on suspension, right?

Author:  iansjack [ Mon Aug 06, 2018 10:51 am ]
Post subject:  Re: Troubles implementing multitasking

Right. Which stack is that going to be on?

Author:  frabert [ Mon Aug 06, 2018 11:03 am ]
Post subject:  Re: Troubles implementing multitasking

Its own, the one I have allocated when I initially created the task (in my case it's a whole page for simplicity)

Author:  iansjack [ Mon Aug 06, 2018 11:15 am ]
Post subject:  Re: Troubles implementing multitasking

So you change the stack pointer before the iret, so that it points to the correct stack (where the return address was pushed last time the task relinquished control).

Author:  frabert [ Mon Aug 06, 2018 11:25 am ]
Post subject:  Re: Troubles implementing multitasking

But if I change the esp before the iret, what is iret going to pop into the eflags and all of that? Or am I supposed to save all of that inside the task's stack too?

Author:  iansjack [ Mon Aug 06, 2018 11:57 am ]
Post subject:  Re: Troubles implementing multitasking

All that was saved when you called the interrupt that originally switched away from the task. Restoring cr3 and the stack pointer (plus all the other registers you have saved) returns the task to the state it was in before you switched.

Author:  TheCool1Kevin [ Mon Aug 06, 2018 12:09 pm ]
Post subject:  Re: Troubles implementing multitasking

yes. The interrupt handler should save all the registers (segment registers included); then when you switch tasks, you point esp to the new task's stack, and the interrupt handler should popa and pop the segment registers too. When iret is executed, the CPU pops the EIP and off you go.
Quote:
Restoring cr3 and the stack pointer (plus all the other registers you have saved)

CR3 does not get restored. Neither does ESP.

Also I should note that after you switch stacks, you should jump directly to your popa/iret instructions to avoid breaking the stack.

Page 1 of 3 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/