Page 1 of 1
Unable to call a C-Function after task switch
Posted: Wed Oct 05, 2011 4:16 pm
by eltomato
Hi,
I just implemented Multitasking in my os and it works .. But there is a big problem left ..
I can't use any C-Functions .. If I do that, it crashs with a general protection fault :/
inline asm works fine .. now I have a operating system, which beeps all the time (with outb) but
can't do anything else
Any Idea?
Re: Unable to call a C-Function after task switch
Posted: Wed Oct 05, 2011 4:38 pm
by NickJohnson
Is your stack in a reasonable state after the task switch? Inline assembly doesn't always use the stack, but C functions do.
Re: Unable to call a C-Function after task switch
Posted: Wed Oct 05, 2011 4:49 pm
by eltomato
hmm.. it's working in QEmu .. But VMWare 8 shows a panic :/
My Task Switch looks like this:
Code: Select all
extern _irq_handler
irq_common_stub:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp
call _irq_handler
mov esp, eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
this returns the cpu registers of the next task ..
Code: Select all
struct regs* irq_handler(struct regs *r)
{
struct regs* new_cpu = r;
/* ... */
if (r->int_no == 0x20) {
new_cpu = schedule(r);
}
/*... */
return new_cpu;
}
And struct regs looks like this:
Code: Select all
struct regs
{
unsigned int gs, fs, es, ds;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int int_no, err_code;
unsigned int eip, cs, eflags, useresp, ss;
};
Any Idea?
Edit:
I have printed the registers before and after the switch ..
As I am a beginner, here is what i have noticed.
Isn't fs a 16 bit register? why is fs so high in vmware? And why does it work fine in Qemu?
What could be the problem?
btw .. it doesn't work in vmware neither on a real pc
Re: Unable to call a C-Function after task switch
Posted: Wed Oct 05, 2011 9:37 pm
by thepowersgang
As I noted in your other thread, you didn't quite get the idea of cdecl. Parameters are passed on the stack in reverse order (going upwards - return address, param1, param2)
Parameters also need to be removed by the caller, not the callee. You don't do this after calling the irq handler, so the your state restore fails.
Re: Unable to call a C-Function after task switch
Posted: Wed Oct 05, 2011 9:54 pm
by eltomato
hmm .. ok .. I'm still learning
Parameters are passed on the stack in reverse order (going upwards - return address, param1, param2)
Am I right that I forgot to pop the esp again?
correct code would be:
Code: Select all
extern _irq_handler
irq_common_stub:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp
call _irq_handler
pop esp
mov esp, eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
this would fix the first problem, right?
2.
Parameters also need to be removed by the caller, not the callee. You don't do this after calling the irq handler, so the your state restore fails.
Hmm.. so I need to pop the stack items pushed by the c-function? (I mean the return struct)
for
Code: Select all
struct regs
{
unsigned int gs, fs, es, ds;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int int_no, err_code;
unsigned int eip, cs, eflags, useresp, ss;
};
i need to pop 19 times, right?
Could you tell me if I'm getting closer or completely wrong?
thx
Re: Unable to call a C-Function after task switch
Posted: Wed Oct 05, 2011 11:56 pm
by thepowersgang
Your first part was right (but only on a technicality, because doing "pop esp" is in most cases a bad idea) However, you do not need to care about what the C function does with the stack, only that it will return to the stack pointer to the same value as when it was called.
Re: Unable to call a C-Function after task switch
Posted: Thu Oct 06, 2011 7:31 am
by eltomato
OK, what should I pop in then? ebx?
What I don't really understand is, what happens to the stack pointer?
What do I have to do with it after the call ?
source would look like this atm:
Code: Select all
extern _irq_handler
irq_common_stub:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp
call _irq_handler
pop ebx
mov esp, eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
hmpf :/
Edit:
OK, i found this:
http://www.cs.umbc.edu/~chang/cs313.s02/stack.shtml
So, do I need to pop the struct from the esp by doing "add esp, [num of bytes]"?
With the struct of 19 ints I would do a "add esp, 76" ?
I'm a little clueless right now :/
Re: Unable to call a C-Function after task switch
Posted: Thu Oct 06, 2011 7:55 am
by Solar
You don't have to pop the values from stack individually because you no longer need them. You simply reset the stack pointer to the value it had before you started pushing values to it for the function call.
Re: Unable to call a C-Function after task switch
Posted: Thu Oct 06, 2011 8:23 am
by eltomato
Hell yeah, it works
I just forgot to init variables in the struct
Thx guys for helping me
If somebody is interested in my solution, here are some pieces ..
irq stub inside my asm file:
Code: Select all
extern _irq_handler
irq_common_stub:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp
call _irq_handler
mov esp, eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret
The timer handler (fired by pic) calls a simple scheduling function
Code: Select all
struct regs* irq_handler(struct regs *r) {
/* ... */
struct regs* new_cpu = r;
new_cpu = schedule(r);
/* ... */
return new_cpu;
}
and returns the registers of the next task (in a struct):
The Struct looks like this:
Code: Select all
struct regs
{
unsigned int gs, fs, es, ds;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int int_no, err_code;
unsigned int eip, cs, eflags, useresp, ss;
};
thx anyone