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