]> git.proxmox.com Git - mirror_edk2.git/blame - PrmPkg/PrmLoaderDxe/PrmLoaderDxe.c
PrmPkg: Remove ALLOCATE_CONTEXT_BUFFER_IN_FW build flag
[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
13#include "PrmLoader.h"\r
14\r
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
21#include <Library/UefiBootServicesTableLib.h>\r
22#include <Library/UefiLib.h>\r
23#include <Protocol/AcpiTable.h>\r
24#include <Protocol/LoadedImage.h>\r
25#include <Protocol/PrmConfig.h>\r
26\r
27#include <PrmContextBuffer.h>\r
28#include <PrmMmio.h>\r
3f7af17c
MK
29\r
30LIST_ENTRY mPrmModuleList;\r
31\r
32// Todo: Potentially refactor mPrmHandlerCount and mPrmModuleCount into localized structures\r
33// in the future.\r
34UINT32 mPrmHandlerCount;\r
35UINT32 mPrmModuleCount;\r
36\r
37/**\r
38 Gets a pointer to the export directory in a given PE/COFF image.\r
39\r
40 @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.\r
41 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
42 PE/COFF image context for the Image containing the PRM Module Export\r
43 Descriptor table.\r
44 @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found\r
45 in the ImageExportDirectory given.\r
46\r
47 @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.\r
48 @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
49 @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given\r
50 ImageExportDirectory.\r
51\r
52**/\r
53EFI_STATUS\r
54GetPrmModuleExportDescriptorTable (\r
55 IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r
56 IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
57 OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT **ExportDescriptor\r
58 )\r
59{\r
60 UINTN Index;\r
61 EFI_PHYSICAL_ADDRESS CurrentImageAddress;\r
62 UINT16 PrmModuleExportDescriptorOrdinal;\r
63 CONST CHAR8 *CurrentExportName;\r
64 UINT16 *OrdinalTable;\r
65 UINT32 *ExportNamePointerTable;\r
66 UINT32 *ExportAddressTable;\r
67 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *TempExportDescriptor;\r
68\r
69 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
70\r
71 *ExportDescriptor = NULL;\r
72\r
73 if (ImageExportDirectory == NULL ||\r
74 PeCoffLoaderImageContext == NULL ||\r
75 PeCoffLoaderImageContext->ImageAddress == 0 ||\r
76 ExportDescriptor == NULL) {\r
77 return EFI_INVALID_PARAMETER;\r
78 }\r
79\r
80 DEBUG ((\r
81 DEBUG_INFO,\r
82 " %a %a: %d exported names found in this image.\n",\r
83 _DBGMSGID_,\r
84 __FUNCTION__,\r
85 ImageExportDirectory->NumberOfNames\r
86 ));\r
87\r
88 //\r
89 // The export name pointer table and export ordinal table form two parallel arrays associated by index.\r
90 //\r
91 CurrentImageAddress = PeCoffLoaderImageContext->ImageAddress;\r
92 ExportAddressTable = (UINT32 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfFunctions);\r
93 ExportNamePointerTable = (UINT32 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfNames);\r
94 OrdinalTable = (UINT16 *) ((UINTN) CurrentImageAddress + ImageExportDirectory->AddressOfNameOrdinals);\r
95\r
96 for (Index = 0; Index < ImageExportDirectory->NumberOfNames; Index++) {\r
97 CurrentExportName = (CONST CHAR8 *) ((UINTN) CurrentImageAddress + ExportNamePointerTable[Index]);\r
98 DEBUG ((\r
99 DEBUG_INFO,\r
100 " %a %a: Export Name[0x%x] - %a.\n",\r
101 _DBGMSGID_,\r
102 __FUNCTION__,\r
103 Index,\r
104 CurrentExportName\r
105 ));\r
106 if (\r
107 AsciiStrnCmp (\r
108 PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME),\r
109 CurrentExportName,\r
110 AsciiStrLen (PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME))\r
111 ) == 0) {\r
112 PrmModuleExportDescriptorOrdinal = OrdinalTable[Index];\r
113 DEBUG ((\r
114 DEBUG_INFO,\r
115 " %a %a: PRM Module Export Descriptor found. Ordinal = %d.\n",\r
116 _DBGMSGID_,\r
117 __FUNCTION__,\r
118 PrmModuleExportDescriptorOrdinal\r
119 ));\r
120 if (PrmModuleExportDescriptorOrdinal >= ImageExportDirectory->NumberOfFunctions) {\r
121 DEBUG ((DEBUG_ERROR, "%a %a: The PRM Module Export Descriptor ordinal value is invalid.\n", _DBGMSGID_, __FUNCTION__));\r
122 return EFI_NOT_FOUND;\r
123 }\r
124 TempExportDescriptor = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *) ((UINTN) CurrentImageAddress + ExportAddressTable[PrmModuleExportDescriptorOrdinal]);\r
a6f8946b 125 if (TempExportDescriptor->Header.Signature == PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE) {\r
3f7af17c
MK
126 *ExportDescriptor = TempExportDescriptor;\r
127 DEBUG ((DEBUG_INFO, " %a %a: PRM Module Export Descriptor found at 0x%x.\n", _DBGMSGID_, __FUNCTION__, (UINTN) ExportDescriptor));\r
128 } else {\r
129 DEBUG ((\r
130 DEBUG_INFO,\r
131 " %a %a: PRM Module Export Descriptor found at 0x%x but signature check failed.\n",\r
132 _DBGMSGID_,\r
133 __FUNCTION__,\r
134 (UINTN) TempExportDescriptor\r
135 ));\r
136 }\r
137 DEBUG ((DEBUG_INFO, " %a %a: Exiting export iteration since export descriptor found.\n", _DBGMSGID_, __FUNCTION__));\r
138 return EFI_SUCCESS;\r
139 }\r
140 }\r
141\r
142 return EFI_NOT_FOUND;\r
143}\r
144\r
145/**\r
146 Gets a pointer to the export directory in a given PE/COFF image.\r
147\r
148 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r
149 and already relocated to the memory base address. RVAs in the image given\r
150 should be valid.\r
151 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
152 PE/COFF image context for the Image given.\r
153 @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.\r
154\r
155 @retval EFI_SUCCESS The export directory was found successfully.\r
156 @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
157 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.\r
158 @retval EFI_NOT_FOUND The image export directory could not be found for this image.\r
159\r
160**/\r
161EFI_STATUS\r
162GetExportDirectoryInPeCoffImage (\r
163 IN VOID *Image,\r
164 IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
165 OUT EFI_IMAGE_EXPORT_DIRECTORY **ImageExportDirectory\r
166 )\r
167{\r
168 UINT16 Magic;\r
169 UINT32 NumberOfRvaAndSizes;\r
170 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;\r
171 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
172 EFI_IMAGE_EXPORT_DIRECTORY *ExportDirectory;\r
173 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
174\r
175 if (Image == NULL || PeCoffLoaderImageContext == NULL || ImageExportDirectory == NULL) {\r
176 return EFI_INVALID_PARAMETER;\r
177 }\r
178\r
179 DirectoryEntry = NULL;\r
180 ExportDirectory = NULL;\r
181\r
182 //\r
183 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+\r
184 // image instead of using the Magic field. Some systems might generate a PE32+\r
185 // image with PE32 magic.\r
186 //\r
187 switch (PeCoffLoaderImageContext->Machine) {\r
188 case EFI_IMAGE_MACHINE_IA32:\r
189 // Todo: Add EFI_IMAGE_MACHINE_ARMT\r
190 //\r
191 // Assume PE32 image with IA32 Machine field.\r
192 //\r
193 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
194 break;\r
195 case EFI_IMAGE_MACHINE_X64:\r
196 //\r
197 // Assume PE32+ image with X64 Machine field\r
198 //\r
199 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
200 break;\r
201 default:\r
202 //\r
203 // For unknown Machine field, use Magic in optional header\r
204 //\r
205 DEBUG ((\r
206 DEBUG_WARN,\r
207 "%a %a: The machine type for this image is not valid for a PRM module.\n",\r
208 _DBGMSGID_,\r
209 __FUNCTION__\r
210 ));\r
211 return EFI_UNSUPPORTED;\r
212 }\r
213\r
214 OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (\r
215 (UINTN) Image +\r
216 PeCoffLoaderImageContext->PeCoffHeaderOffset\r
217 );\r
218\r
219 //\r
220 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.\r
221 //\r
222 if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
223 DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __FUNCTION__));\r
224 return EFI_UNSUPPORTED;\r
225 }\r
226\r
227 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
228 (UINTN) Image +\r
229 PeCoffLoaderImageContext->PeCoffHeaderOffset +\r
230 sizeof (UINT32) +\r
231 sizeof (EFI_IMAGE_FILE_HEADER) +\r
232 PeCoffLoaderImageContext->SizeOfHeaders\r
233 );\r
234 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
235 //\r
236 // Use the PE32 offset to get the Export Directory Entry\r
237 //\r
238 NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
239 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHeaderPtrUnion.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);\r
240 } else if (OptionalHeaderPtrUnion.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
241 //\r
242 // Use the PE32+ offset get the Export Directory Entry\r
243 //\r
244 NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
245 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);\r
246 } else {\r
247 return EFI_UNSUPPORTED;\r
248 }\r
249\r
250 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_EXPORT || DirectoryEntry->VirtualAddress == 0) {\r
251 //\r
252 // The export directory is not present\r
253 //\r
254 return EFI_NOT_FOUND;\r
255 } else if (((UINT32) (~0) - DirectoryEntry->VirtualAddress) < DirectoryEntry->Size) {\r
256 //\r
257 // The directory address overflows\r
258 //\r
259 DEBUG ((DEBUG_ERROR, "%a %a: The export directory entry in this image results in overflow.\n", _DBGMSGID_, __FUNCTION__));\r
260 return EFI_UNSUPPORTED;\r
261 } else {\r
262 DEBUG ((DEBUG_INFO, "%a %a: Export Directory Entry found in the image at 0x%x.\n", _DBGMSGID_, __FUNCTION__, (UINTN) OptionalHeaderPtrUnion.Pe32));\r
263 DEBUG ((DEBUG_INFO, " %a %a: Directory Entry Virtual Address = 0x%x.\n", _DBGMSGID_, __FUNCTION__, DirectoryEntry->VirtualAddress));\r
264\r
265 ExportDirectory = (EFI_IMAGE_EXPORT_DIRECTORY *) ((UINTN) Image + DirectoryEntry->VirtualAddress);\r
266 DEBUG ((\r
267 DEBUG_INFO,\r
268 " %a %a: Export Directory Table found successfully at 0x%x. Name address = 0x%x. Name = %a.\n",\r
269 _DBGMSGID_,\r
270 __FUNCTION__,\r
271 (UINTN) ExportDirectory,\r
272 ((UINTN) Image + ExportDirectory->Name),\r
273 (CHAR8 *) ((UINTN) Image + ExportDirectory->Name)\r
274 ));\r
275 }\r
276 *ImageExportDirectory = ExportDirectory;\r
277\r
278 return EFI_SUCCESS;\r
279}\r
280\r
281/**\r
282 Returns the image major and image minor version in a given PE/COFF image.\r
283\r
284 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory\r
285 and already relocated to the memory base address. RVAs in the image given\r
286 should be valid.\r
287 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the\r
288 PE/COFF image context for the Image given.\r
289 @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.\r
290 @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.\r
291\r
292 @retval EFI_SUCCESS The image version was read successfully.\r
293 @retval EFI_INVALID_PARAMETER A required parameter is NULL.\r
294 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.\r
295\r
296**/\r
297EFI_STATUS\r
298GetImageVersionInPeCoffImage (\r
299 IN VOID *Image,\r
300 IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,\r
301 OUT UINT16 *ImageMajorVersion,\r
302 OUT UINT16 *ImageMinorVersion\r
303 )\r
304{\r
305 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;\r
306 UINT16 Magic;\r
307\r
308 DEBUG ((DEBUG_INFO, " %a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
309\r
310 if (Image == NULL || PeCoffLoaderImageContext == NULL || ImageMajorVersion == NULL || ImageMinorVersion == NULL) {\r
311 return EFI_INVALID_PARAMETER;\r
312 }\r
313\r
314 //\r
315 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+\r
316 // image instead of using the Magic field. Some systems might generate a PE32+\r
317 // image with PE32 magic.\r
318 //\r
319 switch (PeCoffLoaderImageContext->Machine) {\r
320 case EFI_IMAGE_MACHINE_IA32:\r
321 // Todo: Add EFI_IMAGE_MACHINE_ARMT\r
322 //\r
323 // Assume PE32 image with IA32 Machine field.\r
324 //\r
325 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
326 break;\r
327 case EFI_IMAGE_MACHINE_X64:\r
328 //\r
329 // Assume PE32+ image with X64 Machine field\r
330 //\r
331 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
332 break;\r
333 default:\r
334 //\r
335 // For unknown Machine field, use Magic in optional header\r
336 //\r
337 DEBUG ((\r
338 DEBUG_WARN,\r
339 "%a %a: The machine type for this image is not valid for a PRM module.\n",\r
340 _DBGMSGID_,\r
341 __FUNCTION__\r
342 ));\r
343 return EFI_UNSUPPORTED;\r
344 }\r
345\r
346 OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (\r
347 (UINTN) Image +\r
348 PeCoffLoaderImageContext->PeCoffHeaderOffset\r
349 );\r
350 //\r
351 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.\r
352 //\r
353 if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
354 DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __FUNCTION__));\r
355 return EFI_UNSUPPORTED;\r
356 }\r
357\r
358 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
359 //\r
360 // Use the PE32 offset to get the Export Directory Entry\r
361 //\r
362 *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MajorImageVersion;\r
363 *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MinorImageVersion;\r
364 } else {\r
365 //\r
366 // Use the PE32+ offset to get the Export Directory Entry\r
367 //\r
368 *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MajorImageVersion;\r
369 *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MinorImageVersion;\r
370 }\r
371\r
372 DEBUG ((DEBUG_INFO, " %a %a - Image Major Version: 0x%02x.\n", _DBGMSGID_, __FUNCTION__, *ImageMajorVersion));\r
373 DEBUG ((DEBUG_INFO, " %a %a - Image Minor Version: 0x%02x.\n", _DBGMSGID_, __FUNCTION__, *ImageMinorVersion));\r
374\r
375 return EFI_SUCCESS;\r
376}\r
377\r
378/**\r
379 Creates a new PRM Module Image Context linked list entry.\r
380\r
381 @retval PrmModuleImageContextListEntry If successful, a pointer a PRM Module Image Context linked list entry\r
382 otherwise, NULL is returned.\r
383\r
384**/\r
385STATIC\r
386PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *\r
387CreateNewPrmModuleImageContextListEntry (\r
388 VOID\r
389 )\r
390{\r
391 PRM_MODULE_IMAGE_CONTEXT *PrmModuleImageContext;\r
392 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *PrmModuleImageContextListEntry;\r
393\r
394 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
395\r
396 PrmModuleImageContext = AllocateZeroPool (sizeof (*PrmModuleImageContext));\r
397 if (PrmModuleImageContext == NULL) {\r
398 return NULL;\r
399 }\r
400 DEBUG ((\r
401 DEBUG_INFO,\r
402 " %a %a: Allocated PrmModuleImageContext at 0x%x of size 0x%x bytes.\n",\r
403 _DBGMSGID_,\r
404 __FUNCTION__,\r
405 (UINTN) PrmModuleImageContext,\r
406 sizeof (*PrmModuleImageContext)\r
407 ));\r
408\r
409 PrmModuleImageContextListEntry = AllocateZeroPool (sizeof (*PrmModuleImageContextListEntry));\r
410 if (PrmModuleImageContextListEntry == NULL) {\r
411 FreePool (PrmModuleImageContext);\r
412 return NULL;\r
413 }\r
414 DEBUG ((\r
415 DEBUG_INFO,\r
416 " %a %a: Allocated PrmModuleImageContextListEntry at 0x%x of size 0x%x bytes.\n",\r
417 _DBGMSGID_,\r
418 __FUNCTION__,\r
419 (UINTN) PrmModuleImageContextListEntry,\r
420 sizeof (*PrmModuleImageContextListEntry)\r
421 ));\r
422\r
423 PrmModuleImageContextListEntry->Signature = PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE;\r
424 PrmModuleImageContextListEntry->Context = PrmModuleImageContext;\r
425\r
426 return PrmModuleImageContextListEntry;\r
427}\r
428\r
429/**\r
430 Discovers all PRM Modules loaded during the DXE boot phase.\r
431\r
432 Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.\r
433\r
434 @retval EFI_SUCCESS All PRM Modules were discovered successfully.\r
435 @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.\r
436 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context\r
437 linked list nodes.\r
438\r
439**/\r
440EFI_STATUS\r
441DiscoverPrmModules (\r
442 VOID\r
443 )\r
444{\r
445 EFI_STATUS Status;\r
446 PRM_MODULE_IMAGE_CONTEXT TempPrmModuleImageContext;\r
447 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *PrmModuleImageContextListEntry;\r
448 EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol;\r
449 EFI_HANDLE *HandleBuffer;\r
450 UINTN HandleCount;\r
451 UINTN Index;\r
452\r
453 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
454\r
455 Status = gBS->LocateHandleBuffer (\r
456 ByProtocol,\r
457 &gEfiLoadedImageProtocolGuid,\r
458 NULL,\r
459 &HandleCount,\r
460 &HandleBuffer\r
461 );\r
462 if (EFI_ERROR (Status) && (HandleCount == 0)) {\r
463 DEBUG ((DEBUG_ERROR, "%a %a: No LoadedImageProtocol instances found!\n", _DBGMSGID_, __FUNCTION__));\r
464 return EFI_NOT_FOUND;\r
465 }\r
466\r
467 for (Index = 0; Index < HandleCount; Index++) {\r
468 Status = gBS->HandleProtocol (\r
469 HandleBuffer[Index],\r
470 &gEfiLoadedImageProtocolGuid,\r
471 (VOID **) &LoadedImageProtocol\r
472 );\r
473 if (EFI_ERROR (Status)) {\r
474 continue;\r
475 }\r
476\r
477 ZeroMem (&TempPrmModuleImageContext, sizeof (TempPrmModuleImageContext));\r
478 TempPrmModuleImageContext.PeCoffImageContext.Handle = LoadedImageProtocol->ImageBase;\r
479 TempPrmModuleImageContext.PeCoffImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
480\r
481 Status = PeCoffLoaderGetImageInfo (&TempPrmModuleImageContext.PeCoffImageContext);\r
482 if (EFI_ERROR (Status) || TempPrmModuleImageContext.PeCoffImageContext.ImageError != IMAGE_ERROR_SUCCESS) {\r
483 DEBUG ((\r
484 DEBUG_WARN,\r
485 "%a %a: ImageHandle 0x%016lx is not a valid PE/COFF image. It cannot be considered a PRM module.\n",\r
486 _DBGMSGID_,\r
487 __FUNCTION__,\r
488 (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImageProtocol->ImageBase\r
489 ));\r
490 continue;\r
491 }\r
492 if (TempPrmModuleImageContext.PeCoffImageContext.IsTeImage) {\r
493 // A PRM Module is not allowed to be a TE image\r
494 continue;\r
495 }\r
496\r
497 // Attempt to find an export table in this image\r
498 Status = GetExportDirectoryInPeCoffImage (\r
499 LoadedImageProtocol->ImageBase,\r
500 &TempPrmModuleImageContext.PeCoffImageContext,\r
501 &TempPrmModuleImageContext.ExportDirectory\r
502 );\r
503 if (EFI_ERROR (Status)) {\r
504 continue;\r
505 }\r
506\r
507 // Attempt to find the PRM Module Export Descriptor in the export table\r
508 Status = GetPrmModuleExportDescriptorTable (\r
509 TempPrmModuleImageContext.ExportDirectory,\r
510 &TempPrmModuleImageContext.PeCoffImageContext,\r
511 &TempPrmModuleImageContext.ExportDescriptor\r
512 );\r
513 if (EFI_ERROR (Status)) {\r
514 continue;\r
515 }\r
516 // A PRM Module Export Descriptor was successfully found, this is considered a PRM Module.\r
517\r
518 //\r
519 // Create a new PRM Module image context node\r
520 //\r
521 PrmModuleImageContextListEntry = CreateNewPrmModuleImageContextListEntry ();\r
522 if (PrmModuleImageContextListEntry == NULL) {\r
523 return EFI_OUT_OF_RESOURCES;\r
524 }\r
525 CopyMem (\r
526 PrmModuleImageContextListEntry->Context,\r
527 &TempPrmModuleImageContext,\r
528 sizeof (*(PrmModuleImageContextListEntry->Context))\r
529 );\r
530 InsertTailList (&mPrmModuleList, &PrmModuleImageContextListEntry->Link);\r
a6f8946b 531 mPrmHandlerCount += TempPrmModuleImageContext.ExportDescriptor->Header.NumberPrmHandlers;\r
3f7af17c
MK
532 mPrmModuleCount++; // Todo: Match with global variable refactor change in the future\r
533 DEBUG ((DEBUG_INFO, "%a %a: New PRM Module inserted into list to be processed.\n", _DBGMSGID_, __FUNCTION__));\r
534 }\r
535\r
536 return EFI_SUCCESS;\r
537}\r
538\r
539/**\r
540 Gets the address of an entry in an image export table by ASCII name.\r
541\r
542 @param[in] ExportName A pointer to an ASCII name string of the entry name.\r
543 @param[in] ImageBaseAddress The base address of the PE/COFF image.\r
544 @param[in] ImageExportDirectory A pointer to the export directory in the image.\r
545 @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the\r
546 export entry if found.\r
547\r
548 @retval EFI_SUCCESS The export entry was found successfully.\r
549 @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.\r
550 @retval EFI_NOT_FOUND An entry with the given ExportName was not found.\r
551\r
552**/\r
553EFI_STATUS\r
554GetExportEntryAddress (\r
555 IN CONST CHAR8 *ExportName,\r
556 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,\r
557 IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,\r
558 OUT EFI_PHYSICAL_ADDRESS *ExportPhysicalAddress\r
559 )\r
560{\r
561 UINTN ExportNameIndex;\r
562 UINT16 CurrentExportOrdinal;\r
563 UINT32 *ExportAddressTable;\r
564 UINT32 *ExportNamePointerTable;\r
565 UINT16 *OrdinalTable;\r
566 CONST CHAR8 *ExportNameTablePointerName;\r
567\r
568 if (ExportName == NULL || ImageBaseAddress == 0 || ImageExportDirectory == NULL || ExportPhysicalAddress == NULL) {\r
569 return EFI_INVALID_PARAMETER;\r
570 }\r
571 *ExportPhysicalAddress = 0;\r
572\r
573 ExportAddressTable = (UINT32 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfFunctions);\r
574 ExportNamePointerTable = (UINT32 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfNames);\r
575 OrdinalTable = (UINT16 *) ((UINTN) ImageBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);\r
576\r
577 for (ExportNameIndex = 0; ExportNameIndex < ImageExportDirectory->NumberOfNames; ExportNameIndex++) {\r
578 ExportNameTablePointerName = (CONST CHAR8 *) ((UINTN) ImageBaseAddress + ExportNamePointerTable[ExportNameIndex]);\r
579\r
580 if (AsciiStrnCmp (ExportName, ExportNameTablePointerName, PRM_HANDLER_NAME_MAXIMUM_LENGTH) == 0) {\r
581 CurrentExportOrdinal = OrdinalTable[ExportNameIndex];\r
582\r
583 ASSERT (CurrentExportOrdinal < ImageExportDirectory->NumberOfFunctions);\r
584 if (CurrentExportOrdinal >= ImageExportDirectory->NumberOfFunctions) {\r
585 DEBUG ((DEBUG_ERROR, " %a %a: The export ordinal value is invalid.\n", _DBGMSGID_, __FUNCTION__));\r
586 break;\r
587 }\r
588\r
589 *ExportPhysicalAddress = (EFI_PHYSICAL_ADDRESS) ((UINTN) ImageBaseAddress + ExportAddressTable[CurrentExportOrdinal]);\r
590 return EFI_SUCCESS;\r
591 }\r
592 }\r
593\r
594 return EFI_NOT_FOUND;\r
595}\r
596\r
597/**\r
598 Processes a list of PRM context entries to build a PRM ACPI table.\r
599\r
600 The ACPI table buffer is allocated and the table structure is built inside this function.\r
601\r
602 @param[out] PrmAcpiDescriptionTable A pointer to a pointer to a buffer that is allocated within this function\r
603 and will contain the PRM ACPI table. In case of an error in this function,\r
604 *PrmAcpiDescriptorTable will be NULL.\r
605\r
606 @retval EFI_SUCCESS All PRM Modules were processed to construct the PRM ACPI table successfully.\r
607 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL.\r
608 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table boot services\r
609 memory data buffer.\r
610\r
611**/\r
612EFI_STATUS\r
613ProcessPrmModules (\r
614 OUT PRM_ACPI_DESCRIPTION_TABLE **PrmAcpiDescriptionTable\r
615 )\r
616{\r
617 EFI_IMAGE_EXPORT_DIRECTORY *CurrentImageExportDirectory;\r
618 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *CurrentExportDescriptorStruct;\r
619 LIST_ENTRY *Link;\r
620 PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiTable;\r
621 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY *TempListEntry;\r
622 CONST CHAR8 *CurrentExportDescriptorHandlerName;\r
623\r
624 PRM_CONTEXT_BUFFER *CurrentContextBuffer;\r
625 PRM_MODULE_CONTEXT_BUFFERS *CurrentModuleContextBuffers;\r
626 PRM_MODULE_INFORMATION_STRUCT *CurrentModuleInfoStruct;\r
627 PRM_HANDLER_INFORMATION_STRUCT *CurrentHandlerInfoStruct;\r
628\r
629 EFI_STATUS Status;\r
630 EFI_PHYSICAL_ADDRESS CurrentImageAddress;\r
631 UINTN HandlerIndex;\r
632 UINT32 PrmAcpiDescriptionTableBufferSize;\r
633\r
634 UINT64 HandlerPhysicalAddress;\r
635\r
636 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
637\r
638 if (PrmAcpiDescriptionTable == NULL) {\r
639 return EFI_INVALID_PARAMETER;\r
640 }\r
641 Link = NULL;\r
642 *PrmAcpiDescriptionTable = NULL;\r
643\r
644 DEBUG ((DEBUG_INFO, " %a %a: %d total PRM modules to process.\n", _DBGMSGID_, __FUNCTION__, mPrmModuleCount));\r
645 DEBUG ((DEBUG_INFO, " %a %a: %d total PRM handlers to process.\n", _DBGMSGID_, __FUNCTION__, mPrmHandlerCount));\r
646\r
647 PrmAcpiDescriptionTableBufferSize = (OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure) +\r
648 (OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) * mPrmModuleCount) +\r
649 (sizeof (PRM_HANDLER_INFORMATION_STRUCT) * mPrmHandlerCount)\r
650 );\r
651 DEBUG ((DEBUG_INFO, " %a %a: Total PRM ACPI table size: 0x%x.\n", _DBGMSGID_, __FUNCTION__, PrmAcpiDescriptionTableBufferSize));\r
652\r
653 PrmAcpiTable = AllocateZeroPool ((UINTN) PrmAcpiDescriptionTableBufferSize);\r
654 if (PrmAcpiTable == NULL) {\r
655 return EFI_OUT_OF_RESOURCES;\r
656 }\r
657\r
658 PrmAcpiTable->Header.Signature = PRM_TABLE_SIGNATURE;\r
659 PrmAcpiTable->Header.Length = PrmAcpiDescriptionTableBufferSize;\r
660 PrmAcpiTable->Header.Revision = PRM_TABLE_REVISION;\r
661 PrmAcpiTable->Header.Checksum = 0x0;\r
662 CopyMem (&PrmAcpiTable->Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (PrmAcpiTable->Header.OemId));\r
663 PrmAcpiTable->Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
664 PrmAcpiTable->Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
665 PrmAcpiTable->Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
666 PrmAcpiTable->Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
667 PrmAcpiTable->PrmModuleInfoOffset = OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure);\r
668 PrmAcpiTable->PrmModuleInfoCount = mPrmModuleCount;\r
669\r
670 //\r
671 // Iterate across all PRM Modules on the list\r
672 //\r
673 CurrentModuleInfoStruct = &PrmAcpiTable->PrmModuleInfoStructure[0];\r
674 EFI_LIST_FOR_EACH(Link, &mPrmModuleList)\r
675 {\r
676 TempListEntry = CR(Link, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY, Link, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE);\r
677 CurrentImageAddress = TempListEntry->Context->PeCoffImageContext.ImageAddress;\r
678 CurrentImageExportDirectory = TempListEntry->Context->ExportDirectory;\r
679 CurrentExportDescriptorStruct = TempListEntry->Context->ExportDescriptor;\r
680\r
681 DEBUG ((\r
682 DEBUG_INFO,\r
683 " %a %a: PRM Module - %a with %d handlers.\n",\r
684 _DBGMSGID_,\r
685 __FUNCTION__,\r
686 (CHAR8 *) ((UINTN) CurrentImageAddress + CurrentImageExportDirectory->Name),\r
a6f8946b 687 CurrentExportDescriptorStruct->Header.NumberPrmHandlers\r
3f7af17c
MK
688 ));\r
689\r
690 CurrentModuleInfoStruct->StructureRevision = PRM_MODULE_INFORMATION_STRUCT_REVISION;\r
691 CurrentModuleInfoStruct->StructureLength = (\r
692 OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) +\r
a6f8946b 693 (CurrentExportDescriptorStruct->Header.NumberPrmHandlers * sizeof (PRM_HANDLER_INFORMATION_STRUCT))\r
3f7af17c 694 );\r
a6f8946b
MK
695 CopyGuid (&CurrentModuleInfoStruct->Identifier, &CurrentExportDescriptorStruct->Header.ModuleGuid);\r
696 CurrentModuleInfoStruct->HandlerCount = (UINT32) CurrentExportDescriptorStruct->Header.NumberPrmHandlers;\r
3f7af17c
MK
697 CurrentModuleInfoStruct->HandlerInfoOffset = OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure);\r
698\r
699 CurrentModuleInfoStruct->MajorRevision = 0;\r
700 CurrentModuleInfoStruct->MinorRevision = 0;\r
701 Status = GetImageVersionInPeCoffImage (\r
702 (VOID *) (UINTN) CurrentImageAddress,\r
703 &TempListEntry->Context->PeCoffImageContext,\r
704 &CurrentModuleInfoStruct->MajorRevision,\r
705 &CurrentModuleInfoStruct->MinorRevision\r
706 );\r
707 ASSERT_EFI_ERROR (Status);\r
708\r
3f7af17c
MK
709 // It is currently valid for a PRM module not to use a context buffer\r
710 Status = GetModuleContextBuffers (\r
711 ByModuleGuid,\r
712 &CurrentModuleInfoStruct->Identifier,\r
713 &CurrentModuleContextBuffers\r
714 );\r
715 ASSERT (!EFI_ERROR (Status) || Status == EFI_NOT_FOUND);\r
716 if (!EFI_ERROR (Status) && CurrentModuleContextBuffers != NULL) {\r
717 CurrentModuleInfoStruct->RuntimeMmioRanges = (UINT64) (UINTN) CurrentModuleContextBuffers->RuntimeMmioRanges;\r
718 }\r
719\r
720 //\r
721 // Iterate across all PRM handlers in the PRM Module\r
722 //\r
a6f8946b 723 for (HandlerIndex = 0; HandlerIndex < CurrentExportDescriptorStruct->Header.NumberPrmHandlers; HandlerIndex++) {\r
3f7af17c
MK
724 CurrentHandlerInfoStruct = &(CurrentModuleInfoStruct->HandlerInfoStructure[HandlerIndex]);\r
725\r
726 CurrentHandlerInfoStruct->StructureRevision = PRM_HANDLER_INFORMATION_STRUCT_REVISION;\r
727 CurrentHandlerInfoStruct->StructureLength = sizeof (PRM_HANDLER_INFORMATION_STRUCT);\r
728 CopyGuid (\r
729 &CurrentHandlerInfoStruct->Identifier,\r
730 &CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerGuid\r
731 );\r
732\r
733 CurrentExportDescriptorHandlerName = (CONST CHAR8 *) CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerName;\r
734\r
735 Status = GetContextBuffer (\r
736 &CurrentHandlerInfoStruct->Identifier,\r
737 CurrentModuleContextBuffers,\r
738 &CurrentContextBuffer\r
739 );\r
740 if (!EFI_ERROR (Status)) {\r
e8467976 741 CurrentHandlerInfoStruct->StaticDataBuffer = (UINT64) (UINTN) CurrentContextBuffer->StaticDataBuffer;\r
3f7af17c
MK
742 }\r
743\r
744 Status = GetExportEntryAddress (\r
745 CurrentExportDescriptorHandlerName,\r
746 CurrentImageAddress,\r
747 CurrentImageExportDirectory,\r
748 &HandlerPhysicalAddress\r
749 );\r
750 ASSERT_EFI_ERROR (Status);\r
751 if (!EFI_ERROR (Status)) {\r
752 CurrentHandlerInfoStruct->PhysicalAddress = HandlerPhysicalAddress;\r
753 DEBUG ((\r
754 DEBUG_INFO,\r
755 " %a %a: Found %a handler physical address at 0x%016x.\n",\r
756 _DBGMSGID_,\r
757 __FUNCTION__,\r
758 CurrentExportDescriptorHandlerName,\r
759 CurrentHandlerInfoStruct->PhysicalAddress\r
760 ));\r
761 }\r
762 }\r
763 CurrentModuleInfoStruct = (PRM_MODULE_INFORMATION_STRUCT *) ((UINTN) CurrentModuleInfoStruct + CurrentModuleInfoStruct->StructureLength);\r
764 }\r
765 *PrmAcpiDescriptionTable = PrmAcpiTable;\r
766\r
767 return EFI_SUCCESS;\r
768}\r
769\r
770/**\r
771 Publishes the PRM ACPI table (PRMT).\r
772\r
773 @param[in] PrmAcpiDescriptionTable A pointer to a buffer with a completely populated and valid PRM\r
774 ACPI description table.\r
775\r
776 @retval EFI_SUCCESS The PRM ACPI was installed successfully.\r
777 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL or the table signature\r
778 in the table provided is invalid.\r
779 @retval EFI_NOT_FOUND The protocol gEfiAcpiTableProtocolGuid could not be found.\r
780 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table buffer.\r
781\r
782**/\r
783EFI_STATUS\r
784PublishPrmAcpiTable (\r
785 IN PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiDescriptionTable\r
786 )\r
787{\r
788 EFI_STATUS Status;\r
789 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;\r
790 UINTN TableKey;\r
791\r
792 if (PrmAcpiDescriptionTable == NULL || PrmAcpiDescriptionTable->Header.Signature != PRM_TABLE_SIGNATURE) {\r
793 return EFI_INVALID_PARAMETER;\r
794 }\r
795\r
796 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);\r
797 if (!EFI_ERROR (Status)) {\r
798 TableKey = 0;\r
799 //\r
800 // Publish the PRM ACPI table. The table checksum will be computed during installation.\r
801 //\r
802 Status = AcpiTableProtocol->InstallAcpiTable (\r
803 AcpiTableProtocol,\r
804 PrmAcpiDescriptionTable,\r
805 PrmAcpiDescriptionTable->Header.Length,\r
806 &TableKey\r
807 );\r
808 if (!EFI_ERROR (Status)) {\r
809 DEBUG ((DEBUG_INFO, "%a %a: The PRMT ACPI table was installed successfully.\n", _DBGMSGID_, __FUNCTION__));\r
810 }\r
811 }\r
812 ASSERT_EFI_ERROR (Status);\r
813\r
814 return Status;\r
815}\r
816\r
817/**\r
818 The PRM Loader END_OF_DXE protocol notification event handler.\r
819\r
820 All PRM Modules that are eligible for dispatch should have been loaded the DXE Dispatcher at the\r
821 time of this function invocation.\r
822\r
823 The main responsibilities of the PRM Loader are executed from this function which include 3 phases:\r
824 1.) Disover PRM Modules - Find all PRM modules loaded during DXE dispatch and insert a PRM Module\r
825 Context entry into a linked list to be handed off to phase 2.\r
826 2.) Process PRM Modules - Build a GUID to PRM handler mapping for each module that is described in the\r
827 PRM ACPI table so the OS can resolve a PRM Handler GUID to the corresponding PRM Handler physical address.\r
828 3.) Publish PRM ACPI Table - Publish the PRM ACPI table with the information gathered in the phase 2.\r
829\r
830 @param[in] Event Event whose notification function is being invoked.\r
831 @param[in] Context The pointer to the notification function's context,\r
832 which is implementation-dependent.\r
833\r
834 @retval EFI_SUCCESS The function executed successfully\r
835\r
836**/\r
837EFI_STATUS\r
838EFIAPI\r
839PrmLoaderEndOfDxeNotification (\r
840 IN EFI_EVENT Event,\r
841 IN VOID *Context\r
842 )\r
843{\r
844 EFI_STATUS Status;\r
845 PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiDescriptionTable;\r
846\r
847 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
848\r
849 InitializeListHead (&mPrmModuleList);\r
850\r
851 Status = DiscoverPrmModules ();\r
852 ASSERT_EFI_ERROR (Status);\r
853\r
854 Status = ProcessPrmModules (&PrmAcpiDescriptionTable);\r
855 ASSERT_EFI_ERROR (Status);\r
856\r
857 Status = PublishPrmAcpiTable (PrmAcpiDescriptionTable);\r
858 ASSERT_EFI_ERROR (Status);\r
859\r
860 if (PrmAcpiDescriptionTable != NULL) {\r
861 FreePool (PrmAcpiDescriptionTable);\r
862 }\r
863 gBS->CloseEvent (Event);\r
864\r
865 return EFI_SUCCESS;\r
866}\r
867\r
868/**\r
869 The entry point for this module.\r
870\r
871 @param ImageHandle The firmware allocated handle for the EFI image.\r
872 @param SystemTable A pointer to the EFI System Table.\r
873\r
874 @retval EFI_SUCCESS The entry point is executed successfully.\r
875 @retval Others An error occurred when executing this entry point.\r
876\r
877**/\r
878EFI_STATUS\r
879EFIAPI\r
880PrmLoaderEntryPoint (\r
881 IN EFI_HANDLE ImageHandle,\r
882 IN EFI_SYSTEM_TABLE *SystemTable\r
883 )\r
884{\r
885 EFI_STATUS Status;\r
886 EFI_EVENT EndOfDxeEvent;\r
887\r
888 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __FUNCTION__));\r
889\r
890 //\r
891 // Discover and process installed PRM modules at the End of DXE\r
892 // The PRM ACPI table is published if one or PRM modules are discovered\r
893 //\r
894 Status = gBS->CreateEventEx(\r
895 EVT_NOTIFY_SIGNAL,\r
896 TPL_CALLBACK,\r
897 PrmLoaderEndOfDxeNotification,\r
898 NULL,\r
899 &gEfiEndOfDxeEventGroupGuid,\r
900 &EndOfDxeEvent\r
901 );\r
902 if (EFI_ERROR (Status)) {\r
903 DEBUG ((DEBUG_ERROR, "%a %a: EndOfDxe callback registration failed! %r.\n", _DBGMSGID_, __FUNCTION__, Status));\r
904 ASSERT_EFI_ERROR (Status);\r
905 }\r
906\r
907 return EFI_SUCCESS;\r
908}\r