vmcb.c revision 271346
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 271346 2014-09-10 02:35:19Z 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 * Read from segment selector, control and general purpose register of VMCB. 53 */ 54int 55vmcb_read(struct vmcb *vmcb, int ident, uint64_t *retval) 56{ 57 struct vmcb_state *state; 58 struct vmcb_segment *seg; 59 int err; 60 61 state = &vmcb->state; 62 err = 0; 63 64 switch (ident) { 65 case VM_REG_GUEST_CR0: 66 *retval = state->cr0; 67 break; 68 69 case VM_REG_GUEST_CR2: 70 *retval = state->cr2; 71 break; 72 73 case VM_REG_GUEST_CR3: 74 *retval = state->cr3; 75 break; 76 77 case VM_REG_GUEST_CR4: 78 *retval = state->cr4; 79 break; 80 81 case VM_REG_GUEST_DR7: 82 *retval = state->dr7; 83 break; 84 85 case VM_REG_GUEST_EFER: 86 *retval = state->efer; 87 break; 88 89 case VM_REG_GUEST_RAX: 90 *retval = state->rax; 91 break; 92 93 case VM_REG_GUEST_RFLAGS: 94 *retval = state->rflags; 95 break; 96 97 case VM_REG_GUEST_RIP: 98 *retval = state->rip; 99 break; 100 101 case VM_REG_GUEST_RSP: 102 *retval = state->rsp; 103 break; 104 105 case VM_REG_GUEST_CS: 106 case VM_REG_GUEST_DS: 107 case VM_REG_GUEST_ES: 108 case VM_REG_GUEST_FS: 109 case VM_REG_GUEST_GS: 110 case VM_REG_GUEST_SS: 111 case VM_REG_GUEST_GDTR: 112 case VM_REG_GUEST_IDTR: 113 case VM_REG_GUEST_LDTR: 114 case VM_REG_GUEST_TR: 115 seg = vmcb_seg(vmcb, ident); 116 if (seg == NULL) { 117 ERR("Invalid seg type %d\n", ident); 118 err = EINVAL; 119 break; 120 } 121 122 *retval = seg->selector; 123 break; 124 125 default: 126 err = EINVAL; 127 break; 128 } 129 130 return (err); 131} 132 133/* 134 * Write to segment selector, control and general purpose register of VMCB. 135 */ 136int 137vmcb_write(struct vmcb *vmcb, int ident, uint64_t val) 138{ 139 struct vmcb_state *state; 140 struct vmcb_segment *seg; 141 int err; 142 143 state = &vmcb->state; 144 err = 0; 145 146 switch (ident) { 147 case VM_REG_GUEST_CR0: 148 state->cr0 = val; 149 break; 150 151 case VM_REG_GUEST_CR2: 152 state->cr2 = val; 153 break; 154 155 case VM_REG_GUEST_CR3: 156 state->cr3 = val; 157 break; 158 159 case VM_REG_GUEST_CR4: 160 state->cr4 = val; 161 break; 162 163 case VM_REG_GUEST_DR7: 164 state->dr7 = val; 165 break; 166 167 case VM_REG_GUEST_EFER: 168 /* EFER_SVM must always be set when the guest is executing */ 169 state->efer = val | EFER_SVM; 170 break; 171 172 case VM_REG_GUEST_RAX: 173 state->rax = val; 174 break; 175 176 case VM_REG_GUEST_RFLAGS: 177 state->rflags = val; 178 break; 179 180 case VM_REG_GUEST_RIP: 181 state->rip = val; 182 break; 183 184 case VM_REG_GUEST_RSP: 185 state->rsp = val; 186 break; 187 188 case VM_REG_GUEST_CS: 189 case VM_REG_GUEST_DS: 190 case VM_REG_GUEST_ES: 191 case VM_REG_GUEST_FS: 192 case VM_REG_GUEST_GS: 193 case VM_REG_GUEST_SS: 194 case VM_REG_GUEST_GDTR: 195 case VM_REG_GUEST_IDTR: 196 case VM_REG_GUEST_LDTR: 197 case VM_REG_GUEST_TR: 198 seg = vmcb_seg(vmcb, ident); 199 if (seg == NULL) { 200 ERR("Invalid segment type %d\n", ident); 201 err = EINVAL; 202 break; 203 } 204 205 seg->selector = val; 206 break; 207 208 default: 209 err = EINVAL; 210 } 211 212 return (err); 213} 214 215/* 216 * Return VMCB segment area. 217 */ 218struct vmcb_segment * 219vmcb_seg(struct vmcb *vmcb, int type) 220{ 221 struct vmcb_state *state; 222 struct vmcb_segment *seg; 223 224 state = &vmcb->state; 225 226 switch (type) { 227 case VM_REG_GUEST_CS: 228 seg = &state->cs; 229 break; 230 231 case VM_REG_GUEST_DS: 232 seg = &state->ds; 233 break; 234 235 case VM_REG_GUEST_ES: 236 seg = &state->es; 237 break; 238 239 case VM_REG_GUEST_FS: 240 seg = &state->fs; 241 break; 242 243 case VM_REG_GUEST_GS: 244 seg = &state->gs; 245 break; 246 247 case VM_REG_GUEST_SS: 248 seg = &state->ss; 249 break; 250 251 case VM_REG_GUEST_GDTR: 252 seg = &state->gdt; 253 break; 254 255 case VM_REG_GUEST_IDTR: 256 seg = &state->idt; 257 break; 258 259 case VM_REG_GUEST_LDTR: 260 seg = &state->ldt; 261 break; 262 263 case VM_REG_GUEST_TR: 264 seg = &state->tr; 265 break; 266 267 default: 268 seg = NULL; 269 break; 270 } 271 272 return (seg); 273} 274