Running a callback in C

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.
Post Reply
User avatar
IanSeyler
Member
Member
Posts: 326
Joined: Mon Jul 28, 2008 9:46 am
Location: Ontario, Canada
Contact:

Running a callback in C

Post by IanSeyler »

Hi everyone,

I've added callback functionality to the network handler in BareMetal OS. It's a fairly simple stack modification that can be seen here: https://github.com/ReturnInfinity/BareM ... t.asm#L167

With the callback I can have a user function executed every time the network interrupt finishes. Assembly-based programs that use this feature seem to work correctly but I get sporadic GPFs with C-based applications.

Is my stack modification correct?
Is this the correct way to go about this?
What could be causing the C program to GPF sometimes?

Thanks,
Ian
BareMetal OS - http://www.returninfinity.com/
Mono-tasking 64-bit OS for x86-64 based computers, written entirely in Assembly
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Running a callback in C

Post by Combuster »

Code: Select all

sub rsp, 8			; Subtract 8 since we will copy 8 registers
Byte-sized registers? :?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
IanSeyler
Member
Member
Posts: 326
Joined: Mon Jul 28, 2008 9:46 am
Location: Ontario, Canada
Contact:

Re: Running a callback in C

Post by IanSeyler »

I noted that as well. It should have been '8*8'. Setting it to 64 still gives a GPF. Must have just been luck that it works partially.

Are CS and SS 64-bits wide?
BareMetal OS - http://www.returninfinity.com/
Mono-tasking 64-bit OS for x86-64 based computers, written entirely in Assembly
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: Running a callback in C

Post by Kevin »

It is likely not the problem that you are hitting here because I assume that you only receive a reply after you have fully sent a packet and are waiting for the next keypress. But if I'm not mistaken, you're basically using signals here and none of your code looks very signal safe, neither the assembly nor the C one.
Developer of tyndur - community OS of Lowlevel (German)
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Running a callback in C

Post by gerryg400 »

Is this a redzone problem ?
If a trainstation is where trains stop, what is a workstation ?
User avatar
IanSeyler
Member
Member
Posts: 326
Joined: Mon Jul 28, 2008 9:46 am
Location: Ontario, Canada
Contact:

Re: Running a callback in C

Post by IanSeyler »

I don't believe this is a redzone problem. I've compiled my C program with and without that flag before and it makes no difference.

In Bochs it looks like 6 64-bit values are pushed to the stack when a hardware interrupt fires:

64-bit RIP
64-bit CS
64-bit Flags
64-bit RSP
64-bit SS
64-bit ???

With my stack modifications I am trying to adjust the stack like this:

64-bit Program Callback IP
64-bit CS
64-bit Flags
64-bit RSP
64-bit SS
64-bit ???
64-bit RIP

This way the callback will be executed after the IRET and the callback will jump back to the initial RIP when it executes RET. Is this method ok?
BareMetal OS - http://www.returninfinity.com/
Mono-tasking 64-bit OS for x86-64 based computers, written entirely in Assembly
User avatar
siavoshkc
Member
Member
Posts: 40
Joined: Wed Feb 19, 2014 11:10 am

Re: Running a callback in C

Post by siavoshkc »

ReturnInfinity wrote:I noted that as well. It should have been '8*8'. Setting it to 64 still gives a GPF. Must have just been luck that it works partially.

Are CS and SS 64-bits wide?
They are 16 bits wide but stack is aligned on quad word boundaries. So they take 64 bits instead of 16.
Check out my FSB Data Integrity Tester at http://fsbdit.sourceforge.net/.

Siavosh
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Running a callback in C

Post by Combuster »

ReturnInfinity wrote:This way the callback will be executed after the IRET and the callback will jump back to the initial RIP when it executes RET. Is this method ok?
Not really, because it doesn't preserve flag/register state of it's own. The callback function will have to have such functionality that saves and restores the required CPU state (= assembler stub)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: Running a callback in C

Post by jnc100 »

I see a number of problems:

Firstly, you are not using a cross compiler so it is difficult to be sure exactly which calling convention is being used. I will assume you are using the x86_64 one. For this, a number of things need to be addressed:

1) the C function being called expects that it can trash various registers. Whilst your ISR may appropriately save and restore all registers, if it then returns to another function instead of the one that was interrupted, the new function (i.e. your C callback) will probably trash some registers that the function which was executing when the interrupt was triggered wasn't expecting.

2) the x86_64 abi also expects the stack to be aligned on a 16 byte boundary upon entry to a C function. You do not guarantee this anywhere.

3) The red zone may or may not be an issue - if you don't disable it, the C callback function will expect to have some stack space available which it doesn't actually have.

Given all of these (which are reasonably difficult to correct with the way you are doing it), I'd suggest two options:

1) run the C callback from within the ISR. Here you have to be sure that the code is safe and won't mess up your ISR state.

2) have the C callback run as a separate (maybe kernel) thread, that is only switched to when the actual ISR (a small stub) sets a flag. This is commonly how microkernels service interrupts, however you need to make sure the actual ISR removes any data from the device to prevent the interrupt being constantly triggered.

Regards,
John.
Post Reply