--- /dev/null
+/** @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