+++ /dev/null
-/** @file\r
-This is the code for Boot Script Executer module.\r
-\r
-This driver is dispatched by Dxe core and the driver will reload itself to ACPI NVS memory\r
-in the entry point. The functionality is to interpret and restore the S3 boot script\r
-\r
-Copyright (c) 2013-2016 Intel Corporation.\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "ScriptExecute.h"\r
-\r
-#pragma pack(1)\r
-typedef union {\r
- struct {\r
- UINT32 LimitLow : 16;\r
- UINT32 BaseLow : 16;\r
- UINT32 BaseMid : 8;\r
- UINT32 Type : 4;\r
- UINT32 System : 1;\r
- UINT32 Dpl : 2;\r
- UINT32 Present : 1;\r
- UINT32 LimitHigh : 4;\r
- UINT32 Software : 1;\r
- UINT32 Reserved : 1;\r
- UINT32 DefaultSize : 1;\r
- UINT32 Granularity : 1;\r
- UINT32 BaseHigh : 8;\r
- } Bits;\r
- UINT64 Uint64;\r
-} IA32_GDT;\r
-\r
-#pragma pack()\r
-\r
-EFI_GUID mBootScriptExecutorImageGuid = {\r
- 0x9a8d3433, 0x9fe8, 0x42b6, {0x87, 0xb, 0x1e, 0x31, 0xc8, 0x4e, 0xbe, 0x3b}\r
-};\r
-\r
-//\r
-// Global Descriptor Table (GDT)\r
-//\r
-GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {\r
-/* selector { Global Segment Descriptor } */\r
-/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
-/* 0x08 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
-/* 0x10 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}},\r
-/* 0x18 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 1, 1, 0}},\r
-/* 0x20 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
-/* 0x28 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}},\r
-/* 0x30 */ {{0xFFFF, 0, 0, 0x3, 1, 0, 1, 0xF, 0, 0, 0, 1, 0}},\r
-/* 0x38 */ {{0xFFFF, 0, 0, 0xB, 1, 0, 1, 0xF, 0, 1, 0, 1, 0}},\r
-/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},\r
-};\r
-\r
-//\r
-// IA32 Gdt register\r
-//\r
-GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = {\r
- sizeof (mGdtEntries) - 1,\r
- (UINTN) mGdtEntries\r
- };\r
-\r
-/**\r
- Entry function of Boot script exector. This function will be executed in\r
- S3 boot path.\r
- This function should not return, because it is invoked by switch stack.\r
-\r
- @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT\r
- @param PeiS3ResumeState a pointer to a structure of PEI_S3_RESUME_STATE\r
-\r
- @retval EFI_INVALID_PARAMETER - OS waking vector not found\r
- @retval EFI_UNSUPPORTED - something wrong when we resume to OS\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-S3BootScriptExecutorEntryFunction (\r
- IN ACPI_S3_CONTEXT *AcpiS3Context,\r
- IN PEI_S3_RESUME_STATE *PeiS3ResumeState\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- //\r
- // Disable interrupt of Debug timer, since new IDT table cannot handle it.\r
- //\r
- SaveAndSetDebugTimerInterrupt (FALSE);\r
-\r
- //\r
- // Restore IDT for debug\r
- //\r
- SetIdtEntry (AcpiS3Context);\r
-\r
- //\r
- // Initialize Debug Agent to support source level debug in S3 path.\r
- //\r
- InitializeDebugAgent (DEBUG_AGENT_INIT_S3, NULL, NULL);\r
-\r
- //\r
- // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL\r
- // for that parameter.\r
- //\r
- Status = S3BootScriptExecute ();\r
-\r
- AsmWbinvd ();\r
-\r
- //\r
- // We need turn back to S3Resume - install boot script done ppi and report status code on S3resume.\r
- //\r
- if (PeiS3ResumeState != 0) {\r
- //\r
- // Need report status back to S3ResumePeim.\r
- // If boot script execution is failed, S3ResumePeim wil report the error status code.\r
- //\r
- PeiS3ResumeState->ReturnStatus = (UINT64)(UINTN)Status;\r
- //\r
- // IA32 S3 Resume\r
- //\r
- DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));\r
- PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)PlatformTransferControl16;\r
-\r
- SwitchStack (\r
- (SWITCH_STACK_ENTRY_POINT)(UINTN)PeiS3ResumeState->ReturnEntryPoint,\r
- (VOID *)(UINTN)AcpiS3Context,\r
- (VOID *)(UINTN)PeiS3ResumeState,\r
- (VOID *)(UINTN)PeiS3ResumeState->ReturnStackPointer\r
- );\r
-\r
- //\r
- // Never run to here\r
- //\r
- CpuDeadLoop();\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- //\r
- // Never run to here\r
- //\r
- CpuDeadLoop();\r
- return EFI_UNSUPPORTED;\r
-}\r
-/**\r
- Entrypoint of Boot script exector driver, this function will be executed in\r
- normal boot phase and invoked by DXE dispatch.\r
-\r
- @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
- @param[in] SystemTable A pointer to the EFI System Table.\r
-\r
- @retval EFI_SUCCESS The entry point is executed successfully.\r
- @retval other Some error occurs when executing this entry point.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-BootScriptExecutorEntryPoint (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- UINT8 *Buffer;\r
- UINTN BufferSize;\r
- UINTN Pages;\r
- EFI_PHYSICAL_ADDRESS FfsBuffer;\r
- PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
- BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable;\r
- EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer;\r
- EFI_STATUS Status;\r
- VOID *DevicePath;\r
- EFI_HANDLE NewImageHandle;\r
-\r
- //\r
- // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry\r
- // point is loaded by DXE code which is the first time loaded. or else, it is already\r
- // be reloaded be itself.This is a work-around\r
- //\r
- Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath);\r
- if (EFI_ERROR (Status)) {\r
-\r
- //\r
- // This is the first-time loaded by DXE core. reload itself to NVS mem\r
- //\r
- //\r
- // A workarouond: Here we install a dummy handle\r
- //\r
- NewImageHandle = NULL;\r
- Status = gBS->InstallProtocolInterface (\r
- &NewImageHandle,\r
- &gEfiCallerIdGuid,\r
- EFI_NATIVE_INTERFACE,\r
- NULL\r
- );\r
-\r
- Status = GetSectionFromAnyFv (\r
- &gEfiCallerIdGuid,\r
- EFI_SECTION_PE32,\r
- 0,\r
- (VOID **) &Buffer,\r
- &BufferSize\r
- );\r
- ImageContext.Handle = Buffer;\r
- ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
- //\r
- // Get information about the image being loaded\r
- //\r
- Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- Pages = EFI_SIZE_TO_PAGES(BufferSize + ImageContext.SectionAlignment);\r
- FfsBuffer = 0xFFFFFFFF;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiACPIMemoryNVS,\r
- Pages,\r
- &FfsBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;\r
- //\r
- // Align buffer on section boundary\r
- //\r
- ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
- ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
- //\r
- // Load the image to our new buffer\r
- //\r
- Status = PeCoffLoaderLoadImage (&ImageContext);\r
- if (EFI_ERROR (Status)) {\r
- gBS->FreePages (FfsBuffer, Pages);\r
- return Status;\r
- }\r
-\r
- //\r
- // Relocate the image in our new buffer\r
- //\r
- Status = PeCoffLoaderRelocateImage (&ImageContext);\r
-\r
- if (EFI_ERROR (Status)) {\r
- PeCoffLoaderUnloadImage (&ImageContext);\r
- gBS->FreePages (FfsBuffer, Pages);\r
- return Status;\r
- }\r
- //\r
- // Flush the instruction cache so the image data is written before we execute it\r
- //\r
- InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
- Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);\r
- if (EFI_ERROR (Status)) {\r
- gBS->FreePages (FfsBuffer, Pages);\r
- return Status;\r
- }\r
- //\r
- // Additional step for BootScript integrity\r
- // Save BootScriptExecutor image\r
- //\r
- Status = SaveLockBox (\r
- &mBootScriptExecutorImageGuid,\r
- (VOID *)(UINTN)ImageContext.ImageAddress,\r
- (UINTN)ImageContext.ImageSize\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- } else {\r
- //\r
- // the entry point is invoked after reloading. following code only run in ACPI NVS\r
- //\r
- BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE);\r
-\r
- BootScriptExecutorBuffer = 0xFFFFFFFF;\r
- Pages = EFI_SIZE_TO_PAGES(BufferSize);\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiACPIMemoryNVS,\r
- Pages,\r
- &BootScriptExecutorBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer;\r
- EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ;\r
-\r
- Status = SaveLockBox (\r
- &gEfiBootScriptExecutorVariableGuid,\r
- &BootScriptExecutorBuffer,\r
- sizeof(BootScriptExecutorBuffer)\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Additional step for BootScript integrity\r
- // Save BootScriptExecutor context\r
- //\r
- Status = SaveLockBox (\r
- &gEfiBootScriptExecutorContextGuid,\r
- EfiBootScriptExecutorVariable,\r
- sizeof(*EfiBootScriptExecutorVariable)\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Platform specific mechanism to transfer control to 16bit OS waking vector\r
-\r
- @param[in] AcpiWakingVector The 16bit OS waking vector\r
- @param[in] AcpiLowMemoryBase A buffer under 1M which could be used during the transfer\r
-\r
-**/\r
-VOID\r
-PlatformTransferControl16 (\r
- IN UINT32 AcpiWakingVector,\r
- IN UINT32 AcpiLowMemoryBase\r
- )\r
-{\r
- UINT32 NewValue;\r
- UINT64 BaseAddress;\r
- UINT64 SmramLength;\r
- UINTN Index;\r
-\r
- DEBUG (( EFI_D_INFO, "PlatformTransferControl - Entry\r\n"));\r
-\r
- //\r
- // Need to make sure the GDT is loaded with values that support long mode and real mode.\r
- //\r
- AsmWriteGdtr (&mGdt);\r
-\r
- //\r
- // Disable eSram block (this will also clear/zero eSRAM)\r
- // We only use eSRAM in the PEI phase. Disable now that we are resuming the OS\r
- //\r
- NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK);\r
- NewValue |= BLOCK_DISABLE_PG;\r
- QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK, NewValue);\r
-\r
- //\r
- // Update HMBOUND to top of DDR3 memory and LOCK\r
- // We disabled eSRAM so now we move HMBOUND down to top of DDR3\r
- //\r
- QNCGetTSEGMemoryRange (&BaseAddress, &SmramLength);\r
- NewValue = (UINT32)(BaseAddress + SmramLength);\r
- DEBUG ((EFI_D_INFO,"Locking HMBOUND at: = 0x%8x\n",NewValue));\r
- QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG, (NewValue | HMBOUND_LOCK));\r
-\r
- //\r
- // Lock all IMR regions now that HMBOUND is locked\r
- //\r
- 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) {\r
- NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index);\r
- NewValue |= IMR_LOCK;\r
- QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index, NewValue);\r
- }\r
-\r
- //\r
- // Call ASM routine to switch to real mode and jump to 16bit OS waking vector\r
- //\r
- AsmTransferControl(AcpiWakingVector, 0);\r
-\r
- //\r
- // Never run to here\r
- //\r
- CpuDeadLoop();\r
-}\r
-\r
-\r
-\r
-\r