Questions about interrupt handling in an OS (ISRs)
Posted: Thu Jan 18, 2007 6:48 pm
How are interrupts handled robustly in an OS that allows a driver to service them, if the driver is not privileged (i.e. part of the kernel and/or running at a privileged level)?
I'm thinking of exokernels - do they trade-off robustness for the ability to access / service interrupts? (I'm not developing an exokernel, per se, but I some of the concepts I'd like to use are similar.)
The problem I'm having is that I'd like non-privileged services (essentially, user-level apps) to register for / request interrupts from the kernel. As part of the request, the service would provide the ISR for the interrupt; assuming the request is granted, the requested interrupt could be enabled / disabled by the service, and all interrupts would be handled by the provided ISR.
Assuming many interrupts are for hw devices needing servicing (usually in a timely fashion), and to prevent race conditions, corruption, etc. interrupts are usually disabled for at least a portion of the ISR. Sometimes, all other interrupts can be reenabled immediately and only the interrupt needing to be service needs to remain disabled. (There are many variations on this theme.)
So, it's easy enough to switch stacks when the interrupt is received.
It's possible to adjust the priv level when executing the ISR (i.e., the true ISR is a privileged wrapper and calls the user-level "ISR", but the wrapper adjusts and restores the priv level around the call).
What's difficult is :
a) guaranteeing that the provided ISR reenables all other HW interrupts in a timely fashion? Otherwise, the system would come to a screeching halt. I'm thinking a "non-maskable watchdog" timer interrupt / monitor could be used - the timer would be set when the interrupt was dispatched to the user-level ISR, and then, when this timer interrupt occurs, it would reenable interrupts (STI), even if the ISR hasn't yet done so. There would need to be some notification back to the service that this occurred, so it knows of a possible error/corruption situation. And even keeping the serviced interrupt masked indefinitely may not be acceptable, as some interrupts can be shared(?).
b) doing the above quickly, without requiring a full task switch (using TSS on IA32) - otherwise, all interrupts (not just the timer) essentially become a preemptive trigger to reschedule the executing context (which it really is, but we want to keep this lightweight). Some HW interrupts occur fast enough that we don't want a full task switch.
c) Each service will also be allowed to access I/O ports and/or physical memory addresses that it registered for via the OS. So when the interrupt occurs, the privileged level ISR will have to set the appropriate permissions to allow those ports / memory regions to be accessed. I think I know how I could do this, but it's cumbersome.
All this to ask...
Am I thinking about this correctly?
What are alternatives that I should consider?
What do common OS implementations do?
Thanks in advance for any feedback on this!
I'm thinking of exokernels - do they trade-off robustness for the ability to access / service interrupts? (I'm not developing an exokernel, per se, but I some of the concepts I'd like to use are similar.)
The problem I'm having is that I'd like non-privileged services (essentially, user-level apps) to register for / request interrupts from the kernel. As part of the request, the service would provide the ISR for the interrupt; assuming the request is granted, the requested interrupt could be enabled / disabled by the service, and all interrupts would be handled by the provided ISR.
Assuming many interrupts are for hw devices needing servicing (usually in a timely fashion), and to prevent race conditions, corruption, etc. interrupts are usually disabled for at least a portion of the ISR. Sometimes, all other interrupts can be reenabled immediately and only the interrupt needing to be service needs to remain disabled. (There are many variations on this theme.)
So, it's easy enough to switch stacks when the interrupt is received.
It's possible to adjust the priv level when executing the ISR (i.e., the true ISR is a privileged wrapper and calls the user-level "ISR", but the wrapper adjusts and restores the priv level around the call).
What's difficult is :
a) guaranteeing that the provided ISR reenables all other HW interrupts in a timely fashion? Otherwise, the system would come to a screeching halt. I'm thinking a "non-maskable watchdog" timer interrupt / monitor could be used - the timer would be set when the interrupt was dispatched to the user-level ISR, and then, when this timer interrupt occurs, it would reenable interrupts (STI), even if the ISR hasn't yet done so. There would need to be some notification back to the service that this occurred, so it knows of a possible error/corruption situation. And even keeping the serviced interrupt masked indefinitely may not be acceptable, as some interrupts can be shared(?).
b) doing the above quickly, without requiring a full task switch (using TSS on IA32) - otherwise, all interrupts (not just the timer) essentially become a preemptive trigger to reschedule the executing context (which it really is, but we want to keep this lightweight). Some HW interrupts occur fast enough that we don't want a full task switch.
c) Each service will also be allowed to access I/O ports and/or physical memory addresses that it registered for via the OS. So when the interrupt occurs, the privileged level ISR will have to set the appropriate permissions to allow those ports / memory regions to be accessed. I think I know how I could do this, but it's cumbersome.
All this to ask...
Am I thinking about this correctly?
What are alternatives that I should consider?
What do common OS implementations do?
Thanks in advance for any feedback on this!