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 <Library/DxeServicesLib.h>
24 #include <Protocol/AcpiTable.h>
25 #include <Protocol/LoadedImage.h>
26 #include <Protocol/PrmConfig.h>
28 #include <PrmContextBuffer.h>
30 #include <PrmModuleUpdate.h>
32 LIST_ENTRY mPrmModuleList
;
34 // Todo: Potentially refactor mPrmHandlerCount and mPrmModuleCount into localized structures
36 UINT32 mPrmHandlerCount
;
37 UINT32 mPrmModuleCount
;
40 Gets a pointer to the export directory in a given PE/COFF image.
42 @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.
43 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
44 PE/COFF image context for the Image containing the PRM Module Export
46 @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found
47 in the ImageExportDirectory given.
49 @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.
50 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
51 @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given
56 GetPrmModuleExportDescriptorTable (
57 IN EFI_IMAGE_EXPORT_DIRECTORY
*ImageExportDirectory
,
58 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
59 OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
**ExportDescriptor
63 EFI_PHYSICAL_ADDRESS CurrentImageAddress
;
64 UINT16 PrmModuleExportDescriptorOrdinal
;
65 CONST CHAR8
*CurrentExportName
;
67 UINT32
*ExportNamePointerTable
;
68 UINT32
*ExportAddressTable
;
69 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*TempExportDescriptor
;
71 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
73 *ExportDescriptor
= NULL
;
75 if (ImageExportDirectory
== NULL
||
76 PeCoffLoaderImageContext
== NULL
||
77 PeCoffLoaderImageContext
->ImageAddress
== 0 ||
78 ExportDescriptor
== NULL
) {
79 return EFI_INVALID_PARAMETER
;
84 " %a %a: %d exported names found in this image.\n",
87 ImageExportDirectory
->NumberOfNames
91 // The export name pointer table and export ordinal table form two parallel arrays associated by index.
93 CurrentImageAddress
= PeCoffLoaderImageContext
->ImageAddress
;
94 ExportAddressTable
= (UINT32
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfFunctions
);
95 ExportNamePointerTable
= (UINT32
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfNames
);
96 OrdinalTable
= (UINT16
*) ((UINTN
) CurrentImageAddress
+ ImageExportDirectory
->AddressOfNameOrdinals
);
98 for (Index
= 0; Index
< ImageExportDirectory
->NumberOfNames
; Index
++) {
99 CurrentExportName
= (CONST CHAR8
*) ((UINTN
) CurrentImageAddress
+ ExportNamePointerTable
[Index
]);
102 " %a %a: Export Name[0x%x] - %a.\n",
110 PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME
),
112 AsciiStrLen (PRM_STRING(PRM_MODULE_EXPORT_DESCRIPTOR_NAME
))
114 PrmModuleExportDescriptorOrdinal
= OrdinalTable
[Index
];
117 " %a %a: PRM Module Export Descriptor found. Ordinal = %d.\n",
120 PrmModuleExportDescriptorOrdinal
122 if (PrmModuleExportDescriptorOrdinal
>= ImageExportDirectory
->NumberOfFunctions
) {
123 DEBUG ((DEBUG_ERROR
, "%a %a: The PRM Module Export Descriptor ordinal value is invalid.\n", _DBGMSGID_
, __FUNCTION__
));
124 return EFI_NOT_FOUND
;
126 TempExportDescriptor
= (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*) ((UINTN
) CurrentImageAddress
+ ExportAddressTable
[PrmModuleExportDescriptorOrdinal
]);
127 if (TempExportDescriptor
->Header
.Signature
== PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE
) {
128 *ExportDescriptor
= TempExportDescriptor
;
129 DEBUG ((DEBUG_INFO
, " %a %a: PRM Module Export Descriptor found at 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, (UINTN
) ExportDescriptor
));
133 " %a %a: PRM Module Export Descriptor found at 0x%x but signature check failed.\n",
136 (UINTN
) TempExportDescriptor
139 DEBUG ((DEBUG_INFO
, " %a %a: Exiting export iteration since export descriptor found.\n", _DBGMSGID_
, __FUNCTION__
));
144 return EFI_NOT_FOUND
;
148 Gets a pointer to the export directory in a given PE/COFF image.
150 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory
151 and already relocated to the memory base address. RVAs in the image given
153 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
154 PE/COFF image context for the Image given.
155 @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.
157 @retval EFI_SUCCESS The export directory was found successfully.
158 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
159 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.
160 @retval EFI_NOT_FOUND The image export directory could not be found for this image.
164 GetExportDirectoryInPeCoffImage (
166 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
167 OUT EFI_IMAGE_EXPORT_DIRECTORY
**ImageExportDirectory
171 UINT32 NumberOfRvaAndSizes
;
172 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion
;
173 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
174 EFI_IMAGE_EXPORT_DIRECTORY
*ExportDirectory
;
175 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
177 if (Image
== NULL
|| PeCoffLoaderImageContext
== NULL
|| ImageExportDirectory
== NULL
) {
178 return EFI_INVALID_PARAMETER
;
181 DirectoryEntry
= NULL
;
182 ExportDirectory
= NULL
;
185 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+
186 // image instead of using the Magic field. Some systems might generate a PE32+
187 // image with PE32 magic.
189 switch (PeCoffLoaderImageContext
->Machine
) {
190 case EFI_IMAGE_MACHINE_IA32
:
191 // Todo: Add EFI_IMAGE_MACHINE_ARMT
193 // Assume PE32 image with IA32 Machine field.
195 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
197 case EFI_IMAGE_MACHINE_X64
:
199 // Assume PE32+ image with X64 Machine field
201 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
205 // For unknown Machine field, use Magic in optional header
209 "%a %a: The machine type for this image is not valid for a PRM module.\n",
213 return EFI_UNSUPPORTED
;
216 OptionalHeaderPtrUnion
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*) (
218 PeCoffLoaderImageContext
->PeCoffHeaderOffset
222 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.
224 if (OptionalHeaderPtrUnion
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
225 DEBUG ((DEBUG_ERROR
, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_
, __FUNCTION__
));
226 return EFI_UNSUPPORTED
;
229 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
231 PeCoffLoaderImageContext
->PeCoffHeaderOffset
+
233 sizeof (EFI_IMAGE_FILE_HEADER
) +
234 PeCoffLoaderImageContext
->SizeOfHeaders
236 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
238 // Use the PE32 offset to get the Export Directory Entry
240 NumberOfRvaAndSizes
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
241 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
]);
242 } else if (OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
244 // Use the PE32+ offset get the Export Directory Entry
246 NumberOfRvaAndSizes
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
247 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
]);
249 return EFI_UNSUPPORTED
;
252 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_EXPORT
|| DirectoryEntry
->VirtualAddress
== 0) {
254 // The export directory is not present
256 return EFI_NOT_FOUND
;
257 } else if (((UINT32
) (~0) - DirectoryEntry
->VirtualAddress
) < DirectoryEntry
->Size
) {
259 // The directory address overflows
261 DEBUG ((DEBUG_ERROR
, "%a %a: The export directory entry in this image results in overflow.\n", _DBGMSGID_
, __FUNCTION__
));
262 return EFI_UNSUPPORTED
;
264 DEBUG ((DEBUG_INFO
, "%a %a: Export Directory Entry found in the image at 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, (UINTN
) OptionalHeaderPtrUnion
.Pe32
));
265 DEBUG ((DEBUG_INFO
, " %a %a: Directory Entry Virtual Address = 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, DirectoryEntry
->VirtualAddress
));
267 ExportDirectory
= (EFI_IMAGE_EXPORT_DIRECTORY
*) ((UINTN
) Image
+ DirectoryEntry
->VirtualAddress
);
270 " %a %a: Export Directory Table found successfully at 0x%x. Name address = 0x%x. Name = %a.\n",
273 (UINTN
) ExportDirectory
,
274 ((UINTN
) Image
+ ExportDirectory
->Name
),
275 (CHAR8
*) ((UINTN
) Image
+ ExportDirectory
->Name
)
278 *ImageExportDirectory
= ExportDirectory
;
284 Returns the image major and image minor version in a given PE/COFF image.
286 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory
287 and already relocated to the memory base address. RVAs in the image given
289 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
290 PE/COFF image context for the Image given.
291 @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.
292 @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.
294 @retval EFI_SUCCESS The image version was read successfully.
295 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
296 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.
300 GetImageVersionInPeCoffImage (
302 IN PE_COFF_LOADER_IMAGE_CONTEXT
*PeCoffLoaderImageContext
,
303 OUT UINT16
*ImageMajorVersion
,
304 OUT UINT16
*ImageMinorVersion
307 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion
;
310 DEBUG ((DEBUG_INFO
, " %a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
312 if (Image
== NULL
|| PeCoffLoaderImageContext
== NULL
|| ImageMajorVersion
== NULL
|| ImageMinorVersion
== NULL
) {
313 return EFI_INVALID_PARAMETER
;
317 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+
318 // image instead of using the Magic field. Some systems might generate a PE32+
319 // image with PE32 magic.
321 switch (PeCoffLoaderImageContext
->Machine
) {
322 case EFI_IMAGE_MACHINE_IA32
:
323 // Todo: Add EFI_IMAGE_MACHINE_ARMT
325 // Assume PE32 image with IA32 Machine field.
327 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
329 case EFI_IMAGE_MACHINE_X64
:
331 // Assume PE32+ image with X64 Machine field
333 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
337 // For unknown Machine field, use Magic in optional header
341 "%a %a: The machine type for this image is not valid for a PRM module.\n",
345 return EFI_UNSUPPORTED
;
348 OptionalHeaderPtrUnion
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*) (
350 PeCoffLoaderImageContext
->PeCoffHeaderOffset
353 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.
355 if (OptionalHeaderPtrUnion
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
356 DEBUG ((DEBUG_ERROR
, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_
, __FUNCTION__
));
357 return EFI_UNSUPPORTED
;
360 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
362 // Use the PE32 offset to get the Export Directory Entry
364 *ImageMajorVersion
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.MajorImageVersion
;
365 *ImageMinorVersion
= OptionalHeaderPtrUnion
.Pe32
->OptionalHeader
.MinorImageVersion
;
368 // Use the PE32+ offset to get the Export Directory Entry
370 *ImageMajorVersion
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.MajorImageVersion
;
371 *ImageMinorVersion
= OptionalHeaderPtrUnion
.Pe32Plus
->OptionalHeader
.MinorImageVersion
;
374 DEBUG ((DEBUG_INFO
, " %a %a - Image Major Version: 0x%02x.\n", _DBGMSGID_
, __FUNCTION__
, *ImageMajorVersion
));
375 DEBUG ((DEBUG_INFO
, " %a %a - Image Minor Version: 0x%02x.\n", _DBGMSGID_
, __FUNCTION__
, *ImageMinorVersion
));
381 Creates a new PRM Module Image Context linked list entry.
383 @retval PrmModuleImageContextListEntry If successful, a pointer a PRM Module Image Context linked list entry
384 otherwise, NULL is returned.
388 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*
389 CreateNewPrmModuleImageContextListEntry (
393 PRM_MODULE_IMAGE_CONTEXT
*PrmModuleImageContext
;
394 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*PrmModuleImageContextListEntry
;
396 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
398 PrmModuleImageContext
= AllocateZeroPool (sizeof (*PrmModuleImageContext
));
399 if (PrmModuleImageContext
== NULL
) {
404 " %a %a: Allocated PrmModuleImageContext at 0x%x of size 0x%x bytes.\n",
407 (UINTN
) PrmModuleImageContext
,
408 sizeof (*PrmModuleImageContext
)
411 PrmModuleImageContextListEntry
= AllocateZeroPool (sizeof (*PrmModuleImageContextListEntry
));
412 if (PrmModuleImageContextListEntry
== NULL
) {
413 FreePool (PrmModuleImageContext
);
418 " %a %a: Allocated PrmModuleImageContextListEntry at 0x%x of size 0x%x bytes.\n",
421 (UINTN
) PrmModuleImageContextListEntry
,
422 sizeof (*PrmModuleImageContextListEntry
)
425 PrmModuleImageContextListEntry
->Signature
= PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
;
426 PrmModuleImageContextListEntry
->Context
= PrmModuleImageContext
;
428 return PrmModuleImageContextListEntry
;
432 Discovers all PRM Modules loaded during the DXE boot phase.
434 Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.
436 @retval EFI_SUCCESS All PRM Modules were discovered successfully.
437 @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.
438 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context
448 PRM_MODULE_IMAGE_CONTEXT TempPrmModuleImageContext
;
449 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*PrmModuleImageContextListEntry
;
450 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImageProtocol
;
451 EFI_HANDLE
*HandleBuffer
;
455 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
457 Status
= gBS
->LocateHandleBuffer (
459 &gEfiLoadedImageProtocolGuid
,
464 if (EFI_ERROR (Status
) && (HandleCount
== 0)) {
465 DEBUG ((DEBUG_ERROR
, "%a %a: No LoadedImageProtocol instances found!\n", _DBGMSGID_
, __FUNCTION__
));
466 return EFI_NOT_FOUND
;
469 for (Index
= 0; Index
< HandleCount
; Index
++) {
470 Status
= gBS
->HandleProtocol (
472 &gEfiLoadedImageProtocolGuid
,
473 (VOID
**) &LoadedImageProtocol
475 if (EFI_ERROR (Status
)) {
479 ZeroMem (&TempPrmModuleImageContext
, sizeof (TempPrmModuleImageContext
));
480 TempPrmModuleImageContext
.PeCoffImageContext
.Handle
= LoadedImageProtocol
->ImageBase
;
481 TempPrmModuleImageContext
.PeCoffImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
483 Status
= PeCoffLoaderGetImageInfo (&TempPrmModuleImageContext
.PeCoffImageContext
);
484 if (EFI_ERROR (Status
) || TempPrmModuleImageContext
.PeCoffImageContext
.ImageError
!= IMAGE_ERROR_SUCCESS
) {
487 "%a %a: ImageHandle 0x%016lx is not a valid PE/COFF image. It cannot be considered a PRM module.\n",
490 (EFI_PHYSICAL_ADDRESS
) (UINTN
) LoadedImageProtocol
->ImageBase
494 if (TempPrmModuleImageContext
.PeCoffImageContext
.IsTeImage
) {
495 // A PRM Module is not allowed to be a TE image
499 // Attempt to find an export table in this image
500 Status
= GetExportDirectoryInPeCoffImage (
501 LoadedImageProtocol
->ImageBase
,
502 &TempPrmModuleImageContext
.PeCoffImageContext
,
503 &TempPrmModuleImageContext
.ExportDirectory
505 if (EFI_ERROR (Status
)) {
509 // Attempt to find the PRM Module Export Descriptor in the export table
510 Status
= GetPrmModuleExportDescriptorTable (
511 TempPrmModuleImageContext
.ExportDirectory
,
512 &TempPrmModuleImageContext
.PeCoffImageContext
,
513 &TempPrmModuleImageContext
.ExportDescriptor
515 if (EFI_ERROR (Status
)) {
518 // A PRM Module Export Descriptor was successfully found, this is considered a PRM Module.
521 // Create a new PRM Module image context node
523 PrmModuleImageContextListEntry
= CreateNewPrmModuleImageContextListEntry ();
524 if (PrmModuleImageContextListEntry
== NULL
) {
525 return EFI_OUT_OF_RESOURCES
;
528 PrmModuleImageContextListEntry
->Context
,
529 &TempPrmModuleImageContext
,
530 sizeof (*(PrmModuleImageContextListEntry
->Context
))
532 InsertTailList (&mPrmModuleList
, &PrmModuleImageContextListEntry
->Link
);
533 mPrmHandlerCount
+= TempPrmModuleImageContext
.ExportDescriptor
->Header
.NumberPrmHandlers
;
534 mPrmModuleCount
++; // Todo: Match with global variable refactor change in the future
535 DEBUG ((DEBUG_INFO
, "%a %a: New PRM Module inserted into list to be processed.\n", _DBGMSGID_
, __FUNCTION__
));
542 Gets the address of an entry in an image export table by ASCII name.
544 @param[in] ExportName A pointer to an ASCII name string of the entry name.
545 @param[in] ImageBaseAddress The base address of the PE/COFF image.
546 @param[in] ImageExportDirectory A pointer to the export directory in the image.
547 @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the
548 export entry if found.
550 @retval EFI_SUCCESS The export entry was found successfully.
551 @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.
552 @retval EFI_NOT_FOUND An entry with the given ExportName was not found.
556 GetExportEntryAddress (
557 IN CONST CHAR8
*ExportName
,
558 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress
,
559 IN EFI_IMAGE_EXPORT_DIRECTORY
*ImageExportDirectory
,
560 OUT EFI_PHYSICAL_ADDRESS
*ExportPhysicalAddress
563 UINTN ExportNameIndex
;
564 UINT16 CurrentExportOrdinal
;
565 UINT32
*ExportAddressTable
;
566 UINT32
*ExportNamePointerTable
;
567 UINT16
*OrdinalTable
;
568 CONST CHAR8
*ExportNameTablePointerName
;
570 if (ExportName
== NULL
|| ImageBaseAddress
== 0 || ImageExportDirectory
== NULL
|| ExportPhysicalAddress
== NULL
) {
571 return EFI_INVALID_PARAMETER
;
573 *ExportPhysicalAddress
= 0;
575 ExportAddressTable
= (UINT32
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfFunctions
);
576 ExportNamePointerTable
= (UINT32
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfNames
);
577 OrdinalTable
= (UINT16
*) ((UINTN
) ImageBaseAddress
+ ImageExportDirectory
->AddressOfNameOrdinals
);
579 for (ExportNameIndex
= 0; ExportNameIndex
< ImageExportDirectory
->NumberOfNames
; ExportNameIndex
++) {
580 ExportNameTablePointerName
= (CONST CHAR8
*) ((UINTN
) ImageBaseAddress
+ ExportNamePointerTable
[ExportNameIndex
]);
582 if (AsciiStrnCmp (ExportName
, ExportNameTablePointerName
, PRM_HANDLER_NAME_MAXIMUM_LENGTH
) == 0) {
583 CurrentExportOrdinal
= OrdinalTable
[ExportNameIndex
];
585 ASSERT (CurrentExportOrdinal
< ImageExportDirectory
->NumberOfFunctions
);
586 if (CurrentExportOrdinal
>= ImageExportDirectory
->NumberOfFunctions
) {
587 DEBUG ((DEBUG_ERROR
, " %a %a: The export ordinal value is invalid.\n", _DBGMSGID_
, __FUNCTION__
));
591 *ExportPhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) ((UINTN
) ImageBaseAddress
+ ExportAddressTable
[CurrentExportOrdinal
]);
596 return EFI_NOT_FOUND
;
600 Processes a list of PRM context entries to build a PRM ACPI table.
602 The ACPI table buffer is allocated and the table structure is built inside this function.
604 @param[out] PrmAcpiDescriptionTable A pointer to a pointer to a buffer that is allocated within this function
605 and will contain the PRM ACPI table. In case of an error in this function,
606 *PrmAcpiDescriptorTable will be NULL.
608 @retval EFI_SUCCESS All PRM Modules were processed to construct the PRM ACPI table successfully.
609 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL.
610 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table boot services
616 OUT PRM_ACPI_DESCRIPTION_TABLE
**PrmAcpiDescriptionTable
619 EFI_IMAGE_EXPORT_DIRECTORY
*CurrentImageExportDirectory
;
620 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT
*CurrentExportDescriptorStruct
;
622 PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiTable
;
623 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*TempListEntry
;
624 CONST CHAR8
*CurrentExportDescriptorHandlerName
;
626 PRM_CONTEXT_BUFFER
*CurrentContextBuffer
;
627 PRM_MODULE_CONTEXT_BUFFERS
*CurrentModuleContextBuffers
;
628 PRM_MODULE_INFORMATION_STRUCT
*CurrentModuleInfoStruct
;
629 PRM_HANDLER_INFORMATION_STRUCT
*CurrentHandlerInfoStruct
;
632 EFI_PHYSICAL_ADDRESS CurrentImageAddress
;
634 UINT32 PrmAcpiDescriptionTableBufferSize
;
636 UINT64 HandlerPhysicalAddress
;
638 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
640 if (PrmAcpiDescriptionTable
== NULL
) {
641 return EFI_INVALID_PARAMETER
;
644 *PrmAcpiDescriptionTable
= NULL
;
646 DEBUG ((DEBUG_INFO
, " %a %a: %d total PRM modules to process.\n", _DBGMSGID_
, __FUNCTION__
, mPrmModuleCount
));
647 DEBUG ((DEBUG_INFO
, " %a %a: %d total PRM handlers to process.\n", _DBGMSGID_
, __FUNCTION__
, mPrmHandlerCount
));
649 PrmAcpiDescriptionTableBufferSize
= (OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE
, PrmModuleInfoStructure
) +
650 (OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
) * mPrmModuleCount
) +
651 (sizeof (PRM_HANDLER_INFORMATION_STRUCT
) * mPrmHandlerCount
)
653 DEBUG ((DEBUG_INFO
, " %a %a: Total PRM ACPI table size: 0x%x.\n", _DBGMSGID_
, __FUNCTION__
, PrmAcpiDescriptionTableBufferSize
));
655 PrmAcpiTable
= AllocateZeroPool ((UINTN
) PrmAcpiDescriptionTableBufferSize
);
656 if (PrmAcpiTable
== NULL
) {
657 return EFI_OUT_OF_RESOURCES
;
660 PrmAcpiTable
->Header
.Signature
= PRM_TABLE_SIGNATURE
;
661 PrmAcpiTable
->Header
.Length
= PrmAcpiDescriptionTableBufferSize
;
662 PrmAcpiTable
->Header
.Revision
= PRM_TABLE_REVISION
;
663 PrmAcpiTable
->Header
.Checksum
= 0x0;
664 CopyMem (&PrmAcpiTable
->Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (PrmAcpiTable
->Header
.OemId
));
665 PrmAcpiTable
->Header
.OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
666 PrmAcpiTable
->Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
667 PrmAcpiTable
->Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
668 PrmAcpiTable
->Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
669 PrmAcpiTable
->PrmModuleInfoOffset
= OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE
, PrmModuleInfoStructure
);
670 PrmAcpiTable
->PrmModuleInfoCount
= mPrmModuleCount
;
673 // Iterate across all PRM Modules on the list
675 CurrentModuleInfoStruct
= &PrmAcpiTable
->PrmModuleInfoStructure
[0];
676 EFI_LIST_FOR_EACH(Link
, &mPrmModuleList
)
678 TempListEntry
= CR(Link
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
, Link
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
);
679 CurrentImageAddress
= TempListEntry
->Context
->PeCoffImageContext
.ImageAddress
;
680 CurrentImageExportDirectory
= TempListEntry
->Context
->ExportDirectory
;
681 CurrentExportDescriptorStruct
= TempListEntry
->Context
->ExportDescriptor
;
685 " %a %a: PRM Module - %a with %d handlers.\n",
688 (CHAR8
*) ((UINTN
) CurrentImageAddress
+ CurrentImageExportDirectory
->Name
),
689 CurrentExportDescriptorStruct
->Header
.NumberPrmHandlers
692 CurrentModuleInfoStruct
->StructureRevision
= PRM_MODULE_INFORMATION_STRUCT_REVISION
;
693 CurrentModuleInfoStruct
->StructureLength
= (
694 OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
) +
695 (CurrentExportDescriptorStruct
->Header
.NumberPrmHandlers
* sizeof (PRM_HANDLER_INFORMATION_STRUCT
))
697 CopyGuid (&CurrentModuleInfoStruct
->Identifier
, &CurrentExportDescriptorStruct
->Header
.ModuleGuid
);
698 CurrentModuleInfoStruct
->HandlerCount
= (UINT32
) CurrentExportDescriptorStruct
->Header
.NumberPrmHandlers
;
699 CurrentModuleInfoStruct
->HandlerInfoOffset
= OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT
, HandlerInfoStructure
);
701 CurrentModuleInfoStruct
->MajorRevision
= 0;
702 CurrentModuleInfoStruct
->MinorRevision
= 0;
703 Status
= GetImageVersionInPeCoffImage (
704 (VOID
*) (UINTN
) CurrentImageAddress
,
705 &TempListEntry
->Context
->PeCoffImageContext
,
706 &CurrentModuleInfoStruct
->MajorRevision
,
707 &CurrentModuleInfoStruct
->MinorRevision
709 ASSERT_EFI_ERROR (Status
);
711 Status
= GetExportEntryAddress (
712 PRM_STRING (PRM_MODULE_UPDATE_LOCK_DESCRIPTOR_NAME
),
714 CurrentImageExportDirectory
,
715 (EFI_PHYSICAL_ADDRESS
*) &(CurrentModuleInfoStruct
->ModuleUpdateLock
)
717 ASSERT_EFI_ERROR (Status
);
718 if (!EFI_ERROR (Status
)) {
721 " %a %a: Found PRM module update lock physical address at 0x%016x.\n",
724 CurrentModuleInfoStruct
->ModuleUpdateLock
728 // It is currently valid for a PRM module not to use a context buffer
729 Status
= GetModuleContextBuffers (
731 &CurrentModuleInfoStruct
->Identifier
,
732 &CurrentModuleContextBuffers
734 ASSERT (!EFI_ERROR (Status
) || Status
== EFI_NOT_FOUND
);
735 if (!EFI_ERROR (Status
) && CurrentModuleContextBuffers
!= NULL
) {
736 CurrentModuleInfoStruct
->RuntimeMmioRanges
= (UINT64
) (UINTN
) CurrentModuleContextBuffers
->RuntimeMmioRanges
;
740 // Iterate across all PRM handlers in the PRM Module
742 for (HandlerIndex
= 0; HandlerIndex
< CurrentExportDescriptorStruct
->Header
.NumberPrmHandlers
; HandlerIndex
++) {
743 CurrentHandlerInfoStruct
= &(CurrentModuleInfoStruct
->HandlerInfoStructure
[HandlerIndex
]);
745 CurrentHandlerInfoStruct
->StructureRevision
= PRM_HANDLER_INFORMATION_STRUCT_REVISION
;
746 CurrentHandlerInfoStruct
->StructureLength
= sizeof (PRM_HANDLER_INFORMATION_STRUCT
);
748 &CurrentHandlerInfoStruct
->Identifier
,
749 &CurrentExportDescriptorStruct
->PrmHandlerExportDescriptors
[HandlerIndex
].PrmHandlerGuid
752 CurrentExportDescriptorHandlerName
= (CONST CHAR8
*) CurrentExportDescriptorStruct
->PrmHandlerExportDescriptors
[HandlerIndex
].PrmHandlerName
;
754 Status
= GetContextBuffer (
755 &CurrentHandlerInfoStruct
->Identifier
,
756 CurrentModuleContextBuffers
,
757 &CurrentContextBuffer
759 if (!EFI_ERROR (Status
)) {
760 #ifdef ALLOCATE_CONTEXT_BUFFER_IN_FW
761 CurrentHandlerInfoStruct
->PrmContextBuffer
= (UINT64
) (UINTN
) CurrentContextBuffer
;
763 CurrentHandlerInfoStruct
->StaticDataBuffer
= (UINT64
) (UINTN
) CurrentContextBuffer
->StaticDataBuffer
;
767 Status
= GetExportEntryAddress (
768 CurrentExportDescriptorHandlerName
,
770 CurrentImageExportDirectory
,
771 &HandlerPhysicalAddress
773 ASSERT_EFI_ERROR (Status
);
774 if (!EFI_ERROR (Status
)) {
775 CurrentHandlerInfoStruct
->PhysicalAddress
= HandlerPhysicalAddress
;
778 " %a %a: Found %a handler physical address at 0x%016x.\n",
781 CurrentExportDescriptorHandlerName
,
782 CurrentHandlerInfoStruct
->PhysicalAddress
786 CurrentModuleInfoStruct
= (PRM_MODULE_INFORMATION_STRUCT
*) ((UINTN
) CurrentModuleInfoStruct
+ CurrentModuleInfoStruct
->StructureLength
);
788 *PrmAcpiDescriptionTable
= PrmAcpiTable
;
794 Publishes the PRM ACPI table (PRMT).
796 @param[in] PrmAcpiDescriptionTable A pointer to a buffer with a completely populated and valid PRM
797 ACPI description table.
799 @retval EFI_SUCCESS The PRM ACPI was installed successfully.
800 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL or the table signature
801 in the table provided is invalid.
802 @retval EFI_NOT_FOUND The protocol gEfiAcpiTableProtocolGuid could not be found.
803 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table buffer.
807 PublishPrmAcpiTable (
808 IN PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiDescriptionTable
812 EFI_ACPI_TABLE_PROTOCOL
*AcpiTableProtocol
;
814 EFI_ACPI_DESCRIPTION_HEADER
*Ssdt
;
817 if (PrmAcpiDescriptionTable
== NULL
|| PrmAcpiDescriptionTable
->Header
.Signature
!= PRM_TABLE_SIGNATURE
) {
818 return EFI_INVALID_PARAMETER
;
821 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTableProtocol
);
822 if (!EFI_ERROR (Status
)) {
825 // Publish the PRM ACPI table. The table checksum will be computed during installation.
827 Status
= AcpiTableProtocol
->InstallAcpiTable (
829 PrmAcpiDescriptionTable
,
830 PrmAcpiDescriptionTable
->Header
.Length
,
833 if (!EFI_ERROR (Status
)) {
834 DEBUG ((DEBUG_INFO
, "%a %a: The PRMT ACPI table was installed successfully.\n", _DBGMSGID_
, __FUNCTION__
));
837 ASSERT_EFI_ERROR (Status
);
842 Status
= GetSectionFromFv (
849 ASSERT_EFI_ERROR (Status
);
850 DEBUG ((DEBUG_INFO
, "%a %a: SSDT loaded ...\n", _DBGMSGID_
, __FUNCTION__
));
855 CopyMem (&Ssdt
->OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (Ssdt
->OemId
));
858 // Publish the SSDT. Table is re-checksumed.
861 Status
= AcpiTableProtocol
->InstallAcpiTable (
867 ASSERT_EFI_ERROR (Status
);
873 The PRM Loader END_OF_DXE protocol notification event handler.
875 All PRM Modules that are eligible for dispatch should have been loaded the DXE Dispatcher at the
876 time of this function invocation.
878 The main responsibilities of the PRM Loader are executed from this function which include 3 phases:
879 1.) Disover PRM Modules - Find all PRM modules loaded during DXE dispatch and insert a PRM Module
880 Context entry into a linked list to be handed off to phase 2.
881 2.) Process PRM Modules - Build a GUID to PRM handler mapping for each module that is described in the
882 PRM ACPI table so the OS can resolve a PRM Handler GUID to the corresponding PRM Handler physical address.
883 3.) Publish PRM ACPI Table - Publish the PRM ACPI table with the information gathered in the phase 2.
885 @param[in] Event Event whose notification function is being invoked.
886 @param[in] Context The pointer to the notification function's context,
887 which is implementation-dependent.
889 @retval EFI_SUCCESS The function executed successfully
894 PrmLoaderEndOfDxeNotification (
900 PRM_ACPI_DESCRIPTION_TABLE
*PrmAcpiDescriptionTable
;
902 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
904 InitializeListHead (&mPrmModuleList
);
906 Status
= DiscoverPrmModules ();
907 ASSERT_EFI_ERROR (Status
);
909 Status
= ProcessPrmModules (&PrmAcpiDescriptionTable
);
910 ASSERT_EFI_ERROR (Status
);
912 Status
= PublishPrmAcpiTable (PrmAcpiDescriptionTable
);
913 ASSERT_EFI_ERROR (Status
);
915 if (PrmAcpiDescriptionTable
!= NULL
) {
916 FreePool (PrmAcpiDescriptionTable
);
918 gBS
->CloseEvent (Event
);
924 The entry point for this module.
926 @param ImageHandle The firmware allocated handle for the EFI image.
927 @param SystemTable A pointer to the EFI System Table.
929 @retval EFI_SUCCESS The entry point is executed successfully.
930 @retval Others An error occurred when executing this entry point.
935 PrmLoaderEntryPoint (
936 IN EFI_HANDLE ImageHandle
,
937 IN EFI_SYSTEM_TABLE
*SystemTable
941 EFI_EVENT EndOfDxeEvent
;
943 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
946 // Discover and process installed PRM modules at the End of DXE
947 // The PRM ACPI table is published if one or PRM modules are discovered
949 Status
= gBS
->CreateEventEx(
952 PrmLoaderEndOfDxeNotification
,
954 &gEfiEndOfDxeEventGroupGuid
,
957 if (EFI_ERROR (Status
)) {
958 DEBUG ((DEBUG_ERROR
, "%a %a: EndOfDxe callback registration failed! %r.\n", _DBGMSGID_
, __FUNCTION__
, Status
));
959 ASSERT_EFI_ERROR (Status
);