Troubles implementing multitasking

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.
frabert
Member
Member
Posts: 38
Joined: Wed Jul 25, 2018 2:47 pm
Location: Pizzaland, Southern Europe
Contact:

Troubles implementing multitasking

Post by frabert »

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?
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Troubles implementing multitasking

Post by Schol-R-LEA »

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.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Troubles implementing multitasking

Post by Brendan »

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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
frabert
Member
Member
Posts: 38
Joined: Wed Jul 25, 2018 2:47 pm
Location: Pizzaland, Southern Europe
Contact:

Re: Troubles implementing multitasking

Post by frabert »

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/ ... ng.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...
frabert
Member
Member
Posts: 38
Joined: Wed Jul 25, 2018 2:47 pm
Location: Pizzaland, Southern Europe
Contact:

Re: Troubles implementing multitasking

Post by frabert »

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 4224 times
User avatar
TheCool1Kevin
Posts: 24
Joined: Fri Oct 14, 2016 7:37 pm
Location: Canada
Contact:

Re: Troubles implementing multitasking

Post by TheCool1Kevin »

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: Select all

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: Select all

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.
LiquiDOS, my weird hobbyist OS.
"Strive for progress, not perfection" - Anonymous
frabert
Member
Member
Posts: 38
Joined: Wed Jul 25, 2018 2:47 pm
Location: Pizzaland, Southern Europe
Contact:

Re: Troubles implementing multitasking

Post by frabert »

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?
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Troubles implementing multitasking

Post by iansjack »

After a task switch where do you want the iret to return to? Think about it.
frabert
Member
Member
Posts: 38
Joined: Wed Jul 25, 2018 2:47 pm
Location: Pizzaland, Southern Europe
Contact:

Re: Troubles implementing multitasking

Post by frabert »

Well, to the eip of the resumed task as it was saved on suspension, right?
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Troubles implementing multitasking

Post by iansjack »

Right. Which stack is that going to be on?
frabert
Member
Member
Posts: 38
Joined: Wed Jul 25, 2018 2:47 pm
Location: Pizzaland, Southern Europe
Contact:

Re: Troubles implementing multitasking

Post by frabert »

Its own, the one I have allocated when I initially created the task (in my case it's a whole page for simplicity)
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Troubles implementing multitasking

Post by iansjack »

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).
frabert
Member
Member
Posts: 38
Joined: Wed Jul 25, 2018 2:47 pm
Location: Pizzaland, Southern Europe
Contact:

Re: Troubles implementing multitasking

Post by frabert »

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?
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Troubles implementing multitasking

Post by iansjack »

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.
User avatar
TheCool1Kevin
Posts: 24
Joined: Fri Oct 14, 2016 7:37 pm
Location: Canada
Contact:

Re: Troubles implementing multitasking

Post by TheCool1Kevin »

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.
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.
LiquiDOS, my weird hobbyist OS.
"Strive for progress, not perfection" - Anonymous
Post Reply