/** This function is IO write handler for reset. @param Context Context for IO write handler @param Port IO port @param Value IO port value @param Action IO write action **/ VOID IoResetWriteHandler ( IN VOID *Context, IN UINT16 Port, IN UINT32 Value, OUT UINT32 *Action ) { UINT32 Index; Index = ApicToIndex (ReadLocalApicId ()); DEBUG ((EFI_D_INFO, "(FRM) !!!IoResetHandler!!!\n")); FrmTeardownBsp (Index); AsmWbinvd (); // // Work-around for CTRL+ALT+DEL, it will pass 0x2. // Value = Value | 0x6; IoWrite8 (Port, (UINT8)Value); CpuDeadLoop (); *Action = IO_ACTION_PASSTHROUGH; return ; }
/** This function is IO write handler for KBC reset. @param Context Context for IO write handler @param Port IO port @param Value IO port value @param Action IO write action **/ VOID KbcResetWriteHandler ( IN VOID *Context, IN UINT16 Port, IN UINT32 Value, OUT UINT32 *Action ) { UINT32 Index; Index = ApicToIndex (ReadLocalApicId ()); DEBUG ((EFI_D_INFO, "(FRM) !!!KbcResetHandler!!!\n")); if ((UINT8)Value != KBC_RESET_WRITE_VALUE) { // Normal KB *Action = IO_ACTION_PASSTHROUGH; return ; } // Reset FrmTeardownBsp (Index); AsmWbinvd (); *Action = IO_ACTION_PASSTHROUGH; return ; }
/** Erase a certain block from address LbaWriteAddress @param[in] WriteAddress The flash address to be erased. @return The status of flash erase. **/ EFI_STATUS FlashFdErase ( IN UINTN WriteAddress ) { EFI_STATUS Status; Status = mSpiProtocol->Execute ( mSpiProtocol, SPI_OPCODE_ERASE_INDEX, // OpcodeIndex 0, // PrefixOpcodeIndex FALSE, // DataCycle TRUE, // Atomic FALSE, // ShiftOut WriteAddress, // Address 0, // Data Number NULL, EnumSpiRegionBios // SPI_REGION_TYPE ); DEBUG((DEBUG_INFO, "FlashFdErase - 0x%x - %r\n", (UINTN)WriteAddress, Status)); AsmWbinvd (); return Status; }
/** Writes specified number of bytes from the input buffer to the address @param[in] WriteAddress The flash address to be written. @param[in, out] NumBytes The number of bytes. @param[in] Buffer The data buffer to be written. @return The status of flash write. **/ EFI_STATUS FlashFdWrite ( IN UINTN WriteAddress, IN OUT UINTN *NumBytes, IN UINT8 *Buffer ) { EFI_STATUS Status; Status = EFI_SUCCESS; Status = mSpiProtocol->Execute ( mSpiProtocol, SPI_OPCODE_WRITE_INDEX, // OpcodeIndex 0, // PrefixOpcodeIndex TRUE, // DataCycle TRUE, // Atomic TRUE, // ShiftOut WriteAddress, // Address (UINT32) (*NumBytes), // Data Number Buffer, EnumSpiRegionBios ); DEBUG((DEBUG_INFO, "FlashFdWrite - 0x%x - %r\n", (UINTN)WriteAddress, Status)); AsmWbinvd (); return Status; }
/** Invalidates processor instruction cache for a memory range. Subsequent execution in this range causes a fresh memory fetch to retrieve code to be executed. @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL instance. @param ProcessorIndex Specifies which processor's instruction cache is to be invalidated. @param Start Specifies the physical base of the memory range to be invalidated. @param Length Specifies the minimum number of bytes in the processor's instruction cache to invalidate. @retval EFI_SUCCESS Always returned. **/ EFI_STATUS EFIAPI InvalidateInstructionCache ( IN EFI_DEBUG_SUPPORT_PROTOCOL *This, IN UINTN ProcessorIndex, IN VOID *Start, IN UINT64 Length ) { AsmWbinvd (); return EFI_SUCCESS; }
/** This function initialize host context per CPU. @param Index CPU Index **/ VOID InitHostContextPerCpu ( IN UINT32 Index ) { // // VmxOn for this CPU // AsmWbinvd (); AsmWriteCr3 (mHostContextCommon.PageTable); AsmWriteCr4 (AsmReadCr4 () | CR4_PAE | ((UINTN)AsmReadMsr64 (IA32_VMX_CR4_FIXED0_MSR_INDEX) & (UINTN)AsmReadMsr64 (IA32_VMX_CR4_FIXED1_MSR_INDEX))); AsmWriteCr0 (AsmReadCr0 () | ((UINTN)AsmReadMsr64 (IA32_VMX_CR0_FIXED0_MSR_INDEX) & (UINTN)AsmReadMsr64 (IA32_VMX_CR0_FIXED1_MSR_INDEX))); AsmVmxOn (&mHostContextCommon.HostContextPerCpu[Index].Vmcs); }
/** Flush CPU data cache. If the instruction cache is fully coherent with all DMA operations then function can just return EFI_SUCCESS. @param This Protocol instance structure @param Start Physical address to start flushing from. @param Length Number of bytes to flush. Round up to chipset granularity. @param FlushType Specifies the type of flush operation to perform. @retval EFI_SUCCESS If cache was flushed @retval EFI_UNSUPPORTED If flush type is not supported. @retval EFI_DEVICE_ERROR If requested range could not be flushed. **/ EFI_STATUS EFIAPI CpuFlushCpuDataCache ( IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_PHYSICAL_ADDRESS Start, IN UINT64 Length, IN EFI_CPU_FLUSH_TYPE FlushType ) { if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { AsmWbinvd (); return EFI_SUCCESS; } else if (FlushType == EfiCpuFlushTypeInvalidate) { AsmInvd (); return EFI_SUCCESS; } else { return EFI_UNSUPPORTED; } }
/** This function is IO handler for reset. @param Index CPU index @param Port Reset IO port address @param Data Reset IO port data **/ VOID IoResetHandler ( IN UINT32 Index, IN UINT16 Port, IN UINT8 Data ) { DEBUG ((EFI_D_INFO, "(FRM) !!!IoResetHandler!!!\n")); FrmTeardownBsp (Index); AsmWbinvd (); // // Work-around for CTRL+ALT+DEL, it will pass 0x2. // Data = Data | 0x6; IoWrite8 (Port, Data); CpuDeadLoop (); return ; }
EFI_STATUS EFIAPI CpuFlushCpuDataCache ( IN EFI_CPU_ARCH_PROTOCOL *This, IN EFI_PHYSICAL_ADDRESS Start, IN UINT64 Length, IN EFI_CPU_FLUSH_TYPE FlushType ) /*++ Routine Description: Flush CPU data cache. If the instruction cache is fully coherent with all DMA operations then function can just return EFI_SUCCESS. Arguments: This - Protocol instance structure Start - Physical address to start flushing from. Length - Number of bytes to flush. Round up to chipset granularity. FlushType - Specifies the type of flush operation to perform. Returns: EFI_SUCCESS - If cache was flushed EFI_UNSUPPORTED - If flush type is not supported. EFI_DEVICE_ERROR - If requested range could not be flushed. --*/ { if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) { AsmWbinvd (); return EFI_SUCCESS; } else if (FlushType == EfiCpuFlushTypeInvalidate) { AsmInvd (); return EFI_SUCCESS; } else { return EFI_UNSUPPORTED; } }
/** This function launch guest BSP. **/ VOID LaunchGuestBsp ( VOID ) { UINTN Flag; UINTN Rflags; Flag = SetJump (&mGuestJumpBuffer); if (Flag != 0) { DEBUG ((EFI_D_INFO, "(FRM) !!!Guest JumpBack to EFI!!!\n")); // Run successfully return ; } AsmVmPtrLoad (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Vmcs); // // Launch STM // LaunchStm (mBspIndex); AsmVmPtrLoad (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Vmcs); AcquireSpinLock (&mHostContextCommon.DebugLock); DumpVmcsAllField (); ReleaseSpinLock (&mHostContextCommon.DebugLock); AsmWbinvd (); Rflags = AsmVmLaunch (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Register); DEBUG ((EFI_D_ERROR, "(FRM) !!!LaunchGuestBsp FAIL!!!\n")); DEBUG ((EFI_D_ERROR, "(FRM) Rflags: %08x\n", Rflags)); DEBUG ((EFI_D_ERROR, "(FRM) VMCS_32_RO_VM_INSTRUCTION_ERROR: %08x\n", (UINTN)VmRead32 (VMCS_32_RO_VM_INSTRUCTION_ERROR_INDEX))); CpuDeadLoop (); }
/** 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_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs; EFI_STATUS Status; UINTN TempStackTop; UINTN TempStack[0x10]; UINTN AsmTransferControl16Address; IA32_DESCRIPTOR IdtDescriptor; // // Disable interrupt of Debug timer, since new IDT table cannot handle it. // SaveAndSetDebugTimerInterrupt (FALSE); AsmReadIdtr (&IdtDescriptor); // // Restore IDT for debug // SetIdtEntry (AcpiS3Context); // // Initialize Debug Agent to support source level debug in S3 path, it will disable interrupt and Debug Timer. // InitializeDebugAgent (DEBUG_AGENT_INIT_S3, (VOID *)&IdtDescriptor, NULL); // // Because not install BootScriptExecute PPI(used just in this module), So just pass NULL // for that parameter. // Status = S3BootScriptExecute (); // // If invalid script table or opcode in S3 boot script table. // ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { CpuDeadLoop (); return Status; } AsmWbinvd (); // // Get ACPI Table Address // Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)); // // 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; if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { // // X64 S3 Resume // DEBUG ((EFI_D_ERROR, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl32; if ((Facs != NULL) && (Facs->Signature == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) && (Facs->FirmwareWakingVector != 0) ) { // // more step needed - because relative address is handled differently between X64 and IA32. // AsmTransferControl16Address = (UINTN)AsmTransferControl16; AsmFixAddress16 = (UINT32)AsmTransferControl16Address; AsmJmpAddr32 = (UINT32)((Facs->FirmwareWakingVector & 0xF) | ((Facs->FirmwareWakingVector & 0xFFFF0) << 12)); } AsmDisablePaging64 ( PeiS3ResumeState->ReturnCs, (UINT32)PeiS3ResumeState->ReturnEntryPoint, (UINT32)(UINTN)AcpiS3Context, (UINT32)(UINTN)PeiS3ResumeState, (UINT32)PeiS3ResumeState->ReturnStackPointer ); } else { // // IA32 S3 Resume // DEBUG ((EFI_D_ERROR, "Call SwitchStack() to return to S3 Resume in PEI Phase\n")); PeiS3ResumeState->AsmTransferControl = (EFI_PHYSICAL_ADDRESS)(UINTN)AsmTransferControl; 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; } // // S3ResumePeim does not provide a way to jump back to itself, so resume to OS here directly // if (Facs->XFirmwareWakingVector != 0) { // // Switch to native waking vector // TempStackTop = (UINTN)&TempStack + sizeof(TempStack); if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) && ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) && ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) { // // X64 long mode waking vector // DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector, NULL, NULL, (VOID *)(UINTN)TempStackTop ); } else { // Unsupported for 32bit DXE, 64bit OS vector DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n")); ASSERT (FALSE); } } else { // // IA32 protected mode waking vector (Page disabled) // DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector)); if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { AsmDisablePaging64 ( 0x10, (UINT32)Facs->XFirmwareWakingVector, 0, 0, (UINT32)TempStackTop ); } else { SwitchStack ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Facs->XFirmwareWakingVector, NULL, NULL, (VOID *)(UINTN)TempStackTop ); } } } else { // // 16bit Realmode waking vector // DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector)); AsmTransferControl (Facs->FirmwareWakingVector, 0x0); } // // Never run to here // CpuDeadLoop(); return EFI_UNSUPPORTED; }
/** Calling this function causes the system to enter a power state for capsule update. Reset update should not return, if it returns, it means the system does not support capsule update. **/ VOID EFIAPI EnterS3WithImmediateWake ( VOID ) { UINT8 Data8; UINT16 Data16; UINT32 Data32; UINTN Eflags; UINTN RegCr0; EFI_TIME EfiTime; UINT32 SmiEnSave; Eflags = AsmReadEflags (); if ( (Eflags & 0x200) ) { DisableInterrupts (); } // // Write all cache data to memory because processor will lost power // AsmWbinvd(); RegCr0 = AsmReadCr0(); AsmWriteCr0 (RegCr0 | 0x060000000); SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN)); // // Pogram RTC alarm for immediate WAKE // // // Disable SMI sources // IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0); // // Disable RTC alarm interrupt // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5)); // // Clear RTC alarm if already set // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); // Read clears alarm status // // Disable all WAKE events // IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED); // // Clear all WAKE status bits // IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL); // // Avoid RTC rollover // do { WaitForRTCUpdate(); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS); EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER); } while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT); // // Read RTC time // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS); EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES); EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS); EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER); // // Set RTC alarm // // // Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second // The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second) // if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) { Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F)))); } else { Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER; } IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM); IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM); IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute); IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM); IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8); // // Enable RTC alarm interrupt // IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B); Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5)); // // Enable RTC alarm as WAKE event // Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E); IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC)); // // Enter S3 // Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C); Data32 = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN); IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32); Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN; IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32); // // Enable Interrupt if it's enabled before // if ( (Eflags & 0x200) ) { EnableInterrupts (); } }
/** 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; }