]> git.proxmox.com Git - mirror_edk2.git/blame - PrmPkg/PrmLoaderDxe/PrmLoaderDxe.c
PrmPkg: Add PlatformGuid
[mirror_edk2.git] / PrmPkg / PrmLoaderDxe / PrmLoaderDxe.c
CommitLineData
3f7af17c
MK
1/** @file\r
2\r
3 This file contains the implementation for a Platform Runtime Mechanism (PRM)\r
4 loader driver.\r
5\r
ef059559 6 Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
3f7af17c
MK
7 Copyright (c) Microsoft Corporation\r
8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
9\r
10**/\r
11\r
12#include "PrmAcpiTable.h"\r
3f7af17c 13\r
c040831c 14#include <Guid/ZeroGuid.h>\r
3f7af17c
MK
15#include <IndustryStandard/Acpi.h>\r
16#include <Library/BaseLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/DebugLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/PrmContextBufferLib.h>\r
6b7dde7c
MK
21#include <Library/PrmModuleDiscoveryLib.h>\r
22#include <Library/PrmPeCoffLib.h>\r
3f7af17c
MK
23#include <Library/UefiBootServicesTableLib.h>\r
24#include <Library/UefiLib.h>\r
25#include <Protocol/AcpiTable.h>\r
3f7af17c
MK
26#include <Protocol/PrmConfig.h>\r
27\r
28#include <PrmContextBuffer.h>\r
29#include <PrmMmio.h>\r
3f7af17c 30\r
6b7dde7c 31#define _DBGMSGID_ "[PRMLOADER]"\r
3f7af17c 32\r
6b7dde7c
MK
33UINTN mPrmHandlerCount;\r
34UINTN mPrmModuleCount;\r
3f7af17c
MK
35\r
36/**\r
37 Processes a list of PRM context entries to build a PRM ACPI table.\r
38\r
39 The ACPI table buffer is allocated and the table structure is built inside this function.\r
40\r
41 @param[out] PrmAcpiDescriptionTable A pointer to a pointer to a buffer that is allocated within this function\r
42 and will contain the PRM ACPI table. In case of an error in this function,\r
43 *PrmAcpiDescriptorTable will be NULL.\r
44\r
45 @retval EFI_SUCCESS All PRM Modules were processed to construct the PRM ACPI table successfully.\r
46 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL.\r
47 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table boot services\r
48 memory data buffer.\r
49\r
50**/\r
51EFI_STATUS\r
52ProcessPrmModules (\r
53 OUT PRM_ACPI_DESCRIPTION_TABLE **PrmAcpiDescriptionTable\r
54 )\r
55{\r
c040831c 56 EFI_GUID *PlatformGuid;\r
3f7af17c
MK
57 EFI_IMAGE_EXPORT_DIRECTORY *CurrentImageExportDirectory;\r
58 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *CurrentExportDescriptorStruct;\r
3f7af17c 59 PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiTable;\r
6b7dde7c 60 PRM_MODULE_IMAGE_CONTEXT *CurrentPrmModuleImageContext;\r
3f7af17c
MK
61 CONST CHAR8 *CurrentExportDescriptorHandlerName;\r
62\r
be2c927d 63 ACPI_PARAMETER_BUFFER_DESCRIPTOR *CurrentModuleAcpiParamDescriptors;\r
3f7af17c
MK
64 PRM_CONTEXT_BUFFER *CurrentContextBuffer;\r
65 PRM_MODULE_CONTEXT_BUFFERS *CurrentModuleContextBuffers;\r
66 PRM_MODULE_INFORMATION_STRUCT *CurrentModuleInfoStruct;\r
67 PRM_HANDLER_INFORMATION_STRUCT *CurrentHandlerInfoStruct;\r
68\r
69 EFI_STATUS Status;\r
70 EFI_PHYSICAL_ADDRESS CurrentImageAddress;\r
be2c927d 71 UINTN AcpiParamIndex;\r
3f7af17c
MK
72 UINTN HandlerIndex;\r
73 UINT32 PrmAcpiDescriptionTableBufferSize;\r
74\r
75 UINT64 HandlerPhysicalAddress;\r
76\r
77 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
78\r
79 if (PrmAcpiDescriptionTable == NULL) {\r
80 return EFI_INVALID_PARAMETER;\r
81 }\r
3f7af17c
MK
82 *PrmAcpiDescriptionTable = NULL;\r
83\r
c040831c
MK
84 PlatformGuid = (EFI_GUID *) PcdGetPtr (PcdPrmPlatformGuid);\r
85 //\r
86 // The platform should set PcdPrmPlatformGuid to a non-zero value\r
87 //\r
88 if (CompareGuid (PlatformGuid, &gZeroGuid)) {\r
89 DEBUG ((\r
90 DEBUG_ERROR,\r
91 " %a %a: PcdPrmPlatformGuid must be set to a unique value in the platform DSC file.\n",\r
92 _DBGMSGID_,\r
93 __FUNCTION__\r
94 ));\r
95 ASSERT (!CompareGuid (PlatformGuid, &gZeroGuid));\r
96 }\r
97\r
3f7af17c
MK
98 DEBUG ((DEBUG_INFO, " %a %a: %d total PRM modules to process.\n", _DBGMSGID_, __FUNCTION__, mPrmModuleCount));\r
99 DEBUG ((DEBUG_INFO, " %a %a: %d total PRM handlers to process.\n", _DBGMSGID_, __FUNCTION__, mPrmHandlerCount));\r
100\r
6b7dde7c 101 PrmAcpiDescriptionTableBufferSize = (UINT32) (OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure) +\r
3f7af17c
MK
102 (OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) * mPrmModuleCount) +\r
103 (sizeof (PRM_HANDLER_INFORMATION_STRUCT) * mPrmHandlerCount)\r
104 );\r
105 DEBUG ((DEBUG_INFO, " %a %a: Total PRM ACPI table size: 0x%x.\n", _DBGMSGID_, __FUNCTION__, PrmAcpiDescriptionTableBufferSize));\r
106\r
107 PrmAcpiTable = AllocateZeroPool ((UINTN) PrmAcpiDescriptionTableBufferSize);\r
108 if (PrmAcpiTable == NULL) {\r
109 return EFI_OUT_OF_RESOURCES;\r
110 }\r
111\r
112 PrmAcpiTable->Header.Signature = PRM_TABLE_SIGNATURE;\r
113 PrmAcpiTable->Header.Length = PrmAcpiDescriptionTableBufferSize;\r
114 PrmAcpiTable->Header.Revision = PRM_TABLE_REVISION;\r
115 PrmAcpiTable->Header.Checksum = 0x0;\r
116 CopyMem (&PrmAcpiTable->Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (PrmAcpiTable->Header.OemId));\r
117 PrmAcpiTable->Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
118 PrmAcpiTable->Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
119 PrmAcpiTable->Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
120 PrmAcpiTable->Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
c040831c 121 CopyGuid (&PrmAcpiTable->PrmPlatformGuid, PlatformGuid);\r
3f7af17c 122 PrmAcpiTable->PrmModuleInfoOffset = OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure);\r
6b7dde7c 123 PrmAcpiTable->PrmModuleInfoCount = (UINT32) mPrmModuleCount;\r
3f7af17c
MK
124\r
125 //\r
126 // Iterate across all PRM Modules on the list\r
127 //\r
128 CurrentModuleInfoStruct = &PrmAcpiTable->PrmModuleInfoStructure[0];\r
6b7dde7c
MK
129 for (\r
130 CurrentPrmModuleImageContext = NULL, Status = GetNextPrmModuleEntry (&CurrentPrmModuleImageContext);\r
131 !EFI_ERROR (Status);\r
132 Status = GetNextPrmModuleEntry (&CurrentPrmModuleImageContext)) {\r
133\r
134 CurrentImageAddress = CurrentPrmModuleImageContext->PeCoffImageContext.ImageAddress;\r
135 CurrentImageExportDirectory = CurrentPrmModuleImageContext->ExportDirectory;\r
136 CurrentExportDescriptorStruct = CurrentPrmModuleImageContext->ExportDescriptor;\r
be2c927d 137 CurrentModuleAcpiParamDescriptors = NULL;\r
3f7af17c
MK
138\r
139 DEBUG ((\r
140 DEBUG_INFO,\r
141 " %a %a: PRM Module - %a with %d handlers.\n",\r
142 _DBGMSGID_,\r
143 __FUNCTION__,\r
144 (CHAR8 *) ((UINTN) CurrentImageAddress + CurrentImageExportDirectory->Name),\r
a6f8946b 145 CurrentExportDescriptorStruct->Header.NumberPrmHandlers\r
3f7af17c
MK
146 ));\r
147\r
148 CurrentModuleInfoStruct->StructureRevision = PRM_MODULE_INFORMATION_STRUCT_REVISION;\r
149 CurrentModuleInfoStruct->StructureLength = (\r
150 OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) +\r
a6f8946b 151 (CurrentExportDescriptorStruct->Header.NumberPrmHandlers * sizeof (PRM_HANDLER_INFORMATION_STRUCT))\r
3f7af17c 152 );\r
a6f8946b
MK
153 CopyGuid (&CurrentModuleInfoStruct->Identifier, &CurrentExportDescriptorStruct->Header.ModuleGuid);\r
154 CurrentModuleInfoStruct->HandlerCount = (UINT32) CurrentExportDescriptorStruct->Header.NumberPrmHandlers;\r
3f7af17c
MK
155 CurrentModuleInfoStruct->HandlerInfoOffset = OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure);\r
156\r
157 CurrentModuleInfoStruct->MajorRevision = 0;\r
158 CurrentModuleInfoStruct->MinorRevision = 0;\r
159 Status = GetImageVersionInPeCoffImage (\r
160 (VOID *) (UINTN) CurrentImageAddress,\r
6b7dde7c 161 &CurrentPrmModuleImageContext->PeCoffImageContext,\r
3f7af17c
MK
162 &CurrentModuleInfoStruct->MajorRevision,\r
163 &CurrentModuleInfoStruct->MinorRevision\r
164 );\r
165 ASSERT_EFI_ERROR (Status);\r
166\r
3f7af17c
MK
167 // It is currently valid for a PRM module not to use a context buffer\r
168 Status = GetModuleContextBuffers (\r
169 ByModuleGuid,\r
170 &CurrentModuleInfoStruct->Identifier,\r
e10c7764 171 (CONST PRM_MODULE_CONTEXT_BUFFERS **) &CurrentModuleContextBuffers\r
3f7af17c
MK
172 );\r
173 ASSERT (!EFI_ERROR (Status) || Status == EFI_NOT_FOUND);\r
174 if (!EFI_ERROR (Status) && CurrentModuleContextBuffers != NULL) {\r
175 CurrentModuleInfoStruct->RuntimeMmioRanges = (UINT64) (UINTN) CurrentModuleContextBuffers->RuntimeMmioRanges;\r
be2c927d 176 CurrentModuleAcpiParamDescriptors = CurrentModuleContextBuffers->AcpiParameterBufferDescriptors;\r
3f7af17c
MK
177 }\r
178\r
179 //\r
180 // Iterate across all PRM handlers in the PRM Module\r
181 //\r
a6f8946b 182 for (HandlerIndex = 0; HandlerIndex < CurrentExportDescriptorStruct->Header.NumberPrmHandlers; HandlerIndex++) {\r
3f7af17c
MK
183 CurrentHandlerInfoStruct = &(CurrentModuleInfoStruct->HandlerInfoStructure[HandlerIndex]);\r
184\r
185 CurrentHandlerInfoStruct->StructureRevision = PRM_HANDLER_INFORMATION_STRUCT_REVISION;\r
186 CurrentHandlerInfoStruct->StructureLength = sizeof (PRM_HANDLER_INFORMATION_STRUCT);\r
187 CopyGuid (\r
188 &CurrentHandlerInfoStruct->Identifier,\r
189 &CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerGuid\r
190 );\r
191\r
192 CurrentExportDescriptorHandlerName = (CONST CHAR8 *) CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerName;\r
193\r
194 Status = GetContextBuffer (\r
195 &CurrentHandlerInfoStruct->Identifier,\r
196 CurrentModuleContextBuffers,\r
e10c7764 197 (CONST PRM_CONTEXT_BUFFER **) &CurrentContextBuffer\r
3f7af17c
MK
198 );\r
199 if (!EFI_ERROR (Status)) {\r
e8467976 200 CurrentHandlerInfoStruct->StaticDataBuffer = (UINT64) (UINTN) CurrentContextBuffer->StaticDataBuffer;\r
3f7af17c
MK
201 }\r
202\r
203 Status = GetExportEntryAddress (\r
204 CurrentExportDescriptorHandlerName,\r
205 CurrentImageAddress,\r
206 CurrentImageExportDirectory,\r
207 &HandlerPhysicalAddress\r
208 );\r
209 ASSERT_EFI_ERROR (Status);\r
210 if (!EFI_ERROR (Status)) {\r
211 CurrentHandlerInfoStruct->PhysicalAddress = HandlerPhysicalAddress;\r
212 DEBUG ((\r
213 DEBUG_INFO,\r
214 " %a %a: Found %a handler physical address at 0x%016x.\n",\r
215 _DBGMSGID_,\r
216 __FUNCTION__,\r
217 CurrentExportDescriptorHandlerName,\r
218 CurrentHandlerInfoStruct->PhysicalAddress\r
219 ));\r
220 }\r
be2c927d
MK
221\r
222 //\r
223 // Update the handler ACPI parameter buffer address if applicable\r
224 //\r
225 if (CurrentModuleAcpiParamDescriptors != NULL) {\r
226 for (AcpiParamIndex = 0; AcpiParamIndex < CurrentModuleContextBuffers->AcpiParameterBufferDescriptorCount; AcpiParamIndex++) {\r
227 if (CompareGuid (&CurrentModuleAcpiParamDescriptors[AcpiParamIndex].HandlerGuid, &CurrentHandlerInfoStruct->Identifier)) {\r
228 CurrentHandlerInfoStruct->AcpiParameterBuffer = (UINT64) (UINTN) (\r
229 CurrentModuleAcpiParamDescriptors[AcpiParamIndex].AcpiParameterBufferAddress\r
230 );\r
231 }\r
232 }\r
233 }\r
3f7af17c
MK
234 }\r
235 CurrentModuleInfoStruct = (PRM_MODULE_INFORMATION_STRUCT *) ((UINTN) CurrentModuleInfoStruct + CurrentModuleInfoStruct->StructureLength);\r
236 }\r
237 *PrmAcpiDescriptionTable = PrmAcpiTable;\r
238\r
239 return EFI_SUCCESS;\r
240}\r
241\r
242/**\r
243 Publishes the PRM ACPI table (PRMT).\r
244\r
245 @param[in] PrmAcpiDescriptionTable A pointer to a buffer with a completely populated and valid PRM\r
246 ACPI description table.\r
247\r
248 @retval EFI_SUCCESS The PRM ACPI was installed successfully.\r
249 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL or the table signature\r
250 in the table provided is invalid.\r
251 @retval EFI_NOT_FOUND The protocol gEfiAcpiTableProtocolGuid could not be found.\r
252 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table buffer.\r
253\r
254**/\r
255EFI_STATUS\r
256PublishPrmAcpiTable (\r
257 IN PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiDescriptionTable\r
258 )\r
259{\r
260 EFI_STATUS Status;\r
261 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;\r
262 UINTN TableKey;\r
263\r
264 if (PrmAcpiDescriptionTable == NULL || PrmAcpiDescriptionTable->Header.Signature != PRM_TABLE_SIGNATURE) {\r
265 return EFI_INVALID_PARAMETER;\r
266 }\r
267\r
268 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);\r
269 if (!EFI_ERROR (Status)) {\r
270 TableKey = 0;\r
271 //\r
272 // Publish the PRM ACPI table. The table checksum will be computed during installation.\r
273 //\r
274 Status = AcpiTableProtocol->InstallAcpiTable (\r
275 AcpiTableProtocol,\r
276 PrmAcpiDescriptionTable,\r
277 PrmAcpiDescriptionTable->Header.Length,\r
278 &TableKey\r
279 );\r
280 if (!EFI_ERROR (Status)) {\r
281 DEBUG ((DEBUG_INFO, "%a %a: The PRMT ACPI table was installed successfully.\n", _DBGMSGID_, __FUNCTION__));\r
282 }\r
283 }\r
284 ASSERT_EFI_ERROR (Status);\r
285\r
286 return Status;\r
287}\r
288\r
289/**\r
290 The PRM Loader END_OF_DXE protocol notification event handler.\r
291\r
292 All PRM Modules that are eligible for dispatch should have been loaded the DXE Dispatcher at the\r
293 time of this function invocation.\r
294\r
295 The main responsibilities of the PRM Loader are executed from this function which include 3 phases:\r
296 1.) Disover PRM Modules - Find all PRM modules loaded during DXE dispatch and insert a PRM Module\r
297 Context entry into a linked list to be handed off to phase 2.\r
298 2.) Process PRM Modules - Build a GUID to PRM handler mapping for each module that is described in the\r
299 PRM ACPI table so the OS can resolve a PRM Handler GUID to the corresponding PRM Handler physical address.\r
300 3.) Publish PRM ACPI Table - Publish the PRM ACPI table with the information gathered in the phase 2.\r
301\r
302 @param[in] Event Event whose notification function is being invoked.\r
303 @param[in] Context The pointer to the notification function's context,\r
304 which is implementation-dependent.\r
305\r
3f7af17c 306**/\r
e10c7764 307VOID\r
3f7af17c
MK
308EFIAPI\r
309PrmLoaderEndOfDxeNotification (\r
310 IN EFI_EVENT Event,\r
311 IN VOID *Context\r
312 )\r
313{\r
314 EFI_STATUS Status;\r
315 PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiDescriptionTable;\r
316\r
317 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
318\r
6b7dde7c 319 Status = DiscoverPrmModules (&mPrmModuleCount, &mPrmHandlerCount);\r
3f7af17c
MK
320 ASSERT_EFI_ERROR (Status);\r
321\r
322 Status = ProcessPrmModules (&PrmAcpiDescriptionTable);\r
323 ASSERT_EFI_ERROR (Status);\r
324\r
325 Status = PublishPrmAcpiTable (PrmAcpiDescriptionTable);\r
326 ASSERT_EFI_ERROR (Status);\r
327\r
328 if (PrmAcpiDescriptionTable != NULL) {\r
329 FreePool (PrmAcpiDescriptionTable);\r
330 }\r
331 gBS->CloseEvent (Event);\r
3f7af17c
MK
332}\r
333\r
334/**\r
335 The entry point for this module.\r
336\r
337 @param ImageHandle The firmware allocated handle for the EFI image.\r
338 @param SystemTable A pointer to the EFI System Table.\r
339\r
340 @retval EFI_SUCCESS The entry point is executed successfully.\r
341 @retval Others An error occurred when executing this entry point.\r
342\r
343**/\r
344EFI_STATUS\r
345EFIAPI\r
346PrmLoaderEntryPoint (\r
347 IN EFI_HANDLE ImageHandle,\r
348 IN EFI_SYSTEM_TABLE *SystemTable\r
349 )\r
350{\r
351 EFI_STATUS Status;\r
352 EFI_EVENT EndOfDxeEvent;\r
353\r
354 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
355\r
356 //\r
357 // Discover and process installed PRM modules at the End of DXE\r
358 // The PRM ACPI table is published if one or PRM modules are discovered\r
359 //\r
360 Status = gBS->CreateEventEx(\r
361 EVT_NOTIFY_SIGNAL,\r
362 TPL_CALLBACK,\r
363 PrmLoaderEndOfDxeNotification,\r
364 NULL,\r
365 &gEfiEndOfDxeEventGroupGuid,\r
366 &EndOfDxeEvent\r
367 );\r
368 if (EFI_ERROR (Status)) {\r
369 DEBUG ((DEBUG_ERROR, "%a %a: EndOfDxe callback registration failed! %r.\n", _DBGMSGID_, __FUNCTION__, Status));\r
370 ASSERT_EFI_ERROR (Status);\r
371 }\r
372\r
373 return EFI_SUCCESS;\r
374}\r