1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2011 NetApp, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include "opt_ddb.h" 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/pcpu.h> 39 40 #include <vm/vm.h> 41 #include <vm/pmap.h> 42 43 #include <machine/segments.h> 44 #include <machine/vmm.h> 45 #include "vmm_host.h" 46 #include "vmx_cpufunc.h" 47 #include "vmcs.h" 48 #include "ept.h" 49 #include "vmx.h" 50 51 #ifdef DDB 52 #include <ddb/ddb.h> 53 #endif 54 55 static uint64_t 56 vmcs_fix_regval(uint32_t encoding, uint64_t val) 57 { 58 59 switch (encoding) { 60 case VMCS_GUEST_CR0: 61 val = vmx_fix_cr0(val); 62 break; 63 case VMCS_GUEST_CR4: 64 val = vmx_fix_cr4(val); 65 break; 66 default: 67 break; 68 } 69 return (val); 70 } 71 72 static uint32_t 73 vmcs_field_encoding(int ident) 74 { 75 switch (ident) { 76 case VM_REG_GUEST_CR0: 77 return (VMCS_GUEST_CR0); 78 case VM_REG_GUEST_CR3: 79 return (VMCS_GUEST_CR3); 80 case VM_REG_GUEST_CR4: 81 return (VMCS_GUEST_CR4); 82 case VM_REG_GUEST_DR7: 83 return (VMCS_GUEST_DR7); 84 case VM_REG_GUEST_RSP: 85 return (VMCS_GUEST_RSP); 86 case VM_REG_GUEST_RIP: 87 return (VMCS_GUEST_RIP); 88 case VM_REG_GUEST_RFLAGS: 89 return (VMCS_GUEST_RFLAGS); 90 case VM_REG_GUEST_ES: 91 return (VMCS_GUEST_ES_SELECTOR); 92 case VM_REG_GUEST_CS: 93 return (VMCS_GUEST_CS_SELECTOR); 94 case VM_REG_GUEST_SS: 95 return (VMCS_GUEST_SS_SELECTOR); 96 case VM_REG_GUEST_DS: 97 return (VMCS_GUEST_DS_SELECTOR); 98 case VM_REG_GUEST_FS: 99 return (VMCS_GUEST_FS_SELECTOR); 100 case VM_REG_GUEST_GS: 101 return (VMCS_GUEST_GS_SELECTOR); 102 case VM_REG_GUEST_TR: 103 return (VMCS_GUEST_TR_SELECTOR); 104 case VM_REG_GUEST_LDTR: 105 return (VMCS_GUEST_LDTR_SELECTOR); 106 case VM_REG_GUEST_EFER: 107 return (VMCS_GUEST_IA32_EFER); 108 case VM_REG_GUEST_PDPTE0: 109 return (VMCS_GUEST_PDPTE0); 110 case VM_REG_GUEST_PDPTE1: 111 return (VMCS_GUEST_PDPTE1); 112 case VM_REG_GUEST_PDPTE2: 113 return (VMCS_GUEST_PDPTE2); 114 case VM_REG_GUEST_PDPTE3: 115 return (VMCS_GUEST_PDPTE3); 116 default: 117 return (-1); 118 } 119 120 } 121 122 static int 123 vmcs_seg_desc_encoding(int seg, uint32_t *base, uint32_t *lim, uint32_t *acc) 124 { 125 126 switch (seg) { 127 case VM_REG_GUEST_ES: 128 *base = VMCS_GUEST_ES_BASE; 129 *lim = VMCS_GUEST_ES_LIMIT; 130 *acc = VMCS_GUEST_ES_ACCESS_RIGHTS; 131 break; 132 case VM_REG_GUEST_CS: 133 *base = VMCS_GUEST_CS_BASE; 134 *lim = VMCS_GUEST_CS_LIMIT; 135 *acc = VMCS_GUEST_CS_ACCESS_RIGHTS; 136 break; 137 case VM_REG_GUEST_SS: 138 *base = VMCS_GUEST_SS_BASE; 139 *lim = VMCS_GUEST_SS_LIMIT; 140 *acc = VMCS_GUEST_SS_ACCESS_RIGHTS; 141 break; 142 case VM_REG_GUEST_DS: 143 *base = VMCS_GUEST_DS_BASE; 144 *lim = VMCS_GUEST_DS_LIMIT; 145 *acc = VMCS_GUEST_DS_ACCESS_RIGHTS; 146 break; 147 case VM_REG_GUEST_FS: 148 *base = VMCS_GUEST_FS_BASE; 149 *lim = VMCS_GUEST_FS_LIMIT; 150 *acc = VMCS_GUEST_FS_ACCESS_RIGHTS; 151 break; 152 case VM_REG_GUEST_GS: 153 *base = VMCS_GUEST_GS_BASE; 154 *lim = VMCS_GUEST_GS_LIMIT; 155 *acc = VMCS_GUEST_GS_ACCESS_RIGHTS; 156 break; 157 case VM_REG_GUEST_TR: 158 *base = VMCS_GUEST_TR_BASE; 159 *lim = VMCS_GUEST_TR_LIMIT; 160 *acc = VMCS_GUEST_TR_ACCESS_RIGHTS; 161 break; 162 case VM_REG_GUEST_LDTR: 163 *base = VMCS_GUEST_LDTR_BASE; 164 *lim = VMCS_GUEST_LDTR_LIMIT; 165 *acc = VMCS_GUEST_LDTR_ACCESS_RIGHTS; 166 break; 167 case VM_REG_GUEST_IDTR: 168 *base = VMCS_GUEST_IDTR_BASE; 169 *lim = VMCS_GUEST_IDTR_LIMIT; 170 *acc = VMCS_INVALID_ENCODING; 171 break; 172 case VM_REG_GUEST_GDTR: 173 *base = VMCS_GUEST_GDTR_BASE; 174 *lim = VMCS_GUEST_GDTR_LIMIT; 175 *acc = VMCS_INVALID_ENCODING; 176 break; 177 default: 178 return (EINVAL); 179 } 180 181 return (0); 182 } 183 184 int 185 vmcs_getreg(struct vmcs *vmcs, int running, int ident, uint64_t *retval) 186 { 187 int error; 188 uint32_t encoding; 189 190 /* 191 * If we need to get at vmx-specific state in the VMCS we can bypass 192 * the translation of 'ident' to 'encoding' by simply setting the 193 * sign bit. As it so happens the upper 16 bits are reserved (i.e 194 * set to 0) in the encodings for the VMCS so we are free to use the 195 * sign bit. 196 */ 197 if (ident < 0) 198 encoding = ident & 0x7fffffff; 199 else 200 encoding = vmcs_field_encoding(ident); 201 202 if (encoding == (uint32_t)-1) 203 return (EINVAL); 204 205 if (!running) 206 VMPTRLD(vmcs); 207 208 error = vmread(encoding, retval); 209 210 if (!running) 211 VMCLEAR(vmcs); 212 213 return (error); 214 } 215 216 int 217 vmcs_setreg(struct vmcs *vmcs, int running, int ident, uint64_t val) 218 { 219 int error; 220 uint32_t encoding; 221 222 if (ident < 0) 223 encoding = ident & 0x7fffffff; 224 else 225 encoding = vmcs_field_encoding(ident); 226 227 if (encoding == (uint32_t)-1) 228 return (EINVAL); 229 230 val = vmcs_fix_regval(encoding, val); 231 232 if (!running) 233 VMPTRLD(vmcs); 234 235 error = vmwrite(encoding, val); 236 237 if (!running) 238 VMCLEAR(vmcs); 239 240 return (error); 241 } 242 243 int 244 vmcs_setdesc(struct vmcs *vmcs, int running, int seg, struct seg_desc *desc) 245 { 246 int error; 247 uint32_t base, limit, access; 248 249 error = vmcs_seg_desc_encoding(seg, &base, &limit, &access); 250 if (error != 0) 251 panic("vmcs_setdesc: invalid segment register %d", seg); 252 253 if (!running) 254 VMPTRLD(vmcs); 255 if ((error = vmwrite(base, desc->base)) != 0) 256 goto done; 257 258 if ((error = vmwrite(limit, desc->limit)) != 0) 259 goto done; 260 261 if (access != VMCS_INVALID_ENCODING) { 262 if ((error = vmwrite(access, desc->access)) != 0) 263 goto done; 264 } 265 done: 266 if (!running) 267 VMCLEAR(vmcs); 268 return (error); 269 } 270 271 int 272 vmcs_getdesc(struct vmcs *vmcs, int running, int seg, struct seg_desc *desc) 273 { 274 int error; 275 uint32_t base, limit, access; 276 uint64_t u64; 277 278 error = vmcs_seg_desc_encoding(seg, &base, &limit, &access); 279 if (error != 0) 280 panic("vmcs_getdesc: invalid segment register %d", seg); 281 282 if (!running) 283 VMPTRLD(vmcs); 284 if ((error = vmread(base, &u64)) != 0) 285 goto done; 286 desc->base = u64; 287 288 if ((error = vmread(limit, &u64)) != 0) 289 goto done; 290 desc->limit = u64; 291 292 if (access != VMCS_INVALID_ENCODING) { 293 if ((error = vmread(access, &u64)) != 0) 294 goto done; 295 desc->access = u64; 296 } 297 done: 298 if (!running) 299 VMCLEAR(vmcs); 300 return (error); 301 } 302 303 int 304 vmcs_set_msr_save(struct vmcs *vmcs, u_long g_area, u_int g_count) 305 { 306 int error; 307 308 VMPTRLD(vmcs); 309 310 /* 311 * Guest MSRs are saved in the VM-exit MSR-store area. 312 * Guest MSRs are loaded from the VM-entry MSR-load area. 313 * Both areas point to the same location in memory. 314 */ 315 if ((error = vmwrite(VMCS_EXIT_MSR_STORE, g_area)) != 0) 316 goto done; 317 if ((error = vmwrite(VMCS_EXIT_MSR_STORE_COUNT, g_count)) != 0) 318 goto done; 319 320 if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD, g_area)) != 0) 321 goto done; 322 if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD_COUNT, g_count)) != 0) 323 goto done; 324 325 error = 0; 326 done: 327 VMCLEAR(vmcs); 328 return (error); 329 } 330 331 int 332 vmcs_init(struct vmcs *vmcs) 333 { 334 int error, codesel, datasel, tsssel; 335 u_long cr0, cr4, efer; 336 uint64_t pat, fsbase, idtrbase; 337 338 codesel = vmm_get_host_codesel(); 339 datasel = vmm_get_host_datasel(); 340 tsssel = vmm_get_host_tsssel(); 341 342 /* 343 * Make sure we have a "current" VMCS to work with. 344 */ 345 VMPTRLD(vmcs); 346 347 /* Host state */ 348 349 /* Initialize host IA32_PAT MSR */ 350 pat = vmm_get_host_pat(); 351 if ((error = vmwrite(VMCS_HOST_IA32_PAT, pat)) != 0) 352 goto done; 353 354 /* Load the IA32_EFER MSR */ 355 efer = vmm_get_host_efer(); 356 if ((error = vmwrite(VMCS_HOST_IA32_EFER, efer)) != 0) 357 goto done; 358 359 /* Load the control registers */ 360 361 cr0 = vmm_get_host_cr0(); 362 if ((error = vmwrite(VMCS_HOST_CR0, cr0)) != 0) 363 goto done; 364 365 cr4 = vmm_get_host_cr4() | CR4_VMXE; 366 if ((error = vmwrite(VMCS_HOST_CR4, cr4)) != 0) 367 goto done; 368 369 /* Load the segment selectors */ 370 if ((error = vmwrite(VMCS_HOST_ES_SELECTOR, datasel)) != 0) 371 goto done; 372 373 if ((error = vmwrite(VMCS_HOST_CS_SELECTOR, codesel)) != 0) 374 goto done; 375 376 if ((error = vmwrite(VMCS_HOST_SS_SELECTOR, datasel)) != 0) 377 goto done; 378 379 if ((error = vmwrite(VMCS_HOST_DS_SELECTOR, datasel)) != 0) 380 goto done; 381 382 if ((error = vmwrite(VMCS_HOST_FS_SELECTOR, datasel)) != 0) 383 goto done; 384 385 if ((error = vmwrite(VMCS_HOST_GS_SELECTOR, datasel)) != 0) 386 goto done; 387 388 if ((error = vmwrite(VMCS_HOST_TR_SELECTOR, tsssel)) != 0) 389 goto done; 390 391 /* 392 * Load the Base-Address for %fs and idtr. 393 * 394 * Note that we exclude %gs, tss and gdtr here because their base 395 * address is pcpu specific. 396 */ 397 fsbase = vmm_get_host_fsbase(); 398 if ((error = vmwrite(VMCS_HOST_FS_BASE, fsbase)) != 0) 399 goto done; 400 401 idtrbase = vmm_get_host_idtrbase(); 402 if ((error = vmwrite(VMCS_HOST_IDTR_BASE, idtrbase)) != 0) 403 goto done; 404 405 /* instruction pointer */ 406 if ((error = vmwrite(VMCS_HOST_RIP, (u_long)vmx_exit_guest)) != 0) 407 goto done; 408 409 /* link pointer */ 410 if ((error = vmwrite(VMCS_LINK_POINTER, ~0)) != 0) 411 goto done; 412 done: 413 VMCLEAR(vmcs); 414 return (error); 415 } 416 417 #ifdef DDB 418 extern int vmxon_enabled[]; 419 420 DB_SHOW_COMMAND(vmcs, db_show_vmcs) 421 { 422 uint64_t cur_vmcs, val; 423 uint32_t exit; 424 425 if (!vmxon_enabled[curcpu]) { 426 db_printf("VMX not enabled\n"); 427 return; 428 } 429 430 if (have_addr) { 431 db_printf("Only current VMCS supported\n"); 432 return; 433 } 434 435 vmptrst(&cur_vmcs); 436 if (cur_vmcs == VMCS_INITIAL) { 437 db_printf("No current VM context\n"); 438 return; 439 } 440 db_printf("VMCS: %jx\n", cur_vmcs); 441 db_printf("VPID: %lu\n", vmcs_read(VMCS_VPID)); 442 db_printf("Activity: "); 443 val = vmcs_read(VMCS_GUEST_ACTIVITY); 444 switch (val) { 445 case 0: 446 db_printf("Active"); 447 break; 448 case 1: 449 db_printf("HLT"); 450 break; 451 case 2: 452 db_printf("Shutdown"); 453 break; 454 case 3: 455 db_printf("Wait for SIPI"); 456 break; 457 default: 458 db_printf("Unknown: %#lx", val); 459 } 460 db_printf("\n"); 461 exit = vmcs_read(VMCS_EXIT_REASON); 462 if (exit & 0x80000000) 463 db_printf("Entry Failure Reason: %u\n", exit & 0xffff); 464 else 465 db_printf("Exit Reason: %u\n", exit & 0xffff); 466 db_printf("Qualification: %#lx\n", vmcs_exit_qualification()); 467 db_printf("Guest Linear Address: %#lx\n", 468 vmcs_read(VMCS_GUEST_LINEAR_ADDRESS)); 469 switch (exit & 0x8000ffff) { 470 case EXIT_REASON_EXCEPTION: 471 case EXIT_REASON_EXT_INTR: 472 val = vmcs_read(VMCS_EXIT_INTR_INFO); 473 db_printf("Interrupt Type: "); 474 switch (val >> 8 & 0x7) { 475 case 0: 476 db_printf("external"); 477 break; 478 case 2: 479 db_printf("NMI"); 480 break; 481 case 3: 482 db_printf("HW exception"); 483 break; 484 case 4: 485 db_printf("SW exception"); 486 break; 487 default: 488 db_printf("?? %lu", val >> 8 & 0x7); 489 break; 490 } 491 db_printf(" Vector: %lu", val & 0xff); 492 if (val & 0x800) 493 db_printf(" Error Code: %lx", 494 vmcs_read(VMCS_EXIT_INTR_ERRCODE)); 495 db_printf("\n"); 496 break; 497 case EXIT_REASON_EPT_FAULT: 498 case EXIT_REASON_EPT_MISCONFIG: 499 db_printf("Guest Physical Address: %#lx\n", 500 vmcs_read(VMCS_GUEST_PHYSICAL_ADDRESS)); 501 break; 502 } 503 db_printf("VM-instruction error: %#lx\n", vmcs_instruction_error()); 504 } 505 #endif 506