]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/ScriptExecute.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / BootScriptExecutorDxe / ScriptExecute.c
CommitLineData
be46cd5f 1/** @file\r
2 This is the code for Boot Script Executer module.\r
3\r
59cc677c 4 This driver is dispatched by Dxe core and the driver will reload itself to ACPI reserved memory\r
be46cd5f 5 in the entry point. The functionality is to interpret and restore the S3 boot script\r
6\r
d1102dba 7Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
ab1a5a58 8Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
be46cd5f 9\r
10This program and the accompanying materials\r
11are licensed and made available under the terms and conditions of the BSD License\r
12which accompanies this distribution. The full text of the license may be found at\r
13http://opensource.org/licenses/bsd-license.php\r
14\r
15THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
16WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
17\r
18**/\r
19\r
20#include "ScriptExecute.h"\r
21\r
be46cd5f 22EFI_GUID mBootScriptExecutorImageGuid = {\r
ce68d3bc 23 0x9a8d3433, 0x9fe8, 0x42b6, { 0x87, 0xb, 0x1e, 0x31, 0xc8, 0x4e, 0xbe, 0x3b }\r
be46cd5f 24};\r
25\r
59cc677c 26BOOLEAN mPage1GSupport = FALSE;\r
ab1a5a58 27UINT64 mAddressEncMask = 0;\r
59cc677c 28\r
be46cd5f 29/**\r
30 Entry function of Boot script exector. This function will be executed in\r
31 S3 boot path.\r
32 This function should not return, because it is invoked by switch stack.\r
33\r
34 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT\r
35 @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE\r
36\r
37 @retval EFI_INVALID_PARAMETER - OS waking vector not found\r
38 @retval EFI_UNSUPPORTED - something wrong when we resume to OS\r
39**/\r
40EFI_STATUS\r
41EFIAPI\r
42S3BootScriptExecutorEntryFunction (\r
43 IN ACPI_S3_CONTEXT *AcpiS3Context,\r
44 IN PEI_S3_RESUME_STATE *PeiS3ResumeState\r
45 )\r
46{\r
47 EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
48 EFI_STATUS Status;\r
49 UINTN TempStackTop;\r
50 UINTN TempStack[0x10];\r
51 UINTN AsmTransferControl16Address;\r
933d80a1 52 IA32_DESCRIPTOR IdtDescriptor;\r
be46cd5f 53\r
be46cd5f 54 //\r
55 // Disable interrupt of Debug timer, since new IDT table cannot handle it.\r
56 //\r
57 SaveAndSetDebugTimerInterrupt (FALSE);\r
58\r
933d80a1 59 AsmReadIdtr (&IdtDescriptor);\r
be46cd5f 60 //\r
61 // Restore IDT for debug\r
62 //\r
63 SetIdtEntry (AcpiS3Context);\r
64\r
65 //\r
933d80a1 66 // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer.\r
be46cd5f 67 //\r
933d80a1 68 InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL);\r
be46cd5f 69\r
70 //\r
71 // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL\r
72 // for that parameter.\r
73 //\r
be46cd5f 74 Status = S3BootScriptExecute ();\r
d1102dba 75\r
c48abbed
SQ
76 //\r
77 // If invalid script table or opcode in S3 boot script table.\r
78 //\r
79 ASSERT_EFI_ERROR (Status);\r
d1102dba 80\r
c48abbed
SQ
81 if (EFI_ERROR (Status)) {\r
82 CpuDeadLoop ();\r
83 return Status;\r
84 }\r
37623a5c 85\r
be46cd5f 86 AsmWbinvd ();\r
87\r
88 //\r
89 // Get ACPI Table Address\r
90 //\r
91 Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));\r
92\r
be46cd5f 93 //\r
94 // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.\r
95 //\r
96 if (PeiS3ResumeState != 0) {\r
17dd0f2b 97 //\r
d1102dba 98 // Need report status back to S3ResumePeim.\r
17dd0f2b 99 // If boot script execution is failed, S3ResumePeim wil report the error status code.\r
100 //\r
101 PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status;\r
be46cd5f 102 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
103 //\r
104 // X64 S3 Resume\r
105 //\r
558f58e3 106 DEBUG ((DEBUG_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));\r
be46cd5f 107 PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32;\r
108\r
37623a5c 109 if ((Facs != NULL) &&\r
110 (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) &&\r
111 (Facs->FirmwareWakingVector != 0) ) {\r
112 //\r
113 // more step needed - because relative address is handled differently between X64 and IA32.\r
114 //\r
115 AsmTransferControl16Address = (UINTN)AsmTransferControl16;\r
116 AsmFixAddress16 = (UINT32)AsmTransferControl16Address;\r
117 AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12));\r
118 }\r
be46cd5f 119\r
120 AsmDisablePaging64 (\r
121 PeiS3ResumeState->ReturnCs,\r
122 (UINT32)PeiS3ResumeState->ReturnEntryPoint,\r
123 (UINT32)(UINTN)AcpiS3Context,\r
124 (UINT32)(UINTN)PeiS3ResumeState,\r
125 (UINT32)PeiS3ResumeState->ReturnStackPointer\r
126 );\r
127 } else {\r
128 //\r
129 // IA32 S3 Resume\r
130 //\r
558f58e3 131 DEBUG ((DEBUG_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));\r
be46cd5f 132 PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl;\r
133\r
134 SwitchStack (\r
135 (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint,\r
136 (VOID *)(UINTN)AcpiS3Context,\r
137 (VOID *)(UINTN)PeiS3ResumeState,\r
138 (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer\r
139 );\r
140 }\r
141\r
142 //\r
143 // Never run to here\r
144 //\r
145 CpuDeadLoop();\r
146 return EFI_UNSUPPORTED;\r
147 }\r
d1102dba 148\r
37623a5c 149 //\r
150 // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly\r
151 //\r
be46cd5f 152 if (Facs->XFirmwareWakingVector != 0) {\r
153 //\r
154 // Switch to native waking vector\r
155 //\r
156 TempStackTop = (UINTN)&TempStack + sizeof(TempStack);\r
157 if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
158 ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&\r
159 ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {\r
160 //\r
161 // X64 long mode waking vector\r
162 //\r
558f58e3 163 DEBUG ((DEBUG_INFO, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));\r
be46cd5f 164 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
165 SwitchStack (\r
166 (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,\r
167 NULL,\r
168 NULL,\r
169 (VOID *)(UINTN)TempStackTop\r
170 );\r
171 } else {\r
172 // Unsupported for 32bit DXE, 64bit OS vector\r
173 DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));\r
174 ASSERT (FALSE);\r
175 }\r
176 } else {\r
177 //\r
178 // IA32 protected mode waking vector (Page disabled)\r
179 //\r
558f58e3 180 DEBUG ((DEBUG_INFO, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));\r
be46cd5f 181 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
182 AsmDisablePaging64 (\r
183 0x10,\r
184 (UINT32)Facs->XFirmwareWakingVector,\r
185 0,\r
186 0,\r
187 (UINT32)TempStackTop\r
188 );\r
189 } else {\r
190 SwitchStack (\r
191 (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector,\r
192 NULL,\r
193 NULL,\r
194 (VOID *)(UINTN)TempStackTop\r
195 );\r
196 }\r
197 }\r
198 } else {\r
199 //\r
200 // 16bit Realmode waking vector\r
201 //\r
558f58e3 202 DEBUG ((DEBUG_INFO, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));\r
be46cd5f 203 AsmTransferControl (Facs->FirmwareWakingVector, 0x0);\r
204 }\r
205\r
206 //\r
207 // Never run to here\r
208 //\r
209 CpuDeadLoop();\r
210 return EFI_UNSUPPORTED;\r
211}\r
59cc677c 212\r
84edd20b
SZ
213/**\r
214 Register image to memory profile.\r
215\r
216 @param FileName File name of the image.\r
217 @param ImageBase Image base address.\r
218 @param ImageSize Image size.\r
219 @param FileType File type of the image.\r
220\r
221**/\r
222VOID\r
223RegisterMemoryProfileImage (\r
224 IN EFI_GUID *FileName,\r
225 IN PHYSICAL_ADDRESS ImageBase,\r
226 IN UINT64 ImageSize,\r
227 IN EFI_FV_FILETYPE FileType\r
228 )\r
229{\r
230 EFI_STATUS Status;\r
231 EDKII_MEMORY_PROFILE_PROTOCOL *ProfileProtocol;\r
232 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FilePath;\r
233 UINT8 TempBuffer[sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH) + sizeof (EFI_DEVICE_PATH_PROTOCOL)];\r
234\r
235 if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT0) != 0) {\r
236\r
237 FilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)TempBuffer;\r
238 Status = gBS->LocateProtocol (&gEdkiiMemoryProfileGuid, NULL, (VOID **) &ProfileProtocol);\r
239 if (!EFI_ERROR (Status)) {\r
240 EfiInitializeFwVolDevicepathNode (FilePath, FileName);\r
241 SetDevicePathEndNode (FilePath + 1);\r
242\r
243 Status = ProfileProtocol->RegisterImage (\r
244 ProfileProtocol,\r
245 (EFI_DEVICE_PATH_PROTOCOL *) FilePath,\r
246 ImageBase,\r
247 ImageSize,\r
248 FileType\r
249 );\r
250 }\r
251 }\r
252}\r
253\r
59cc677c
SZ
254/**\r
255 This is the Event notification function to reload BootScriptExecutor image\r
256 to RESERVED mem and save it to LockBox.\r
d1102dba 257\r
59cc677c 258 @param Event Pointer to this event\r
d1102dba 259 @param Context Event handler private data\r
59cc677c
SZ
260 **/\r
261VOID\r
262EFIAPI\r
263ReadyToLockEventNotify (\r
264 IN EFI_EVENT Event,\r
265 IN VOID *Context\r
266 )\r
267{\r
268 EFI_STATUS Status;\r
269 VOID *Interface;\r
270 UINT8 *Buffer;\r
271 UINTN BufferSize;\r
272 EFI_HANDLE NewImageHandle;\r
273 UINTN Pages;\r
274 EFI_PHYSICAL_ADDRESS FfsBuffer;\r
275 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
6a3094c9 276 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
59cc677c
SZ
277\r
278 Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);\r
279 if (EFI_ERROR (Status)) {\r
280 return;\r
281 }\r
282\r
283 //\r
284 // A workaround: Here we install a dummy handle\r
285 //\r
286 NewImageHandle = NULL;\r
287 Status = gBS->InstallProtocolInterface (\r
288 &NewImageHandle,\r
289 &gEfiCallerIdGuid,\r
290 EFI_NATIVE_INTERFACE,\r
291 NULL\r
292 );\r
293 ASSERT_EFI_ERROR (Status);\r
294\r
295 //\r
296 // Reload BootScriptExecutor image itself to RESERVED mem\r
297 //\r
298 Status = GetSectionFromAnyFv (\r
299 &gEfiCallerIdGuid,\r
300 EFI_SECTION_PE32,\r
301 0,\r
302 (VOID **) &Buffer,\r
303 &BufferSize\r
304 );\r
305 ASSERT_EFI_ERROR (Status);\r
306 ImageContext.Handle = Buffer;\r
307 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
308 //\r
309 // Get information about the image being loaded\r
310 //\r
311 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
312 ASSERT_EFI_ERROR (Status);\r
32a81741 313 if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {\r
afe5262e 314 Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment));\r
32a81741 315 } else {\r
afe5262e 316 Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize);\r
32a81741 317 }\r
59cc677c
SZ
318 FfsBuffer = 0xFFFFFFFF;\r
319 Status = gBS->AllocatePages (\r
320 AllocateMaxAddress,\r
321 EfiReservedMemoryType,\r
322 Pages,\r
323 &FfsBuffer\r
324 );\r
325 ASSERT_EFI_ERROR (Status);\r
6a3094c9
JW
326\r
327 //\r
328 // Make sure that the buffer can be used to store code.\r
329 //\r
330 Status = gDS->GetMemorySpaceDescriptor (FfsBuffer, &MemDesc);\r
331 if (!EFI_ERROR (Status) && (MemDesc.Attributes & EFI_MEMORY_XP) != 0) {\r
332 gDS->SetMemorySpaceAttributes (\r
333 FfsBuffer,\r
334 EFI_PAGES_TO_SIZE (Pages),\r
335 MemDesc.Attributes & (~EFI_MEMORY_XP)\r
336 );\r
337 }\r
338\r
59cc677c
SZ
339 ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;\r
340 //\r
0a18956d 341 // Align buffer on section boundary\r
59cc677c
SZ
342 //\r
343 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
16f69227 344 ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);\r
59cc677c
SZ
345 //\r
346 // Load the image to our new buffer\r
347 //\r
348 Status = PeCoffLoaderLoadImage (&ImageContext);\r
349 ASSERT_EFI_ERROR (Status);\r
350\r
351 //\r
352 // Relocate the image in our new buffer\r
353 //\r
354 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
355 ASSERT_EFI_ERROR (Status);\r
356\r
357 //\r
358 // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer\r
359 //\r
360 gBS->FreePool (Buffer);\r
361\r
362 //\r
363 // Flush the instruction cache so the image data is written before we execute it\r
364 //\r
365 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
84edd20b
SZ
366\r
367 RegisterMemoryProfileImage (\r
368 &gEfiCallerIdGuid,\r
369 ImageContext.ImageAddress,\r
370 ImageContext.ImageSize,\r
371 EFI_FV_FILETYPE_DRIVER\r
372 );\r
373\r
59cc677c
SZ
374 Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST);\r
375 ASSERT_EFI_ERROR (Status);\r
376\r
377 //\r
378 // Additional step for BootScript integrity\r
379 // Save BootScriptExecutor image\r
380 //\r
381 Status = SaveLockBox (\r
382 &mBootScriptExecutorImageGuid,\r
383 (VOID *)(UINTN)ImageContext.ImageAddress,\r
384 (UINTN)ImageContext.ImageSize\r
385 );\r
386 ASSERT_EFI_ERROR (Status);\r
387\r
388 Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
389 ASSERT_EFI_ERROR (Status);\r
390\r
391 gBS->CloseEvent (Event);\r
392}\r
393\r
be46cd5f 394/**\r
395 Entrypoint of Boot script exector driver, this function will be executed in\r
396 normal boot phase and invoked by DXE dispatch.\r
397\r
398 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
399 @param[in] SystemTable A pointer to the EFI System Table.\r
400\r
401 @retval EFI_SUCCESS The entry point is executed successfully.\r
402 @retval other Some error occurs when executing this entry point.\r
403**/\r
404EFI_STATUS\r
405EFIAPI\r
406BootScriptExecutorEntryPoint (\r
407 IN EFI_HANDLE ImageHandle,\r
408 IN EFI_SYSTEM_TABLE *SystemTable\r
409 )\r
410{\r
be46cd5f 411 UINTN BufferSize;\r
412 UINTN Pages;\r
be46cd5f 413 BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable;\r
414 EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer;\r
415 EFI_STATUS Status;\r
416 VOID *DevicePath;\r
59cc677c
SZ
417 EFI_EVENT ReadyToLockEvent;\r
418 VOID *Registration;\r
419 UINT32 RegEax;\r
420 UINT32 RegEdx;\r
be46cd5f 421\r
800c02fb
SZ
422 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
423 return EFI_UNSUPPORTED;\r
424 }\r
425\r
ab1a5a58
LD
426 //\r
427 // Make sure AddressEncMask is contained to smallest supported address field.\r
428 //\r
429 mAddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;\r
430\r
be46cd5f 431 //\r
432 // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry\r
433 // point is loaded by DXE code which is the first time loaded. or else, it is already\r
434 // be reloaded be itself.This is a work-around\r
435 //\r
436 Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);\r
437 if (EFI_ERROR (Status)) {\r
be46cd5f 438 //\r
59cc677c
SZ
439 // Create ReadyToLock event to reload BootScriptExecutor image\r
440 // to RESERVED mem and save it to LockBox.\r
be46cd5f 441 //\r
59cc677c
SZ
442 ReadyToLockEvent = EfiCreateProtocolNotifyEvent (\r
443 &gEfiDxeSmmReadyToLockProtocolGuid,\r
444 TPL_NOTIFY,\r
445 ReadyToLockEventNotify,\r
446 NULL,\r
447 &Registration\r
448 );\r
449 ASSERT (ReadyToLockEvent != NULL);\r
be46cd5f 450 } else {\r
451 //\r
bad73446 452 // the entry point is invoked after reloading. following code only run in RESERVED mem\r
be46cd5f 453 //\r
59cc677c
SZ
454 if (PcdGetBool(PcdUse1GPageTable)) {\r
455 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
456 if (RegEax >= 0x80000001) {\r
457 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
458 if ((RegEdx & BIT26) != 0) {\r
459 mPage1GSupport = TRUE;\r
460 }\r
461 }\r
462 }\r
463\r
be46cd5f 464 BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE);\r
465\r
466 BootScriptExecutorBuffer = 0xFFFFFFFF;\r
467 Pages = EFI_SIZE_TO_PAGES(BufferSize);\r
468 Status = gBS->AllocatePages (\r
469 AllocateMaxAddress,\r
bad73446 470 EfiReservedMemoryType,\r
be46cd5f 471 Pages,\r
472 &BootScriptExecutorBuffer\r
473 );\r
e0d216f6 474 ASSERT_EFI_ERROR (Status);\r
be46cd5f 475\r
476 EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer;\r
477 EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ;\r
478\r
479 Status = SaveLockBox (\r
480 &gEfiBootScriptExecutorVariableGuid,\r
481 &BootScriptExecutorBuffer,\r
482 sizeof(BootScriptExecutorBuffer)\r
483 );\r
484 ASSERT_EFI_ERROR (Status);\r
485\r
486 //\r
487 // Additional step for BootScript integrity\r
488 // Save BootScriptExecutor context\r
489 //\r
490 Status = SaveLockBox (\r
491 &gEfiBootScriptExecutorContextGuid,\r
492 EfiBootScriptExecutorVariable,\r
493 sizeof(*EfiBootScriptExecutorVariable)\r
494 );\r
495 ASSERT_EFI_ERROR (Status);\r
496\r
497 Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
498 ASSERT_EFI_ERROR (Status);\r
be46cd5f 499 }\r
500\r
501 return EFI_SUCCESS;\r
502}\r
503\r