Page 1 of 2

Something about multitasking

Posted: Thu Jan 26, 2017 1:23 pm
by Agola
Hi forum.

I'm debugging my multitasking code, because sometimes system goes crazy because of multitasking.

I suspect the code that jumps to first task;

Code: Select all

void start_tasking()
{
   asm volatile ("mov %0, %%eax" : : "a"(first_task->regs->eax));
   asm volatile ("mov %0, %%ebx" : : "b"(first_task->regs->ebx));
   asm volatile ("mov %0, %%ecx" : : "c"(first_task->regs->ecx));
   asm volatile ("mov %0, %%edx" : : "d"(first_task->regs->edx));
   asm volatile ("mov %0, %%esi" : : "S"(first_task->regs->esi));
   asm volatile ("mov %0, %%edi" : : "D"(first_task->regs->edi));

   asm volatile ("pushl $0x10"); // ss (kernel)
   asm volatile ("pushl %0" : : "m"(first_task->regs->esp)); // esp
   asm volatile ("pushf"); // flags
   asm volatile ("pushl $0x8"); // cs (kernel)
   asm volatile ("pushl %0" : : "m"(first_task->regs->eip)); // eip
   
   asm volatile("iret"); 
}
It simply uses iret to make cpu pop eip, esp, cs, ss, and flags. For testing I used their default values for flags, ss and cs, but I'm going to change them after tracking the bug.

What can I do?
Other code is good I think. I miss something that in front of my eyes. #-o

Thanks

Re: Something about multitasking

Posted: Thu Jan 26, 2017 1:33 pm
by dozniak
You can write this code correctly in the first place.

Have you tried disassembling this pile of poo to see what is actually in there?

Re: Something about multitasking

Posted: Thu Jan 26, 2017 1:39 pm
by Ch4ozz
You can start coding this in a new asm file.
Your compiler is an ******* (never forget this) and will never do what you say.
It will create function prologue and epilogue if you dont declare the function as naked, it also can mix all the asm lines in terms of order as it likes because you didnt make it into one asm statement.
The next thing is, it usually uses ecx, edx etc as base pointers to dereference values.
So your compiler overwrites all the registers you just set...
Drag this into https://www.onlinedisassembler.com/static/home/ or IDA or whatever disasm you like to check if its what you expected.

Re: Something about multitasking

Posted: Thu Jan 26, 2017 1:44 pm
by Agola
dozniak wrote:You can write this code correctly in the first place.

Have you tried disassembling this pile of poo to see what is actually in there?
Yes, didn't see anything strange.

Code: Select all

   asm volatile ("mov %0, %%eax" : : "a"(first_task->regs->eax));
   asm volatile ("mov %0, %%ebx" : : "b"(first_task->regs->ebx));
   asm volatile ("mov %0, %%ecx" : : "c"(first_task->regs->ecx));
   asm volatile ("mov %0, %%edx" : : "d"(first_task->regs->edx));
   asm volatile ("mov %0, %%esi" : : "S"(first_task->regs->esi));
   asm volatile ("mov %0, %%edi" : : "D"(first_task->regs->edi));
Compiler replaced here with pushes of each member of first_task->regs, and pops of them to registers, which is more elegant I think.

Then does the other pushes and calls iret, nothing strange.

Re: Something about multitasking

Posted: Thu Jan 26, 2017 2:03 pm
by iansjack
What happens when you single-step through the code in your debugger? At what point does it fail?

Re: Something about multitasking

Posted: Thu Jan 26, 2017 2:08 pm
by Agola
iansjack wrote:What happens when you single-step through the code in your debugger? At what point does it fail?
That happens not very often, so I haven't catch it with debugger yet.

Re: Something about multitasking

Posted: Thu Jan 26, 2017 2:14 pm
by iansjack
Do you have interrupt handlers for all interrupts and exceptions, including spurious interrupts?

Re: Something about multitasking

Posted: Thu Jan 26, 2017 4:46 pm
by Agola
After debugging, I've just found the problem.

Newlib is not thread-safe. I'm using mutex for thread-safeness, but sometimes it even can't do anything. Then boom, crash.
How can I patch newlib to be thread-safe?

One more possibility is Newlib is already thread-safe and I haven't seen it yet. :|

Re: Something about multitasking

Posted: Thu Jan 26, 2017 4:55 pm
by mikegonta
Agola wrote:After debugging, I've just found the problem.
Newlib is not thread-safe. I'm using mutex for thread-safeness, but sometimes it even can't do anything. Then boom, crash.
How can I patch newlib to be thread-safe?
One more possibility is Newlib is already thread-safe and I haven't seen it yet. :|

Re: Something about multitasking

Posted: Thu Jan 26, 2017 5:20 pm
by gerryg400
Agola wrote:After debugging, I've just found the problem.

Newlib is not thread-safe. I'm using mutex for thread-safeness, but sometimes it even can't do anything. Then boom, crash.
How can I patch newlib to be thread-safe?

One more possibility is Newlib is already thread-safe and I haven't seen it yet. :|
Which particular part of newlib is not threadsafe?

Re: Something about multitasking

Posted: Fri Jan 27, 2017 2:53 am
by MollenOS
I'm sorry for being skeptical and all that, but as another person in this thread mentioned that start_tasking code is a pile of poo, and I have a much easier time believing that it's your synchronization code and/or tasking code that is faulty.

Please do write all the tasking code in assembly where you can control prologue and epilogue, otherwise you'll end up destroying the stack. Also post your other tasking code.

Re: Something about multitasking

Posted: Fri Jan 27, 2017 5:41 am
by Agola
I rewrote the switch to new task code with assembly instead of c with inline assembly.
Then, found a new bug.

iret doesn't pop the esp off, causing a screw on idle task's stack.
Shouldn't iret pop the esp?

Also it even works with jmp with esp and ebp change.
But it need to work with iret, because I will use both user and kernel tasks, requiring cs and ss changes.

Code: Select all

.section .text

.align 16

.global switch_to_first_task
switch_to_first_task:
    push %ebp
    mov %esp, %ebp
    mov 8(%ebp), %eax
    mov 12(%ebp), %ebx
    mov %ebp, %esp
    pop %ebp

    mov %eax, %ebp
    mov %eax, %esp
    jmp %ebx
That works, but it doesn't work (iret doesn't pop the esp off)

Code: Select all

.section .text

.align 16

.global switch_to_first_task
switch_to_first_task:

    push %ebp
    mov %esp, %ebp
    mov 8(%ebp), %eax
    mov 12(%ebp), %ebx
    mov %ebp, %esp
    pop %ebp

    push $0x10
    push %eax
    pushf
    push $0x8
    push %ebx
    iret
Also found here: http://forum.osdev.org/viewtopic.php?f=1&t=24148

I'm afraid my code has more secret bugs that I haven't seen yet.

Re: Something about multitasking

Posted: Fri Jan 27, 2017 6:03 am
by MollenOS

Code: Select all

iret
Only pops ESP and SS off in case you are returning to a Ring3 code-segment, in kernel tasks (Ring0) iret doesn't pop the stack off and stays in the stack it has.

Re: Something about multitasking

Posted: Fri Jan 27, 2017 6:07 am
by Agola
MollenOS wrote:

Code: Select all

iret
Only pops ESP and SS off in case you are returning to a Ring3 code-segment, in kernel tasks (Ring0) iret doesn't pop the stack off and stays in the stack it has.
Then I should write a seperate IRQ0 handler to prevent stack problems.

Code: Select all

irq_common:
    pusha

    /* Save segment registers */
    push %ds
    push %es
    push %fs
    push %gs

    /* Call interrupt handler */
    push %esp
    call irq_handler
    add $4, %esp

    /* Restore segment registers */
    pop %gs
    pop %fs
    pop %es
    pop %ds

    /* Restore all registers */
    popa
    /* Cleanup error code and IRQ # */
    add $8, %esp
    /* pop CS, EIP, EFLAGS, SS and ESP */
    iret
Then I can easily change the esp. Changing esp with common irq handler is not a good idea.

It pushes all registers to esp, then pushes esp as a pointer of registers_t structure for c irq handler.
Then I change registers from registers_t pointer, so stack.
After it pops to registers, so my register values changes to their new values.

But iret doesn't pop off the esp because of no privilege change. Then esp doesn't change, causes serious bugs sometimes.

I had a big mutitasking problem like that before, then I thought I fixed it, but looks I couldn't.

Re: Something about multitasking

Posted: Fri Jan 27, 2017 6:14 am
by MollenOS
Exactly, you need to handle the timer that handles task-switching a bit differently than a irq_common.

While they can share the entry point of the interrupt, you need to code a different exit function for the one that does the task switching, instead of letting the interrupt handler return on a normal way, call a new function next_thread or whatever you want, where you do the special-exit routine