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