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 |
|
---|
33 | UINTN mPrmHandlerCount;
|
---|
34 | UINTN 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 | **/
|
---|
51 | EFI_STATUS
|
---|
52 | ProcessPrmModules (
|
---|
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 | **/
|
---|
256 | EFI_STATUS
|
---|
257 | PublishPrmAcpiTable (
|
---|
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 | **/
|
---|
309 | VOID
|
---|
310 | EFIAPI
|
---|
311 | PrmLoaderEndOfDxeNotification (
|
---|
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 | **/
|
---|
347 | EFI_STATUS
|
---|
348 | EFIAPI
|
---|
349 | PrmLoaderEntryPoint (
|
---|
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 | }
|
---|