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