Program Status Word
The Program Status Word (PSW) on IBM Mainframe architectures (s390x / z/Architecture and ESA/390) is the central execution context register of the CPU. It controls the instruction address, execution state (supervisor vs. user/problem state, wait state), DAT (paging), interrupt masks, condition code, arithmetic exception masks, storage protection keys, and addressing modes.
Depending on the operational mode and the instruction used, the CPU works with three distinct PSW formats:
- Extended PSW (16 bytes / 128 bits): The standard native format in 64-bit z/Architecture, commonly referred to as a current PSW.
- Short PSW (8 bytes / 64 bits): An 8-byte format used within z/Architecture when executing legacy instructions like
LPSWor processing certain I/O/interruption structures. - ESA/390 PSW (8 bytes / 64 bits): The native 31-bit format used when the CPU is running in ESA/390 mode (e.g., before switching to z/Architecture or in 31-bit guest partitions).
Bit Numbering Convention
In standard IBM Principles of Operation (PoP) documentation and hardware specifications, Bit 0 is the Most Significant Bit (MSB 0).
- In a 64-bit doubleword: Bit 0 is
0x8000000000000000ULL, Bit 63 is0x0000000000000001ULL. - In a 32-bit word: Bit 0 is
0x80000000U, Bit 31 is0x00000001U.
1. Extended PSW (16-Byte z/Architecture Format)
The native z/Architecture format consists of two 64-bit doublewords (16 bytes total, 8-byte aligned) loaded via LPSWE.
Doubleword 0: PSW Mask (Bits 0–63)
| Bits (MSB 0) | Bitmask (64-bit) | Short | Name | Description |
|---|---|---|---|---|
| 0 | — | — | Reserved | Must be 0; otherwise triggers a Specification Exception (`PGM_SPECIFICATION`). |
| 1 | 0x4000000000000000ULL |
R | Program Event Recording (PER) | 1 = PER enabled (hardware debugging/trace traps). |
| 2–4 | — | — | Reserved | Must be 0. |
| 5 | 0x0400000000000000ULL |
T | Dynamic Address Translation (DAT) | 1 = DAT enabled (virtual addressing). 0 = Real/Absolute addressing. |
| 6 | 0x0200000000000000ULL |
IO | I/O Interrupt Mask | 1 = Input/Output interruptions unmasked. |
| 7 | 0x0100000000000000ULL |
EX | External Interrupt Mask | 1 = External interruptions (timers, inter-CPU signals) unmasked. |
| 8–11 | 0x00F0000000000000ULL |
Key | PSW Storage Key | 4-bit storage access key (0 = master key). |
| 12 | — | — | Architecture Mode | Must be 0 in z/Architecture. |
| 13 | 0x0004000000000000ULL |
M | Machine-Check Mask | 1 = Machine-check interruptions unmasked. |
| 14 | 0x0002000000000000ULL |
W | Wait State | 1 = CPU is halted in wait state. |
| 15 | 0x0001000000000000ULL |
P | Problem State | 0 = Supervisor state (Privileged), 1 = Problem state (User mode). |
| 16–17 | 0x0000C00000000000ULL |
AS | Address-Space Control (ASC) | Determines the active translation table register (CR1, CR7, or CR13). |
| 18–19 | 0x0000300000000000ULL |
CC | Condition Code | Condition code (0, 1, 2, or 3). |
| 20–23 | 0x00000F0000000000ULL |
PM | Program Mask | Arithmetic exception masks (Fixed-point overflow, Decimal overflow, HFP underflow, HFP significance). |
| 24–30 | — | — | Reserved | Must be 0. |
| 31 | 0x0000000100000000ULL |
EA | Extended Addressing Mode | Extended addressing mode bit. |
| 32 | 0x0000000080000000ULL |
BA | Basic Addressing Mode | Basic addressing mode bit. |
| 33–63 | — | — | Reserved | Must be 0 in the 16-byte PSW mask. |
Doubleword 1: Instruction Address (Bits 64–127)
- Holds the 64-bit virtual/absolute instruction address.
- Bit 127 must be 0 (all s390x instructions are aligned to 2-byte halfwords).
2. Short PSW (8-Byte z/Architecture Format)
In z/Architecture mode, an 8-byte (64-bit) Short PSW format exists primarily to maintain compatibility with software or instructions that only pass 64-bit descriptors (such as LPSW, legacy channel programs, and certain diagnostics).
Unlike the 16-byte PSW, the Short PSW packs both the control flags and a 31-bit instruction address into a single 64-bit word.
Short PSW Layout
| Bits (MSB 0) | Short | Name | Description |
|---|---|---|---|
| 0 | — | Reserved | Must be 0. |
| 1 | R | PER Mask | Program Event Recording. |
| 2–4 | — | Reserved | Must be 0. |
| 5 | T | DAT Mode | Dynamic Address Translation. |
| 6 | IO | I/O Mask | I/O Interrupt Enable. |
| 7 | EX | External Mask | External Interrupt Enable. |
| 8–11 | Key | Storage Key | 4-bit storage protection key. |
| 12 | — | Architecture Mode | Must be 0 in z/Architecture. |
| 13 | M | Machine Check | Machine Check Interrupt Enable. |
| 14 | W | Wait State | CPU Wait State. |
| 15 | P | Problem State | Problem State (0 = Supervisor, 1 = User). |
| 16–17 | AS | Address-Space Control | Primary (00), Secondary (01), AR (10), Home (11). |
| 18–19 | CC | Condition Code | Condition code. |
| 20–23 | PM | Program Mask | Arithmetic masks. |
| 24–30 | — | Reserved | Must be 0. |
| 31 | EA | Extended Addressing | Extended addressing mode bit. |
| 32 | BA | Basic Addressing | Basic addressing mode bit. |
| 33–63 | IA | Instruction Address | 31-bit instruction address (Target PC). |
Behavior of LPSW in z/Architecture
When the LPSW (opcode `82`) instruction is executed in z/Architecture mode:
- Bits 0–32 of the 8-byte operand are loaded directly into bits 0–32 of the CPU's internal 64-bit PSW mask.
- Bits 33–63 of the internal PSW mask are set to 0.
- Bits 0–32 of the internal 64-bit instruction address are set to 0.
- Bits 33–63 of the 8-byte operand are loaded into bits 33–63 of the internal instruction address.
3. ESA/390 Mode PSW (8-Byte Legacy Format)
When the processor is running in ESA/390 mode (e.g. at initial IPL before sending a `SIGP` architecture-switch signal, or inside a 31-bit legacy virtual machine), the CPU uses the legacy 64-bit ESA/390 Extended Control (EC-mode) PSW.
ESA/390 PSW Layout
| Bits (MSB 0) | Short | Name | Description |
|---|---|---|---|
| 0 | — | Reserved | Must be 0. |
| 1 | R | PER Mask | Program Event Recording. |
| 2–4 | — | Reserved | Must be 0. |
| 5 | T | DAT Mode | Dynamic Address Translation. |
| 6 | IO | I/O Mask | I/O Interrupt Enable. |
| 7 | EX | External Mask | External Interrupt Enable. |
| 8–11 | Key | Storage Key | 4-bit storage key. |
| 12 | A | Architecture Mode | Must be 1 in ESA/390 EC-mode. |
| 13 | M | Machine Check | Machine Check Mask. |
| 14 | W | Wait State | Wait State flag. |
| 15 | P | Problem State | Problem State flag. |
| 16–17 | AS | Address-Space Control | Primary (00), Secondary (01), AR (10), Home (11). |
| 18–19 | CC | Condition Code | Condition code. |
| 20–23 | PM | Program Mask | Arithmetic masks. |
| 24–31 | — | Reserved | Must be 0. |
| 32 | A | Addressing Mode | 0 = 24-bit AMODE, 1 = 31-bit AMODE. |
| 33–63 | IA | Instruction Address | 31-bit instruction address. |
Differences Between Short PSW and ESA/390 PSW
While both formats are 8 bytes long:
- Bit 12: Is
0in z/Architecture Short PSW, but must be1in ESA/390 EC-mode. - Bit 31: Is
EA(Extended Addressing) in z/Arch Short PSW, but is a reserved 0 bit in ESA/390. - Bit 32: Is
BA(Basic Addressing) in z/Arch Short PSW, but represents the sole 31-bit addressing mode flag in ESA/390.
Addressing Modes (AMODE)
In z/Architecture (both 16-byte and Short PSW), addressing modes are controlled by the pair of bits EA (Bit 31) and BA (Bit 32):
| EA (Bit 31) | BA (Bit 32) | Mode | Address Bits Evaluated |
|---|---|---|---|
| 0 | 0 | 24-bit addressing | Lower 24 bits (Bits 40–63) |
| 0 | 1 | 31-bit addressing | Lower 31 bits (Bits 33–63) |
| 1 | 1 | 64-bit addressing | Full 64 bits (Bits 0–63) |
| 1 | 0 | Invalid | Triggers a Specification Exception (`PGM_SPECIFICATION`). |
Address Space Control (ASC) Modes
When DAT is enabled (Bit 5 = 1), bits 16–17 select the active translation mode:
| Bits 16–17 | Mode | Active ASCE Source | Usage |
|---|---|---|---|
00 |
Primary-space mode | Control Register 1 (CR1) | Standard user/kernel virtual address space. |
01 |
Secondary-space mode | Control Register 7 (CR7) | Cross-memory communication. |
10 |
Access-register (AR) mode | Access Registers (AR0–AR15) | Fine-grained multi-space addressing via ALETs. |
11 |
Home-space mode | Control Register 13 (CR13) | Kernel / system-wide execution space. |
Interruption Lowcore Vectors
In 64-bit z/Architecture, interruptions automatically save the current 16-byte PSW to an Old PSW field in the Lowcore (the Prefix Page, real offset `0x0000`), and load the execution context from the corresponding 16-byte New PSW:
| Interruption Class | Old PSW Offset | New PSW Offset |
|---|---|---|
| Restart | 0x0120 |
0x01A0
|
| External | 0x0130 |
0x01B0
|
| Supervisor Call (SVC) | 0x0140 |
0x01C0
|
| Program Check (Exception) | 0x0150 |
0x01D0
|
| Machine Check | 0x0160 |
0x01E0
|
| Input/Output (I/O) | 0x0170 |
0x01F0
|
(Note: In legacy ESA/390 31-bit mode, Old and New PSWs are 8 bytes each and reside at offsets `0x0018`–`0x0078`).
C Structures & Code Examples
C Definitions for All Three PSW Types
#include <stdint.h>
/* 1. Standard 16-byte z/Architecture Extended PSW */
typedef struct __attribute__((packed, aligned(8))) {
uint64_t mask;
uint64_t addr;
} zpsw_t;
/* 2. 8-byte z/Architecture Short PSW (used by LPSW under z/Arch) */
typedef struct __attribute__((packed, aligned(8))) {
uint32_t mask_flags; /* Bits 0..32: Control flags + EA/BA */
uint32_t addr_31; /* Bits 33..63: 31-bit address */
} short_psw_t;
/* 3. 8-byte legacy ESA/390 Mode PSW */
typedef struct __attribute__((packed, aligned(8))) {
uint32_t mask_flags; /* Bits 0..31: Includes Bit 12 (EC mode = 1) */
uint32_t addr_31; /* Bit 32 = AMODE31 flag, Bits 33..63 = 31-bit address */
} esa390_psw_t;
/* Extended PSW Mask Constants (MSB 0) */
#define PSW_MASK_PER (0x4000000000000000ULL)
#define PSW_MASK_DAT (0x0400000000000000ULL)
#define PSW_MASK_IO (0x0200000000000000ULL)
#define PSW_MASK_EXT (0x0100000000000000ULL)
#define PSW_MASK_KEY(k) (((uint64_t)((k) & 0x0F)) << 52)
#define PSW_MASK_MCHECK (0x0004000000000000ULL)
#define PSW_MASK_WAIT (0x0002000000000000ULL)
#define PSW_MASK_PROBLEM (0x0001000000000000ULL)
/* Address Space Control Modes */
#define PSW_ASC_PRIMARY (0x0000000000000000ULL)
#define PSW_ASC_SECONDARY (0x0000800000000000ULL)
#define PSW_ASC_ACCREG (0x0000400000000000ULL)
#define PSW_ASC_HOME (0x0000C00000000000ULL)
/* 64-bit Addressing Mode (EA=1 | BA=1) */
#define PSW_MASK_EA (0x0000000100000000ULL)
#define PSW_MASK_BA (0x0000000080000000ULL)
#define PSW_MASK_AMODE64 (PSW_MASK_EA | PSW_MASK_BA)
/* Standard Pre-composed 64-bit Kernel Masks */
#define PSW_KERNEL_BOOT \
(PSW_MASK_AMODE64 | PSW_ASC_PRIMARY)
#define PSW_KERNEL_RUNNING \
(PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | PSW_MASK_AMODE64 | PSW_ASC_HOME)
#define PSW_USER_RUNNING \
(PSW_MASK_PROBLEM | PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | PSW_MASK_AMODE64 | PSW_ASC_PRIMARY)
Loading PSWs
Loading a 16-Byte Extended PSW (LPSWE)
static inline __attribute__((noreturn)) void lpswe(const zpsw_t *psw) {
__asm__ volatile (
"lpswe %0\n"
:
: "Q" (*psw)
: "cc", "memory"
);
__builtin_unreachable();
}
Loading an 8-Byte Short PSW (LPSW)
static inline __attribute__((noreturn)) void lpsw(const short_psw_t *psw) {
__asm__ volatile (
"lpsw %0\n"
:
: "Q" (*psw)
: "cc", "memory"
);
__builtin_unreachable();
}
Extracting Current PSW Mask (EPSW)
static inline uint64_t epsw(void) {
uint32_t hi, lo;
__asm__ volatile (
"epsw %0, %1\n"
: "=d" (hi), "=d" (lo)
);
return ((uint64_t)hi << 32) | (uint64_t)lo;
}
CPU Idle & Panic Idioms
Enabled Wait (Idle Loop)
void cpu_idle(void) {
zpsw_t wait_pswrest = {
.mask direct = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT |
PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_MASK_AMODE64 | PSW_ASC_HOME,
.addr = (uint64_t)&&wake_up
};
lpswe(&wait_pswrest);
wake_up:
return;
}
Disabled Wait (Panic / Halt)
__attribute__((noreturn)) void cpu_halt(uint64_t panic_code) {
zpsw_t halt_psw = {
.mask = PSW_MASK_WAIT | PSW_MASK_AMODE64,
.addr地理 = (panic_code != 0) ? panic_code : 0x0000000000DEAD00ULL
};
lpswe(&halt_psw);
}