vbox6: avoid unintended state transfer on hw enter

intr_state and actv_state are now charged only if required and with
valid values.

Issue #4313
This commit is contained in:
Alexander Boettcher 2021-10-08 11:43:33 +02:00 committed by Christian Helmuth
parent 74a8a801e4
commit 8d5903cba9
3 changed files with 11 additions and 15 deletions

View File

@ -123,7 +123,6 @@ class Sup::Vcpu_impl : public Sup::Vcpu, Genode::Noncopyable
};
struct {
unsigned intr_state = 0;
unsigned ctrl_primary = VIRT::ctrl_primary();
unsigned ctrl_secondary = VIRT::ctrl_secondary();
} _cached_state;
@ -173,9 +172,6 @@ template <typename VIRT> void Sup::Vcpu_impl<VIRT>::_transfer_state_to_vcpu(CPUM
Vcpu_state &state { _vcpu.state() };
/* transfer defaults and cached state */
state.inj_info.charge(VMX_ENTRY_INT_INFO_NONE); /* XXX never injects events */
state.intr_state.charge(_cached_state.intr_state);
state.actv_state.charge(VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
state.ctrl_primary.charge(_cached_state.ctrl_primary); /* XXX always updates ctrls */
state.ctrl_secondary.charge(_cached_state.ctrl_secondary); /* XXX always updates ctrls */
@ -354,14 +350,14 @@ template <typename VIRT> void Sup::Vcpu_impl<VIRT>::_transfer_state_to_vbox(CPUM
uint32_t const tpr = state.tpr.value();
/* update cached state */
Assert(!VMX_ENTRY_INT_INFO_IS_VALID(state.inj_info.value()));
_cached_state.intr_state = state.intr_state.value();
_cached_state.ctrl_primary = state.ctrl_primary.value();
_cached_state.ctrl_secondary = state.ctrl_secondary.value();
/* clear blocking by MOV SS or STI bits */
if (_cached_state.intr_state & 3)
_cached_state.intr_state &= ~3U;
if (_vcpu.state().intr_state.value() & 3) {
_vcpu.state().intr_state.charge(state.intr_state.value() & ~3U);
_vcpu.state().actv_state.charge(VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
}
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
@ -491,7 +487,7 @@ typename Sup::Vcpu_impl<T>::Current_state Sup::Vcpu_impl<T>::_handle_paused()
Assert(state.actv_state.value() == VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
if (VMX_ENTRY_INT_INFO_IS_VALID(state.inj_info.value())) {
if (VMX_EXIT_INT_INFO_IS_VALID(state.inj_info.value())) {
Assert(state.flags.value() & X86_EFL_IF);
@ -519,7 +515,6 @@ typename Sup::Vcpu_impl<T>::Current_state Sup::Vcpu_impl<T>::_handle_paused()
/* check whether we have to request irq injection window */
if (_check_and_request_irq_window()) {
state.discharge();
state.inj_info.charge(state.inj_info.value());
_irq_window = true;
return RUNNING;
@ -541,14 +536,12 @@ typename Sup::Vcpu_impl<T>::Current_state Sup::Vcpu_impl<T>::_handle_irq_window(
{
Vcpu_state &state { _vcpu.state() };
state.discharge();
PVMCPU pVCpu = &_vmcpu;
Assert(state.intr_state.value() == VMX_VMCS_GUEST_INT_STATE_NONE);
Assert(state.flags.value() & X86_EFL_IF);
Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
Assert(!VMX_ENTRY_INT_INFO_IS_VALID(state.inj_info.value()));
Assert(!VMX_EXIT_INT_INFO_IS_VALID(state.inj_info.value()));
Assert(_irq_window);
_irq_window = false;
@ -638,6 +631,9 @@ template <typename VIRT> VBOXSTRICTRC Sup::Vcpu_impl<VIRT>::_switch_to_hw()
result = VIRT::handle_exit(_vcpu.state());
/* discharge by default */
_vcpu.state().discharge();
switch (result.state) {
case Exit_state::STARTUP:

View File

@ -193,7 +193,7 @@ Sup::Handle_exit_result Sup::Svm::handle_exit(Vcpu_state &state)
case SVM_EXIT_RDTSCP:
case SVM_EXIT_WBINVD:
Assert(state.actv_state.value() == VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
Assert(!VMX_ENTRY_INT_INFO_IS_VALID(state.inj_info.value()));
Assert(!VMX_EXIT_INT_INFO_IS_VALID(state.inj_info.value()));
return { Exit_state::DEFAULT, VINF_EM_RAW_EMULATE_INSTR };
case SVM_EXIT_VINTR:

View File

@ -183,7 +183,7 @@ void Sup::Vmx::_handle_invalid(Vcpu_state const &state)
void Sup::Vmx::_handle_default(Vcpu_state &state)
{
Assert(state.actv_state.value() == VMX_VMCS_GUEST_ACTIVITY_ACTIVE);
Assert(!VMX_ENTRY_INT_INFO_IS_VALID(state.inj_info.value()));
Assert(!VMX_EXIT_INT_INFO_IS_VALID(state.inj_info.value()));
}