diff options
-rw-r--r-- | sys/arch/amd64/amd64/vmm.c | 71 | ||||
-rw-r--r-- | sys/arch/amd64/include/vmmvar.h | 66 | ||||
-rw-r--r-- | usr.sbin/vmd/vm.c | 48 | ||||
-rw-r--r-- | usr.sbin/vmd/vmd.c | 129 | ||||
-rw-r--r-- | usr.sbin/vmd/vmd.h | 13 |
5 files changed, 247 insertions, 80 deletions
diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c index 5262b37b949..fb8303c5e1c 100644 --- a/sys/arch/amd64/amd64/vmm.c +++ b/sys/arch/amd64/amd64/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.167 2017/08/20 05:14:16 mlarkin Exp $ */ +/* $OpenBSD: vmm.c,v 1.168 2017/08/20 21:15:32 pd Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -5379,41 +5379,8 @@ vmm_handle_cpuid(struct vcpu *vcpu) /* mask off host's APIC ID, reset to vcpu id */ *rbx = cpu_ebxfeature & 0x0000FFFF; *rbx |= (vcpu->vc_id & 0xFF) << 24; - /* - * clone host capabilities minus: - * debug store (CPUIDECX_DTES64, CPUIDECX_DSCPL, CPUID_DS) - * monitor/mwait (CPUIDECX_MWAIT) - * vmx (CPUIDECX_VMX) - * smx (CPUIDECX_SMX) - * speedstep (CPUIDECX_EST) - * thermal (CPUIDECX_TM2, CPUID_ACPI, CPUID_TM) - * context id (CPUIDECX_CNXTID) - * silicon debug (CPUIDECX_SDBG) - * xTPR (CPUIDECX_XTPR) - * perf/debug (CPUIDECX_PDCM) - * pcid (CPUIDECX_PCID) - * direct cache access (CPUIDECX_DCA) - * x2APIC (CPUIDECX_X2APIC) - * apic deadline (CPUIDECX_DEADLINE) - * apic (CPUID_APIC) - * psn (CPUID_PSN) - * self snoop (CPUID_SS) - * hyperthreading (CPUID_HTT) - * pending break enabled (CPUID_PBE) - * MTRR (CPUID_MTRR) - * plus: - * hypervisor (CPUIDECX_HV) - */ - *rcx = (cpu_ecxfeature | CPUIDECX_HV) & - ~(CPUIDECX_EST | CPUIDECX_TM2 | CPUIDECX_MWAIT | - CPUIDECX_PDCM | CPUIDECX_VMX | CPUIDECX_DTES64 | - CPUIDECX_DSCPL | CPUIDECX_SMX | CPUIDECX_CNXTID | - CPUIDECX_SDBG | CPUIDECX_XTPR | CPUIDECX_PCID | - CPUIDECX_DCA | CPUIDECX_X2APIC | CPUIDECX_DEADLINE); - *rdx = curcpu()->ci_feature_flags & - ~(CPUID_ACPI | CPUID_TM | CPUID_HTT | - CPUID_DS | CPUID_APIC | CPUID_PSN | - CPUID_SS | CPUID_PBE | CPUID_MTRR); + *rcx = (cpu_ecxfeature | CPUIDECX_HV) & VMM_CPUIDECX_MASK; + *rdx = curcpu()->ci_feature_flags & VMM_CPUIDEDX_MASK; break; case 0x02: /* Cache and TLB information */ *rax = eax; @@ -5461,37 +5428,9 @@ vmm_handle_cpuid(struct vcpu *vcpu) break; case 0x07: /* SEFF */ if (*rcx == 0) { - /* - * SEFF flags - copy from host minus: - * SGX (SEFF0EBX_SGX) - * HLE (SEFF0EBX_HLE) - * INVPCID (SEFF0EBX_INVPCID) - * RTM (SEFF0EBX_RTM) - * PQM (SEFF0EBX_PQM) - * AVX512F (SEFF0EBX_AVX512F) - * AVX512DQ (SEFF0EBX_AVX512DQ) - * AVX512IFMA (SEFF0EBX_AVX512IFMA) - * AVX512PF (SEFF0EBX_AVX512PF) - * AVX512ER (SEFF0EBX_AVX512ER) - * AVX512CD (SEFF0EBX_AVX512CD) - * AVX512BW (SEFF0EBX_AVX512BW) - * AVX512VL (SEFF0EBX_AVX512VL) - * MPX (SEFF0EBX_MPX) - * PCOMMIT (SEFF0EBX_PCOMMIT) - * PT (SEFF0EBX_PT) - * AVX512VBMI (SEFF0ECX_AVX512VBMI) - */ *rax = 0; /* Highest subleaf supported */ - *rbx = curcpu()->ci_feature_sefflags_ebx & - ~(SEFF0EBX_SGX | SEFF0EBX_HLE | SEFF0EBX_INVPCID | - SEFF0EBX_RTM | SEFF0EBX_PQM | SEFF0EBX_MPX | - SEFF0EBX_PCOMMIT | SEFF0EBX_PT | - SEFF0EBX_AVX512F | SEFF0EBX_AVX512DQ | - SEFF0EBX_AVX512IFMA | SEFF0EBX_AVX512PF | - SEFF0EBX_AVX512ER | SEFF0EBX_AVX512CD | - SEFF0EBX_AVX512BW | SEFF0EBX_AVX512VL); - *rcx = curcpu()->ci_feature_sefflags_ecx & - ~(SEFF0ECX_AVX512VBMI); + *rbx = curcpu()->ci_feature_sefflags_ebx & VMM_SEFF0EBX_MASK; + *rcx = curcpu()->ci_feature_sefflags_ecx & VMM_SEFF0ECX_MASK; *rdx = 0; } else { /* Unsupported subleaf */ diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h index 4dddc8bf354..4847fa3defa 100644 --- a/sys/arch/amd64/include/vmmvar.h +++ b/sys/arch/amd64/include/vmmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmmvar.h,v 1.46 2017/08/14 18:29:41 mlarkin Exp $ */ +/* $OpenBSD: vmmvar.h,v 1.47 2017/08/20 21:15:32 pd Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -505,6 +505,70 @@ struct vm_rwregs_params { #define VMM_IOC_READREGS _IOWR('V', 7, struct vm_rwregs_params) /* Get registers */ #define VMM_IOC_WRITEREGS _IOW('V', 8, struct vm_rwregs_params) /* Set registers */ + +/* CPUID masks */ +/* + * clone host capabilities minus: + * debug store (CPUIDECX_DTES64, CPUIDECX_DSCPL, CPUID_DS) + * monitor/mwait (CPUIDECX_MWAIT) + * vmx (CPUIDECX_VMX) + * smx (CPUIDECX_SMX) + * speedstep (CPUIDECX_EST) + * thermal (CPUIDECX_TM2, CPUID_ACPI, CPUID_TM) + * context id (CPUIDECX_CNXTID) + * silicon debug (CPUIDECX_SDBG) + * xTPR (CPUIDECX_XTPR) + * perf/debug (CPUIDECX_PDCM) + * pcid (CPUIDECX_PCID) + * direct cache access (CPUIDECX_DCA) + * x2APIC (CPUIDECX_X2APIC) + * apic deadline (CPUIDECX_DEADLINE) + * apic (CPUID_APIC) + * psn (CPUID_PSN) + * self snoop (CPUID_SS) + * hyperthreading (CPUID_HTT) + * pending break enabled (CPUID_PBE) + * MTRR (CPUID_MTRR) + */ +#define VMM_CPUIDECX_MASK ~(CPUIDECX_EST | CPUIDECX_TM2 | CPUIDECX_MWAIT | \ + CPUIDECX_PDCM | CPUIDECX_VMX | CPUIDECX_DTES64 | \ + CPUIDECX_DSCPL | CPUIDECX_SMX | CPUIDECX_CNXTID | \ + CPUIDECX_SDBG | CPUIDECX_XTPR | CPUIDECX_PCID | \ + CPUIDECX_DCA | CPUIDECX_X2APIC | CPUIDECX_DEADLINE) +#define VMM_CPUIDEDX_MASK ~(CPUID_ACPI | CPUID_TM | \ + CPUID_HTT | CPUID_DS | CPUID_APIC | \ + CPUID_PSN | CPUID_SS | CPUID_PBE | \ + CPUID_MTRR) + +/* + * SEFF flags - copy from host minus: + * SGX (SEFF0EBX_SGX) + * HLE (SEFF0EBX_HLE) + * INVPCID (SEFF0EBX_INVPCID) + * RTM (SEFF0EBX_RTM) + * PQM (SEFF0EBX_PQM) + * AVX512F (SEFF0EBX_AVX512F) + * AVX512DQ (SEFF0EBX_AVX512DQ) + * AVX512IFMA (SEFF0EBX_AVX512IFMA) + * AVX512PF (SEFF0EBX_AVX512PF) + * AVX512ER (SEFF0EBX_AVX512ER) + * AVX512CD (SEFF0EBX_AVX512CD) + * AVX512BW (SEFF0EBX_AVX512BW) + * AVX512VL (SEFF0EBX_AVX512VL) + * MPX (SEFF0EBX_MPX) + * PCOMMIT (SEFF0EBX_PCOMMIT) + * PT (SEFF0EBX_PT) + * AVX512VBMI (SEFF0ECX_AVX512VBMI) + */ +#define VMM_SEFF0EBX_MASK ~(SEFF0EBX_SGX | SEFF0EBX_HLE | SEFF0EBX_INVPCID | \ + SEFF0EBX_RTM | SEFF0EBX_PQM | SEFF0EBX_MPX | \ + SEFF0EBX_PCOMMIT | SEFF0EBX_PT | \ + SEFF0EBX_AVX512F | SEFF0EBX_AVX512DQ | \ + SEFF0EBX_AVX512IFMA | SEFF0EBX_AVX512PF | \ + SEFF0EBX_AVX512ER | SEFF0EBX_AVX512CD | \ + SEFF0EBX_AVX512BW | SEFF0EBX_AVX512VL) +#define VMM_SEFF0ECX_MASK ~(SEFF0ECX_AVX512VBMI) + #ifdef _KERNEL #define VMX_FAIL_LAUNCH_UNKNOWN 1 diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c index 20adc2a46f8..0199f77860a 100644 --- a/usr.sbin/vmd/vm.c +++ b/usr.sbin/vmd/vm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm.c,v 1.23 2017/08/14 18:27:58 mlarkin Exp $ */ +/* $OpenBSD: vm.c,v 1.24 2017/08/20 21:15:32 pd Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -80,6 +80,7 @@ uint8_t vcpu_exit_pci(struct vm_run_params *); int vcpu_pic_intr(uint32_t, uint32_t, uint8_t); int loadfile_bios(FILE *, struct vcpu_reg_state *); int send_vm(int, struct vm_create_params *); +int dump_send_header(int); int dump_vmr(int , struct vm_mem_range *); int dump_mem(int, struct vm_create_params *); void restore_vmr(int, struct vm_mem_range *); @@ -490,16 +491,12 @@ send_vm(int fd, struct vm_create_params *vcp) struct vm_rwregs_params vrp; struct vmop_create_params *vmc; struct vm_terminate_params vtp; - struct vm_dump_header vmh; unsigned int flags = 0; unsigned int i; int ret = 0; - memset(&vmh, 0, sizeof(vmh)); - memcpy(vmh.vmh_signature, VM_DUMP_SIGNATURE, sizeof(vmh.vmh_signature)); - vmh.vmh_version = VM_DUMP_VERSION; - if (atomicio(vwrite, fd, &vmh, sizeof(vmh)) != sizeof(vmh)) { - log_warn("%s: failed to send vm dump header", __func__); + if (dump_send_header(fd)) { + log_info("%s: failed to send vm dump header", __func__); goto err; } @@ -564,6 +561,43 @@ err: } int +dump_send_header(int fd) { + struct vm_dump_header vmh; + int i; + + vmh.vmh_cpuids[0].code = 0x00; + vmh.vmh_cpuids[0].leaf = 0x00; + + vmh.vmh_cpuids[1].code = 0x01; + vmh.vmh_cpuids[1].leaf = 0x00; + + vmh.vmh_cpuids[2].code = 0x07; + vmh.vmh_cpuids[2].leaf = 0x00; + + vmh.vmh_cpuids[3].code = 0x0d; + vmh.vmh_cpuids[3].leaf = 0x00; + + vmh.vmh_cpuids[4].code = 0x80000001; + vmh.vmh_cpuids[4].leaf = 0x00; + + vmh.vmh_version = VM_DUMP_VERSION; + + for (i=0; i < VM_DUMP_HEADER_CPUID_COUNT; i++) { + CPUID_LEAF(vmh.vmh_cpuids[i].code, + vmh.vmh_cpuids[i].leaf, + vmh.vmh_cpuids[i].a, + vmh.vmh_cpuids[i].b, + vmh.vmh_cpuids[i].c, + vmh.vmh_cpuids[i].d); + } + + if (atomicio(vwrite, fd, &vmh, sizeof(vmh)) != sizeof(vmh)) + return (-1); + + return (0); +} + +int dump_mem(int fd, struct vm_create_params *vcp) { unsigned int i; diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c index 4fefc3f0420..c7b9247d326 100644 --- a/usr.sbin/vmd/vmd.c +++ b/usr.sbin/vmd/vmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.c,v 1.67 2017/08/15 15:10:35 pd Exp $ */ +/* $OpenBSD: vmd.c,v 1.68 2017/08/20 21:15:32 pd Exp $ */ /* * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org> @@ -39,6 +39,9 @@ #include <pwd.h> #include <grp.h> +#include <machine/specialreg.h> +#include <machine/vmmvar.h> + #include "proc.h" #include "atomicio.h" #include "vmd.h" @@ -52,6 +55,7 @@ void vmd_shutdown(void); int vmd_control_run(void); int vmd_dispatch_control(int, struct privsep_proc *, struct imsg *); int vmd_dispatch_vmm(int, struct privsep_proc *, struct imsg *); +int check_vmh(struct vm_dump_header *); struct vmd *env; @@ -226,9 +230,7 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg) cmd = IMSG_VMDOP_START_VM_RESPONSE; break; } - if (vmh.vmh_version != VM_DUMP_VERSION) { - log_warnx("%s: incompatible dump version", - __func__); + if(check_vmh(&vmh)) { res = ENOENT; close(imsg->fd); cmd = IMSG_VMDOP_START_VM_RESPONSE; @@ -466,6 +468,125 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg) return (0); } +int +check_vmh(struct vm_dump_header *vmh) { + int i; + unsigned int code, leaf; + unsigned int a, b, c, d; + + + if (vmh->vmh_version != VM_DUMP_VERSION) { + log_warnx("%s: incompatible dump version", __func__); + return (-1); + } + + for (i = 0; i < VM_DUMP_HEADER_CPUID_COUNT; i++) { + code = vmh->vmh_cpuids[i].code; + leaf = vmh->vmh_cpuids[i].leaf; + if (leaf != 0x00) { + log_debug("%s: invalid leaf 0x%x for code 0x%x", + __func__, leaf, code); + return (-1); + } + + switch(code) { + case 0x00: + CPUID_LEAF(code, leaf, a, b, c, d); + if (vmh->vmh_cpuids[i].a > a) { + log_debug("%s: incompatible cpuid level", __func__); + return (-1); + } + if (!(vmh->vmh_cpuids[i].b == b && + vmh->vmh_cpuids[i].c == c && + vmh->vmh_cpuids[i].d == d)) { + log_debug("%s: incompatible cpu brand", __func__); + return (-1); + } + break; + + case 0x01: + CPUID_LEAF(code, leaf, a, b, c, d); + if ((vmh->vmh_cpuids[i].c & c & VMM_CPUIDECX_MASK) != + (vmh->vmh_cpuids[i].c & VMM_CPUIDECX_MASK)) { + log_debug("%s: incompatible cpu features " + "code: 0x%x leaf: 0x%x reg: c", __func__, + code, leaf); + return (-1); + } + if ((vmh->vmh_cpuids[i].d & d & VMM_CPUIDEDX_MASK) != + (vmh->vmh_cpuids[i].d & VMM_CPUIDEDX_MASK)) { + log_debug("%s: incompatible cpu features " + "code: 0x%x leaf: 0x%x reg: d", __func__, + code, leaf); + return (-1); + } + break; + + case 0x07: + CPUID_LEAF(code, leaf, a, b, c, d); + if ((vmh->vmh_cpuids[i].b & b & VMM_SEFF0EBX_MASK) != + (vmh->vmh_cpuids[i].b & VMM_SEFF0EBX_MASK)) { + log_debug("%s: incompatible cpu features " + "code: 0x%x leaf: 0x%x reg: c", __func__, + code, leaf); + return (-1); + } + if ((vmh->vmh_cpuids[i].c & c & VMM_SEFF0ECX_MASK) != + (vmh->vmh_cpuids[i].c & VMM_SEFF0ECX_MASK)) { + log_debug("%s: incompatible cpu features " + "code: 0x%x leaf: 0x%x reg: d", __func__, + code, leaf); + return (-1); + } + break; + + case 0x0d: + CPUID_LEAF(code, leaf, a, b, c, d); + if (vmh->vmh_cpuids[i].b > b) { + log_debug("%s: incompatible cpu: insufficient " + "max save area for enabled XCR0 features", + __func__); + return (-1); + } + if (vmh->vmh_cpuids[i].c > c) { + log_debug("%s: incompatible cpu: insufficient " + "max save area for supported XCR0 features", + __func__); + return (-1); + } + break; + + case 0x80000001: + CPUID_LEAF(code, leaf, a, b, c, d); + if ((vmh->vmh_cpuids[i].a & a) != vmh->vmh_cpuids[i].a) { + log_debug("%s: incompatible cpu features " + "code: 0x%x leaf: 0x%x reg: a", __func__, + code, leaf); + return (-1); + } + if ((vmh->vmh_cpuids[i].c & c) != vmh->vmh_cpuids[i].c) { + log_debug("%s: incompatible cpu features " + "code: 0x%x leaf: 0x%x reg: c", __func__, + code, leaf); + return (-1); + } + if ((vmh->vmh_cpuids[i].d & d) != vmh->vmh_cpuids[i].d) { + log_debug("%s: incompatible cpu features " + "code: 0x%x leaf: 0x%x reg: d", __func__, + code, leaf); + return (-1); + } + break; + + default: + log_debug("%s: unknown code 0x%x", __func__, code); + return (-1); + } + } + + return (0); +} + void vmd_sighdlr(int sig, short event, void *arg) { diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index d22b797dc35..57bdb71cd5f 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.59 2017/08/18 07:01:29 mlarkin Exp $ */ +/* $OpenBSD: vmd.h,v 1.60 2017/08/20 21:15:32 pd Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -149,12 +149,21 @@ struct vmop_create_params { int64_t vmc_gid; }; +struct vm_dump_header_cpuid { + unsigned long code, leaf; + unsigned int a, b, c, d; +}; + +#define VM_DUMP_HEADER_CPUID_COUNT 5 + struct vm_dump_header { uint8_t vmh_signature[12]; #define VM_DUMP_SIGNATURE VMM_HV_SIGNATURE uint8_t vmh_pad[3]; uint8_t vmh_version; -#define VM_DUMP_VERSION 1 +#define VM_DUMP_VERSION 2 + struct vm_dump_header_cpuid + vmh_cpuids[VM_DUMP_HEADER_CPUID_COUNT]; } __packed; struct vmboot_params { |