1/* 2 * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7/* This file contains macros for CPUID emulation in x86. 8 * Most of the code in this file is from arch/x86/kvm/cpuid.h Linux 3.8.8 9 10 * Authors: 11 * Qian Ge 12 */ 13 14#include <stdio.h> 15#include <stdlib.h> 16 17#include <sel4/sel4.h> 18 19#include <sel4vm/guest_vm.h> 20#include <sel4vm/arch/guest_x86_context.h> 21 22#include "processor/cpuid.h" 23#include "processor/cpufeature.h" 24 25#include "vm.h" 26#include "guest_state.h" 27 28static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, 29 unsigned int *ecx, unsigned int *edx) 30{ 31 /* ecx is often an input as well as an output. */ 32 asm volatile("cpuid" 33 : "=a"(*eax), 34 "=b"(*ebx), 35 "=c"(*ecx), 36 "=d"(*edx) 37 : "0"(*eax), "2"(*ecx) 38 : "memory"); 39} 40 41static int vm_cpuid_virt(unsigned int function, unsigned int index, struct cpuid_val *val, vm_vcpu_t *vcpu) 42{ 43 unsigned int eax, ebx, ecx, edx; 44 45 eax = function; 46 ecx = index; 47 48 native_cpuid(&eax, &ebx, &ecx, &edx); 49 50 /* cpuid 1.edx */ 51 const unsigned int kvm_supported_word0_x86_features = 52 F(FPU) | 0 /*F(VME)*/ | 0 /*F(DE)*/ | 0/*F(PSE)*/ | 53 F(TSC) | 0/*F(MSR)*/ | 0 /*F(PAE)*/ | 0/*F(MCE)*/ | 54 0 /*F(CX8)*/ | F(APIC) | 0 /* Reserved */ | F(SEP) | 55 /*F(MTRR)*/ 0 | F(PGE) | 0/*F(MCA)*/ | F(CMOV) | 56 0 /*F(PAT)*/ | 0 /* F(PSE36)*/ | 0 /* PSN */ | 0/*F(CLFLSH)*/ | 57 0 /* Reserved, DS, ACPI */ | F(MMX) | 58 F(FXSR) | F(XMM) | F(XMM2) | 0/*F(SELFSNOOP)*/ | 59 0 /* HTT, TM, Reserved, PBE */; 60 61 /* cpuid 1.ecx */ 62 const unsigned int kvm_supported_word4_x86_features = 63 F(XMM3) | 0 /*F(PCLMULQDQ)*/ | 0 /* DTES64, MONITOR */ | 64 0 /* DS-CPL, VMX, SMX, EST */ | 65 0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ | 66 0 /*F(FMA)*/ | 0 /*F(CX16)*/ | 0 /* xTPR Update, PDCM */ | 67 0 /*F(PCID)*/ | 0 /* Reserved, DCA */ | F(XMM4_1) | 68 F(XMM4_2) | 0 /*F(X2APIC)*/ | 0 /*F(MOVBE)*/ | 0 /*F(POPCNT)*/ | 69 0 /* Reserved*/ | 0 /*F(AES)*/ | 0/*F(XSAVE)*/ | 0/*F(OSXSAVE)*/ | 0 /*F(AVX)*/ | 70 0 /*F(F16C)*/ | 0 /*F(RDRAND)*/; 71 72 /* cpuid 0x80000001.edx */ 73 const unsigned int kvm_supported_word1_x86_features = 74 0 /*F(NX)*/ | 0/*F(RDTSCP)*/; /*not support x86 64*/ 75 76 /* cpuid 0x80000001.ecx */ 77 const unsigned int kvm_supported_word6_x86_features = 0; 78 79#if 0 80 /* cpuid 0xC0000001.edx */ 81 const unsigned int kvm_supported_word5_x86_features = 82 F(XSTORE) | F(XSTORE_EN) | F(XCRYPT) | F(XCRYPT_EN) | 83 F(ACE2) | F(ACE2_EN) | F(PHE) | F(PHE_EN) | 84 F(PMM) | F(PMM_EN); 85#endif 86 87 /* cpuid 7.0.ebx */ 88 const unsigned int kvm_supported_word9_x86_features = 89 F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) | 90 F(BMI2) | F(ERMS) | 0 /*F(INVPCID)*/ | F(RTM); 91 92 /* Virtualize the return value according to the function. */ 93 94 ZF_LOGD("cpuid function 0x%x index 0x%x eax 0x%x ebx 0%x ecx 0x%x edx 0x%x\n", function, index, eax, ebx, ecx, edx); 95 96 /* ref: http://www.sandpile.org/x86/cpuid.htm */ 97 98 switch (function) { 99 case 0: /* Get highest function supported plus vendor ID */ 100 if (eax > 0xb) { 101 eax = 0xb; 102 } 103 break; 104 105 case 1: /* Processor, info and feature. family, model, stepping */ 106 edx &= kvm_supported_word0_x86_features; 107 ecx &= kvm_supported_word4_x86_features; 108 break; 109 110 case 2: 111 case 4: /* Cache and TLB descriptor information */ 112 /* Simply pass through information from native CPUID. */ 113 break; 114 115 case 7: /* Extended flags */ 116 ebx &= kvm_supported_word9_x86_features; 117 break; 118 119 case 0xa: /* disable performance monitoring */ 120 eax = ebx = ecx = edx = 0; 121 break; 122 123 case 0xb: /* Disable topology information */ 124 eax = ebx = ecx = edx = 0; 125 break; 126 127 case VMM_CPUID_KVM_SIGNATURE: /* Unsupported KVM features. We are not KVM. */ 128 case VMM_CPUID_KVM_FEATURES: 129 eax = ebx = ecx = edx = 0; 130 break; 131 132 case 0x80000000: /* Get highest extended function supported */ 133 break; 134 135 case 0x80000001: /* extended processor info and feature bits */ 136 ecx &= kvm_supported_word6_x86_features; 137 edx &= kvm_supported_word1_x86_features; 138 break; 139 140 case 0x80000002: /* Get processor name string. */ 141 case 0x80000003: 142 case 0x80000004: 143 case 0x80000005: 144 case 0x80000006: /* Cache information. */ 145 /* Pass through brand name from native CPUID. */ 146 break; 147 148 case 0x80000008: /* Virtual and Physics address sizes */ 149 break; 150 151 case 3: /* Processor serial number. */ 152 break; 153 case 5: /* MONITOR / MWAIT */ 154 case 6: /* Thermal management */ 155 case 0x80000007: /* Advanced power management - unsupported. */ 156 case 0xC0000002: 157 case 0xC0000003: 158 case 0xC0000004: 159 eax = ebx = ecx = edx = 0; 160 break; 161 162 default: 163 /* TODO: Adding more CPUID functions whenever necessary */ 164 ZF_LOGE("CPUID unimplemented function 0x%x\n", function); 165 return -1; 166 167 } 168 169 val->eax = eax; 170 val->ebx = ebx; 171 val->ecx = ecx; 172 val->edx = edx; 173 174 ZF_LOGD("cpuid virt value eax 0x%x ebx 0x%x ecx 0x%x edx 0x%x\n", eax, ebx, ecx, edx); 175 176 return 0; 177 178} 179 180#if 0 181/* function 2 entries are STATEFUL. That is, repeated cpuid commands 182 * may return different values. This forces us to get_cpu() before 183 * issuing the first command, and also to emulate this annoying behavior 184 * in kvm_emulate_cpuid() using KVM_CPUID_FLAG_STATE_READ_NEXT */ 185case 2: 186{ 187 int t, times = entry->eax & 0xff; 188 189 entry->flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; 190 entry->flags |= KVM_CPUID_FLAG_STATE_READ_NEXT; 191 for (t = 1; t < times; ++t) { 192 if (*nent >= maxnent) { 193 goto out; 194 } 195 196 do_cpuid_1_ent(&entry[t], function, 0); 197 entry[t].flags |= KVM_CPUID_FLAG_STATEFUL_FUNC; 198 ++*nent; 199 } 200 break; 201} 202/* function 4 has additional index. */ 203case 4: 204{ 205 int i, cache_type; 206 207 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 208 /* read more entries until cache_type is zero */ 209 for (i = 1; ; ++i) { 210 if (*nent >= maxnent) { 211 goto out; 212 } 213 214 cache_type = entry[i - 1].eax & 0x1f; 215 if (!cache_type) { 216 break; 217 } 218 do_cpuid_1_ent(&entry[i], function, i); 219 entry[i].flags |= 220 KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 221 ++*nent; 222 } 223 break; 224} 225case 7: 226{ 227 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 228 /* Mask ebx against host capability word 9 */ 229 if (index == 0) { 230 entry->ebx &= kvm_supported_word9_x86_features; 231 cpuid_mask(&entry->ebx, 9); 232 // TSC_ADJUST is emulated 233 entry->ebx |= F(TSC_ADJUST); 234 } else { 235 entry->ebx = 0; 236 } 237 entry->eax = 0; 238 entry->ecx = 0; 239 entry->edx = 0; 240 break; 241} 242case 9: 243break; 244case 0xa: /* Architectural Performance Monitoring */ 245{ 246 struct x86_pmu_capability cap; 247 union cpuid10_eax eax; 248 union cpuid10_edx edx; 249 250 perf_get_x86_pmu_capability(&cap); 251 252 /* 253 * Only support guest architectural pmu on a host 254 * with architectural pmu. 255 */ 256 if (!cap.version) { 257 memset(&cap, 0, sizeof(cap)); 258 } 259 260 eax.split.version_id = min(cap.version, 2); 261 eax.split.num_counters = cap.num_counters_gp; 262 eax.split.bit_width = cap.bit_width_gp; 263 eax.split.mask_length = cap.events_mask_len; 264 265 edx.split.num_counters_fixed = cap.num_counters_fixed; 266 edx.split.bit_width_fixed = cap.bit_width_fixed; 267 edx.split.reserved = 0; 268 269 entry->eax = eax.full; 270 entry->ebx = cap.events_mask; 271 entry->ecx = 0; 272 entry->edx = edx.full; 273 break; 274} 275/* function 0xb has additional index. */ 276case 0xb: 277{ 278 int i, level_type; 279 280 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 281 /* read more entries until level_type is zero */ 282 for (i = 1; ; ++i) { 283 if (*nent >= maxnent) { 284 goto out; 285 } 286 287 level_type = entry[i - 1].ecx & 0xff00; 288 if (!level_type) { 289 break; 290 } 291 do_cpuid_1_ent(&entry[i], function, i); 292 entry[i].flags |= 293 KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 294 ++*nent; 295 } 296 break; 297} 298case 0xd: 299{ 300 int idx, i; 301 302 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 303 for (idx = 1, i = 1; idx < 64; ++idx) { 304 if (*nent >= maxnent) { 305 goto out; 306 } 307 308 do_cpuid_1_ent(&entry[i], function, idx); 309 if (entry[i].eax == 0 || !supported_xcr0_bit(idx)) { 310 continue; 311 } 312 entry[i].flags |= 313 KVM_CPUID_FLAG_SIGNIFCANT_INDEX; 314 ++*nent; 315 ++i; 316 } 317 break; 318} 319case KVM_CPUID_SIGNATURE: 320{ 321 static const char signature[12] = "KVMKVMKVM\0\0"; 322 const unsigned int *sigptr = (const unsigned int *)signature; 323 entry->eax = KVM_CPUID_FEATURES; 324 entry->ebx = sigptr[0]; 325 entry->ecx = sigptr[1]; 326 entry->edx = sigptr[2]; 327 break; 328} 329case KVM_CPUID_FEATURES: 330entry->eax = (BIT(KVM_FEATURE_CLOCKSOURCE)) | 331 (BIT(KVM_FEATURE_NOP_IO_DELAY)) | 332 (BIT(KVM_FEATURE_CLOCKSOURCE2)) | 333 (BIT(KVM_FEATURE_ASYNC_PF)) | 334 (BIT(KVM_FEATURE_PV_EOI)) | 335 (BIT(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT)); 336 337if (sched_info_on()) 338{ 339 entry->eax |= (BIT(KVM_FEATURE_STEAL_TIME)); 340} 341 342entry->ebx = 0; 343entry->ecx = 0; 344entry->edx = 0; 345break; 346case 0x80000019: 347entry->ecx = entry->edx = 0; 348break; 349case 0x8000001a: 350break; 351case 0x8000001d: 352break; 353/*Add support for Centaur's CPUID instruction*/ 354case 0xC0000000: 355/*Just support up to 0xC0000004 now*/ 356entry->eax = min(entry->eax, 0xC0000004); 357break; 358case 0xC0000001: 359entry->edx &= kvm_supported_word5_x86_features; 360cpuid_mask(&entry->edx, 5); 361break; 362case 3: /* Processor serial number */ 363case 5: /* MONITOR/MWAIT */ 364case 6: /* Thermal management */ 365case 0x80000007: /* Advanced power management */ 366case 0xC0000002: 367case 0xC0000003: 368case 0xC0000004: 369default: 370entry->eax = entry->ebx = entry->ecx = entry->edx = 0; 371break; 372} 373#endif 374 375/* VM exit handler: for the CPUID instruction. */ 376int vm_cpuid_handler(vm_vcpu_t *vcpu) 377{ 378 379 int ret; 380 struct cpuid_val val; 381 382 /* Read parameter information. */ 383 unsigned int function, index; 384 if (vm_get_thread_context_reg(vcpu, VCPU_CONTEXT_EAX, &function) 385 || vm_get_thread_context_reg(vcpu, VCPU_CONTEXT_ECX, &index)) { 386 return VM_EXIT_HANDLE_ERROR; 387 } 388 389 /* Virtualise the CPUID instruction. */ 390 ret = vm_cpuid_virt(function, index, &val, vcpu); 391 if (ret) { 392 return VM_EXIT_HANDLE_ERROR; 393 } 394 395 /* Set the return values in guest context. */ 396 vm_set_thread_context_reg(vcpu, VCPU_CONTEXT_EAX, val.eax); 397 vm_set_thread_context_reg(vcpu, VCPU_CONTEXT_EBX, val.ebx); 398 vm_set_thread_context_reg(vcpu, VCPU_CONTEXT_ECX, val.ecx); 399 vm_set_thread_context_reg(vcpu, VCPU_CONTEXT_EDX, val.edx); 400 401 vm_guest_exit_next_instruction(vcpu->vcpu_arch.guest_state, vcpu->vcpu.cptr); 402 403 /* Return success. */ 404 return VM_EXIT_HANDLED; 405} 406