Newer
Older
AMI-Aptio-BIOS-Reversed / CpuIo2Dxe / CpuIo2Dxe.c
@Ajax Dong Ajax Dong 2 days ago 31 KB Init
/**
 *CpuIo2Dxe.c -- EFI CPU I/O 2 Protocol DXE Driver
 *
 *This driver implements and produces the EFI_CPU_IO2_PROTOCOL for a UEFI
 *system. It provides validated access to:
 * - Memory-mapped I/O (MMIO) space
 * - Port I/O space
 *
 *Each access is parameter-validated for Width, alignment, address range,
 *and buffer alignment before dispatch.
 *
 *Source: e:\hs\UefiCpuPkg\CpuIo2Dxe\CpuIo2Dxe.c
 * (EDK2 / Intel UEFI CPU package)
 */

#include "CpuIo2Dxe.h"

/* =========================================================================
 *Local Data (.rdata section)
 * ========================================================================= */

/**
 *I/O access width and stride table at 0xEF8.
 *
 *Maps EFI_CPU_IO_PROTOCOL_WIDTH index values to byte widths and strides.
 *Only indices 0-3 (masked by Width & 3) are used for non-FIFO access.
 *
 *When Width > 3 (FIFO/Fill modes), byte_EF8[Width] = 0 and the module
 *accesses the FIFO variants directly (Width & 3 determines the element
 *size, and the access width is hardcoded as 1 via the a4 = 1 in
 *CpuIoCheckParameter).
 *
 *Offsets:
 * [0..3] Access width in bytes (1, 2, 4, 8)
 * [4..7] Reserved (zero)
 * [8..11] Access width in bytes (duplicate for alternate stride calc)
 * [16..19] Destination stride in bytes for Read operations
 * [20..23] Destination stride in bytes for Write operations
 * [24..31] Reserved (zero)
 */
const UINT8 mIoWidthTable[32] = {
 1, 2, 4, 8, /* [0..3] Access width per Width index */
 0, 0, 0, 0, /* [4..7] Reserved */
 1, 2, 4, 8, /* [8..11] Access width (duplicate) */
 0, 0, 0, 0, /* [12..15] Reserved */
 1, 2, 4, 8, /* [16..19] Read buffer stride */
 1, 2, 4, 8, /* [20..23] Write buffer stride */
 0, 0, 0, 0, /* [24..27] Reserved */
 0, 0, 0, 0 /* [28..31] Reserved */
};

/* =========================================================================
 *Global Variables (.data section)
 * ========================================================================= */

/*0x13B8 */ EFI_SYSTEM_TABLE *gST = NULL;
/*0x13C0 */ EFI_BOOT_SERVICES *gBS = NULL;
/*0x13C8 */ EFI_HANDLE gImageHandle = NULL;
/*0x13D0 */ EFI_RUNTIME_SERVICES *gRT = NULL;
/*0x13D8 */ VOID *gDebugProtocol = NULL;
/*0x13E0 */ VOID *gHobList = NULL;

/*0x13E8 -- stack-local temporary for ASSERT processing (not a global) */

/* =========================================================================
 *GUID instances (.rdata section)
 * ========================================================================= */

static const EFI_GUID mStatusCodeRuntimeProtocolGuid =
 EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID; /*0x1360 */

static const EFI_GUID mEfiHobListGuid =
 EFI_HOB_LIST_GUID; /*0x1370 */

static const EFI_GUID mEfiCpuIo2ProtocolGuid =
 EFI_CPU_IO2_PROTOCOL_GUID; /*0x1380 */

/**
 *Function pointer table for the EFI_CPU_IO2_PROTOCOL interface.
 *
 *At 0x1390, 48 bytes (room for 6 function pointers, only 4 used):
 * [0] 0x061C = CpuMemoryServiceRead
 * [1] 0x0714 = CpuMemoryServiceWrite
 * [2] 0x0818 = CpuIoServiceRead
 * [3] 0x0970 = CpuIoServiceWrite
 * [4] zero (reserved)
 * [5] zero (reserved)
 *
 *These are installed as the .Mem.Read, .Mem.Write, .Io.Read, .Io.Write
 *entries of the EFI_CPU_IO2_PROTOCOL.
 */
static const VOID *mCpuIo2FunctionTable[6] = {
 CpuMemoryServiceRead, /*0x61C */
 CpuMemoryServiceWrite, /*0x714 */
 CpuIoServiceRead, /*0x818 */
 CpuIoServiceWrite, /*0x970 */
 NULL,
 NULL
};

/* =========================================================================
 *Intrinsic Port I/O String Functions (.text section)
 *
 *These are compiler intrinsics / library routines that provide string
 * (repetitive) I/O access. Each uses the x86 REP-prefixed I/O instruction.
 *
 *Addresses 0x2C0-0x30F
 * ========================================================================= */

/**
 *Read Count bytes from Port into Buffer using rep insb.
 *Address: 0x2C0
 *
 *Implementation:
 *push rdi
 *mov rax, r8 ; Count
 *mov rdi, rcx ; Buffer (destination)
 *xchg rcx, rdx ; rcx = Count, rdx = Port
 *rep stosb ; No, this is NOT rep insb -- this is rep stosb?
 * ... This function is actually a rep insb wrapper.
 *mov rax, rdx
 *pop rdi
 *ret
 *
 *NOTE: The decompiler shows __inbytestring() -- the disassembly shows
 *this is generated inline by the compiler using rep insb/stosb patterns.
 *The exact instruction sequence:
 *rep insb BYTE PTR [rdi], dx ; Read from port DX into [rdi]
 */
#pragma intrinsic(__inbytestring)
void __inbytestring(UINT16 Port, OUT VOID *Buffer, IN UINTN Count)
{
 __inbytestring_w(Port, Buffer, Count);
}

/**
 *Read Count words from Port into Buffer using rep insw.
 *Address: 0x2CD
 */
#pragma intrinsic(__inwordstring)
void __inwordstring(UINT16 Port, OUT VOID *Buffer, IN UINTN Count)
{
 __inwordstring_w(Port, Buffer, Count);
}

/**
 *Read Count dwords from Port into Buffer using rep insd.
 *Address: 0x2DB
 */
#pragma intrinsic(__indwordstring)
void __indwordstring(UINT16 Port, OUT VOID *Buffer, IN UINTN Count)
{
 __indwordstring_w(Port, Buffer, Count);
}

/**
 *Write Count bytes from Buffer to Port using rep outsb.
 *Address: 0x2E8
 */
#pragma intrinsic(__outbytestring)
void __outbytestring(UINT16 Port, IN VOID *Buffer, IN UINTN Count)
{
 __outbytestring_w(Port, Buffer, Count);
}

/**
 *Write Count words from Buffer to Port using rep outsw.
 *Address: 0x2F5
 */
#pragma intrinsic(__outwordstring)
void __outwordstring(UINT16 Port, IN VOID *Buffer, IN UINTN Count)
{
 __outwordstring_w(Port, Buffer, Count);
}

/**
 *Write Count dwords from Buffer to Port using rep outsd.
 *Address: 0x303
 */
#pragma intrinsic(__outdwordstring)
void __outdwordstring(UINT16 Port, IN VOID *Buffer, IN UINTN Count)
{
 __outdwordstring_w(Port, Buffer, Count);
}

/* =========================================================================
 *64-bit Shift Operations
 * ========================================================================= */

/**
 *64-bit left shift with count validation.
 *Address: 0xC24
 *
 *Asserts if Count >= 64 (from BaseLib\LShiftU64.c line 39).
 *
 * @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)
{
 ASSERT(Count < 64);
 return Value << Count;
}

/**
 *64-bit right shift with count validation.
 *Address: 0xC68
 *
 *Asserts if Count >= 64 (from BaseLib\RShiftU64.c line 39).
 *
 * @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)
{
 ASSERT(Count < 64);
 return Value >> Count;
}

/* =========================================================================
 *Unaligned Memory Access
 * ========================================================================= */

/**
 *Reads a UINT64 from a pointer with NULL assertion.
 *Address: 0xDF4
 *
 *Assertion from MdePkg\Library\BaseLib\Unaligned.c line 192:
 * "Buffer != ((void *) 0)"
 *
 * @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)
{
 ASSERT(Buffer != NULL);
 return *(const UINT64 *)Buffer;
}

/* =========================================================================
 *Protocol Helper: GetDebugProtocol
 * ========================================================================= */

/**
 *Lazily resolves the EFI_STATUS_CODE_RUNTIME_PROTOCOL.
 *Address: 0xADC
 *
 *Uses a pool alloc/free canary to verify UEFI boot services are functional:
 *1. AllocatePool(EfiBootServicesData, 0, &TempBuffer) -- [gBS+0x18]
 *2. FreePool(TempBuffer) -- [gBS+0x20]
 *3. If (UINTN)TempBuffer <= 0x10 -> boot services unavailable, return NULL
 *4. gBS->LocateProtocol(&gEfiStatusCodeRuntimeProtocolGuid, NULL, &gDebugProtocol)
 *
 *The canary at step 3 detects whether AllocatePool returned a real pointer.
 *On a functioning UEFI, a 0-byte AllocatePool returns a valid non-NULL
 *pointer with an address > 0x10. On broken/missing boot services, it
 *returns NULL or a very low value.
 *
 *The function calls:
 * [gBS + 0x18] -- AllocatePool? No, actually this is RaiseTPL with (31).
 * [gBS + 0x20] -- RestoreTPL to restore original TPL.
 *
 *Wait -- the disassembly shows:
 *lea ecx, [rax+1Fh] ; ecx = 0 + 31 = 31 (TPL_HIGH_LEVEL)
 *call [BootServices + 18h] ; gBS->RaiseTPL(TPL_HIGH_LEVEL)
 *call [BootServices + 20h] ; gBS->RestoreTPL(result)
 *
 *This is actually a TPL manipulation check that verifies
 *RaiseTPL/RestoreTPL are functional (the return value of RaiseTPL is the
 *previous TPL, which is then checked: if previous TPL <= TPL_NOTIFY (0x10),
 *boot services are active).
 *
 *Then: call [BootServices + 140h] -- gBS->LocateProtocol()
 *
 * @return Cached pointer to the StatusCodeRuntimeProtocol, or NULL.
 */
VOID *GetDebugProtocol(VOID)
{
 EFI_STATUS Status;
 UINTN OldTpl;
 VOID *TempBuffer;
 VOID *Protocol;

 /*Check cache first */
 if (gDebugProtocol != NULL) {
 return gDebugProtocol;
 }

 /*
 *Validate boot services via RaiseTPL/RestoreTPL.
 *If boot services are functional, RaiseTPL returns the previous TPL,
 *which should be a value > TPL_NOTIFY (0x10) on a properly initialized
 *system. If the return is <= 0x10, something is wrong.
 */
 OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL); /*TPL_HIGH_LEVEL = 31 */
 gBS->RestoreTPL(OldTpl);

 if (OldTpl <= TPL_NOTIFY) { /*TPL_NOTIFY = 16 = 0x10 */
 /*
 *Boot services appear unavailable -- this can happen in runtime phase.
 *Do not attempt protocol resolution.
 */
 return NULL;
 }

 /*
 *Resolve the StatusCodeRuntimeProtocol.
 *gBS->LocateProtocol(&gEfiStatusCodeRuntimeProtocolGuid, NULL, &Protocol)
 */
 Status = gBS->LocateProtocol(
 (EFI_GUID *)&mStatusCodeRuntimeProtocolGuid,
 NULL,
 &Protocol
 );

 if (!EFI_ERROR(Status)) {
 gDebugProtocol = Protocol;
 } else {
 gDebugProtocol = NULL;
 }

 return gDebugProtocol;
}

/* =========================================================================
 *Debug Output Support
 * ========================================================================= */

/**
 *Debug assert handler.
 *Address: 0xBE4
 *
 *Resolves the StatusCodeRuntimeProtocol (if not already cached) and
 *calls the assertion handler at protocol interface offset +0x08.
 *
 *This corresponds to:
 *Protocol->ReportStatusCode(EFI_ERROR_CODE | EFI_ERROR_MAJOR, ...)
 *followed by a CpuDeadLoop() in the full EDK2 implementation (not
 *included in this binary -- the caller loops or halts).
 *
 * @param[in] FileName Source file name string.
 * @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
 )
{
 VOID *Protocol;

 Protocol = GetDebugProtocol();
 if (Protocol != NULL) {
 /*
 *Call the assertion handler at interface offset +0x08.
 *The StatusCodeRuntimeProtocol interface has:
 * +0x00: ReportStatusCode (print/format)
 * +0x08: ReportStatusCode (assert handler variant, or
 *ReportStatusCodeEx)
 */
 ((EFI_STATUS (EFIAPI *)(CONST CHAR8 *, UINTN, CONST CHAR8 *))
 ((UINT8 *)Protocol + 8))(FileName, LineNumber, Description);
 }
}

/**
 *Debug print through StatusCodeRuntimeProtocol.
 *Address: 0xB5C
 *
 *Before calling the protocol, reads the CMOS debug level register to
 *determine the current verbosity mask. Falls back to MMIO 0xFDAF0490
 *if CMOS level is 0.
 *
 *CMOS RTC register 0x4B:
 *out 0x70, 0x4B -- select register 0x4B
 *in 0x71 -- read debug level
 *
 *The register index is written with NMI bit preserved:
 *in 0x70 -- read current CMOS index (includes NMI bit 7)
 *and al, 0x80 -- preserve only NMI bit
 *or al, 0x4B -- set register to 0x4B
 *out 0x70, al -- select
 *in 0x71 -- read value
 *
 *Fallback at 0xFDAF0490:
 *if (CMOSLevel == 0) -> read byte from (0xFDAF0490)
 *if (byte & 2) -> set ErrorLevel to 0x80000000 | (byte & 1 ? 0xC : 0x4)
 *else -> default to ErrorLevel = 4
 *
 *Calls the protocol's ReportStatusCode at offset +0x00 if the error
 *level mask matches.
 *
 * @param[in] ErrorLevel Severity/class mask.
 * @param[in] Format Format string.
 * @param[in] ... Variable arguments.
 */
VOID EFIAPI DebugPrint(
 IN UINTN ErrorLevel,
 IN CONST CHAR8 *Format,
 ...
 )
{
 VOID *Protocol;
 UINT8 CmosDebugLevel;
 UINT32 DebugLevelMask;
 VA_LIST VaList;

 Protocol = GetDebugProtocol();
 if (Protocol == NULL) {
 return;
 }

 /*
 *Read CMOS debug level register 0x4B.
 */
 __outbyte(0x70, (__inbyte(0x70) & 0x80) | 0x4B);
 CmosDebugLevel = __inbyte(0x71);

 /*
 *Determine the effective debug level mask.
 */
 if (CmosDebugLevel > 3) {
 /*Level is already valid (> 3 means non-standard; use as-is) */
 DebugLevelMask = CmosDebugLevel;
 if (CmosDebugLevel == 0) {
 /*Level 0: fallback to MMIO-based detection */
 UINT8 BoardDebugReg = *(volatile UINT8 *)0xFDAF0490;
 if (BoardDebugReg & 2) {
 DebugLevelMask = EFI_ERROR_CODE | EFI_ERROR_MAJOR;
 if (!(BoardDebugReg & 1)) {
 DebugLevelMask = EFI_ERROR_CODE;
 }
 } else {
 DebugLevelMask = 4;
 }
 }
 } else {
 /*Level 1 -> mask 0x80000004, other -> mask 0x80000006 */
 if (CmosDebugLevel == 1) {
 DebugLevelMask = 0x80000004;
 } else {
 DebugLevelMask = 0x80000006;
 }
 }

 /*
 *If the error level matches, call the protocol's report function.
 */
 if (DebugLevelMask & ErrorLevel) {
 VA_START(VaList, Format);
 /*
 *Call the report function at protocol interface offset +0x00.
 *Signature: ReportStatusCode(ErrorLevel, Format, VaList)
 */
 ((EFI_STATUS (EFIAPI *)(UINTN, CONST CHAR8 *, VA_LIST))
 Protocol)(ErrorLevel, Format, VaList);
 VA_END(VaList);
 }
}

/* =========================================================================
 *HOB List Resolution
 * ========================================================================= */

/**
 *Compares two GUID pointers by reading two 8-byte halves.
 *Address: 0xD84
 *
 *Avoids a full CompareGuid() call by reading the first 8 bytes and
 *second 8 bytes of each GUID as UINT64 values, then comparing both pairs.
 *
 * @param[in] Guid1 Pointer to the reference GUID.
 * @param[in] Guid2 Pointer to the candidate GUID.
 *
 * @return TRUE if both 64-bit halves match, FALSE otherwise.
 */
BOOLEAN CompareGuidByUnaligned64(
 IN EFI_GUID *Guid1,
 IN EFI_GUID *Guid2
 )
{
 return (ReadUnaligned64(Guid1) == ReadUnaligned64(Guid2)) &&
 (ReadUnaligned64((UINT8 *)Guid1 + 8) == ReadUnaligned64((UINT8 *)Guid2 + 8));
}

/**
 *Locates the HOB list by scanning the system configuration table.
 *Address: 0xCAC
 *
 *Iterates over SystemTable->ConfigurationTable[] looking for
 *gEfiHobListGuid. Caches the result in gHobList.
 *
 *The configuration table is an array of:
 *typedef struct {
 *EFI_GUID VendorGuid; /*16 bytes */
 *VOID *VendorTable; /*8 bytes */
 * } EFI_CONFIGURATION_TABLE;
 *Total per entry: 24 (0x18) bytes.
 *
 *If the GUID is not found, triggers ASSERT_EFI_ERROR(EFI_NOT_FOUND).
 *
 *Source: e:\hs\MdePkg\Library\DxeHobLib\HobLib.c lines 54-55
 */
VOID GetHobList(VOID)
{
 UINTN Index;
 EFI_STATUS Status;
 EFI_GUID **ConfigEntry;

 if (gHobList != NULL) {
 return;
 }

 gHobList = NULL;

 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
 ConfigEntry = (EFI_GUID **)((UINT8 *)gST->ConfigurationTable +
 Index *sizeof(EFI_CONFIGURATION_TABLE));

 if (CompareGuidByUnaligned64(
 (EFI_GUID *)&mEfiHobListGuid,
 ConfigEntry[0])) /*ConfigEntry[0] = VendorGuid field */
 {
 gHobList = *(VOID **)((UINT8 *)ConfigEntry + sizeof(EFI_GUID));
 return;
 }
 }

 /*
 *HOB list GUID not found in configuration table.
 */
 ASSERT_EFI_ERROR(EFI_NOT_FOUND);
 ASSERT(gHobList != NULL);
}

/* =========================================================================
 *Parameter Validation
 * ========================================================================= */

/**
 *Validates I/O access parameters.
 *Address: 0x518
 *
 *Checks:
 *1. Buffer != NULL (return EFI_INVALID_PARAMETER if NULL)
 *2. Width < 12 (EFI_CPU_IO_PROTOCOL_WIDTH_MAXIMUM)
 *3. For non-FIFO/Fill modes (Width <= 3), AccessType must be valid:
 * - If AccessType == IO and Width == 3 (UINT64):
 *EFI_INVALID_PARAMETER (64-bit port I/O not supported)
 *4. Address alignment matches Width requirement
 *5. Address + Count*Width doesn't overflow architectural limit
 *6. Buffer alignment matches access width
 *
 *The Width value is masked as (Width & 3) when Width > 3 (FIFO/Fill
 *modes use the same alignment rules as the base width).
 *
 * @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 combo.
 * @return EFI_UNSUPPORTED Address alignment mismatch.
 * @return EFI_BAD_BUFFER_SIZE Address range overflow.
 */
EFI_STATUS CpuIoCheckParameter(
 UINT8 AccessType,
 UINT32 Width,
 UINT64 Address,
 UINT64 Count,
 VOID *Buffer
 )
{
 UINT64 MaxAddress;
 UINT64 AccessSize;
 UINT64 Alignment;

 /*
 *1. Validate Buffer and Width.
 */
 if (Buffer == NULL || Width >= EfiCpuIoWidthMaximum) {
 return EFI_INVALID_PARAMETER;
 }

 /*
 *2. For FIFO/Fill modes, the access width is effectively 1 element
 *of the base type (the stride remains the element size).
 */
 if (Width > 3) {
 AccessSize = 1; /*FIFO modes access one element at a time, but
 *a4 = AccessSize is set to 1 for bounds checking */
 Width = Width & 3;
 } else {
 AccessSize = Count;
 }

 /*
 *3. For port IO (AccessType == 0), 64-bit access (Width == 3) is
 *not supported on x64 port I/O.
 */
 if (AccessType == 0 && Width == 3) {
 return EFI_INVALID_PARAMETER;
 }

 /*
 *4. Check address alignment.
 *Width 0 (byte) -> alignment 1, passes for any address.
 *Width 1 (word) -> alignment 2 (must be even).
 *Width 2 (dword) -> alignment 4.
 *Width 3 (qword) -> alignment 8.
 */
 Alignment = mIoWidthTable[Width] - 1;
 if (Alignment & Address) {
 return EFI_UNSUPPORTED;
 }

 /*
 *5. Check that the address range fits within the architectural limit.
 *For I/O space: limit is 0xFFFF (16-bit port address space).
 *For MMIO: limit is MAX_UINT64 (full 64-bit address space).
 */
 if (AccessType == 0) {
 MaxAddress = 0xFFFF;
 } else {
 MaxAddress = MAX_UINT64;
 }

 if (AccessSize > 0) {
 /*
 *Compute whether Address + (AccessSize - 1) *elementWidth fits.
 *Uses shift operations to avoid overflow.
 */
 if ((Count > 1) && (Width > 0)) {
 /*Address + (Count - 1) * (1 << Width) */
 if (RShiftU64(MaxAddress - Address, Width) < (Count - 1)) {
 return EFI_UNSUPPORTED;
 }
 } else {
 if (Address > MaxAddress) {
 return EFI_UNSUPPORTED;
 }
 }
 }

 /*
 *6. Check buffer alignment.
 */
 if (Buffer != NULL) {
 UINT64 BufAlignment = mIoWidthTable[Width] - 1;
 if (BufAlignment & (UINT64)Buffer) {
 return EFI_UNSUPPORTED;
 }
 }

 return EFI_SUCCESS;
}

/* =========================================================================
 *CpuIoServiceRead -- Port I/O Read
 * ========================================================================= */

/**
 *Port I/O Read dispatcher.
 *Address: 0x818
 *
 *Handles port I/O reads for EFI_CPU_IO_PROTOCOL_WIDTH values 0-3.
 *For Width=0 (byte), uses direct __inbyte() for single reads or
 *__inbytestring() for bulk reads.
 *
 *Width=0 (byte):
 * - single: __inbyte(Port) -> *Buffer = result
 * - bulk: __inbytestring(Port, Buffer, Count)
 *
 *Width=1 (word):
 * - single: __inword(Port) with (Port & 1) alignment check -> *Buffer
 * - bulk: __inwordstring(Port, Buffer, Count)
 *
 *Width=2 (dword):
 * - single: __indword(Port) with (Port & 3) alignment check -> *Buffer
 * - bulk: __indwordstring(Port, Buffer, Count)
 *
 *For Width=0 non-bulk mode (Count=1):
 * - direct __inbyte call
 *
 *After validation, iterates Count times, reading each element with
 *the appropriate I/O instruction. The port is advanced by the access
 *width after each read. The buffer is advanced by the stride.
 *
 * @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.
 * @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
 )
{
 EFI_STATUS Status;
 UINT8 AccessWidth; /*In bytes per element */
 UINT8 Stride; /*Buffer advance per element */

 Status = CpuIoCheckParameter(0, Width, Port, Count, Buffer);
 if (EFI_ERROR(Status)) {
 return Status;
 }

 AccessWidth = mIoWidthTable[Width & 3];
 Stride = mIoWidthTable[(Width & 3) + 16]; /*Read stride */

 if (Count == 0) {
 return EFI_SUCCESS;
 }

 if (AccessWidth == 0) {
 /*
 *Bulk I/O string read.
 *For byte access: __inbytestring(Port, Buffer, Count).
 */
 UINTN BulkWidth = Width & 3;

 if (BulkWidth == 0) {
 /*Count byte reads */
 if (Count == 1) {
 *(UINT8 *)Buffer = __inbyte((UINT16)Port);
 } else {
 __inbytestring((UINT16)Port, Buffer, Count);
 }
 } else if (BulkWidth == 1) {
 /*Count word reads */
 if (Count == 1) {
 ASSERT(((UINTN)Port & 1) == 0);
 *(UINT16 *)Buffer = __inword((UINT16)Port);
 } else {
 __inwordstring((UINT16)Port, Buffer, Count);
 }
 } else if (BulkWidth == 2) {
 /*Count dword reads */
 if (Count == 1) {
 ASSERT(((UINTN)Port & 3) == 0);
 *(UINT32 *)Buffer = __indword((UINT16)Port);
 } else {
 __indwordstring((UINT16)Port, Buffer, Count);
 }
 }
 return EFI_SUCCESS;
 }

 /*
 *Element-by-element access with stride.
 *Each iteration reads one element, advances the port by AccessWidth,
 *and advances the buffer by Stride bytes.
 */
 do {
 UINT8 *BufPtr = (UINT8 *)Buffer;
 UINT16 Port16 = (UINT16)Port;

 if (AccessWidth == 1) {
 *BufPtr = __inbyte(Port16);
 Buffer = (VOID *)(BufPtr + 1);
 } else if (AccessWidth == 2) {
 ASSERT(((UINTN)Port & 1) == 0);
 *(UINT16 *)BufPtr = __inword(Port16);
 Buffer = (VOID *)((UINT16 *)BufPtr + 1);
 } else if (AccessWidth == 4) {
 ASSERT(((UINTN)Port & 3) == 0);
 *(UINT32 *)BufPtr = __indword(Port16);
 Buffer = (VOID *)((UINT32 *)BufPtr + 1);
 } else if (AccessWidth == 8) {
 /*8-byte port IO is not supported (caught by validation) */
 ASSERT(FALSE);
 }

 Port += AccessWidth;
 Count -= 1;
 } while (Count > 0);

 return EFI_SUCCESS;
}

/* =========================================================================
 *CpuIoServiceWrite -- Port I/O Write
 * ========================================================================= */

/**
 *Port I/O Write dispatcher.
 *Address: 0x970
 *
 *Handles port I/O writes for EFI_CPU_IO_PROTOCOL_WIDTH values 0-3.
 *
 *For each element:
 *Width=0: __outbyte(Port, *Buffer)
 *Width=1: __outword(Port, *(UINT16 *)Buffer) with alignment check
 *Width=2: __outdword(Port, *(UINT32 *)Buffer) with alignment check
 *Width=3: __outqword? Not supported by port I/O.
 *
 *Bulk operations use __outbytestring/__outwordstring/__outdwordstring.
 *
 * @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.
 * @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
 )
{
 EFI_STATUS Status;
 UINT8 AccessWidth;
 UINT8 Stride;

 Status = CpuIoCheckParameter(0, Width, Port, Count, Buffer);
 if (EFI_ERROR(Status)) {
 return Status;
 }

 AccessWidth = mIoWidthTable[Width & 3];
 Stride = mIoWidthTable[(Width & 3) + 20]; /*Write stride */

 if (Count == 0) {
 return EFI_SUCCESS;
 }

 if (AccessWidth == 0) {
 /*Bulk I/O string writes */
 UINTN BulkWidth = Width & 3;

 if (BulkWidth == 0) {
 __outbytestring((UINT16)Port, Buffer, Count);
 } else if (BulkWidth == 1) {
 __outwordstring((UINT16)Port, Buffer, Count);
 } else if (BulkWidth == 2) {
 __outdwordstring((UINT16)Port, Buffer, Count);
 }
 return EFI_SUCCESS;
 }

 /*
 *Element-by-element write.
 */
 do {
 UINT8 *BufPtr = (UINT8 *)Buffer;
 UINT16 Port16 = (UINT16)Port;

 if (AccessWidth == 1) {
 __outbyte(Port16, *BufPtr);
 Buffer = (VOID *)(BufPtr + Stride);
 } else if (AccessWidth == 2) {
 ASSERT(((UINTN)Port & 1) == 0);
 __outword(Port16, *(UINT16 *)BufPtr);
 Buffer = (VOID *)(BufPtr + Stride);
 } else if (AccessWidth == 4) {
 ASSERT(((UINTN)Port & 3) == 0);
 __outdword(Port16, *(UINT32 *)BufPtr);
 Buffer = (VOID *)(BufPtr + Stride);
 } else if (AccessWidth == 8) {
 ASSERT(FALSE);
 }

 Port += AccessWidth;
 Count -= 1;
 } while (Count > 0);

 return EFI_SUCCESS;
}

/* =========================================================================
 *CpuMemoryServiceRead -- MMIO Read
 * ========================================================================= */

/**
 *MMIO Read dispatcher.
 *Address: 0x61C
 *
 *Handles memory-mapped I/O reads. Parameters are first validated via
 *CpuIoCheckParameter with AccessType=MEM (1), then the read is
 *performed directly from the MMIO address.
 *
 *The MMIO read is a direct memory read from Address:
 *Width=0: *(volatile UINT8 *)Address
 *Width=1: *(volatile UINT16 *)Address
 *Width=2: *(volatile UINT32 *)Address
 *Width=3: *(volatile UINT64 *)Address
 *
 *For Count > 1, iterates Count times, advancing the address by the
 *access width and the buffer by the stride per element.
 *
 * @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
 )
{
 EFI_STATUS Status;
 UINT8 AccessWidth;
 UINT8 Stride;

 Status = CpuIoCheckParameter(1, Width, Address, Count, Buffer);
 if (EFI_ERROR(Status)) {
 return Status;
 }

 AccessWidth = mIoWidthTable[Width & 3];
 Stride = mIoWidthTable[(Width & 3) + 16]; /*Read stride */

 if (Count == 0) {
 return EFI_SUCCESS;
 }

 do {
 UINT8 *BufPtr = (UINT8 *)Buffer;

 if (AccessWidth == 1) {
 *BufPtr = *(volatile UINT8 *)Address;
 Buffer = (VOID *)(BufPtr + Stride);
 } else if (AccessWidth == 2) {
 /*ASSERT((Address & 1) == 0); */
 *(UINT16 *)BufPtr = *(volatile UINT16 *)Address;
 Buffer = (VOID *)((UINT16 *)BufPtr + 1); /*Stride varies */
 } else if (AccessWidth == 4) {
 *(UINT32 *)BufPtr = *(volatile UINT32 *)Address;
 Buffer = (VOID *)((UINT32 *)BufPtr + 1);
 } else if (AccessWidth == 8) {
 /*ASSERT((Address & 7) == 0); */
 *(UINT64 *)BufPtr = *(volatile UINT64 *)Address;
 Buffer = (VOID *)((UINT64 *)BufPtr + 1);
 }

 Address += AccessWidth;
 Count -= 1;
 } while (Count > 0);

 return EFI_SUCCESS;
}

/* =========================================================================
 *CpuMemoryServiceWrite -- MMIO Write
 * ========================================================================= */

/**
 *MMIO Write dispatcher.
 *Address: 0x714
 *
 *Handles memory-mapped I/O writes. Parameters are first validated via
 *CpuIoCheckParameter with AccessType=MEM (1), then the write is
 *performed directly to the MMIO address.
 *
 *The MMIO write is a direct memory write to Address:
 *Width=0: *(volatile UINT8 *)Address = *Buffer
 *Width=1: *(volatile UINT16 *)Address = *(UINT16 *)Buffer
 *Width=2: *(volatile UINT32 *)Address = *(UINT32 *)Buffer
 *Width=3: *(volatile UINT64 *)Address = *(UINT64 *)Buffer
 *
 * @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
 )
{
 EFI_STATUS Status;
 UINT8 AccessWidth;
 UINT8 Stride;

 Status = CpuIoCheckParameter(1, Width, Address, Count, Buffer);
 if (EFI_ERROR(Status)) {
 return Status;
 }

 AccessWidth = mIoWidthTable[Width & 3];
 Stride = mIoWidthTable[(Width & 3) + 20]; /*Write stride */

 if (Count == 0) {
 return EFI_SUCCESS;
 }

 do {
 UINT8 *BufPtr = (UINT8 *)Buffer;

 if (AccessWidth == 1) {
 *(volatile UINT8 *)Address = *BufPtr;
 Buffer = (VOID *)(BufPtr + Stride);
 } else if (AccessWidth == 2) {
 /*ASSERT((Address & 1) == 0); */
 *(volatile UINT16 *)Address = *(UINT16 *)BufPtr;
 Buffer = (VOID *)((UINT16 *)BufPtr + 1);
 } else if (AccessWidth == 4) {
 *(volatile UINT32 *)Address = *(UINT32 *)BufPtr;
 Buffer = (VOID *)((UINT32 *)BufPtr + 1);
 } else if (AccessWidth == 8) {
 /*ASSERT((Address & 7) == 0); */
 *(volatile UINT64 *)Address = *(UINT64 *)BufPtr;
 Buffer = (VOID *)((UINT64 *)BufPtr + 1);
 }

 Address += AccessWidth;
 Count -= 1;
 } while (Count > 0);

 return EFI_SUCCESS;
}

/* =========================================================================
 *Module Entry Point
 * ========================================================================= */

/**
 *Driver entry point -- ModuleEntryPoint (_ModuleEntryPoint).
 *Address: 0x3E0
 *
 *1. Saves ImageHandle and validates it.
 *2. Saves SystemTable (gST) and validates it.
 *3. Extracts gBS from gST->BootServices and validates.
 *4. Extracts gRT from gST->RuntimeServices and validates.
 *5. Calls GetHobList() to locate and cache the HOB list pointer.
 *6. Checks if gEfiCpuIo2ProtocolGuid is already installed in the
 *protocol database. If so, ASSERTs (single-instance driver).
 *7. Installs the EFI_CPU_IO2_PROTOCOL on a new handle via
 *gBS->InstallMultipleProtocolInterfaces():
 *Handle = NULL
 *Protocol: gEfiCpuIo2ProtocolGuid
 *Interface: protocol instance with function table
 *8. Returns EFI_STATUS from InstallMultipleProtocolInterfaces.
 *
 * @param[in] ImageHandle Handle for this driver image.
 * @param[in] SystemTable Pointer to the UEFI system table.
 *
 * @return EFI_SUCCESS Protocol installed.
 * @return EFI_INVALID_PARAMETER NULL ImageHandle or SystemTable.
 * @return EFI_ALREADY_STARTED Protocol already installed (asserted).
 */
EFI_STATUS EFIAPI ModuleEntryPoint(
 IN EFI_HANDLE ImageHandle,
 IN EFI_SYSTEM_TABLE *SystemTable
 )
{
 EFI_STATUS Status;
 EFI_CPU_IO2_PROTOCOL CpuIo2Protocol;
 EFI_HANDLE Handle;
 EFI_STATUS CheckStatus;

 /*
 *Save and validate global image handle.
 */
 gImageHandle = ImageHandle;
 ASSERT(gImageHandle != NULL);

 /*
 *Save and validate system table.
 */
 gST = SystemTable;
 ASSERT(gST != NULL);

 /*
 *Save and validate boot services pointer.
 */
 gBS = gST->BootServices;
 ASSERT(gBS != NULL);

 /*
 *Save and validate runtime services pointer.
 */
 gRT = gST->RuntimeServices;
 ASSERT(gRT != NULL);

 /*
 *Locate and cache the HOB list.
 */
 GetHobList();

 /*
 *Check that gEfiCpuIo2ProtocolGuid is NOT already installed.
 *Only one instance should exist system-wide.
 */
 Handle = NULL;
 CheckStatus = gBS->LocateProtocol(
 (EFI_GUID *)&mEfiCpuIo2ProtocolGuid,
 NULL,
 &Handle
 );
 if (!EFI_ERROR(CheckStatus)) {
 /*Protocol already installed -- this should not happen */
 ASSERT(FALSE);
 }

 /*
 *Build the CpuIo2Protocol instance.
 */
 CpuIo2Protocol.Revision = EFI_CPU_IO2_PROTOCOL_REVISION;
 CpuIo2Protocol.Mem.Read = CpuMemoryServiceRead;
 CpuIo2Protocol.Mem.Write = CpuMemoryServiceWrite;
 CpuIo2Protocol.Io.Read = CpuIoServiceRead;
 CpuIo2Protocol.Io.Write = CpuIoServiceWrite;

 /*
 *Install the protocol on a new handle.
 */
 Handle = NULL;
 Status = gBS->InstallMultipleProtocolInterfaces(
 &Handle,
 &mEfiCpuIo2ProtocolGuid,
 &CpuIo2Protocol,
 NULL
 );

 /*
 *This is an ASSERT_EFI_ERROR -- the module asserts on failure.
 */
 if (EFI_ERROR(Status)) {
 DEBUG((EFI_ERROR_CODE, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
 ASSERT_EFI_ERROR(FALSE);
 }

 return Status;
}