diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2017-03-24 09:06:03 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2017-03-24 09:06:03 +0000 |
commit | 628010d4c9eb168cd01eb1416f903433b81b3f90 (patch) | |
tree | 492055e6a8e4833a37612888b6820b2b53d30194 /sys/arch | |
parent | 83d5e5c50b1b17d3b87f5ee02a5e3a644f41d40a (diff) |
Handle guest interruptibility state - Reset the interruptibility state
VMCS field on vmentry when we advanced %rip on the last exit (simulating
a real processor's behaviour). Handles guest "sti ; hlt" instruction
sequences, which is used in seabios as a primitive idle loop construct.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/amd64/amd64/vmm.c | 54 |
1 files changed, 37 insertions, 17 deletions
diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c index bd25f0f44b2..02fc76d2ca0 100644 --- a/sys/arch/amd64/amd64/vmm.c +++ b/sys/arch/amd64/amd64/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.124 2017/03/24 08:52:53 mlarkin Exp $ */ +/* $OpenBSD: vmm.c,v 1.125 2017/03/24 09:06:02 mlarkin Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -3377,7 +3377,7 @@ vcpu_run_vmx(struct vcpu *vcpu, struct vm_run_params *vrp) uint64_t exit_reason, cr3, vmcs_ptr, insn_error; struct schedstate_percpu *spc; struct vmx_invvpid_descriptor vid; - uint64_t eii, procbased; + uint64_t eii, procbased, int_st; uint16_t irq; resume = 0; @@ -3404,7 +3404,7 @@ vcpu_run_vmx(struct vcpu *vcpu, struct vm_run_params *vrp) case VMX_EXIT_EPT_VIOLATION: break; case VMX_EXIT_CPUID: - break; + break; #ifdef VMM_DEBUG case VMX_EXIT_TRIPLE_FAULT: DPRINTF("%s: vm %d vcpu %d triple fault\n", @@ -3481,24 +3481,27 @@ vcpu_run_vmx(struct vcpu *vcpu, struct vm_run_params *vrp) /* Handle vmd(8) injected interrupts */ /* Is there an interrupt pending injection? */ if (irq != 0xFFFF) { - if (!vcpu->vc_irqready) { - printf("vcpu_run_vmx: error - irq injected" - " while not ready\n"); + if (vmread(VMCS_GUEST_INTERRUPTIBILITY_ST, &int_st)) { + printf("%s: can't get interruptibility state\n", + __func__); ret = EINVAL; break; } - eii = (irq & 0xFF); - eii |= (1ULL << 31); /* Valid */ - eii |= (0ULL << 8); /* Hardware Interrupt */ - if (vmwrite(VMCS_ENTRY_INTERRUPTION_INFO, eii)) { - printf("vcpu_run_vmx: can't vector " - "interrupt to guest\n"); - ret = EINVAL; - break; - } + /* Interruptbility state 0x3 covers NMIs and STI */ + if (!(int_st & 0x3) && vcpu->vc_irqready) { + eii = (irq & 0xFF); + eii |= (1ULL << 31); /* Valid */ + eii |= (0ULL << 8); /* Hardware Interrupt */ + if (vmwrite(VMCS_ENTRY_INTERRUPTION_INFO, eii)) { + printf("vcpu_run_vmx: can't vector " + "interrupt to guest\n"); + ret = EINVAL; + break; + } - irq = 0xFFFF; + irq = 0xFFFF; + } } else if (!vcpu->vc_intr) { /* * Disable window exiting @@ -3774,7 +3777,7 @@ vmx_get_exit_info(uint64_t *rip, uint64_t *exit_reason) int vmx_handle_exit(struct vcpu *vcpu) { - uint64_t exit_reason, rflags; + uint64_t exit_reason, rflags, istate; int update_rip, ret = 0; update_rip = 0; @@ -3847,6 +3850,23 @@ vmx_handle_exit(struct vcpu *vcpu) printf("vmx_handle_exit: can't advance rip\n"); return (EINVAL); } + + if (vmread(VMCS_GUEST_INTERRUPTIBILITY_ST, + &istate)) { + printf("%s: can't read interruptibility state\n", + __func__); + return (EINVAL); + } + + /* Interruptibilty state 0x3 covers NMIs and STI */ + istate &= ~0x3; + + if (vmwrite(VMCS_GUEST_INTERRUPTIBILITY_ST, + istate)) { + printf("%s: can't write interruptibility state\n", + __func__); + return (EINVAL); + } } return (ret); |