Efficient interrupt handling

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
User avatar
Revelation
Member
Member
Posts: 47
Joined: Sat Jun 21, 2008 8:15 am

Efficient interrupt handling

Post 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. :shock: Isn't there a better way to retrieve the interrupt number?
Now is the winter of my disk content.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: Efficient interrupt handling

Post 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
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Efficient interrupt handling

Post 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...
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
User avatar
Revelation
Member
Member
Posts: 47
Joined: Sat Jun 21, 2008 8:15 am

Re: Efficient interrupt handling

Post 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.
Now is the winter of my disk content.
JohnnyTheDon
Member
Member
Posts: 524
Joined: Sun Nov 09, 2008 2:55 am
Location: Pennsylvania, USA

Re: Efficient interrupt handling

Post 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.
User avatar
Revelation
Member
Member
Posts: 47
Joined: Sat Jun 21, 2008 8:15 am

Re: Efficient interrupt handling

Post 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!
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.
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Re: Efficient interrupt handling

Post 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.
1234
Posts: 24
Joined: Sat May 26, 2007 7:58 pm

Post by 1234 »

[post deleted]
Last edited by 1234 on Tue Jan 27, 2009 3:22 pm, edited 4 times in total.
User avatar
Revelation
Member
Member
Posts: 47
Joined: Sat Jun 21, 2008 8:15 am

Re: Efficient interrupt handling

Post by Revelation »

Are you sure you want to decode and execute all those nops?
Good suggestion!
Now is the winter of my disk content.
User avatar
gzaloprgm
Member
Member
Posts: 141
Joined: Sun Sep 23, 2007 4:53 pm
Location: Buenos Aires, Argentina
Contact:

Re: Efficient interrupt handling

Post 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
Visit https://gzalo.com : my web site with electronic circuits, articles, schematics, pcb, calculators, and other things related to electronics.
Post Reply