vmcb.c revision 271203
1/*- 2 * Copyright (c) 2013 Anish Gupta (akgupt3@gmail.com) 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: projects/bhyve_svm/sys/amd64/vmm/amd/vmcb.c 271203 2014-09-06 19:02:52Z neel $"); 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/cpuset.h> 33 34#include <machine/segments.h> 35#include <machine/specialreg.h> 36#include <machine/vmm.h> 37 38#include "vmcb.h" 39#include "svm.h" 40 41/* 42 * The VMCB aka Virtual Machine Control Block is a 4KB aligned page 43 * in memory that describes the virtual machine. 44 * 45 * The VMCB contains: 46 * - instructions or events in the guest to intercept 47 * - control bits that modify execution environment of the guest 48 * - guest processor state (e.g. general purpose registers) 49 */ 50 51/* 52 * Initialize SVM h/w context i.e. the VMCB control and saved state areas. 53 */ 54void 55svm_init_vmcb(struct vmcb *vmcb, uint64_t iopm_base_pa, uint64_t msrpm_base_pa, 56 uint64_t np_pml4) 57{ 58 struct vmcb_ctrl *ctrl; 59 struct vmcb_state *state; 60 uint16_t cr_shadow; 61 62 ctrl = &vmcb->ctrl; 63 state = &vmcb->state; 64 65 ctrl->iopm_base_pa = iopm_base_pa; 66 ctrl->msrpm_base_pa = msrpm_base_pa; 67 68 /* Enable nested paging */ 69 ctrl->np_enable = 1; 70 ctrl->n_cr3 = np_pml4; 71 72 /* 73 * Intercept accesses to the control registers that are not shadowed 74 * in the VMCB - i.e. all except cr0, cr2, cr3, cr4 and cr8. 75 */ 76 cr_shadow = BIT(0) | BIT(2) | BIT(3) | BIT(4) | BIT(8); 77 ctrl->cr_write = ctrl->cr_read = ~cr_shadow; 78 79 /* Intercept Machine Check exceptions. */ 80 ctrl->exception = BIT(IDT_MC); 81 82 /* Intercept various events (for e.g. I/O, MSR and CPUID accesses) */ 83 ctrl->ctrl1 = VMCB_INTCPT_IO | 84 VMCB_INTCPT_MSR | 85 VMCB_INTCPT_HLT | 86 VMCB_INTCPT_CPUID | 87 VMCB_INTCPT_INTR | 88 VMCB_INTCPT_VINTR | 89 VMCB_INTCPT_INIT | 90 VMCB_INTCPT_NMI | 91 VMCB_INTCPT_SMI | 92 VMCB_INTCPT_FERR_FREEZE | 93 VMCB_INTCPT_SHUTDOWN; 94 95 /* 96 * From section "Canonicalization and Consistency Checks" in APMv2 97 * the VMRUN intercept bit must be set to pass the consistency check. 98 */ 99 ctrl->ctrl2 = VMCB_INTCPT_VMRUN; 100 101 /* 102 * The ASID will be set to a non-zero value just before VMRUN. 103 */ 104 ctrl->asid = 0; 105 106 /* 107 * Section 15.21.1, Interrupt Masking in EFLAGS 108 * Section 15.21.2, Virtualizing APIC.TPR 109 * 110 * This must be set for %rflag and %cr8 isolation of guest and host. 111 */ 112 ctrl->v_intr_masking = 1; 113 114 /* Enable Last Branch Record aka LBR for debugging */ 115 ctrl->lbr_virt_en = 1; 116 state->dbgctl = BIT(0); 117 118 /* EFER_SVM must always be set when the guest is executing */ 119 state->efer = EFER_SVM; 120 121 /* Set up the PAT to power-on state */ 122 state->g_pat = PAT_VALUE(0, PAT_WRITE_BACK) | 123 PAT_VALUE(1, PAT_WRITE_THROUGH) | 124 PAT_VALUE(2, PAT_UNCACHED) | 125 PAT_VALUE(3, PAT_UNCACHEABLE) | 126 PAT_VALUE(4, PAT_WRITE_BACK) | 127 PAT_VALUE(5, PAT_WRITE_THROUGH) | 128 PAT_VALUE(6, PAT_UNCACHED) | 129 PAT_VALUE(7, PAT_UNCACHEABLE); 130} 131 132/* 133 * Read from segment selector, control and general purpose register of VMCB. 134 */ 135int 136vmcb_read(struct vmcb *vmcb, int ident, uint64_t *retval) 137{ 138 struct vmcb_state *state; 139 struct vmcb_segment *seg; 140 int err; 141 142 state = &vmcb->state; 143 err = 0; 144 145 switch (ident) { 146 case VM_REG_GUEST_CR0: 147 *retval = state->cr0; 148 break; 149 150 case VM_REG_GUEST_CR2: 151 *retval = state->cr2; 152 break; 153 154 case VM_REG_GUEST_CR3: 155 *retval = state->cr3; 156 break; 157 158 case VM_REG_GUEST_CR4: 159 *retval = state->cr4; 160 break; 161 162 case VM_REG_GUEST_DR7: 163 *retval = state->dr7; 164 break; 165 166 case VM_REG_GUEST_EFER: 167 *retval = state->efer; 168 break; 169 170 case VM_REG_GUEST_RAX: 171 *retval = state->rax; 172 break; 173 174 case VM_REG_GUEST_RFLAGS: 175 *retval = state->rflags; 176 break; 177 178 case VM_REG_GUEST_RIP: 179 *retval = state->rip; 180 break; 181 182 case VM_REG_GUEST_RSP: 183 *retval = state->rsp; 184 break; 185 186 case VM_REG_GUEST_CS: 187 case VM_REG_GUEST_DS: 188 case VM_REG_GUEST_ES: 189 case VM_REG_GUEST_FS: 190 case VM_REG_GUEST_GS: 191 case VM_REG_GUEST_SS: 192 case VM_REG_GUEST_GDTR: 193 case VM_REG_GUEST_IDTR: 194 case VM_REG_GUEST_LDTR: 195 case VM_REG_GUEST_TR: 196 seg = vmcb_seg(vmcb, ident); 197 if (seg == NULL) { 198 ERR("Invalid seg type %d\n", ident); 199 err = EINVAL; 200 break; 201 } 202 203 *retval = seg->selector; 204 break; 205 206 default: 207 err = EINVAL; 208 break; 209 } 210 211 return (err); 212} 213 214/* 215 * Write to segment selector, control and general purpose register of VMCB. 216 */ 217int 218vmcb_write(struct vmcb *vmcb, int ident, uint64_t val) 219{ 220 struct vmcb_state *state; 221 struct vmcb_segment *seg; 222 int err; 223 224 state = &vmcb->state; 225 err = 0; 226 227 switch (ident) { 228 case VM_REG_GUEST_CR0: 229 state->cr0 = val; 230 break; 231 232 case VM_REG_GUEST_CR2: 233 state->cr2 = val; 234 break; 235 236 case VM_REG_GUEST_CR3: 237 state->cr3 = val; 238 break; 239 240 case VM_REG_GUEST_CR4: 241 state->cr4 = val; 242 break; 243 244 case VM_REG_GUEST_DR7: 245 state->dr7 = val; 246 break; 247 248 case VM_REG_GUEST_EFER: 249 /* EFER_SVM must always be set when the guest is executing */ 250 state->efer = val | EFER_SVM; 251 break; 252 253 case VM_REG_GUEST_RAX: 254 state->rax = val; 255 break; 256 257 case VM_REG_GUEST_RFLAGS: 258 state->rflags = val; 259 break; 260 261 case VM_REG_GUEST_RIP: 262 state->rip = val; 263 break; 264 265 case VM_REG_GUEST_RSP: 266 state->rsp = val; 267 break; 268 269 case VM_REG_GUEST_CS: 270 case VM_REG_GUEST_DS: 271 case VM_REG_GUEST_ES: 272 case VM_REG_GUEST_FS: 273 case VM_REG_GUEST_GS: 274 case VM_REG_GUEST_SS: 275 case VM_REG_GUEST_GDTR: 276 case VM_REG_GUEST_IDTR: 277 case VM_REG_GUEST_LDTR: 278 case VM_REG_GUEST_TR: 279 seg = vmcb_seg(vmcb, ident); 280 if (seg == NULL) { 281 ERR("Invalid segment type %d\n", ident); 282 err = EINVAL; 283 break; 284 } 285 286 seg->selector = val; 287 break; 288 289 default: 290 err = EINVAL; 291 } 292 293 return (err); 294} 295 296/* 297 * Return VMCB segment area. 298 */ 299struct vmcb_segment * 300vmcb_seg(struct vmcb *vmcb, int type) 301{ 302 struct vmcb_state *state; 303 struct vmcb_segment *seg; 304 305 state = &vmcb->state; 306 307 switch (type) { 308 case VM_REG_GUEST_CS: 309 seg = &state->cs; 310 break; 311 312 case VM_REG_GUEST_DS: 313 seg = &state->ds; 314 break; 315 316 case VM_REG_GUEST_ES: 317 seg = &state->es; 318 break; 319 320 case VM_REG_GUEST_FS: 321 seg = &state->fs; 322 break; 323 324 case VM_REG_GUEST_GS: 325 seg = &state->gs; 326 break; 327 328 case VM_REG_GUEST_SS: 329 seg = &state->ss; 330 break; 331 332 case VM_REG_GUEST_GDTR: 333 seg = &state->gdt; 334 break; 335 336 case VM_REG_GUEST_IDTR: 337 seg = &state->idt; 338 break; 339 340 case VM_REG_GUEST_LDTR: 341 seg = &state->ldt; 342 break; 343 344 case VM_REG_GUEST_TR: 345 seg = &state->tr; 346 break; 347 348 default: 349 seg = NULL; 350 break; 351 } 352 353 return (seg); 354} 355 356/* 357 * Inject an event to vcpu as described in section 15.20, "Event injection". 358 */ 359void 360vmcb_eventinject(struct vmcb_ctrl *ctrl, int intr_type, int vector, 361 uint32_t error, bool ec_valid) 362{ 363 KASSERT((ctrl->eventinj & VMCB_EVENTINJ_VALID) == 0, 364 ("%s: event already pending %#lx", __func__, ctrl->eventinj)); 365 366 KASSERT(vector >=0 && vector <= 255, ("%s: invalid vector %d", 367 __func__, vector)); 368 369 switch (intr_type) { 370 case VMCB_EVENTINJ_TYPE_INTR: 371 case VMCB_EVENTINJ_TYPE_NMI: 372 case VMCB_EVENTINJ_TYPE_INTn: 373 break; 374 case VMCB_EVENTINJ_TYPE_EXCEPTION: 375 if (vector >= 0 && vector <= 31 && vector != 2) 376 break; 377 /* FALLTHROUGH */ 378 default: 379 panic("%s: invalid intr_type/vector: %d/%d", __func__, 380 intr_type, vector); 381 } 382 ctrl->eventinj = vector | (intr_type << 8) | VMCB_EVENTINJ_VALID; 383 if (ec_valid) { 384 ctrl->eventinj |= VMCB_EVENTINJ_EC_VALID; 385 ctrl->eventinj |= (uint64_t)error << 32; 386 } 387} 388