Post by Josef Sipek
It sounds like if you want to load-balance interrupt handlers, you have to
Nah nah nah...
PREFIX is irrelevant when only 1 CPU is active and MUST be used in a
multi CPU environment.
Ok.. Here is a crash course on interrupts..
How interrupts are distributed among CPUs is not controlled by prefixing
but by the architecture and by CPU interrupt masking & subclass masking.
Interrupts come in 2 flavors : Floating and non-floating. Floating
interrupts are interrupts that can trigger a PSW switch on any
operational CPU in a configuration. Notably, I/O interrupts are floating
(and only in S/390 & z/Arch).. Some Machine Checks may also be floating
(External Damage may be floating).
There are 6 classes of interrupts :
- Program Interrupt : They relate to an exception or condition
encountered during execution of an instruction. They may be related to
the operation code, operation parameters, address translation, tracing,
- SVC Interrupt : Every time the SVC instruction is executed
- I/O : Pertains the a device meaning to present some status to the CPU
- which may be solicited - the result of an ongoing I/O operation, or
unsolicited (Attention or not-ready to ready state switch)
- External : Various non-damage conditions : Timing, inter-cpu
communication, Service Processor communication, the 'External' operator
button, etc.. (there are more)
- Machine check : Various possibly damage conditions : System damage,
instruction damage, External Damage (I/O damage goes there IIRC) and
some non damage conditions such as I/O reconfiguration.. Machine check
may also be presented to indicate an error occurred but was fixed
internally like when a single bit error in storage was fixed by ECC.
- Restart : Operator initiated non maskable interrupt (depending on the
Operating System, this may be used to trigger a dump when the system has
entered a disabled loop). Note that the RESTART new PSW is at the same
location as the IPL PSW - which means that on simple IPLable programs,
RESTART will actually restart the program from the beginning !
Now.. Interrupts are not THAT complicated. Some interrupts are
synchronous (and deal with the execution of instructions). These are the
Program and SVC interrupts. Others are asynchronous (in that they can
occur when executing instructions or when being in a wait state but are
not usually the direct consequence of the execution of a particular
instruction) : I/O, EXT and RESTART. Machine check can be both
(depending on the reason for the machine check).
Except for the RESTART Interrupt, asynchronous Interrupts may be masked.
The primary mask is in the PSW (and is called the System Mask which can
be manipulated with SSM, STNSM, STOSM and of course LPSW).. There are
also subclass masks that can more finely mask interrupts (CR0 contain
EXT related subclass masks while CR2 (in S/370) and CR6 (in S/390 &
z/Arch) contain I/O subclass masks. The primary reason why the control
register was changed is probably related to the fact that the masking
mechanism was changed from Channel number based to a subchannel
The interrupt process itself is fairly simple : The current PSW is
stored at the 'OLD PSW' location and the 'NEW PSW' is loaded in the
actual PSW. Those fields are located in the famous low storage area we
have been discussing. Each interrupt class has its own OLD/NEW PSW
locations and are defined by the architecture. Since z/Architecture has
128 bit PSWs (not to mention a fairly different format), they had to be
relocated in order not to conflict with previously existing locations.
Some interrupts are cleared simply by them firing : I/O, Machine Check,
Program, SVC, Restart. For External, it depends on the cause but
basically Clock Comparator and CPU Timer interrupts are NOT cleared by
taking the interrupt (they are only cleared when the respective reason
for the interrupt is cleared). For non self clearing interrupts - having
a NEW PSW that is enabled for the interrupt class will lead to an
The location of the interrupt code (the *reason* for the interrupt or
the I/O device causing the interrupt) is located, again, in the low
storage area. The location is dependent on both the architecture and the
PSW format used (BC or EC). This code allows the interrupt handler to
determine what action to take. This really IS the main reason that each
CPU needs its own low storage area and the primary reason for the Prefix
register & mechanism.
I/O interrupts for a specific device can also sometimes merge - and the
status bits in the CSW/SCSW will have been OR'd (there are some merging
conditions though.. they will not ALWAYS merge).
Interrupts also have defined priorities, so if more than 1 interrupt
class is pending, the order in which they will be presented to the CPU
Although Machine Check interrupts can be masked, if the machine check is
a repressible machine check (like instruction damage or system damage)
then the system will enter a check stop state because it is no longer
safe to continue operations. This may also occur if a machine check
interrupt occurs while there is already a machine check interrupt being
processed (even with the machine check mask enabled).
If you look at it, interrupts on S/370, S/390 and z/Arch are a whole lot
simpler than it is on x86 for example (there is no need for internal
knowledge of PICs & bus interrupt mechanism) and the interrupt process
is perfectly well defined by the architecture itself - that is - it is
not implementation dependent.
Finally, here is a (not even tried) small sample program that can be
IPLed (it's 3CARD LOADER Compatible since there are no ADCONs) that will
loop for 1 second until the CPU Timer interrupt occurs and then loads a
disabled wait PSW. There may be some errors since I haven't even tried
to compile it - and it may not even work - but if it doesn't it
shouldn't be hard to fix ! It should give you an idea of how simple
handling interrupts is.
START1 CSECT *
START DS 0H
BALR 12,0 * ESTABLISH ADDRESSABILITY
MVC EXTNPSW(8),MYEXTN * SET NEW EXT PSW
LA 1,EXTH * GET HANDLER ADDRESS
ST 1,EXTNPSW+4 * SAVE IN NEW PSW
STCTL 0,0,WORK1 * GET CR0
OI WORK1+2,X'04' * ENABLE CPU TIMER SUBCLASS
NI WORK1+2,X'7F' * DISABLE CLOCK COMP
LCTL 0,0,WORK1 * RELOAD MODIFIED CR0
SCPT SEC1SEC * SET THE CPU TIMER VALUE (~1SEC)
LA 1,CONT * LOAD LOOP ADDR
ST 1,CONTPSW+4 * SAVE IN PSW
LPSW CONTPSW * THAT WE LOAD NOW
CONT DS 0H
TM FIRED,X'80' * HAS THE CPU TIMER FIRE ?
BNZ CONT * NOPE.. LOOP SOME MORE
LPSW DISAWAIT * YES.. EOJ
* EXTERNAL INTERRUPT HANDLER
* (NOTE WE ASSUME WE HAVE ADDRESSABILITY)
EXTH DS 0H
CLC EXTINT(2),=XL2'1005' * CPT INT ?
BNZ NOTCPT * NOPE
OI FIRED,X'80' * INDICATE CPT FIRED
NOTCPT DS 0H
LPSW EXTOPSW * BACK WHENCE WE CAME FROM
* END OF EXT HANDLER
SEC1SEC DC AL4(1),AL4(0) *APPROX. 1 SEC
MYEXTN DC X'00080000',AL4(*-*)
CONTPSW DC X'02080000',AL4(*-*)
DISAPSW DC X'000A0000',AL4(0)
WORK1 DS F
FIRED DC X'00'
* SOME PSA LOCATIONS
EXTNPSW EQU X'58'
EXTOPSW EQU X'18'
EXTINT EQU X'86'