GCC and interrupt handlers: More black magic.

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
linguofreak
Member
Member
Posts: 510
Joined: Wed Mar 09, 2011 3:55 am

GCC and interrupt handlers: More black magic.

Post by linguofreak »

I was looking at the black magic section on the Wiki page on interrupt handlers, and I thought up another way to kludge together interrupt handler code in gcc:

Code: Select all

void * random_interrupt_handler(int dummy)
{
    if(dummy)
        return &&handler;

    handler:
    asm(//ISR prologue goes here);

    //C code

    asm(//ISR epilogue goes here);
}
Calling random_interrupt_handler() will return the address of the actual handler (this is useful as the unary operator && can only be used to get the address of a label in the same function), which we can use to construct our IDT entry.

The good: The handler's prologue and epilogue consist entirely of our handwritten inline assembly, unlike the Wiki's black magic code, where part of the prologue is generated by the compiler and part is written by us, and we have to write an epilogue that matches the part of the prologue the compiler constructs.

The bad: The compiler will give a warning about returning the address of a local variable because we return &&handler. We also have to keep track of the number and size of local variables we use and make sure our prologue and epilogue create an appropriate stack for them (this is the flip side of "the good").

The ugly: Ideally, the first line of the function would simply be "return &&handler;". Unfortunately, that results in the handler code being "optimized" away by the compiler, even if options like -fno-dce are used. Therefore, we need to test a dummy variable with an if statement to convince the compiler that the handler code is actually needed. The wrapper function must always be called with "dummy" being non-zero, otherwise it will fall through to the interrupt handler, which is bad for obvious reasons.

I'd like to get people's opinions on how this compares to the "black magic" method listed on the Wiki. My impression is that it's less dependent on compiler internals (in that it doesn't depend on how the compiler generates stack handling code). Would you agree?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: GCC and interrupt handlers: More black magic.

Post by bluemoon »

While interrupt are not called *very frequently*, I think assembly stub is more maintainable and there is no need to optimize that call instruction away - you might just lost a nanosecond once every millisecond (0.0001%).
jbemmel
Member
Member
Posts: 53
Joined: Fri May 11, 2012 11:54 am

Re: GCC and interrupt handlers: More black magic.

Post by jbemmel »

Here's an alternative solution:

void * someISR( )
{
__asm__ __volatile__ goto( "jmp %l[endOfISR]" : : : "memory" : endOfISR );
__asm__ __volatile__( ".align 16\t\n" : : : "memory" );
startOfISR:
__asm__ __volatile__( "nop\t\n" : : : "memory" );

printf( "Hello, world of ISRs!" );
__asm__ __volatile__( "iret\t\n" : : : "memory" );
endOfISR:
__asm__ __volatile__ goto( "mov %l[startOfISR], %%rax" : : : "memory" : startOfISR );
}


This does not require the dummy variable & associated test, and does not give a compiler warning either. It uses "asm goto", a relatively new feature of GCC (see http://wiki.osdev.org/Inline_Assembly#asm_goto). Now GCC does not optimize the ISR code away, because it cannot know what's happening in the __asm__ block

Just be careful when you need to interpret the DWARF2 information that the compiler generates for this function - it probably gets it wrong...
jbemmel
Member
Member
Posts: 53
Joined: Fri May 11, 2012 11:54 am

Re: GCC and interrupt handlers: More black magic.

Post by jbemmel »

bluemoon wrote:While interrupt are not called *very frequently*, I think assembly stub is more maintainable and there is no need to optimize that call instruction away - you might just lost a nanosecond once every millisecond (0.0001%).
While this may have some merit for device triggered interrupts, trap handlers can benefit from removing the extra call/ret instructions - not only for timing, but also for the additional stack usage. Some handlers like the stack fault handler (for example) cannot afford to use the stack without fixing it first
User avatar
Nessphoro
Member
Member
Posts: 308
Joined: Sat Apr 30, 2011 12:50 am

Re: GCC and interrupt handlers: More black magic.

Post by Nessphoro »

jbemmel wrote:
bluemoon wrote:While interrupt are not called *very frequently*, I think assembly stub is more maintainable and there is no need to optimize that call instruction away - you might just lost a nanosecond once every millisecond (0.0001%).
While this may have some merit for device triggered interrupts, trap handlers can benefit from removing the extra call/ret instructions - not only for timing, but also for the additional stack usage. Some handlers like the stack fault handler (for example) cannot afford to use the stack without fixing it first
If the stack is broken, how did the CPU push data onto it?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: GCC and interrupt handlers: More black magic.

Post by bluemoon »

There is two kind of stack fault: one occur in user mode and one in kernel mode.

For user mode stack fault the CPU perform stack switch when enter kernel so it's all good.
For kernel mode stack fault, there are three possibility:
Without IST or task gate: you are dead. The CPU cannot push return address before invoke stack fault handler, result in double fault (see below)
With task gate: CPU switch to good stack and no problem or significant stress to use stack for an extra call.
With IST: CPU switch to good stack and no problem or significant stress to use stack for an extra call.

For Double Fault, the above logic repeat for with or without IST / task.

Note: IST has it's own issue, especially on nested NMI, but it's beyond the scope of this thread.
Post Reply