Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/vmm/x86.c
Show First 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | switch (func) { | ||||
case CPUID_8000_0003: | case CPUID_8000_0003: | ||||
case CPUID_8000_0004: | case CPUID_8000_0004: | ||||
case CPUID_8000_0006: | case CPUID_8000_0006: | ||||
cpuid_count(*eax, *ecx, regs); | cpuid_count(*eax, *ecx, regs); | ||||
break; | break; | ||||
case CPUID_8000_0008: | case CPUID_8000_0008: | ||||
cpuid_count(*eax, *ecx, regs); | cpuid_count(*eax, *ecx, regs); | ||||
if (vmm_is_amd()) { | if (vmm_is_amd()) { | ||||
vm_get_topology(vm, &sockets, &cores, &threads, | |||||
&maxcpus); | |||||
/* | /* | ||||
* XXX this might appear silly because AMD | * Here, width is ApicIdCoreIdSize, present on | ||||
* cpus don't have threads. | * at least Family 15h and newer. It | ||||
* represents the "number of bits in the | |||||
* initial apicid that indicate thread id | |||||
* within a package." | |||||
* | * | ||||
* However this matches the logical cpus as | * Our topo_probe_amd() uses it for | ||||
* advertised by leaf 0x1 and will work even | * pkg_id_shift and other OSes may rely on it. | ||||
* if threads is set incorrectly on an AMD host. | |||||
*/ | */ | ||||
vm_get_topology(vm, &sockets, &cores, &threads, | width = MIN(0xF, log2(threads * cores)); | ||||
&maxcpus); | if (width < 0x4) | ||||
logical_cpus = threads * cores; | width = 0; | ||||
regs[2] = logical_cpus - 1; | logical_cpus = MIN(0xFF, threads * cores - 1); | ||||
regs[2] = (width << AMDID_COREID_SIZE_SHIFT) | logical_cpus; | |||||
} | } | ||||
break; | break; | ||||
case CPUID_8000_0001: | case CPUID_8000_0001: | ||||
cpuid_count(*eax, *ecx, regs); | cpuid_count(*eax, *ecx, regs); | ||||
/* | /* | ||||
* Hide SVM and Topology Extension features from guest. | * Hide SVM from guest. | ||||
*/ | */ | ||||
regs[2] &= ~(AMDID2_SVM | AMDID2_TOPOLOGY); | regs[2] &= ~AMDID2_SVM; | ||||
/* | /* | ||||
* Don't advertise extended performance counter MSRs | * Don't advertise extended performance counter MSRs | ||||
* to the guest. | * to the guest. | ||||
*/ | */ | ||||
regs[2] &= ~AMDID2_PCXC; | regs[2] &= ~AMDID2_PCXC; | ||||
regs[2] &= ~AMDID2_PNXC; | regs[2] &= ~AMDID2_PNXC; | ||||
regs[2] &= ~AMDID2_PTSCEL2I; | regs[2] &= ~AMDID2_PTSCEL2I; | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | case CPUID_8000_0007: | ||||
* migrates across physical cpus. But at least | * migrates across physical cpus. But at least | ||||
* it should discourage the guest from using the | * it should discourage the guest from using the | ||||
* TSC to keep track of time. | * TSC to keep track of time. | ||||
*/ | */ | ||||
if (tsc_is_invariant && smp_tsc) | if (tsc_is_invariant && smp_tsc) | ||||
regs[3] |= AMDPM_TSC_INVARIANT; | regs[3] |= AMDPM_TSC_INVARIANT; | ||||
break; | break; | ||||
case CPUID_8000_001D: | |||||
/* AMD Cache topology, like 0000_0004 for Intel. */ | |||||
if (!vmm_is_amd()) | |||||
goto default_leaf; | |||||
/* | |||||
* Similar to Intel, generate a ficticious cache | |||||
* topology for the guest with L3 shared by the | |||||
* package, and L1 and L2 local to a core. | |||||
*/ | |||||
vm_get_topology(vm, &sockets, &cores, &threads, | |||||
&maxcpus); | |||||
switch (*ecx) { | |||||
case 0: | |||||
logical_cpus = threads; | |||||
level = 1; | |||||
func = 1; /* data cache */ | |||||
break; | |||||
case 1: | |||||
logical_cpus = threads; | |||||
level = 2; | |||||
func = 3; /* unified cache */ | |||||
break; | |||||
case 2: | |||||
logical_cpus = threads * cores; | |||||
level = 3; | |||||
func = 3; /* unified cache */ | |||||
break; | |||||
default: | |||||
logical_cpus = 0; | |||||
level = 0; | |||||
func = 0; | |||||
break; | |||||
} | |||||
logical_cpus = MIN(0xfff, logical_cpus - 1); | |||||
regs[0] = (logical_cpus << 14) | (1 << 8) | | |||||
(level << 5) | func; | |||||
regs[1] = (func > 0) ? (CACHE_LINE_SIZE - 1) : 0; | |||||
regs[2] = 0; | |||||
regs[3] = 0; | |||||
break; | |||||
case CPUID_8000_001E: | |||||
/* AMD Family 16h+ additional identifiers */ | |||||
if (!vmm_is_amd() || CPUID_TO_FAMILY(cpu_id) < 0x16) | |||||
goto default_leaf; | |||||
vm_get_topology(vm, &sockets, &cores, &threads, | |||||
&maxcpus); | |||||
regs[0] = vcpu_id; | |||||
threads = MIN(0xFF, threads - 1); | |||||
regs[1] = (threads << 8) | | |||||
(vcpu_id >> log2(threads + 1)); | |||||
/* | |||||
* XXX Bhyve topology cannot yet represent >1 node per | |||||
* processor. | |||||
*/ | |||||
regs[2] = 0; | |||||
regs[3] = 0; | |||||
break; | |||||
case CPUID_0000_0001: | case CPUID_0000_0001: | ||||
do_cpuid(1, regs); | do_cpuid(1, regs); | ||||
error = vm_get_x2apic_state(vm, vcpu_id, &x2apic_state); | error = vm_get_x2apic_state(vm, vcpu_id, &x2apic_state); | ||||
if (error) { | if (error) { | ||||
panic("x86_emulate_cpuid: error %d " | panic("x86_emulate_cpuid: error %d " | ||||
"fetching x2apic state", error); | "fetching x2apic state", error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | case CPUID_0000_0007: | ||||
*/ | */ | ||||
regs[1] &= (CPUID_STDEXT_FSGSBASE | | regs[1] &= (CPUID_STDEXT_FSGSBASE | | ||||
CPUID_STDEXT_BMI1 | CPUID_STDEXT_HLE | | CPUID_STDEXT_BMI1 | CPUID_STDEXT_HLE | | ||||
CPUID_STDEXT_AVX2 | CPUID_STDEXT_BMI2 | | CPUID_STDEXT_AVX2 | CPUID_STDEXT_BMI2 | | ||||
CPUID_STDEXT_ERMS | CPUID_STDEXT_RTM | | CPUID_STDEXT_ERMS | CPUID_STDEXT_RTM | | ||||
CPUID_STDEXT_AVX512F | | CPUID_STDEXT_AVX512F | | ||||
CPUID_STDEXT_AVX512PF | | CPUID_STDEXT_AVX512PF | | ||||
CPUID_STDEXT_AVX512ER | | CPUID_STDEXT_AVX512ER | | ||||
CPUID_STDEXT_AVX512CD); | CPUID_STDEXT_AVX512CD | CPUID_STDEXT_SHA); | ||||
regs[2] = 0; | regs[2] = 0; | ||||
regs[3] = 0; | regs[3] = 0; | ||||
/* Advertise INVPCID if it is enabled. */ | /* Advertise INVPCID if it is enabled. */ | ||||
error = vm_get_capability(vm, vcpu_id, | error = vm_get_capability(vm, vcpu_id, | ||||
VM_CAP_ENABLE_INVPCID, &enable_invpcid); | VM_CAP_ENABLE_INVPCID, &enable_invpcid); | ||||
if (error == 0 && enable_invpcid) | if (error == 0 && enable_invpcid) | ||||
regs[1] |= CPUID_STDEXT_INVPCID; | regs[1] |= CPUID_STDEXT_INVPCID; | ||||
Show All 15 Lines | case CPUID_0000_000A: | ||||
regs[0] = 0; | regs[0] = 0; | ||||
regs[1] = 0; | regs[1] = 0; | ||||
regs[2] = 0; | regs[2] = 0; | ||||
regs[3] = 0; | regs[3] = 0; | ||||
break; | break; | ||||
case CPUID_0000_000B: | case CPUID_0000_000B: | ||||
/* | /* | ||||
* Processor topology enumeration | * Intel processor topology enumeration | ||||
*/ | */ | ||||
if (vmm_is_intel()) { | |||||
vm_get_topology(vm, &sockets, &cores, &threads, | vm_get_topology(vm, &sockets, &cores, &threads, | ||||
&maxcpus); | &maxcpus); | ||||
if (*ecx == 0) { | if (*ecx == 0) { | ||||
logical_cpus = threads; | logical_cpus = threads; | ||||
width = log2(logical_cpus); | width = log2(logical_cpus); | ||||
level = CPUID_TYPE_SMT; | level = CPUID_TYPE_SMT; | ||||
x2apic_id = vcpu_id; | x2apic_id = vcpu_id; | ||||
} | } | ||||
if (*ecx == 1) { | if (*ecx == 1) { | ||||
logical_cpus = threads * cores; | logical_cpus = threads * cores; | ||||
width = log2(logical_cpus); | width = log2(logical_cpus); | ||||
level = CPUID_TYPE_CORE; | level = CPUID_TYPE_CORE; | ||||
x2apic_id = vcpu_id; | x2apic_id = vcpu_id; | ||||
} | } | ||||
if (!cpuid_leaf_b || *ecx >= 2) { | if (!cpuid_leaf_b || *ecx >= 2) { | ||||
width = 0; | width = 0; | ||||
logical_cpus = 0; | logical_cpus = 0; | ||||
level = 0; | level = 0; | ||||
x2apic_id = 0; | x2apic_id = 0; | ||||
} | } | ||||
regs[0] = width & 0x1f; | regs[0] = width & 0x1f; | ||||
regs[1] = logical_cpus & 0xffff; | regs[1] = logical_cpus & 0xffff; | ||||
regs[2] = (level << 8) | (*ecx & 0xff); | regs[2] = (level << 8) | (*ecx & 0xff); | ||||
regs[3] = x2apic_id; | regs[3] = x2apic_id; | ||||
} else { | |||||
regs[0] = 0; | |||||
regs[1] = 0; | |||||
regs[2] = 0; | |||||
regs[3] = 0; | |||||
} | |||||
break; | break; | ||||
case CPUID_0000_000D: | case CPUID_0000_000D: | ||||
limits = vmm_get_xsave_limits(); | limits = vmm_get_xsave_limits(); | ||||
if (!limits->xsave_enabled) { | if (!limits->xsave_enabled) { | ||||
regs[0] = 0; | regs[0] = 0; | ||||
regs[1] = 0; | regs[1] = 0; | ||||
regs[2] = 0; | regs[2] = 0; | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | switch (func) { | ||||
case 0x40000000: | case 0x40000000: | ||||
regs[0] = CPUID_VM_HIGH; | regs[0] = CPUID_VM_HIGH; | ||||
bcopy(bhyve_id, ®s[1], 4); | bcopy(bhyve_id, ®s[1], 4); | ||||
bcopy(bhyve_id + 4, ®s[2], 4); | bcopy(bhyve_id + 4, ®s[2], 4); | ||||
bcopy(bhyve_id + 8, ®s[3], 4); | bcopy(bhyve_id + 8, ®s[3], 4); | ||||
break; | break; | ||||
default: | default: | ||||
default_leaf: | |||||
/* | /* | ||||
* The leaf value has already been clamped so | * The leaf value has already been clamped so | ||||
* simply pass this through, keeping count of | * simply pass this through, keeping count of | ||||
* how many unhandled leaf values have been seen. | * how many unhandled leaf values have been seen. | ||||
*/ | */ | ||||
atomic_add_long(&bhyve_xcpuids, 1); | atomic_add_long(&bhyve_xcpuids, 1); | ||||
cpuid_count(*eax, *ecx, regs); | cpuid_count(*eax, *ecx, regs); | ||||
break; | break; | ||||
Show All 40 Lines |