]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/CpuIoPei/CpuIoPei.c
Add generic CpuIoPei module that produces the CPU I/O PPU using the services of the...
[mirror_edk2.git] / UefiCpuPkg / CpuIoPei / CpuIoPei.c
diff --git a/UefiCpuPkg/CpuIoPei/CpuIoPei.c b/UefiCpuPkg/CpuIoPei/CpuIoPei.c
new file mode 100644 (file)
index 0000000..7f73838
--- /dev/null
@@ -0,0 +1,1056 @@
+/** @file\r
+  Produces the CPU I/O PPI.\r
+\r
+Copyright (c) 2009 - 2010, Intel Corporation\r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Ppi/CpuIo.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#define MAX_IO_PORT_ADDRESS   0xFFFF\r
+\r
+//\r
+// Function Prototypes\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+CpuMemoryServiceRead (\r
+  IN  CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN  EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN  UINT64                    Address,\r
+  IN  UINTN                     Count,\r
+  OUT VOID                      *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuMemoryServiceWrite (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN UINT64                    Address,\r
+  IN UINTN                     Count,\r
+  IN VOID                      *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuIoServiceRead (\r
+  IN  CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN  EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN  UINT64                    Address,\r
+  IN  UINTN                     Count,\r
+  OUT VOID                      *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CpuIoServiceWrite (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN UINT64                    Address,\r
+  IN UINTN                     Count,\r
+  IN VOID                      *Buffer\r
+  );\r
+\r
+UINT8\r
+EFIAPI\r
+CpuIoRead8 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address\r
+  );\r
+\r
+UINT16\r
+EFIAPI\r
+CpuIoRead16 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address\r
+  );\r
+\r
+UINT32\r
+EFIAPI\r
+CpuIoRead32 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address\r
+  );\r
+\r
+UINT64\r
+EFIAPI\r
+CpuIoRead64 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+CpuIoWrite8 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address,\r
+  IN  UINT8                       Data\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+CpuIoWrite16 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address,\r
+  IN  UINT16                      Data\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+CpuIoWrite32 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address,\r
+  IN  UINT32                      Data\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+CpuIoWrite64 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address,\r
+  IN  UINT64                      Data\r
+  );\r
+\r
+UINT8\r
+EFIAPI\r
+CpuMemRead8 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address\r
+  );\r
+\r
+UINT16\r
+EFIAPI\r
+CpuMemRead16 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address\r
+  );\r
+\r
+UINT32\r
+EFIAPI\r
+CpuMemRead32 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address\r
+  );\r
+\r
+UINT64\r
+EFIAPI\r
+CpuMemRead64 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+CpuMemWrite8 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address,\r
+  IN  UINT8                       Data\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+CpuMemWrite16 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address,\r
+  IN  UINT16                      Data\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+CpuMemWrite32 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address,\r
+  IN  UINT32                      Data\r
+  );\r
+\r
+VOID\r
+EFIAPI\r
+CpuMemWrite64 (\r
+  IN  CONST EFI_PEI_SERVICES      **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI    *This,\r
+  IN  UINT64                      Address,\r
+  IN  UINT64                      Data\r
+  );\r
+  \r
+//\r
+// Instance of CPU I/O PPI\r
+//\r
+EFI_PEI_CPU_IO_PPI  gCpuIoPpi = {\r
+  {\r
+    CpuMemoryServiceRead,\r
+    CpuMemoryServiceWrite\r
+  },\r
+  {\r
+    CpuIoServiceRead,\r
+    CpuIoServiceWrite\r
+  },\r
+  CpuIoRead8,\r
+  CpuIoRead16,\r
+  CpuIoRead32,\r
+  CpuIoRead64,\r
+  CpuIoWrite8,\r
+  CpuIoWrite16,\r
+  CpuIoWrite32,\r
+  CpuIoWrite64,\r
+  CpuMemRead8,\r
+  CpuMemRead16,\r
+  CpuMemRead32,\r
+  CpuMemRead64,\r
+  CpuMemWrite8,\r
+  CpuMemWrite16,\r
+  CpuMemWrite32,\r
+  CpuMemWrite64\r
+};\r
+\r
+//\r
+// PPI Descriptor used to install the CPU I/O PPI\r
+//\r
+EFI_PEI_PPI_DESCRIPTOR gPpiList = {\r
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+  &gEfiPeiCpuIoPpiInstalledGuid,\r
+  NULL\r
+};\r
+  \r
+//\r
+// Lookup table for increment values based on transfer widths\r
+//\r
+UINT8 mInStride[] = {\r
+  1, // EfiPeiCpuIoWidthUint8\r
+  2, // EfiPeiCpuIoWidthUint16\r
+  4, // EfiPeiCpuIoWidthUint32\r
+  8, // EfiPeiCpuIoWidthUint64\r
+  0, // EfiPeiCpuIoWidthFifoUint8\r
+  0, // EfiPeiCpuIoWidthFifoUint16\r
+  0, // EfiPeiCpuIoWidthFifoUint32\r
+  0, // EfiPeiCpuIoWidthFifoUint64\r
+  1, // EfiPeiCpuIoWidthFillUint8\r
+  2, // EfiPeiCpuIoWidthFillUint16\r
+  4, // EfiPeiCpuIoWidthFillUint32\r
+  8  // EfiPeiCpuIoWidthFillUint64\r
+};\r
+\r
+//\r
+// Lookup table for increment values based on transfer widths\r
+//\r
+UINT8 mOutStride[] = {\r
+  1, // EfiPeiCpuIoWidthUint8\r
+  2, // EfiPeiCpuIoWidthUint16\r
+  4, // EfiPeiCpuIoWidthUint32\r
+  8, // EfiPeiCpuIoWidthUint64\r
+  1, // EfiPeiCpuIoWidthFifoUint8\r
+  2, // EfiPeiCpuIoWidthFifoUint16\r
+  4, // EfiPeiCpuIoWidthFifoUint32\r
+  8, // EfiPeiCpuIoWidthFifoUint64\r
+  0, // EfiPeiCpuIoWidthFillUint8\r
+  0, // EfiPeiCpuIoWidthFillUint16\r
+  0, // EfiPeiCpuIoWidthFillUint32\r
+  0  // EfiPeiCpuIoWidthFillUint64\r
+};\r
+\r
+/**\r
+  Check parameters to a CPU I/O PPI service request.\r
+\r
+  @param[in]  MmioOperation  TRUE for an MMIO operation, FALSE for I/O Port operation.\r
+  @param[in]  Width          The width of the access. Enumerated in bytes.\r
+  @param[in]  Address        The physical address of the access.\r
+  @param[in]  Count          The number of accesses to perform.\r
+  @param[in]  Buffer         A pointer to the buffer of data.\r
+\r
+  @retval EFI_SUCCESS            The parameters for this request pass the checks.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this EFI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width, \r
+                                 and Count is not valid for this EFI system.\r
+                                 \r
+**/\r
+EFI_STATUS\r
+CpuIoCheckParameter (\r
+  IN BOOLEAN                   MmioOperation,\r
+  IN EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN UINT64                    Address,\r
+  IN UINTN                     Count,\r
+  IN VOID                      *Buffer\r
+  )\r
+{\r
+  UINT64  MaxCount;\r
+  UINT64  Limit;\r
+\r
+  //\r
+  // Check to see if Buffer is NULL\r
+  //\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check to see if Width is in the valid range\r
+  //\r
+  if (Width < 0 || Width >= EfiPeiCpuIoWidthMaximum) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // For FIFO type, the target address won't increase during the access,\r
+  // so treat Count as 1\r
+  //\r
+  if (Width >= EfiPeiCpuIoWidthFifoUint8 && Width <= EfiPeiCpuIoWidthFifoUint64) {\r
+    Count = 1;\r
+  }\r
+\r
+  //\r
+  // Check to see if Width is in the valid range for I/O Port operations\r
+  //\r
+  Width = Width & 0x03;\r
+  if (!MmioOperation && (Width == EfiPeiCpuIoWidthUint64)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check to see if any address associated with this transfer exceeds the maximum \r
+  // allowed address.  The maximum address implied by the parameters passed in is\r
+  // Address + Size * Count.  If the following condition is met, then the transfer\r
+  // is not supported.\r
+  //\r
+  //    Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1\r
+  //\r
+  // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count \r
+  // can also be the maximum integer value supported by the CPU, this range\r
+  // check must be adjusted to avoid all oveflow conditions.\r
+  //   \r
+  // The follwing form of the range check is equivalent but assumes that \r
+  // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).\r
+  //\r
+  Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);\r
+  if (Count == 0) {\r
+    if (Address > Limit) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  } else {  \r
+    MaxCount = RShiftU64 (Limit, Width);\r
+    if (MaxCount < (Count - 1)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+    if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads memory-mapped registers.\r
+\r
+  @param[in]  PeiServices  An indirect pointer to the PEI Services Table\r
+                           published by the PEI Foundation.\r
+  @param[in]  This         Pointer to local data for the interface.\r
+  @param[in]  Width        The width of the access. Enumerated in bytes.\r
+  @param[in]  Address      The physical address of the access.\r
+  @param[in]  Count        The number of accesses to perform.\r
+  @param[out] Buffer       A pointer to the buffer of data.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this EFI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width, \r
+                                 and Count is not valid for this EFI system.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuMemoryServiceRead (\r
+  IN  CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN  EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN  UINT64                    Address,\r
+  IN  UINTN                     Count,\r
+  OUT VOID                      *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     InStride;\r
+  UINT8                     OutStride;\r
+  EFI_PEI_CPU_IO_PPI_WIDTH  OperationWidth;\r
+  BOOLEAN                   Aligned;\r
+  UINT8                     *Uint8Buffer;\r
+\r
+  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Select loop based on the width of the transfer\r
+  //\r
+  InStride = mInStride[Width];\r
+  OutStride = mOutStride[Width];\r
+  OperationWidth = Width & 0x03;\r
+  Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00);\r
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
+    if (OperationWidth == EfiPeiCpuIoWidthUint8) {\r
+      *Uint8Buffer = MmioRead8 ((UINTN)Address);\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint16) {\r
+      if (Aligned) {\r
+        *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);\r
+      } else {\r
+        WriteUnaligned16 ((UINT16 *)Uint8Buffer, MmioRead16 ((UINTN)Address));\r
+      }\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint32) {\r
+      if (Aligned) {\r
+        *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);\r
+      } else {\r
+        WriteUnaligned32 ((UINT32 *)Uint8Buffer, MmioRead32 ((UINTN)Address));\r
+      }\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint64) {\r
+      if (Aligned) {\r
+        *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);\r
+      } else {\r
+        WriteUnaligned64 ((UINT64 *)Uint8Buffer, MmioRead64 ((UINTN)Address));\r
+      }\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Writes memory-mapped registers.\r
+\r
+  @param[in]  PeiServices  An indirect pointer to the PEI Services Table\r
+                           published by the PEI Foundation.\r
+  @param[in]  This         Pointer to local data for the interface.\r
+  @param[in]  Width        The width of the access. Enumerated in bytes.\r
+  @param[in]  Address      The physical address of the access.\r
+  @param[in]  Count        The number of accesses to perform.\r
+  @param[in]  Buffer       A pointer to the buffer of data.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this EFI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width, \r
+                                 and Count is not valid for this EFI system.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuMemoryServiceWrite (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN UINT64                    Address,\r
+  IN UINTN                     Count,\r
+  IN VOID                      *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     InStride;\r
+  UINT8                     OutStride;\r
+  EFI_PEI_CPU_IO_PPI_WIDTH  OperationWidth;\r
+  BOOLEAN                   Aligned;\r
+  UINT8                     *Uint8Buffer;\r
+\r
+  Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Select loop based on the width of the transfer\r
+  //\r
+  InStride = mInStride[Width];\r
+  OutStride = mOutStride[Width];\r
+  OperationWidth = Width & 0x03;\r
+  Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00);\r
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
+    if (OperationWidth == EfiPeiCpuIoWidthUint8) {\r
+      MmioWrite8 ((UINTN)Address, *Uint8Buffer);\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint16) {\r
+      if (Aligned) {\r
+        MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));\r
+      } else {\r
+        MmioWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer));\r
+      }\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint32) {\r
+      if (Aligned) {\r
+        MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));\r
+      } else {\r
+        MmioWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer));\r
+      }\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint64) {\r
+      if (Aligned) {\r
+        MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));\r
+      } else {\r
+        MmioWrite64 ((UINTN)Address, ReadUnaligned64 ((UINT64 *)Uint8Buffer));\r
+      }\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads I/O registers.\r
+\r
+  @param[in]  PeiServices  An indirect pointer to the PEI Services Table\r
+                           published by the PEI Foundation.\r
+  @param[in]  This         Pointer to local data for the interface.\r
+  @param[in]  Width        The width of the access. Enumerated in bytes.\r
+  @param[in]  Address      The physical address of the access.\r
+  @param[in]  Count        The number of accesses to perform.\r
+  @param[out] Buffer       A pointer to the buffer of data.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this EFI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width, \r
+                                 and Count is not valid for this EFI system.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuIoServiceRead (\r
+  IN  CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN  CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN  EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN  UINT64                    Address,\r
+  IN  UINTN                     Count,\r
+  OUT VOID                      *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     InStride;\r
+  UINT8                     OutStride;\r
+  EFI_PEI_CPU_IO_PPI_WIDTH  OperationWidth;\r
+  BOOLEAN                   Aligned;\r
+  UINT8                     *Uint8Buffer;\r
+\r
+  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Select loop based on the width of the transfer\r
+  //\r
+  InStride = mInStride[Width];\r
+  OutStride = mOutStride[Width];\r
+  OperationWidth = Width & 0x03;\r
+  Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00);\r
+  for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
+    if (OperationWidth == EfiPeiCpuIoWidthUint8) {\r
+      *Uint8Buffer = IoRead8 ((UINTN)Address);\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint16) {\r
+      if (Aligned) {\r
+        *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address);\r
+      } else {\r
+        WriteUnaligned16 ((UINT16 *)Uint8Buffer, IoRead16 ((UINTN)Address));\r
+      }\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint32) {\r
+      if (Aligned) {\r
+        *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address);\r
+      } else {\r
+        WriteUnaligned32 ((UINT32 *)Uint8Buffer, IoRead32 ((UINTN)Address));\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Write I/O registers.\r
+\r
+  @param[in]  PeiServices  An indirect pointer to the PEI Services Table\r
+                           published by the PEI Foundation.\r
+  @param[in]  This         Pointer to local data for the interface.\r
+  @param[in]  Width        The width of the access. Enumerated in bytes.\r
+  @param[in]  Address      The physical address of the access.\r
+  @param[in]  Count        The number of accesses to perform.\r
+  @param[in]  Buffer       A pointer to the buffer of data.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Width is invalid for this EFI system.\r
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL.\r
+  @retval EFI_UNSUPPORTED        The address range specified by Address, Width, \r
+                                 and Count is not valid for this EFI system.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuIoServiceWrite (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN EFI_PEI_CPU_IO_PPI_WIDTH  Width,\r
+  IN UINT64                    Address,\r
+  IN UINTN                     Count,\r
+  IN VOID                      *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     InStride;\r
+  UINT8                     OutStride;\r
+  EFI_PEI_CPU_IO_PPI_WIDTH  OperationWidth;\r
+  BOOLEAN                   Aligned;\r
+  UINT8                     *Uint8Buffer;\r
+\r
+  //\r
+  // Make sure the parameters are valid\r
+  //\r
+  Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Select loop based on the width of the transfer\r
+  //\r
+  InStride = mInStride[Width];\r
+  OutStride = mOutStride[Width];\r
+  OperationWidth = Width & 0x03;\r
+  Aligned = (BOOLEAN)(((UINTN)Buffer & (mInStride[OperationWidth] - 1)) == 0x00);\r
+  for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {\r
+    if (OperationWidth == EfiPeiCpuIoWidthUint8) {\r
+      IoWrite8 ((UINTN)Address, *Uint8Buffer);\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint16) {\r
+      if (Aligned) {\r
+        IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));\r
+      } else {\r
+        IoWrite16 ((UINTN)Address, ReadUnaligned16 ((UINT16 *)Uint8Buffer));\r
+      }\r
+    } else if (OperationWidth == EfiPeiCpuIoWidthUint32) {\r
+      if (Aligned) {\r
+        IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));\r
+      } else {\r
+        IoWrite32 ((UINTN)Address, ReadUnaligned32 ((UINT32 *)Uint8Buffer));\r
+      }\r
+    }\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  8-bit I/O read operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+\r
+  @return  An 8-bit value returned from the I/O space.\r
+**/\r
+UINT8\r
+EFIAPI\r
+CpuIoRead8 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address\r
+  )\r
+{\r
+  return IoRead8 ((UINTN)Address);\r
+}\r
+\r
+/**\r
+  16-bit I/O read operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+\r
+  @return  A 16-bit value returned from the I/O space.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+CpuIoRead16 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address\r
+  )\r
+{\r
+  return IoRead16 ((UINTN)Address);\r
+}\r
+\r
+/**\r
+  32-bit I/O read operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+\r
+  @return  A 32-bit value returned from the I/O space.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+CpuIoRead32 (\r
+  IN CONST EFI_PEI_SERVICES     **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI   *This,\r
+  IN UINT64                     Address\r
+  )\r
+{\r
+  return IoRead32 ((UINTN)Address);\r
+}\r
+\r
+/**\r
+  64-bit I/O read operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+\r
+  @return  A 64-bit value returned from the I/O space.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+CpuIoRead64 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address\r
+  )\r
+{\r
+  return IoRead64 ((UINTN)Address);\r
+}\r
+\r
+/**\r
+  8-bit I/O write operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+  @param[in] Data         The data to write.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuIoWrite8 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address,\r
+  IN UINT8                     Data\r
+  )\r
+{\r
+  IoWrite8 ((UINTN)Address, Data);\r
+}\r
+\r
+/**\r
+  16-bit I/O write operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+  @param[in] Data         The data to write.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuIoWrite16 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address,\r
+  IN UINT16                    Data\r
+  )\r
+{\r
+  IoWrite16 ((UINTN)Address, Data);\r
+}\r
+\r
+/**\r
+  32-bit I/O write operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+  @param[in] Data         The data to write.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuIoWrite32 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address,\r
+  IN UINT32                    Data\r
+  )\r
+{\r
+  IoWrite32 ((UINTN)Address, Data);\r
+}\r
+\r
+/**\r
+  64-bit I/O write operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+  @param[in] Data         The data to write.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuIoWrite64 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address,\r
+  IN UINT64                    Data\r
+  )\r
+{\r
+  IoWrite64 ((UINTN)Address, Data);\r
+}\r
+\r
+/**\r
+  8-bit memory read operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+\r
+  @return  An 8-bit value returned from the memory space.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+CpuMemRead8 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address\r
+  )\r
+{\r
+  return MmioRead8 ((UINTN)Address);\r
+}\r
+\r
+/**\r
+  16-bit memory read operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+\r
+  @return  A 16-bit value returned from the memory space.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+CpuMemRead16 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address\r
+  )\r
+{\r
+  return MmioRead16 ((UINTN)Address);\r
+}\r
+\r
+/**\r
+  32-bit memory read operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+\r
+  @return  A 32-bit value returned from the memory space.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+CpuMemRead32 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address\r
+  )\r
+{\r
+  return MmioRead32 ((UINTN)Address);\r
+}\r
+\r
+/**\r
+  64-bit memory read operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+\r
+  @return  A 64-bit value returned from the memory space.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+CpuMemRead64 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address\r
+  )\r
+{\r
+  return MmioRead64 ((UINTN)Address);\r
+}\r
+\r
+/**\r
+  8-bit memory write operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+  @param[in] Data         The data to write.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuMemWrite8 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address,\r
+  IN  UINT8                    Data\r
+  )\r
+{\r
+  MmioWrite8 ((UINTN)Address, Data);\r
+}\r
+\r
+/**\r
+  16-bit memory write operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+  @param[in] Data         The data to write.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuMemWrite16 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address,\r
+  IN UINT16                    Data\r
+  )\r
+{\r
+  MmioWrite16 ((UINTN)Address, Data);\r
+}\r
+\r
+/**\r
+  32-bit memory write operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+  @param[in] Data         The data to write.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuMemWrite32 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address,\r
+  IN UINT32                    Data\r
+  )\r
+{\r
+  MmioWrite32 ((UINTN)Address, Data);\r
+}\r
+\r
+/**\r
+  64-bit memory write operations.\r
+\r
+  @param[in] PeiServices  An indirect pointer to the PEI Services Table published \r
+                          by the PEI Foundation.\r
+  @param[in] This         Pointer to local data for the interface.\r
+  @param[in] Address      The physical address of the access.\r
+  @param[in] Data         The data to write.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CpuMemWrite64 (\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices,\r
+  IN CONST EFI_PEI_CPU_IO_PPI  *This,\r
+  IN UINT64                    Address,\r
+  IN UINT64                    Data\r
+  )\r
+{\r
+  MmioWrite64 ((UINTN)Address, Data);\r
+}\r
+\r
+/**\r
+  The Entry point of the CPU I/O PEIM\r
+\r
+  This function is the Entry point of the CPU I/O PEIM which installs CpuIoPpi.\r
+\r
+  @param[in]  FileHandle   Pointer to image file handle.\r
+  @param[in]  PeiServices  Pointer to PEI Services Table   \r
+\r
+  @retval EFI_SUCCESS  CPU I/O PPI successfully installed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CpuIoInitialize (\r
+  IN EFI_PEI_FILE_HANDLE     FileHandle,\r
+  IN CONST EFI_PEI_SERVICES  **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Register so it will be automatically shadowed to memory\r
+  //\r
+  Status = PeiServicesRegisterForShadow (FileHandle);\r
+  \r
+  //\r
+  // Make CpuIo pointer in PeiService table point to gCpuIoPpi\r
+  //\r
+  (*((EFI_PEI_SERVICES **)PeiServices))->CpuIo = &gCpuIoPpi;\r
+  \r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    //\r
+    // Shadow completed and running from memory\r
+    //\r
+    DEBUG ((EFI_D_INFO, "CpuIO PPI has been loaded into memory.  Reinstalled PPI=0x%x\n", &gCpuIoPpi));\r
+  } else {\r
+    Status = PeiServicesInstallPpi (&gPpiList);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r