3 This file contains the implementation for a Platform Runtime Mechanism (PRM)
6 Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) Microsoft Corporation
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include "PrmAcpiTable.h"
13 #include "PrmLoader.h"
15 #include <IndustryStandard/Acpi.h>
16 #include <Library/BaseLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/PrmContextBufferLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 #include <Protocol/AcpiTable.h>
24 #include <Protocol/LoadedImage.h>
25 #include <Protocol/PrmConfig.h>
27 #include <PrmContextBuffer.h>
29 #include <PrmModuleUpdate.h>
31 LIST_ENTRY mPrmModuleList
;
33 // Todo: Potentially refactor mPrmHandlerCount and mPrmModuleCount into localized structures
35 UINT32 mPrmHandlerCount
;
36 UINT32 mPrmModuleCount
;
39 Gets a pointer to the export directory in a given PE/COFF image.
41 @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.
42 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
43 PE/COFF image context for the Image containing the PRM Module Export
45 @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found
46 in the ImageExportDirectory given.
48 @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.
49 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
50 @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given
55 GetPrmModuleExportDescriptorTable (
56 IN EFI_IMAGE_EXPORT_DIRECTORY
*ImageExportDirectory
,
57 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
58 OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
**ExportDescriptor
62 EFI_PHYSICAL_ADDRESS CurrentImageAddress
;
63 UINT16 PrmModuleExportDescriptorOrdinal
;
64 CONST CHAR8
*CurrentExportName
;
66 UINT32
*ExportNamePointerTable
;
67 UINT32
*ExportAddressTable
;
68 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*TempExportDescriptor
;
70 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
72 *ExportDescriptor
= NULL
;
74 if (ImageExportDirectory
== NULL
||
75 PeCoffLoaderImageContext
== NULL
||
76 PeCoffLoaderImageContext
->ImageAddress
== 0 ||
77 ExportDescriptor
== NULL
) {
78 return EFI_INVALID_PARAMETER
;
83 " %a %a: %d exported names found in this image.\n",
86 ImageExportDirectory
->NumberOfNames
90 // The export name pointer table and export ordinal table form two parallel arrays associated by index.
92 CurrentImageAddress
= PeCoffLoaderImageContext
->ImageAddress
;
93 ExportAddressTable
= (UINT32
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfFunctions
);
94 ExportNamePointerTable
= (UINT32
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfNames
);
95 OrdinalTable
= (UINT16
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfNameOrdinals
);
97 for (Index
= 0; Index
< ImageExportDirectory
->NumberOfNames
; Index
++) {
98 CurrentExportName
= (CONST CHAR8
*) ((UINTN
) CurrentImageAddress
+ ExportNamePointerTable
[Index
]);
101 " %a %a: Export Name[0x%x] - %a.\n",
109 PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME
),
111 AsciiStrLen (PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME
))
113 PrmModuleExportDescriptorOrdinal
= OrdinalTable
[Index
];
116 " %a %a: PRM Module Export Descriptor found. Ordinal = %d.\n",
119 PrmModuleExportDescriptorOrdinal
121 if (PrmModuleExportDescriptorOrdinal
>= ImageExportDirectory
->NumberOfFunctions
) {
122 DEBUG ((DEBUG_ERROR
, "%a %a: The PRM Module Export Descriptor ordinal value is invalid.\n", _DBGMSGID_
, __FUNCTION__
));
123 return EFI_NOT_FOUND
;
125 TempExportDescriptor
= (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*) ((UINTN
) CurrentImageAddress
+ ExportAddressTable
[PrmModuleExportDescriptorOrdinal
]);
126 if (TempExportDescriptor
->Header
.Signature
== PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE
) {
127 *ExportDescriptor
= TempExportDescriptor
;
128 DEBUG ((DEBUG_INFO
, " %a %a: PRM Module Export Descriptor found at 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, (UINTN
) ExportDescriptor
));
132 " %a %a: PRM Module Export Descriptor found at 0x%x but signature check failed.\n",
135 (UINTN
) TempExportDescriptor
138 DEBUG ((DEBUG_INFO
, " %a %a: Exiting export iteration since export descriptor found.\n", _DBGMSGID_
, __FUNCTION__
));
143 return EFI_NOT_FOUND
;
147 Gets a pointer to the export directory in a given PE/COFF image.
149 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory
150 and already relocated to the memory base address. RVAs in the image given
152 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
153 PE/COFF image context for the Image given.
154 @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.
156 @retval EFI_SUCCESS The export directory was found successfully.
157 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
158 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.
159 @retval EFI_NOT_FOUND The image export directory could not be found for this image.
163 GetExportDirectoryInPeCoffImage (
165 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
166 OUT EFI_IMAGE_EXPORT_DIRECTORY
**ImageExportDirectory
170 UINT32 NumberOfRvaAndSizes
;
171 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion
;
172 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
173 EFI_IMAGE_EXPORT_DIRECTORY
*ExportDirectory
;
174 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
176 if (Image
== NULL
|| PeCoffLoaderImageContext
== NULL
|| ImageExportDirectory
== NULL
) {
177 return EFI_INVALID_PARAMETER
;
180 DirectoryEntry
= NULL
;
181 ExportDirectory
= NULL
;
184 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+
185 // image instead of using the Magic field. Some systems might generate a PE32+
186 // image with PE32 magic.
188 switch (PeCoffLoaderImageContext
->Machine
) {
189 case EFI_IMAGE_MACHINE_IA32
:
190 // Todo: Add EFI_IMAGE_MACHINE_ARMT
192 // Assume PE32 image with IA32 Machine field.
194 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
196 case EFI_IMAGE_MACHINE_X64
:
198 // Assume PE32+ image with X64 Machine field
200 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
204 // For unknown Machine field, use Magic in optional header
208 "%a %a: The machine type for this image is not valid for a PRM module.\n",
212 return EFI_UNSUPPORTED
;
215 OptionalHeaderPtrUnion
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*) (
217 PeCoffLoaderImageContext
->PeCoffHeaderOffset
221 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.
223 if (OptionalHeaderPtrUnion
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
224 DEBUG ((DEBUG_ERROR
, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_
, __FUNCTION__
));
225 return EFI_UNSUPPORTED
;
228 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
230 PeCoffLoaderImageContext
->PeCoffHeaderOffset
+
232 sizeof (EFI_IMAGE_FILE_HEADER
) +
233 PeCoffLoaderImageContext
->SizeOfHeaders
235 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
237 // Use the PE32 offset to get the Export Directory Entry
239 NumberOfRvaAndSizes
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
240 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
]);
241 } else if (OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
243 // Use the PE32+ offset get the Export Directory Entry
245 NumberOfRvaAndSizes
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
246 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
]);
248 return EFI_UNSUPPORTED
;
251 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
|| DirectoryEntry
->VirtualAddress
== 0) {
253 // The export directory is not present
255 return EFI_NOT_FOUND
;
256 } else if (((UINT32
) (~0) - DirectoryEntry
->VirtualAddress
) < DirectoryEntry
->Size
) {
258 // The directory address overflows
260 DEBUG ((DEBUG_ERROR
, "%a %a: The export directory entry in this image results in overflow.\n", _DBGMSGID_
, __FUNCTION__
));
261 return EFI_UNSUPPORTED
;
263 DEBUG ((DEBUG_INFO
, "%a %a: Export Directory Entry found in the image at 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, (UINTN
) OptionalHeaderPtrUnion
.Pe32
));
264 DEBUG ((DEBUG_INFO
, " %a %a: Directory Entry Virtual Address = 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, DirectoryEntry
->VirtualAddress
));
266 ExportDirectory
= (EFI_IMAGE_EXPORT_DIRECTORY
*) ((UINTN
) Image
+ DirectoryEntry
->VirtualAddress
);
269 " %a %a: Export Directory Table found successfully at 0x%x. Name address = 0x%x. Name = %a.\n",
272 (UINTN
) ExportDirectory
,
273 ((UINTN
) Image
+ ExportDirectory
->Name
),
274 (CHAR8
*) ((UINTN
) Image
+ ExportDirectory
->Name
)
277 *ImageExportDirectory
= ExportDirectory
;
283 Returns the image major and image minor version in a given PE/COFF image.
285 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory
286 and already relocated to the memory base address. RVAs in the image given
288 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
289 PE/COFF image context for the Image given.
290 @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.
291 @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.
293 @retval EFI_SUCCESS The image version was read successfully.
294 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
295 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.
299 GetImageVersionInPeCoffImage (
301 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
302 OUT UINT16
*ImageMajorVersion
,
303 OUT UINT16
*ImageMinorVersion
306 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion
;
309 DEBUG ((DEBUG_INFO
, " %a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
311 if (Image
== NULL
|| PeCoffLoaderImageContext
== NULL
|| ImageMajorVersion
== NULL
|| ImageMinorVersion
== NULL
) {
312 return EFI_INVALID_PARAMETER
;
316 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+
317 // image instead of using the Magic field. Some systems might generate a PE32+
318 // image with PE32 magic.
320 switch (PeCoffLoaderImageContext
->Machine
) {
321 case EFI_IMAGE_MACHINE_IA32
:
322 // Todo: Add EFI_IMAGE_MACHINE_ARMT
324 // Assume PE32 image with IA32 Machine field.
326 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
328 case EFI_IMAGE_MACHINE_X64
:
330 // Assume PE32+ image with X64 Machine field
332 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
336 // For unknown Machine field, use Magic in optional header
340 "%a %a: The machine type for this image is not valid for a PRM module.\n",
344 return EFI_UNSUPPORTED
;
347 OptionalHeaderPtrUnion
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*) (
349 PeCoffLoaderImageContext
->PeCoffHeaderOffset
352 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.
354 if (OptionalHeaderPtrUnion
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
355 DEBUG ((DEBUG_ERROR
, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_
, __FUNCTION__
));
356 return EFI_UNSUPPORTED
;
359 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
361 // Use the PE32 offset to get the Export Directory Entry
363 *ImageMajorVersion
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.MajorImageVersion
;
364 *ImageMinorVersion
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.MinorImageVersion
;
367 // Use the PE32+ offset to get the Export Directory Entry
369 *ImageMajorVersion
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.MajorImageVersion
;
370 *ImageMinorVersion
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.MinorImageVersion
;
373 DEBUG ((DEBUG_INFO
, " %a %a - Image Major Version: 0x%02x.\n", _DBGMSGID_
, __FUNCTION__
, *ImageMajorVersion
));
374 DEBUG ((DEBUG_INFO
, " %a %a - Image Minor Version: 0x%02x.\n", _DBGMSGID_
, __FUNCTION__
, *ImageMinorVersion
));
380 Creates a new PRM Module Image Context linked list entry.
382 @retval PrmModuleImageContextListEntry If successful, a pointer a PRM Module Image Context linked list entry
383 otherwise, NULL is returned.
387 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*
388 CreateNewPrmModuleImageContextListEntry (
392 PRM_MODULE_IMAGE_CONTEXT
*PrmModuleImageContext
;
393 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*PrmModuleImageContextListEntry
;
395 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
397 PrmModuleImageContext
= AllocateZeroPool (sizeof (*PrmModuleImageContext
));
398 if (PrmModuleImageContext
== NULL
) {
403 " %a %a: Allocated PrmModuleImageContext at 0x%x of size 0x%x bytes.\n",
406 (UINTN
) PrmModuleImageContext
,
407 sizeof (*PrmModuleImageContext
)
410 PrmModuleImageContextListEntry
= AllocateZeroPool (sizeof (*PrmModuleImageContextListEntry
));
411 if (PrmModuleImageContextListEntry
== NULL
) {
412 FreePool (PrmModuleImageContext
);
417 " %a %a: Allocated PrmModuleImageContextListEntry at 0x%x of size 0x%x bytes.\n",
420 (UINTN
) PrmModuleImageContextListEntry
,
421 sizeof (*PrmModuleImageContextListEntry
)
424 PrmModuleImageContextListEntry
->Signature
= PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
;
425 PrmModuleImageContextListEntry
->Context
= PrmModuleImageContext
;
427 return PrmModuleImageContextListEntry
;
431 Discovers all PRM Modules loaded during the DXE boot phase.
433 Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.
435 @retval EFI_SUCCESS All PRM Modules were discovered successfully.
436 @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.
437 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context
447 PRM_MODULE_IMAGE_CONTEXT TempPrmModuleImageContext
;
448 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*PrmModuleImageContextListEntry
;
449 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImageProtocol
;
450 EFI_HANDLE
*HandleBuffer
;
454 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
456 Status
= gBS
->LocateHandleBuffer (
458 &gEfiLoadedImageProtocolGuid
,
463 if (EFI_ERROR (Status
) && (HandleCount
== 0)) {
464 DEBUG ((DEBUG_ERROR
, "%a %a: No LoadedImageProtocol instances found!\n", _DBGMSGID_
, __FUNCTION__
));
465 return EFI_NOT_FOUND
;
468 for (Index
= 0; Index
< HandleCount
; Index
++) {
469 Status
= gBS
->HandleProtocol (
471 &gEfiLoadedImageProtocolGuid
,
472 (VOID
**) &LoadedImageProtocol
474 if (EFI_ERROR (Status
)) {
478 ZeroMem (&TempPrmModuleImageContext
, sizeof (TempPrmModuleImageContext
));
479 TempPrmModuleImageContext
.PeCoffImageContext
.Handle
= LoadedImageProtocol
->ImageBase
;
480 TempPrmModuleImageContext
.PeCoffImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
482 Status
= PeCoffLoaderGetImageInfo (&TempPrmModuleImageContext
.PeCoffImageContext
);
483 if (EFI_ERROR (Status
) || TempPrmModuleImageContext
.PeCoffImageContext
.ImageError
!= IMAGE_ERROR_SUCCESS
) {
486 "%a %a: ImageHandle 0x%016lx is not a valid PE/COFF image. It cannot be considered a PRM module.\n",
489 (EFI_PHYSICAL_ADDRESS
) (UINTN
) LoadedImageProtocol
->ImageBase
493 if (TempPrmModuleImageContext
.PeCoffImageContext
.IsTeImage
) {
494 // A PRM Module is not allowed to be a TE image
498 // Attempt to find an export table in this image
499 Status
= GetExportDirectoryInPeCoffImage (
500 LoadedImageProtocol
->ImageBase
,
501 &TempPrmModuleImageContext
.PeCoffImageContext
,
502 &TempPrmModuleImageContext
.ExportDirectory
504 if (EFI_ERROR (Status
)) {
508 // Attempt to find the PRM Module Export Descriptor in the export table
509 Status
= GetPrmModuleExportDescriptorTable (
510 TempPrmModuleImageContext
.ExportDirectory
,
511 &TempPrmModuleImageContext
.PeCoffImageContext
,
512 &TempPrmModuleImageContext
.ExportDescriptor
514 if (EFI_ERROR (Status
)) {
517 // A PRM Module Export Descriptor was successfully found, this is considered a PRM Module.
520 // Create a new PRM Module image context node
522 PrmModuleImageContextListEntry
= CreateNewPrmModuleImageContextListEntry ();
523 if (PrmModuleImageContextListEntry
== NULL
) {
524 return EFI_OUT_OF_RESOURCES
;
527 PrmModuleImageContextListEntry
->Context
,
528 &TempPrmModuleImageContext
,
529 sizeof (*(PrmModuleImageContextListEntry
->Context
))
531 InsertTailList (&mPrmModuleList
, &PrmModuleImageContextListEntry
->Link
);
532 mPrmHandlerCount
+= TempPrmModuleImageContext
.ExportDescriptor
->Header
.NumberPrmHandlers
;
533 mPrmModuleCount
++; // Todo: Match with global variable refactor change in the future
534 DEBUG ((DEBUG_INFO
, "%a %a: New PRM Module inserted into list to be processed.\n", _DBGMSGID_
, __FUNCTION__
));
541 Gets the address of an entry in an image export table by ASCII name.
543 @param[in] ExportName A pointer to an ASCII name string of the entry name.
544 @param[in] ImageBaseAddress The base address of the PE/COFF image.
545 @param[in] ImageExportDirectory A pointer to the export directory in the image.
546 @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the
547 export entry if found.
549 @retval EFI_SUCCESS The export entry was found successfully.
550 @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.
551 @retval EFI_NOT_FOUND An entry with the given ExportName was not found.
555 GetExportEntryAddress (
556 IN CONST CHAR8
*ExportName
,
557 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
558 IN EFI_IMAGE_EXPORT_DIRECTORY
*ImageExportDirectory
,
559 OUT EFI_PHYSICAL_ADDRESS
*ExportPhysicalAddress
562 UINTN ExportNameIndex
;
563 UINT16 CurrentExportOrdinal
;
564 UINT32
*ExportAddressTable
;
565 UINT32
*ExportNamePointerTable
;
566 UINT16
*OrdinalTable
;
567 CONST CHAR8
*ExportNameTablePointerName
;
569 if (ExportName
== NULL
|| ImageBaseAddress
== 0 || ImageExportDirectory
== NULL
|| ExportPhysicalAddress
== NULL
) {
570 return EFI_INVALID_PARAMETER
;
572 *ExportPhysicalAddress
= 0;
574 ExportAddressTable
= (UINT32
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfFunctions
);
575 ExportNamePointerTable
= (UINT32
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfNames
);
576 OrdinalTable
= (UINT16
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfNameOrdinals
);
578 for (ExportNameIndex
= 0; ExportNameIndex
< ImageExportDirectory
->NumberOfNames
; ExportNameIndex
++) {
579 ExportNameTablePointerName
= (CONST CHAR8
*) ((UINTN
) ImageBaseAddress
+ ExportNamePointerTable
[ExportNameIndex
]);
581 if (AsciiStrnCmp (ExportName
, ExportNameTablePointerName
, PRM_HANDLER_NAME_MAXIMUM_LENGTH
) == 0) {
582 CurrentExportOrdinal
= OrdinalTable
[ExportNameIndex
];
584 ASSERT (CurrentExportOrdinal
< ImageExportDirectory
->NumberOfFunctions
);
585 if (CurrentExportOrdinal
>= ImageExportDirectory
->NumberOfFunctions
) {
586 DEBUG ((DEBUG_ERROR
, " %a %a: The export ordinal value is invalid.\n", _DBGMSGID_
, __FUNCTION__
));
590 *ExportPhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) ImageBaseAddress
+ ExportAddressTable
[CurrentExportOrdinal
]);
595 return EFI_NOT_FOUND
;
599 Processes a list of PRM context entries to build a PRM ACPI table.
601 The ACPI table buffer is allocated and the table structure is built inside this function.
603 @param[out] PrmAcpiDescriptionTable A pointer to a pointer to a buffer that is allocated within this function
604 and will contain the PRM ACPI table. In case of an error in this function,
605 *PrmAcpiDescriptorTable will be NULL.
607 @retval EFI_SUCCESS All PRM Modules were processed to construct the PRM ACPI table successfully.
608 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL.
609 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table boot services
615 OUT PRM_ACPI_DESCRIPTION_TABLE
**PrmAcpiDescriptionTable
618 EFI_IMAGE_EXPORT_DIRECTORY
*CurrentImageExportDirectory
;
619 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*CurrentExportDescriptorStruct
;
621 PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiTable
;
622 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*TempListEntry
;
623 CONST CHAR8
*CurrentExportDescriptorHandlerName
;
625 PRM_CONTEXT_BUFFER
*CurrentContextBuffer
;
626 PRM_MODULE_CONTEXT_BUFFERS
*CurrentModuleContextBuffers
;
627 PRM_MODULE_INFORMATION_STRUCT
*CurrentModuleInfoStruct
;
628 PRM_HANDLER_INFORMATION_STRUCT
*CurrentHandlerInfoStruct
;
631 EFI_PHYSICAL_ADDRESS CurrentImageAddress
;
633 UINT32 PrmAcpiDescriptionTableBufferSize
;
635 UINT64 HandlerPhysicalAddress
;
637 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
639 if (PrmAcpiDescriptionTable
== NULL
) {
640 return EFI_INVALID_PARAMETER
;
643 *PrmAcpiDescriptionTable
= NULL
;
645 DEBUG ((DEBUG_INFO
, " %a %a: %d total PRM modules to process.\n", _DBGMSGID_
, __FUNCTION__
, mPrmModuleCount
));
646 DEBUG ((DEBUG_INFO
, " %a %a: %d total PRM handlers to process.\n", _DBGMSGID_
, __FUNCTION__
, mPrmHandlerCount
));
648 PrmAcpiDescriptionTableBufferSize
= (OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE
, PrmModuleInfoStructure
) +
649 (OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
) * mPrmModuleCount
) +
650 (sizeof (PRM_HANDLER_INFORMATION_STRUCT
) * mPrmHandlerCount
)
652 DEBUG ((DEBUG_INFO
, " %a %a: Total PRM ACPI table size: 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, PrmAcpiDescriptionTableBufferSize
));
654 PrmAcpiTable
= AllocateZeroPool ((UINTN
) PrmAcpiDescriptionTableBufferSize
);
655 if (PrmAcpiTable
== NULL
) {
656 return EFI_OUT_OF_RESOURCES
;
659 PrmAcpiTable
->Header
.Signature
= PRM_TABLE_SIGNATURE
;
660 PrmAcpiTable
->Header
.Length
= PrmAcpiDescriptionTableBufferSize
;
661 PrmAcpiTable
->Header
.Revision
= PRM_TABLE_REVISION
;
662 PrmAcpiTable
->Header
.Checksum
= 0x0;
663 CopyMem (&PrmAcpiTable
->Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (PrmAcpiTable
->Header
.OemId
));
664 PrmAcpiTable
->Header
.OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
665 PrmAcpiTable
->Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
666 PrmAcpiTable
->Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
667 PrmAcpiTable
->Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
668 PrmAcpiTable
->PrmModuleInfoOffset
= OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE
, PrmModuleInfoStructure
);
669 PrmAcpiTable
->PrmModuleInfoCount
= mPrmModuleCount
;
672 // Iterate across all PRM Modules on the list
674 CurrentModuleInfoStruct
= &PrmAcpiTable
->PrmModuleInfoStructure
[0];
675 EFI_LIST_FOR_EACH(Link
, &mPrmModuleList
)
677 TempListEntry
= CR(Link
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
, Link
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
);
678 CurrentImageAddress
= TempListEntry
->Context
->PeCoffImageContext
.ImageAddress
;
679 CurrentImageExportDirectory
= TempListEntry
->Context
->ExportDirectory
;
680 CurrentExportDescriptorStruct
= TempListEntry
->Context
->ExportDescriptor
;
684 " %a %a: PRM Module - %a with %d handlers.\n",
687 (CHAR8
*) ((UINTN
) CurrentImageAddress
+ CurrentImageExportDirectory
->Name
),
688 CurrentExportDescriptorStruct
->Header
.NumberPrmHandlers
691 CurrentModuleInfoStruct
->StructureRevision
= PRM_MODULE_INFORMATION_STRUCT_REVISION
;
692 CurrentModuleInfoStruct
->StructureLength
= (
693 OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
) +
694 (CurrentExportDescriptorStruct
->Header
.NumberPrmHandlers
* sizeof (PRM_HANDLER_INFORMATION_STRUCT
))
696 CopyGuid (&CurrentModuleInfoStruct
->Identifier
, &CurrentExportDescriptorStruct
->Header
.ModuleGuid
);
697 CurrentModuleInfoStruct
->HandlerCount
= (UINT32
) CurrentExportDescriptorStruct
->Header
.NumberPrmHandlers
;
698 CurrentModuleInfoStruct
->HandlerInfoOffset
= OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
);
700 CurrentModuleInfoStruct
->MajorRevision
= 0;
701 CurrentModuleInfoStruct
->MinorRevision
= 0;
702 Status
= GetImageVersionInPeCoffImage (
703 (VOID
*) (UINTN
) CurrentImageAddress
,
704 &TempListEntry
->Context
->PeCoffImageContext
,
705 &CurrentModuleInfoStruct
->MajorRevision
,
706 &CurrentModuleInfoStruct
->MinorRevision
708 ASSERT_EFI_ERROR (Status
);
710 Status
= GetExportEntryAddress (
711 PRM_STRING (PRM_MODULE_UPDATE_LOCK_DESCRIPTOR_NAME
),
713 CurrentImageExportDirectory
,
714 (EFI_PHYSICAL_ADDRESS
*) &(CurrentModuleInfoStruct
->ModuleUpdateLock
)
716 ASSERT_EFI_ERROR (Status
);
717 if (!EFI_ERROR (Status
)) {
720 " %a %a: Found PRM module update lock physical address at 0x%016x.\n",
723 CurrentModuleInfoStruct
->ModuleUpdateLock
727 // It is currently valid for a PRM module not to use a context buffer
728 Status
= GetModuleContextBuffers (
730 &CurrentModuleInfoStruct
->Identifier
,
731 &CurrentModuleContextBuffers
733 ASSERT (!EFI_ERROR (Status
) || Status
== EFI_NOT_FOUND
);
734 if (!EFI_ERROR (Status
) && CurrentModuleContextBuffers
!= NULL
) {
735 CurrentModuleInfoStruct
->RuntimeMmioRanges
= (UINT64
) (UINTN
) CurrentModuleContextBuffers
->RuntimeMmioRanges
;
739 // Iterate across all PRM handlers in the PRM Module
741 for (HandlerIndex
= 0; HandlerIndex
< CurrentExportDescriptorStruct
->Header
.NumberPrmHandlers
; HandlerIndex
++) {
742 CurrentHandlerInfoStruct
= &(CurrentModuleInfoStruct
->HandlerInfoStructure
[HandlerIndex
]);
744 CurrentHandlerInfoStruct
->StructureRevision
= PRM_HANDLER_INFORMATION_STRUCT_REVISION
;
745 CurrentHandlerInfoStruct
->StructureLength
= sizeof (PRM_HANDLER_INFORMATION_STRUCT
);
747 &CurrentHandlerInfoStruct
->Identifier
,
748 &CurrentExportDescriptorStruct
->PrmHandlerExportDescriptors
[HandlerIndex
].PrmHandlerGuid
751 CurrentExportDescriptorHandlerName
= (CONST CHAR8
*) CurrentExportDescriptorStruct
->PrmHandlerExportDescriptors
[HandlerIndex
].PrmHandlerName
;
753 Status
= GetContextBuffer (
754 &CurrentHandlerInfoStruct
->Identifier
,
755 CurrentModuleContextBuffers
,
756 &CurrentContextBuffer
758 if (!EFI_ERROR (Status
)) {
759 #ifdef ALLOCATE_CONTEXT_BUFFER_IN_FW
760 CurrentHandlerInfoStruct
->PrmContextBuffer
= (UINT64
) (UINTN
) CurrentContextBuffer
;
762 CurrentHandlerInfoStruct
->StaticDataBuffer
= (UINT64
) (UINTN
) CurrentContextBuffer
->StaticDataBuffer
;
766 Status
= GetExportEntryAddress (
767 CurrentExportDescriptorHandlerName
,
769 CurrentImageExportDirectory
,
770 &HandlerPhysicalAddress
772 ASSERT_EFI_ERROR (Status
);
773 if (!EFI_ERROR (Status
)) {
774 CurrentHandlerInfoStruct
->PhysicalAddress
= HandlerPhysicalAddress
;
777 " %a %a: Found %a handler physical address at 0x%016x.\n",
780 CurrentExportDescriptorHandlerName
,
781 CurrentHandlerInfoStruct
->PhysicalAddress
785 CurrentModuleInfoStruct
= (PRM_MODULE_INFORMATION_STRUCT
*) ((UINTN
) CurrentModuleInfoStruct
+ CurrentModuleInfoStruct
->StructureLength
);
787 *PrmAcpiDescriptionTable
= PrmAcpiTable
;
793 Publishes the PRM ACPI table (PRMT).
795 @param[in] PrmAcpiDescriptionTable A pointer to a buffer with a completely populated and valid PRM
796 ACPI description table.
798 @retval EFI_SUCCESS The PRM ACPI was installed successfully.
799 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL or the table signature
800 in the table provided is invalid.
801 @retval EFI_NOT_FOUND The protocol gEfiAcpiTableProtocolGuid could not be found.
802 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table buffer.
806 PublishPrmAcpiTable (
807 IN PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiDescriptionTable
811 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
814 if (PrmAcpiDescriptionTable
== NULL
|| PrmAcpiDescriptionTable
->Header
.Signature
!= PRM_TABLE_SIGNATURE
) {
815 return EFI_INVALID_PARAMETER
;
818 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTableProtocol
);
819 if (!EFI_ERROR (Status
)) {
822 // Publish the PRM ACPI table. The table checksum will be computed during installation.
824 Status
= AcpiTableProtocol
->InstallAcpiTable (
826 PrmAcpiDescriptionTable
,
827 PrmAcpiDescriptionTable
->Header
.Length
,
830 if (!EFI_ERROR (Status
)) {
831 DEBUG ((DEBUG_INFO
, "%a %a: The PRMT ACPI table was installed successfully.\n", _DBGMSGID_
, __FUNCTION__
));
834 ASSERT_EFI_ERROR (Status
);
840 The PRM Loader END_OF_DXE protocol notification event handler.
842 All PRM Modules that are eligible for dispatch should have been loaded the DXE Dispatcher at the
843 time of this function invocation.
845 The main responsibilities of the PRM Loader are executed from this function which include 3 phases:
846 1.) Disover PRM Modules - Find all PRM modules loaded during DXE dispatch and insert a PRM Module
847 Context entry into a linked list to be handed off to phase 2.
848 2.) Process PRM Modules - Build a GUID to PRM handler mapping for each module that is described in the
849 PRM ACPI table so the OS can resolve a PRM Handler GUID to the corresponding PRM Handler physical address.
850 3.) Publish PRM ACPI Table - Publish the PRM ACPI table with the information gathered in the phase 2.
852 @param[in] Event Event whose notification function is being invoked.
853 @param[in] Context The pointer to the notification function's context,
854 which is implementation-dependent.
856 @retval EFI_SUCCESS The function executed successfully
861 PrmLoaderEndOfDxeNotification (
867 PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiDescriptionTable
;
869 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
871 InitializeListHead (&mPrmModuleList
);
873 Status
= DiscoverPrmModules ();
874 ASSERT_EFI_ERROR (Status
);
876 Status
= ProcessPrmModules (&PrmAcpiDescriptionTable
);
877 ASSERT_EFI_ERROR (Status
);
879 Status
= PublishPrmAcpiTable (PrmAcpiDescriptionTable
);
880 ASSERT_EFI_ERROR (Status
);
882 if (PrmAcpiDescriptionTable
!= NULL
) {
883 FreePool (PrmAcpiDescriptionTable
);
885 gBS
->CloseEvent (Event
);
891 The entry point for this module.
893 @param ImageHandle The firmware allocated handle for the EFI image.
894 @param SystemTable A pointer to the EFI System Table.
896 @retval EFI_SUCCESS The entry point is executed successfully.
897 @retval Others An error occurred when executing this entry point.
902 PrmLoaderEntryPoint (
903 IN EFI_HANDLE ImageHandle
,
904 IN EFI_SYSTEM_TABLE
*SystemTable
908 EFI_EVENT EndOfDxeEvent
;
910 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
913 // Discover and process installed PRM modules at the End of DXE
914 // The PRM ACPI table is published if one or PRM modules are discovered
916 Status
= gBS
->CreateEventEx(
919 PrmLoaderEndOfDxeNotification
,
921 &gEfiEndOfDxeEventGroupGuid
,
924 if (EFI_ERROR (Status
)) {
925 DEBUG ((DEBUG_ERROR
, "%a %a: EndOfDxe callback registration failed! %r.\n", _DBGMSGID_
, __FUNCTION__
, Status
));
926 ASSERT_EFI_ERROR (Status
);