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