Newer
Older
AMI-Aptio-BIOS-Reversed / CpRcPkg / Universal / RegAccess / Pei / RegAccessPeim / RegAccessPeim.c
@Ajax Dong Ajax Dong 2 days ago 35 KB Recovering names (cleanups)
/**
 * @file RegAccessPeim.c
 * @brief Register Access PEIM
 *
 * Provides register read/write/modify services during the PEI phase.
 * Handles address translation for IIO (Integrated IO), CHA, PCU, Ubox,
 * and other CPU/internal bus registers across multiple sockets.
 *
 * Source path: CpRcPkg/Universal/RegAccess/Pei/RegAccess.c
 * Build path:  Build/HR6N0XMLK/DEBUG_VS2015/IA32/.../RegAccessPeim.pdb
 */

#include "RegAccessPeim.h"

/* ========================================================================
 * PEI Register Access PPI GUID
 * GUID data at unk_FFDB09BC location
 * ======================================================================== */
extern EFI_GUID gRegAccessPpiGuid;

/* ========================================================================
 * Register access function dispatch tables
 * ======================================================================== */

/**
 * Dispatch table for RegAccessReadRegister.
 * Address: 0xFFDB05B0 (funcs_FFDAED70)
 * Indexed by (Descriptor->ExtInfo >> 8) & 0xF (access width/box type)
 */
typedef EFI_STATUS (*REG_ACCESS_READ_FUNC)(REG_ACCESS_DESC *Desc, UINT64 *Value);
extern REG_ACCESS_READ_FUNC gRegAccessReadDispatchTable[];

/**
 * Dispatch table for RegAccessWriteRegister.
 * Address: 0xFFDB05BC (funcs_FFDAED59)
 */
typedef EFI_STATUS (*REG_ACCESS_WRITE_FUNC)(REG_ACCESS_DESC *Desc, UINT64 Value);
extern REG_ACCESS_WRITE_FUNC gRegAccessWriteDispatchTable[];

/**
 * Dispatch table for RegAccessReadModify.
 * Address: 0xFFDB05C8 (funcs_FFDAED8B)
 */
typedef EFI_STATUS (*REG_ACCESS_RM_FUNC)(REG_ACCESS_DESC *Desc, UINT64 AndMask, UINT64 OrMask);
extern REG_ACCESS_RM_FUNC gRegAccessReadModifyDispatchTable[];

/**
 * Dispatch table for RegAccessGetConfigSpace.
 * Address: 0xFFDB05D4 (funcs_FFDAEDA9)
 */
typedef VOID (*REG_ACCESS_CFG_FUNC)(UINT32 a, UINT32 b, REG_ACCESS_DESC *Desc, REG_ACCESS_DESC **Out);
extern REG_ACCESS_CFG_FUNC gRegAccessConfigDispatchTable[];

/* ========================================================================
 * Hardware topology byte tables
 * ======================================================================== */

/* Access width per box type: byte_FFDB05E0
 * Values: 1=byte, 2=word, 4=dword, 8=qword */
extern const UINT8 gRegAccessWidth[];

/* Element stride per box type: byte_FFDB05EC */
extern const UINT8 gRegAccessStride[];

/* Functional block to table index mapping arrays: byte_FFDB090C - byte_FFDB099C
 * Organized as 168-byte rows per CPU type variant */
extern const UINT8 gFuncBlockToIndex_Socket0[];  /* byte_FFDB090C */
extern const UINT8 gFuncBlockToIndex_Socket1[];  /* byte_FFDB0944 (168*1 offset) */

/* Device number mapping tables */
extern const UINT8 gDeviceNum_CHA[];             /* byte_FFDB0944 (also used by CHA) */
extern const UINT8 gDeviceNum_M2MEM[];           /* byte_FFDB094C */
extern const UINT8 gDeviceNum_MC[];              /* byte_FFDB0954 */
extern const UINT8 gDeviceNum_PCU[];             /* byte_FFDB095C */
extern const UINT8 gDeviceNum_IIO[];             /* byte_FFDB0964 */
extern const UINT8 gDeviceNum_KTI[];             /* byte_FFDB096C */
extern const UINT8 gDeviceNum_IIODfx[];          /* byte_FFDB099C (0xFF = invalid) */

/* KTI instance to device mapping */
extern const UINT8 gKtiInstanceToDevice[];       /* byte_FFDB09B4 */

/* ========================================================================
 * PEI module globals (.data section)
 * ======================================================================== */
extern REG_ACCESS_DESC    *gRegAccessConfigSpace;
extern UINT32             gRegAccessPpiDescriptorData[];

/* ========================================================================
 * Utility: library-style memset replacement
 * Equivalent to memset(buf, value, count)
 * Utility helper
 * ======================================================================== */
VOID *
EFIAPI
RegAccessMemSet (
  VOID   *Buffer,
  UINTN  Count,
  UINT8  Value
  )
{
  return memset (Buffer, Value, Count);
}

/* ========================================================================
 * Utility: library-style memmove replacement
 * Handles overlapping regions
 * Utility helper
 * ======================================================================== */
CHAR8 *
EFIAPI
RegAccessMemMove (
  CHAR8        *Destination,
  CONST CHAR8  *Source,
  UINTN        Count
  )
{
  UINTN  WordCount = Count >> 2;
  UINTN  Remainder = Count & 3;

  if (Source < Destination && &Source[Count - 1] >= Destination) {
    /* Overlapping: copy backward */
    Source    = &Source[Count - 1];
    Destination = &Destination[Count - 1];
  } else {
    /* Non-overlapping: copy dwords first */
    CopyMem (Destination, Source, WordCount * 4);
    Source    = &Source[WordCount * 4];
    Destination = &Destination[WordCount * 4];
  }

  CopyMem (Destination, Source, Remainder);
  return Destination;
}

/* ========================================================================
 * Utility: fill 64-bit values into array
 * Utility helper
 * Parameters:
 *   Base  - destination array base (UINT64*)
 *   Index - starting index, decremented to 0
 *   ValueLow, ValueHigh - the 64-bit value to write
 * ======================================================================== */
INTN
EFIAPI
RegAccessFill64 (
  UINT64  *Base,
  INTN    Index,
  UINT32  ValueLow,
  UINT32  ValueHigh
  )
{
  do {
    Base[Index - 1] = ValueLow | ((UINT64)ValueHigh << 32);
  } while (--Index);
  return (INTN)Base;
}

/* ========================================================================
 * Utility: memset32 wrapper
 * Utility helper
 * ======================================================================== */
VOID *
EFIAPI
RegAccessMemSet32 (
  VOID   *Buffer,
  UINTN  Count,
  UINT32 Value
  )
{
  return memset32 (Buffer, Value, Count);
}

/* ========================================================================
 * PEI Services: Get PEI Services Table Pointer
 * Returns the PeiServices pointer via IDT-based lookup
 * PEI services helper
 * ======================================================================== */
INTN
EFIAPI
GetPeiServicesTablePointer (
  VOID
  )
{
  IA32_DESCRIPTOR  Idtr;
  UINTN            *Ptr;

  AsmReadIdtr (&Idtr);
  Ptr = (UINTN *)(*(UINTN *)(Idtr.Base + 2) - 4);
  if (*Ptr == 0) {
    DEBUG ((EFI_D_ERROR, "PeiServices == NULL\n"));
    ASSERT (FALSE);
  }
  return *Ptr;
}

/* ========================================================================
 * PEI Services: Report Debug/Assert Message
 * Debug helper
 * ======================================================================== */
VOID
EFIAPI
ReportAssertMessage (
  IN UINTN        ErrorLevel,
  IN CONST CHAR8  *Message,
  ...
  )
{
  VA_LIST     Args;
  INTN        PeiServices;
  INTN        (*DebugFunc)(UINTN, CONST CHAR8 *, VA_LIST);

  PeiServices = GetPeiServicesTablePointer ();
  if (PeiServices == 0) {
    return;
  }

  DebugFunc = (VOID *)(*(UINTN *)PeiServices + 4);
  if ((GetDebugErrorLevel () & ErrorLevel) != 0) {
    VA_START (Args, Message);
    DebugFunc (ErrorLevel, Message, Args);
    VA_END (Args);
  }
}

/* ========================================================================
 * PEI Services: Debug Print (simple)
 * Debug helper
 * ======================================================================== */
INTN
EFIAPI
DebugPrint (
  IN UINTN        ErrorLevel,
  IN CONST CHAR8  *Format,
  ...
  )
{
  INTN  PeiServices;
  INTN  (*PrintFunc)(UINTN, CONST CHAR8 *, VA_LIST);

  PeiServices = GetPeiServicesTablePointer ();
  if (PeiServices == 0) {
    return 0;
  }

  VA_LIST Args;
  VA_START (Args, Format);
  PrintFunc = (VOID *)(*(UINTN *)PeiServices + 4);
  VA_END (Args);

  return PrintFunc (ErrorLevel, Format, Args);
}

/* ========================================================================
 * Get Debug Error Level via CMOS
 * Reads CMOS index 0x4A to determine current debug print mask
 * Debug helper
 * ======================================================================== */
INTN
EFIAPI
GetDebugErrorLevel (
  VOID
  )
{
  UINT8   CmosValue;
  UINT8   ResultVar;

  IoWrite8 (0x70, (IoRead8 (0x70) & 0x80) | 0x4A);
  CmosValue = IoRead8 (0x71);
  ResultVar = CmosValue;

  if (CmosValue <= 3) {
    goto CheckDone;
  }

  ResultVar = CmosValue;
  if (CmosValue == 0) {
    ResultVar = (MEMORY[0xFDAF0490] & 2) | 1;
    goto CheckDone;
  }

CheckDone:
  if (ResultVar == (UINT8)-1) return 0;
  if (ResultVar == 1)          return EFI_ALREADY_STARTED;
  return EFI_UNSUPPORTED;
}

/* ========================================================================
 * Utility: Always returns TRUE (debug enabled)
 * Utility helper
 * ======================================================================== */
BOOLEAN
EFIAPI
IsDebugEnabled (
  VOID
  )
{
  return TRUE;
}

/* ========================================================================
 * Utility: Boolean conversion
 * Utility helper
 * ======================================================================== */
BOOLEAN
EFIAPI
BoolCheck (
  IN UINTN  Value
  )
{
  return Value != 0;
}

/* ========================================================================
 * Cpu Dead Loop (infinite loop on error assertion)
 * Assertion helper
 * ======================================================================== */
VOID
EFIAPI
CpuDeadLoopEx (
  IN UINTN        ErrorLevel,
  IN CONST CHAR8  *Message,
  IN UINTN        Status
  )
{
  if (Status != 0) {
    if ((Status & 0xFFFFFF00) == 0xFFFFFF00) {
      Status = (UINT8)Status;
    }
    if ((Status & 0xFFFF0000) == 0xFFFF0000) {
      Status = (UINT16)Status;
    }
    if (IsDebugEnabled () && BoolCheck (0x80000000)) {
      ReportAssertMessage (0x80000000, Message, Status);
    }
  }
  while (TRUE);
}

/* ========================================================================
 * IO Memory Read (aligned memory access)
 * MMIO helper
 * ======================================================================== */
INTN
EFIAPI
IoMemRead (
  IN   UINTN    AccessWidth,
  IN   VOID     *Address,
  OUT  UINT64   *Value
  )
{
  switch (AccessWidth) {
  case 0:                           /* 1 byte */
    *(UINT8 *)Value = *(volatile UINT8 *)Address;
    break;

  case 1:                           /* 2 bytes */
    ASSERT (((UINTN)Address & 1) == 0);
    *(UINT16 *)Value = *(volatile UINT16 *)Address;
    break;

  default:                          /* 8 bytes */
    ASSERT (((UINTN)Address & 7) == 0);
    Value[0] = *(volatile UINT64 *)Address;
    break;
  }
  return 0;
}

/* ========================================================================
 * IO Memory Write (aligned memory access)
 * MMIO helper
 * ======================================================================== */
INTN
EFIAPI
IoMemWrite (
  IN   UINTN    AccessWidth,
  OUT  VOID     *Address,
  IN   UINT64   *Value
  )
{
  switch (AccessWidth) {
  case 0:                           /* 1 byte */
    *(volatile UINT8 *)Address = *(UINT8 *)Value;
    break;

  case 1:                           /* 2 bytes */
    ASSERT (((UINTN)Address & 1) == 0);
    *(volatile UINT16 *)Address = *(UINT16 *)Value;
    break;

  default:                          /* 4 or 8 bytes */
    ASSERT (((UINTN)Address & 7) == 0);
    *(volatile UINT32 *)Address = *(UINT32 *)Value;
    Address[4] = Value[1];
    break;
  }
  return 0;
}

/* ========================================================================
 * Bitwise merge (used by ReadModify)
 * Bitfield helper
 * ======================================================================== */
UINTN
EFIAPI
BitFieldMerge (
  IN OUT  UINT64  *Value,
  IN      UINTN   AndMask,
  IN      UINTN   OrMask,
  IN      UINT8   ByteCount
  )
{
  UINT8   Result[8];
  UINT8   SrcParts[8];
  UINT8   DstParts[8];
  UINTN   i;

  /* Initialize source and destination parts */
  for (i = 0; i < ByteCount; i++) {
    SrcParts[i] = (AndMask != 0) ? ((UINT8 *)&Value)[i + Offset] : 0xFF;
    DstParts[i] = (OrMask != 0) ? ((UINT8 *)(&Value))[Offset2 + i] : 0;
    Result[i] = DstParts[i] | (SrcParts[i] & AND[i]);
  }

  /* Write back */
  *Value = *(UINT64 *)&Result;
  return *Value;
}

/* ========================================================================
 * Shift Left 64 (with bounds check)
 * Shift helper
 * ======================================================================== */
UINT64
EFIAPI
InternalLShift64 (
  IN  UINT64  Value,
  IN  UINTN   ShiftCount
  )
{
  ASSERT (ShiftCount < 64);
  if (ShiftCount >= 64) {
    CpuDeadLoop (0x80000000, "ASSERT_EFI_ERROR (Status = %r)\n", EFI_UNSUPPORTED);
  }
  if ((ShiftCount & 0x20) != 0) {
    return Value << (ShiftCount & 0x1F);
  }
  return Value << (ShiftCount & 0x1F);
}

/* ========================================================================
 * Shift Right 64 (with bounds check)
 * Shift helper
 * ======================================================================== */
UINT64
EFIAPI
InternalRShift64 (
  IN  UINT64  Value,
  IN  UINTN   ShiftCount
  )
{
  ASSERT (ShiftCount < 64);
  if ((ShiftCount & 0x20) != 0) {
    return (UINT64)(UINT32)(Value >> (ShiftCount & 0x1F));
  }
  return Value >> (ShiftCount & 0x1F);
}

/* ========================================================================
 * Read IDTR (sidt instruction wrapper)
 * Utility helper
 * ======================================================================== */
VOID
EFIAPI
InternalReadIdtr (
  OUT IA32_DESCRIPTOR *Idtr
  )
{
  ASSERT (Idtr != NULL);
  AsmReadIdtr (Idtr);
}

/* ========================================================================
 * PCD Protocol: Get PCD value via PCD protocol
 * PCD helper
 * ======================================================================== */
VOID *
EFIAPI
PcdGetProtocol (
  IN  UINTN  TokenNumber
  )
{
  INTN        PeiServices;
  EFI_STATUS  Status;
  VOID        *PcdProtocol;

  PeiServices = GetPeiServicesTablePointer ();
  Status = (*PeiServices->LocateProtocol) (&gPcdPpiGuid, NULL, &PcdProtocol);
  if (EFI_ERROR (Status)) {
    CpuDeadLoop (0x80000000, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
  }
  return PcdProtocol;
}

/* ========================================================================
 * PCD Get Pointer wrapper (token 5)
 * PCD helper
 * ======================================================================== */
VOID *
EFIAPI
PcdGetPtr (
  IN  UINTN  TokenNumber
  )
{
  VOID  *PcdProtocol;
  VOID  *Value;

  PcdProtocol = PcdGetProtocol (TokenNumber);
  Value = ((PCD_PPI_PROTOCOL *)PcdProtocol)->GetPtr (TokenNumber);
  return Value;
}

/* ========================================================================
 * PCD Get Size wrapper (token 6)
 * PCD helper
 * ======================================================================== */
UINTN
EFIAPI
PcdGetSize (
  IN  UINTN  TokenNumber
  )
{
  VOID  *PcdProtocol;

  PcdProtocol = PcdGetProtocol (TokenNumber);
  return ((PCD_PPI_PROTOCOL *)PcdProtocol)->GetSize (TokenNumber);
}

/* ========================================================================
 * PCD Set Ptr/Size (allocate PCD data buffer)
 * PCD helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
PcdSetRegisterAccess (
  IN  REG_ACCESS_DESC  *Desc,
  IN  UINTN            ElementCount
  )
{
  UINTN  PcdSize;

  PcdSize = PcdGetSize (6, 0);
  Desc->AddressLow = 16 * ElementCount + 16;

  if (Desc->AddressHigh == 0 && Desc->AddressLow == 0) {
    *((UINTN *)(PcdSize + 16)) = PcdGetPtr (5);
    *((UINTN *)(PcdSize + 20)) = 0;
  }
  return EFI_SUCCESS;
}

/* ========================================================================
 * Register Access: Lookup PCD data pointer
 * Address translation helper
 * ======================================================================== */
VOID *
EFIAPI
RegAccessLookupTablePointer (
  IN  REG_ACCESS_DESC  *Desc
  )
{
  VOID   *PcdTable;
  UINT32 PcdAddrLow;
  UINT32 PcdAddrHigh;
  UINTN  PcdSize;
  UINT16 SocketIndex;

  SocketIndex = Desc->AddressLow & 0xFFFF;

  if (Desc->InstanceData != NULL) {
    PcdAddrLow  = *(UINT32 *)(Desc->InstanceData + 4 * SocketIndex + 0x3E638);
    PcdAddrHigh = *(UINT32 *)(Desc->InstanceData + 4 * SocketIndex + 0x3E648);
  } else {
    PcdSize = PcdGetSize (6, 0);
    if (*(UINT32 *)(PcdSize + 4) != 0) {
      PcdAddrLow  = *(UINT32 *)(PcdSize + 20 + 16 * SocketIndex);
      PcdAddrHigh = *(UINT32 *)(PcdSize + 16 + 16 * SocketIndex);
    } else {
      PcdSetRegisterAccess (gRegAccessConfigSpace, 8);
      PcdAddrLow  = gRegAccessConfigSpace[4 * SocketIndex].AddressLow;
      PcdAddrHigh = gRegAccessConfigSpace[4 * SocketIndex].AddressHigh;
      if (PcdAddrHigh == 0 && PcdAddrLow == 0) {
        PcdAddrHigh = PcdGetPtr (5);
        PcdAddrLow  = 0;
      }
    }
  }

  if (PcdAddrHigh == 0 && PcdAddrLow == 0) {
    return PcdGetPtr (5);
  }
  return (VOID *)(UINTN)PcdAddrHigh;
}

/* ========================================================================
 * Address translation page table walk
 * Address translation helper
 * ======================================================================== */

/* ========================================================================
 * Translate Socket & Box Type to page table index (high-level)
 * Address translation helper
 * Returns a byte index into the socket/box-specific page table
 * ======================================================================== */
UINTN
EFIAPI
CpuTypeToTableIndex (
  IN  UINTN   SocketId,
  IN  UINTN   CpuType,
  IN  UINTN   BoxInstance,
  IN  UINTN   FunctionalBlock
  )
{
  /* Validated by the translation helper on failure. */
  return 0;
}

/* ========================================================================
 * Device number lookup (address translation step 2)
 * Address translation helper
 * ======================================================================== */
UINTN
EFIAPI
CpuTypeToDeviceIndex (
  IN  UINTN   SocketId,
  IN  UINTN   CpuType,
  IN  UINTN   BoxInstance,
  IN  UINTN   FunctionalBlock
  )
{
  UINTN   Index = 0;
  UINT8   IsSimpleCpu = *(UINT8 *)(CpuConfigTable + 44);
  UINT8   KtiPerSocket = *(UINT8 *)(CpuConfigTable + 60);

  switch (CpuType) {
  case 0:                       /* CHA */
    if (!IsSimpleCpu && BoxInstance < 28) {
      if (BoxInstance < 8)      return 9;
      if (BoxInstance < 16)     return 10;
      return 11 - (BoxInstance < 24);
    }
    break;

  case 1:                       /* M2MEM */
    if (!IsSimpleCpu && BoxInstance < 2) {
      Index = BoxInstance + 8;
    } else {
      CpuDeadLoop (SocketId, "Invalid M2MEM Box Instance Number %d. \n", BoxInstance);
    }
    return Index;

  case 2:                       /* CHA (alt mapping) */
    if (!IsSimpleCpu && BoxInstance < 28) {
      if (BoxInstance < 8)      return 20;
      if (BoxInstance < 16)     return 21;
      return 23 - (BoxInstance < 24);
    }
    break;

  case 3:                       /* CHABC */
  case 4:                       /* PCU */
  case 5:                       /* VCU */
    if (!IsSimpleCpu && BoxInstance == 0) {
      Index = (CpuType == 3) ? 29 : (CpuType == 4) ? 30 : 31;
    } else {
      CpuDeadLoop(...);
    }
    return Index;

  case 7:                       /* IIO generic */
  case 11:
    if (!IsSimpleCpu) {
      if (BoxInstance <= 1)           Index = 10;
      else if (BoxInstance == 2)      Index = 11;
      else if (BoxInstance <= 4)      Index = 12;
      else if (BoxInstance == 5)      Index = 13;
    } else {
      CpuDeadLoop(SocketId, "Invalid Cpu type.\n", 0);
    }
    return Index;

  /* Remaining cases follow the same translation pattern. */
  }
  return 0;
}

/* ========================================================================
 * Functional block number lookup (address translation step 3)
 * Address translation helper
 * ======================================================================== */
UINTN
EFIAPI
FuncBlockToTableIndex (
  IN  UINTN   SocketId,
  IN  UINTN   CpuType,
  IN  UINTN   BoxInstance,
  IN  UINTN   FunctionalBlock
  )
{
  UINTN   Index = 0;
  UINT8   IsSimpleCpu;
  UINT8   KtiPerSocket;

  IsSimpleCpu = *(UINT8 *)(CpuConfigTable + 44);
  KtiPerSocket = *(UINT8 *)(CpuConfigTable + 60);

  switch (CpuType) {
  case 0: case 1: case 2:     /* CHA/M2MEM/CHA-alt */
    if (!IsSimpleCpu && BoxInstance < 28) {
      Index = BoxInstance & 7;
    }
    return Index;

  case 3: case 4: case 5: case 6: case 13:
  case 14: case 15: case 16: case 17: case 19:
    Index = gFuncBlockToIndex_Socket0[168 * IsSimpleCpu + 8 * CpuType + FunctionalBlock];
    break;

  case 7:                     /* IIO generic */
    Index = FunctionalBlock + gDeviceNum_IIO[168 * IsSimpleCpu + BoxInstance % KtiPerSocket];
    break;

  /* ... more cases */
  }

  if (Index > 7) {
    CpuDeadLoop(SocketId, "Invalid Functional Block...", FunctionalBlock);
  }
  return Index;
}

/* ========================================================================
 * Address translation: page table walk (3-level)
 * Combines socket, box type, instance, and functional block into
 * a final page table index.
 * Address translation helper
 * ======================================================================== */
UINTN
EFIAPI
TranslateAddressWalk (
  IN  REG_ACCESS_DESC  *Descriptor,
  IN  UINTN            PageTableBase,
  OUT UINT64           *TranslatedAddress
  )
{
  UINT8   SocketId;
  UINT8   CpuType;
  UINT8   BoxInstance;
  UINT8   FuncBlock;

  SocketId    = *(UINT8 *)(Descriptor + 5);
  CpuType     = *(UINT8 *)(Descriptor + 3);
  BoxInstance = *(UINT8 *)(Descriptor + 4);
  FuncBlock   = *(UINT8 *)(Descriptor + 2);

  *TranslatedAddress ^= (CpuTypeToTableIndex(SocketId, CpuType, BoxInstance, FuncBlock, PageTableBase) << 20);
  *TranslatedAddress ^= (CpuTypeToDeviceIndex(SocketId, CpuType, BoxInstance, FuncBlock, PageTableBase) << 15);
  *TranslatedAddress ^= (FuncBlockToTableIndex(SocketId, CpuType, BoxInstance, FuncBlock, PageTableBase) << 12);

  return SocketId;
}

/* ========================================================================
 * Validate register range and alignment
 * Validation helper
 * Returns 0 on success, EFI error code on failure
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessValidateRange (
  IN  UINTN   AccessWidth,
  IN  UINT64  Address,
  IN  UINTN   Count,
  IN  UINTN   Buffer
  )
{
  UINTN   AccessBytes;

  if (Buffer == 0 || AccessWidth >= 12) {
    return EFI_INVALID_PARAMETER;
  }

  AccessBytes = gRegAccessWidth[AccessWidth & 3];
  if ((Address & (AccessBytes - 1)) != 0) {
    return EFI_ALIGNMENT_ERROR;      /* misaligned */
  }

  if (Count == 0) {
    if (Address >> 32 != 0) {
      return EFI_ALIGNMENT_ERROR;    /* out of range for 32-bit */
    }
    /* Range check: count-1 fits in accessible space */
    if (InternalLShift64 (1, Count) < (Count - 1)) {
      return EFI_ALIGNMENT_ERROR;
    }
  }

  /* Verify buffer alignment */
  if ((Buffer & (MIN(AccessBytes, 4) - 1)) != 0) {
    return EFI_ALIGNMENT_ERROR;
  }

  return EFI_SUCCESS;
}

/* ========================================================================
 * DISPATCH: RegAccess Read Register (via dispatch table)
 * Dispatch helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessReadRegister (
  IN  REG_ACCESS_DESC  *Descriptor,
  OUT UINT64           *Value
  )
{
  return gRegAccessReadDispatchTable[
           (Descriptor->ExtInfo >> 8) & REG_ACCESS_BOX_TYPE_MASK
         ] (Descriptor, Value);
}

/* ========================================================================
 * DISPATCH: RegAccess Write Register (via dispatch table)
 * Dispatch helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessWriteRegister (
  IN  REG_ACCESS_DESC  *Descriptor,
  IN  UINT64            Value
  )
{
  return gRegAccessWriteDispatchTable[
           (Descriptor->ExtInfo >> 8) & REG_ACCESS_BOX_TYPE_MASK
         ] (Descriptor, Value);
}

/* ========================================================================
 * DISPATCH: RegAccess Read Modify (via dispatch table)
 * Dispatch helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessReadModify (
  IN  REG_ACCESS_DESC  *Descriptor,
  IN  UINT64           AndMask,
  IN  UINT64           OrMask
  )
{
  return gRegAccessReadModifyDispatchTable[
           (Descriptor->ExtInfo >> 8) & REG_ACCESS_BOX_TYPE_MASK
         ] (Descriptor, AndMask, OrMask);
}

/* ========================================================================
 * DISPATCH: RegAccess Get Config Space
 * Dispatch helper
 * ======================================================================== */
VOID
EFIAPI
RegAccessGetConfigSpace (
  OUT REG_ACCESS_DESC  *Descriptor
  )
{
  gRegAccessConfigDispatchTable[
    (Descriptor->ExtInfo >> 8) & REG_ACCESS_BOX_TYPE_MASK
  ] (0, 0, Descriptor, &Descriptor);
}

/* ========================================================================
 * IMPL: RegAccess Read Register (box type dispatch = 0)
 * Reads from translated address via IoMemRead
 * Implementation helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessReadImpl (
  IN  REG_ACCESS_DESC  *Descriptor,
  OUT UINT64           *Value
  )
{
  UINT64  TranslatedAddress;
  UINT64  *AddressPtr;

  RegAccessTranslateAddress (Descriptor, &TranslatedAddress);
  AddressPtr = (UINT64 *)(UINTN)TranslatedAddress;
  IoMemRead (
    (Descriptor->ExtInfo >> 8) & 0xF,
    AddressPtr,
    Value
    );
  return EFI_SUCCESS;
}

/* ========================================================================
 * IMPL: RegAccess Write Register (box type dispatch = 0)
 * Writes to translated address via IoMemWrite
 * Implementation helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessWriteImpl (
  IN  REG_ACCESS_DESC  *Descriptor,
  IN  UINT64           Value
  )
{
  UINT64  TranslatedAddress;
  UINT64  *AddressPtr;

  RegAccessTranslateAddress (Descriptor, &TranslatedAddress);
  AddressPtr = (UINT64 *)(UINTN)TranslatedAddress;
  IoMemWrite (
    (Descriptor->ExtInfo >> 8) & 0xF,
    AddressPtr,
    &Value
    );
  return EFI_SUCCESS;
}

/* ========================================================================
 * IMPL: RegAccess Read Modify (box type dispatch = 0)
 * Reads, applies AND/OR mask, writes back
 * Implementation helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessReadModifyImpl (
  IN  REG_ACCESS_DESC  *Descriptor,
  IN  UINT64           AndMask,
  IN  UINT64           OrMask
  )
{
  UINT64  Value[2];
  UINT8   ByteMask;

  RegAccessReadImpl (Descriptor, Value);
  ByteMask = (UINT8)(UINTN)&Value[-1] + ((Descriptor->ExtInfo >> 8) & 0xF);
  BitFieldMerge (Value, AndMask, OrMask, ByteMask);
  RegAccessWriteImpl (Descriptor, Value);
  return EFI_SUCCESS;
}

/* ========================================================================
 * IMPL: Read multiple elements via IoMemRead (box type dispatch = 1)
 * Implementation helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessReadMultiImpl (
  IN  REG_ACCESS_DESC  *Descriptor,
  OUT VOID             *Buffer
  )
{
  UINTN   Count;
  UINT64  TranslatedAddress;
  UINT64  *SrcPtr;
  UINT64  *DstPtr;
  UINTN   ElementSize;
  UINTN   Stride;

  Count = Descriptor->Count;
  RegAccessTranslateAddress (Descriptor, &TranslatedAddress);
  SrcPtr = (UINT64 *)(UINTN)TranslatedAddress;

  if (RegAccessValidateRange (
        (Descriptor->ExtInfo >> 8) & 0xF,
        TranslatedAddress,
        Count,
        (UINTN)Buffer
        ) < 0) {
    return EFI_INVALID_PARAMETER;
  }

  {
    UINTN   BoxType = (Descriptor->ExtInfo >> 8) & 0xF;
    ElementSize = gRegAccessWidth[BoxType];
    Stride    = gRegAccessStride[BoxType];
    DstPtr    = (UINT64 *)Buffer;

    while (Count--) {
      IoMemRead (
        (Descriptor->ExtInfo >> 8) & 3,
        SrcPtr,
        DstPtr
        );
      DstPtr = (UINT64 *)((UINT8 *)DstPtr + Stride);
      SrcPtr = (UINT64 *)((UINT8 *)SrcPtr + ElementSize);
    }
  }
  return EFI_SUCCESS;
}

/* ========================================================================
 * IMPL: Write multiple elements via IoMemWrite (box type dispatch = 1)
 * Implementation helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessWriteMultiImpl (
  IN  REG_ACCESS_DESC  *Descriptor,
  IN  VOID             *Buffer
  )
{
  UINTN   Count;
  UINT64  TranslatedAddress;
  UINT64  *SrcPtr;
  UINT64  *DstPtr;
  UINTN   ElementSize;
  UINTN   Stride;

  Count = Descriptor->Count;
  RegAccessTranslateAddress (Descriptor, &TranslatedAddress);
  SrcPtr = (UINT64 *)(UINTN)TranslatedAddress;

  if (RegAccessValidateRange (...) < 0) {
    return EFI_INVALID_PARAMETER;
  }

  {
    UINTN   BoxType = (Descriptor->ExtInfo >> 8) & 0xF;
    ElementSize = gRegAccessWidth[BoxType];
    Stride    = gRegAccessStride[BoxType];
    DstPtr    = (UINT64 *)Buffer;

    while (Count--) {
      IoMemWrite (
        (Descriptor->ExtInfo >> 8) & 3,
        DstPtr,
        SrcPtr
        );
      DstPtr = (UINT64 *)((UINT8 *)DstPtr + Stride);
      SrcPtr = (UINT64 *)((UINT8 *)SrcPtr + ElementSize);
    }
  }
  return EFI_SUCCESS;
}

/* ========================================================================
 * IMPL: Get MMIO address from descriptor (box type dispatch = 0)
 * Implementation helper
 * ======================================================================== */
INTN
EFIAPI
RegAccessTranslateAddress (
  IN  REG_ACCESS_DESC  *Descriptor,
  OUT UINT64           *TranslatedAddress
  )
{
  UINTN  TablePtr;

  TablePtr = RegAccessLookupTablePointer (Descriptor);
  *TranslatedAddress = TablePtr + (Descriptor->AddressLow & 0xFFFFFFF);
  return *TranslatedAddress;
}

/* ========================================================================
 * Page table address translation (full path)
 * Address translation helper
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessTranslateFull (
  IN  REG_ACCESS_DESC  *Descriptor,
  OUT UINT64           *TranslatedAddress
  )
{
  UINTN   PageTable;
  UINT32  OriginalLow;
  UINT32  PageTableInfo[3];

  PageTable = Descriptor->InstanceData;
  OriginalLow = Descriptor->AddressLow;

  /* Check if address needs translation */
  if (PageTable != 0 && (OriginalLow & 0x8000) != 0) {
    Descriptor->AddressLow = OriginalLow & 0xFFFF0000;
  }

  /* Encode box type from address bits 13-14 */
  Descriptor->ExtInfo &= 0xFFFFF0FF;
  Descriptor->ExtInfo |= ((OriginalLow >> 13) & 3) << 8;

  /* Check cached translation */
  if (PageTable != 0
      && *(UINT8 *)(PageTable + 0x998C0) != 0
      && *(UINT32 *)(PageTable + 0x998B4) == (OriginalLow & 0xFFFFF000)
      && *(UINT32 *)(PageTable + 0x998B8) == Descriptor->AddressHigh) {
    /* Cached hit */
    *TranslatedAddress = (*(UINT32 *)(PageTable + 0x998BC) & 0xFFFFF000)
                         | (OriginalLow & 0xFFF);
  } else {
    /* Page walk */
    ZeroMem (PageTableInfo, sizeof(PageTableInfo));
    TranslateAddressWalk (Descriptor, PageTable + 0x3E5F8, PageTableInfo);

    PageTableInfo[0] ^= (Descriptor->AddressLow & 0xFFF) ^ (OriginalLow & 0xFFF);
    PageTableInfo[0] = (PageTableInfo[0] ^ (OriginalLow ^ PageTableInfo[0]) & 0xFFF);
    Descriptor->InstanceData = (VOID *)(UINTN)PageTable;

    *TranslatedAddress = RegAccessLookupTablePointer (PageTableInfo)
                        + (PageTableInfo[0] & 0xFFFFFFF);

    /* Cache translation */
    if (PageTable != 0) {
      *(UINT32 *)(PageTable + 0x998B4) = OriginalLow & 0xFFFFF000;
      *(UINT32 *)(PageTable + 0x998B8) = Descriptor->AddressHigh;
      *(UINT32 *)(PageTable + 0x998BC) = *TranslatedAddress & 0xFFFFF000;
    }
  }
  return EFI_SUCCESS;
}

/* ========================================================================
 * Thunk helper
 * ======================================================================== */
INTN
EFIAPI
RegAccessGetConfigSpaceThunk (
  IN  REG_ACCESS_DESC  *Descriptor,
  OUT REG_ACCESS_DESC  *ConfigSpace
  )
{
  UINT64  *AddressPtr = NULL;

  RegAccessTranslateFull (0, 0, Descriptor, &AddressPtr);
  IoMemRead (
    (Descriptor->ExtInfo >> 8) & 0xF,
    AddressPtr,
    ConfigSpace
    );
  return 0;
}

/* ========================================================================
 * Write config space via translation and IoMemWrite
 * Thunk helper
 * ======================================================================== */
INTN
EFIAPI
RegAccessWriteConfigThunk (
  IN  REG_ACCESS_DESC  *Descriptor,
  OUT REG_ACCESS_DESC  *ConfigSpace
  )
{
  UINT64  *AddressPtr = NULL;

  RegAccessTranslateFull (0, 0, Descriptor, &AddressPtr);
  IoMemWrite (
    (Descriptor->ExtInfo >> 8) & 0xF,
    AddressPtr,
    ConfigSpace
    );
  return 0;
}

/* ========================================================================
 * Thunk: ReadModify with AND/OR via translation
 * Thunk helper
 * ======================================================================== */
INTN
EFIAPI
RegAccessReadModifyThunk (
  IN  REG_ACCESS_DESC  *Descriptor,
  IN  UINT64           AndMask,
  IN  UINT64           OrMask
  )
{
  UINT64  Value[2];
  UINT64  *AddressPtr = NULL;
  UINT32  BoxTypeInfo = 134480385;   /* magic constant */
  UINT8   ByteCount;

  RegAccessTranslateFull (0, 0, Descriptor, &AddressPtr);
  IoMemRead ((Descriptor->ExtInfo >> 8) & 0xF, AddressPtr, Value);

  ByteCount = *((UINT8 *)&BoxTypeInfo + ((Descriptor->ExtInfo >> 8) & 0xF));
  BitFieldMerge (Value, AndMask, OrMask, ByteCount);

  IoMemWrite ((Descriptor->ExtInfo >> 8) & 0xF, AddressPtr, Value);
  return 0;
}

/* ========================================================================
 * Address translation helper (strip high bits)
 * Address helper
 * ======================================================================== */
UINT32
EFIAPI
RegAccessStripHighBits (
  IN  UINTN   PageTable,
  IN  UINT32  Address
  )
{
  return Address & 0xFFFF0000;
}

/* ========================================================================
 * Module Entry Point (PEIM)
 * Registers the RegAccess PPI
 * Address: _ModuleEntryPoint (0xFFDAED01)
 * ======================================================================== */
EFI_STATUS
EFIAPI
RegAccessEntryPoint (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS              Status;
  EFI_PEI_PPI_DESCRIPTOR  *PpiDescriptor;

  /* Save PEI services table pointer */
  gImageHandle = ImageHandle;
  gST = SystemTable;
  gBS = SystemTable->BootServices;
  gRT = SystemTable->RuntimeServices;

  /* Initialize PCD protocol */
  PcdGetProtocol (5);

  /* Register the RegAccess PPI */
  DEBUG ((EFI_D_INFO, "UBA:SETUPConfigUpdate-TypeLightningRidgeEXRP\n"));

  Status = (*gBS->InstallPpi) (&gRegAccessPpiDescriptor);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
    ASSERT_EFI_ERROR (Status);
  }

  return Status;
}

/* ========================================================================
 * PCD Get PPI via PeiServices->LocatePpi
 * Equivalent to PeiPcdLib GetPcdProtocol()
 * PCD helper
 * ======================================================================== */
VOID *
EFIAPI
PcdGetProtocol (
  IN  UINTN  TokenNumber
  )
{
  PEI_PCD_PPI     *PcdPpi;
  EFI_STATUS      Status;
  INTN            PeiServices;

  PeiServices = GetPeiServicesTablePointer ();
  Status = (*PeiServices->LocatePpi) (&gEfiPeiPcdPpiGuid, &PpiDescriptor, &PcdPpi);
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "ASSERT_EFI_ERROR (Status = %r)\n", Status));
    ASSERT_EFI_ERROR (Status);
  }
  return (VOID *)PcdPpi;
}