Newer
Older
AMI-Aptio-BIOS-Reversed / MdeModulePkg / Universal / LockBox / SmmLockBox / Legacy8259 / Legacy8259.h
@Ajax Dong Ajax Dong 2 days ago 17 KB Restructure the repo
/**
 * @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__ */