This is a situation where I need the help of you OSnews readers who are experienced with low-level development on ARM, SPARC, PowerPC, MIPS, and other hardware architectures we have on computers nowadays. The issue is that I'm currently designing the part of my hobby kernel which takes care of interrupts. Although I mostly work on x86 at the moment, I'd like to keep this code portable to other hardware architectures in the future. To do that, I have to know how interrupt handling works on as much HW architectures as possible.

Heh, I've just read the VAX-11 documentation following the advice of someone else... Indeed, the IPL system sounded like an interesting way of prioritizing interrupts.

However, I wonder if it was as safe as nowadays' schemes where you disable interrupts altogether until the basic interrupt handler which saves the CPU's state is done. Wouldn't there be a risk of smashing register values or trashing the stack if an interrupt occurs while another interrupt is being processed ?

Or is it the case that the VAX fully saves the CPU state on the stack all by itself (kind of like hardware multitasking) ? I thought it only saved the PC and the PSL...

VAX indeed only saves PC and PSL. There may also be a stack change depending upon what the processor was doing. That's enough; the instruction set is powerful enough to allow the ISRs to manage saving the remainder of the context in a re-entrant manner.

A VAX kernel is essentially a primitive RTOS for which scheduling is managed by the interrupt system.
The interrupt hardware includes a mechanism for software to request interrupts, the Software Interrupt Request Register. Setting a bit in the SIRR requests an interrupt at the associated IPL.

The fundamental rules for managing IPL in the kernel are:

<ul><li>You can always raise IPL. Since you have the CPU, you are the highest-priority task running.
<li>If you have raised IPL, you can lower it to your original IPL without additional effort.
<li>If you need to lower IPL below your original IPL, you have to make other arrangements. This is usually done by pushing a "fork block" onto a queue and requesting a software interrupt.
</ul>

If these rules are followed, the hardware can guarantee that the processor is executing the highest-priority IPL.

A fork block consists of a queue entry that contains a minimal processor context; typically, only a handful of register values. The ISR for interrupts generated by the SIRR saves that handful of registers then grabs a fork block from its queue, loads the handful of registers from it, and calls the function indicated by the fork block. For VMS, the SIRR ISR saves only R0 through R5, and pulls R3 and R4 from the fork block (R5 is used to hold the address of the fork block). If the called function needs more registers than that saved, it must save them.

Since the VAX processor has interlocked queue instructions, it takes astonishingly few instructions for an ISR to fire off a fork block.

Operating system resources are serialized by requiring they be manipulated at a specified IPL; for example, memory is allocated at IPL 8. An ISR operating at a higher IPL must queue a fork block to be able to lower IPL far enough to allocate memory.

This originally got extended to multiprocessors by using spinlocks to ensure that only one processor was running at a given IPL. Processors can also interrupt each other using doorbell interrupts. Since then, the spinlock scheme has gotten finer.