]> git.proxmox.com Git - mirror_edk2.git/commitdiff
PrmPkg: Add initial PrmSampleHardwareAccessModule
authorMichael Kubacki <michael.kubacki@microsoft.com>
Tue, 7 Apr 2020 18:31:15 +0000 (11:31 -0700)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Tue, 5 Apr 2022 00:42:38 +0000 (00:42 +0000)
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3812

Adds a sample PRM module that demonstrates:
  1. How to write a PRM module
  2. How to use multiple PRM handlers in a module
  3. How to use a basic PRM OS service
  4. MSR access at OS runtime

Note: This module contains a PRM handler to read from the HPET MMIO
      range but the memory map changes needed for this to succeed
      are currently not implemented. These will be implemented in a
      future change.

Cc: Andrew Fish <afish@apple.com>
Cc: Kang Gao <kang.gao@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Michael Kubacki <michael.kubacki@microsoft.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Benjamin You <benjamin.you@intel.com>
Cc: Liu Yun <yun.y.liu@intel.com>
Cc: Ankit Sinha <ankit.sinha@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
Acked-by: Michael D Kinney <michael.d.kinney@intel.com>
Acked-by: Liming Gao <gaoliming@byosoft.com.cn>
Acked-by: Leif Lindholm <quic_llindhol@quicinc.com>
Reviewed-by: Ankit Sinha <ankit.sinha@intel.com>
PrmPkg/Samples/PrmSampleHardwareAccessModule/Hpet.h [new file with mode: 0644]
PrmPkg/Samples/PrmSampleHardwareAccessModule/PrmSampleHardwareAccessModule.c [new file with mode: 0644]
PrmPkg/Samples/PrmSampleHardwareAccessModule/PrmSampleHardwareAccessModule.inf [new file with mode: 0644]

diff --git a/PrmPkg/Samples/PrmSampleHardwareAccessModule/Hpet.h b/PrmPkg/Samples/PrmSampleHardwareAccessModule/Hpet.h
new file mode 100644 (file)
index 0000000..c7eb0cb
--- /dev/null
@@ -0,0 +1,105 @@
+/** @file\r
+  HPET register definitions from the IA-PC HPET (High Precision Event Timers)\r
+  Specification, Revision 1.0a, October 2004.\r
+\r
+  PRM Module Note:\r
+  This specific header was copied from PcAtChipsetPkg to avoid a module dependency on the package\r
+  just for this header. This is done for temporary testing purposes of the PRM module.\r
+\r
+  Copyright (c) Microsoft Corporation\r
+  Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef HPET_REGISTER_H_\r
+#define HPET_REGISTER_H_\r
+\r
+///\r
+/// HPET General Register Offsets\r
+///\r
+#define HPET_GENERAL_CAPABILITIES_ID_OFFSET   0x000\r
+#define HPET_GENERAL_CONFIGURATION_OFFSET     0x010\r
+#define HPET_GENERAL_INTERRUPT_STATUS_OFFSET  0x020\r
+\r
+///\r
+/// HPET Timer Register Offsets\r
+///\r
+#define HPET_MAIN_COUNTER_OFFSET              0x0F0\r
+#define HPET_TIMER_CONFIGURATION_OFFSET       0x100\r
+#define HPET_TIMER_COMPARATOR_OFFSET          0x108\r
+#define HPET_TIMER_MSI_ROUTE_OFFSET           0x110\r
+\r
+///\r
+/// Stride between sets of HPET Timer Registers\r
+///\r
+#define HPET_TIMER_STRIDE         0x20\r
+\r
+#pragma pack(1)\r
+\r
+///\r
+/// HPET General Capabilities and ID Register\r
+///\r
+typedef union {\r
+  struct {\r
+    UINT32  Revision:8;\r
+    UINT32  NumberOfTimers:5;\r
+    UINT32  CounterSize:1;\r
+    UINT32  Reserved0:1;\r
+    UINT32  LegacyRoute:1;\r
+    UINT32  VendorId:16;\r
+    UINT32  CounterClockPeriod:32;\r
+  } Bits;\r
+  UINT64  Uint64;\r
+} HPET_GENERAL_CAPABILITIES_ID_REGISTER;\r
+\r
+///\r
+/// HPET General Configuration Register\r
+///\r
+typedef union {\r
+  struct {\r
+    UINT32  MainCounterEnable:1;\r
+    UINT32  LegacyRouteEnable:1;\r
+    UINT32  Reserved0:30;\r
+    UINT32  Reserved1:32;\r
+  } Bits;\r
+  UINT64  Uint64;\r
+} HPET_GENERAL_CONFIGURATION_REGISTER;\r
+\r
+///\r
+/// HPET Timer Configuration Register\r
+///\r
+typedef union {\r
+  struct {\r
+    UINT32  Reserved0:1;\r
+    UINT32  LevelTriggeredInterrupt:1;\r
+    UINT32  InterruptEnable:1;\r
+    UINT32  PeriodicInterruptEnable:1;\r
+    UINT32  PeriodicInterruptCapability:1;\r
+    UINT32  CounterSizeCapability:1;\r
+    UINT32  ValueSetEnable:1;\r
+    UINT32  Reserved1:1;\r
+    UINT32  CounterSizeEnable:1;\r
+    UINT32  InterruptRoute:5;\r
+    UINT32  MsiInterruptEnable:1;\r
+    UINT32  MsiInterruptCapability:1;\r
+    UINT32  Reserved2:16;\r
+    UINT32  InterruptRouteCapability;\r
+  } Bits;\r
+  UINT64  Uint64;\r
+} HPET_TIMER_CONFIGURATION_REGISTER;\r
+\r
+///\r
+/// HPET Timer MSI Route Register\r
+///\r
+typedef union {\r
+  struct {\r
+    UINT32  Value:32;\r
+    UINT32  Address:32;\r
+  } Bits;\r
+  UINT64  Uint64;\r
+} HPET_TIMER_MSI_ROUTE_REGISTER;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
diff --git a/PrmPkg/Samples/PrmSampleHardwareAccessModule/PrmSampleHardwareAccessModule.c b/PrmPkg/Samples/PrmSampleHardwareAccessModule/PrmSampleHardwareAccessModule.c
new file mode 100644 (file)
index 0000000..87fe9ca
--- /dev/null
@@ -0,0 +1,537 @@
+/** @file\r
+\r
+  A sample PRM Module implementation. This PRM Module provides PRM handlers that perform various types\r
+  of hardware access. This is simply meant to demonstrate hardware access capabilities from a PRM handler.\r
+\r
+  Copyright (c) Microsoft Corporation\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <PrmModule.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/MtrrLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <Register/Intel/ArchitecturalMsr.h>\r
+#include <Register/Intel/Cpuid.h>\r
+\r
+#include "Hpet.h"\r
+\r
+//\r
+// PRM Handler GUIDs\r
+//\r
+\r
+// {2120cd3c-848b-4d8f-abbb-4b74ce64ac89}\r
+#define MSR_ACCESS_MICROCODE_SIGNATURE_PRM_HANDLER_GUID {0x2120cd3c, 0x848b, 0x4d8f, {0xab, 0xbb, 0x4b, 0x74, 0xce, 0x64, 0xac, 0x89}}\r
+\r
+// {ea0935a7-506b-4159-bbbb-48deeecb6f58}\r
+#define MSR_ACCESS_MTRR_DUMP_PRM_HANDLER_GUID {0xea0935a7, 0x506b, 0x4159, {0xbb, 0xbb, 0x48, 0xde, 0xee, 0xcb, 0x6f, 0x58}}\r
+\r
+// {1bd1bda9-909a-4614-9699-25ec0c2783f7}\r
+#define MMIO_ACCESS_HPET_PRM_HANDLER_GUID {0x1bd1bda9, 0x909a, 0x4614, {0x96, 0x99, 0x25, 0xec, 0x0c, 0x27, 0x83, 0xf7}}\r
+\r
+#define HPET_BASE_ADDRESS 0xFED00000\r
+\r
+//\r
+// BEGIN: MtrrLib internal library globals and function prototypes here for testing\r
+//\r
+extern CONST CHAR8        *mMtrrMemoryCacheTypeShortName[];\r
+\r
+/**\r
+  Initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+  This function initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+  @param[out]  MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param[out]  MtrrValidAddressMask  The valid address mask for the MTRR\r
+\r
+**/\r
+VOID\r
+MtrrLibInitializeMtrrMask (\r
+  OUT UINT64 *MtrrValidBitsMask,\r
+  OUT UINT64 *MtrrValidAddressMask\r
+  );\r
+\r
+/**\r
+  Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.\r
+  One MTRR_MEMORY_RANGE element is created for each MTRR setting.\r
+  The routine doesn't remove the overlap or combine the near-by region.\r
+\r
+  @param[in]   VariableSettings      The variable MTRR values to shadow\r
+  @param[in]   VariableMtrrCount     The number of variable MTRRs\r
+  @param[in]   MtrrValidBitsMask     The mask for the valid bit of the MTRR\r
+  @param[in]   MtrrValidAddressMask  The valid address mask for MTRR\r
+  @param[out]  VariableMtrr          The array to shadow variable MTRRs content\r
+\r
+  @return      Number of MTRRs which has been used.\r
+\r
+**/\r
+UINT32\r
+MtrrLibGetRawVariableRanges (\r
+  IN  MTRR_VARIABLE_SETTINGS  *VariableSettings,\r
+  IN  UINTN                   VariableMtrrCount,\r
+  IN  UINT64                  MtrrValidBitsMask,\r
+  IN  UINT64                  MtrrValidAddressMask,\r
+  OUT MTRR_MEMORY_RANGE       *VariableMtrr\r
+  );\r
+\r
+/**\r
+  Apply the fixed MTRR settings to memory range array.\r
+\r
+  @param Fixed             The fixed MTRR settings.\r
+  @param Ranges            Return the memory range array holding memory type\r
+                           settings for all memory address.\r
+  @param RangeCapacity     The capacity of memory range array.\r
+  @param RangeCount        Return the count of memory range.\r
+\r
+  @retval RETURN_SUCCESS          The memory range array is returned successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibApplyFixedMtrrs (\r
+  IN     MTRR_FIXED_SETTINGS  *Fixed,\r
+  IN OUT MTRR_MEMORY_RANGE    *Ranges,\r
+  IN     UINTN                RangeCapacity,\r
+  IN OUT UINTN                *RangeCount\r
+  );\r
+\r
+/**\r
+  Apply the variable MTRR settings to memory range array.\r
+\r
+  @param VariableMtrr      The variable MTRR array.\r
+  @param VariableMtrrCount The count of variable MTRRs.\r
+  @param Ranges            Return the memory range array with new MTRR settings applied.\r
+  @param RangeCapacity     The capacity of memory range array.\r
+  @param RangeCount        Return the count of memory range.\r
+\r
+  @retval RETURN_SUCCESS          The memory range array is returned successfully.\r
+  @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.\r
+**/\r
+RETURN_STATUS\r
+MtrrLibApplyVariableMtrrs (\r
+  IN     CONST MTRR_MEMORY_RANGE *VariableMtrr,\r
+  IN     UINT32                  VariableMtrrCount,\r
+  IN OUT MTRR_MEMORY_RANGE       *Ranges,\r
+  IN     UINTN                   RangeCapacity,\r
+  IN OUT UINTN                   *RangeCount\r
+  );\r
+\r
+//\r
+// END: MtrrLib internal library function prototypes here for testing\r
+//\r
+\r
+/**\r
+  Prints all MTRR values including architectural and variable MTTRs.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PrintAllMtrrs (\r
+  IN PRM_OS_SERVICE_DEBUG_PRINT   OsServiceDebugPrint\r
+  )\r
+{\r
+  MTRR_SETTINGS                   LocalMtrrs;\r
+  MTRR_SETTINGS                   *Mtrrs;\r
+  UINTN                           Index;\r
+  UINTN                           RangeCount;\r
+  UINT64                          MtrrValidBitsMask;\r
+  UINT64                          MtrrValidAddressMask;\r
+  UINT32                          VariableMtrrCount;\r
+  BOOLEAN                         ContainVariableMtrr;\r
+  CHAR8                           DebugMessage[256];\r
+\r
+  MTRR_MEMORY_RANGE Ranges[\r
+    MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1\r
+    ];\r
+  MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];\r
+\r
+  if (OsServiceDebugPrint == NULL || !IsMtrrSupported ()) {\r
+    return;\r
+  }\r
+\r
+  VariableMtrrCount = GetVariableMtrrCount ();\r
+\r
+  MtrrGetAllMtrrs (&LocalMtrrs);\r
+  Mtrrs = &LocalMtrrs;\r
+\r
+  //\r
+  // Dump RAW MTRR contents\r
+  //\r
+  OsServiceDebugPrint ("  MTRR Settings:\n");\r
+  OsServiceDebugPrint ("  =============\n");\r
+\r
+  AsciiSPrint (\r
+    &DebugMessage[0],\r
+    ARRAY_SIZE (DebugMessage),\r
+    "  MTRR Default Type: %016lx\n",\r
+    Mtrrs->MtrrDefType\r
+    );\r
+  OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+  for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+    AsciiSPrint (\r
+      &DebugMessage[0],\r
+      ARRAY_SIZE (DebugMessage),\r
+      "  Fixed MTRR[%02d]   : %016lx\n",\r
+      Index,\r
+      Mtrrs->Fixed.Mtrr[Index]\r
+      );\r
+    OsServiceDebugPrint (&DebugMessage[0]);\r
+  }\r
+  ContainVariableMtrr = FALSE;\r
+  for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+    if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
+      //\r
+      // If mask is not valid, then do not display range\r
+      //\r
+      continue;\r
+    }\r
+    ContainVariableMtrr = TRUE;\r
+    AsciiSPrint (\r
+      &DebugMessage[0],\r
+      ARRAY_SIZE (DebugMessage),\r
+      "  Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
+      Index,\r
+      Mtrrs->Variables.Mtrr[Index].Base,\r
+      Mtrrs->Variables.Mtrr[Index].Mask\r
+      );\r
+    OsServiceDebugPrint (&DebugMessage[0]);\r
+  }\r
+  if (!ContainVariableMtrr) {\r
+    OsServiceDebugPrint ("  Variable MTRR    : None.\n");\r
+  }\r
+  OsServiceDebugPrint ("\n");\r
+\r
+  //\r
+  // Dump MTRR setting in ranges\r
+  //\r
+  OsServiceDebugPrint ("  Memory Ranges:\n");\r
+  OsServiceDebugPrint ("  ====================================\n");\r
+  MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+  Ranges[0].BaseAddress = 0;\r
+  Ranges[0].Length      = MtrrValidBitsMask + 1;\r
+  Ranges[0].Type        = MtrrGetDefaultMemoryType ();\r
+  RangeCount = 1;\r
+\r
+  MtrrLibGetRawVariableRanges (\r
+    &Mtrrs->Variables, VariableMtrrCount,\r
+    MtrrValidBitsMask, MtrrValidAddressMask, RawVariableRanges\r
+    );\r
+  MtrrLibApplyVariableMtrrs (\r
+    RawVariableRanges, VariableMtrrCount,\r
+    Ranges, ARRAY_SIZE (Ranges), &RangeCount\r
+    );\r
+\r
+  MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, Ranges, ARRAY_SIZE (Ranges), &RangeCount);\r
+\r
+  for (Index = 0; Index < RangeCount; Index++) {\r
+    AsciiSPrint (\r
+      &DebugMessage[0],\r
+      ARRAY_SIZE (DebugMessage),\r
+      "  %a:%016lx-%016lx\n",\r
+      mMtrrMemoryCacheTypeShortName[Ranges[Index].Type],\r
+      Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length - 1\r
+      );\r
+    OsServiceDebugPrint (&DebugMessage[0]);\r
+  }\r
+}\r
+\r
+/**\r
+  Reads a HPET MMIO register.\r
+\r
+  Reads the 64-bit HPET MMIO register specified by Address.\r
+\r
+  This function must guarantee that all MMIO read and write\r
+  operations are serialized.\r
+\r
+  If Address is not aligned on a 64-bit boundary, zero will be returned.\r
+\r
+  @param  Offset                  Specifies the offset of the HPET register to read.\r
+\r
+  @return                         The value read.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+HpetRead (\r
+  IN  UINTN                       Offset\r
+  )\r
+{\r
+  UINTN                           Address;\r
+  UINT64                          Value;\r
+\r
+  Address = HPET_BASE_ADDRESS + Offset;\r
+\r
+  if ((Address & 7) == 0) {\r
+    return 0;\r
+  }\r
+\r
+  MemoryFence ();\r
+  Value = *(volatile UINT64*)Address;\r
+  MemoryFence ();\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Prints HPET configuration information.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PrintHpetConfiguration (\r
+  IN PRM_OS_SERVICE_DEBUG_PRINT           OsServiceDebugPrint\r
+  )\r
+{\r
+  UINTN                                   TimerIndex;\r
+  HPET_GENERAL_CAPABILITIES_ID_REGISTER   HpetGeneralCapabilities;\r
+  HPET_GENERAL_CONFIGURATION_REGISTER     HpetGeneralConfiguration;\r
+  CHAR8                                   DebugMessage[256];\r
+\r
+  if (OsServiceDebugPrint == NULL) {\r
+    return;\r
+  }\r
+\r
+  HpetGeneralCapabilities.Uint64  = HpetRead (HPET_GENERAL_CAPABILITIES_ID_OFFSET);\r
+  HpetGeneralConfiguration.Uint64 = HpetRead (HPET_GENERAL_CONFIGURATION_OFFSET);\r
+\r
+  AsciiSPrint (\r
+    &DebugMessage[0],\r
+    ARRAY_SIZE (DebugMessage),\r
+    "  HPET Base Address = 0x%08x\n",\r
+    HPET_BASE_ADDRESS\r
+    );\r
+  OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+  AsciiSPrint (\r
+    &DebugMessage[0],\r
+    ARRAY_SIZE (DebugMessage),\r
+    "  HPET_GENERAL_CAPABILITIES_ID  = 0x%016lx\n",\r
+    HpetGeneralCapabilities\r
+    );\r
+  OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+  AsciiSPrint (\r
+    &DebugMessage[0],\r
+    ARRAY_SIZE (DebugMessage),\r
+    "  HPET_GENERAL_CONFIGURATION    = 0x%016lx\n",\r
+    HpetGeneralConfiguration.Uint64\r
+    );\r
+  OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+  AsciiSPrint (\r
+    &DebugMessage[0],\r
+    ARRAY_SIZE (DebugMessage),\r
+    "  HPET_GENERAL_INTERRUPT_STATUS = 0x%016lx\n",\r
+    HpetRead (HPET_GENERAL_INTERRUPT_STATUS_OFFSET)\r
+    );\r
+  OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+  AsciiSPrint (\r
+    &DebugMessage[0],\r
+    ARRAY_SIZE (DebugMessage),\r
+    "  HPET_MAIN_COUNTER             = 0x%016lx\n",\r
+    HpetRead (HPET_MAIN_COUNTER_OFFSET)\r
+    );\r
+  OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+  AsciiSPrint (\r
+    &DebugMessage[0],\r
+    ARRAY_SIZE (DebugMessage),\r
+    "  HPET Main Counter Period      = %d (fs)\n",\r
+    HpetGeneralCapabilities.Bits.CounterClockPeriod\r
+    );\r
+  OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+  for (TimerIndex = 0; TimerIndex <= HpetGeneralCapabilities.Bits.NumberOfTimers; TimerIndex++) {\r
+    AsciiSPrint (\r
+      &DebugMessage[0],\r
+      ARRAY_SIZE (DebugMessage),\r
+      "  HPET_TIMER%d_CONFIGURATION     = 0x%016lx\n",\r
+      TimerIndex,\r
+      HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + TimerIndex * HPET_TIMER_STRIDE)\r
+      );\r
+    OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+    AsciiSPrint (\r
+      &DebugMessage[0],\r
+      ARRAY_SIZE (DebugMessage),\r
+      "  HPET_TIMER%d_COMPARATOR        = 0x%016lx\n",\r
+      TimerIndex,\r
+      HpetRead (HPET_TIMER_COMPARATOR_OFFSET    + TimerIndex * HPET_TIMER_STRIDE)\r
+      );\r
+    OsServiceDebugPrint (&DebugMessage[0]);\r
+\r
+    AsciiSPrint (\r
+      &DebugMessage[0],\r
+      ARRAY_SIZE (DebugMessage),\r
+      "  HPET_TIMER%d_MSI_ROUTE         = 0x%016lx\n",\r
+      TimerIndex,\r
+      HpetRead (HPET_TIMER_MSI_ROUTE_OFFSET     + TimerIndex * HPET_TIMER_STRIDE)\r
+      );\r
+    OsServiceDebugPrint (&DebugMessage[0]);\r
+  }\r
+}\r
+\r
+/**\r
+  Prints the microcode update signature as read from architectural MSR 0x8B.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PrintMicrocodeUpdateSignature (\r
+  IN PRM_OS_SERVICE_DEBUG_PRINT   OsServiceDebugPrint\r
+  )\r
+{\r
+  MSR_IA32_BIOS_SIGN_ID_REGISTER  BiosSignIdMsr;\r
+  CHAR8                           DebugMessage[256];\r
+\r
+  if (OsServiceDebugPrint == NULL) {\r
+    return;\r
+  }\r
+\r
+  AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);\r
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
+  BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);\r
+\r
+  AsciiSPrint (\r
+    &DebugMessage[0],\r
+    ARRAY_SIZE (DebugMessage),\r
+    "  Signature read = 0x%x.\n",\r
+    BiosSignIdMsr.Bits.MicrocodeUpdateSignature\r
+    );\r
+  OsServiceDebugPrint (&DebugMessage[0]);\r
+}\r
+\r
+/**\r
+  A sample Platform Runtime Mechanism (PRM) handler.\r
+\r
+  This sample handler attempts to read the microcode update signature MSR and print the result to a debug message.\r
+\r
+  @param[in]  ParameterBuffer     A pointer to the PRM handler parameter buffer\r
+  @param[in]  ContextBUffer       A pointer to the PRM handler context buffer\r
+\r
+  @retval EFI_STATUS              The PRM handler executed successfully.\r
+  @retval Others                  An error occurred in the PRM handler.\r
+\r
+**/\r
+PRM_HANDLER_EXPORT (MsrAccessMicrocodeSignaturePrmHandler)\r
+{\r
+  PRM_OS_SERVICE_DEBUG_PRINT      OsServiceDebugPrint;\r
+\r
+  if (ParameterBuffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // In the POC, the OS debug print service is assumed to be at the beginning of ParameterBuffer\r
+  OsServiceDebugPrint = *((PRM_OS_SERVICE_DEBUG_PRINT *) ParameterBuffer);\r
+  if (OsServiceDebugPrint == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OsServiceDebugPrint ("Hardware Access MsrAccessMicrocodeSignaturePrmHandler entry.\n");\r
+  OsServiceDebugPrint ("  Attempting to read the Microcode Update Signature MSR (0x8B)...\n");\r
+  PrintMicrocodeUpdateSignature (OsServiceDebugPrint);\r
+  OsServiceDebugPrint ("Hardware Access MsrAccessMicrocodeSignaturePrmHandler exit.\n");\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  A sample Platform Runtime Mechanism (PRM) handler.\r
+\r
+  This sample handler attempts to read the current MTRR settings and print the result to a debug message.\r
+\r
+  @param[in]  ParameterBuffer     A pointer to the PRM handler parameter buffer\r
+  @param[in]  ContextBUffer       A pointer to the PRM handler context buffer\r
+\r
+  @retval EFI_STATUS              The PRM handler executed successfully.\r
+  @retval Others                  An error occurred in the PRM handler.\r
+\r
+**/\r
+PRM_HANDLER_EXPORT (MsrAccessMtrrDumpPrmHandler)\r
+{\r
+  PRM_OS_SERVICE_DEBUG_PRINT      OsServiceDebugPrint;\r
+\r
+  if (ParameterBuffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // In the POC, the OS debug print service is assumed to be at the beginning of ParameterBuffer\r
+  OsServiceDebugPrint = *((PRM_OS_SERVICE_DEBUG_PRINT *) ParameterBuffer);\r
+  if (OsServiceDebugPrint == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OsServiceDebugPrint ("Hardware Access MsrAccessMtrrDumpPrmHandler entry.\n");\r
+  OsServiceDebugPrint ("  Attempting to dump MTRR values:\n");\r
+  PrintAllMtrrs (OsServiceDebugPrint);\r
+  OsServiceDebugPrint ("Hardware Access MsrAccessMtrrDumpPrmHandler exit.\n");\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  A sample Platform Runtime Mechanism (PRM) handler.\r
+\r
+  This sample handler attempts to read from a HPET MMIO resource and print the result to a debug message.\r
+\r
+  @param[in]  ParameterBuffer     A pointer to the PRM handler parameter buffer\r
+  @param[in]  ContextBUffer       A pointer to the PRM handler context buffer\r
+\r
+  @retval EFI_STATUS              The PRM handler executed successfully.\r
+  @retval Others                  An error occurred in the PRM handler.\r
+\r
+**/\r
+PRM_HANDLER_EXPORT (MmioAccessHpetPrmHandler)\r
+{\r
+  PRM_OS_SERVICE_DEBUG_PRINT      OsServiceDebugPrint;\r
+\r
+  if (ParameterBuffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // In the POC, the OS debug print service is assumed to be at the beginning of ParameterBuffer\r
+  OsServiceDebugPrint = *((PRM_OS_SERVICE_DEBUG_PRINT *) ParameterBuffer);\r
+  if (OsServiceDebugPrint == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OsServiceDebugPrint ("Hardware Access MmioAccessHpetPrmHandler entry.\n");\r
+  OsServiceDebugPrint ("  Attempting to read HPET configuration...\n");\r
+  PrintHpetConfiguration (OsServiceDebugPrint);\r
+  OsServiceDebugPrint ("Hardware Access MmioAccessHpetPrmHandler exit.\n");\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+//\r
+// Register the PRM export information for this PRM Module\r
+//\r
+PRM_MODULE_EXPORT (\r
+  PRM_HANDLER_EXPORT_ENTRY (MSR_ACCESS_MICROCODE_SIGNATURE_PRM_HANDLER_GUID, MsrAccessMicrocodeSignaturePrmHandler),\r
+  PRM_HANDLER_EXPORT_ENTRY (MSR_ACCESS_MTRR_DUMP_PRM_HANDLER_GUID, MsrAccessMtrrDumpPrmHandler),\r
+  PRM_HANDLER_EXPORT_ENTRY (MMIO_ACCESS_HPET_PRM_HANDLER_GUID, MmioAccessHpetPrmHandler)\r
+  );\r
+\r
+/**\r
+  Module entry point.\r
+\r
+  @param[in]   ImageHandle     The image handle.\r
+  @param[in]   SystemTable     A pointer to the system table.\r
+\r
+  @retval  EFI_SUCCESS         This function always returns success.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PrmSampleHardwareAccessModuleInit (\r
+  IN  EFI_HANDLE                  ImageHandle,\r
+  IN  EFI_SYSTEM_TABLE            *SystemTable\r
+  )\r
+{\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/PrmPkg/Samples/PrmSampleHardwareAccessModule/PrmSampleHardwareAccessModule.inf b/PrmPkg/Samples/PrmSampleHardwareAccessModule/PrmSampleHardwareAccessModule.inf
new file mode 100644 (file)
index 0000000..302183c
--- /dev/null
@@ -0,0 +1,42 @@
+## @file\r
+#  Sample PRM Driver\r
+#\r
+#  A sample PRM Module implementation. This PRM Module provides PRM handlers that perform various types\r
+#  of hardware access. This is simply meant to demonstrate hardware access capabilities from a PRM handler.\r
+#\r
+#  Copyright (c) Microsoft Corporation\r
+#\r
+#  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PrmSampleHardwareAccessModule\r
+  FILE_GUID                      = 0EF93ED7-14AE-425B-928F-B85A6213B57E\r
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = PrmSampleHardwareAccessModuleInit\r
+\r
+[Sources]\r
+  Hpet.h\r
+  PrmSampleHardwareAccessModule.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  UefiCpuPkg/UefiCpuPkg.dec\r
+  PrmPkg/PrmPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  MtrrLib\r
+  PrintLib\r
+  UefiDriverEntryPoint\r
+  UefiLib\r
+\r
+[Depex]\r
+  TRUE\r
+\r
+[BuildOptions.common]\r
+  MSFT:*_*_*_DLINK_FLAGS  = /DLL /SUBSYSTEM:CONSOLE /VERSION:1.0\r