My interrupt system is like this:
I have an IDT of 48 entries (32 exceptions and the next 16 are the remapped IRQs). All of these descriptors point to their own piece of code which does the following. If the interrupt pushes NO error code on the stack, an error code of 0 is pushed on the stack and then the interrupt number is pushed on the stack, it then jumps to the global interrupt handler (GIH from now on). For exceptions which do have their own error code, only the extra interrupt number is pushed on the stack and the code jumps to the GIH. Only the double fault handler works different, it uses a Task descriptor and how that works is unimportant right now.
When the GIH gets control it saves all registers and then checks the interrupt number. It has a list somewhere in memory with the interrupt handler for each interrupt (only 1 interrupt handlers per interrupt), this interrupt handler gets the error code as a parameter. If the interrupt handler is a NULL value, nothing is done. This piece of code works the same for all 48 interrupts. After the interrupt handler gives control back to the GIH, the GIH checks if the interrupt handler is above 31 (an IRQ), it then sends the EOI to the PIC (and also an EOI to the slave pic if the IRQ is above 7).
This is actually very basic ideas and I think this is used by more system (Tim's Mobius does it like this if I'm right, and Newos too). But there are some things I might change. Is the list with interrupt handlers the GIH uses with only 1 pointer to an interrupt handler enough (and that the interrupt handler itself can share it with other handling code), or should it be able to register a max of 4 or 8 interrupt handlers per interrupt in the GIH? I think the first option is the best, since for the exceptions, only one handler is enough.
If I do make it possible to register more interrupt handlers per interrupt in the GIH, I think it's better to use 2 GIHs. One for the first 32 exceptions (which will only have one interrupt handler in their GIH) and one for the next 16 IRQs (which will have multiple interrupt handlers registered in the GIH).
The other question I have is if I should directly implement some code inside the GIH that runs the task sheduler, besides the the interrupt handler which can be registered with the interrupt. The task sheduler is one of the very core parts of the system and I think it deserves to be baked inside the GIH itself.
Now I would like to know what you think of my idea. Do you have any comments or anything else to say? How does your interrupt system works? I'd like to know more about anybody else's interrupt system, let me know.
My interrupt system
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:My interrupt system
My own approach was to assign each interrupt an ordered linked list of handlers. Each handler can tell if it has successfully handled the interrupt/exception or if further processing must be done.Is the list with interrupt handlers the GIH uses with only 1 pointer to an interrupt handler enough (and that the interrupt handler itself can share it with other handling code), or should it be able to register a max of 4 or 8 interrupt handlers per interrupt in the GIH? I think the first option is the best, since for the exceptions, only one handler is enough.
This allow daisy chain of handler like what we usually did in the Ms-DOS times where you could easily add a functionnality of re-calling a command with F3 by hooking the keyboard interrupt and watching for the F3 scancode. If it wasn't there you could simply defer the processing to the "normal" keyboard handler.
i'm not sure this is what you wanted to do with "4 or 8" handlers ...
Re:My interrupt system
Yes, definitely allow for more than one handler per IRQ. PCI allows for many devices to share the same interrupt. On my machine, Windows reports no fewer than 6 devices sharing IRQ 11.
I too maintain a linked list of handlers for each IRQ. The IRQ dispatch code looks something like:
I too maintain a linked list of handlers for each IRQ. The IRQ dispatch code looks something like:
Code: Select all
irq_t *irq;
for (irq = irqs[number];
irq != NULL && !irq->handler(number);
irq = irq->next)
;
Re:My interrupt system
I'm still not sure if I would allow more than one handler per IRQ. Only for PCI it would be usefull, but for other devices..I'm not sure. I'm thinking of letting the specified IRQ handler do the multiplexing work what your linked list does.
So in my case, there is one interrupt handler per interrupt, for interrupt 0x2b (IRQ 11) there is an PCI handler connected. This PCI handler then handles the multiple PCI device handlers. Maybe the PCI handler has some code to specify which PCI device gets the interrupt.
What about the above idea?
And also about the task scheduler, would it be best to put it directly in the global interrupt handler or in the timer interrupt handler (which calls the task scheduler and does updating the system clock and the system counter) which is called by the global interrupt handler.
PS: Tim, the mobius version I have contains completely different code than what you describe in your post. This is how my copy of the mobius looks like:
Do you have a newer version online than the one I have?
So in my case, there is one interrupt handler per interrupt, for interrupt 0x2b (IRQ 11) there is an PCI handler connected. This PCI handler then handles the multiple PCI device handlers. Maybe the PCI handler has some code to specify which PCI device gets the interrupt.
What about the above idea?
And also about the task scheduler, would it be best to put it directly in the global interrupt handler or in the timer interrupt handler (which calls the task scheduler and does updating the system clock and the system counter) which is called by the global interrupt handler.
PS: Tim, the mobius version I have contains completely different code than what you describe in your post. This is how my copy of the mobius looks like:
Code: Select all
irq = irq_first[ctx.intr];
i = 0;
while (irq)
{
assert(irq->dev->vtbl->isr);
if (irq->dev->vtbl->isr(irq->dev, ctx.intr))
break;
irq = irq->next;
i++;
if (i > 6)
assert(false && "Too many interrupt handlers");
}
Re:My interrupt system
No, I just wrote it from memory. Think of my post as pseudocode, and the actual Mobius code as being the same with lots of little details added.