summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMike Larkin <mlarkin@cvs.openbsd.org>2017-03-24 09:06:03 +0000
committerMike Larkin <mlarkin@cvs.openbsd.org>2017-03-24 09:06:03 +0000
commit628010d4c9eb168cd01eb1416f903433b81b3f90 (patch)
tree492055e6a8e4833a37612888b6820b2b53d30194 /sys/arch
parent83d5e5c50b1b17d3b87f5ee02a5e3a644f41d40a (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.c54
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);