diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2019-02-20 06:59:17 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2019-02-20 06:59:17 +0000 |
commit | bc63c19e092d0f4d7a49de3c0c8686b96a634e25 (patch) | |
tree | 0e0ad86fdc237abbf6794bc9282399bda94fa57a /sys | |
parent | d382c767872fc3a0ccd7f6945f1b922a4ac08c02 (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.c | 61 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/vmm_support.S | 50 | ||||
-rw-r--r-- | sys/arch/amd64/include/vmmvar.h | 24 |
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 */ }; /* |