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