Newer
Older
AMI-Aptio-BIOS-Reversed / CpuIo2Dxe / CpuIo2Dxe.h
@Ajax Dong Ajax Dong 2 days ago 15 KB Init
/**
 * CpuIo2Dxe.h -- EFI CPU I/O 2 Protocol DXE Driver Header
 *
 * This driver produces the EFI_CPU_IO2_PROTOCOL on a UEFI system. It provides
 * access to memory-mapped I/O (MMIO) and port I/O operations with width and
 * alignment validation.
 *
 * Source paths (from build-time debug strings):
 *   e:\hs\UefiCpuPkg\CpuIo2Dxe\CpuIo2Dxe.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_IO2_DXE_H
#define CPU_IO2_DXE_H

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

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

/**
 * 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 } }

/**
 * gEfiCpuIo2ProtocolGuid
 * {AD61F191-AE5F-4C0E-B9FA-E869D288C64F}
 *
 * The protocol this driver produces. Provides access to memory and I/O
 * spaces with width and alignment checking.
 */
#define EFI_CPU_IO2_PROTOCOL_GUID \
  { 0xAD61F191, 0xAE5F, 0x4C0E, \
    { 0xB9, 0xFA, 0xE8, 0x69, 0xD2, 0x88, 0xC6, 0x4F } }

/* =========================================================================
 * EFI_CPU_IO2_PROTOCOL definitions
 * ========================================================================= */

/**
 * Width of the access operation.
 *
 * Maps to byte_EF8[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_IO2_PROTOCOL exposes two of these: .Mem and .Io.
 */
typedef struct {
  EFI_STATUS (*Read)(EFI_CPU_IO2_PROTOCOL *This,
                     EFI_CPU_IO_PROTOCOL_WIDTH Width,
                     UINTN Address,
                     UINTN Count,
                     VOID *Buffer);

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

/**
 * EFI_CPU_IO2_PROTOCOL -- full protocol interface.
 *
 * Layout (each pointer is 8 bytes on x64):
 *   Offset  Size  Field
 *   ------  ----  -----
 *   0x00    8     Revision (UINT32 padded to UINT64)
 *   0x04    4     Revision (actual UINT32)
 *   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_IO2_PROTOCOL {
  UINT32                    Revision;
  EFI_CPU_IO_PROTOCOL_ACCESS Mem;
  EFI_CPU_IO_PROTOCOL_ACCESS Io;
} EFI_CPU_IO2_PROTOCOL;

/* =========================================================================
 * IO Access Width Table (byte_EF8)
 * ========================================================================= */

/**
 * Width mapping table at 0xEF8 (32 bytes 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 the HOB (Hand-Off Block) list.
 * Resolved lazily by GetHobList() by scanning the system configuration table.
 * Zero until first resolution attempt.
 */
extern VOID *gHobList;

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

/**
 * Driver entry point.
 *
 * Initializes global variables (ImageHandle, SystemTable, BootServices,
 * RuntimeServices), locates the HOB list, checks that
 * gEfiCpuIo2ProtocolGuid is not already installed, then installs the
 * EFI_CPU_IO2_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.
 * Delegates to IoReadFifo*() for Width>3 (FIFO/Fill) or to the
 * CpuMemoryServiceRead() for Width<=3.
 *
 * This is the .Mem.Read entry in the EFI_CPU_IO2_PROTOCOL.
 *
 * @param[in]      This     Pointer to the EFI_CPU_IO2_PROTOCOL instance.
 * @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_IO2_PROTOCOL       *This,
  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.
 * Delegates to IoWriteFifo*() for Width>3 or to
 * CpuMemoryServiceWrite() for Width<=3.
 *
 * This is the .Mem.Write entry in the EFI_CPU_IO2_PROTOCOL.
 *
 * @param[in]      This     Pointer to the EFI_CPU_IO2_PROTOCOL instance.
 * @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_IO2_PROTOCOL       *This,
  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. For Width=0 (byte), uses __inbytestring()
 * to call rep insb when Count>1.
 *
 * This is the .Io.Read entry in the EFI_CPU_IO2_PROTOCOL.
 *
 * @param[in]      This     Pointer to the EFI_CPU_IO2_PROTOCOL instance.
 * @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_IO2_PROTOCOL       *This,
  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_IO2_PROTOCOL.
 *
 * @param[in]      This     Pointer to the EFI_CPU_IO2_PROTOCOL instance.
 * @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_IO2_PROTOCOL       *This,
  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 gHobList. Asserts if not found.
 * Called once during ModuleEntryPoint.
 *
 * Uses ReadUnaligned64() 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 pool alloc/free pair to validate that UEFI boot services are
 * functional (canary check: if AllocatePool(31, 0, &Buf) returns a value
 * <= 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
  );

/**
 * Port I/O string read intrinsics (Width=0 i.e. byte).
 *
 * Reads Count bytes from Port into Buffer using x86 rep insb.
 */
VOID
__inbytestring(
  IN UINT16  Port,
  OUT VOID   *Buffer,
  IN UINTN   Count
  );

/**
 * Port I/O string read intrinsics (Width=1 i.e. word).
 *
 * Reads Count words from Port into Buffer using x86 rep insw.
 */
VOID
__inwordstring(
  IN UINT16  Port,
  OUT VOID   *Buffer,
  IN UINTN   Count
  );

/**
 * Port I/O string read intrinsics (Width=2 i.e. dword).
 *
 * Reads Count dwords from Port into Buffer using x86 rep insd.
 */
VOID
__indwordstring(
  IN UINT16  Port,
  OUT VOID   *Buffer,
  IN UINTN   Count
  );

/**
 * Port I/O string write intrinsics (Width=0 i.e. byte).
 *
 * Writes Count bytes from Buffer to Port using x86 rep outsb.
 */
VOID
__outbytestring(
  IN UINT16  Port,
  IN VOID    *Buffer,
  IN UINTN   Count
  );

/**
 * Port I/O string write intrinsics (Width=1 i.e. word).
 *
 * Writes Count words from Buffer to Port using x86 rep outsw.
 */
VOID
__outwordstring(
  IN UINT16  Port,
  IN VOID    *Buffer,
  IN UINTN   Count
  );

/**
 * Port I/O string write intrinsics (Width=2 i.e. dword).
 *
 * Writes Count dwords from Buffer to Port using x86 rep outsd.
 */
VOID
__outdwordstring(
  IN UINT16  Port,
  IN VOID    *Buffer,
  IN UINTN   Count
  );

#endif /* CPU_IO2_DXE_H */