3 The PRM Module Discovery library provides functionality to discover PRM modules installed by platform firmware.
5 Copyright (c) Microsoft Corporation
6 Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Protocol/MmAccess.h>
13 #include <Library/BaseLib.h>
14 #include <Library/BaseMemoryLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/PrmModuleDiscoveryLib.h>
18 #include <Library/PrmPeCoffLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Protocol/LoadedImage.h>
22 #include "PrmModuleDiscovery.h"
24 #define _DBGMSGID_ "[PRMMODULEDISCOVERYLIB]"
26 LIST_ENTRY mPrmModuleList
;
29 Gets the next PRM module discovered after the given PRM module.
31 @param[in,out] ModuleImageContext A pointer to a pointer to a PRM module image context structure.
32 ModuleImageContext should point to a pointer that points to NULL to
33 get the first PRM module discovered.
35 @retval EFI_SUCCESS The next PRM module was found successfully.
36 @retval EFI_INVALID_PARAMETER The given ModuleImageContext structure is invalid or the pointer is NULL.
37 @retval EFI_NOT_FOUND The next PRM module was not found.
42 GetNextPrmModuleEntry (
43 IN OUT PRM_MODULE_IMAGE_CONTEXT
**ModuleImageContext
46 LIST_ENTRY
*CurrentLink
;
47 LIST_ENTRY
*ForwardLink
;
48 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*CurrentListEntry
;
49 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*ForwardListEntry
;
51 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
53 if (ModuleImageContext
== NULL
) {
54 return EFI_INVALID_PARAMETER
;
57 if (*ModuleImageContext
== NULL
) {
58 ForwardLink
= GetFirstNode (&mPrmModuleList
);
60 CurrentListEntry
= NULL
;
61 CurrentListEntry
= CR (*ModuleImageContext
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
, Context
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
);
62 if (CurrentListEntry
== NULL
|| CurrentListEntry
->Signature
!= PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
) {
63 return EFI_INVALID_PARAMETER
;
66 CurrentLink
= &CurrentListEntry
->Link
;
67 ForwardLink
= GetNextNode (&mPrmModuleList
, CurrentLink
);
69 if (ForwardLink
== &mPrmModuleList
) {
74 ForwardListEntry
= BASE_CR (ForwardLink
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
, Link
);
75 if (ForwardListEntry
->Signature
== PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
) {
76 *ModuleImageContext
= &ForwardListEntry
->Context
;
84 Creates a new PRM Module Image Context linked list entry.
86 @retval PrmModuleImageContextListEntry If successful, a pointer a PRM Module Image Context linked list entry
87 otherwise, NULL is returned.
90 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*
91 CreateNewPrmModuleImageContextListEntry (
95 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*PrmModuleImageContextListEntry
;
97 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
99 PrmModuleImageContextListEntry
= AllocateZeroPool (sizeof (*PrmModuleImageContextListEntry
));
100 if (PrmModuleImageContextListEntry
== NULL
) {
105 " %a %a: Allocated PrmModuleImageContextListEntry at 0x%x of size 0x%x bytes.\n",
108 (UINTN
) PrmModuleImageContextListEntry
,
109 sizeof (*PrmModuleImageContextListEntry
)
112 PrmModuleImageContextListEntry
->Signature
= PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
;
114 return PrmModuleImageContextListEntry
;
118 Check whether the address is within any of the MMRAM ranges.
120 @param[in] Address The address to be checked.
121 @param[in] MmramRanges Pointer to MMRAM descriptor.
122 @param[in] MmramRangeCount MMRAM range count.
124 @retval TRUE The address is in MMRAM ranges.
125 @retval FALSE The address is out of MMRAM ranges.
130 IN EFI_PHYSICAL_ADDRESS Address
,
131 IN EFI_MMRAM_DESCRIPTOR
*MmramRanges
,
132 IN UINTN MmramRangeCount
137 for (Index
= 0; Index
< MmramRangeCount
; Index
++) {
138 if ((Address
>= MmramRanges
[Index
].CpuStart
) &&
139 (Address
< (MmramRanges
[Index
].CpuStart
+ MmramRanges
[Index
].PhysicalSize
)))
149 Discovers all PRM Modules loaded during boot.
151 Each PRM Module discovered is placed into a linked list so the list can br processsed in the future.
153 @param[out] ModuleCount An optional pointer parameter that, if provided, is set to the number
154 of PRM modules discovered.
155 @param[out] HandlerCount An optional pointer parameter that, if provided, is set to the number
156 of PRM handlers discovered.
158 @retval EFI_SUCCESS All PRM Modules were discovered successfully.
159 @retval EFI_INVALID_PARAMETER An actual pointer parameter was passed as NULL.
160 @retval EFI_NOT_FOUND The gEfiLoadedImageProtocolGuid protocol could not be found.
161 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the new PRM Context
163 @retval EFI_ALREADY_STARTED The function was called previously and already discovered the PRM modules
170 OUT UINTN
*ModuleCount OPTIONAL
,
171 OUT UINTN
*HandlerCount OPTIONAL
175 PRM_MODULE_IMAGE_CONTEXT TempPrmModuleImageContext
;
176 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*PrmModuleImageContextListEntry
;
177 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImageProtocol
;
178 EFI_HANDLE
*HandleBuffer
;
181 UINTN PrmHandlerCount
;
182 UINTN PrmModuleCount
;
183 EFI_MM_ACCESS_PROTOCOL
*MmAccess
;
185 EFI_MMRAM_DESCRIPTOR
*MmramRanges
;
186 UINTN MmramRangeCount
;
188 DEBUG ((DEBUG_INFO
, "%a %a - Entry.\n", _DBGMSGID_
, __FUNCTION__
));
193 if (!IsListEmpty (&mPrmModuleList
)) {
194 return EFI_ALREADY_STARTED
;
197 Status
= gBS
->LocateHandleBuffer (
199 &gEfiLoadedImageProtocolGuid
,
204 if (EFI_ERROR (Status
) && (HandleCount
== 0)) {
205 DEBUG ((DEBUG_ERROR
, "%a %a: No LoadedImageProtocol instances found!\n", _DBGMSGID_
, __FUNCTION__
));
206 return EFI_NOT_FOUND
;
211 Status
= gBS
->LocateProtocol (
212 &gEfiMmAccessProtocolGuid
,
216 if (Status
== EFI_SUCCESS
) {
218 // Get MMRAM range information
221 Status
= MmAccess
->GetCapabilities (MmAccess
, &Size
, NULL
);
222 if ((Status
== EFI_BUFFER_TOO_SMALL
) && (Size
!= 0)) {
223 MmramRanges
= (EFI_MMRAM_DESCRIPTOR
*)AllocatePool (Size
);
224 if (MmramRanges
!= NULL
) {
225 Status
= MmAccess
->GetCapabilities (MmAccess
, &Size
, MmramRanges
);
226 if (Status
== EFI_SUCCESS
) {
227 MmramRangeCount
= Size
/ sizeof (EFI_MMRAM_DESCRIPTOR
);
233 for (Index
= 0; Index
< HandleCount
; Index
++) {
234 Status
= gBS
->HandleProtocol (
236 &gEfiLoadedImageProtocolGuid
,
237 (VOID
**) &LoadedImageProtocol
239 if (EFI_ERROR (Status
)) {
243 if (IsAddressInMmram ((EFI_PHYSICAL_ADDRESS
)(UINTN
)(LoadedImageProtocol
->ImageBase
), MmramRanges
, MmramRangeCount
)) {
247 ZeroMem (&TempPrmModuleImageContext
, sizeof (TempPrmModuleImageContext
));
248 TempPrmModuleImageContext
.PeCoffImageContext
.Handle
= LoadedImageProtocol
->ImageBase
;
249 TempPrmModuleImageContext
.PeCoffImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
251 Status
= PeCoffLoaderGetImageInfo (&TempPrmModuleImageContext
.PeCoffImageContext
);
252 if (EFI_ERROR (Status
) || TempPrmModuleImageContext
.PeCoffImageContext
.ImageError
!= IMAGE_ERROR_SUCCESS
) {
255 "%a %a: ImageHandle 0x%016lx is not a valid PE/COFF image. It cannot be considered a PRM module.\n",
258 (EFI_PHYSICAL_ADDRESS
) (UINTN
) LoadedImageProtocol
->ImageBase
262 if (TempPrmModuleImageContext
.PeCoffImageContext
.IsTeImage
) {
263 // A PRM Module is not allowed to be a TE image
267 // Attempt to find an export table in this image
268 Status
= GetExportDirectoryInPeCoffImage (
269 LoadedImageProtocol
->ImageBase
,
270 &TempPrmModuleImageContext
.PeCoffImageContext
,
271 &TempPrmModuleImageContext
.ExportDirectory
273 if (EFI_ERROR (Status
)) {
277 // Attempt to find the PRM Module Export Descriptor in the export table
278 Status
= GetPrmModuleExportDescriptorTable (
279 TempPrmModuleImageContext
.ExportDirectory
,
280 &TempPrmModuleImageContext
.PeCoffImageContext
,
281 &TempPrmModuleImageContext
.ExportDescriptor
283 if (EFI_ERROR (Status
) || TempPrmModuleImageContext
.ExportDescriptor
== NULL
) {
286 // A PRM Module Export Descriptor was successfully found, this is considered a PRM Module.
289 // Create a new PRM Module image context node
291 PrmModuleImageContextListEntry
= CreateNewPrmModuleImageContextListEntry ();
292 if (PrmModuleImageContextListEntry
== NULL
) {
293 return EFI_OUT_OF_RESOURCES
;
296 &PrmModuleImageContextListEntry
->Context
,
297 &TempPrmModuleImageContext
,
298 sizeof (PrmModuleImageContextListEntry
->Context
)
300 InsertTailList (&mPrmModuleList
, &PrmModuleImageContextListEntry
->Link
);
301 PrmHandlerCount
+= TempPrmModuleImageContext
.ExportDescriptor
->Header
.NumberPrmHandlers
;
303 DEBUG ((DEBUG_INFO
, "%a %a: New PRM Module inserted into list to be processed.\n", _DBGMSGID_
, __FUNCTION__
));
306 if (HandlerCount
!= NULL
) {
307 *HandlerCount
= PrmHandlerCount
;
309 if (ModuleCount
!= NULL
) {
310 *ModuleCount
= PrmModuleCount
;
313 if (MmramRanges
!= NULL
) {
314 FreePool (MmramRanges
);
321 The destructor function for this library instance.
323 Frees global resources allocated by this library instance.
325 @param ImageHandle The firmware allocated handle for the EFI image.
326 @param SystemTable A pointer to the EFI System Table.
328 @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
333 PrmModuleDiscoveryLibDestructor (
334 IN EFI_HANDLE ImageHandle
,
335 IN EFI_SYSTEM_TABLE
*SystemTable
339 LIST_ENTRY
*NextLink
;
340 PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
*ListEntry
;
342 if (IsListEmpty (&mPrmModuleList
)) {
346 Link
= GetFirstNode (&mPrmModuleList
);
347 while (!IsNull (&mPrmModuleList
, Link
)) {
348 ListEntry
= CR (Link
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY
, Link
, PRM_MODULE_IMAGE_CONTEXT_LIST_ENTRY_SIGNATURE
);
349 NextLink
= GetNextNode (&mPrmModuleList
, Link
);
351 RemoveEntryList (Link
);
352 FreePool (ListEntry
);
361 The constructor function for this library instance.
363 Internally initializes data structures used later during library execution.
365 @param ImageHandle The firmware allocated handle for the EFI image.
366 @param SystemTable A pointer to the EFI System Table.
368 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
373 PrmModuleDiscoveryLibConstructor (
374 IN EFI_HANDLE ImageHandle
,
375 IN EFI_SYSTEM_TABLE
*SystemTable
378 InitializeListHead (&mPrmModuleList
);