/**
* @file Legacy8259.h
* @brief Legacy 8259 Programmable Interrupt Controller (PIC) UEFI Driver - Header
*
* UEFI DXE driver for the Intel 8259 Programmable Interrupt Controller (PIC).
* Manages the legacy 8259 PIC hardware and provides the EFI_LEGACY_8259_PROTOCOL
* interface. Handles PIC initialization (ICW1-ICW4), interrupt masking via IMR,
* mode switching (legacy vs virtual wire), IRQ-to-vector translation, and
* End-of-Interrupt (EOI) signaling.
*
* The driver is loaded during DXE phase and publishes its protocol using
* gBS->InstallProtocolInterface(). It uses TPL_HIGH_LEVEL during PIC
* programming to prevent interrupt delivery while the PIC is in an
* inconsistent state.
*
* Hardware ports:
* Master PIC: command = 0x20, data = 0x21 (IRQ0-IRQ7)
* Slave PIC: command = 0xA0, data = 0xA1 (IRQ8-IRQ15, cascaded on IRQ2)
* ELCR: master = 0x4D0, slave = 0x4D1 (Edge/Level Control Registers)
* CMOS/RTC: address = 0x70, data = 0x71
*
* Source layout (from IDA analysis of Legacy8259.efi):
* .text: 0x2C0-0xC80 (code)
* .rdata: 0xC80-0xFE0 (strings, GUIDs)
* .data: 0xFE0-0x10E0 (globals: IMR caches, mode, dispatch table)
*/
#ifndef __LEGACY8259_H__
#define __LEGACY8259_H__
#include "../uefi_headers/Uefi.h"
/*=============================================================================
* GUID Definitions
*============================================================================*/
/**
* EFI_LEGACY_8259_PROTOCOL_GUID
* Protocol GUID for the Legacy 8259 PIC driver.
* This is the GUID installed via InstallProtocolInterface().
* EDK2 canonical: PcAtChipsetPkg/Include/Protocol/Legacy8259.h
*
* GUID value: { 0x38321dba, 0x4fe0, 0x4e17,
* { 0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1 } }
*/
#define EFI_LEGACY_8259_PROTOCOL_GUID \
{ 0x38321DBA, 0x4FE0, 0x4E17, \
{ 0x8A, 0xEC, 0x41, 0x30, 0x55, 0xEA, 0xED, 0xC1 } }
/**
* gEfiHobListGuid
* GUID for locating the HOB (Hand-Off Block) list from the UEFI system
* configuration table. Standard UEFI PI specification GUID.
*
* GUID value: { 0x7739f24c, 0x93d7, 0x11d4,
* { 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } }
*/
#define EFI_HOB_LIST_GUID \
{ 0x7739F24C, 0x93D7, 0x11D4, \
{ 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }
/**
* Debug output protocol GUID (platform-specific).
* Used with LocateProtocol() to locate a protocol for debug/assert
* message output during PIC driver initialization.
*
* GUID value: { 0x36292336, 0x0E76, 0x31C8,
* { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } }
*/
#define EFI_DEBUG_OUTPUT_PROTOCOL_GUID \
{ 0x36292336, 0x0E76, 0x31C8, \
{ 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } }
/**
* PCAT compatibility protocol GUID (platform-specific).
* Used with HandleProtocol() to open a protocol that provides the
* PCAT_COMPAT flag for determining whether dual 8259 PICs are present.
*
* GUID value: { 0x4CF5B200, 0x68B8, 0x4CA5,
* { 0x9E, 0xEC, 0xB2, 0x3E, 0x3F, 0x50, 0x02, 0x9A } }
*/
#define EFI_PCAT_COMPAT_PROTOCOL_GUID \
{ 0x4CF5B200, 0x68B8, 0x4CA5, \
{ 0x9E, 0xEC, 0xB2, 0x3E, 0x3F, 0x50, 0x02, 0x9A } }
/*=============================================================================
* Protocol Interface Structure
*============================================================================*/
/**
* Forward declaration of the Legacy8259 protocol structure.
*/
typedef struct _EFI_LEGACY_8259_PROTOCOL EFI_LEGACY_8259_PROTOCOL;
/*=============================================================================
* PIC Hardware Constants
*============================================================================*/
/**
* Intel 8259A I/O Ports.
* The master PIC controls IRQ0-IRQ7; the slave PIC controls IRQ8-IRQ15.
* The slave is cascaded to the master through IRQ2.
*/
#define LEGACY_8259_MASTER_PIC_CMD 0x20 /**< Master PIC command port (ICW1/OCW2/OCW3) */
#define LEGACY_8259_MASTER_PIC_DATA 0x21 /**< Master PIC data port (ICW2/ICW3/ICW4/OCW1) */
#define LEGACY_8259_SLAVE_PIC_CMD 0xA0 /**< Slave PIC command port */
#define LEGACY_8259_SLAVE_PIC_DATA 0xA1 /**< Slave PIC data port */
#define LEGACY_8259_ELCR1 0x4D0 /**< Edge/Level Control Register 1 (master IRQ0-IRQ7) */
#define LEGACY_8259_ELCR2 0x4D1 /**< Edge/Level Control Register 2 (slave IRQ8-IRQ15) */
/**
* PIC ICW (Initialization Command Word) constants.
* ICW1 is written to the command port; ICW2-ICW4 are written to the data port.
*/
#define LEGACY_8259_ICW1_ICW4 0x01 /**< ICW4 will be issued */
#define LEGACY_8259_ICW1_SINGLE 0x02 /**< Single (cascade) mode */
#define LEGACY_8259_ICW1_INTERVAL4 0x04 /**< Call address interval 4 */
#define LEGACY_8259_ICW1_LEVEL 0x08 /**< Level triggered mode */
#define LEGACY_8259_ICW1_INIT 0x10 /**< Initialization command */
#define LEGACY_8259_ICW4_8086 0x01 /**< 8086/88 mode */
#define LEGACY_8259_ICW4_AUTO 0x02 /**< Auto EOI */
#define LEGACY_8259_ICW4_BUF_MASTER 0x0C /**< Buffered mode/master */
#define LEGACY_8259_ICW4_BUF_SLAVE 0x08 /**< Buffered mode/slave */
#define LEGACY_8259_ICW4_SFNM 0x10 /**< Special fully nested mode */
/**
* ICW1 value for full initialization sequence with ICW4 in cascade mode.
* ICW2: Vector base addresses.
* Master PIC: 0x58 = 88 (IRQ0-IRQ7 map to vectors 88-95)
* Slave PIC: 0x70 = 112 (IRQ8-IRQ15 map to vectors 112-119)
*/
#define LEGACY_8259_ICW1_INIT_SEQ (LEGACY_8259_ICW1_ICW4 | LEGACY_8259_ICW1_INIT) /* 0x11 */
#define LEGACY_8259_MASTER_VECTOR_BASE 0x58 /**< ICW2 for master (IRQ0-IRQ7 -> INT 0x58-0x5F) */
#define LEGACY_8259_SLAVE_VECTOR_BASE 0x70 /**< ICW2 for slave (IRQ8-IRQ15 -> INT 0x70-0x77) */
/**
* ICW3: Cascade maps.
* Master ICW3 bits indicate which IRQ lines have slave PICs attached.
* Slave ICW3 lower 3 bits indicate the slave's cascade IRQ on the master.
*/
#define LEGACY_8259_ICW3_MASTER_CASCADE 0x04 /**< Master has slave on IRQ2 */
#define LEGACY_8259_ICW3_SLAVE_CASCADE 0x02 /**< Slave connected to master IRQ2 */
/**
* OCW (Operation Command Word) constants.
* OCW2: EOI commands.
* OCW3: Read IRR/ISR commands.
*/
#define LEGACY_8259_OCW2_NON_SPECIFIC_EOI 0x20 /**< Non-specific EOI */
#define LEGACY_8259_OCW2_SPECIFIC_EOI 0x60 /**< Specific EOI + IRQ# */
#define LEGACY_8259_OCW3_READ_IRR 0x0A /**< Read Interrupt Request Register */
#define LEGACY_8259_OCW3_READ_ISR 0x0B /**< Read In-Service Register */
#define LEGACY_8259_OCW3_POLL 0x0C /**< Poll command */
/**
* EOI command (non-specific).
*/
#define LEGACY_8259_EOI LEGACY_8259_OCW2_NON_SPECIFIC_EOI /**< 0x20 */
/**
* Interrupt Mask Register bit definitions.
* Each bit corresponds to one IRQ line; 1 = masked (disabled), 0 = enabled.
*/
#define LEGACY_8259_IRQ0_TIMER 0x01 /**< Master bit 0: System Timer (IRQ0) */
#define LEGACY_8259_IRQ1_KEYBOARD 0x02 /**< Master bit 1: Keyboard (IRQ1) */
#define LEGACY_8259_IRQ2_CASCADE 0x04 /**< Master bit 2: Slave PIC cascade (IRQ2) */
#define LEGACY_8259_IRQ8_CMOS_RTC 0x01 /**< Slave bit 0: RTC CMOS (IRQ8) */
#define LEGACY_8259_IRQ13_FPU 0x20 /**< Slave bit 5: FPU (IRQ13) */
/**
* IRQ count and limits.
*/
#define LEGACY_8259_NUM_IRQS 16 /**< Total IRQs (master 0-7 + slave 8-15) */
#define LEGACY_8259_MASTER_IRQ_COUNT 8 /**< IRQs handled by master PIC */
#define LEGACY_8259_SLAVE_IRQ_COUNT 8 /**< IRQs handled by slave PIC */
/*=============================================================================
* PIC State Structure
*============================================================================*/
/**
* Snapshot of the 8259 PIC register state.
* Stores the current Interrupt Mask Register (IMR) values and
* Edge/Level Control Register (ELCR) values for both master and slave PICs.
*/
typedef struct {
UINT16 MasterImr; /**< Master PIC IMR (OCW1) value at port 0x21. Bit n = IRQn mask (1=disabled). */
UINT16 SlaveImr; /**< Slave PIC IMR (OCW1) value at port 0xA1. Bit (n-8) = IRQn mask. */
UINT16 Elcr1; /**< Master PIC ELCR at port 0x4D0. Bit n = IRQn trigger (0=edge, 1=level). */
UINT16 Elcr2; /**< Slave PIC ELCR at port 0x4D1. Bit (n-8) = IRQn trigger. */
} LEGACY_8259_STATE;
/*=============================================================================
* Mode Definitions
*============================================================================*/
/**
* PIC operating modes.
*
* LEGACY_8259_MODE_LEGACY (0):
* - 8259 PIC is fully operational
* - All 16 IRQs are routed through the PIC
* - IMR controls which interrupts are masked
* - Used for backward compatibility with legacy software
*
* LEGACY_8259_MODE_VIRTUAL_WIRE (1):
* - PIC is minimally configured for APIC compatibility
* - Only IRQ0 (timer) is routed through PIC master
* - All other interrupts go through I/O APIC
* - Bit 0 of IMR is cleared to allow timer through
* - Used when platform boots with APIC enabled
*/
#define LEGACY_8259_MODE_LEGACY 0
#define LEGACY_8259_MODE_VIRTUAL_WIRE 1
/*=============================================================================
* Function Dispatch Table (Protocol Interface)
*============================================================================*/
/**
* Initialize the 8259 PIC with ICW1-ICW4 programming.
*
* Programs both master and slave PICs with:
* - ICW1: Initialization command word (0x11)
* - ICW2: Vector base address
* - ICW3: Cascade connection map
* - ICW4: 8086 mode, non-buffered, normal EOI
*
* Writes initial IMR values from the global state to hardware.
* Raises to TPL_HIGH_LEVEL during programming to prevent interrupt
* delivery while PIC is in an inconsistent state.
*
* @param[in] This Protocol instance pointer
* @param[in] MasterBase ICW2 vector base for master PIC (default 0x58)
* @param[in] SlaveBase ICW2 vector base for slave PIC (default 0x70)
*
* @retval EFI_SUCCESS PIC programmed successfully
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_INITIALIZE)(
IN EFI_LEGACY_8259_PROTOCOL *This,
IN UINT8 MasterBase,
IN UINT8 SlaveBase
);
/**
* Read the current PIC state (IMR and ELCR values).
*
* Reads the cached PIC register values and returns them in the
* provided LEGACY_8259_STATE structure.
*
* @param[in] This Protocol instance pointer
* @param[out] State Structure receiving current PIC state values
*
* @retval EFI_SUCCESS State read successfully
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_GET_STATE)(
IN EFI_LEGACY_8259_PROTOCOL *This,
OUT LEGACY_8259_STATE *State
);
/**
* Write new PIC state (update IMR and ELCR registers).
*
* Programs the PIC hardware with provided IMR and ELCR values.
* The behavior depends on the current operating mode:
* - In LEGACY_8259_MODE_VIRTUAL_WIRE (1): writes the provided values directly.
* - In LEGACY_8259_MODE_LEGACY (0): writes provided IMR plus ELCR values
* with cascade preservation.
*
* @param[in] This Protocol instance pointer
* @param[in] State Structure containing new PIC state values
*
* @retval EFI_SUCCESS State written successfully
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_SET_STATE)(
IN EFI_LEGACY_8259_PROTOCOL *This,
IN LEGACY_8259_STATE *State
);
/**
* Set PIC operating mode (legacy vs virtual wire).
*
* When switching modes, saves the current IMR values from both PICs,
* adjusts the IRQ0 (timer) mask, and writes the updated masks.
*
* LEGACY_8259_MODE_LEGACY (0):
* - Saves current IMR from both PICs and ELCR values
* - Sets mode internal flag to 0 (legacy)
* - Writes original masks with ELCR cascade preservation
*
* LEGACY_8259_MODE_VIRTUAL_WIRE (1):
* - Saves current IMR from master and slave
* - Clears IRQ0 mask in master IMR, preserves IRQ0 in ELCR
* - Sets mode internal flag to 1 (virtual wire)
* - Writes updated masks
*
* @param[in] This Protocol instance pointer
* @param[in] Mode LEGACY_8259_MODE_LEGACY (0) or
* LEGACY_8259_MODE_VIRTUAL_WIRE (1)
*
* @retval EFI_SUCCESS Mode changed successfully
* @retval EFI_INVALID_PARAMETER Mode is not 0 or 1
* @retval EFI_UNSUPPORTED Invalid mode value
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_SET_MODE)(
IN EFI_LEGACY_8259_PROTOCOL *This,
IN UINT8 Mode
);
/**
* Get the interrupt vector number for a given IRQ.
*
* Converts IRQ# (0-15) to the hardware interrupt vector by adding
* the appropriate PIC vector base. Master PIC IRQs (0-7) use the
* master base (0x58). Slave PIC IRQs (8-15) use the slave base (0x70)
* minus 8 to account for the offset.
*
* @param[in] This Protocol instance pointer
* @param[in] Irq IRQ number (0-15)
* @param[out] Vector Output interrupt vector number
*
* @retval EFI_SUCCESS Vector computed successfully
* @retval EFI_INVALID_PARAMETER Irq > 15
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_GET_VECTOR)(
IN EFI_LEGACY_8259_PROTOCOL *This,
IN UINT8 Irq,
OUT UINT8 *Vector
);
/**
* Enable or disable a specific IRQ in the PIC mask and ELCR.
*
* Updates the Interrupt Mask Register (IMR) and ELCR for the specified IRQ:
* - If Enable is TRUE: clears the IMR bit (unmasks) and sets the ELCR bit
* to level-triggered mode.
* - If Enable is FALSE: sets the IMR bit (masks) and clears the ELCR bit
* to edge-triggered mode.
*
* Writes new IMR/ELCR values directly to PIC hardware ports.
*
* @param[in] This Protocol instance pointer
* @param[in] Irq IRQ number (0-15)
* @param[in] Enable TRUE=unmask+level, FALSE=mask+edge
*
* @retval EFI_SUCCESS IRQ mask updated
* @retval EFI_INVALID_PARAMETER IRQ > 15
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_ENABLE_IRQ)(
IN EFI_LEGACY_8259_PROTOCOL *This,
IN UINT8 Irq,
IN BOOLEAN Enable
);
/**
* Disable a specific IRQ in both IMR and ELCR.
*
* Unconditionally masks the IRQ in both the master/slave IMR (sets the bit)
* AND clears the ELCR bit (edge-triggered mode). For slave IRQs (>= 8),
* also sends an EOI to the slave PIC first.
*
* Writes updated values to all PIC hardware registers.
*
* @param[in] This Protocol instance pointer
* @param[in] Irq IRQ number (0-15)
*
* @retval EFI_SUCCESS IRQ disabled
* @retval EFI_INVALID_PARAMETER IRQ > 15
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_DISABLE_IRQ)(
IN EFI_LEGACY_8259_PROTOCOL *This,
IN UINT8 Irq
);
/**
* Send End-Of-Interrupt (EOI) to the PIC(s).
*
* Issues a non-specific EOI command (0x20) to the appropriate PIC(s):
* - If IRQ >= 8: sends EOI to slave PIC first (port 0xA0)
* - Always: sends EOI to master PIC (port 0x20)
*
* @param[in] This Protocol instance pointer
* @param[in] Irq IRQ number (0-15) that is being completed
*
* @retval EFI_SUCCESS EOI sent
* @retval EFI_INVALID_PARAMETER IRQ > 15
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_END_OF_INTERRUPT)(
IN EFI_LEGACY_8259_PROTOCOL *This,
IN UINT8 Irq
);
/**
* Read the PCAT compatibility flag from the platform protocol.
*
* Opens a platform-specific protocol on the ACPI handle and reads the
* PCAT_COMPAT flag at offset 60 (0x3C), which indicates whether dual
* 8259 PICs are present and must be configured:
* = Non-zero: Dual 8259 PICs are present
* = 0: Only APIC mode; 8259 PICs may not exist
*
* @param[in] This Protocol instance pointer
* @param[in] Handle Handle that supports the PCAT compatibility protocol
* @param[out] PcatFlags PCAT_COMPAT flag byte (offset 60 of protocol)
*
* @retval EFI_SUCCESS Flag read successfully
* @retval EFI_INVALID_PARAMETER Handle does not support the protocol
* @retval EFI_UNSUPPORTED Protocol not found on handle
*/
typedef
EFI_STATUS
(EFIAPI *LEGACY_8259_GET_PCAT_COMPATIBILITY_FLAG)(
IN EFI_LEGACY_8259_PROTOCOL *This,
IN EFI_HANDLE Handle,
OUT UINT8 *PcatFlags
);
/*=============================================================================
* Protocol Structure
*============================================================================*/
#define LEGACY_8259_PROTOCOL_INTERFACE_REVISION 1
/**
* EFI_LEGACY_8259_PROTOCOL structure.
*
* This is the published protocol interface for the Legacy 8259 PIC driver.
* All members are function pointers installed via
* gBS->InstallProtocolInterface() during driver initialization.
*
* Dispatch table offsets (relative to protocol base):
* +0x00: InitPic (Legacy8259InitPic)
* +0x01: GetState (Legacy8259GetState)
* +0x02: SetState (Legacy8259SetState)
* +0x03: SetMode (Legacy8259SetMode)
* +0x04: GetVector (Legacy8259GetVector)
* +0x05: EnableIrq (Legacy8259EnableIrq)
* +0x06: DisableIrq (Legacy8259DisableIrq)
* +0x07: EndOfInterrupt (Legacy8259EndOfInterrupt)
* +0x08: GetPcatFlag (Legacy8259GetPcatCompatibilityFlag)
*/
struct _EFI_LEGACY_8259_PROTOCOL {
LEGACY_8259_INITIALIZE InitPic;
LEGACY_8259_GET_STATE GetState;
LEGACY_8259_SET_STATE SetState;
LEGACY_8259_SET_MODE SetMode;
LEGACY_8259_GET_VECTOR GetVector;
LEGACY_8259_ENABLE_IRQ EnableIrq;
LEGACY_8259_DISABLE_IRQ DisableIrq;
LEGACY_8259_END_OF_INTERRUPT EndOfInterrupt;
LEGACY_8259_GET_PCAT_COMPATIBILITY_FLAG GetPcatCompatibilityFlag;
};
#endif /* __LEGACY8259_H__ */