Here's the proposal. Feel free to comment.
The idea is to get the PICs to inform us immediately of any IRQs which are requesting service so we gain a complete picture of all IRQs which require attention. Then, since we will know of all IRQs which need attention we can process them in whatever order we want.
The key change from normal is for an interrupt to be EOId before it is handled rather than afterwards, and for the relevant IMR to be used to prevent that same IRQ from firing again.
As well as masking an IRQ it would be added to a waiting set. The waiting set could be as simple as a bit array with one bit for each IRQ number or it could be more extensive but the point is that it would keep track of which IRQs had been signalled but had not yet been processed.
To illustrate, here's a piece of pseudocode to show what would happen when a hardware interrupt comes in. Before it starts EOI would have been issued automatically by AEOI (on all but very old hardware).
On an interrupt:
Code: Select all
Push registers
Mask this interrupt in the relevant IMR
Add this interrupt to the set of waiting interrupts
... body ...
Pop registers
iret
For example, say half a dozen interrupts all fire at once. Each of the six would, in turn, follow the above code path. That would leave all six masked off and recorded as awaiting service.
Naturally, something has to do the actual servicing. AISI it could be one of the interrupts or a high-priority task.
In the pseudocode below I'll make it one of the interrupts. I'll use a nesting level to determine whether an interrupt is already being serviced or not. Nesting level will be zero on initial entry and will be 1 if one or more interrupts are being serviced. There would only be the two levels.
The code in the above which is shown as "... body ..." would be
Code: Select all
If nesting level is zero
Increment nesting level
Loop while there are any interrupts waiting
Pick the IRQ we regard as of highest priority
Delete it from waiting list
Enable interrupts
Handle the IRQ
Disable interrupts
Unmask the IRQ
Endloop
Decrement nesting level
Endif
If any new interrupts fired while the code was running they would be added to the waiting set and then would be processed in their turn before the loop completed.
Only once the waiting set was empty would the loop terminate. The code would then, as normal, ireq back to whatever had been interrupted.
I think it would work but it is at present untested. I have in mind some potential caveats and a number of potential improvements but I think the above is enough to show the basic idea.
FWIW I'd probably give the IRQs the following priorities:
- 0 PIT
8 RTC
3 Serial
4 Serial
all the rest ...