2 This is the code for Boot Script Executer module.
4 This driver is dispatched by Dxe core and the driver will reload itself to ACPI NVS memory
5 in the entry point. The functionality is to interpret and restore the S3 boot script
7 Copyright (c) 2013-2016 Intel Corporation.
9 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "ScriptExecute.h"
28 UINT32 DefaultSize
: 1;
29 UINT32 Granularity
: 1;
37 EFI_GUID mBootScriptExecutorImageGuid
= {
38 0x9a8d3433, 0x9fe8, 0x42b6, {0x87, 0xb, 0x1e, 0x31, 0xc8, 0x4e, 0xbe, 0x3b}
42 // Global Descriptor Table (GDT)
44 GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries
[] = {
45 /* selector { Global Segment Descriptor } */
46 /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
47 /* 0x08 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
48 /* 0x10 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}},
49 /* 0x18 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}},
50 /* 0x20 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
51 /* 0x28 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}},
52 /* 0x30 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}},
53 /* 0x38 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}},
54 /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
60 GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt
= {
61 sizeof (mGdtEntries
) - 1,
66 Entry function of Boot script exector. This function will be executed in
68 This function should not return, because it is invoked by switch stack.
70 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
71 @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE
73 @retval EFI_INVALID_PARAMETER - OS waking vector not found
74 @retval EFI_UNSUPPORTED - something wrong when we resume to OS
78 S3BootScriptExecutorEntryFunction (
79 IN ACPI_S3_CONTEXT
*AcpiS3Context
,
80 IN PEI_S3_RESUME_STATE
*PeiS3ResumeState
86 // Disable interrupt of Debug timer, since new IDT table cannot handle it.
88 SaveAndSetDebugTimerInterrupt (FALSE
);
91 // Restore IDT for debug
93 SetIdtEntry (AcpiS3Context
);
96 // Initialize Debug Agent to support source level debug in S3 path.
98 InitializeDebugAgent (DEBUG_AGENT_INIT_S3
, NULL
, NULL
);
101 // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL
102 // for that parameter.
104 Status
= S3BootScriptExecute ();
109 // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.
111 if (PeiS3ResumeState
!= 0) {
113 // Need report status back to S3ResumePeim.
114 // If boot script execution is failed, S3ResumePeim wil report the error status code.
116 PeiS3ResumeState
->ReturnStatus
= (UINT64
)(UINTN
)Status
;
120 DEBUG ((EFI_D_INFO
, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
121 PeiS3ResumeState
->AsmTransferControl
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)PlatformTransferControl16
;
124 (SWITCH_STACK_ENTRY_POINT
)(UINTN
)PeiS3ResumeState
->ReturnEntryPoint
,
125 (VOID
*)(UINTN
)AcpiS3Context
,
126 (VOID
*)(UINTN
)PeiS3ResumeState
,
127 (VOID
*)(UINTN
)PeiS3ResumeState
->ReturnStackPointer
134 return EFI_UNSUPPORTED
;
141 return EFI_UNSUPPORTED
;
144 Entrypoint of Boot script exector driver, this function will be executed in
145 normal boot phase and invoked by DXE dispatch.
147 @param[in] ImageHandle The firmware allocated handle for the EFI image.
148 @param[in] SystemTable A pointer to the EFI System Table.
150 @retval EFI_SUCCESS The entry point is executed successfully.
151 @retval other Some error occurs when executing this entry point.
155 BootScriptExecutorEntryPoint (
156 IN EFI_HANDLE ImageHandle
,
157 IN EFI_SYSTEM_TABLE
*SystemTable
163 EFI_PHYSICAL_ADDRESS FfsBuffer
;
164 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
165 BOOT_SCRIPT_EXECUTOR_VARIABLE
*EfiBootScriptExecutorVariable
;
166 EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer
;
169 EFI_HANDLE NewImageHandle
;
172 // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry
173 // point is loaded by DXE code which is the first time loaded. or else, it is already
174 // be reloaded be itself.This is a work-around
176 Status
= gBS
->LocateProtocol (&gEfiCallerIdGuid
, NULL
, &DevicePath
);
177 if (EFI_ERROR (Status
)) {
180 // This is the first-time loaded by DXE core. reload itself to NVS mem
183 // A workarouond: Here we install a dummy handle
185 NewImageHandle
= NULL
;
186 Status
= gBS
->InstallProtocolInterface (
189 EFI_NATIVE_INTERFACE
,
193 Status
= GetSectionFromAnyFv (
200 ImageContext
.Handle
= Buffer
;
201 ImageContext
.ImageRead
= PeCoffLoaderImageReadFromMemory
;
203 // Get information about the image being loaded
205 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
206 if (EFI_ERROR (Status
)) {
209 Pages
= EFI_SIZE_TO_PAGES(BufferSize
+ ImageContext
.SectionAlignment
);
210 FfsBuffer
= 0xFFFFFFFF;
211 Status
= gBS
->AllocatePages (
217 if (EFI_ERROR (Status
)) {
218 return EFI_OUT_OF_RESOURCES
;
220 ImageContext
.ImageAddress
= (PHYSICAL_ADDRESS
)(UINTN
)FfsBuffer
;
222 // Align buffer on section boundary
224 ImageContext
.ImageAddress
+= ImageContext
.SectionAlignment
- 1;
225 ImageContext
.ImageAddress
&= ~(ImageContext
.SectionAlignment
- 1);
227 // Load the image to our new buffer
229 Status
= PeCoffLoaderLoadImage (&ImageContext
);
230 if (EFI_ERROR (Status
)) {
231 gBS
->FreePages (FfsBuffer
, Pages
);
236 // Relocate the image in our new buffer
238 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
240 if (EFI_ERROR (Status
)) {
241 PeCoffLoaderUnloadImage (&ImageContext
);
242 gBS
->FreePages (FfsBuffer
, Pages
);
246 // Flush the instruction cache so the image data is written before we execute it
248 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
249 Status
= ((EFI_IMAGE_ENTRY_POINT
)(UINTN
)(ImageContext
.EntryPoint
)) (NewImageHandle
, SystemTable
);
250 if (EFI_ERROR (Status
)) {
251 gBS
->FreePages (FfsBuffer
, Pages
);
255 // Additional step for BootScript integrity
256 // Save BootScriptExecutor image
258 Status
= SaveLockBox (
259 &mBootScriptExecutorImageGuid
,
260 (VOID
*)(UINTN
)ImageContext
.ImageAddress
,
261 (UINTN
)ImageContext
.ImageSize
263 ASSERT_EFI_ERROR (Status
);
265 Status
= SetLockBoxAttributes (&mBootScriptExecutorImageGuid
, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
);
266 ASSERT_EFI_ERROR (Status
);
270 // the entry point is invoked after reloading. following code only run in ACPI NVS
272 BufferSize
= sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE
);
274 BootScriptExecutorBuffer
= 0xFFFFFFFF;
275 Pages
= EFI_SIZE_TO_PAGES(BufferSize
);
276 Status
= gBS
->AllocatePages (
280 &BootScriptExecutorBuffer
282 if (EFI_ERROR (Status
)) {
283 return EFI_OUT_OF_RESOURCES
;
286 EfiBootScriptExecutorVariable
= (BOOT_SCRIPT_EXECUTOR_VARIABLE
*)(UINTN
)BootScriptExecutorBuffer
;
287 EfiBootScriptExecutorVariable
->BootScriptExecutorEntrypoint
= (UINTN
) S3BootScriptExecutorEntryFunction
;
289 Status
= SaveLockBox (
290 &gEfiBootScriptExecutorVariableGuid
,
291 &BootScriptExecutorBuffer
,
292 sizeof(BootScriptExecutorBuffer
)
294 ASSERT_EFI_ERROR (Status
);
297 // Additional step for BootScript integrity
298 // Save BootScriptExecutor context
300 Status
= SaveLockBox (
301 &gEfiBootScriptExecutorContextGuid
,
302 EfiBootScriptExecutorVariable
,
303 sizeof(*EfiBootScriptExecutorVariable
)
305 ASSERT_EFI_ERROR (Status
);
307 Status
= SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid
, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE
);
308 ASSERT_EFI_ERROR (Status
);
316 Platform specific mechanism to transfer control to 16bit OS waking vector
318 @param[in] AcpiWakingVector The 16bit OS waking vector
319 @param[in] AcpiLowMemoryBase A buffer under 1M which could be used during the transfer
323 PlatformTransferControl16 (
324 IN UINT32 AcpiWakingVector
,
325 IN UINT32 AcpiLowMemoryBase
333 DEBUG (( EFI_D_INFO
, "PlatformTransferControl - Entry\r\n"));
336 // Need to make sure the GDT is loaded with values that support long mode and real mode.
338 AsmWriteGdtr (&mGdt
);
341 // Disable eSram block (this will also clear/zero eSRAM)
342 // We only use eSRAM in the PEI phase. Disable now that we are resuming the OS
344 NewValue
= QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID
, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK
);
345 NewValue
|= BLOCK_DISABLE_PG
;
346 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID
, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK
, NewValue
);
349 // Update HMBOUND to top of DDR3 memory and LOCK
350 // We disabled eSRAM so now we move HMBOUND down to top of DDR3
352 QNCGetTSEGMemoryRange (&BaseAddress
, &SmramLength
);
353 NewValue
= (UINT32
)(BaseAddress
+ SmramLength
);
354 DEBUG ((EFI_D_INFO
,"Locking HMBOUND at: = 0x%8x\n",NewValue
));
355 QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID
, QUARK_NC_HOST_BRIDGE_HMBOUND_REG
, (NewValue
| HMBOUND_LOCK
));
358 // Lock all IMR regions now that HMBOUND is locked
360 for (Index
= (QUARK_NC_MEMORY_MANAGER_IMR0
+QUARK_NC_MEMORY_MANAGER_IMRXL
); Index
<= (QUARK_NC_MEMORY_MANAGER_IMR7
+QUARK_NC_MEMORY_MANAGER_IMRXL
); Index
+= 4) {
361 NewValue
= QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID
, Index
);
362 NewValue
|= IMR_LOCK
;
363 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID
, Index
, NewValue
);
367 // Call ASM routine to switch to real mode and jump to 16bit OS waking vector
369 AsmTransferControl(AcpiWakingVector
, 0);