Newer
Older
AMI-Aptio-BIOS-Reversed / MdeModulePkg / Universal / LockBox / SmmLockBox / Legacy8259 / Legacy8259.c
@Ajax Dong Ajax Dong 2 days ago 33 KB Restructure the repo
/**
 * @file Legacy8259.c
 * @brief Legacy 8259 Programmable Interrupt Controller (PIC) UEFI Driver
 *
 * UEFI DXE driver for the Intel 8259A Programmable Interrupt Controller.
 * Source: PcAtChipsetPkg/8259InterruptControllerDxe/8259/Legacy8259.c
 *
 * This driver manages the legacy 8259 PIC hardware by providing an
 * EFI_LEGACY_8259_PROTOCOL interface. It handles PIC initialization
 * (ICW1-ICW4), interrupt masking via IMR, mode switching (legacy vs.
 * virtual wire), IRQ-to-vector translation, and EOI signaling.
 *
 * Hardware Layout:
 *   Master PIC (IRQs 0-7):   Cmd=0x20, Data=0x21
 *   Slave PIC  (IRQs 8-15):  Cmd=0xA0, Data=0xA1
 *   ELCR1 (Master):          0x4D0
 *   ELCR2 (Slave):           0x4D1
 *   CMOS/RTC:                Addr=0x70, Data=0x71
 *
 * Entry point flow:
 *   1. Initialize UEFI globals (ImageHandle, SystemTable, BootServices, RuntimeServices)
 *   2. Locate HOB list from system configuration table
 *   3. Send EOI to both PICs for all IRQs (clear stale ISR bits)
 *   4. Program ICW1-ICW4 for both PICs (master=0x58, slave=0x70)
 *   5. Write initial IMR and ELCR to hardware
 *   6. Install EFI_LEGACY_8259_PROTOCOL via gBS->InstallProtocolInterface()
 */

#include "../uefi_headers/Uefi.h"
#include "Legacy8259.h"

/*=============================================================================
 * GUID Definitions
 *============================================================================*/

/**
 * EFI_LEGACY_8259_PROTOCOL_GUID -- Published protocol GUID.
 * Stored at 0xFF0 in the binary (used by InstallProtocolInterface).
 */
EFI_GUID gEfiLegacy8259ProtocolGuid = EFI_LEGACY_8259_PROTOCOL_GUID;

/**
 * Debug output protocol GUID (platform-specific).
 * Stored at 0xFE0 in the binary (used by LocateProtocol in GetDebugInterface).
 */
EFI_GUID gEfiDebugOutputProtocolGuid = EFI_DEBUG_OUTPUT_PROTOCOL_GUID;

/**
 * PCAT compatibility protocol GUID (platform-specific).
 * Stored at 0x1000 in the binary (used by HandleProtocol in GetPcatCompatibilityFlag).
 */
EFI_GUID gEfiPcatCompatibilityProtocolGuid = EFI_PCAT_COMPAT_PROTOCOL_GUID;

/**
 * HOB List GUID -- Standard UEFI PI specification GUID.
 * Stored at 0x1010 in the binary.
 */
EFI_GUID gEfiHobListGuid = EFI_HOB_LIST_GUID;

/*=============================================================================
 * Global State Variables
 *============================================================================*/

//
// -- UEFI service pointer caches (initialized by ModuleEntryPoint) --
//

/** Cached pointer to EFI_BOOT_SERVICES (qword at 0x1098) */
STATIC EFI_BOOT_SERVICES  *gBS = NULL;

/** Cached pointer to EFI_SYSTEM_TABLE (qword at 0x1090) */
STATIC EFI_SYSTEM_TABLE   *gST = NULL;

/** Cached ImageHandle (qword at 0x10A0) */
STATIC EFI_HANDLE          gImageHandle = NULL;

/** Cached pointer to EFI_RUNTIME_SERVICES (qword at 0x10A8) */
STATIC EFI_RUNTIME_SERVICES *gRT = NULL;

//
// -- PIC register shadow and state --
//

/** Combined master+slave IMR shadow (word at 0x1020: mMasterImr).
 *  Low byte = master IMR (port 0x21), High byte = slave IMR (port 0xA1).
 *  Initialized to 0xFFFF (all IRQs masked). */
STATIC UINT16  mMasterImr = 0xFFFF;

/** Combined master+slave ELCR shadow (word at 0x1088: mElcrCombined).
 *  Low byte = master ELCR (port 0x4D0), High byte = slave ELCR (port 0x4D1). */
STATIC UINT16  mElcrCombined = 0;

/** Master PIC vector base (byte at 0x1022).
 *  Written to master ICW2 during initialization. */
STATIC UINT8   mMasterVectorBase = 0xFF;

/** Current PIC operating mode (dword at 0x1078).
 *  0 = LEGACY_8259_MODE_LEGACY, 1 = LEGACY_8259_MODE_VIRTUAL_WIRE.
 *  Initialized to 1 (virtual wire). */
STATIC UINT32  mMode = 1;

/** Slave PIC vector base (byte at 0x107C).
 *  Written to slave ICW2 during initialization. */
STATIC UINT8   mSlaveVectorBase = 0xFF;

/** Protocol handle (qword at 0x1080).
 *  Set by InstallProtocolInterface during driver initialization. */
STATIC VOID   *mHandle = NULL;

/** Slave ELCR shadow (word at 0x10C2: mElcr2).
 *  Slave PIC ELCR value (port 0x4D1). */
STATIC UINT16  mElcr2 = 0;

/** Cached master IMR for init (word at 0x10C4: mCachedMasterImr).
 *  Set to 0x0EB8 during initialization.
 *  0x0EB8 bit pattern enables timer(0), keyboard(1), cascade(2), IRQ5;
 *  masks COM1, COM2, floppy, LPT1, RTC. */
STATIC UINT16  mCachedMasterImr = 0x0EB8;

//
// -- Debug and HOB caches --
//

/** Cached debug protocol interface (qword at 0x10B0).
 *  Located once via LocateProtocol during first assert call. */
STATIC VOID   *mDebugInterface = NULL;

/** Cached HOB list pointer (qword at 0x10B8).
 *  Located once from the system configuration table. */
STATIC VOID   *mHobList = NULL;

/*=============================================================================
 * Protocol Dispatch Table
 *============================================================================*/

/**
 * The EFI_LEGACY_8259_PROTOCOL instance published to the system.
 * Located at offset 0x1030 in the binary.
 */
STATIC EFI_LEGACY_8259_PROTOCOL m8259Interface;

/*=============================================================================
 * I/O Port Access Wrappers
 *============================================================================*/

/**
 * @brief Read a byte from an I/O port.
 *
 * @param[in] Port  I/O port address.
 *
 * @return Byte read from the port.
 */
STATIC
UINT8
IoRead8 (
    IN UINT16  Port
    )
{
    UINT8  Value;
    __asm {
        mov dx, Port
        in  al, dx
        mov Value, al
    }
    return Value;
}

/**
 * @brief Write a byte to an I/O port.
 *
 * @param[in] Port   I/O port address.
 * @param[in] Value  Byte to write.
 */
STATIC
VOID
IoWrite8 (
    IN UINT16  Port,
    IN UINT8   Value
    )
{
    __asm {
        mov dx, Port
        mov al, Value
        out dx, al
    }
}

/*=============================================================================
 * Forward Declarations
 *============================================================================*/

STATIC
VOID
PicReadImr (
    OUT UINT16 *MasterPmr OPTIONAL,
    OUT UINT16 *ElcrValue OPTIONAL
    );

STATIC
VOID *
GetDebugInterface (
    VOID
    );

/*=============================================================================
 * Protocol Function Implementations
 *============================================================================*/

/**
 * @brief Initialize the 8259 PIC with ICW1-ICW4 programming -- Protocol fn [0].
 *
 * Programs both master and slave PICs with the initialization command word
 * sequence. If the vector base for a PIC has changed since the last
 * initialization, that PIC is fully re-initialized. Raises TPL to
 * TPL_HIGH_LEVEL during programming to prevent interrupt delivery while
 * the PIC is in an inconsistent state.
 *
 * ICW sequence:
 *   1. ICW1 (0x11) to command port: edge-triggered, cascade mode, ICW4 needed
 *   2. ICW2 (VectorBase) to data port: interrupt vector base address
 *   3. ICW3 to data port: cascade connection map
 *   4. ICW4 (0x01) to data port: 8086 mode, normal EOI, non-buffered
 *   5. Restore saved IMR
 *
 * After programming both PICs, sends EOI to both to clear ISR bits.
 *
 * @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).
 *
 * @return EFI_SUCCESS always.
 */
EFI_STATUS
EFIAPI
PicInitialize (
    IN EFI_LEGACY_8259_PROTOCOL  *This,
    IN UINT8                     MasterBase,
    IN UINT8                     SlaveBase
    )
{
    EFI_TPL  OldTpl;
    UINT8    SavedImr;

    //
    // Raise TPL to prevent interrupts during PIC programming.
    //
    OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);

    //
    // If slave vector base changed, re-initialize slave PIC.
    //
    if (SlaveBase != mSlaveVectorBase) {
        mSlaveVectorBase = SlaveBase;

        //
        // Save current slave IMR for restoration after ICW sequence.
        //
        SavedImr = IoRead8 (LEGACY_8259_SLAVE_PIC_DATA);

        //
        // ICW1: Write initialization command (0x11 = init + ICW4)
        //
        IoWrite8 (LEGACY_8259_SLAVE_PIC_CMD, LEGACY_8259_ICW1_INIT_SEQ);
        //
        // ICW2: Write vector base address
        //
        IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA, mSlaveVectorBase);
        //
        // ICW3: Slave ID (0x02 = slave on master IRQ2)
        //
        IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA, LEGACY_8259_ICW3_SLAVE_CASCADE);
        //
        // ICW4: 8086 mode, non-buffered, normal EOI
        //
        IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA, LEGACY_8259_ICW4_8086);
        //
        // Restore saved slave IMR
        //
        IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA, SavedImr);
    }

    //
    // If master vector base changed, re-initialize master PIC.
    //
    if (MasterBase != mMasterVectorBase) {
        mMasterVectorBase = MasterBase;

        //
        // Save current master IMR for restoration after ICW sequence.
        //
        SavedImr = IoRead8 (LEGACY_8259_MASTER_PIC_DATA);

        //
        // ICW1: Write initialization command (0x11 = init + ICW4)
        //
        IoWrite8 (LEGACY_8259_MASTER_PIC_CMD, LEGACY_8259_ICW1_INIT_SEQ);
        //
        // ICW2: Write vector base address
        //
        IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, mMasterVectorBase);
        //
        // ICW3: Cascade map (0x04 = slave on IRQ2)
        //
        IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, LEGACY_8259_ICW3_MASTER_CASCADE);
        //
        // ICW4: 8086 mode, non-buffered, normal EOI
        //
        IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, LEGACY_8259_ICW4_8086);
        //
        // Restore saved master IMR
        //
        IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, SavedImr);
    }

    //
    // Send non-specific EOI to both PICs to clear any pending ISR bits.
    //
    IoWrite8 (LEGACY_8259_SLAVE_PIC_CMD, LEGACY_8259_OCW2_NON_SPECIFIC_EOI);
    IoWrite8 (LEGACY_8259_MASTER_PIC_CMD, LEGACY_8259_OCW2_NON_SPECIFIC_EOI);

    //
    // Restore TPL.
    //
    gBS->RestoreTPL (OldTpl);

    return EFI_SUCCESS;
}

/**
 * @brief Read the current PIC state (cached values) -- Protocol fn [1].
 *
 * Returns the software-cached values of the PIC registers without
 * touching hardware.
 *
 * @param[in]  This   Protocol instance pointer.
 * @param[out] State  Structure to receive:
 *                    MasterImr = combined master+slave IMR shadow
 *                    SlaveImr  = combined master+slave ELCR shadow
 *                    Elcr1     = master ELCR portion of shadow
 *                    Elcr2     = slave ELCR portion of shadow
 *
 * @return EFI_SUCCESS on success.
 * @return EFI_INVALID_PARAMETER if State is NULL.
 */
EFI_STATUS
EFIAPI
PicGetState (
    IN  EFI_LEGACY_8259_PROTOCOL  *This,
    OUT LEGACY_8259_STATE         *State
    )
{
    if (State == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    //
    // Return cached register values from shadow variables.
    //
    State->MasterImr = mMasterImr;
    State->SlaveImr  = mElcrCombined;
    State->Elcr1     = (UINT16)(mElcrCombined & 0xFF);
    State->Elcr2     = mElcr2;

    return EFI_SUCCESS;
}

/**
 * @brief Write new state to the 8259 PIC -- Protocol fn [2].
 *
 * Programs the PIC hardware IMR and ELCR registers with the provided
 * values. Behavior depends on the current operating mode:
 *
 * If mMode == LEGACY_8259_MODE_VIRTUAL_WIRE (1):
 *   Writes the provided MasterImr as master IMR (low byte to 0x21)
 *   and its high byte as slave IMR (to 0xA1).
 *   Uses SlaveImr for ELCR values.
 *
 * Otherwise (mode 0, legacy):
 *   Uses the shadow mMasterImr for IMR values.
 *   Uses SlaveImr for ELCR values.
 *
 * @param[in] This   Protocol instance pointer.
 * @param[in] State  Structure with new IMR and ELCR values.
 *
 * @return EFI_SUCCESS on success.
 * @return EFI_INVALID_PARAMETER if State is NULL.
 */
EFI_STATUS
EFIAPI
PicSetState (
    IN EFI_LEGACY_8259_PROTOCOL  *This,
    IN LEGACY_8259_STATE         *State
    )
{
    UINT16  ImrToWrite;
    UINT8   SlaveImrByte;

    if (State == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    if (mMode == LEGACY_8259_MODE_VIRTUAL_WIRE) {
        //
        // Virtual wire mode: write the provided IMR values directly.
        //
        ImrToWrite  = State->MasterImr;
        SlaveImrByte = (UINT8)((State->MasterImr >> 8) & 0xFF);
    } else {
        //
        // Legacy mode: write the shadow IMR and caller's ELCR.
        //
        ImrToWrite  = mMasterImr;
        SlaveImrByte = (UINT8)((mMasterImr >> 8) & 0xFF);
    }

    //
    // Write IMR to hardware ports.
    //
    IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, (UINT8)(ImrToWrite & 0xFF));
    IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA,  SlaveImrByte);

    //
    // Write ELCR values from the state SlaveImr field.
    //
    IoWrite8 (LEGACY_8259_ELCR1, (UINT8)(State->SlaveImr & 0xFF));
    IoWrite8 (LEGACY_8259_ELCR2, (UINT8)((State->SlaveImr >> 8) & 0xFF));

    //
    // Update ELCR shadows.
    //
    mElcrCombined = (UINT16)(State->SlaveImr & 0xFFFF);
    mElcr2        = (UINT16)((State->SlaveImr >> 8) & 0xFF);

    return EFI_SUCCESS;
}

/**
 * @brief Set the PIC operating mode -- Protocol fn [3].
 *
 * Switches between legacy PIC mode and virtual wire mode.
 *
 * LEGACY_8259_MODE_LEGACY (0):
 *   - Saves current IMR and ELCR from hardware
 *   - Configures for full legacy PIC operation
 *   - All IRQs routed through the 8259
 *
 * LEGACY_8259_MODE_VIRTUAL_WIRE (1):
 *   - Saves current IMR and ELCR from hardware
 *   - Clears IRQ0 (timer) mask bit in IMR
 *   - Only IRQ0 passes through PIC master; rest via I/O APIC
 *
 * @param[in] This  Protocol instance pointer.
 * @param[in] Mode  LEGACY_8259_MODE_LEGACY (0) or
 *                  LEGACY_8259_MODE_VIRTUAL_WIRE (1).
 *
 * @return EFI_SUCCESS on success.
 * @return EFI_ALREADY_STARTED if mode is already set.
 * @return EFI_INVALID_PARAMETER if Mode is not 0 or 1.
 */
EFI_STATUS
EFIAPI
PicSetMode (
    IN EFI_LEGACY_8259_PROTOCOL  *This,
    IN UINT8                     Mode
    )
{
    UINT16  SavedImr;
    UINT16  SavedElcr;

    if (Mode == mMode) {
        return EFI_ALREADY_STARTED;
    }

    //
    // Save current hardware state before switching.
    //
    SavedImr  = (UINT16)(IoRead8 (LEGACY_8259_MASTER_PIC_DATA) |
                         (IoRead8 (LEGACY_8259_SLAVE_PIC_DATA) << 8));
    SavedElcr = (UINT16)(IoRead8 (LEGACY_8259_ELCR1) |
                         (IoRead8 (LEGACY_8259_ELCR2) << 8));

    if (Mode == LEGACY_8259_MODE_LEGACY) {
        //
        // Legacy mode: route all IRQs through PIC.
        // Ensure timer (IRQ0) is unmasked.
        //
        mMasterImr = SavedImr & (UINT16)~(1U << 0);
        mMode      = LEGACY_8259_MODE_LEGACY;

        //
        // Write IMR to hardware.
        //
        IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, (UINT8)(mMasterImr & 0xFF));
        IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA,  (UINT8)((mMasterImr >> 8) & 0xFF));

        //
        // Write ELCR to hardware (preserving SavedElcr).
        //
        IoWrite8 (LEGACY_8259_ELCR1, (UINT8)(SavedElcr & 0xFF));
        IoWrite8 (LEGACY_8259_ELCR2, (UINT8)((SavedElcr >> 8) & 0xFF));

    } else if (Mode == LEGACY_8259_MODE_VIRTUAL_WIRE) {
        //
        // Virtual wire mode: only IRQ0 via PIC, rest via I/O APIC.
        // Preserve IRQ0 unmasked (clear bit 0).
        //
        mMasterImr = SavedImr & (UINT16)~(1U << 0);
        mMode      = LEGACY_8259_MODE_VIRTUAL_WIRE;

        //
        // Write IMR to hardware.
        //
        IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, (UINT8)(mMasterImr & 0xFF));
        IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA,  (UINT8)((mMasterImr >> 8) & 0xFF));

        //
        // Write ELCR to hardware.
        //
        IoWrite8 (LEGACY_8259_ELCR1, (UINT8)(SavedElcr & 0xFF));
        IoWrite8 (LEGACY_8259_ELCR2, (UINT8)((SavedElcr >> 8) & 0xFF));

        //
        // Update ELCR shadows.
        //
        mElcrCombined = SavedElcr;
        mElcr2        = (UINT16)((SavedElcr >> 8) & 0xFF);

    } else {
        return EFI_INVALID_PARAMETER;
    }

    return EFI_SUCCESS;
}

/**
 * @brief Get the interrupt vector for a given IRQ -- Protocol fn [4].
 *
 * Converts IRQ number (0-15) to the hardware interrupt vector by
 * adding the appropriate PIC vector base.
 *
 * For master IRQs (0-7): vector = IRQ + mMasterVectorBase.
 * For slave IRQs (8-15): vector = IRQ + (mSlaveVectorBase - 8).
 *
 * @param[in]  This    Protocol instance pointer.
 * @param[in]  Irq     IRQ number (0-15).
 * @param[out] Vector  Pointer to receive the vector number.
 *
 * @return EFI_SUCCESS on success.
 * @return EFI_INVALID_PARAMETER if Irq > 15 or Vector is NULL.
 */
EFI_STATUS
EFIAPI
PicGetVector (
    IN  EFI_LEGACY_8259_PROTOCOL  *This,
    IN  UINT8                     Irq,
    OUT UINT8                     *Vector
    )
{
    if (Irq > 15) {
        return EFI_INVALID_PARAMETER;
    }
    if (Vector == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    if (Irq >= 8) {
        //
        // Slave PIC IRQs: subtract cascade offset.
        // IRQ8 -> mSlaveVectorBase (0x70 = 112)
        //
        *Vector = (UINT8)(Irq + (mSlaveVectorBase - 8));
    } else {
        //
        // Master PIC IRQs: direct offset from master base.
        // IRQ0 -> mMasterVectorBase (0x58 = 88)
        //
        *Vector = (UINT8)(Irq + mMasterVectorBase);
    }

    return EFI_SUCCESS;
}

/**
 * @brief Enable or disable a specific IRQ -- Protocol fn [5].
 *
 * Updates the IMR bit for the specified IRQ and manages the ELCR:
 *   Enable = TRUE:   clears IMR bit (unmask), sets ELCR bit (level).
 *   Enable = FALSE:  sets IMR bit (mask), clears ELCR bit (edge).
 *
 * Writes updated values to PIC hardware immediately.
 *
 * @param[in] This    Protocol instance pointer.
 * @param[in] Irq     IRQ number (0-15).
 * @param[in] Enable  TRUE = unmask + level, FALSE = mask + edge.
 *
 * @return EFI_SUCCESS on success.
 * @return EFI_INVALID_PARAMETER if Irq > 15.
 */
EFI_STATUS
EFIAPI
PicEnableIrq (
    IN EFI_LEGACY_8259_PROTOCOL  *This,
    IN UINT8                     Irq,
    IN BOOLEAN                   Enable
    )
{
    UINT16  NewImr;
    UINT16  NewElcr;

    if (Irq > 15) {
        return EFI_INVALID_PARAMETER;
    }

    if (Enable) {
        //
        // Unmask: clear IMR bit, set ELCR bit (level-triggered).
        //
        mMasterImr &= (UINT16)~(1U << Irq);
        mElcrCombined |= (UINT16)(1U << Irq);
    } else {
        //
        // Mask: set IMR bit, clear ELCR bit (edge-triggered).
        //
        mMasterImr |= (UINT16)(1U << Irq);
        mElcrCombined &= (UINT16)~(1U << Irq);
    }

    NewImr  = mMasterImr;
    NewElcr = mElcrCombined;

    //
    // Write to hardware.
    //
    IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, (UINT8)(NewImr & 0xFF));
    IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA,  (UINT8)((NewImr >> 8) & 0xFF));
    IoWrite8 (LEGACY_8259_ELCR1,            (UINT8)(NewElcr & 0xFF));
    IoWrite8 (LEGACY_8259_ELCR2,            (UINT8)((NewElcr >> 8) & 0xFF));

    //
    // Update slave ELCR shadow.
    //
    mElcr2 = (UINT16)((NewElcr >> 8) & 0xFF);

    return EFI_SUCCESS;
}

/**
 * @brief Disable a specific IRQ in both IMR and ELCR -- Protocol fn [6].
 *
 * Stronger than masking: sets the IMR bit (masking) AND clears the
 * ELCR bit (forcing edge-triggered), providing maximum isolation.
 *
 * @param[in] This  Protocol instance pointer.
 * @param[in] Irq   IRQ number (0-15).
 *
 * @return EFI_SUCCESS on success.
 * @return EFI_INVALID_PARAMETER if Irq > 15.
 */
EFI_STATUS
EFIAPI
PicDisableIrq (
    IN EFI_LEGACY_8259_PROTOCOL  *This,
    IN UINT8                     Irq
    )
{
    if (Irq > 15) {
        return EFI_INVALID_PARAMETER;
    }

    //
    // Mask in IMR (set bit).
    //
    mMasterImr |= (UINT16)(1U << Irq);

    //
    // Clear ELCR bit (force edge-triggered).
    //
    mElcrCombined &= (UINT16)~(1U << Irq);

    //
    // Write to hardware.
    //
    IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, (UINT8)(mMasterImr & 0xFF));
    IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA,  (UINT8)((mMasterImr >> 8) & 0xFF));
    IoWrite8 (LEGACY_8259_ELCR1,            (UINT8)(mElcrCombined & 0xFF));
    IoWrite8 (LEGACY_8259_ELCR2,            (UINT8)((mElcrCombined >> 8) & 0xFF));

    //
    * Update slave ELCR shadow.
    //
    mElcr2 = (UINT16)((mElcrCombined >> 8) & 0xFF);

    return EFI_SUCCESS;
}

/**
 * @brief Issue End-Of-Interrupt (EOI) to the appropriate PIC(s).
 *
 * For slave IRQs (>= 8), EOI first goes to slave PIC (0xA0) then
 * master PIC (0x20) to deassert the cascade line.
 * For master IRQs (< 8), only master PIC receives EOI.
 *
 * @param[in] This  Protocol instance pointer.
 * @param[in] Irq   IRQ number (0-15) being completed.
 *
 * @return EFI_SUCCESS on success.
 * @return EFI_INVALID_PARAMETER if Irq > 15.
 */
EFI_STATUS
EFIAPI
PicEndOfInterrupt (
    IN EFI_LEGACY_8259_PROTOCOL  *This,
    IN UINT8                     Irq
    )
{
    if (Irq > 15) {
        return EFI_INVALID_PARAMETER;
    }

    //
    // Slave IRQ requires EOI to slave PIC first (cascade on IRQ2).
    //
    if (Irq >= 8) {
        IoWrite8 (LEGACY_8259_SLAVE_PIC_CMD, LEGACY_8259_OCW2_NON_SPECIFIC_EOI);
    }

    //
    // Always send EOI to master PIC.
    //
    IoWrite8 (LEGACY_8259_MASTER_PIC_CMD, LEGACY_8259_OCW2_NON_SPECIFIC_EOI);

    return EFI_SUCCESS;
}

/**
 * @brief Read the PCAT compatibility flag -- Protocol fn [7].
 *
 * Uses gBS->HandleProtocol() with the provided EFI handle to open
 * the PCAT compatibility protocol interface, then reads 1 byte at
 * offset 0x3C (60) of the protocol data, which is the PCAT_COMPAT
 * flag indicating whether dual 8259 PICs are present.
 *
 * Bit 0 (PCAT_COMPAT):
 *   1 = Dual 8259 PICs present (legacy PC/AT compatible).
 *   0 = APIC only; 8259 PICs may not exist.
 *
 * @param[in]  This          Protocol instance pointer.
 * @param[in]  Handle        Handle supporting the PCAT compatibility protocol.
 * @param[out] PcatFlags     Pointer to receive the PCAT_COMPAT flag byte.
 *
 * @return EFI_SUCCESS on success.
 * @return EFI_INVALID_PARAMETER if Handle or PcatFlags is NULL.
 * @return EFI_UNSUPPORTED if Handle does not support the protocol.
 */
EFI_STATUS
EFIAPI
PicGetPcatCompatibilityFlag (
    IN  EFI_LEGACY_8259_PROTOCOL  *This,
    IN  EFI_HANDLE                Handle,
    OUT UINT8                     *PcatFlags
    )
{
    EFI_STATUS  Status;
    VOID       *Interface;
    UINT8       Flags;

    if (Handle == NULL || PcatFlags == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    //
    // Open the PCAT compatibility protocol on the given handle.
    //
    Status = gBS->HandleProtocol (
                 Handle,
                 &gEfiPcatCompatibilityProtocolGuid,
                 &Interface
                 );
    if (EFI_ERROR (Status)) {
        return Status;
    }

    //
    // Read byte at offset 0x3C (60) of the protocol interface data.
    // This is the PCAT_COMPAT flag in the MADT (or equivalent table).
    //
    *PcatFlags = *(UINT8 *)((UINT8 *)Interface + 0x3C);

    return EFI_SUCCESS;
}

/*=============================================================================
 * Internal Helper Functions
 *============================================================================*/

/**
 * @brief Read current IMR and ELCR from PIC hardware.
 *
 * Reads the actual IMR and ELCR register values from hardware ports.
 * Used internally during mode transitions to capture hardware state.
 *
 * @param[out] MasterPmr  Optional: receives combined IMR = low(0x21) | high(0xA1<<8).
 * @param[out] ElcrValue  Optional: receives combined ELCR = low(0x4D0) | high(0x4D1<<8).
 */
STATIC
VOID
PicReadImr (
    OUT UINT16 *MasterPmr OPTIONAL,
    OUT UINT16 *ElcrValue OPTIONAL
    )
{
    UINT8  LowByte;
    UINT8  HighByte;

    if (MasterPmr != NULL) {
        LowByte    = IoRead8 (LEGACY_8259_MASTER_PIC_DATA);
        HighByte   = IoRead8 (LEGACY_8259_SLAVE_PIC_DATA);
        *MasterPmr = (UINT16)(LowByte | ((UINT16)HighByte << 8));
    }

    if (ElcrValue != NULL) {
        LowByte    = IoRead8 (LEGACY_8259_ELCR1);
        HighByte   = IoRead8 (LEGACY_8259_ELCR2);
        *ElcrValue = (UINT16)(LowByte | ((UINT16)HighByte << 8));
    }
}

/**
 * @brief Locate the debug ASSERT protocol interface.
 *
 * Locates a platform-specific debug protocol via gBS->LocateProtocol()
 * using gEfiDebugOutputProtocolGuid. Caches the interface in mDebugInterface.
 *
 * To prevent re-entrancy issues, raises TPL to TPL_HIGH_LEVEL to verify
 * we are not in interrupt context (TPL > TPL_NOTIFY) before calling
 * LocateProtocol.
 *
 * The returned interface provides assertion output at offset +8:
 *   Interface[1](FileName, LineNumber, ExpressionText).
 *
 * @return Pointer to debug protocol interface, or NULL if unavailable.
 */
STATIC
VOID *
GetDebugInterface (
    VOID
    )
{
    EFI_TPL  OldTpl;

    if (mDebugInterface != NULL) {
        return mDebugInterface;
    }

    //
    // Raise to TPL_HIGH_LEVEL, then restore to check current TPL.
    // If OldTpl > TPL_NOTIFY, we are in an interrupt context and
    // LocateProtocol cannot be safely called.
    //
    OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
    gBS->RestoreTPL (OldTpl);

    if (OldTpl <= TPL_NOTIFY) {
        //
        * Safe to locate the debug protocol.
        //
        gBS->LocateProtocol (
                 &gEfiDebugOutputProtocolGuid,
                 NULL,
                 &mDebugInterface
                 );
    }

    return mDebugInterface;
}

/**
 * @brief ASSERT handler -- reports assertion messages.
 *
 * Called by the ASSERT() macro. Uses the debug protocol interface
 * to report the assertion: Interface[1](FileName, Line, AssertText).
 *
 * If the debug interface is not available, the assertion is silently
 * dropped (as per UEFI convention).
 *
 * @param[in] FileName  Source file name string (ASCII).
 * @param[in] Line      Line number of the assertion.
 * @param[in] Text      Assertion expression text (ASCII).
 */
VOID
EFIAPI
DebugAssert (
    IN CHAR8  *FileName,
    IN UINTN   Line,
    IN CHAR8   *Text
    )
{
    VOID  *Interface;

    Interface = GetDebugInterface ();
    if (Interface != NULL) {
        //
        // Call the debug protocol's DebugAssert function at offset +8.
        //
        ((VOID (EFIAPI *)(CHAR8 *, UINTN, CHAR8 *))
         ((UINTN *)Interface)[1]) (FileName, Line, Text);
    }
}

/**
 * @brief Read an unaligned 64-bit value.
 *
 * Performs an unaligned memory read of a 64-bit value by dereferencing
 * the buffer as a 64-bit pointer. Used by the GUID comparison routine.
 *
 * @param[in] Buffer  Pointer to the potentially unaligned memory.
 *
 * @return The 64-bit value at Buffer.
 */
STATIC
UINT64
ReadUnaligned64 (
    IN VOID  *Buffer
    )
{
    if (Buffer == NULL) {
        DebugAssert (
            "e:\\hs\\MdePkg\\Library\\BaseLib\\Unaligned.c",
            192,
            "Buffer != ((void *) 0)"
            );
    }
    return *(UINT64 *)Buffer;
}

/**
 * @brief Compare two GUIDs for equality.
 *
 * Compares two EFI_GUID values using 64-bit unaligned reads for
 * efficiency. Splits each GUID into two 64-bit halves.
 *
 * @param[in] Guid1  First GUID to compare.
 * @param[in] Guid2  Second GUID to compare.
 *
 * @return TRUE if GUIDs are equal, FALSE otherwise.
 */
STATIC
BOOLEAN
CompareGuid (
    IN EFI_GUID  *Guid1,
    IN EFI_GUID  *Guid2
    )
{
    UINT64  Guid1First;
    UINT64  Guid2First;
    UINT64  Guid1Second;
    UINT64  Guid2Second;

    Guid1First  = ReadUnaligned64 (Guid1);
    Guid2First  = ReadUnaligned64 (Guid2);
    Guid1Second = ReadUnaligned64 ((EFI_GUID *)((UINT8 *)Guid1 + 8));
    Guid2Second = ReadUnaligned64 ((EFI_GUID *)((UINT8 *)Guid2 + 8));

    return (Guid1First == Guid2First) && (Guid1Second == Guid2Second);
}

/**
 * @brief Locate the HOB list from the system configuration table.
 *
 * Iterates through gST->ConfigurationTable entries to find the entry
 * whose VendorGuid matches gEfiHobListGuid. Caches the HOB list pointer
 * in mHobList on success.
 *
 * @return Pointer to the HOB list, or NULL if not found.
 */
STATIC
VOID *
GetHobList (
    VOID
    )
{
    UINTN  Index;

    if (mHobList != NULL) {
        return mHobList;
    }

    for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
        if (CompareGuid (
                &gEfiHobListGuid,
                (EFI_GUID *)&gST->ConfigurationTable[Index].VendorGuid
                )) {
            mHobList = gST->ConfigurationTable[Index].VendorTable;
            return mHobList;
        }
    }

    return mHobList;
}

/*=============================================================================
 * Driver Entry Point
 *============================================================================*/

/**
 * @brief Module entry point (_ModuleEntryPoint at 0x384).
 *
 * Called by the DXE Foundation when the driver is loaded. Validates and
 * caches UEFI service table pointers, then calls the main driver
 * initialization routine.
 *
 * @param[in] ImageHandle  Handle for the UEFI image.
 * @param[in] SystemTable  Pointer to the UEFI system table.
 *
 * @return EFI_STATUS from Legacy8259DriverEntry().
 */
EFI_STATUS
EFIAPI
ModuleEntryPoint (
    IN EFI_HANDLE        ImageHandle,
    IN EFI_SYSTEM_TABLE  *SystemTable
    )
{
    //
    // Validate and cache UEFI service table pointers.
    //
    if (ImageHandle == NULL) {
        DebugAssert (
            "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
            51,
            "gImageHandle != ((void *) 0)"
            );
    }
    if (SystemTable == NULL) {
        DebugAssert (
            "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
            57,
            "gST != ((void *) 0)"
            );
    }

    gImageHandle = ImageHandle;
    gST          = SystemTable;
    gBS          = SystemTable->BootServices;
    gRT          = SystemTable->RuntimeServices;

    if (gBS == NULL) {
        DebugAssert (
            "e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
            63,
            "gBS != ((void *) 0)"
            );
    }
    if (gRT == NULL) {
        DebugAssert (
            "e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c",
            47,
            "gRT != ((void *) 0)"
            );
    }

    //
    // Initialize HOB list for DXE library.
    //
    GetHobList ();

    //
    * Perform full driver initialization.
    //
    return Legacy8259DriverEntry ();
}

/**
 * @brief Main driver initialization (sub_430).
 *
 * Performs the full 8259 PIC initialization sequence:
 *
 * 1. Set initial IMR programming value (0x0EB8) enabling timer,
 *    keyboard, and cascade; masking COM, floppy, LPT, RTC.
 *
 * 2. Send EOI for all 16 IRQs to clear any stale In-Service bits.
 *
 * 3. Initialize protocol dispatch table function pointers.
 *
 * 4. Program both PICs with ICW1-ICW4 via PicInitialize:
 *    Master base 0x58, Slave base 0x70.
 *
 * 5. Write initial IMR and ELCR to hardware ports.
 *
 * 6. Install EFI_LEGACY_8259_PROTOCOL via gBS->InstallProtocolInterface().
 *
 * @return EFI_SUCCESS on success, or error from InstallProtocolInterface.
 */
EFI_STATUS
Legacy8259DriverEntry (
    VOID
    )
{
    UINTN  Index;

    //
    // Step 1: Set IMR shadow to default programming value (0x0EB8).
    //   0x0EB8 bit assignments:
    //     Bit 0 = 0  (IRQ0 - Timer: unmasked)
    //     Bit 1 = 0  (IRQ1 - Keyboard: unmasked)
    //     Bit 2 = 0  (IRQ2 - Slave cascade: unmasked)
    //     Bit 3 = 1  (IRQ3 - COM2: masked)
    //     Bit 4 = 1  (IRQ4 - COM1: masked)
    //     Bit 5 = 0  (IRQ5 - LPT2 or free: unmasked)
    //     Bit 6 = 1  (IRQ6 - Floppy: masked)
    //     Bit 7 = 1  (IRQ7 - LPT1: masked)
    //     Bit 8 = 1  (IRQ8 - RTC: masked on slave)
    //
    mCachedMasterImr = 0x0EB8;
    mElcrCombined    = 0;

    //
    // Step 2: Clear any stale ISR bits by sending EOI to both PICs
    // for all possible IRQs (0-15).
    //
    for (Index = 0; Index <= 15; Index++) {
        if (Index >= 8) {
            //
            // Slave IRQ: EOI to slave PIC first.
            //
            IoWrite8 (LEGACY_8259_SLAVE_PIC_CMD, LEGACY_8259_OCW2_NON_SPECIFIC_EOI);
        }
        //
        // Send EOI to master PIC.
        //
        IoWrite8 (LEGACY_8259_MASTER_PIC_CMD, LEGACY_8259_OCW2_NON_SPECIFIC_EOI);
    }

    //
    // Step 3: Initialize protocol dispatch table.
    //
    m8259Interface.InitPic                 = PicInitialize;
    m8259Interface.GetState                = PicGetState;
    m8259Interface.SetState                = PicSetState;
    m8259Interface.SetMode                 = PicSetMode;
    m8259Interface.GetVector               = PicGetVector;
    m8259Interface.EnableIrq               = PicEnableIrq;
    m8259Interface.DisableIrq              = PicDisableIrq;
    m8259Interface.EndOfInterrupt          = PicEndOfInterrupt;
    m8259Interface.GetPcatCompatibilityFlag = PicGetPcatCompatibilityFlag;

    //
    // Step 4: Program PICs with ICW1-ICW4.
    //   Master vector base: 0x58 (IRQ0 -> INT 88).
    //   Slave vector base:  0x70 (IRQ8 -> INT 112).
    //
    PicInitialize (
        &m8259Interface,
        LEGACY_8259_MASTER_VECTOR_BASE,
        LEGACY_8259_SLAVE_VECTOR_BASE
        );

    //
    // Step 5: Write initial IMR and ELCR values to hardware.
    //
    IoWrite8 (LEGACY_8259_MASTER_PIC_DATA, (UINT8)(mCachedMasterImr & 0xFF));
    IoWrite8 (LEGACY_8259_SLAVE_PIC_DATA,  (UINT8)((mCachedMasterImr >> 8) & 0xFF));
    IoWrite8 (LEGACY_8259_ELCR1,            (UINT8)(mElcrCombined & 0xFF));
    IoWrite8 (LEGACY_8259_ELCR2,            (UINT8)((mElcrCombined >> 8) & 0xFF));

    //
    // Step 6: Install the EFI_LEGACY_8259_PROTOCOL.
    //
    return gBS->InstallProtocolInterface (
                 &mHandle,
                 &gEfiLegacy8259ProtocolGuid,
                 EFI_NATIVE_INTERFACE,
                 &m8259Interface
                 );
}