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