3 This file contains the implementation for a Platform Runtime Mechanism (PRM)
6 Copyright (c) Microsoft Corporation
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "PrmAcpiTable.h"
12 #include "PrmLoader.h"
14 #include <IndustryStandard/Acpi.h>
15 #include <Library/BaseLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/PrmContextBufferLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiLib.h>
22 #include <Protocol/AcpiTable.h>
23 #include <Protocol/LoadedImage.h>
24 #include <Protocol/PrmConfig.h>
26 #include <PrmContextBuffer.h>
28 #include <PrmModuleUpdate.h>
30 LIST_ENTRY mPrmModuleList
;
32 // Todo: Potentially refactor mPrmHandlerCount and mPrmModuleCount into localized structures
34 UINT32 mPrmHandlerCount
;
35 UINT32 mPrmModuleCount
;
38 Gets a pointer to the export directory in a given PE/COFF image.
40 @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.
41 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
42 PE/COFF image context for the Image containing the PRM Module Export
44 @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found
45 in the ImageExportDirectory given.
47 @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.
48 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
49 @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given
54 GetPrmModuleExportDescriptorTable (
55 IN EFI_IMAGE_EXPORT_DIRECTORY
*ImageExportDirectory
,
56 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
57 OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
**ExportDescriptor
61 EFI_PHYSICAL_ADDRESS CurrentImageAddress
;
62 UINT16 PrmModuleExportDescriptorOrdinal
;
63 CONST CHAR8
*CurrentExportName
;
65 UINT32
*ExportNamePointerTable
;
66 UINT32
*ExportAddressTable
;
67 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*TempExportDescriptor
;
69 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
71 *ExportDescriptor
= NULL
;
73 if (ImageExportDirectory
== NULL
||
74 PeCoffLoaderImageContext
== NULL
||
75 PeCoffLoaderImageContext
->ImageAddress
== 0 ||
76 ExportDescriptor
== NULL
) {
77 return EFI_INVALID_PARAMETER
;
82 " %a %a: %d exported names found in this image.\n",
85 ImageExportDirectory
->NumberOfNames
89 // The export name pointer table and export ordinal table form two parallel arrays associated by index.
91 CurrentImageAddress
= PeCoffLoaderImageContext
->ImageAddress
;
92 ExportAddressTable
= (UINT32
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfFunctions
);
93 ExportNamePointerTable
= (UINT32
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfNames
);
94 OrdinalTable
= (UINT16
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfNameOrdinals
);
96 for (Index
= 0; Index
< ImageExportDirectory
->NumberOfNames
; Index
++) {
97 CurrentExportName
= (CONST CHAR8
*) ((UINTN
) CurrentImageAddress
+ ExportNamePointerTable
[Index
]);
100 " %a %a: Export Name[0x%x] - %a.\n",
108 PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME
),
110 AsciiStrLen (PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME
))
112 PrmModuleExportDescriptorOrdinal
= OrdinalTable
[Index
];
115 " %a %a: PRM Module Export Descriptor found. Ordinal = %d.\n",
118 PrmModuleExportDescriptorOrdinal
120 if (PrmModuleExportDescriptorOrdinal
>= ImageExportDirectory
->NumberOfFunctions
) {
121 DEBUG ((DEBUG_ERROR
, "%a %a: The PRM Module Export Descriptor ordinal value is invalid.\n", _DBGMSGID_
, __FUNCTION__
));
122 return EFI_NOT_FOUND
;
124 TempExportDescriptor
= (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*) ((UINTN
) CurrentImageAddress
+ ExportAddressTable
[PrmModuleExportDescriptorOrdinal
]);
125 if (TempExportDescriptor
->Signature
== PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE
) {
126 *ExportDescriptor
= TempExportDescriptor
;
127 DEBUG ((DEBUG_INFO
, " %a %a: PRM Module Export Descriptor found at 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, (UINTN
) ExportDescriptor
));
131 " %a %a: PRM Module Export Descriptor found at 0x%x but signature check failed.\n",
134 (UINTN
) TempExportDescriptor
137 DEBUG ((DEBUG_INFO
, " %a %a: Exiting export iteration since export descriptor found.\n", _DBGMSGID_
, __FUNCTION__
));
142 return EFI_NOT_FOUND
;
146 Gets a pointer to the export directory in a given PE/COFF image.
148 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory
149 and already relocated to the memory base address. RVAs in the image given
151 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
152 PE/COFF image context for the Image given.
153 @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.
155 @retval EFI_SUCCESS The export directory was found successfully.
156 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
157 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.
158 @retval EFI_NOT_FOUND The image export directory could not be found for this image.
162 GetExportDirectoryInPeCoffImage (
164 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
165 OUT EFI_IMAGE_EXPORT_DIRECTORY
**ImageExportDirectory
169 UINT32 NumberOfRvaAndSizes
;
170 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion
;
171 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
172 EFI_IMAGE_EXPORT_DIRECTORY
*ExportDirectory
;
173 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
175 if (Image
== NULL
|| PeCoffLoaderImageContext
== NULL
|| ImageExportDirectory
== NULL
) {
176 return EFI_INVALID_PARAMETER
;
179 DirectoryEntry
= NULL
;
180 ExportDirectory
= NULL
;
183 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+
184 // image instead of using the Magic field. Some systems might generate a PE32+
185 // image with PE32 magic.
187 switch (PeCoffLoaderImageContext
->Machine
) {
188 case EFI_IMAGE_MACHINE_IA32
:
189 // Todo: Add EFI_IMAGE_MACHINE_ARMT
191 // Assume PE32 image with IA32 Machine field.
193 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
195 case EFI_IMAGE_MACHINE_X64
:
197 // Assume PE32+ image with X64 Machine field
199 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
203 // For unknown Machine field, use Magic in optional header
207 "%a %a: The machine type for this image is not valid for a PRM module.\n",
211 return EFI_UNSUPPORTED
;
214 OptionalHeaderPtrUnion
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*) (
216 PeCoffLoaderImageContext
->PeCoffHeaderOffset
220 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.
222 if (OptionalHeaderPtrUnion
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
223 DEBUG ((DEBUG_ERROR
, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_
, __FUNCTION__
));
224 return EFI_UNSUPPORTED
;
227 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
229 PeCoffLoaderImageContext
->PeCoffHeaderOffset
+
231 sizeof (EFI_IMAGE_FILE_HEADER
) +
232 PeCoffLoaderImageContext
->SizeOfHeaders
234 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
236 // Use the PE32 offset to get the Export Directory Entry
238 NumberOfRvaAndSizes
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
239 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
]);
240 } else if (OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
242 // Use the PE32+ offset get the Export Directory Entry
244 NumberOfRvaAndSizes
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
245 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
]);
247 return EFI_UNSUPPORTED
;
250 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
|| DirectoryEntry
->VirtualAddress
== 0) {
252 // The export directory is not present
254 return EFI_NOT_FOUND
;
255 } else if (((UINT32
) (~0) - DirectoryEntry
->VirtualAddress
) < DirectoryEntry
->Size
) {
257 // The directory address overflows
259 DEBUG ((DEBUG_ERROR
, "%a %a: The export directory entry in this image results in overflow.\n", _DBGMSGID_
, __FUNCTION__
));
260 return EFI_UNSUPPORTED
;
262 DEBUG ((DEBUG_INFO
, "%a %a: Export Directory Entry found in the image at 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, (UINTN
) OptionalHeaderPtrUnion
.Pe32
));
263 DEBUG ((DEBUG_INFO
, " %a %a: Directory Entry Virtual Address = 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, DirectoryEntry
->VirtualAddress
));
265 ExportDirectory
= (EFI_IMAGE_EXPORT_DIRECTORY
*) ((UINTN
) Image
+ DirectoryEntry
->VirtualAddress
);
268 " %a %a: Export Directory Table found successfully at 0x%x. Name address = 0x%x. Name = %a.\n",
271 (UINTN
) ExportDirectory
,
272 ((UINTN
) Image
+ ExportDirectory
->Name
),
273 (CHAR8
*) ((UINTN
) Image
+ ExportDirectory
->Name
)
276 *ImageExportDirectory
= ExportDirectory
;
282 Returns the image major and image minor version in a given PE/COFF image.
284 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory
285 and already relocated to the memory base address. RVAs in the image given
287 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
288 PE/COFF image context for the Image given.
289 @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.
290 @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.
292 @retval EFI_SUCCESS The image version was read successfully.
293 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
294 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.
298 GetImageVersionInPeCoffImage (
300 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
301 OUT UINT16
*ImageMajorVersion
,
302 OUT UINT16
*ImageMinorVersion
305 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion
;
308 DEBUG ((DEBUG_INFO
, " %a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
310 if (Image
== NULL
|| PeCoffLoaderImageContext
== NULL
|| ImageMajorVersion
== NULL
|| ImageMinorVersion
== NULL
) {
311 return EFI_INVALID_PARAMETER
;
315 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+
316 // image instead of using the Magic field. Some systems might generate a PE32+
317 // image with PE32 magic.
319 switch (PeCoffLoaderImageContext
->Machine
) {
320 case EFI_IMAGE_MACHINE_IA32
:
321 // Todo: Add EFI_IMAGE_MACHINE_ARMT
323 // Assume PE32 image with IA32 Machine field.
325 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
327 case EFI_IMAGE_MACHINE_X64
:
329 // Assume PE32+ image with X64 Machine field
331 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
335 // For unknown Machine field, use Magic in optional header
339 "%a %a: The machine type for this image is not valid for a PRM module.\n",
343 return EFI_UNSUPPORTED
;
346 OptionalHeaderPtrUnion
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*) (
348 PeCoffLoaderImageContext
->PeCoffHeaderOffset
351 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.
353 if (OptionalHeaderPtrUnion
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
354 DEBUG ((DEBUG_ERROR
, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_
, __FUNCTION__
));
355 return EFI_UNSUPPORTED
;
358 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
360 // Use the PE32 offset to get the Export Directory Entry
362 *ImageMajorVersion
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.MajorImageVersion
;
363 *ImageMinorVersion
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.MinorImageVersion
;
366 // Use the PE32+ offset to get the Export Directory Entry
368 *ImageMajorVersion
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.MajorImageVersion
;
369 *ImageMinorVersion
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.MinorImageVersion
;
372 DEBUG ((DEBUG_INFO
, " %a %a - Image Major Version: 0x%02x.\n", _DBGMSGID_
, __FUNCTION__
, *ImageMajorVersion
));
373 DEBUG ((DEBUG_INFO
, " %a %a - Image Minor Version: 0x%02x.\n", _DBGMSGID_
, __FUNCTION__
, *ImageMinorVersion
));
379 Creates a new PRM Module Image Context linked list entry.
381 @retval PrmModuleImageContextListEntry If successful, a pointer a PRM Module Image Context linked list entry
382 otherwise, NULL is returned.
386 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*
387 CreateNewPrmModuleImageContextListEntry (
391 PRM_MODULE_IMAGE_CONTEXT
*PrmModuleImageContext
;
392 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*PrmModuleImageContextListEntry
;
394 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
396 PrmModuleImageContext
= AllocateZeroPool (sizeof (*PrmModuleImageContext
));
397 if (PrmModuleImageContext
== NULL
) {
402 " %a %a: Allocated PrmModuleImageContext at 0x%x of size 0x%x bytes.\n",
405 (UINTN
) PrmModuleImageContext
,
406 sizeof (*PrmModuleImageContext
)
409 PrmModuleImageContextListEntry
= AllocateZeroPool (sizeof (*PrmModuleImageContextListEntry
));
410 if (PrmModuleImageContextListEntry
== NULL
) {
411 FreePool (PrmModuleImageContext
);
416 " %a %a: Allocated PrmModuleImageContextListEntry at 0x%x of size 0x%x bytes.\n",
419 (UINTN
) PrmModuleImageContextListEntry
,
420 sizeof (*PrmModuleImageContextListEntry
)
423 PrmModuleImageContextListEntry
->Signature
= PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
;
424 PrmModuleImageContextListEntry
->Context
= PrmModuleImageContext
;
426 return PrmModuleImageContextListEntry
;
430 Discovers all PRM Modules loaded during the DXE boot phase.
432 Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.
434 @retval EFI_SUCCESS All PRM Modules were discovered successfully.
435 @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.
436 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context
446 PRM_MODULE_IMAGE_CONTEXT TempPrmModuleImageContext
;
447 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*PrmModuleImageContextListEntry
;
448 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImageProtocol
;
449 EFI_HANDLE
*HandleBuffer
;
453 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
455 Status
= gBS
->LocateHandleBuffer (
457 &gEfiLoadedImageProtocolGuid
,
462 if (EFI_ERROR (Status
) && (HandleCount
== 0)) {
463 DEBUG ((DEBUG_ERROR
, "%a %a: No LoadedImageProtocol instances found!\n", _DBGMSGID_
, __FUNCTION__
));
464 return EFI_NOT_FOUND
;
467 for (Index
= 0; Index
< HandleCount
; Index
++) {
468 Status
= gBS
->HandleProtocol (
470 &gEfiLoadedImageProtocolGuid
,
471 (VOID
**) &LoadedImageProtocol
473 if (EFI_ERROR (Status
)) {
477 ZeroMem (&TempPrmModuleImageContext
, sizeof (TempPrmModuleImageContext
));
478 TempPrmModuleImageContext
.PeCoffImageContext
.Handle
= LoadedImageProtocol
->ImageBase
;
479 TempPrmModuleImageContext
.PeCoffImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
481 Status
= PeCoffLoaderGetImageInfo (&TempPrmModuleImageContext
.PeCoffImageContext
);
482 if (EFI_ERROR (Status
) || TempPrmModuleImageContext
.PeCoffImageContext
.ImageError
!= IMAGE_ERROR_SUCCESS
) {
485 "%a %a: ImageHandle 0x%016lx is not a valid PE/COFF image. It cannot be considered a PRM module.\n",
488 (EFI_PHYSICAL_ADDRESS
) (UINTN
) LoadedImageProtocol
->ImageBase
492 if (TempPrmModuleImageContext
.PeCoffImageContext
.IsTeImage
) {
493 // A PRM Module is not allowed to be a TE image
497 // Attempt to find an export table in this image
498 Status
= GetExportDirectoryInPeCoffImage (
499 LoadedImageProtocol
->ImageBase
,
500 &TempPrmModuleImageContext
.PeCoffImageContext
,
501 &TempPrmModuleImageContext
.ExportDirectory
503 if (EFI_ERROR (Status
)) {
507 // Attempt to find the PRM Module Export Descriptor in the export table
508 Status
= GetPrmModuleExportDescriptorTable (
509 TempPrmModuleImageContext
.ExportDirectory
,
510 &TempPrmModuleImageContext
.PeCoffImageContext
,
511 &TempPrmModuleImageContext
.ExportDescriptor
513 if (EFI_ERROR (Status
)) {
516 // A PRM Module Export Descriptor was successfully found, this is considered a PRM Module.
519 // Create a new PRM Module image context node
521 PrmModuleImageContextListEntry
= CreateNewPrmModuleImageContextListEntry ();
522 if (PrmModuleImageContextListEntry
== NULL
) {
523 return EFI_OUT_OF_RESOURCES
;
526 PrmModuleImageContextListEntry
->Context
,
527 &TempPrmModuleImageContext
,
528 sizeof (*(PrmModuleImageContextListEntry
->Context
))
530 InsertTailList (&mPrmModuleList
, &PrmModuleImageContextListEntry
->Link
);
531 mPrmHandlerCount
+= TempPrmModuleImageContext
.ExportDescriptor
->NumberPrmHandlers
;
532 mPrmModuleCount
++; // Todo: Match with global variable refactor change in the future
533 DEBUG ((DEBUG_INFO
, "%a %a: New PRM Module inserted into list to be processed.\n", _DBGMSGID_
, __FUNCTION__
));
540 Gets the address of an entry in an image export table by ASCII name.
542 @param[in] ExportName A pointer to an ASCII name string of the entry name.
543 @param[in] ImageBaseAddress The base address of the PE/COFF image.
544 @param[in] ImageExportDirectory A pointer to the export directory in the image.
545 @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the
546 export entry if found.
548 @retval EFI_SUCCESS The export entry was found successfully.
549 @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.
550 @retval EFI_NOT_FOUND An entry with the given ExportName was not found.
554 GetExportEntryAddress (
555 IN CONST CHAR8
*ExportName
,
556 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
557 IN EFI_IMAGE_EXPORT_DIRECTORY
*ImageExportDirectory
,
558 OUT EFI_PHYSICAL_ADDRESS
*ExportPhysicalAddress
561 UINTN ExportNameIndex
;
562 UINT16 CurrentExportOrdinal
;
563 UINT32
*ExportAddressTable
;
564 UINT32
*ExportNamePointerTable
;
565 UINT16
*OrdinalTable
;
566 CONST CHAR8
*ExportNameTablePointerName
;
568 if (ExportName
== NULL
|| ImageBaseAddress
== 0 || ImageExportDirectory
== NULL
|| ExportPhysicalAddress
== NULL
) {
569 return EFI_INVALID_PARAMETER
;
571 *ExportPhysicalAddress
= 0;
573 ExportAddressTable
= (UINT32
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfFunctions
);
574 ExportNamePointerTable
= (UINT32
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfNames
);
575 OrdinalTable
= (UINT16
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfNameOrdinals
);
577 for (ExportNameIndex
= 0; ExportNameIndex
< ImageExportDirectory
->NumberOfNames
; ExportNameIndex
++) {
578 ExportNameTablePointerName
= (CONST CHAR8
*) ((UINTN
) ImageBaseAddress
+ ExportNamePointerTable
[ExportNameIndex
]);
580 if (AsciiStrnCmp (ExportName
, ExportNameTablePointerName
, PRM_HANDLER_NAME_MAXIMUM_LENGTH
) == 0) {
581 CurrentExportOrdinal
= OrdinalTable
[ExportNameIndex
];
583 ASSERT (CurrentExportOrdinal
< ImageExportDirectory
->NumberOfFunctions
);
584 if (CurrentExportOrdinal
>= ImageExportDirectory
->NumberOfFunctions
) {
585 DEBUG ((DEBUG_ERROR
, " %a %a: The export ordinal value is invalid.\n", _DBGMSGID_
, __FUNCTION__
));
589 *ExportPhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) ImageBaseAddress
+ ExportAddressTable
[CurrentExportOrdinal
]);
594 return EFI_NOT_FOUND
;
598 Processes a list of PRM context entries to build a PRM ACPI table.
600 The ACPI table buffer is allocated and the table structure is built inside this function.
602 @param[out] PrmAcpiDescriptionTable A pointer to a pointer to a buffer that is allocated within this function
603 and will contain the PRM ACPI table. In case of an error in this function,
604 *PrmAcpiDescriptorTable will be NULL.
606 @retval EFI_SUCCESS All PRM Modules were processed to construct the PRM ACPI table successfully.
607 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL.
608 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table boot services
614 OUT PRM_ACPI_DESCRIPTION_TABLE
**PrmAcpiDescriptionTable
617 EFI_IMAGE_EXPORT_DIRECTORY
*CurrentImageExportDirectory
;
618 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*CurrentExportDescriptorStruct
;
620 PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiTable
;
621 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*TempListEntry
;
622 CONST CHAR8
*CurrentExportDescriptorHandlerName
;
624 PRM_CONTEXT_BUFFER
*CurrentContextBuffer
;
625 PRM_MODULE_CONTEXT_BUFFERS
*CurrentModuleContextBuffers
;
626 PRM_MODULE_INFORMATION_STRUCT
*CurrentModuleInfoStruct
;
627 PRM_HANDLER_INFORMATION_STRUCT
*CurrentHandlerInfoStruct
;
630 EFI_PHYSICAL_ADDRESS CurrentImageAddress
;
632 UINT32 PrmAcpiDescriptionTableBufferSize
;
634 UINT64 HandlerPhysicalAddress
;
636 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
638 if (PrmAcpiDescriptionTable
== NULL
) {
639 return EFI_INVALID_PARAMETER
;
642 *PrmAcpiDescriptionTable
= NULL
;
644 DEBUG ((DEBUG_INFO
, " %a %a: %d total PRM modules to process.\n", _DBGMSGID_
, __FUNCTION__
, mPrmModuleCount
));
645 DEBUG ((DEBUG_INFO
, " %a %a: %d total PRM handlers to process.\n", _DBGMSGID_
, __FUNCTION__
, mPrmHandlerCount
));
647 PrmAcpiDescriptionTableBufferSize
= (OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE
, PrmModuleInfoStructure
) +
648 (OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
) * mPrmModuleCount
) +
649 (sizeof (PRM_HANDLER_INFORMATION_STRUCT
) * mPrmHandlerCount
)
651 DEBUG ((DEBUG_INFO
, " %a %a: Total PRM ACPI table size: 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, PrmAcpiDescriptionTableBufferSize
));
653 PrmAcpiTable
= AllocateZeroPool ((UINTN
) PrmAcpiDescriptionTableBufferSize
);
654 if (PrmAcpiTable
== NULL
) {
655 return EFI_OUT_OF_RESOURCES
;
658 PrmAcpiTable
->Header
.Signature
= PRM_TABLE_SIGNATURE
;
659 PrmAcpiTable
->Header
.Length
= PrmAcpiDescriptionTableBufferSize
;
660 PrmAcpiTable
->Header
.Revision
= PRM_TABLE_REVISION
;
661 PrmAcpiTable
->Header
.Checksum
= 0x0;
662 CopyMem (&PrmAcpiTable
->Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (PrmAcpiTable
->Header
.OemId
));
663 PrmAcpiTable
->Header
.OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
664 PrmAcpiTable
->Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
665 PrmAcpiTable
->Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
666 PrmAcpiTable
->Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
667 PrmAcpiTable
->PrmModuleInfoOffset
= OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE
, PrmModuleInfoStructure
);
668 PrmAcpiTable
->PrmModuleInfoCount
= mPrmModuleCount
;
671 // Iterate across all PRM Modules on the list
673 CurrentModuleInfoStruct
= &PrmAcpiTable
->PrmModuleInfoStructure
[0];
674 EFI_LIST_FOR_EACH(Link
, &mPrmModuleList
)
676 TempListEntry
= CR(Link
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
, Link
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
);
677 CurrentImageAddress
= TempListEntry
->Context
->PeCoffImageContext
.ImageAddress
;
678 CurrentImageExportDirectory
= TempListEntry
->Context
->ExportDirectory
;
679 CurrentExportDescriptorStruct
= TempListEntry
->Context
->ExportDescriptor
;
683 " %a %a: PRM Module - %a with %d handlers.\n",
686 (CHAR8
*) ((UINTN
) CurrentImageAddress
+ CurrentImageExportDirectory
->Name
),
687 CurrentExportDescriptorStruct
->NumberPrmHandlers
690 CurrentModuleInfoStruct
->StructureRevision
= PRM_MODULE_INFORMATION_STRUCT_REVISION
;
691 CurrentModuleInfoStruct
->StructureLength
= (
692 OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
) +
693 (CurrentExportDescriptorStruct
->NumberPrmHandlers
* sizeof (PRM_HANDLER_INFORMATION_STRUCT
))
695 CopyGuid (&CurrentModuleInfoStruct
->Identifier
, &CurrentExportDescriptorStruct
->ModuleGuid
);
696 CurrentModuleInfoStruct
->HandlerCount
= (UINT32
) CurrentExportDescriptorStruct
->NumberPrmHandlers
;
697 CurrentModuleInfoStruct
->HandlerInfoOffset
= OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
);
699 CurrentModuleInfoStruct
->MajorRevision
= 0;
700 CurrentModuleInfoStruct
->MinorRevision
= 0;
701 Status
= GetImageVersionInPeCoffImage (
702 (VOID
*) (UINTN
) CurrentImageAddress
,
703 &TempListEntry
->Context
->PeCoffImageContext
,
704 &CurrentModuleInfoStruct
->MajorRevision
,
705 &CurrentModuleInfoStruct
->MinorRevision
707 ASSERT_EFI_ERROR (Status
);
709 Status
= GetExportEntryAddress (
710 PRM_STRING (PRM_MODULE_UPDATE_LOCK_DESCRIPTOR_NAME
),
712 CurrentImageExportDirectory
,
713 (EFI_PHYSICAL_ADDRESS
*) &(CurrentModuleInfoStruct
->ModuleUpdateLock
)
715 ASSERT_EFI_ERROR (Status
);
716 if (!EFI_ERROR (Status
)) {
719 " %a %a: Found PRM module update lock physical address at 0x%016x.\n",
722 CurrentModuleInfoStruct
->ModuleUpdateLock
726 // It is currently valid for a PRM module not to use a context buffer
727 Status
= GetModuleContextBuffers (
729 &CurrentModuleInfoStruct
->Identifier
,
730 &CurrentModuleContextBuffers
732 ASSERT (!EFI_ERROR (Status
) || Status
== EFI_NOT_FOUND
);
733 if (!EFI_ERROR (Status
) && CurrentModuleContextBuffers
!= NULL
) {
734 CurrentModuleInfoStruct
->RuntimeMmioRanges
= (UINT64
) (UINTN
) CurrentModuleContextBuffers
->RuntimeMmioRanges
;
738 // Iterate across all PRM handlers in the PRM Module
740 for (HandlerIndex
= 0; HandlerIndex
< CurrentExportDescriptorStruct
->NumberPrmHandlers
; HandlerIndex
++) {
741 CurrentHandlerInfoStruct
= &(CurrentModuleInfoStruct
->HandlerInfoStructure
[HandlerIndex
]);
743 CurrentHandlerInfoStruct
->StructureRevision
= PRM_HANDLER_INFORMATION_STRUCT_REVISION
;
744 CurrentHandlerInfoStruct
->StructureLength
= sizeof (PRM_HANDLER_INFORMATION_STRUCT
);
746 &CurrentHandlerInfoStruct
->Identifier
,
747 &CurrentExportDescriptorStruct
->PrmHandlerExportDescriptors
[HandlerIndex
].PrmHandlerGuid
750 CurrentExportDescriptorHandlerName
= (CONST CHAR8
*) CurrentExportDescriptorStruct
->PrmHandlerExportDescriptors
[HandlerIndex
].PrmHandlerName
;
752 Status
= GetContextBuffer (
753 &CurrentHandlerInfoStruct
->Identifier
,
754 CurrentModuleContextBuffers
,
755 &CurrentContextBuffer
757 if (!EFI_ERROR (Status
)) {
758 CurrentHandlerInfoStruct
->PrmContextBuffer
= (UINT64
) CurrentContextBuffer
;
761 Status
= GetExportEntryAddress (
762 CurrentExportDescriptorHandlerName
,
764 CurrentImageExportDirectory
,
765 &HandlerPhysicalAddress
767 ASSERT_EFI_ERROR (Status
);
768 if (!EFI_ERROR (Status
)) {
769 CurrentHandlerInfoStruct
->PhysicalAddress
= HandlerPhysicalAddress
;
772 " %a %a: Found %a handler physical address at 0x%016x.\n",
775 CurrentExportDescriptorHandlerName
,
776 CurrentHandlerInfoStruct
->PhysicalAddress
780 CurrentModuleInfoStruct
= (PRM_MODULE_INFORMATION_STRUCT
*) ((UINTN
) CurrentModuleInfoStruct
+ CurrentModuleInfoStruct
->StructureLength
);
782 *PrmAcpiDescriptionTable
= PrmAcpiTable
;
788 Publishes the PRM ACPI table (PRMT).
790 @param[in] PrmAcpiDescriptionTable A pointer to a buffer with a completely populated and valid PRM
791 ACPI description table.
793 @retval EFI_SUCCESS The PRM ACPI was installed successfully.
794 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL or the table signature
795 in the table provided is invalid.
796 @retval EFI_NOT_FOUND The protocol gEfiAcpiTableProtocolGuid could not be found.
797 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table buffer.
801 PublishPrmAcpiTable (
802 IN PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiDescriptionTable
806 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
809 if (PrmAcpiDescriptionTable
== NULL
|| PrmAcpiDescriptionTable
->Header
.Signature
!= PRM_TABLE_SIGNATURE
) {
810 return EFI_INVALID_PARAMETER
;
813 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTableProtocol
);
814 if (!EFI_ERROR (Status
)) {
817 // Publish the PRM ACPI table. The table checksum will be computed during installation.
819 Status
= AcpiTableProtocol
->InstallAcpiTable (
821 PrmAcpiDescriptionTable
,
822 PrmAcpiDescriptionTable
->Header
.Length
,
825 if (!EFI_ERROR (Status
)) {
826 DEBUG ((DEBUG_INFO
, "%a %a: The PRMT ACPI table was installed successfully.\n", _DBGMSGID_
, __FUNCTION__
));
829 ASSERT_EFI_ERROR (Status
);
835 The PRM Loader END_OF_DXE protocol notification event handler.
837 All PRM Modules that are eligible for dispatch should have been loaded the DXE Dispatcher at the
838 time of this function invocation.
840 The main responsibilities of the PRM Loader are executed from this function which include 3 phases:
841 1.) Disover PRM Modules - Find all PRM modules loaded during DXE dispatch and insert a PRM Module
842 Context entry into a linked list to be handed off to phase 2.
843 2.) Process PRM Modules - Build a GUID to PRM handler mapping for each module that is described in the
844 PRM ACPI table so the OS can resolve a PRM Handler GUID to the corresponding PRM Handler physical address.
845 3.) Publish PRM ACPI Table - Publish the PRM ACPI table with the information gathered in the phase 2.
847 @param[in] Event Event whose notification function is being invoked.
848 @param[in] Context The pointer to the notification function's context,
849 which is implementation-dependent.
851 @retval EFI_SUCCESS The function executed successfully
856 PrmLoaderEndOfDxeNotification (
862 PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiDescriptionTable
;
864 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
866 InitializeListHead (&mPrmModuleList
);
868 Status
= DiscoverPrmModules ();
869 ASSERT_EFI_ERROR (Status
);
871 Status
= ProcessPrmModules (&PrmAcpiDescriptionTable
);
872 ASSERT_EFI_ERROR (Status
);
874 Status
= PublishPrmAcpiTable (PrmAcpiDescriptionTable
);
875 ASSERT_EFI_ERROR (Status
);
877 if (PrmAcpiDescriptionTable
!= NULL
) {
878 FreePool (PrmAcpiDescriptionTable
);
880 gBS
->CloseEvent (Event
);
886 The entry point for this module.
888 @param ImageHandle The firmware allocated handle for the EFI image.
889 @param SystemTable A pointer to the EFI System Table.
891 @retval EFI_SUCCESS The entry point is executed successfully.
892 @retval Others An error occurred when executing this entry point.
897 PrmLoaderEntryPoint (
898 IN EFI_HANDLE ImageHandle
,
899 IN EFI_SYSTEM_TABLE
*SystemTable
903 EFI_EVENT EndOfDxeEvent
;
905 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
908 // Discover and process installed PRM modules at the End of DXE
909 // The PRM ACPI table is published if one or PRM modules are discovered
911 Status
= gBS
->CreateEventEx(
914 PrmLoaderEndOfDxeNotification
,
916 &gEfiEndOfDxeEventGroupGuid
,
919 if (EFI_ERROR (Status
)) {
920 DEBUG ((DEBUG_ERROR
, "%a %a: EndOfDxe callback registration failed! %r.\n", _DBGMSGID_
, __FUNCTION__
, Status
));
921 ASSERT_EFI_ERROR (Status
);