1 /* $NetBSD: nvmm_x86.c,v 1.25 2026/07/15 01:22:21 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net 5 * All rights reserved. 6 * 7 * This code is part of the NVMM hypervisor. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: nvmm_x86.c,v 1.25 2026/07/15 01:22:21 riastradh Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/cpu.h> 38 39 #include <uvm/uvm_extern.h> 40 41 #include <x86/cputypes.h> 42 #include <x86/pat.h> 43 #include <x86/specialreg.h> 44 45 #include <dev/nvmm/nvmm.h> 46 #include <dev/nvmm/nvmm_internal.h> 47 #include <dev/nvmm/x86/nvmm_x86.h> 48 49 /* 50 * Code shared between x86-SVM and x86-VMX. 51 */ 52 53 const struct nvmm_x64_state nvmm_x86_reset_state = { 54 .segs = { 55 [NVMM_X64_SEG_ES] = { 56 .selector = 0x0000, 57 .base = 0x00000000, 58 .limit = 0xFFFF, 59 .attrib = { 60 .type = 3, 61 .s = 1, 62 .p = 1, 63 } 64 }, 65 [NVMM_X64_SEG_CS] = { 66 .selector = 0xF000, 67 .base = 0xFFFF0000, 68 .limit = 0xFFFF, 69 .attrib = { 70 .type = 3, 71 .s = 1, 72 .p = 1, 73 } 74 }, 75 [NVMM_X64_SEG_SS] = { 76 .selector = 0x0000, 77 .base = 0x00000000, 78 .limit = 0xFFFF, 79 .attrib = { 80 .type = 3, 81 .s = 1, 82 .p = 1, 83 } 84 }, 85 [NVMM_X64_SEG_DS] = { 86 .selector = 0x0000, 87 .base = 0x00000000, 88 .limit = 0xFFFF, 89 .attrib = { 90 .type = 3, 91 .s = 1, 92 .p = 1, 93 } 94 }, 95 [NVMM_X64_SEG_FS] = { 96 .selector = 0x0000, 97 .base = 0x00000000, 98 .limit = 0xFFFF, 99 .attrib = { 100 .type = 3, 101 .s = 1, 102 .p = 1, 103 } 104 }, 105 [NVMM_X64_SEG_GS] = { 106 .selector = 0x0000, 107 .base = 0x00000000, 108 .limit = 0xFFFF, 109 .attrib = { 110 .type = 3, 111 .s = 1, 112 .p = 1, 113 } 114 }, 115 [NVMM_X64_SEG_GDT] = { 116 .selector = 0x0000, 117 .base = 0x00000000, 118 .limit = 0xFFFF, 119 .attrib = { 120 .type = 2, 121 .s = 1, 122 .p = 1, 123 } 124 }, 125 [NVMM_X64_SEG_IDT] = { 126 .selector = 0x0000, 127 .base = 0x00000000, 128 .limit = 0xFFFF, 129 .attrib = { 130 .type = 2, 131 .s = 1, 132 .p = 1, 133 } 134 }, 135 [NVMM_X64_SEG_LDT] = { 136 .selector = 0x0000, 137 .base = 0x00000000, 138 .limit = 0xFFFF, 139 .attrib = { 140 .type = SDT_SYSLDT, 141 .s = 0, 142 .p = 1, 143 } 144 }, 145 [NVMM_X64_SEG_TR] = { 146 .selector = 0x0000, 147 .base = 0x00000000, 148 .limit = 0xFFFF, 149 .attrib = { 150 .type = SDT_SYS286BSY, 151 .s = 0, 152 .p = 1, 153 } 154 }, 155 }, 156 157 .gprs = { 158 [NVMM_X64_GPR_RAX] = 0x00000000, 159 [NVMM_X64_GPR_RCX] = 0x00000000, 160 [NVMM_X64_GPR_RDX] = 0x00000600, 161 [NVMM_X64_GPR_RBX] = 0x00000000, 162 [NVMM_X64_GPR_RSP] = 0x00000000, 163 [NVMM_X64_GPR_RBP] = 0x00000000, 164 [NVMM_X64_GPR_RSI] = 0x00000000, 165 [NVMM_X64_GPR_RDI] = 0x00000000, 166 [NVMM_X64_GPR_R8] = 0x00000000, 167 [NVMM_X64_GPR_R9] = 0x00000000, 168 [NVMM_X64_GPR_R10] = 0x00000000, 169 [NVMM_X64_GPR_R11] = 0x00000000, 170 [NVMM_X64_GPR_R12] = 0x00000000, 171 [NVMM_X64_GPR_R13] = 0x00000000, 172 [NVMM_X64_GPR_R14] = 0x00000000, 173 [NVMM_X64_GPR_R15] = 0x00000000, 174 [NVMM_X64_GPR_RIP] = 0x0000FFF0, 175 [NVMM_X64_GPR_RFLAGS] = 0x00000002, 176 }, 177 178 .crs = { 179 [NVMM_X64_CR_CR0] = 0x60000010, 180 [NVMM_X64_CR_CR2] = 0x00000000, 181 [NVMM_X64_CR_CR3] = 0x00000000, 182 [NVMM_X64_CR_CR4] = 0x00000000, 183 [NVMM_X64_CR_CR8] = 0x00000000, 184 [NVMM_X64_CR_XCR0] = 0x00000001, 185 }, 186 187 .drs = { 188 [NVMM_X64_DR_DR0] = 0x00000000, 189 [NVMM_X64_DR_DR1] = 0x00000000, 190 [NVMM_X64_DR_DR2] = 0x00000000, 191 [NVMM_X64_DR_DR3] = 0x00000000, 192 [NVMM_X64_DR_DR6] = 0xFFFF0FF0, 193 [NVMM_X64_DR_DR7] = 0x00000400, 194 }, 195 196 .msrs = { 197 [NVMM_X64_MSR_EFER] = 0x00000000, 198 [NVMM_X64_MSR_STAR] = 0x00000000, 199 [NVMM_X64_MSR_LSTAR] = 0x00000000, 200 [NVMM_X64_MSR_CSTAR] = 0x00000000, 201 [NVMM_X64_MSR_SFMASK] = 0x00000000, 202 [NVMM_X64_MSR_KERNELGSBASE] = 0x00000000, 203 [NVMM_X64_MSR_SYSENTER_CS] = 0x00000000, 204 [NVMM_X64_MSR_SYSENTER_ESP] = 0x00000000, 205 [NVMM_X64_MSR_SYSENTER_EIP] = 0x00000000, 206 [NVMM_X64_MSR_PAT] = 207 PATENTRY(0, PAT_WB) | PATENTRY(1, PAT_WT) | 208 PATENTRY(2, PAT_UCMINUS) | PATENTRY(3, PAT_UC) | 209 PATENTRY(4, PAT_WB) | PATENTRY(5, PAT_WT) | 210 PATENTRY(6, PAT_UCMINUS) | PATENTRY(7, PAT_UC), 211 [NVMM_X64_MSR_TSC] = 0, 212 }, 213 214 .intr = { 215 .int_shadow = 0, 216 .int_window_exiting = 0, 217 .nmi_window_exiting = 0, 218 .evt_pending = 0, 219 }, 220 221 .fpu = { 222 .fx_cw = 0x0040, 223 .fx_sw = 0x0000, 224 .fx_tw = 0x55, 225 .fx_zero = 0x55, 226 .fx_mxcsr = 0x1F80, 227 } 228 }; 229 230 const struct nvmm_x86_cpuid_mask nvmm_cpuid_00000001 = { 231 .eax = ~0, 232 .ebx = ~0, 233 .ecx = 234 CPUID2_SSE3 | 235 CPUID2_PCLMULQDQ | 236 /* CPUID2_DTES64 excluded */ 237 /* CPUID2_MONITOR excluded */ 238 /* CPUID2_DS_CPL excluded */ 239 /* CPUID2_VMX excluded */ 240 /* CPUID2_SMX excluded */ 241 /* CPUID2_EST excluded */ 242 /* CPUID2_TM2 excluded */ 243 CPUID2_SSSE3 | 244 /* CPUID2_CNXTID excluded */ 245 /* CPUID2_SDBG excluded */ 246 CPUID2_FMA | 247 CPUID2_CX16 | 248 /* CPUID2_XTPR excluded */ 249 /* CPUID2_PDCM excluded */ 250 /* CPUID2_PCID excluded, but re-included in VMX */ 251 /* CPUID2_DCA excluded */ 252 CPUID2_SSE41 | 253 CPUID2_SSE42 | 254 /* CPUID2_X2APIC excluded */ 255 CPUID2_MOVBE | 256 CPUID2_POPCNT | 257 /* CPUID2_DEADLINE excluded */ 258 CPUID2_AESNI | 259 CPUID2_XSAVE | 260 CPUID2_OSXSAVE | 261 CPUID2_AVX | 262 CPUID2_F16C | 263 CPUID2_RDRAND, 264 /* CPUID2_RAZ excluded */ 265 .edx = 266 CPUID_FPU | 267 CPUID_VME | 268 CPUID_DE | 269 CPUID_PSE | 270 CPUID_TSC | 271 CPUID_MSR | 272 CPUID_PAE | 273 /* CPUID_MCE excluded */ 274 CPUID_CX8 | 275 CPUID_APIC | 276 CPUID_SEP | 277 /* CPUID_MTRR excluded */ 278 CPUID_PGE | 279 /* CPUID_MCA excluded */ 280 CPUID_CMOV | 281 CPUID_PAT | 282 CPUID_PSE36 | 283 /* CPUID_PSN excluded */ 284 CPUID_CLFSH | 285 /* CPUID_DS excluded */ 286 /* CPUID_ACPI excluded */ 287 CPUID_MMX | 288 CPUID_FXSR | 289 CPUID_SSE | 290 CPUID_SSE2 | 291 CPUID_SS | 292 CPUID_HTT | 293 /* CPUID_TM excluded */ 294 CPUID_PBE 295 }; 296 297 const struct nvmm_x86_cpuid_mask nvmm_cpuid_00000007 = { 298 .eax = ~0, 299 .ebx = 300 CPUID_SEF_FSGSBASE | 301 /* CPUID_SEF_TSC_ADJUST excluded */ 302 /* CPUID_SEF_SGX excluded */ 303 CPUID_SEF_BMI1 | 304 /* CPUID_SEF_HLE excluded */ 305 CPUID_SEF_AVX2 | 306 CPUID_SEF_FDPEXONLY | 307 CPUID_SEF_SMEP | 308 CPUID_SEF_BMI2 | 309 CPUID_SEF_ERMS | 310 /* CPUID_SEF_INVPCID excluded, but re-included in VMX */ 311 /* CPUID_SEF_RTM excluded */ 312 /* CPUID_SEF_QM excluded */ 313 CPUID_SEF_FPUCSDS | 314 /* CPUID_SEF_MPX excluded */ 315 /* CPUID_SEF_PQE excluded */ 316 /* CPUID_SEF_AVX512F excluded */ 317 /* CPUID_SEF_AVX512DQ excluded */ 318 CPUID_SEF_RDSEED | 319 CPUID_SEF_ADX | 320 CPUID_SEF_SMAP | 321 /* CPUID_SEF_AVX512_IFMA excluded */ 322 CPUID_SEF_CLFLUSHOPT | 323 CPUID_SEF_CLWB, 324 /* CPUID_SEF_PT excluded */ 325 /* CPUID_SEF_AVX512PF excluded */ 326 /* CPUID_SEF_AVX512ER excluded */ 327 /* CPUID_SEF_AVX512CD excluded */ 328 /* CPUID_SEF_SHA excluded */ 329 /* CPUID_SEF_AVX512BW excluded */ 330 /* CPUID_SEF_AVX512VL excluded */ 331 .ecx = 332 CPUID_SEF_PREFETCHWT1 | 333 /* CPUID_SEF_AVX512_VBMI excluded */ 334 CPUID_SEF_UMIP | 335 /* CPUID_SEF_PKU excluded */ 336 /* CPUID_SEF_OSPKE excluded */ 337 /* CPUID_SEF_WAITPKG excluded */ 338 /* CPUID_SEF_AVX512_VBMI2 excluded */ 339 /* CPUID_SEF_CET_SS excluded */ 340 CPUID_SEF_GFNI | 341 CPUID_SEF_VAES | 342 CPUID_SEF_VPCLMULQDQ | 343 /* CPUID_SEF_AVX512_VNNI excluded */ 344 /* CPUID_SEF_AVX512_BITALG excluded */ 345 /* CPUID_SEF_AVX512_VPOPCNTDQ excluded */ 346 /* CPUID_SEF_MAWAU excluded */ 347 /* CPUID_SEF_RDPID excluded */ 348 CPUID_SEF_CLDEMOTE | 349 CPUID_SEF_MOVDIRI | 350 CPUID_SEF_MOVDIR64B, 351 /* CPUID_SEF_SGXLC excluded */ 352 /* CPUID_SEF_PKS excluded */ 353 .edx = 354 /* CPUID_SEF_AVX512_4VNNIW excluded */ 355 /* CPUID_SEF_AVX512_4FMAPS excluded */ 356 CPUID_SEF_FSRM | 357 /* CPUID_SEF_AVX512_VP2INTERSECT excluded */ 358 /* CPUID_SEF_SRBDS_CTRL excluded */ 359 CPUID_SEF_MD_CLEAR | 360 /* CPUID_SEF_TSX_FORCE_ABORT excluded */ 361 CPUID_SEF_SERIALIZE 362 /* CPUID_SEF_HYBRID excluded */ 363 /* CPUID_SEF_TSXLDTRK excluded */ 364 /* CPUID_SEF_CET_IBT excluded */ 365 /* CPUID_SEF_IBRS excluded */ 366 /* CPUID_SEF_STIBP excluded */ 367 /* CPUID_SEF_L1D_FLUSH excluded */ 368 /* CPUID_SEF_ARCH_CAP excluded */ 369 /* CPUID_SEF_CORE_CAP excluded */ 370 /* CPUID_SEF_SSBD excluded */ 371 }; 372 373 const struct nvmm_x86_cpuid_mask nvmm_cpuid_80000001 = { 374 .eax = ~0, 375 .ebx = ~0, 376 .ecx = 377 CPUID_LAHF | 378 CPUID_CMPLEGACY | 379 /* CPUID_SVM excluded */ 380 /* CPUID_EAPIC excluded */ 381 CPUID_ALTMOVCR0 | 382 CPUID_ABM | 383 CPUID_SSE4A | 384 CPUID_MISALIGNSSE | 385 CPUID_3DNOWPF | 386 /* CPUID_OSVW excluded */ 387 /* CPUID_IBS excluded */ 388 CPUID_XOP | 389 /* CPUID_SKINIT excluded */ 390 /* CPUID_WDT excluded */ 391 /* CPUID_LWP excluded */ 392 CPUID_FMA4 | 393 CPUID_TCE | 394 /* CPUID_NODEID excluded */ 395 CPUID_TBM | 396 CPUID_TOPOEXT, 397 /* CPUID_PCEC excluded */ 398 /* CPUID_PCENB excluded */ 399 /* CPUID_SPM excluded */ 400 /* CPUID_DBE excluded */ 401 /* CPUID_PTSC excluded */ 402 /* CPUID_L2IPERFC excluded */ 403 /* CPUID_MWAITX excluded */ 404 .edx = 405 CPUID_FPU | 406 CPUID_VME | 407 CPUID_DE | 408 CPUID_PSE | 409 CPUID_TSC | 410 CPUID_MSR | 411 CPUID_PAE | 412 /* CPUID_MCE excluded */ 413 CPUID_CX8 | 414 CPUID_APIC | 415 CPUID_SYSCALL | 416 /* CPUID_MTRR excluded */ 417 CPUID_PGE | 418 /* CPUID_MCA excluded */ 419 CPUID_CMOV | 420 CPUID_PAT | 421 CPUID_PSE36 | 422 CPUID_XD | 423 CPUID_MMXX | 424 CPUID_MMX | 425 CPUID_FXSR | 426 CPUID_FFXSR | 427 CPUID_PAGE1GB | 428 /* CPUID_RDTSCP excluded */ 429 CPUID_EM64T | 430 CPUID_3DNOW2 | 431 CPUID_3DNOW 432 }; 433 434 const struct nvmm_x86_cpuid_mask nvmm_cpuid_80000007 = { 435 .eax = 0, 436 .ebx = 0, 437 .ecx = 0, 438 .edx = CPUID_APM_ITSC 439 }; 440 441 const struct nvmm_x86_cpuid_mask nvmm_cpuid_80000008 = { 442 .eax = ~0, 443 .ebx = 444 CPUID_CAPEX_CLZERO | 445 /* CPUID_CAPEX_IRPERF excluded */ 446 CPUID_CAPEX_XSAVEERPTR | 447 /* CPUID_CAPEX_RDPRU excluded */ 448 /* CPUID_CAPEX_MCOMMIT excluded */ 449 CPUID_CAPEX_WBNOINVD, 450 .ecx = ~0, /* TODO? */ 451 .edx = 0 452 }; 453 454 bool 455 nvmm_x86_pat_validate(uint64_t val) 456 { 457 uint8_t *pat = (uint8_t *)&val; 458 size_t i; 459 460 for (i = 0; i < 8; i++) { 461 if (__predict_false(pat[i] & ~__BITS(2,0))) 462 return false; 463 if (__predict_false(pat[i] == 2 || pat[i] == 3)) 464 return false; 465 } 466 467 return true; 468 } 469 470 /* 471 * nvmm_x86_xsave_size(xcr0) 472 * 473 * Returns the maximum XSAVE area size in bytes needed to 474 * represent all user state components corresponding to bits set 475 * in xcr0. Bit 63, which is reserved for future architecture 476 * extension at the time of writing, MUST NOT be set. Bits that 477 * were not previously advertised in CPUID[EAX=0x0d,ECX=0].EDX:EAX 478 * MUST NOT be set. 479 */ 480 uint32_t 481 nvmm_x86_xsave_size(uint64_t xcr0) 482 { 483 uint32_t totalsize = sizeof(struct xsave_header); 484 unsigned i; 485 486 /* 487 * Caller must not pass bit 63 until the architectural 488 * extension mechanism it is reserved for has been defined. 489 * Caller must also not pass any bits that the CPU has not 490 * advertised support for. 491 */ 492 KASSERTMSG((xcr0 & ~__BITS(62, 0)) == 0, "xcr0=0x%"PRIx64, xcr0); 493 KASSERTMSG((xcr0 & ~x86_xsave_features) == 0, 494 "xcr0=0x%"PRIx64" x86_xsave_features=0x%"PRIx64, 495 xcr0, x86_xsave_features); 496 497 /* 498 * Bit 0 is for x87 state, and bit 1 is for SSE state, for 499 * which (a) space is already included in the 512-byte legacy 500 * area of XSAVE (which is included in `struct xsave_header'), 501 * and (b) we can't query the CPUID[EAX=0x0d,ECX=i] leaf 502 * because for i=0 and i=1 the leaf serves a different purpose. 503 * 504 * We stop before bit 63 because it is reserved for future 505 * architectural extension which is not yet defined. 506 */ 507 CTASSERT(sizeof(struct xsave_header) == 512 + 64); 508 for (i = 2; i < 63; i++) { 509 uint32_t descs[4]; 510 uint32_t size, offset; 511 512 /* 513 * Skip state components that are not of interest to 514 * the caller. 515 */ 516 if ((xcr0 & __BIT(i)) == 0) 517 continue; 518 519 /* 520 * Can't use x86_xsave_offsets[i] + x86_xsave_sizes[i] 521 * because the NetBSD kernel only queries those for the 522 * user state components it knows about, but in 523 * principle this should support any user state 524 * component the guest wants to use even if NetBSD 525 * doesn't know how. 526 */ 527 x86_cpuid2(0x0d, i, descs); 528 size = descs[0]; /* CPUID[EAX=0x0d,ECX=i].EAX */ 529 offset = descs[1]; /* CPUID[EAX=0x0d,ECX=i].EBX */ 530 KASSERT(size <= UINT32_MAX - offset); 531 totalsize = MAX(totalsize, offset + size); 532 } 533 534 return totalsize; 535 } 536 537 /* 538 * nvmm_x86_xcr0_valid(xcr0, xcr0_mask) 539 * 540 * True if xcr0 is a valid content for the XCR0 register, false if 541 * not. 542 * 543 * - Bits outside xcr0_mask must not be set. 544 * - Bit for x87 state must be set. 545 * - The bit for the YMM_Hi128 state (high 128-bit halves of the 546 * ymm registers) can only be set if the SSE state (xmm 547 * registers, a.k.a. low 128-bit halves of the ymm registers) is 548 * also enabled. 549 * 550 * What about ZMM_Hi256? According to even recent architecture 551 * manuals from Intel and AMD, this does _not_ seem to require 552 * that SSE or YMM_Hi128 be enabled for ZMM_Hi256 to be enabled. 553 * Not requiring this is sensible because it enables XSAVE 554 * extensions to work safely even if software doesn't know such 555 * details. But I have not tested on real hardware whether 556 * ZMM_Hi256 actually does require YMM_Hi128 or SSE to be enabled 557 * in XCR0. 558 * 559 * References: 560 * 561 * - Intel 64 and IA-32 Architectures Software Developer's Manual, 562 * Volume 2 (2A, 2B, 2C, & 2D): Instruction Set Reference, A-Z, 563 * Intel, Order Number: 325383-092US, June 2026, Sec. 6.1 564 * `Instructions (W-Z)', `XSETBV---Set Extended Control 565 * Register', pp. 6-70 -- 6-71. 566 * https://cdrdv2.intel.com/v1/dl/getContent/671110 567 * https://web.archive.org/web/20260711031355/https://cdrdv2-public.intel.com/922478/325383-092-sdm-vol-2abcd.pdf 568 * 569 * - AMD64 Architecture Programmer's Manual, Volume 4: 128-bit, 570 * 256-bit, and 512-bit Media Instructions, Advanced Micro 571 * Devices, Publication No. 26568, Rev. 3.26, January 2026, 572 * pp. 1576--1577. 573 * https://docs.amd.com/v/u/en-US/26568_3.26_APM_Vol4 574 * https://web.archive.org/web/20260714233827/https://docs.amd.com/api/khub/documents/ioQiNhSqxlMkRaU~IyGQYQ/content?Ft-Calling-App=ft%2Fturnkey-portal&Ft-Calling-App-Version=5.3.24 575 */ 576 bool 577 nvmm_x86_xcr0_valid(uint64_t xcr0, uint64_t xcr0_mask) 578 { 579 580 /* 581 * Refuse setting any bits in XCR0 that are disabled in the 582 * vCPU configuration. 583 */ 584 if (__predict_false(xcr0 & ~xcr0_mask)) 585 return false; 586 587 /* 588 * Refuse clearing the x87 state component in XCR0, as the 589 * physical CPU would. 590 */ 591 if (__predict_false((xcr0 & XCR0_X87) == 0)) 592 return false; 593 594 /* 595 * Refuse setting the YMM_Hi128 state component in XCR0 if the 596 * SSE/XMM state component is not also enabled, like the 597 * physical CPU would. 598 */ 599 if (__predict_false((xcr0 & (XCR0_YMM_Hi128|XCR0_SSE)) == 600 XCR0_YMM_Hi128)) 601 return false; 602 603 /* Looks good! */ 604 return true; 605 } 606 607 /* 608 * nvmm_x86_munge_xcr0(xcr0, xcr0_mask) 609 * 610 * Map an arbitrary 64-bit word into a plausible value for XCR0 611 * under the given mask (which must itself be a plausible value 612 * for XCR0). This function MUST NOT be called on CPUs without 613 * XSAVE at all. 614 */ 615 uint64_t 616 nvmm_x86_munge_xcr0(uint64_t xcr0, uint64_t xcr0_mask) 617 { 618 uint64_t origxcr0 __diagused = xcr0; 619 620 KASSERT(xcr0_mask != 0); 621 KASSERTMSG(xcr0_mask & XCR0_X87, "xcr0_mask=0x%"PRIx64, xcr0_mask); 622 KASSERTMSG((xcr0_mask & (XCR0_YMM_Hi128|XCR0_SSE)) != XCR0_YMM_Hi128, 623 "xcr0_mask=0x%"PRIx64, xcr0_mask); 624 625 /* 626 * Clear any bits not in xcr0_mask. 627 */ 628 xcr0 &= xcr0_mask; 629 630 /* 631 * Set the mandatory x87 bit. 632 */ 633 xcr0 |= XCR0_X87; 634 635 /* 636 * If YMM_Hi128 (high 128-bit halves of ymmN) is enabled, then 637 * SSE (xmmN, a.k.a. low 128-bit halves of ymmN) must also be 638 * enabled. 639 * 640 * Note: The same may not apply to zmmN; see above about 641 * nvmm_x86_xcr0_valid. 642 */ 643 if (__predict_false((xcr0 & (XCR0_YMM_Hi128|XCR0_SSE)) == 644 XCR0_YMM_Hi128)) 645 xcr0 |= XCR0_SSE; 646 647 KASSERTMSG(nvmm_x86_xcr0_valid(xcr0, xcr0_mask), 648 "origxcr0=0x%"PRIx64" xcr0=0x%"PRIx64" xcr0_mask=0x%"PRIx64, 649 origxcr0, xcr0, xcr0_mask); 650 651 return xcr0; 652 } 653