| 87 | } |
| 88 | |
| 89 | int |
| 90 | x86_emulate_cpuid(struct vm *vm, int vcpu_id, uint64_t *rax, uint64_t *rbx, |
| 91 | uint64_t *rcx, uint64_t *rdx) |
| 92 | { |
| 93 | const struct xsave_limits *limits; |
| 94 | uint64_t cr4; |
| 95 | int error, enable_invpcid, enable_rdpid, enable_rdtscp, level, |
| 96 | width, x2apic_id; |
| 97 | unsigned int func, regs[4], logical_cpus, param; |
| 98 | enum x2apic_state x2apic_state; |
| 99 | uint16_t cores, maxcpus, sockets, threads; |
| 100 | |
| 101 | /* |
| 102 | * The function of CPUID is controlled through the provided value of |
| 103 | * %eax (and secondarily %ecx, for certain leaf data). |
| 104 | */ |
| 105 | func = (uint32_t)*rax; |
| 106 | param = (uint32_t)*rcx; |
| 107 | |
| 108 | VCPU_CTR2(vm, vcpu_id, "cpuid %#x,%#x", func, param); |
| 109 | |
| 110 | /* |
| 111 | * Requests for invalid CPUID levels should map to the highest |
| 112 | * available level instead. |
| 113 | */ |
| 114 | if (cpu_exthigh != 0 && func >= 0x80000000) { |
| 115 | if (func > cpu_exthigh) |
| 116 | func = cpu_exthigh; |
| 117 | } else if (func >= 0x40000000) { |
| 118 | if (func > CPUID_VM_HIGH) |
| 119 | func = CPUID_VM_HIGH; |
| 120 | } else if (func > cpu_high) { |
| 121 | func = cpu_high; |
| 122 | } |
| 123 | |
| 124 | /* |
| 125 | * In general the approach used for CPU topology is to |
| 126 | * advertise a flat topology where all CPUs are packages with |
| 127 | * no multi-core or SMT. |
| 128 | */ |
| 129 | switch (func) { |
| 130 | /* |
| 131 | * Pass these through to the guest |
| 132 | */ |
| 133 | case CPUID_0000_0000: |
| 134 | case CPUID_0000_0002: |
| 135 | case CPUID_0000_0003: |
| 136 | case CPUID_8000_0000: |
| 137 | case CPUID_8000_0002: |
| 138 | case CPUID_8000_0003: |
| 139 | case CPUID_8000_0004: |
| 140 | case CPUID_8000_0006: |
| 141 | cpuid_count(func, param, regs); |
| 142 | break; |
| 143 | case CPUID_8000_0008: |
| 144 | cpuid_count(func, param, regs); |
| 145 | if (vmm_is_svm()) { |
| 146 | /* |
no test coverage detected