Newer
Older
AMI-Aptio-BIOS-Reversed / CpuIoDxe / CpuIoDxe.h
@Ajax Dong Ajax Dong 2 days ago 14 KB Init
/**
 * CpuIoDxe.h -- EFI CPU I/O Protocol DXE Driver Header
 *
 * This driver produces the EFI_CPU_IO_PROTOCOL on a UEFI system. It provides
 * access to memory-mapped I/O (MMIO) and port I/O operations with width and
 * alignment validation.
 *
 * Based on IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.c (EDK2).
 *
 * Source paths (from build-time debug strings):
 *   e:\hs\IntelFrameworkModulePkg\Universal\CpuIoDxe\CpuIo.c
 *   e:\hs\MdePkg\Library\BaseIoLibIntrinsic\IoLibMsc.c
 *   e:\hs\MdePkg\Library\BaseIoLibIntrinsic\IoLib.c
 *   e:\hs\MdePkg\Library\BaseLib\LShiftU64.c
 *   e:\hs\MdePkg\Library\BaseLib\RShiftU64.c
 *   e:\hs\MdePkg\Library\DxeHobLib\HobLib.c
 *   e:\hs\MdePkg\Library\UefiBootServicesTableLib\UefiBootServicesTableLib.c
 *   e:\hs\MdePkg\Library\UefiRuntimeServicesTableLib\UefiRuntimeServicesTableLib.c
 */

#ifndef CPU_IO_DXE_H
#define CPU_IO_DXE_H

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

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

/**
 * gEfiCpuIoProtocolGuid
 * {6B33944A-A75D-41B4-91F1-9B977F6AB78D}
 *
 * The protocol this driver produces. Provides access to memory and I/O
 * spaces with width and alignment checking.
 *
 * This is the older EFI_CPU_IO_PROTOCOL (not CPU_IO2) from the
 * IntelFrameworkModulePkg.
 */
#define EFI_CPU_IO_PROTOCOL_GUID \
  { 0x6B33944A, 0xA75D, 0x41B4, \
    { 0x91, 0xF1, 0x9B, 0x97, 0x7F, 0x6A, 0xB7, 0x8D } }

/**
 * gEfiStatusCodeRuntimeProtocolGuid
 * {36232936-0E76-31C8-A13A-3AF2FC1C3932}
 *
 * Used by the DebugLib to report status codes at runtime. Resolved lazily
 * via gBS->LocateProtocol() in GetDebugProtocol().
 */
#define EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID \
  { 0x36232936, 0x0E76, 0x31C8, \
    { 0xA1, 0x3A, 0x3A, 0xF2, 0xFC, 0x1C, 0x39, 0x32 } }

/**
 * gEfiHobListGuid
 * {7739F24C-93D7-11D4-9A3A-0090273FC14D}
 *
 * Standard UEFI HOB list GUID. Used in GetHobList() to scan the system
 * configuration table for the HOB list pointer.
 */
#define EFI_HOB_LIST_GUID \
  { 0x7739F24C, 0x93D7, 0x11D4, \
    { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }

/* =========================================================================
 * EFI_CPU_IO_PROTOCOL definitions
 * ========================================================================= */

/**
 * Width of the access operation.
 *
 * Maps to mIoWidthTable[Width] for actual byte count:
 *   0 -> 1 byte (EfiCpuIoWidthUint8)
 *   1 -> 2 bytes (EfiCpuIoWidthUint16)
 *   2 -> 4 bytes (EfiCpuIoWidthUint32)
 *   3 -> 8 bytes (EfiCpuIoWidthUint64)
 *
 * Values 4-7 are reserved (FIFO variants in UEFI spec).
 * The module only handles indices 0-3 with a mask of (Width & 3).
 */
typedef enum {
  EfiCpuIoWidthUint8,    /* 0: 1 byte */
  EfiCpuIoWidthUint16,   /* 1: 2 bytes */
  EfiCpuIoWidthUint32,   /* 2: 4 bytes */
  EfiCpuIoWidthUint64,   /* 3: 8 bytes */
  EfiCpuIoWidthFifoUint8,
  EfiCpuIoWidthFifoUint16,
  EfiCpuIoWidthFifoUint32,
  EfiCpuIoWidthFifoUint64,
  EfiCpuIoWidthFillUint8,
  EfiCpuIoWidthFillUint16,
  EfiCpuIoWidthFillUint32,
  EfiCpuIoWidthFillUint64,
  EfiCpuIoWidthMaximum
} EFI_CPU_IO_PROTOCOL_WIDTH;

/**
 * IO access type (operation).
 */
#define EFI_CPU_IO_PROTOCOL_IO    0
#define EFI_CPU_IO_PROTOCOL_MEM   1

/**
 * EFI_CPU_IO_PROTOCOL_ACCESS -- access functions for one address space.
 *
 * Each EFI_CPU_IO_PROTOCOL exposes two of these: .Mem and .Io.
 */
typedef struct {
  EFI_STATUS (*Read)(EFI_CPU_IO_PROTOCOL_WIDTH Width,
                     UINTN Address,
                     UINTN Count,
                     VOID *Buffer);

  EFI_STATUS (*Write)(EFI_CPU_IO_PROTOCOL_WIDTH Width,
                      UINTN Address,
                      UINTN Count,
                      VOID *Buffer);
} EFI_CPU_IO_PROTOCOL_ACCESS;

/**
 * EFI_CPU_IO_PROTOCOL -- full protocol interface.
 *
 * This is the older (Framework) CPU I/O protocol. Unlike EFI_CPU_IO2_PROTOCOL,
 * the access functions do NOT take a 'This' pointer as the first parameter.
 *
 * Layout (each pointer is 8 bytes on x64):
 *   Offset  Size  Field
 *   ------  ----  -----
 *   0x00    8     Revision (UINT32 padded to UINT64)
 *   0x08    16    EFI_CPU_IO_PROTOCOL_ACCESS Mem
 *                     +0x00: Mem.Read  (function pointer)
 *                     +0x08: Mem.Write (function pointer)
 *   0x18    16    EFI_CPU_IO_PROTOCOL_ACCESS Io
 *                     +0x00: Io.Read  (function pointer)
 *                     +0x08: Io.Write (function pointer)
 *
 * Total size: 0x28 (40 bytes)
 */
typedef struct _EFI_CPU_IO_PROTOCOL {
  UINT32                    Revision;
  EFI_CPU_IO_PROTOCOL_ACCESS Mem;
  EFI_CPU_IO_PROTOCOL_ACCESS Io;
} EFI_CPU_IO_PROTOCOL;

/* =========================================================================
 * I/O Access Width Table (byte_20B8)
 * ========================================================================= */

/**
 * Width mapping table at 0x20B8 (in .rdata).
 *
 * Index range: 0-3 (masked with 3 from Width parameter for non-FIFO modes).
 *
 * Layout:
 *   [0..3]    Access width in bytes for each Width index (1, 2, 4, 8)
 *   [4..7]    Reserved (zero)
 *   [8..11]   Access width in bytes (duplicate of [0..3])
 *   [12..15]  Reserved (zero)
 *   [16..19]  Destination stride for Read operations (1, 2, 4, 8)
 *   [20..23]  Destination stride for Write operations (1, 2, 4, 8)
 *   [24..31]  Reserved (zero)
 */
extern const UINT8 mIoWidthTable[32];

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

/* Driver image handle -- set by ModuleEntryPoint() */
extern EFI_HANDLE          gImageHandle;

/* Pointer to UEFI system table -- set by ModuleEntryPoint() */
extern EFI_SYSTEM_TABLE    *gST;

/* Pointer to UEFI boot services -- resolved from gST */
extern EFI_BOOT_SERVICES   *gBS;

/* Pointer to UEFI runtime services -- resolved from gST */
extern EFI_RUNTIME_SERVICES *gRT;

/**
 * Cached pointer to the EFI_STATUS_CODE_RUNTIME_PROTOCOL.
 * Resolved lazily by GetDebugProtocol() via gBS->LocateProtocol().
 * Zero until first resolution attempt. Once set, never cleared.
 */
extern VOID *gDebugProtocol;

/**
 * Cached pointer to HOB list.
 * Resolved lazily by GetHobList() by scanning the system configuration table.
 * Zero until first resolution attempt.
 */
extern VOID *mHobList;

/* =========================================================================
 * Function Declarations
 * ========================================================================= */

/**
 * Driver entry point.
 *
 * Initializes global variables (ImageHandle, SystemTable, BootServices,
 * RuntimeServices), locates the HOB list, checks that
 * gEfiCpuIoProtocolGuid is not already installed, then installs the
 * EFI_CPU_IO_PROTOCOL on a new handle.
 *
 * @param[in] ImageHandle  Handle for this driver image.
 * @param[in] SystemTable  Pointer to the UEFI system table.
 *
 * @return EFI_SUCCESS           Protocol installed successfully.
 * @return EFI_ALREADY_STARTED   Protocol already installed (assert).
 * @return EFI_INVALID_PARAMETER ImageHandle or SystemTable was NULL.
 */
EFI_STATUS
EFIAPI
ModuleEntryPoint(
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  );

/**
 * Validates I/O access parameters.
 *
 * Checks Width<12, alignment, address range validity, and buffer alignment
 * for a given access type (IO=0 or MEM=1).
 *
 * @param[in]  AccessType  EFI_CPU_IO_PROTOCOL_IO (0) or _MEM (1).
 * @param[in]  Width       One of EFI_CPU_IO_PROTOCOL_WIDTH (0-11).
 * @param[in]  Address     Starting I/O or MMIO address.
 * @param[in]  Count       Number of elements to access.
 * @param[in]  Buffer      Pointer to the data buffer.
 *
 * @return EFI_SUCCESS             Parameters are valid.
 * @return EFI_INVALID_PARAMETER   Width >= 12, or invalid AccessType+Width combo.
 * @return EFI_UNSUPPORTED         Address alignment does not match Width.
 * @return EFI_BAD_BUFFER_SIZE     Address range exceeds architectural limit.
 */
EFI_STATUS
CpuIoCheckParameter(
  UINT8    AccessType,
  UINT32   Width,
  UINT64   Address,
  UINT64   Count,
  VOID     *Buffer
  );

/**
 * Memory-mapped I/O Read dispatcher.
 *
 * Reads Count elements of Width from Address into Buffer.
 *
 * This is the .Mem.Read entry in the EFI_CPU_IO_PROTOCOL.
 *
 * @param[in]      Width    Width of the access.
 * @param[in]      Address  Starting MMIO address.
 * @param[in]      Count    Number of elements.
 * @param[out]     Buffer   Destination buffer.
 *
 * @return EFI_SUCCESS or error from CpuIoCheckParameter.
 */
EFI_STATUS
EFIAPI
CpuMemoryServiceRead(
  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
  IN  UINTN                      Address,
  IN  UINTN                      Count,
  OUT VOID                       *Buffer
  );

/**
 * Memory-mapped I/O Write dispatcher.
 *
 * Writes Count elements of Width from Buffer to Address.
 *
 * This is the .Mem.Write entry in the EFI_CPU_IO_PROTOCOL.
 *
 * @param[in]      Width    Width of the access.
 * @param[in]      Address  Starting MMIO address.
 * @param[in]      Count    Number of elements.
 * @param[in]      Buffer   Source buffer.
 *
 * @return EFI_SUCCESS or error from CpuIoCheckParameter.
 */
EFI_STATUS
EFIAPI
CpuMemoryServiceWrite(
  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
  IN UINTN                      Address,
  IN UINTN                      Count,
  IN VOID                       *Buffer
  );

/**
 * Port I/O Read dispatcher.
 *
 * Reads Count elements of Width from Port into Buffer.
 * For Width<=3, uses direct I/O instructions (__inbyte, __inword, __indword)
 * with proper alignment checking.
 *
 * This is the .Io.Read entry in the EFI_CPU_IO_PROTOCOL.
 *
 * @param[in]      Width    Width of the access.
 * @param[in]      Port     Starting I/O port address.
 * @param[in]      Count    Number of elements.
 * @param[out]     Buffer   Destination buffer.
 *
 * @return EFI_SUCCESS or error from CpuIoCheckParameter.
 */
EFI_STATUS
EFIAPI
CpuIoServiceRead(
  IN  EFI_CPU_IO_PROTOCOL_WIDTH  Width,
  IN  UINTN                      Port,
  IN  UINTN                      Count,
  OUT VOID                       *Buffer
  );

/**
 * Port I/O Write dispatcher.
 *
 * Writes Count elements of Width from Buffer to Port.
 * For Width<=3, uses direct I/O instructions (__outbyte, __outword, __outdword)
 * with proper alignment checking.
 *
 * This is the .Io.Write entry in the EFI_CPU_IO_PROTOCOL.
 *
 * @param[in]      Width    Width of the access.
 * @param[in]      Port     Starting I/O port address.
 * @param[in]      Count    Number of elements.
 * @param[in]      Buffer   Source buffer.
 *
 * @return EFI_SUCCESS or error from CpuIoCheckParameter.
 */
EFI_STATUS
EFIAPI
CpuIoServiceWrite(
  IN EFI_CPU_IO_PROTOCOL_WIDTH  Width,
  IN UINTN                      Port,
  IN UINTN                      Count,
  IN VOID                       *Buffer
  );

/**
 * Reads from the HOB list pointer.
 *
 * Scans the system configuration table for gEfiHobListGuid.
 * Caches the result in mHobList. Asserts if not found.
 * Called once during ModuleEntryPoint.
 *
 * Uses CompareGuidByUnaligned64() to compare GUIDs in two 8-byte halves.
 */
VOID
GetHobList(
  VOID
  );

/**
 * Compares two GUID pointers by reading two 8-byte halves.
 *
 * @param[in]  Guid1  Pointer to reference GUID.
 * @param[in]  Guid2  Pointer to candidate GUID from config table.
 *
 * @return TRUE if both halves match, FALSE otherwise.
 */
BOOLEAN
CompareGuidByUnaligned64(
  IN EFI_GUID  *Guid1,
  IN EFI_GUID  *Guid2
  );

/**
 * Reads a UINT64 from a pointer with NULL assertion.
 *
 * @param[in]  Buffer  Pointer to read from (must not be NULL).
 *
 * @return The 64-bit value at Buffer.
 */
UINT64
EFIAPI
ReadUnaligned64(
  IN CONST VOID  *Buffer
  );

/**
 * Lazily resolves and caches the EFI_STATUS_CODE_RUNTIME_PROTOCOL.
 *
 * Uses a RaiseTPL/RestoreTPL canary to verify UEFI boot services are
 * functional. If OldTpl <= TPL_NOTIFY (0x10), boot services are not
 * available.
 *
 * On success, calls gBS->LocateProtocol() and caches the result.
 *
 * @return Pointer to the StatusCodeRuntimeProtocol, or NULL if unavailable.
 */
VOID *
GetDebugProtocol(
  VOID
  );

/**
 * Debug print through the StatusCodeRuntimeProtocol.
 *
 * Reads CMOS register 0x4B to get the current debug level mask.
 * Falls back to MMIO at 0xFDAF0490 if CMOS level is 0.
 * Calls the protocol's report function if the error level matches.
 *
 * @param[in]  ErrorLevel  Severity/class mask for this message.
 * @param[in]  Format      Format string.
 * @param[in]  ...         Variable arguments.
 */
VOID
EFIAPI
DebugPrint(
  IN UINTN       ErrorLevel,
  IN CONST CHAR8 *Format,
  ...
  );

/**
 * Debug assert handler.
 *
 * Resolves the debug protocol and calls the assertion handler
 * at protocol interface offset +0x08.
 *
 * @param[in]  FileName    Source file name.
 * @param[in]  LineNumber  Line number of the assertion.
 * @param[in]  Description  Assertion description string.
 */
VOID
EFIAPI
DebugAssert(
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  );

/**
 * 64-bit left shift with count validation.
 *
 * @param[in]  Value   Value to shift.
 * @param[in]  Count   Shift count (must be < 64).
 *
 * @return Value << Count.
 */
UINT64
EFIAPI
LShiftU64(
  IN UINT64  Value,
  IN UINTN   Count
  );

/**
 * 64-bit right shift with count validation.
 *
 * @param[in]  Value   Value to shift.
 * @param[in]  Count   Shift count (must be < 64).
 *
 * @return Value >> Count.
 */
UINT64
EFIAPI
RShiftU64(
  IN UINT64  Value,
  IN UINTN   Count
  );

/**
 * Notification callback for TPL end-of-boot-services event.
 *
 * Clears gBS to NULL when boot services are exiting.
 * Registered via gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_NOTIFY, sub_196C).
 * Prevents further gBS usage after ExitBootServices.
 */
VOID
EFIAPI
OnExitBootServices(
  VOID
  );

/**
 * Notification callback for runtime event.
 *
 * Cleans up debug protocol resources. Registered via
 * gBS->CreateEventEx(EVT_NOTIFY_SIGNAL, TPL_NOTIFY, sub_1978, &gEfiEventVirtualAddressChangeGuid).
 */
VOID
EFIAPI
OnVirtualAddressChange(
  VOID
  );

/**
 * Port I/O byte read intrinsic.
 */
UINT8
__inbyte(
  UINT16 Port
  );

/**
 * Port I/O word read intrinsic.
 */
UINT16
__inword(
  UINT16 Port
  );

/**
 * Port I/O dword read intrinsic.
 */
UINT32
__indword(
  UINT16 Port
  );

/**
 * Port I/O byte write intrinsic.
 */
VOID
__outbyte(
  UINT16 Port,
  UINT8  Value
  );

/**
 * Port I/O word write intrinsic.
 */
VOID
__outword(
  UINT16 Port,
  UINT16 Value
  );

/**
 * Port I/O dword write intrinsic.
 */
VOID
__outdword(
  UINT16 Port,
  UINT32 Value
  );

#endif /* CPU_IO_DXE_H */