VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/PrmPkg/PrmLoaderDxe/PrmLoaderDxe.c@ 107365

Last change on this file since 107365 was 101291, checked in by vboxsync, 20 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • Property svn:eol-style set to native
File size: 15.3 KB
Line 
1/** @file
2
3 This file contains the implementation for a Platform Runtime Mechanism (PRM)
4 loader driver.
5
6 Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) Microsoft Corporation
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10**/
11
12#include "PrmAcpiTable.h"
13
14#include <Guid/ZeroGuid.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/PrmModuleDiscoveryLib.h>
22#include <Library/PrmPeCoffLib.h>
23#include <Library/UefiBootServicesTableLib.h>
24#include <Library/UefiLib.h>
25#include <Protocol/AcpiTable.h>
26#include <Protocol/PrmConfig.h>
27
28#include <PrmContextBuffer.h>
29#include <PrmMmio.h>
30
31#define _DBGMSGID_ "[PRMLOADER]"
32
33UINTN mPrmHandlerCount;
34UINTN mPrmModuleCount;
35
36/**
37 Processes a list of PRM context entries to build a PRM ACPI table.
38
39 The ACPI table buffer is allocated and the table structure is built inside this function.
40
41 @param[out] PrmAcpiDescriptionTable A pointer to a pointer to a buffer that is allocated within this function
42 and will contain the PRM ACPI table. In case of an error in this function,
43 *PrmAcpiDescriptorTable will be NULL.
44
45 @retval EFI_SUCCESS All PRM Modules were processed to construct the PRM ACPI table successfully.
46 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL.
47 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table boot services
48 memory data buffer.
49
50**/
51EFI_STATUS
52ProcessPrmModules (
53 OUT PRM_ACPI_DESCRIPTION_TABLE **PrmAcpiDescriptionTable
54 )
55{
56 EFI_IMAGE_EXPORT_DIRECTORY *CurrentImageExportDirectory;
57 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *CurrentExportDescriptorStruct;
58 PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiTable;
59 PRM_MODULE_IMAGE_CONTEXT *CurrentPrmModuleImageContext;
60 CONST CHAR8 *CurrentExportDescriptorHandlerName;
61
62 ACPI_PARAMETER_BUFFER_DESCRIPTOR *CurrentModuleAcpiParamDescriptors;
63 PRM_CONTEXT_BUFFER *CurrentContextBuffer;
64 PRM_MODULE_CONTEXT_BUFFERS *CurrentModuleContextBuffers;
65 PRM_MODULE_INFORMATION_STRUCT *CurrentModuleInfoStruct;
66 PRM_HANDLER_INFORMATION_STRUCT *CurrentHandlerInfoStruct;
67
68 EFI_STATUS Status;
69 EFI_PHYSICAL_ADDRESS CurrentImageAddress;
70 UINTN AcpiParamIndex;
71 UINTN HandlerIndex;
72 UINT32 PrmAcpiDescriptionTableBufferSize;
73
74 UINT64 HandlerPhysicalAddress;
75
76 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __func__));
77
78 if (PrmAcpiDescriptionTable == NULL) {
79 return EFI_INVALID_PARAMETER;
80 }
81
82 *PrmAcpiDescriptionTable = NULL;
83
84 //
85 // The platform DSC GUID must be set to a non-zero value
86 //
87 if (CompareGuid (&gEdkiiDscPlatformGuid, &gZeroGuid)) {
88 DEBUG ((
89 DEBUG_ERROR,
90 " %a %a: The Platform GUID in the DSC file must be set to a unique non-zero value.\n",
91 _DBGMSGID_,
92 __func__
93 ));
94 ASSERT (!CompareGuid (&gEdkiiDscPlatformGuid, &gZeroGuid));
95 }
96
97 DEBUG ((DEBUG_INFO, " %a %a: %d total PRM modules to process.\n", _DBGMSGID_, __func__, mPrmModuleCount));
98 DEBUG ((DEBUG_INFO, " %a %a: %d total PRM handlers to process.\n", _DBGMSGID_, __func__, mPrmHandlerCount));
99
100 PrmAcpiDescriptionTableBufferSize = (UINT32)(OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure) +
101 (OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) * mPrmModuleCount) +
102 (sizeof (PRM_HANDLER_INFORMATION_STRUCT) * mPrmHandlerCount)
103 );
104 DEBUG ((DEBUG_INFO, " %a %a: Total PRM ACPI table size: 0x%x.\n", _DBGMSGID_, __func__, PrmAcpiDescriptionTableBufferSize));
105
106 PrmAcpiTable = AllocateZeroPool ((UINTN)PrmAcpiDescriptionTableBufferSize);
107 if (PrmAcpiTable == NULL) {
108 return EFI_OUT_OF_RESOURCES;
109 }
110
111 PrmAcpiTable->Header.Signature = PRM_TABLE_SIGNATURE;
112 PrmAcpiTable->Header.Length = PrmAcpiDescriptionTableBufferSize;
113 PrmAcpiTable->Header.Revision = PRM_TABLE_REVISION;
114 PrmAcpiTable->Header.Checksum = 0x0;
115 CopyMem (&PrmAcpiTable->Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (PrmAcpiTable->Header.OemId));
116 PrmAcpiTable->Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
117 PrmAcpiTable->Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
118 PrmAcpiTable->Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
119 PrmAcpiTable->Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
120 CopyGuid (&PrmAcpiTable->PrmPlatformGuid, &gEdkiiDscPlatformGuid);
121 PrmAcpiTable->PrmModuleInfoOffset = OFFSET_OF (PRM_ACPI_DESCRIPTION_TABLE, PrmModuleInfoStructure);
122 PrmAcpiTable->PrmModuleInfoCount = (UINT32)mPrmModuleCount;
123
124 //
125 // Iterate across all PRM Modules on the list
126 //
127 CurrentModuleInfoStruct = &PrmAcpiTable->PrmModuleInfoStructure[0];
128 for (
129 CurrentPrmModuleImageContext = NULL, Status = GetNextPrmModuleEntry (&CurrentPrmModuleImageContext);
130 !EFI_ERROR (Status);
131 Status = GetNextPrmModuleEntry (&CurrentPrmModuleImageContext))
132 {
133 CurrentImageAddress = CurrentPrmModuleImageContext->PeCoffImageContext.ImageAddress;
134 CurrentImageExportDirectory = CurrentPrmModuleImageContext->ExportDirectory;
135 CurrentExportDescriptorStruct = CurrentPrmModuleImageContext->ExportDescriptor;
136 CurrentModuleAcpiParamDescriptors = NULL;
137
138 DEBUG ((
139 DEBUG_INFO,
140 " %a %a: PRM Module - %a with %d handlers.\n",
141 _DBGMSGID_,
142 __func__,
143 (CHAR8 *)((UINTN)CurrentImageAddress + CurrentImageExportDirectory->Name),
144 CurrentExportDescriptorStruct->Header.NumberPrmHandlers
145 ));
146
147 CurrentModuleInfoStruct->StructureRevision = PRM_MODULE_INFORMATION_STRUCT_REVISION;
148 CurrentModuleInfoStruct->StructureLength = (
149 OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure) +
150 (CurrentExportDescriptorStruct->Header.NumberPrmHandlers * sizeof (PRM_HANDLER_INFORMATION_STRUCT))
151 );
152 CopyGuid (&CurrentModuleInfoStruct->Identifier, &CurrentExportDescriptorStruct->Header.ModuleGuid);
153 CurrentModuleInfoStruct->HandlerCount = (UINT32)CurrentExportDescriptorStruct->Header.NumberPrmHandlers;
154 CurrentModuleInfoStruct->HandlerInfoOffset = OFFSET_OF (PRM_MODULE_INFORMATION_STRUCT, HandlerInfoStructure);
155
156 CurrentModuleInfoStruct->MajorRevision = 0;
157 CurrentModuleInfoStruct->MinorRevision = 0;
158 Status = GetImageVersionInPeCoffImage (
159 (VOID *)(UINTN)CurrentImageAddress,
160 &CurrentPrmModuleImageContext->PeCoffImageContext,
161 &CurrentModuleInfoStruct->MajorRevision,
162 &CurrentModuleInfoStruct->MinorRevision
163 );
164 ASSERT_EFI_ERROR (Status);
165
166 // It is currently valid for a PRM module not to use a context buffer
167 Status = GetModuleContextBuffers (
168 ByModuleGuid,
169 &CurrentModuleInfoStruct->Identifier,
170 (CONST PRM_MODULE_CONTEXT_BUFFERS **)&CurrentModuleContextBuffers
171 );
172 ASSERT (!EFI_ERROR (Status) || Status == EFI_NOT_FOUND);
173 if (!EFI_ERROR (Status) && (CurrentModuleContextBuffers != NULL)) {
174 CurrentModuleInfoStruct->RuntimeMmioRanges = (UINT64)(UINTN)CurrentModuleContextBuffers->RuntimeMmioRanges;
175 CurrentModuleAcpiParamDescriptors = CurrentModuleContextBuffers->AcpiParameterBufferDescriptors;
176 }
177
178 //
179 // Iterate across all PRM handlers in the PRM Module
180 //
181 for (HandlerIndex = 0; HandlerIndex < CurrentExportDescriptorStruct->Header.NumberPrmHandlers; HandlerIndex++) {
182 CurrentHandlerInfoStruct = &(CurrentModuleInfoStruct->HandlerInfoStructure[HandlerIndex]);
183
184 CurrentHandlerInfoStruct->StructureRevision = PRM_HANDLER_INFORMATION_STRUCT_REVISION;
185 CurrentHandlerInfoStruct->StructureLength = sizeof (PRM_HANDLER_INFORMATION_STRUCT);
186 CopyGuid (
187 &CurrentHandlerInfoStruct->Identifier,
188 &CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerGuid
189 );
190
191 CurrentExportDescriptorHandlerName = (CONST CHAR8 *)CurrentExportDescriptorStruct->PrmHandlerExportDescriptors[HandlerIndex].PrmHandlerName;
192
193 Status = GetContextBuffer (
194 &CurrentHandlerInfoStruct->Identifier,
195 CurrentModuleContextBuffers,
196 (CONST PRM_CONTEXT_BUFFER **)&CurrentContextBuffer
197 );
198 if (!EFI_ERROR (Status)) {
199 CurrentHandlerInfoStruct->StaticDataBuffer = (UINT64)(UINTN)CurrentContextBuffer->StaticDataBuffer;
200 }
201
202 Status = GetExportEntryAddress (
203 CurrentExportDescriptorHandlerName,
204 CurrentImageAddress,
205 CurrentImageExportDirectory,
206 &HandlerPhysicalAddress
207 );
208 ASSERT_EFI_ERROR (Status);
209 if (!EFI_ERROR (Status)) {
210 CurrentHandlerInfoStruct->PhysicalAddress = HandlerPhysicalAddress;
211 DEBUG ((
212 DEBUG_INFO,
213 " %a %a: Found %a handler physical address at 0x%016x.\n",
214 _DBGMSGID_,
215 __func__,
216 CurrentExportDescriptorHandlerName,
217 CurrentHandlerInfoStruct->PhysicalAddress
218 ));
219 }
220
221 //
222 // Update the handler ACPI parameter buffer address if applicable
223 //
224 if (CurrentModuleAcpiParamDescriptors != NULL) {
225 for (AcpiParamIndex = 0; AcpiParamIndex < CurrentModuleContextBuffers->AcpiParameterBufferDescriptorCount; AcpiParamIndex++) {
226 if (CompareGuid (&CurrentModuleAcpiParamDescriptors[AcpiParamIndex].HandlerGuid, &CurrentHandlerInfoStruct->Identifier)) {
227 CurrentHandlerInfoStruct->AcpiParameterBuffer = (UINT64)(UINTN)(
228 CurrentModuleAcpiParamDescriptors[AcpiParamIndex].AcpiParameterBufferAddress
229 );
230 }
231 }
232 }
233 }
234
235 CurrentModuleInfoStruct = (PRM_MODULE_INFORMATION_STRUCT *)((UINTN)CurrentModuleInfoStruct + CurrentModuleInfoStruct->StructureLength);
236 }
237
238 *PrmAcpiDescriptionTable = PrmAcpiTable;
239
240 return EFI_SUCCESS;
241}
242
243/**
244 Publishes the PRM ACPI table (PRMT).
245
246 @param[in] PrmAcpiDescriptionTable A pointer to a buffer with a completely populated and valid PRM
247 ACPI description table.
248
249 @retval EFI_SUCCESS The PRM ACPI was installed successfully.
250 @retval EFI_INVALID_PARAMETER THe parameter PrmAcpiDescriptionTable is NULL or the table signature
251 in the table provided is invalid.
252 @retval EFI_NOT_FOUND The protocol gEfiAcpiTableProtocolGuid could not be found.
253 @retval EFI_OUT_OF_RESOURCES Insufficient memory resources to allocate the PRM ACPI table buffer.
254
255**/
256EFI_STATUS
257PublishPrmAcpiTable (
258 IN PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiDescriptionTable
259 )
260{
261 EFI_STATUS Status;
262 EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
263 UINTN TableKey;
264
265 if ((PrmAcpiDescriptionTable == NULL) || (PrmAcpiDescriptionTable->Header.Signature != PRM_TABLE_SIGNATURE)) {
266 return EFI_INVALID_PARAMETER;
267 }
268
269 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTableProtocol);
270 if (!EFI_ERROR (Status)) {
271 TableKey = 0;
272 //
273 // Publish the PRM ACPI table. The table checksum will be computed during installation.
274 //
275 Status = AcpiTableProtocol->InstallAcpiTable (
276 AcpiTableProtocol,
277 PrmAcpiDescriptionTable,
278 PrmAcpiDescriptionTable->Header.Length,
279 &TableKey
280 );
281 if (!EFI_ERROR (Status)) {
282 DEBUG ((DEBUG_INFO, "%a %a: The PRMT ACPI table was installed successfully.\n", _DBGMSGID_, __func__));
283 }
284 }
285
286 ASSERT_EFI_ERROR (Status);
287
288 return Status;
289}
290
291/**
292 The PRM Loader END_OF_DXE protocol notification event handler.
293
294 All PRM Modules that are eligible for dispatch should have been loaded the DXE Dispatcher at the
295 time of this function invocation.
296
297 The main responsibilities of the PRM Loader are executed from this function which include 3 phases:
298 1.) Disover PRM Modules - Find all PRM modules loaded during DXE dispatch and insert a PRM Module
299 Context entry into a linked list to be handed off to phase 2.
300 2.) Process PRM Modules - Build a GUID to PRM handler mapping for each module that is described in the
301 PRM ACPI table so the OS can resolve a PRM Handler GUID to the corresponding PRM Handler physical address.
302 3.) Publish PRM ACPI Table - Publish the PRM ACPI table with the information gathered in the phase 2.
303
304 @param[in] Event Event whose notification function is being invoked.
305 @param[in] Context The pointer to the notification function's context,
306 which is implementation-dependent.
307
308**/
309VOID
310EFIAPI
311PrmLoaderEndOfDxeNotification (
312 IN EFI_EVENT Event,
313 IN VOID *Context
314 )
315{
316 EFI_STATUS Status;
317 PRM_ACPI_DESCRIPTION_TABLE *PrmAcpiDescriptionTable;
318
319 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __func__));
320
321 Status = DiscoverPrmModules (&mPrmModuleCount, &mPrmHandlerCount);
322 ASSERT_EFI_ERROR (Status);
323
324 Status = ProcessPrmModules (&PrmAcpiDescriptionTable);
325 ASSERT_EFI_ERROR (Status);
326
327 Status = PublishPrmAcpiTable (PrmAcpiDescriptionTable);
328 ASSERT_EFI_ERROR (Status);
329
330 if (PrmAcpiDescriptionTable != NULL) {
331 FreePool (PrmAcpiDescriptionTable);
332 }
333
334 gBS->CloseEvent (Event);
335}
336
337/**
338 The entry point for this module.
339
340 @param ImageHandle The firmware allocated handle for the EFI image.
341 @param SystemTable A pointer to the EFI System Table.
342
343 @retval EFI_SUCCESS The entry point is executed successfully.
344 @retval Others An error occurred when executing this entry point.
345
346**/
347EFI_STATUS
348EFIAPI
349PrmLoaderEntryPoint (
350 IN EFI_HANDLE ImageHandle,
351 IN EFI_SYSTEM_TABLE *SystemTable
352 )
353{
354 EFI_STATUS Status;
355 EFI_EVENT EndOfDxeEvent;
356
357 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __func__));
358
359 //
360 // Discover and process installed PRM modules at the End of DXE
361 // The PRM ACPI table is published if one or PRM modules are discovered
362 //
363 Status = gBS->CreateEventEx (
364 EVT_NOTIFY_SIGNAL,
365 TPL_CALLBACK,
366 PrmLoaderEndOfDxeNotification,
367 NULL,
368 &gEfiEndOfDxeEventGroupGuid,
369 &EndOfDxeEvent
370 );
371 if (EFI_ERROR (Status)) {
372 DEBUG ((DEBUG_ERROR, "%a %a: EndOfDxe callback registration failed! %r.\n", _DBGMSGID_, __func__, Status));
373 ASSERT_EFI_ERROR (Status);
374 }
375
376 return EFI_SUCCESS;
377}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette