From 1a770dd2600b6a73dbe94dd867609bc49f286687 Mon Sep 17 00:00:00 2001 From: Stanislav Shwartsman Date: Tue, 5 Mar 2013 21:12:43 +0000 Subject: [PATCH] implementation of virtual NMI --- bochs/cpu/cpu.h | 2 +- bochs/cpu/ctrl_xfer16.cc | 7 +++++-- bochs/cpu/ctrl_xfer32.cc | 7 +++++-- bochs/cpu/ctrl_xfer64.cc | 7 +++++-- bochs/cpu/event.cc | 6 +++--- bochs/cpu/smm.cc | 4 ++-- bochs/cpu/svm.cc | 2 +- bochs/cpu/vmx.cc | 37 +++++++++++++++++++++++++++++++------ 8 files changed, 53 insertions(+), 19 deletions(-) diff --git a/bochs/cpu/cpu.h b/bochs/cpu/cpu.h index c60fc1bf2..3aa347370 100644 --- a/bochs/cpu/cpu.h +++ b/bochs/cpu/cpu.h @@ -1111,7 +1111,7 @@ public: // for now... #define BX_EVENT_VMX_MONITOR_TRAP_FLAG (1 << 4) #define BX_EVENT_VMX_PREEMPTION_TIMER_EXPIRED (1 << 5) #define BX_EVENT_VMX_INTERRUPT_WINDOW_EXITING (1 << 6) -#define BX_EVENT_VMX_NMI_WINDOW_EXITING (1 << 7) +#define BX_EVENT_VMX_VIRTUAL_NMI (1 << 7) #define BX_EVENT_SVM_VIRQ_PENDING (1 << 8) #define BX_EVENT_PENDING_VMX_VIRTUAL_INTR (1 << 9) #define BX_EVENT_PENDING_INTR (1 << 10) diff --git a/bochs/cpu/ctrl_xfer16.cc b/bochs/cpu/ctrl_xfer16.cc index 2c3ef12ee..413ee2dd9 100644 --- a/bochs/cpu/ctrl_xfer16.cc +++ b/bochs/cpu/ctrl_xfer16.cc @@ -551,9 +551,12 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET16(bxInstruction_c *i) #endif #if BX_SUPPORT_VMX - if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_EXITING)) + if (BX_CPU_THIS_PTR in_vmx_guest && PIN_VMEXIT(VMX_VM_EXEC_CTRL1_NMI_EXITING)) { + if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_VIRTUAL_NMI)) unmask_event(BX_EVENT_VMX_VIRTUAL_NMI); + } + else #endif - unmask_event(BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + unmask_event(BX_EVENT_NMI); #if BX_DEBUGGER BX_CPU_THIS_PTR show_flag |= Flag_iret; diff --git a/bochs/cpu/ctrl_xfer32.cc b/bochs/cpu/ctrl_xfer32.cc index 4a2aac139..b851c9940 100644 --- a/bochs/cpu/ctrl_xfer32.cc +++ b/bochs/cpu/ctrl_xfer32.cc @@ -594,9 +594,12 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET32(bxInstruction_c *i) #endif #if BX_SUPPORT_VMX - if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_EXITING)) + if (BX_CPU_THIS_PTR in_vmx_guest && PIN_VMEXIT(VMX_VM_EXEC_CTRL1_NMI_EXITING)) { + if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_VIRTUAL_NMI)) unmask_event(BX_EVENT_VMX_VIRTUAL_NMI); + } + else #endif - unmask_event(BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + unmask_event(BX_EVENT_NMI); #if BX_DEBUGGER BX_CPU_THIS_PTR show_flag |= Flag_iret; diff --git a/bochs/cpu/ctrl_xfer64.cc b/bochs/cpu/ctrl_xfer64.cc index 53e8d9995..88fec9bdf 100644 --- a/bochs/cpu/ctrl_xfer64.cc +++ b/bochs/cpu/ctrl_xfer64.cc @@ -433,9 +433,12 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET64(bxInstruction_c *i) #endif #if BX_SUPPORT_VMX - if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_EXITING)) + if (BX_CPU_THIS_PTR in_vmx_guest && PIN_VMEXIT(VMX_VM_EXEC_CTRL1_NMI_EXITING)) { + if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_VIRTUAL_NMI)) unmask_event(BX_EVENT_VMX_VIRTUAL_NMI); + } + else #endif - unmask_event(BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + unmask_event(BX_EVENT_NMI); #if BX_DEBUGGER BX_CPU_THIS_PTR show_flag |= Flag_iret; diff --git a/bochs/cpu/event.cc b/bochs/cpu/event.cc index e17b85c17..61f5ebb33 100644 --- a/bochs/cpu/event.cc +++ b/bochs/cpu/event.cc @@ -40,7 +40,7 @@ bx_bool BX_CPU_C::handleWaitForEvent(void) BX_EVENT_VMX_VIRTUAL_APIC_WRITE | BX_EVENT_VMX_MONITOR_TRAP_FLAG | BX_EVENT_VMX_PREEMPTION_TIMER_EXPIRED | - BX_EVENT_VMX_NMI_WINDOW_EXITING)) + BX_EVENT_VMX_VIRTUAL_NMI)) { // interrupt ends the HALT condition #if BX_SUPPORT_MONITOR_MWAIT @@ -277,7 +277,7 @@ bx_bool BX_CPU_C::handleAsyncEvent(void) } #endif #if BX_SUPPORT_VMX - else if (is_unmasked_event_pending(BX_EVENT_VMX_NMI_WINDOW_EXITING)) { + else if (is_unmasked_event_pending(BX_EVENT_VMX_VIRTUAL_NMI)) { VMexit(VMX_VMEXIT_NMI_WINDOW, 0); } #endif @@ -288,7 +288,7 @@ bx_bool BX_CPU_C::handleAsyncEvent(void) } #endif clear_event(BX_EVENT_NMI); - mask_event(BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + mask_event(BX_EVENT_NMI); BX_CPU_THIS_PTR EXT = 1; /* external event */ #if BX_SUPPORT_VMX VMexit_Event(BX_NMI, 2, 0, 0); diff --git a/bochs/cpu/smm.cc b/bochs/cpu/smm.cc index 9e3f54113..c7fd3eaba 100644 --- a/bochs/cpu/smm.cc +++ b/bochs/cpu/smm.cc @@ -56,7 +56,7 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::RSM(bxInstruction_c *i) BX_INFO(("RSM: Resuming from System Management Mode")); - unmask_event(BX_EVENT_SMI | BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + unmask_event(BX_EVENT_SMI | BX_EVENT_NMI | BX_EVENT_VMX_VIRTUAL_NMI); Bit32u saved_state[SMM_SAVE_STATE_MAP_SIZE], n; // reset reserved bits @@ -120,7 +120,7 @@ void BX_CPU_C::enter_system_management_mode(void) BX_CPU_THIS_PTR in_smm = 1; - mask_event(BX_EVENT_SMI | BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + mask_event(BX_EVENT_SMI | BX_EVENT_NMI | BX_EVENT_VMX_VIRTUAL_NMI); Bit32u saved_state[SMM_SAVE_STATE_MAP_SIZE], n; // reset reserved bits diff --git a/bochs/cpu/svm.cc b/bochs/cpu/svm.cc index 097381098..3f3c46600 100644 --- a/bochs/cpu/svm.cc +++ b/bochs/cpu/svm.cc @@ -686,7 +686,7 @@ bx_bool BX_CPU_C::SvmInjectEvents(void) switch(type) { case BX_NMI: - mask_event(BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + mask_event(BX_EVENT_NMI); BX_CPU_THIS_PTR EXT = 1; vector = 2; break; diff --git a/bochs/cpu/vmx.cc b/bochs/cpu/vmx.cc index ad1dcad31..82eb2b717 100644 --- a/bochs/cpu/vmx.cc +++ b/bochs/cpu/vmx.cc @@ -864,6 +864,15 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void) BX_ERROR(("VMFAIL: VMENTRY bad injected event vector %d", vector)); return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD; } +/* + // injecting NMI + if (vm->vmexec_ctrls1 & VMX_VM_EXEC_CTRL1_VIRTUAL_NMI) { + if (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_NMI_BLOCKED) { + BX_ERROR(("VMFAIL: VMENTRY injected NMI vector when blocked by NMI in interruptibility state", vector)); + return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD; + } + } +*/ break; case BX_HARDWARE_EXCEPTION: @@ -1885,11 +1894,14 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification) } if (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_NMI_BLOCKED) { - mask_event(BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + if (vm->vmexec_ctrls1 & VMX_VM_EXEC_CTRL1_VIRTUAL_NMI) + mask_event(BX_EVENT_VMX_VIRTUAL_NMI); + else + mask_event(BX_EVENT_NMI); } if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_NMI_WINDOW_EXITING) { - signal_event(BX_EVENT_VMX_NMI_WINDOW_EXITING); + signal_event(BX_EVENT_VMX_VIRTUAL_NMI); } if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_INTERRUPT_WINDOW_VMEXIT) { @@ -1935,7 +1947,11 @@ void BX_CPU_C::VMenterInjectEvents(void) break; case BX_NMI: - mask_event(BX_EVENT_NMI | BX_EVENT_VMX_NMI_WINDOW_EXITING); + if (vm->vmexec_ctrls1 & VMX_VM_EXEC_CTRL1_VIRTUAL_NMI) + mask_event(BX_EVENT_VMX_VIRTUAL_NMI); + else + mask_event(BX_EVENT_NMI); + BX_CPU_THIS_PTR EXT = 1; break; @@ -2137,10 +2153,19 @@ void BX_CPU_C::VMexitSaveGuestState(void) else interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_BY_STI; } + if (is_masked_event(BX_EVENT_SMI)) interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_SMI_BLOCKED; - if (is_masked_event(BX_EVENT_NMI)) - interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_NMI_BLOCKED; + + if (vm->vmexec_ctrls1 & VMX_VM_EXEC_CTRL1_VIRTUAL_NMI) { + if (is_masked_event(BX_EVENT_VMX_VIRTUAL_NMI)) + interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_NMI_BLOCKED; + } + else { + if (is_masked_event(BX_EVENT_NMI)) + interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_NMI_BLOCKED; + } + VMwrite32(VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE, interruptibility_state); #if BX_SUPPORT_VMX >= 2 @@ -2421,7 +2446,7 @@ void BX_CPU_C::VMexit(Bit32u reason, Bit64u qualification) BX_EVENT_VMX_MONITOR_TRAP_FLAG | BX_EVENT_VMX_INTERRUPT_WINDOW_EXITING | BX_EVENT_VMX_PREEMPTION_TIMER_EXPIRED | - BX_EVENT_VMX_NMI_WINDOW_EXITING | + BX_EVENT_VMX_VIRTUAL_NMI | BX_EVENT_PENDING_VMX_VIRTUAL_INTR); //