summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/io/vmm/x86.c
diff options
context:
space:
mode:
authorJohn Levon <john.levon@joyent.com>2020-05-26 13:57:13 +0000
committerJohn Levon <john.levon@joyent.com>2020-05-26 13:57:13 +0000
commit5b2acc0949194447bba6e45a0fa44d0b5f42f208 (patch)
tree7ea9eb87bc68fee386dd39035ce715e87a0e673c /usr/src/uts/i86pc/io/vmm/x86.c
parent8ca018083101bf1cb175869679bc123187fb1bab (diff)
parent2a1277d3064386cd5c4e372301007aa330bf1d5e (diff)
downloadillumos-joyent-gcc9.tar.gz
mergegcc9
Diffstat (limited to 'usr/src/uts/i86pc/io/vmm/x86.c')
-rw-r--r--usr/src/uts/i86pc/io/vmm/x86.c75
1 files changed, 42 insertions, 33 deletions
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);
}