svm updates
This commit is contained in:
parent
c403b4b699
commit
76ee7b499b
@ -4274,7 +4274,7 @@ public: // for now...
|
||||
BX_SMF bx_bool SvmEnterLoadCheckControls(SVM_CONTROLS *ctrls);
|
||||
BX_SMF bx_bool SvmEnterLoadCheckGuestState(void);
|
||||
BX_SMF bx_bool SvmInjectEvents(void);
|
||||
BX_SMF void Svm_Vmexit(int reason);
|
||||
BX_SMF void Svm_Vmexit(int reason, Bit64u exitinfo1 = 0);
|
||||
BX_SMF void SvmExitSaveGuestState(void);
|
||||
BX_SMF void SvmExitLoadHostState(SVM_HOST_STATE *host);
|
||||
BX_SMF Bit8u vmcb_read8(unsigned offset);
|
||||
|
@ -656,6 +656,12 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::MONITOR(bxInstruction_c *i)
|
||||
|
||||
bx_phy_address paddr = translate_linear(laddr, USER_PL, BX_READ);
|
||||
|
||||
#if BX_SUPPORT_SVM
|
||||
if (BX_CPU_THIS_PTR in_svm_guest) {
|
||||
if (SVM_INTERCEPT(SVM_INTERCEPT1_MONITOR)) Svm_Vmexit(SVM_VMEXIT_MONITOR);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set the monitor immediately. If monitor is still armed when we MWAIT,
|
||||
// the processor will stall.
|
||||
|
||||
@ -692,6 +698,15 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::MWAIT(bxInstruction_c *i)
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_SVM
|
||||
if (BX_CPU_THIS_PTR in_svm_guest) {
|
||||
if (SVM_INTERCEPT(SVM_INTERCEPT1_MWAIT_ARMED))
|
||||
if (BX_CPU_THIS_PTR monitor.armed) Svm_Vmexit(SVM_VMEXIT_MWAIT_CONDITIONAL);
|
||||
|
||||
if (SVM_INTERCEPT(SVM_INTERCEPT1_MWAIT)) Svm_Vmexit(SVM_VMEXIT_MWAIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If monitor has already triggered, we just return.
|
||||
if (! BX_CPU_THIS_PTR monitor.armed) {
|
||||
BX_DEBUG(("MWAIT: the MONITOR was not armed or already triggered"));
|
||||
|
@ -234,7 +234,7 @@ void BX_CPU_C::SvmExitLoadHostState(SVM_HOST_STATE *host)
|
||||
BX_CPU_THIS_PTR idtr = host->idtr;
|
||||
|
||||
BX_CPU_THIS_PTR efer.set32(host->efer);
|
||||
BX_CPU_THIS_PTR cr0.set32(host->cr0 | 0x1); // always set the CR0.PE
|
||||
BX_CPU_THIS_PTR cr0.set32(host->cr0 | BX_CR0_PE_MASK); // always set the CR0.PE
|
||||
BX_CPU_THIS_PTR cr3 = host->cr3;
|
||||
BX_CPU_THIS_PTR cr4.set32(host->cr4);
|
||||
|
||||
@ -247,10 +247,7 @@ void BX_CPU_C::SvmExitLoadHostState(SVM_HOST_STATE *host)
|
||||
|
||||
BX_CPU_THIS_PTR dr7.set32(0x00000400);
|
||||
|
||||
// set flags directly, avoid setEFlags side effects
|
||||
BX_CPU_THIS_PTR eflags = host->eflags & ~EFlagsVMMask; // ignore saved copy of EFLAGS.VM
|
||||
// Update lazy flags state
|
||||
setEFlagsOSZAPC(host->eflags);
|
||||
setEFlags(host->eflags & ~EFlagsVMMask); // ignore saved copy of EFLAGS.VM
|
||||
|
||||
RIP = BX_CPU_THIS_PTR prev_rip = host->rip;
|
||||
RSP = host->rsp;
|
||||
@ -314,37 +311,37 @@ void BX_CPU_C::SvmExitSaveGuestState(void)
|
||||
|
||||
bx_bool BX_CPU_C::SvmEnterLoadCheckControls(SVM_CONTROLS *ctrls)
|
||||
{
|
||||
ctrls->cr_rd_ctrl = vmcb_read16(SVM_CONTROL_INTERCEPT_CR_READ);
|
||||
ctrls->cr_wr_ctrl = vmcb_read16(SVM_CONTROL_INTERCEPT_CR_WRITE);
|
||||
ctrls->cr_rd_ctrl = vmcb_read16(SVM_CONTROL16_INTERCEPT_CR_READ);
|
||||
ctrls->cr_wr_ctrl = vmcb_read16(SVM_CONTROL16_INTERCEPT_CR_WRITE);
|
||||
|
||||
ctrls->dr_rd_ctrl = vmcb_read16(SVM_CONTROL_INTERCEPT_DR_READ);
|
||||
ctrls->dr_wr_ctrl = vmcb_read16(SVM_CONTROL_INTERCEPT_DR_WRITE);
|
||||
ctrls->dr_rd_ctrl = vmcb_read16(SVM_CONTROL16_INTERCEPT_DR_READ);
|
||||
ctrls->dr_wr_ctrl = vmcb_read16(SVM_CONTROL16_INTERCEPT_DR_WRITE);
|
||||
|
||||
ctrls->intercept_vector[0] = vmcb_read32(SVM_CONTROL_INTERCEPT1);
|
||||
ctrls->intercept_vector[1] = vmcb_read32(SVM_CONTROL_INTERCEPT2);
|
||||
ctrls->intercept_vector[0] = vmcb_read32(SVM_CONTROL32_INTERCEPT1);
|
||||
ctrls->intercept_vector[1] = vmcb_read32(SVM_CONTROL32_INTERCEPT2);
|
||||
|
||||
if (! SVM_INTERCEPT(SVM_INTERCEPT1_VMRUN)) {
|
||||
BX_ERROR(("VMRUN: VMRUN intercept bit is not set!"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctrls->exceptions_intercept = vmcb_read32(SVM_CONTROL_INTERCEPT_EXCEPTIONS);
|
||||
ctrls->exceptions_intercept = vmcb_read32(SVM_CONTROL32_INTERCEPT_EXCEPTIONS);
|
||||
|
||||
// force 4K page alignment
|
||||
ctrls->iopm_base = PPFOf(vmcb_read64(SVM_CONTROL_IOPM_BASE_PHY_ADDR));
|
||||
ctrls->iopm_base = PPFOf(vmcb_read64(SVM_CONTROL64_IOPM_BASE_PHY_ADDR));
|
||||
if (! IsValidPhyAddr(ctrls->iopm_base)) {
|
||||
BX_ERROR(("VMRUN: invalid IOPM Base Address !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// force 4K page alignment
|
||||
ctrls->msrpm_base = PPFOf(vmcb_read64(SVM_CONTROL_MSRPM_BASE_PHY_ADDR));
|
||||
ctrls->msrpm_base = PPFOf(vmcb_read64(SVM_CONTROL64_MSRPM_BASE_PHY_ADDR));
|
||||
if (! IsValidPhyAddr(ctrls->msrpm_base)) {
|
||||
BX_ERROR(("VMRUN: invalid MSRPM Base Address !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bit32u guest_asid = vmcb_read32(SVM_CONTROL_GUEST_ASID);
|
||||
Bit32u guest_asid = vmcb_read32(SVM_CONTROL32_GUEST_ASID);
|
||||
if (guest_asid == 0) {
|
||||
BX_ERROR(("VMRUN: attempt to run guest with host ASID !"));
|
||||
return 0;
|
||||
@ -363,10 +360,8 @@ bx_bool BX_CPU_C::SvmEnterLoadCheckControls(SVM_CONTROLS *ctrls)
|
||||
BX_PANIC(("VMRUN: Nested Paging support is not implemented yet !"));
|
||||
}
|
||||
|
||||
vmcb_write64(SVM_CONTROL_EXITINFO1, 0);
|
||||
|
||||
/* clear exitinfo2 so we behave like the real hardware */
|
||||
vmcb_write64(SVM_CONTROL_EXITINFO2, 0);
|
||||
vmcb_write64(SVM_CONTROL64_EXITINFO2, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -395,6 +390,11 @@ bx_bool BX_CPU_C::SvmEnterLoadCheckGuestState(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! guest.efer.get_SVME()) {
|
||||
BX_ERROR(("VMRUN: Guest EFER.SVME = 0"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
guest.cr0.val32 = vmcb_read32(SVM_GUEST_CR0);
|
||||
tmp = vmcb_read32(SVM_GUEST_CR0_HI);
|
||||
if (tmp) {
|
||||
@ -478,7 +478,7 @@ bx_bool BX_CPU_C::SvmEnterLoadCheckGuestState(void)
|
||||
// Load guest state
|
||||
//
|
||||
|
||||
BX_CPU_THIS_PTR tsc_offset = vmcb_read64(SVM_CONTROL_TSC_OFFSET);
|
||||
BX_CPU_THIS_PTR tsc_offset = vmcb_read64(SVM_CONTROL64_TSC_OFFSET);
|
||||
|
||||
BX_CPU_THIS_PTR efer.set32(guest.efer.get32());
|
||||
|
||||
@ -554,15 +554,18 @@ bx_bool BX_CPU_C::SvmEnterLoadCheckGuestState(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BX_CPU_C::Svm_Vmexit(int reason)
|
||||
void BX_CPU_C::Svm_Vmexit(int reason, Bit64u exitinfo1)
|
||||
{
|
||||
BX_DEBUG(("SVM VMEXIT reason=%d", reason));
|
||||
BX_DEBUG(("SVM VMEXIT reason=%d exitinfo1=0x%08x%08x", reason, GET32H(exitinfo1), GET32L(exitinfo1)));
|
||||
|
||||
if (!BX_CPU_THIS_PTR in_svm_guest) {
|
||||
if (reason != SVM_VMEXIT_INVALID)
|
||||
BX_PANIC(("PANIC: VMEXIT %d not in SVM guest mode !", reason));
|
||||
}
|
||||
|
||||
if (BX_SUPPORT_SVM_EXTENSION(BX_CPUID_SVM_NRIP_SAVE))
|
||||
vmcb_write64(SVM_CONTROL64_NRIP, RIP);
|
||||
|
||||
// VMEXITs are FAULT-like: restore RIP/RSP to value before VMEXIT occurred
|
||||
RIP = BX_CPU_THIS_PTR prev_rip;
|
||||
if (BX_CPU_THIS_PTR speculative_rsp)
|
||||
@ -577,15 +580,16 @@ void BX_CPU_C::Svm_Vmexit(int reason)
|
||||
|
||||
SVM_CONTROLS *ctrls = &BX_CPU_THIS_PTR vmcb.ctrls;
|
||||
|
||||
vmcb_write64(SVM_CONTROL_EXITCODE, (Bit64u) ((Bit64s) reason));
|
||||
vmcb_write64(SVM_CONTROL64_EXITCODE, (Bit64u) ((Bit64s) reason));
|
||||
vmcb_write64(SVM_CONTROL64_EXITINFO1, exitinfo1);
|
||||
|
||||
if (BX_CPU_THIS_PTR in_event) {
|
||||
vmcb_write32(SVM_CONTROL_EXITINTINFO, ctrls->exitintinfo | 0x80000000);
|
||||
vmcb_write32(SVM_CONTROL_EXITINTINFO_ERROR_CODE, ctrls->exitintinfo_error_code);
|
||||
vmcb_write32(SVM_CONTROL32_EXITINTINFO, ctrls->exitintinfo | 0x80000000);
|
||||
vmcb_write32(SVM_CONTROL32_EXITINTINFO_ERROR_CODE, ctrls->exitintinfo_error_code);
|
||||
BX_CPU_THIS_PTR in_event = 0;
|
||||
}
|
||||
else {
|
||||
vmcb_write32(SVM_CONTROL_EXITINTINFO, 0);
|
||||
vmcb_write32(SVM_CONTROL32_EXITINTINFO, 0);
|
||||
}
|
||||
|
||||
//
|
||||
@ -619,18 +623,19 @@ extern struct BxExceptionInfo exceptions_info[];
|
||||
|
||||
bx_bool BX_CPU_C::SvmInjectEvents(void)
|
||||
{
|
||||
Bit32u injecting_event = vmcb_read32(SVM_CONTROL_EVENT_INJECTION);
|
||||
Bit32u injecting_event = vmcb_read32(SVM_CONTROL32_EVENT_INJECTION);
|
||||
if ((injecting_event & 0x80000000) == 0) return 1;
|
||||
|
||||
/* the VMENTRY injecting event to the guest */
|
||||
unsigned vector = injecting_event & 0xff;
|
||||
unsigned type = (injecting_event >> 8) & 7;
|
||||
unsigned push_error = injecting_event & (1 << 11);
|
||||
unsigned error_code = push_error ? vmcb_read32(SVM_CONTROL_EVENT_INJECTION_ERRORCODE) : 0;
|
||||
unsigned error_code = push_error ? vmcb_read32(SVM_CONTROL32_EVENT_INJECTION_ERRORCODE) : 0;
|
||||
|
||||
switch(type) {
|
||||
case BX_EXTERNAL_INTERRUPT:
|
||||
case BX_NMI:
|
||||
vector = 2;
|
||||
case BX_EXTERNAL_INTERRUPT:
|
||||
BX_CPU_THIS_PTR EXT = 1;
|
||||
break;
|
||||
|
||||
@ -729,9 +734,9 @@ void BX_CPU_C::SvmInterceptException(unsigned type, unsigned vector, Bit16u errc
|
||||
BX_CPU_THIS_PTR in_event = 0; // clear in_event indication on #DF
|
||||
|
||||
if (errcode_valid) {
|
||||
vmcb_write64(SVM_CONTROL_EXITINFO1, errcode);
|
||||
vmcb_write64(SVM_CONTROL64_EXITINFO1, errcode);
|
||||
if (vector == BX_PF_EXCEPTION)
|
||||
vmcb_write64(SVM_CONTROL_EXITINFO2, qualification);
|
||||
vmcb_write64(SVM_CONTROL64_EXITINFO2, qualification);
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR debug_trap = 0; // clear debug_trap field
|
||||
@ -824,9 +829,15 @@ void BX_CPU_C::SvmInterceptIO(bxInstruction_c *i, unsigned port, unsigned len)
|
||||
else if (len == 4)
|
||||
qualification |= SVM_VMEXIT_IO_INSTR_LEN32;
|
||||
|
||||
vmcb_write64(SVM_CONTROL_EXITINFO1, qualification);
|
||||
vmcb_write64(SVM_CONTROL_EXITINFO2, RIP);
|
||||
Svm_Vmexit(SVM_VMEXIT_IO);
|
||||
if (i->as64L())
|
||||
qualification |= SVM_VMEXIT_IO_INSTR_ASIZE64;
|
||||
else if (i->as32L())
|
||||
qualification |= SVM_VMEXIT_IO_INSTR_ASIZE32;
|
||||
else
|
||||
qualification |= SVM_VMEXIT_IO_INSTR_ASIZE16;
|
||||
|
||||
vmcb_write64(SVM_CONTROL64_EXITINFO2, RIP);
|
||||
Svm_Vmexit(SVM_VMEXIT_IO, qualification);
|
||||
}
|
||||
}
|
||||
|
||||
@ -857,8 +868,7 @@ void BX_CPU_C::SvmInterceptMSR(unsigned op, Bit32u msr)
|
||||
}
|
||||
|
||||
if (vmexit) {
|
||||
vmcb_write64(SVM_CONTROL_EXITINFO1, op); // 0 - RDMSR, 1 - WRMSR
|
||||
Svm_Vmexit(SVM_VMEXIT_MSR);
|
||||
Svm_Vmexit(SVM_VMEXIT_MSR, op); // 0 - RDMSR, 1 - WRMSR
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,35 +97,40 @@ enum SVM_intercept_codes {
|
||||
// VMCB control fields
|
||||
// =====================
|
||||
|
||||
#define SVM_CONTROL_INTERCEPT_CR_READ (0x000)
|
||||
#define SVM_CONTROL_INTERCEPT_CR_WRITE (0x002)
|
||||
#define SVM_CONTROL_INTERCEPT_DR_READ (0x004)
|
||||
#define SVM_CONTROL_INTERCEPT_DR_WRITE (0x006)
|
||||
#define SVM_CONTROL_INTERCEPT_EXCEPTIONS (0x008)
|
||||
#define SVM_CONTROL_INTERCEPT1 (0x00c)
|
||||
#define SVM_CONTROL_INTERCEPT2 (0x010)
|
||||
#define SVM_CONTROL16_INTERCEPT_CR_READ (0x000)
|
||||
#define SVM_CONTROL16_INTERCEPT_CR_WRITE (0x002)
|
||||
#define SVM_CONTROL16_INTERCEPT_DR_READ (0x004)
|
||||
#define SVM_CONTROL16_INTERCEPT_DR_WRITE (0x006)
|
||||
#define SVM_CONTROL32_INTERCEPT_EXCEPTIONS (0x008)
|
||||
#define SVM_CONTROL32_INTERCEPT1 (0x00c)
|
||||
#define SVM_CONTROL32_INTERCEPT2 (0x010)
|
||||
|
||||
#define SVM_CONTROL_IOPM_BASE_PHY_ADDR (0x040)
|
||||
#define SVM_CONTROL_MSRPM_BASE_PHY_ADDR (0x048)
|
||||
#define SVM_CONTROL_TSC_OFFSET (0x050)
|
||||
#define SVM_CONTROL_GUEST_ASID (0x058)
|
||||
#define SVM_CONTROL_TLB_CONTROL (0x05c)
|
||||
#define SVM_CONTROL_VTPR (0x060)
|
||||
#define SVM_CONTROL_VIRQ (0x061)
|
||||
#define SVM_CONTROL_VINTR_PRIO_IGN_TPR (0x062)
|
||||
#define SVM_CONTROL_VINTR_MASKING (0x063)
|
||||
#define SVM_CONTROL_VINTR_VECTOR (0x064)
|
||||
#define SVM_CONTROL_INTERRUPT_SHADOW (0x068)
|
||||
#define SVM_CONTROL_EXITCODE (0x070)
|
||||
#define SVM_CONTROL_EXITINFO1 (0x078)
|
||||
#define SVM_CONTROL_EXITINFO2 (0x080)
|
||||
#define SVM_CONTROL_EXITINTINFO (0x088)
|
||||
#define SVM_CONTROL_EXITINTINFO_ERROR_CODE (0x08c)
|
||||
#define SVM_CONTROL_NESTED_PAGING_ENABLE (0x090)
|
||||
#define SVM_CONTROL16_PAUSE_FILTER_THRESHOLD (0x03c)
|
||||
#define SVM_CONTROL16_PAUSE_FILTER_COUNT (0x03e)
|
||||
#define SVM_CONTROL64_IOPM_BASE_PHY_ADDR (0x040)
|
||||
#define SVM_CONTROL64_MSRPM_BASE_PHY_ADDR (0x048)
|
||||
#define SVM_CONTROL64_TSC_OFFSET (0x050)
|
||||
#define SVM_CONTROL32_GUEST_ASID (0x058)
|
||||
#define SVM_CONTROL32_TLB_CONTROL (0x05c)
|
||||
#define SVM_CONTROL_VTPR (0x060)
|
||||
#define SVM_CONTROL_VIRQ (0x061)
|
||||
#define SVM_CONTROL_VINTR_PRIO_IGN_TPR (0x062)
|
||||
#define SVM_CONTROL_VINTR_MASKING (0x063)
|
||||
#define SVM_CONTROL_VINTR_VECTOR (0x064)
|
||||
#define SVM_CONTROL_INTERRUPT_SHADOW (0x068)
|
||||
#define SVM_CONTROL64_EXITCODE (0x070)
|
||||
#define SVM_CONTROL64_EXITINFO1 (0x078)
|
||||
#define SVM_CONTROL64_EXITINFO2 (0x080)
|
||||
#define SVM_CONTROL32_EXITINTINFO (0x088)
|
||||
#define SVM_CONTROL32_EXITINTINFO_ERROR_CODE (0x08c)
|
||||
#define SVM_CONTROL_NESTED_PAGING_ENABLE (0x090)
|
||||
|
||||
#define SVM_CONTROL_EVENT_INJECTION (0x0a8)
|
||||
#define SVM_CONTROL_EVENT_INJECTION_ERRORCODE (0x0ac)
|
||||
#define SVM_CONTROL_NESTED_PAGING_HOST_CR3 (0x0b0)
|
||||
#define SVM_CONTROL32_EVENT_INJECTION (0x0a8)
|
||||
#define SVM_CONTROL32_EVENT_INJECTION_ERRORCODE (0x0ac)
|
||||
#define SVM_CONTROL64_NESTED_PAGING_HOST_CR3 (0x0b0)
|
||||
#define SVM_CONTROL_LBR_VIRTUALIZATION_ENABLE (0x0b8)
|
||||
#define SVM_CONTROL32_VMCB_CLEAN_BITS (0x0c0)
|
||||
#define SVM_CONTROL64_NRIP (0x0c8)
|
||||
|
||||
// ======================
|
||||
// VMCB save state area
|
||||
@ -214,7 +219,13 @@ enum SVM_intercept_codes {
|
||||
#define SVM_GUEST_SYSENTER_ESP_MSR (0x630)
|
||||
#define SVM_GUEST_SYSENTER_EIP_MSR (0x638)
|
||||
#define SVM_GUEST_CR2 (0x640)
|
||||
|
||||
#define SVM_GUEST_PAT (0x668) /* used only when nested paging is enabled */
|
||||
#define SVM_GUEST_DBGCTL_MSR (0x670)
|
||||
#define SVM_GUEST_BR_FROM_MSR (0x678)
|
||||
#define SVM_GUEST_BR_TO_MSR (0x680)
|
||||
#define SVM_GUEST_LAST_EXCEPTION_FROM_MSR (0x688)
|
||||
#define SVM_GUEST_LAST_EXCEPTION_TO_MSR (0x690)
|
||||
|
||||
typedef struct bx_SVM_HOST_STATE
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user