Efficient interrupt handling
- Revelation
- Member
- Posts: 47
- Joined: Sat Jun 21, 2008 8:15 am
Efficient interrupt handling
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?
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?
Now is the winter of my disk content.
Re: Efficient interrupt handling
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
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
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...
It works fine this way (installing IDT entries via C function pointers) so long as you know how to fix up the stack...
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
- Revelation
- Member
- Posts: 47
- Joined: Sat Jun 21, 2008 8:15 am
Re: Efficient interrupt handling
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.It works fine this way (installing IDT entries via C function pointers) so long as you know how to fix up the stack...
That's possible, only that would make it static.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
Now is the winter of my disk content.
-
- Member
- Posts: 524
- Joined: Sun Nov 09, 2008 2:55 am
- Location: Pennsylvania, USA
Re: Efficient interrupt handling
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.
- Revelation
- Member
- Posts: 47
- Joined: Sat Jun 21, 2008 8:15 am
Re: Efficient interrupt handling
Well, I found a way to really shrink the C code for interrupt registration. This was the old way:
But if you arrange your stubs that they all have the same size, you can do this:
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:
I hope this is useful to someone!
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
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);
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
Last edited by Revelation on Wed Jan 21, 2009 12:35 pm, edited 1 time in total.
Now is the winter of my disk content.
Re: Efficient interrupt handling
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.
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.
Website: https://joscor.com
- Revelation
- Member
- Posts: 47
- Joined: Sat Jun 21, 2008 8:15 am
Re: Efficient interrupt handling
Good suggestion!Are you sure you want to decode and execute all those nops?
Now is the winter of my disk content.
- gzaloprgm
- Member
- Posts: 141
- Joined: Sun Sep 23, 2007 4:53 pm
- Location: Buenos Aires, Argentina
- Contact:
Re: Efficient interrupt handling
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.
Cheers,
Gonzalo
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
Gonzalo
Visit https://gzalo.com : my web site with electronic circuits, articles, schematics, pcb, calculators, and other things related to electronics.