summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMike Larkin <mlarkin@cvs.openbsd.org>2019-02-20 06:59:17 +0000
committerMike Larkin <mlarkin@cvs.openbsd.org>2019-02-20 06:59:17 +0000
commitbc63c19e092d0f4d7a49de3c0c8686b96a634e25 (patch)
tree0e0ad86fdc237abbf6794bc9282399bda94fa57a /sys
parentd382c767872fc3a0ccd7f6945f1b922a4ac08c02 (diff)
vmm(4): allow preservation and restoration of guest debug registers
Allow save/restore of %drX registers during VM exit and entry discussed with deraadt@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/vmm.c61
-rw-r--r--sys/arch/amd64/amd64/vmm_support.S50
-rw-r--r--sys/arch/amd64/include/vmmvar.h24
3 files changed, 124 insertions, 11 deletions
diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c
index d7449d0b99b..06c55a2704f 100644
--- a/sys/arch/amd64/amd64/vmm.c
+++ b/sys/arch/amd64/amd64/vmm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmm.c,v 1.228 2019/02/16 01:55:48 mlarkin Exp $ */
+/* $OpenBSD: vmm.c,v 1.229 2019/02/20 06:59:16 mlarkin Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
*
@@ -1418,6 +1418,7 @@ vcpu_readregs_vmx(struct vcpu *vcpu, uint64_t regmask,
uint64_t *gprs = vrs->vrs_gprs;
uint64_t *crs = vrs->vrs_crs;
uint64_t *msrs = vrs->vrs_msrs;
+ uint64_t *drs = vrs->vrs_drs;
struct vcpu_segment_info *sregs = vrs->vrs_sregs;
struct vmx_msr_store *msr_store;
@@ -1446,6 +1447,7 @@ vcpu_readregs_vmx(struct vcpu *vcpu, uint64_t regmask,
if (vmread(VMCS_GUEST_IA32_RFLAGS, &gprs[VCPU_REGS_RFLAGS]))
goto errout;
}
+
if (regmask & VM_RWREGS_SREGS) {
for (i = 0; i < nitems(vmm_vmx_sreg_vmcs_fields); i++) {
if (vmread(vmm_vmx_sreg_vmcs_fields[i].selid, &sel))
@@ -1477,6 +1479,7 @@ vcpu_readregs_vmx(struct vcpu *vcpu, uint64_t regmask,
goto errout;
vrs->vrs_idtr.vsi_limit = limit;
}
+
if (regmask & VM_RWREGS_CRS) {
crs[VCPU_REGS_CR2] = vcpu->vc_gueststate.vg_cr2;
crs[VCPU_REGS_XCR0] = vcpu->vc_gueststate.vg_xcr0;
@@ -1504,6 +1507,16 @@ vcpu_readregs_vmx(struct vcpu *vcpu, uint64_t regmask,
}
}
+ if (regmask & VM_RWREGS_DRS) {
+ drs[VCPU_REGS_DR0] = vcpu->vc_gueststate.vg_dr0;
+ drs[VCPU_REGS_DR1] = vcpu->vc_gueststate.vg_dr1;
+ drs[VCPU_REGS_DR2] = vcpu->vc_gueststate.vg_dr2;
+ drs[VCPU_REGS_DR3] = vcpu->vc_gueststate.vg_dr3;
+ drs[VCPU_REGS_DR6] = vcpu->vc_gueststate.vg_dr6;
+ if (vmread(VMCS_GUEST_IA32_DR7, &drs[VCPU_REGS_DR7]))
+ goto errout;
+ }
+
goto out;
errout:
@@ -1534,6 +1547,7 @@ vcpu_readregs_svm(struct vcpu *vcpu, uint64_t regmask,
uint64_t *gprs = vrs->vrs_gprs;
uint64_t *crs = vrs->vrs_crs;
uint64_t *msrs = vrs->vrs_msrs;
+ uint64_t *drs = vrs->vrs_drs;
uint32_t attr;
struct vcpu_segment_info *sregs = vrs->vrs_sregs;
struct vmcb *vmcb = (struct vmcb *)vcpu->vc_control_va;
@@ -1639,6 +1653,15 @@ vcpu_readregs_svm(struct vcpu *vcpu, uint64_t regmask,
msrs[VCPU_REGS_KGSBASE] = vmcb->v_kgsbase;
}
+ if (regmask & VM_RWREGS_DRS) {
+ drs[VCPU_REGS_DR0] = vcpu->vc_gueststate.vg_dr0;
+ drs[VCPU_REGS_DR1] = vcpu->vc_gueststate.vg_dr1;
+ drs[VCPU_REGS_DR2] = vcpu->vc_gueststate.vg_dr2;
+ drs[VCPU_REGS_DR3] = vcpu->vc_gueststate.vg_dr3;
+ drs[VCPU_REGS_DR6] = vmcb->v_dr6;
+ drs[VCPU_REGS_DR7] = vmcb->v_dr7;
+ }
+
return (0);
}
@@ -1667,6 +1690,7 @@ vcpu_writeregs_vmx(struct vcpu *vcpu, uint64_t regmask, int loadvmcs,
uint64_t *gprs = vrs->vrs_gprs;
uint64_t *crs = vrs->vrs_crs;
uint64_t *msrs = vrs->vrs_msrs;
+ uint64_t *drs = vrs->vrs_drs;
struct vcpu_segment_info *sregs = vrs->vrs_sregs;
struct vmx_msr_store *msr_store;
@@ -1699,6 +1723,7 @@ vcpu_writeregs_vmx(struct vcpu *vcpu, uint64_t regmask, int loadvmcs,
if (vmwrite(VMCS_GUEST_IA32_RFLAGS, gprs[VCPU_REGS_RFLAGS]))
goto errout;
}
+
if (regmask & VM_RWREGS_SREGS) {
for (i = 0; i < nitems(vmm_vmx_sreg_vmcs_fields); i++) {
sel = sregs[i].vsi_sel;
@@ -1729,6 +1754,7 @@ vcpu_writeregs_vmx(struct vcpu *vcpu, uint64_t regmask, int loadvmcs,
vrs->vrs_idtr.vsi_base))
goto errout;
}
+
if (regmask & VM_RWREGS_CRS) {
vcpu->vc_gueststate.vg_xcr0 = crs[VCPU_REGS_XCR0];
if (vmwrite(VMCS_GUEST_IA32_CR0, crs[VCPU_REGS_CR0]))
@@ -1755,6 +1781,16 @@ vcpu_writeregs_vmx(struct vcpu *vcpu, uint64_t regmask, int loadvmcs,
}
}
+ if (regmask & VM_RWREGS_DRS) {
+ vcpu->vc_gueststate.vg_dr0 = drs[VCPU_REGS_DR0];
+ vcpu->vc_gueststate.vg_dr1 = drs[VCPU_REGS_DR1];
+ vcpu->vc_gueststate.vg_dr2 = drs[VCPU_REGS_DR2];
+ vcpu->vc_gueststate.vg_dr3 = drs[VCPU_REGS_DR3];
+ vcpu->vc_gueststate.vg_dr6 = drs[VCPU_REGS_DR6];
+ if (vmwrite(VMCS_GUEST_IA32_DR7, drs[VCPU_REGS_DR7]))
+ goto errout;
+ }
+
goto out;
errout:
@@ -1789,6 +1825,7 @@ vcpu_writeregs_svm(struct vcpu *vcpu, uint64_t regmask,
uint64_t *crs = vrs->vrs_crs;
uint16_t attr;
uint64_t *msrs = vrs->vrs_msrs;
+ uint64_t *drs = vrs->vrs_drs;
struct vcpu_segment_info *sregs = vrs->vrs_sregs;
struct vmcb *vmcb = (struct vmcb *)vcpu->vc_control_va;
@@ -1879,6 +1916,15 @@ vcpu_writeregs_svm(struct vcpu *vcpu, uint64_t regmask,
vmcb->v_kgsbase = msrs[VCPU_REGS_KGSBASE];
}
+ if (regmask & VM_RWREGS_DRS) {
+ vcpu->vc_gueststate.vg_dr0 = drs[VCPU_REGS_DR0];
+ vcpu->vc_gueststate.vg_dr1 = drs[VCPU_REGS_DR1];
+ vcpu->vc_gueststate.vg_dr2 = drs[VCPU_REGS_DR2];
+ vcpu->vc_gueststate.vg_dr3 = drs[VCPU_REGS_DR3];
+ vmcb->v_dr6 = drs[VCPU_REGS_DR6];
+ vmcb->v_dr7 = drs[VCPU_REGS_DR7];
+ }
+
return (0);
}
@@ -2440,12 +2486,13 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_reg_state *vrs)
* Exit ctrls
*
* We must be able to set the following:
+ * IA32_VMX_SAVE_DEBUG_CONTROLS
* IA32_VMX_HOST_SPACE_ADDRESS_SIZE - exit to long mode
* IA32_VMX_ACKNOWLEDGE_INTERRUPT_ON_EXIT - ack interrupt on exit
- * XXX clear save_debug_ctrls on exit ?
*/
want1 = IA32_VMX_HOST_SPACE_ADDRESS_SIZE |
- IA32_VMX_ACKNOWLEDGE_INTERRUPT_ON_EXIT;
+ IA32_VMX_ACKNOWLEDGE_INTERRUPT_ON_EXIT |
+ IA32_VMX_SAVE_DEBUG_CONTROLS;
want0 = 0;
if (vcpu->vc_vmx_basic & IA32_VMX_TRUE_CTLS_AVAIL) {
@@ -2473,20 +2520,18 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_reg_state *vrs)
*
* We must be able to set the following:
* IA32_VMX_IA32E_MODE_GUEST (if no unrestricted guest)
+ * IA32_VMX_LOAD_DEBUG_CONTROLS
* We must be able to clear the following:
* IA32_VMX_ENTRY_TO_SMM - enter to SMM
* IA32_VMX_DEACTIVATE_DUAL_MONITOR_TREATMENT
- * IA32_VMX_LOAD_DEBUG_CONTROLS
* IA32_VMX_LOAD_IA32_PERF_GLOBAL_CTRL_ON_ENTRY
*/
+ want1 = IA32_VMX_LOAD_DEBUG_CONTROLS;
if (vrs->vrs_msrs[VCPU_REGS_EFER] & EFER_LMA)
- want1 = IA32_VMX_IA32E_MODE_GUEST;
- else
- want1 = 0;
+ want1 |= IA32_VMX_IA32E_MODE_GUEST;
want0 = IA32_VMX_ENTRY_TO_SMM |
IA32_VMX_DEACTIVATE_DUAL_MONITOR_TREATMENT |
- IA32_VMX_LOAD_DEBUG_CONTROLS |
IA32_VMX_LOAD_IA32_PERF_GLOBAL_CTRL_ON_ENTRY;
if (vcpu->vc_vmx_basic & IA32_VMX_TRUE_CTLS_AVAIL) {
diff --git a/sys/arch/amd64/amd64/vmm_support.S b/sys/arch/amd64/amd64/vmm_support.S
index e7f02555f7e..c8cb97ba7f4 100644
--- a/sys/arch/amd64/amd64/vmm_support.S
+++ b/sys/arch/amd64/amd64/vmm_support.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmm_support.S,v 1.14 2018/09/18 16:02:08 mlarkin Exp $ */
+/* $OpenBSD: vmm_support.S,v 1.15 2019/02/20 06:59:16 mlarkin Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
*
@@ -311,6 +311,16 @@ done_flush:
jnz do_resume
/* Restore guest registers */
+ movq 0xa0(%rsi), %rax
+ movq %rax, %dr0
+ movq 0xa8(%rsi), %rax
+ movq %rax, %dr1
+ movq 0xb0(%rsi), %rax
+ movq %rax, %dr2
+ movq 0xb8(%rsi), %rax
+ movq %rax, %dr3
+ movq 0xc0(%rsi), %rax
+ movq %rax, %dr6
movq 0x78(%rsi), %rax
movq %rax, %cr2
movq 0x70(%rsi), %r15
@@ -338,6 +348,16 @@ done_flush:
jmp fail_launch_or_resume
do_resume:
/* Restore guest registers */
+ movq 0xa0(%rsi), %rax
+ movq %rax, %dr0
+ movq 0xa8(%rsi), %rax
+ movq %rax, %dr1
+ movq 0xb0(%rsi), %rax
+ movq %rax, %dr2
+ movq 0xb8(%rsi), %rax
+ movq %rax, %dr3
+ movq 0xc0(%rsi), %rax
+ movq %rax, %dr6
movq 0x78(%rsi), %rax
movq %rax, %cr2
movq 0x70(%rsi), %r15
@@ -416,6 +436,16 @@ vmx_exit_handler_asm:
movq %r15, 0x70(%rsi)
movq %cr2, %rax
movq %rax, 0x78(%rsi)
+ movq %dr0, %rax
+ movq %rax, 0xa0(%rsi)
+ movq %dr1, %rax
+ movq %rax, 0xa8(%rsi)
+ movq %dr2, %rax
+ movq %rax, 0xb0(%rsi)
+ movq %dr3, %rax
+ movq %rax, 0xb8(%rsi)
+ movq %dr6, %rax
+ movq %rax, 0xc0(%rsi)
/* %rdi = 0 means we took an exit */
xorq %rdi, %rdi
@@ -563,6 +593,15 @@ _C_LABEL(svm_enter_guest):
/* Restore guest registers */
movq %r8, %rax /* rax = vmcb pa */
+ movq 0xa0(%rsi), %r8
+ movq %r8, %dr0
+ movq 0xa8(%rsi), %r8
+ movq %r8, %dr1
+ movq 0xb0(%rsi), %r8
+ movq %r8, %dr2
+ movq 0xb8(%rsi), %r8
+ movq %r8, %dr3
+ /* %dr6 is saved in the VMCB */
movq 0x78(%rsi), %r8
movq %r8, %cr2
movq 0x70(%rsi), %r15
@@ -611,6 +650,15 @@ _C_LABEL(svm_enter_guest):
movq %r15, 0x70(%rsi)
movq %cr2, %rax
movq %rax, 0x78(%rsi)
+ movq %dr0, %rax
+ movq %rax, 0xa0(%rsi)
+ movq %dr1, %rax
+ movq %rax, 0xa8(%rsi)
+ movq %dr2, %rax
+ movq %rax, 0xb0(%rsi)
+ movq %dr3, %rax
+ movq %rax, 0xb8(%rsi)
+ /* %dr6 is saved in the VMCB */
/* %rdi = 0 means we took an exit */
xorq %rdi, %rdi
diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h
index 812e660f5f2..8479e19abfd 100644
--- a/sys/arch/amd64/include/vmmvar.h
+++ b/sys/arch/amd64/include/vmmvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmmvar.h,v 1.59 2018/09/20 14:32:59 brynet Exp $ */
+/* $OpenBSD: vmmvar.h,v 1.60 2019/02/20 06:59:16 mlarkin Exp $ */
/*
* Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org>
*
@@ -415,10 +415,19 @@ struct vcpu_segment_info {
#define VCPU_REGS_MISC_ENABLE 6
#define VCPU_REGS_NMSRS (VCPU_REGS_MISC_ENABLE + 1)
+#define VCPU_REGS_DR0 0
+#define VCPU_REGS_DR1 1
+#define VCPU_REGS_DR2 2
+#define VCPU_REGS_DR3 3
+#define VCPU_REGS_DR6 4
+#define VCPU_REGS_DR7 5
+#define VCPU_REGS_NDRS (VCPU_REGS_DR7 + 1)
+
struct vcpu_reg_state {
uint64_t vrs_gprs[VCPU_REGS_NGPRS];
uint64_t vrs_crs[VCPU_REGS_NCRS];
uint64_t vrs_msrs[VCPU_REGS_NMSRS];
+ uint64_t vrs_drs[VCPU_REGS_NDRS];
struct vcpu_segment_info vrs_sregs[VCPU_REGS_NSREGS];
struct vcpu_segment_info vrs_gdtr;
struct vcpu_segment_info vrs_idtr;
@@ -519,8 +528,9 @@ struct vm_intr_params {
#define VM_RWREGS_SREGS 0x2 /* read/write segment registers */
#define VM_RWREGS_CRS 0x4 /* read/write CRs */
#define VM_RWREGS_MSRS 0x8 /* read/write MSRs */
+#define VM_RWREGS_DRS 0x10 /* read/write DRs */
#define VM_RWREGS_ALL (VM_RWREGS_GPRS | VM_RWREGS_SREGS | VM_RWREGS_CRS | \
- VM_RWREGS_MSRS)
+ VM_RWREGS_MSRS | VM_RWREGS_DRS)
struct vm_rwregs_params {
/*
@@ -812,6 +822,16 @@ struct vcpu_gueststate
uint32_t vg_exit_reason; /* 0x88 */
uint64_t vg_rflags; /* 0x90 */
uint64_t vg_xcr0; /* 0x98 */
+ /*
+ * Debug registers
+ * - %dr4/%dr5 are aliased to %dr6/%dr7 (or cause #DE)
+ * - %dr7 is saved automatically in the VMCS
+ */
+ uint64_t vg_dr0; /* 0xa0 */
+ uint64_t vg_dr1; /* 0xa8 */
+ uint64_t vg_dr2; /* 0xb0 */
+ uint64_t vg_dr3; /* 0xb8 */
+ uint64_t vg_dr6; /* 0xc0 */
};
/*