Page 1 of 1
Efficient interrupt handling
Posted: Mon Jan 19, 2009 1:11 pm
by Revelation
I'm currently working on a complete redesign of my OS and I arrived at interrupt handling. My old kernel was based on Bran's tutorial which just defined a large amount of dummy interrupt handlers that jumped to a general interrupt handler in ASM that forwarded it to a handler in C.
I want my kernel to theoretically use all interrupt handlers, so I'd have to define 256 dummy interrupt handlers.
Isn't there a better way to retrieve the interrupt number?
Re: Efficient interrupt handling
Posted: Mon Jan 19, 2009 1:20 pm
by AJ
Hi,
Looking at that tutorial, it jumps to a common stub. That means that you only need two PUSHes and a JMP for each handler, which doesn't waste much. However, a better option may be just to define the exceptions, IRQ's and whatever else you actually use, rather than having 207 handlers sitting around doing nothing
Cheers,
Adam
Re: Efficient interrupt handling
Posted: Mon Jan 19, 2009 2:08 pm
by neon
In my system (and series) I simply install a default C interrupt handler for each interrupt directly in the IDT (no stubs). My HAL provides a setvect() routine that allows any part of the system to install new interrupt handlers at any time. Thus, is an undefined interrupt is generated, the default handler gets called by the processor. If a defined interrupt is generated, the processor will just execute the C handler.
It works fine this way (installing IDT entries via C function pointers) so long as you know how to fix up the stack...
Re: Efficient interrupt handling
Posted: Mon Jan 19, 2009 2:30 pm
by Revelation
It works fine this way (installing IDT entries via C function pointers) so long as you know how to fix up the stack...
This way sounds like the most efficient one, only I got a little deterred from that method because of the warnings in the
wiki article.
However, a better option may be just to define the exceptions, IRQ's and whatever else you actually use, rather than having 207 handlers sitting around doing nothing
That's possible, only that would make it static.
Re: Efficient interrupt handling
Posted: Mon Jan 19, 2009 2:37 pm
by JohnnyTheDon
I provide stubs that pass the error code, faulting instruction address, previous stack pointer, and the ID of the processor the handler is running on to the C function. This requires me to make a copy of this stub for each interrupt, but it doesn't take that much memory. I'm thinking of switching to a table based method, so I will only need one stub for each processor.
Re: Efficient interrupt handling
Posted: Wed Jan 21, 2009 10:04 am
by Revelation
Well, I found a way to really shrink the C code for interrupt registration. This was the old way:
Code: Select all
idt_set_gate(0, isr0, GDT_CODE_SEG, IDT_RING0 | IDT_GATE_INT_32 | IDT_PRESENT);
idt_set_gate(1, isr1, GDT_CODE_SEG, IDT_RING0 | IDT_GATE_INT_32 | IDT_PRESENT);
idt_set_gate(2, isr2, GDT_CODE_SEG, IDT_RING0 | IDT_GATE_INT_32 | IDT_PRESENT);
idt_set_gate(3, isr3, GDT_CODE_SEG, IDT_RING0 | IDT_GATE_INT_32 | IDT_PRESENT);
idt_set_gate(4, isr4, GDT_CODE_SEG, IDT_RING0 | IDT_GATE_INT_32 | IDT_PRESENT);
..etc
But if you arrange your stubs that they all have the same size, you can do this:
Code: Select all
for (i = 0; i < 255; i++)
idt_set_gate(i, isr0 + i * 10, GDT_CODE_SEG, IDT_RING0 | IDT_GATE_INT_32 | IDT_PRESENT);
10 is the size of a normal stub (like isr7 below). Some interrupts have an error code and thus they are 5 bytes shorter. To fix that, you can fill that space with 5 NOPs:
Code: Select all
isr7:
cli
push byte 0
push byte 7
jmp isr_common_stub
isr8:
cli
nop
nop
nop
nop
nop
push byte 8
jmp isr_common_stub
isr9:
cli
push byte 0
push byte 9
jmp isr_common_stub
..etc
I hope this is useful to someone!
Re: Efficient interrupt handling
Posted: Wed Jan 21, 2009 11:46 am
by 01000101
I loath the days of writing/copying each ISR stub. Just use a NASM macro and do a lovely looping statement for all your ISR stubs. Saves a ton of screen space, and everything is centralized. Just make a few macro "if" statements checking to see if they push error codes or if you need to push a fake one to keep consistent.
My common ISR macro just pushed all of the GPR's, R8-15, FPU/SSE/MMX (FXSAVE/FXRSTOR), switched to a known-state stack for ISR's and sent some values to the C handlers.
The size of each structure is increased alot, but if I took a few minutes to re-do it, I'd just have the "core" peices (the error code handling) in that loop, and have those call another intermediate handler which push's/pop's the GPRs and such.
Posted: Wed Jan 21, 2009 8:54 pm
by 1234
[post deleted]
Re: Efficient interrupt handling
Posted: Thu Jan 22, 2009 3:37 am
by Revelation
Are you sure you want to decode and execute all those nops?
Good suggestion!
Re: Efficient interrupt handling
Posted: Thu Jan 22, 2009 7:59 pm
by gzaloprgm
You may have already noticed, but push byte instruction takes 2 bytes only (at least in my nasm compiling as 32 bits does).
You need to add only two nops, not 5.
Code: Select all
%macro ISR_ERRCODE 1
global _isr%1
_isr%1:
cli
push byte %1
jmp isrStub
nop
nop
%endmacro
Cheers,
Gonzalo