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