STM/Stm/StmPkg/Core/Runtime/SmiHandler.c

180 lines
4.8 KiB
C

/** @file
SMI handler
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "StmRuntime.h"
STM_HANDLER mStmHandlerSmi[VmExitReasonMax];
/**
This function initialize STM handle for SMI.
**/
VOID
InitStmHandlerSmi (
VOID
)
{
UINT32 Index;
for (Index = 0; Index < VmExitReasonMax; Index++) {
mStmHandlerSmi[Index] = UnknownHandlerSmi;
}
mStmHandlerSmi[VmExitReasonIoSmi] = SmiEventHandler;
mStmHandlerSmi[VmExitReasonOtherSmi] = SmiEventHandler;
mStmHandlerSmi[VmExitReasonVmCall] = SmiVmcallHandler;
AsmWbinvd (); // make sure all see it
}
/**
This function is unknown handler for SMI.
@param Index CPU index
**/
VOID
UnknownHandlerSmi (
IN UINT32 Index
)
{
AcquireSpinLock (&mHostContextCommon.DebugLock);
DEBUG ((EFI_D_ERROR, "!!!UnknownHandlerSmi - %d\n", (UINTN)Index));
DumpVmcsAllField ();
ReleaseSpinLock (&mHostContextCommon.DebugLock);
CpuDeadLoop ();
}
/**
This function checks Pending Mtf before resume.
@param Index CPU index
**/
VOID
CheckPendingMtf (
IN UINT32 Index
)
{
VM_EXIT_INFO_INTERRUPTION VmEntryControlInterrupt;
//
// Check pending MTF
//
if (mGuestContextCommonSmi.GuestContextPerCpu[Index].InfoBasic.Bits.PendingMtf == 0) {
return ;
}
//
// In this case, prior to resuming the interrupted guest, the STM must set the VMENTRY
// interrupt-information field in the interrupted contexts VMCS to 80000070H (inject
// "other event" number 0). This will cause an MTF VMEXIT to be pended and delivered
// immediately after completion of the VMRESUME from the STM.
//
// If the STM doesn't do this re-injection, the guest will execute two instructions, rather
// than one, before the MTF VMEXIT occurs. This may have undesirable effects on the
// MLE and must be avoided.
//
VmEntryControlInterrupt.Uint32 = 0;
VmEntryControlInterrupt.Bits.InterruptType = INTERRUPT_TYPE_OTHER_EVENT;
VmEntryControlInterrupt.Bits.Valid = 1;
VmWrite32 (VMCS_32_CONTROL_VMENTRY_INTERRUPTION_INFO_INDEX, VmEntryControlInterrupt.Uint32);
}
/**
This function is STM handler for SMI.
@param Register X86 register context
**/
VOID
StmHandlerSmi (
IN X86_REGISTER *Register
)
{
UINT32 Index;
UINTN Rflags;
VM_EXIT_INFO_BASIC InfoBasic;
X86_REGISTER *Reg;
Index = ApicToIndex (ReadLocalApicId ());
InfoBasic.Uint32 = VmRead32 (VMCS_32_RO_EXIT_REASON_INDEX);
STM_PERF_START (Index, InfoBasic.Bits.Reason, "OsSmiHandler", "StmHandlerSmi");
Reg = &mGuestContextCommonSmi.GuestContextPerCpu[Index].Register;
Register->Rsp = VmReadN (VMCS_N_GUEST_RSP_INDEX);
CopyMem (Reg, Register, sizeof(X86_REGISTER));
#if 0
DEBUG ((EFI_D_INFO, "%ld - !!!StmHandlerSmi InfoBasic %x reason %x \n",
(UINTN)Index,
InfoBasic.Uint32,
InfoBasic.Bits.Reason));
#endif
//
// Dispatch
//
if (InfoBasic.Bits.Reason >= VmExitReasonMax) {
DEBUG ((EFI_D_ERROR, "%ld !!!UnknownReason: %d!!!\n", Index, InfoBasic.Bits.Reason));
DumpVmcsAllField ();
CpuDeadLoop ();
}
mGuestContextCommonSmi.GuestContextPerCpu[Index].InfoBasic.Uint32 = InfoBasic.Uint32;
//
// Call dispatch handler
//
mStmHandlerSmi[InfoBasic.Bits.Reason] (Index);
VmWriteN (VMCS_N_GUEST_RSP_INDEX, Reg->Rsp); // sync RSP
STM_PERF_END (Index, "OsSmiHandler", "StmHandlerSmi");
CheckPendingMtf (Index);
// clear caches
AsmWbinvd(); // flush caches
//
// Resume
//
Rflags = AsmVmResume (&mGuestContextCommonSmi.GuestContextPerCpu[Index].Register);
// BUGBUG: - AsmVmLaunch if AsmVmResume fail
if (VmRead32 (VMCS_32_RO_VM_INSTRUCTION_ERROR_INDEX) == VmxFailErrorVmResumeWithNonLaunchedVmcs) {
// DEBUG ((EFI_D_ERROR, "(STM):o(\n", (UINTN)Index));
Rflags = AsmVmLaunch (&mGuestContextCommonSmi.GuestContextPerCpu[Index].Register);
}
AcquireSpinLock (&mHostContextCommon.DebugLock);
DEBUG ((EFI_D_ERROR, "%ld StmHandlerSmi - !!!ResumeGuestSmi FAIL!!!", (UINTN)Index));
DEBUG ((EFI_D_ERROR, "%ld StmHandlerSmi - Rflags: %08x\n", Index, Rflags));
DEBUG ((EFI_D_ERROR, "%ld StmHandlerSmi - VMCS_32_RO_VM_INSTRUCTION_ERROR: %08x\n", Index, (UINTN)VmRead32 (VMCS_32_RO_VM_INSTRUCTION_ERROR_INDEX)));
DumpVmcsAllField ();
DumpRegContext (&mGuestContextCommonSmi.GuestContextPerCpu[Index].Register);
DumpGuestStack(Index);
ReleaseSpinLock (&mHostContextCommon.DebugLock);
CpuDeadLoop ();
return ;
}