Module Name: src
Committed By: maxv
Date: Thu Jan 24 13:05:59 UTC 2019
Modified Files:
src/sys/dev/nvmm: nvmm.h
src/sys/dev/nvmm/x86: nvmm_x86_svm.c
Log Message:
Optimize: change the behavior of the HLT vmexit, make it a "change in vcpu
state" which occurs after the instruction executed, rather than an
instruction intercept which occurs before. Disable the shadow and the intr
window in kernel mode, and advance the RIP, so that the virtualizer doesn't
have to do it itself. This saves two syscalls and one VMCB cache flush.
Provide npc for other instruction intercepts, in case someone is
interested.
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/nvmm/nvmm.h
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/nvmm/x86/nvmm_x86_svm.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/nvmm/nvmm.h
diff -u src/sys/dev/nvmm/nvmm.h:1.2 src/sys/dev/nvmm/nvmm.h:1.3
--- src/sys/dev/nvmm/nvmm.h:1.2 Sun Jan 6 16:10:51 2019
+++ src/sys/dev/nvmm/nvmm.h Thu Jan 24 13:05:59 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: nvmm.h,v 1.2 2019/01/06 16:10:51 maxv Exp $ */
+/* $NetBSD: nvmm.h,v 1.3 2019/01/24 13:05:59 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -53,13 +53,13 @@ enum nvmm_exit_reason {
NVMM_EXIT_MSR = 0x0000000000000003,
NVMM_EXIT_INT_READY = 0x0000000000000004,
NVMM_EXIT_NMI_READY = 0x0000000000000005,
- NVMM_EXIT_SHUTDOWN = 0x0000000000000006,
+ NVMM_EXIT_HALTED = 0x0000000000000006,
+ NVMM_EXIT_SHUTDOWN = 0x0000000000000007,
/* Instructions (x86). */
- NVMM_EXIT_HLT = 0x0000000000001000,
- NVMM_EXIT_MONITOR = 0x0000000000001001,
- NVMM_EXIT_MWAIT = 0x0000000000001002,
- NVMM_EXIT_MWAIT_COND = 0x0000000000001003,
+ NVMM_EXIT_MONITOR = 0x0000000000001000,
+ NVMM_EXIT_MWAIT = 0x0000000000001001,
+ NVMM_EXIT_MWAIT_COND = 0x0000000000001002,
NVMM_EXIT_INVALID = 0xFFFFFFFFFFFFFFFF
};
@@ -106,7 +106,7 @@ struct nvmm_exit_msr {
uint64_t npc;
};
-struct nvmm_exit_hlt {
+struct nvmm_exit_insn {
uint64_t npc;
};
@@ -116,7 +116,7 @@ struct nvmm_exit {
struct nvmm_exit_memory mem;
struct nvmm_exit_io io;
struct nvmm_exit_msr msr;
- struct nvmm_exit_hlt hlt;
+ struct nvmm_exit_insn insn;
} u;
uint64_t exitstate[8];
};
Index: src/sys/dev/nvmm/x86/nvmm_x86_svm.c
diff -u src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.16 src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.17
--- src/sys/dev/nvmm/x86/nvmm_x86_svm.c:1.16 Sun Jan 20 16:55:21 2019
+++ src/sys/dev/nvmm/x86/nvmm_x86_svm.c Thu Jan 24 13:05:59 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: nvmm_x86_svm.c,v 1.16 2019/01/20 16:55:21 maxv Exp $ */
+/* $NetBSD: nvmm_x86_svm.c,v 1.17 2019/01/24 13:05:59 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.16 2019/01/20 16:55:21 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvmm_x86_svm.c,v 1.17 2019/01/24 13:05:59 maxv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -726,31 +726,29 @@ svm_inject_ud(struct nvmm_machine *mach,
}
static void
-svm_inject_db(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
+svm_inject_gp(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
{
struct nvmm_event event;
int ret __diagused;
event.type = NVMM_EVENT_EXCEPTION;
- event.vector = 1;
+ event.vector = 13;
event.u.error = 0;
ret = svm_vcpu_inject(mach, vcpu, &event);
KASSERT(ret == 0);
}
-static void
-svm_inject_gp(struct nvmm_machine *mach, struct nvmm_cpu *vcpu)
+static inline void
+svm_inkernel_advance(struct vmcb *vmcb)
{
- struct nvmm_event event;
- int ret __diagused;
-
- event.type = NVMM_EVENT_EXCEPTION;
- event.vector = 13;
- event.u.error = 0;
-
- ret = svm_vcpu_inject(mach, vcpu, &event);
- KASSERT(ret == 0);
+ /*
+ * Maybe we should also apply single-stepping and debug exceptions.
+ * Matters for guest-ring3, because it can execute 'cpuid' under a
+ * debugger.
+ */
+ vmcb->state.rip = vmcb->ctrl.nrip;
+ vmcb->ctrl.intr &= ~VMCB_CTRL_INTR_SHADOW;
}
static void
@@ -842,12 +840,7 @@ svm_exit_cpuid(struct nvmm_machine *mach
/* Overwrite non-tunable leaves. */
svm_inkernel_handle_cpuid(vcpu, eax, ecx);
- /* For now we omit DBREGS. */
- if (__predict_false(cpudata->vmcb->state.rflags & PSL_T)) {
- svm_inject_db(mach, vcpu);
- }
-
- cpudata->vmcb->state.rip = cpudata->vmcb->ctrl.nrip;
+ svm_inkernel_advance(cpudata->vmcb);
exit->reason = NVMM_EXIT_NONE;
}
@@ -856,9 +849,14 @@ svm_exit_hlt(struct nvmm_machine *mach,
struct nvmm_exit *exit)
{
struct svm_cpudata *cpudata = vcpu->cpudata;
+ struct vmcb *vmcb = cpudata->vmcb;
- exit->reason = NVMM_EXIT_HLT;
- exit->u.hlt.npc = cpudata->vmcb->ctrl.nrip;
+ if (cpudata->int_window_exit && (vmcb->state.rflags & PSL_I)) {
+ svm_event_waitexit_disable(vcpu, false);
+ }
+
+ svm_inkernel_advance(cpudata->vmcb);
+ exit->reason = NVMM_EXIT_HALTED;
}
#define SVM_EXIT_IO_PORT __BITS(31,16)
@@ -994,7 +992,7 @@ svm_inkernel_handle_msr(struct nvmm_mach
return false;
handled:
- cpudata->vmcb->state.rip = cpudata->vmcb->ctrl.nrip;
+ svm_inkernel_advance(cpudata->vmcb);
return true;
}
@@ -1060,6 +1058,13 @@ svm_exit_npf(struct nvmm_machine *mach,
}
static void
+svm_exit_insn(struct vmcb *vmcb, struct nvmm_exit *exit, uint64_t reason)
+{
+ exit->u.insn.npc = vmcb->ctrl.nrip;
+ exit->reason = reason;
+}
+
+static void
svm_exit_xsetbv(struct nvmm_machine *mach, struct nvmm_cpu *vcpu,
struct nvmm_exit *exit)
{
@@ -1084,7 +1089,7 @@ svm_exit_xsetbv(struct nvmm_machine *mac
cpudata->gxcr0 = val;
- cpudata->vmcb->state.rip = cpudata->vmcb->ctrl.nrip;
+ svm_inkernel_advance(cpudata->vmcb);
return;
error:
@@ -1269,13 +1274,13 @@ svm_vcpu_run(struct nvmm_machine *mach,
exit->reason = NVMM_EXIT_NONE;
break;
case VMCB_EXITCODE_MONITOR:
- exit->reason = NVMM_EXIT_MONITOR;
+ svm_exit_insn(vmcb, exit, NVMM_EXIT_MONITOR);
break;
case VMCB_EXITCODE_MWAIT:
- exit->reason = NVMM_EXIT_MWAIT;
+ svm_exit_insn(vmcb, exit, NVMM_EXIT_MWAIT);
break;
case VMCB_EXITCODE_MWAIT_CONDITIONAL:
- exit->reason = NVMM_EXIT_MWAIT_COND;
+ svm_exit_insn(vmcb, exit, NVMM_EXIT_MWAIT_COND);
break;
case VMCB_EXITCODE_XSETBV:
svm_exit_xsetbv(mach, vcpu, exit);