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