diff options
author | Patrick Mooney <pmooney@pfmooney.com> | 2020-05-05 15:31:34 -0500 |
---|---|---|
committer | Patrick Mooney <pmooney@pfmooney.com> | 2020-05-22 02:56:09 +0000 |
commit | 3c5f2a9de9c6554ce899ad4ebf7978ea7293994a (patch) | |
tree | 93b2f9726b921d07911adaccd4df1de79c49e8c9 /usr/src/uts | |
parent | 537911b676ea740315ce9055d857ea1d626e6fe7 (diff) | |
download | illumos-gate-3c5f2a9de9c6554ce899ad4ebf7978ea7293994a.tar.gz |
12746 x86_emulate_cpuid() should clear upper 32 bits
Reviewed by: John Levon <john.levon@joyent.com>
Reviewed by: Mike Zeller <mike.zeller@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/uts')
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/amd/svm.c | 8 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/intel/vmx.c | 9 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/x86.c | 75 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/vmm/x86.h | 4 |
4 files changed, 51 insertions, 45 deletions
diff --git a/usr/src/uts/i86pc/io/vmm/amd/svm.c b/usr/src/uts/i86pc/io/vmm/amd/svm.c index 25dc3a63fa..80d76ab640 100644 --- a/usr/src/uts/i86pc/io/vmm/amd/svm.c +++ b/usr/src/uts/i86pc/io/vmm/amd/svm.c @@ -28,6 +28,7 @@ /* * Copyright 2018 Joyent, Inc. + * Copyright 2020 Oxide Computer Company */ #include <sys/cdefs.h> @@ -1518,11 +1519,8 @@ svm_vmexit(struct svm_softc *svm_sc, int vcpu, struct vm_exit *vmexit) break; case VMCB_EXIT_CPUID: vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_CPUID, 1); - handled = x86_emulate_cpuid(svm_sc->vm, vcpu, - (uint32_t *)&state->rax, - (uint32_t *)&ctx->sctx_rbx, - (uint32_t *)&ctx->sctx_rcx, - (uint32_t *)&ctx->sctx_rdx); + handled = x86_emulate_cpuid(svm_sc->vm, vcpu, &state->rax, + &ctx->sctx_rbx, &ctx->sctx_rcx, &ctx->sctx_rdx); break; case VMCB_EXIT_HLT: vmm_stat_incr(svm_sc->vm, vcpu, VMEXIT_HLT, 1); diff --git a/usr/src/uts/i86pc/io/vmm/intel/vmx.c b/usr/src/uts/i86pc/io/vmm/intel/vmx.c index ce42ff8c9c..eea036b253 100644 --- a/usr/src/uts/i86pc/io/vmm/intel/vmx.c +++ b/usr/src/uts/i86pc/io/vmm/intel/vmx.c @@ -40,6 +40,7 @@ * * Copyright 2015 Pluribus Networks Inc. * Copyright 2018 Joyent, Inc. + * Copyright 2020 Oxide Computer Company */ #include <sys/cdefs.h> @@ -1244,11 +1245,9 @@ vmx_handle_cpuid(struct vm *vm, int vcpu, struct vmxctx *vmxctx) int handled; #endif - handled = x86_emulate_cpuid(vm, vcpu, - (uint32_t*)(&vmxctx->guest_rax), - (uint32_t*)(&vmxctx->guest_rbx), - (uint32_t*)(&vmxctx->guest_rcx), - (uint32_t*)(&vmxctx->guest_rdx)); + handled = x86_emulate_cpuid(vm, vcpu, (uint64_t *)&vmxctx->guest_rax, + (uint64_t *)&vmxctx->guest_rbx, (uint64_t *)&vmxctx->guest_rcx, + (uint64_t *)&vmxctx->guest_rdx); return (handled); } diff --git a/usr/src/uts/i86pc/io/vmm/x86.c b/usr/src/uts/i86pc/io/vmm/x86.c index d74f866013..6213173587 100644 --- a/usr/src/uts/i86pc/io/vmm/x86.c +++ b/usr/src/uts/i86pc/io/vmm/x86.c @@ -39,6 +39,7 @@ * * Copyright 2014 Pluribus Networks Inc. * Copyright 2018 Joyent, Inc. + * Copyright 2020 Oxide Computer Company */ #include <sys/cdefs.h> @@ -90,34 +91,39 @@ log2(u_int x) } int -x86_emulate_cpuid(struct vm *vm, int vcpu_id, - uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) +x86_emulate_cpuid(struct vm *vm, int vcpu_id, uint64_t *rax, uint64_t *rbx, + uint64_t *rcx, uint64_t *rdx) { const struct xsave_limits *limits; uint64_t cr4; int error, enable_invpcid, level, width = 0, x2apic_id = 0; - unsigned int func, regs[4], logical_cpus = 0; + unsigned int func, regs[4], logical_cpus = 0, param; enum x2apic_state x2apic_state; uint16_t cores, maxcpus, sockets, threads; - VCPU_CTR2(vm, vcpu_id, "cpuid %#x,%#x", *eax, *ecx); + /* + * The function of CPUID is controlled through the provided value of + * %eax (and secondarily %ecx, for certain leaf data). + */ + func = (uint32_t)*rax; + param = (uint32_t)*rcx; + + VCPU_CTR2(vm, vcpu_id, "cpuid %#x,%#x", func, param); /* * Requests for invalid CPUID levels should map to the highest * available level instead. */ - if (cpu_exthigh != 0 && *eax >= 0x80000000) { - if (*eax > cpu_exthigh) - *eax = cpu_exthigh; - } else if (*eax >= 0x40000000) { - if (*eax > CPUID_VM_HIGH) - *eax = CPUID_VM_HIGH; - } else if (*eax > cpu_high) { - *eax = cpu_high; + if (cpu_exthigh != 0 && func >= 0x80000000) { + if (func > cpu_exthigh) + func = cpu_exthigh; + } else if (func >= 0x40000000) { + if (func > CPUID_VM_HIGH) + func = CPUID_VM_HIGH; + } else if (func > cpu_high) { + func = cpu_high; } - func = *eax; - /* * In general the approach used for CPU topology is to * advertise a flat topology where all CPUs are packages with @@ -135,10 +141,10 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, case CPUID_8000_0003: case CPUID_8000_0004: case CPUID_8000_0006: - cpuid_count(*eax, *ecx, regs); + cpuid_count(func, param, regs); break; case CPUID_8000_0008: - cpuid_count(*eax, *ecx, regs); + cpuid_count(func, param, regs); if (vmm_is_amd()) { /* * As on Intel (0000_0007:0, EDX), mask out @@ -169,7 +175,7 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, break; case CPUID_8000_0001: - cpuid_count(*eax, *ecx, regs); + cpuid_count(func, param, regs); /* * Hide SVM from guest. @@ -263,7 +269,7 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, */ vm_get_topology(vm, &sockets, &cores, &threads, &maxcpus); - switch (*ecx) { + switch (param) { case 0: logical_cpus = threads; level = 1; @@ -408,7 +414,7 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, break; case CPUID_0000_0004: - cpuid_count(*eax, *ecx, regs); + cpuid_count(func, param, regs); if (regs[0] || regs[1] || regs[2] || regs[3]) { vm_get_topology(vm, &sockets, &cores, &threads, @@ -437,8 +443,8 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, regs[3] = 0; /* leaf 0 */ - if (*ecx == 0) { - cpuid_count(*eax, *ecx, regs); + if (param == 0) { + cpuid_count(func, param, regs); /* Only leaf 0 is supported */ regs[0] = 0; @@ -491,21 +497,21 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, if (vmm_is_intel()) { vm_get_topology(vm, &sockets, &cores, &threads, &maxcpus); - if (*ecx == 0) { + if (param == 0) { logical_cpus = threads; width = log2(logical_cpus); level = CPUID_TYPE_SMT; x2apic_id = vcpu_id; } - if (*ecx == 1) { + if (param == 1) { logical_cpus = threads * cores; width = log2(logical_cpus); level = CPUID_TYPE_CORE; x2apic_id = vcpu_id; } - if (!cpuid_leaf_b || *ecx >= 2) { + if (!cpuid_leaf_b || param >= 2) { width = 0; logical_cpus = 0; level = 0; @@ -514,7 +520,7 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, regs[0] = width & 0x1f; regs[1] = logical_cpus & 0xffff; - regs[2] = (level << 8) | (*ecx & 0xff); + regs[2] = (level << 8) | (param & 0xff); regs[3] = x2apic_id; } else { regs[0] = 0; @@ -534,8 +540,8 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, break; } - cpuid_count(*eax, *ecx, regs); - switch (*ecx) { + cpuid_count(func, param, regs); + switch (param) { case 0: /* * Only permit the guest to use bits @@ -565,7 +571,7 @@ x86_emulate_cpuid(struct vm *vm, int vcpu_id, * pass through as-is, otherwise return * all zeroes. */ - if (!(limits->xcr0_allowed & (1ul << *ecx))) { + if (!(limits->xcr0_allowed & (1ul << param))) { regs[0] = 0; regs[1] = 0; regs[2] = 0; @@ -590,14 +596,17 @@ default_leaf: * how many unhandled leaf values have been seen. */ atomic_add_long(&bhyve_xcpuids, 1); - cpuid_count(*eax, *ecx, regs); + cpuid_count(func, param, regs); break; } - *eax = regs[0]; - *ebx = regs[1]; - *ecx = regs[2]; - *edx = regs[3]; + /* + * CPUID clears the upper 32-bits of the long-mode registers. + */ + *rax = regs[0]; + *rbx = regs[1]; + *rcx = regs[2]; + *rdx = regs[3]; return (1); } diff --git a/usr/src/uts/i86pc/io/vmm/x86.h b/usr/src/uts/i86pc/io/vmm/x86.h index 0d70c04fd8..cb8e12fcd2 100644 --- a/usr/src/uts/i86pc/io/vmm/x86.h +++ b/usr/src/uts/i86pc/io/vmm/x86.h @@ -63,8 +63,8 @@ */ #define CPUID_0000_0001_FEAT0_VMX (1<<5) -int x86_emulate_cpuid(struct vm *vm, int vcpu_id, uint32_t *eax, uint32_t *ebx, - uint32_t *ecx, uint32_t *edx); +int x86_emulate_cpuid(struct vm *vm, int vcpu_id, uint64_t *rax, uint64_t *rbx, + uint64_t *rcx, uint64_t *rdx); enum vm_cpuid_capability { VCC_NONE, |