Question

When an interrupt is triggered in protected mode on x86 is it possible to figure out what interrupt number was fired? For example lets say I called int 0xFF. In the handler can I find out that int 0xFF was called?

Était-ce utile?

La solution

If you have unique interrupt handlers (or, at least, unique entry points and prologue code), then, of course, you can differentiate int 0xFF from, say, int 0x30. The ISR addresses are stored in the IDT, so, that's the place where the differentiation starts.

There's no very good alternative to unique ISRs. Here's why...

In an ISR you could examine the caller's stack, see the return address and examine the code right before the return address to see if it's the 2-byte int n instruction (encoded as bytes: 0xCD, n) or something else. The problem is, there are also int 3 and into 1-byte instructions (encoded as 0xCC and 0xCE respectively). How do you differentiate between 0xCD+0xCC (int 0xCC) or 0xCD+0xCE (int 0xCE) and simply 0xCC (int 3) or 0xCE (into)? There could be anything before 0xCC or 0xCE. The variable length of instructions doesn't let us easily and reliably analyze/disassemble code backwards.

What about other ways of triggering interrupts/exceptions, like ud2? Or instructions triggering #GP, #PF? Those can be arbitrary instructions.

Also you should keep in mind that exceptions aren't handled in the exact same way. Some of them come with the extra information saved by the CPU on the stack prior to entering the ISR, it's the error code. Others don't have this error code and your ISR needs to remove it before doing iret. A mistake in determination of the exception vector will crash or hang your code.

Now, about hardware interrupts... You may be able to determine which hardware interrupt is being serviced. The PIC has the in-service register (ISR), where a bit set to 1 (AFAIR) indicates the IRQ, but if you let interrupts of higher priority preempt ISRs handling interrupts of lower priority (by enabling interrupts inside of ISRs), then the interrupt identification quickly becomes more complicated than necessary.

So, just go with unique ISRs for all of your IRQs, exceptions and system calls. Or use one common ISR but with multiple unique entry points each saving a unique number (=vector number) on the stack. The common code afterwards will extract this number and do what's necessary for that interrupt vector.

Autres conseils

Making stubs that push the value to the stack is a neat way to deal with this, and is used on the James Molloy tutorial:

%macro ISR_NOERRCODE 1
  global isr%1
  isr%1:
    cli                         ; Disable interrupts firstly.
    push byte 0                 ; Push a dummy error code.
    push byte %1                ; Push the interrupt number.
    jmp isr_common_stub         ; Go to our common handler code.
%endmacro

%macro ISR_ERRCODE 1
  global isr%1
  isr%1:
    cli                         ; Disable interrupts.
    push byte %1                ; Push the interrupt number
    jmp isr_common_stub
%endmacro

ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE   8
ISR_NOERRCODE 9
ISR_ERRCODE   10
ISR_ERRCODE   11
ISR_ERRCODE   12
ISR_ERRCODE   13
ISR_ERRCODE   14
ISR_NOERRCODE 15
/* More entries */

This also deals with the error code.

I'm no expert on interrupt handlers but they have to have a return address somewhere so that the original code can resume execution. If you can get old of this address then you can inspect the previous address which will presumably contain the number of the interrupt.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top