Get IRQ number in ISR

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
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Get IRQ number in ISR

Post by teodori »

Hello,
I have a functionnal IDT with 256 ISRs:

Code: Select all

idt:
	.rept 256						# Fill IDT with 256 Dummy ISR
	.word DmyIsr, 0x0008
	.byte 0x00, 0xae
	.word 0x0000
	.endr
idt_end:

idtptr:
	.word (idt_end - idt - 1)
	.long (idt + 0x0500)
and here is my ISR:

Code: Select all

DmyIsr:
	pusha
	pushl %eax	# EAX contains the IRQ number
	call dmy_isr
	popl %eax
	popa
	iret
My question: Is it possible to retrieve IRQ number in "DmyIsr" and to push it to the stack, so I can use a C function like this:

Code: Select all

void dmy_isr(int irq);
Thank you
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Get IRQ number in ISR

Post by Brendan »

Hi,
teodori wrote:My question: Is it possible to retrieve IRQ number in "DmyIsr" and to push it to the stack, so I can use a C function like this:
If you need each interrupt handler to be different, even if the only difference is pushing a different number on the stack, then you have to have different interrupt handlers.

To do this, one way is to use the assembler's preprocessor . For an example (NASM):

Code: Select all

    %assign i 0
    %rep 256
     align 4,nop
IRQstub%[i]:
    pusha
    push dword %1
    call dmy_isr
    add esp,4
    popa
    iret
    %assign i i+1
    %endrep
This should generate 256 IRQ handlers with labels named "IRQstub0", "IRQstub1", "IRQstub2", ... "IRQstub255". You could generate the IDT in a similar way, so that the first IDT entry points to "IRQstub0", the second points to "IRQstub1", etc.

Unfortunately some assemblers don't have good preprocessors. In this case you can write code to generate code. For example, you could write a little C utility or a Python script or something that generates the assembly for the IRQ stubs and IDT.

However, the idea of having one common interrupt handler for all the extremely different types of interrupts is "less than intelligent".

For exceptions, software interrupts, IPIs and spurious IRQs the only thing a common interrupt handler is going to do is call the interrupt handler that's designed for that interrupt, and it makes more sense to setup the IDT so that the correct interrupt handler is called directly without wasting time getting an "interrupt number" and doing something like "if(number == 0x0E) { handler_that_should_have_been_called_to_begin_with(); return; }".

For IRQs you'd want to use trap gates, for some exceptions you'd want to use interrupt gates, and for some exceptions (NMI, machine check and double fault) you'd want to use task gates. For some of the exceptions the CPU pushes an extra error code and for some exceptions it doesn't. For the page fault handler the first thing you should do is save CR2 (so that it doesn't matter if CR2 gets trashed if a second page fault occurs). For things like spurious IRQ handlers you could just do "IRET" and nothing else.

Basically the idea only makes sense for normal IRQs; possibly excluding the IRQ the scheduler uses for figuring out when a task should be preempted, the IRQ the scheduler uses for figuring out when a sleeping task should wake up, any IRQ used for a watchdog, and any spurious IRQ.

What this means is that idea of generating the IDT and all the interrupt handling stubs using a simple loop is broken - it needs to be much more flexible. Instead, you might have different macros that generate different types of IDT entries and use them manually; and different pieces of code (some generated by macros) for different interrupt stubs.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
mich
Posts: 18
Joined: Sun Nov 11, 2012 5:36 pm

Re: Get IRQ number in ISR

Post by mich »

Brendan wrote:However, the idea of having one common interrupt handler for all the extremely different types of interrupts is "less than intelligent".
Let me just throw in my opinion:
I think it is a great way to quickly escape the platform specifics and get into the abstraction layer. Because once you have one function that is called with the IRQ # you can have a dispatch table ala "table[IRQ#]();" in that function which will be independent of the actual underlying IRQ system.
But than again it all depends highly on what your goals are, because in some cases a layer-up-on-layer approach to get a nice hierarchy is not desired.
Of course you could design an IRQ registration system that makes directly use of the IDT and is still good abstractable, but it will also mean more platform specific work, which in some cases might not be desirable ... so it really all depends!

Anyway I never had problems with generating a stub for each IRQ # that simply pushes that IRQ # and then calls a global handler function, which then dispatches the appropriate IRQ hander via a table.
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: Get IRQ number in ISR

Post by Owen »

Assuming "exceptions" and "Interrupts" behave the same would happen to be a very x86 tainted abstraction
teodori
Member
Member
Posts: 103
Joined: Wed Nov 14, 2012 4:55 pm

Re: Get IRQ number in ISR

Post by teodori »

thank you :-)
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Get IRQ number in ISR

Post by bluemoon »

mich wrote:I think it is a great way to quickly escape the platform specifics and get into the abstraction layer.
This is quite a common mistake. As Brendan points out, almost every handler needs to do different things, this is not an abstraction by pulling different things into one entry point just to perform a switch case to handle them differently. It just make you, the programmer feel convenience, while not actually increase maintainability.

You may, however, abstract different sources of exceptions and interrupt, something like an HAL, so that you may implement similar functionality on different architecture, but be careful that at this level things are less likely to be compatible across architecture anyway, and performance should be well considered.
Post Reply