svm_helper.c (32846B)
1/* 2 * x86 SVM helpers (sysemu only) 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20#include "qemu/osdep.h" 21#include "cpu.h" 22#include "exec/helper-proto.h" 23#include "exec/exec-all.h" 24#include "exec/cpu_ldst.h" 25#include "tcg/helper-tcg.h" 26 27/* Secure Virtual Machine helpers */ 28 29static inline void svm_save_seg(CPUX86State *env, hwaddr addr, 30 const SegmentCache *sc) 31{ 32 CPUState *cs = env_cpu(env); 33 34 x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector), 35 sc->selector); 36 x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base), 37 sc->base); 38 x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit), 39 sc->limit); 40 x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib), 41 ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); 42} 43 44/* 45 * VMRUN and VMLOAD canonicalizes (i.e., sign-extend to bit 63) all base 46 * addresses in the segment registers that have been loaded. 47 */ 48static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base) 49{ 50 uint16_t shift_amt = 64 - cpu_x86_virtual_addr_width(env); 51 *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt); 52} 53 54static inline void svm_load_seg(CPUX86State *env, hwaddr addr, 55 SegmentCache *sc) 56{ 57 CPUState *cs = env_cpu(env); 58 unsigned int flags; 59 60 sc->selector = x86_lduw_phys(cs, 61 addr + offsetof(struct vmcb_seg, selector)); 62 sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base)); 63 sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit)); 64 flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib)); 65 sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); 66 svm_canonicalization(env, &sc->base); 67} 68 69static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, 70 int seg_reg) 71{ 72 SegmentCache sc1, *sc = &sc1; 73 74 svm_load_seg(env, addr, sc); 75 cpu_x86_load_seg_cache(env, seg_reg, sc->selector, 76 sc->base, sc->limit, sc->flags); 77} 78 79static inline bool is_efer_invalid_state (CPUX86State *env) 80{ 81 if (!(env->efer & MSR_EFER_SVME)) { 82 return true; 83 } 84 85 if (env->efer & MSR_EFER_RESERVED) { 86 return true; 87 } 88 89 if ((env->efer & (MSR_EFER_LMA | MSR_EFER_LME)) && 90 !(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) { 91 return true; 92 } 93 94 if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK) 95 && !(env->cr[4] & CR4_PAE_MASK)) { 96 return true; 97 } 98 99 if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK) 100 && !(env->cr[0] & CR0_PE_MASK)) { 101 return true; 102 } 103 104 if ((env->efer & MSR_EFER_LME) && (env->cr[0] & CR0_PG_MASK) 105 && (env->cr[4] & CR4_PAE_MASK) 106 && (env->segs[R_CS].flags & DESC_L_MASK) 107 && (env->segs[R_CS].flags & DESC_B_MASK)) { 108 return true; 109 } 110 111 return false; 112} 113 114static inline bool virtual_gif_enabled(CPUX86State *env) 115{ 116 if (likely(env->hflags & HF_GUEST_MASK)) { 117 return (env->features[FEAT_SVM] & CPUID_SVM_VGIF) 118 && (env->int_ctl & V_GIF_ENABLED_MASK); 119 } 120 return false; 121} 122 123static inline bool virtual_vm_load_save_enabled(CPUX86State *env, uint32_t exit_code, uintptr_t retaddr) 124{ 125 uint64_t lbr_ctl; 126 127 if (likely(env->hflags & HF_GUEST_MASK)) { 128 if (likely(!(env->hflags2 & HF2_NPT_MASK)) || !(env->efer & MSR_EFER_LMA)) { 129 cpu_vmexit(env, exit_code, 0, retaddr); 130 } 131 132 lbr_ctl = x86_ldl_phys(env_cpu(env), env->vm_vmcb + offsetof(struct vmcb, 133 control.lbr_ctl)); 134 return (env->features[FEAT_SVM] & CPUID_SVM_V_VMSAVE_VMLOAD) 135 && (lbr_ctl & V_VMLOAD_VMSAVE_ENABLED_MASK); 136 137 } 138 139 return false; 140} 141 142static inline bool virtual_gif_set(CPUX86State *env) 143{ 144 return !virtual_gif_enabled(env) || (env->int_ctl & V_GIF_MASK); 145} 146 147void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) 148{ 149 CPUState *cs = env_cpu(env); 150 X86CPU *cpu = env_archcpu(env); 151 target_ulong addr; 152 uint64_t nested_ctl; 153 uint32_t event_inj; 154 uint32_t asid; 155 uint64_t new_cr0; 156 uint64_t new_cr3; 157 uint64_t new_cr4; 158 159 cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC()); 160 161 if (aflag == 2) { 162 addr = env->regs[R_EAX]; 163 } else { 164 addr = (uint32_t)env->regs[R_EAX]; 165 } 166 167 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr); 168 169 env->vm_vmcb = addr; 170 171 /* save the current CPU state in the hsave page */ 172 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), 173 env->gdt.base); 174 x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), 175 env->gdt.limit); 176 177 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.base), 178 env->idt.base); 179 x86_stl_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), 180 env->idt.limit); 181 182 x86_stq_phys(cs, 183 env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]); 184 x86_stq_phys(cs, 185 env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]); 186 x86_stq_phys(cs, 187 env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]); 188 x86_stq_phys(cs, 189 env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]); 190 x86_stq_phys(cs, 191 env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]); 192 x86_stq_phys(cs, 193 env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]); 194 195 x86_stq_phys(cs, 196 env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer); 197 x86_stq_phys(cs, 198 env->vm_hsave + offsetof(struct vmcb, save.rflags), 199 cpu_compute_eflags(env)); 200 201 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es), 202 &env->segs[R_ES]); 203 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs), 204 &env->segs[R_CS]); 205 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss), 206 &env->segs[R_SS]); 207 svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds), 208 &env->segs[R_DS]); 209 210 x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip), 211 env->eip + next_eip_addend); 212 x86_stq_phys(cs, 213 env->vm_hsave + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]); 214 x86_stq_phys(cs, 215 env->vm_hsave + offsetof(struct vmcb, save.rax), env->regs[R_EAX]); 216 217 /* load the interception bitmaps so we do not need to access the 218 vmcb in svm mode */ 219 env->intercept = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 220 control.intercept)); 221 env->intercept_cr_read = x86_lduw_phys(cs, env->vm_vmcb + 222 offsetof(struct vmcb, 223 control.intercept_cr_read)); 224 env->intercept_cr_write = x86_lduw_phys(cs, env->vm_vmcb + 225 offsetof(struct vmcb, 226 control.intercept_cr_write)); 227 env->intercept_dr_read = x86_lduw_phys(cs, env->vm_vmcb + 228 offsetof(struct vmcb, 229 control.intercept_dr_read)); 230 env->intercept_dr_write = x86_lduw_phys(cs, env->vm_vmcb + 231 offsetof(struct vmcb, 232 control.intercept_dr_write)); 233 env->intercept_exceptions = x86_ldl_phys(cs, env->vm_vmcb + 234 offsetof(struct vmcb, 235 control.intercept_exceptions 236 )); 237 238 nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 239 control.nested_ctl)); 240 asid = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 241 control.asid)); 242 243 uint64_t msrpm_base_pa = x86_ldq_phys(cs, env->vm_vmcb + 244 offsetof(struct vmcb, 245 control.msrpm_base_pa)); 246 uint64_t iopm_base_pa = x86_ldq_phys(cs, env->vm_vmcb + 247 offsetof(struct vmcb, control.iopm_base_pa)); 248 249 if ((msrpm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_MSRPM_SIZE) { 250 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 251 } 252 253 if ((iopm_base_pa & ~0xfff) >= (1ull << cpu->phys_bits) - SVM_IOPM_SIZE) { 254 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 255 } 256 257 env->nested_pg_mode = 0; 258 259 if (!cpu_svm_has_intercept(env, SVM_EXIT_VMRUN)) { 260 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 261 } 262 if (asid == 0) { 263 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 264 } 265 266 if (nested_ctl & SVM_NPT_ENABLED) { 267 env->nested_cr3 = x86_ldq_phys(cs, 268 env->vm_vmcb + offsetof(struct vmcb, 269 control.nested_cr3)); 270 env->hflags2 |= HF2_NPT_MASK; 271 272 env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK; 273 } 274 275 /* enable intercepts */ 276 env->hflags |= HF_GUEST_MASK; 277 278 env->tsc_offset = x86_ldq_phys(cs, env->vm_vmcb + 279 offsetof(struct vmcb, control.tsc_offset)); 280 281 new_cr0 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr0)); 282 if (new_cr0 & SVM_CR0_RESERVED_MASK) { 283 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 284 } 285 if ((new_cr0 & CR0_NW_MASK) && !(new_cr0 & CR0_CD_MASK)) { 286 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 287 } 288 new_cr3 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr3)); 289 if ((env->efer & MSR_EFER_LMA) && 290 (new_cr3 & ((~0ULL) << cpu->phys_bits))) { 291 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 292 } 293 new_cr4 = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cr4)); 294 if (new_cr4 & cr4_reserved_bits(env)) { 295 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 296 } 297 /* clear exit_info_2 so we behave like the real hardware */ 298 x86_stq_phys(cs, 299 env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0); 300 301 cpu_x86_update_cr0(env, new_cr0); 302 cpu_x86_update_cr4(env, new_cr4); 303 cpu_x86_update_cr3(env, new_cr3); 304 env->cr[2] = x86_ldq_phys(cs, 305 env->vm_vmcb + offsetof(struct vmcb, save.cr2)); 306 env->int_ctl = x86_ldl_phys(cs, 307 env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)); 308 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); 309 if (env->int_ctl & V_INTR_MASKING_MASK) { 310 env->hflags2 |= HF2_VINTR_MASK; 311 if (env->eflags & IF_MASK) { 312 env->hflags2 |= HF2_HIF_MASK; 313 } 314 } 315 316 cpu_load_efer(env, 317 x86_ldq_phys(cs, 318 env->vm_vmcb + offsetof(struct vmcb, save.efer))); 319 env->eflags = 0; 320 cpu_load_eflags(env, x86_ldq_phys(cs, 321 env->vm_vmcb + offsetof(struct vmcb, 322 save.rflags)), 323 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); 324 325 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es), 326 R_ES); 327 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs), 328 R_CS); 329 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss), 330 R_SS); 331 svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), 332 R_DS); 333 svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.idtr), 334 &env->idt); 335 svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.gdtr), 336 &env->gdt); 337 338 env->eip = x86_ldq_phys(cs, 339 env->vm_vmcb + offsetof(struct vmcb, save.rip)); 340 341 env->regs[R_ESP] = x86_ldq_phys(cs, 342 env->vm_vmcb + offsetof(struct vmcb, save.rsp)); 343 env->regs[R_EAX] = x86_ldq_phys(cs, 344 env->vm_vmcb + offsetof(struct vmcb, save.rax)); 345 env->dr[7] = x86_ldq_phys(cs, 346 env->vm_vmcb + offsetof(struct vmcb, save.dr7)); 347 env->dr[6] = x86_ldq_phys(cs, 348 env->vm_vmcb + offsetof(struct vmcb, save.dr6)); 349 350#ifdef TARGET_X86_64 351 if (env->dr[6] & DR_RESERVED_MASK) { 352 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 353 } 354 if (env->dr[7] & DR_RESERVED_MASK) { 355 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 356 } 357#endif 358 359 if (is_efer_invalid_state(env)) { 360 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 361 } 362 363 switch (x86_ldub_phys(cs, 364 env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) { 365 case TLB_CONTROL_DO_NOTHING: 366 break; 367 case TLB_CONTROL_FLUSH_ALL_ASID: 368 /* FIXME: this is not 100% correct but should work for now */ 369 tlb_flush(cs); 370 break; 371 } 372 373 env->hflags2 |= HF2_GIF_MASK; 374 375 if (ctl_has_irq(env)) { 376 CPUState *cs = env_cpu(env); 377 378 cs->interrupt_request |= CPU_INTERRUPT_VIRQ; 379 } 380 381 if (virtual_gif_set(env)) { 382 env->hflags2 |= HF2_VGIF_MASK; 383 } 384 385 /* maybe we need to inject an event */ 386 event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 387 control.event_inj)); 388 if (event_inj & SVM_EVTINJ_VALID) { 389 uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK; 390 uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR; 391 uint32_t event_inj_err = x86_ldl_phys(cs, env->vm_vmcb + 392 offsetof(struct vmcb, 393 control.event_inj_err)); 394 395 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err); 396 /* FIXME: need to implement valid_err */ 397 switch (event_inj & SVM_EVTINJ_TYPE_MASK) { 398 case SVM_EVTINJ_TYPE_INTR: 399 cs->exception_index = vector; 400 env->error_code = event_inj_err; 401 env->exception_is_int = 0; 402 env->exception_next_eip = -1; 403 qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR"); 404 /* XXX: is it always correct? */ 405 do_interrupt_x86_hardirq(env, vector, 1); 406 break; 407 case SVM_EVTINJ_TYPE_NMI: 408 cs->exception_index = EXCP02_NMI; 409 env->error_code = event_inj_err; 410 env->exception_is_int = 0; 411 env->exception_next_eip = env->eip; 412 qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI"); 413 cpu_loop_exit(cs); 414 break; 415 case SVM_EVTINJ_TYPE_EXEPT: 416 if (vector == EXCP02_NMI || vector >= 31) { 417 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 418 } 419 cs->exception_index = vector; 420 env->error_code = event_inj_err; 421 env->exception_is_int = 0; 422 env->exception_next_eip = -1; 423 qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT"); 424 cpu_loop_exit(cs); 425 break; 426 case SVM_EVTINJ_TYPE_SOFT: 427 cs->exception_index = vector; 428 env->error_code = event_inj_err; 429 env->exception_is_int = 1; 430 env->exception_next_eip = env->eip; 431 qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT"); 432 cpu_loop_exit(cs); 433 break; 434 default: 435 cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); 436 break; 437 } 438 qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", cs->exception_index, 439 env->error_code); 440 } 441} 442 443void helper_vmmcall(CPUX86State *env) 444{ 445 cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0, GETPC()); 446 raise_exception(env, EXCP06_ILLOP); 447} 448 449void helper_vmload(CPUX86State *env, int aflag) 450{ 451 CPUState *cs = env_cpu(env); 452 target_ulong addr; 453 int prot; 454 455 cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); 456 457 if (aflag == 2) { 458 addr = env->regs[R_EAX]; 459 } else { 460 addr = (uint32_t)env->regs[R_EAX]; 461 } 462 463 if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) { 464 addr = get_hphys(cs, addr, MMU_DATA_LOAD, &prot); 465 } 466 467 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx 468 "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", 469 addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb, 470 save.fs.base)), 471 env->segs[R_FS].base); 472 473 svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS); 474 svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS); 475 svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr); 476 svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt); 477 478#ifdef TARGET_X86_64 479 env->kernelgsbase = x86_ldq_phys(cs, addr + offsetof(struct vmcb, 480 save.kernel_gs_base)); 481 env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar)); 482 env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar)); 483 env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask)); 484 svm_canonicalization(env, &env->kernelgsbase); 485#endif 486 env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star)); 487 env->sysenter_cs = x86_ldq_phys(cs, 488 addr + offsetof(struct vmcb, save.sysenter_cs)); 489 env->sysenter_esp = x86_ldq_phys(cs, addr + offsetof(struct vmcb, 490 save.sysenter_esp)); 491 env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb, 492 save.sysenter_eip)); 493 494} 495 496void helper_vmsave(CPUX86State *env, int aflag) 497{ 498 CPUState *cs = env_cpu(env); 499 target_ulong addr; 500 int prot; 501 502 cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); 503 504 if (aflag == 2) { 505 addr = env->regs[R_EAX]; 506 } else { 507 addr = (uint32_t)env->regs[R_EAX]; 508 } 509 510 if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) { 511 addr = get_hphys(cs, addr, MMU_DATA_STORE, &prot); 512 } 513 514 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx 515 "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", 516 addr, x86_ldq_phys(cs, 517 addr + offsetof(struct vmcb, save.fs.base)), 518 env->segs[R_FS].base); 519 520 svm_save_seg(env, addr + offsetof(struct vmcb, save.fs), 521 &env->segs[R_FS]); 522 svm_save_seg(env, addr + offsetof(struct vmcb, save.gs), 523 &env->segs[R_GS]); 524 svm_save_seg(env, addr + offsetof(struct vmcb, save.tr), 525 &env->tr); 526 svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr), 527 &env->ldt); 528 529#ifdef TARGET_X86_64 530 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.kernel_gs_base), 531 env->kernelgsbase); 532 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.lstar), env->lstar); 533 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.cstar), env->cstar); 534 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sfmask), env->fmask); 535#endif 536 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.star), env->star); 537 x86_stq_phys(cs, 538 addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); 539 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_esp), 540 env->sysenter_esp); 541 x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip), 542 env->sysenter_eip); 543} 544 545void helper_stgi(CPUX86State *env) 546{ 547 cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC()); 548 549 if (virtual_gif_enabled(env)) { 550 env->int_ctl |= V_GIF_MASK; 551 env->hflags2 |= HF2_VGIF_MASK; 552 } else { 553 env->hflags2 |= HF2_GIF_MASK; 554 } 555} 556 557void helper_clgi(CPUX86State *env) 558{ 559 cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC()); 560 561 if (virtual_gif_enabled(env)) { 562 env->int_ctl &= ~V_GIF_MASK; 563 env->hflags2 &= ~HF2_VGIF_MASK; 564 } else { 565 env->hflags2 &= ~HF2_GIF_MASK; 566 } 567} 568 569bool cpu_svm_has_intercept(CPUX86State *env, uint32_t type) 570{ 571 switch (type) { 572 case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: 573 if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) { 574 return true; 575 } 576 break; 577 case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: 578 if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) { 579 return true; 580 } 581 break; 582 case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7: 583 if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) { 584 return true; 585 } 586 break; 587 case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7: 588 if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) { 589 return true; 590 } 591 break; 592 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31: 593 if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) { 594 return true; 595 } 596 break; 597 default: 598 if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) { 599 return true; 600 } 601 break; 602 } 603 return false; 604} 605 606void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, 607 uint64_t param, uintptr_t retaddr) 608{ 609 CPUState *cs = env_cpu(env); 610 611 if (likely(!(env->hflags & HF_GUEST_MASK))) { 612 return; 613 } 614 615 if (!cpu_svm_has_intercept(env, type)) { 616 return; 617 } 618 619 if (type == SVM_EXIT_MSR) { 620 /* FIXME: this should be read in at vmrun (faster this way?) */ 621 uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb + 622 offsetof(struct vmcb, 623 control.msrpm_base_pa)); 624 uint32_t t0, t1; 625 626 switch ((uint32_t)env->regs[R_ECX]) { 627 case 0 ... 0x1fff: 628 t0 = (env->regs[R_ECX] * 2) % 8; 629 t1 = (env->regs[R_ECX] * 2) / 8; 630 break; 631 case 0xc0000000 ... 0xc0001fff: 632 t0 = (8192 + env->regs[R_ECX] - 0xc0000000) * 2; 633 t1 = (t0 / 8); 634 t0 %= 8; 635 break; 636 case 0xc0010000 ... 0xc0011fff: 637 t0 = (16384 + env->regs[R_ECX] - 0xc0010000) * 2; 638 t1 = (t0 / 8); 639 t0 %= 8; 640 break; 641 default: 642 cpu_vmexit(env, type, param, retaddr); 643 t0 = 0; 644 t1 = 0; 645 break; 646 } 647 if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) { 648 cpu_vmexit(env, type, param, retaddr); 649 } 650 return; 651 } 652 653 cpu_vmexit(env, type, param, retaddr); 654} 655 656void helper_svm_check_intercept(CPUX86State *env, uint32_t type) 657{ 658 cpu_svm_check_intercept_param(env, type, 0, GETPC()); 659} 660 661void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, 662 uint32_t next_eip_addend) 663{ 664 CPUState *cs = env_cpu(env); 665 666 if (env->intercept & (1ULL << (SVM_EXIT_IOIO - SVM_EXIT_INTR))) { 667 /* FIXME: this should be read in at vmrun (faster this way?) */ 668 uint64_t addr = x86_ldq_phys(cs, env->vm_vmcb + 669 offsetof(struct vmcb, control.iopm_base_pa)); 670 uint16_t mask = (1 << ((param >> 4) & 7)) - 1; 671 672 if (x86_lduw_phys(cs, addr + port / 8) & (mask << (port & 7))) { 673 /* next env->eip */ 674 x86_stq_phys(cs, 675 env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 676 env->eip + next_eip_addend); 677 cpu_vmexit(env, SVM_EXIT_IOIO, param | (port << 16), GETPC()); 678 } 679 } 680} 681 682void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1, 683 uintptr_t retaddr) 684{ 685 CPUState *cs = env_cpu(env); 686 687 cpu_restore_state(cs, retaddr, true); 688 689 qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" 690 PRIx64 ", " TARGET_FMT_lx ")!\n", 691 exit_code, exit_info_1, 692 x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 693 control.exit_info_2)), 694 env->eip); 695 696 cs->exception_index = EXCP_VMEXIT; 697 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_code), 698 exit_code); 699 700 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 701 control.exit_info_1), exit_info_1), 702 703 /* remove any pending exception */ 704 env->old_exception = -1; 705 cpu_loop_exit(cs); 706} 707 708void do_vmexit(CPUX86State *env) 709{ 710 CPUState *cs = env_cpu(env); 711 712 if (env->hflags & HF_INHIBIT_IRQ_MASK) { 713 x86_stl_phys(cs, 714 env->vm_vmcb + offsetof(struct vmcb, control.int_state), 715 SVM_INTERRUPT_SHADOW_MASK); 716 env->hflags &= ~HF_INHIBIT_IRQ_MASK; 717 } else { 718 x86_stl_phys(cs, 719 env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); 720 } 721 env->hflags2 &= ~HF2_NPT_MASK; 722 723 /* Save the VM state in the vmcb */ 724 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es), 725 &env->segs[R_ES]); 726 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs), 727 &env->segs[R_CS]); 728 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss), 729 &env->segs[R_SS]); 730 svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), 731 &env->segs[R_DS]); 732 733 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), 734 env->gdt.base); 735 x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), 736 env->gdt.limit); 737 738 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), 739 env->idt.base); 740 x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), 741 env->idt.limit); 742 743 x86_stq_phys(cs, 744 env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer); 745 x86_stq_phys(cs, 746 env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]); 747 x86_stq_phys(cs, 748 env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]); 749 x86_stq_phys(cs, 750 env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]); 751 x86_stq_phys(cs, 752 env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]); 753 x86_stl_phys(cs, 754 env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), env->int_ctl); 755 756 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rflags), 757 cpu_compute_eflags(env)); 758 x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.rip), 759 env->eip); 760 x86_stq_phys(cs, 761 env->vm_vmcb + offsetof(struct vmcb, save.rsp), env->regs[R_ESP]); 762 x86_stq_phys(cs, 763 env->vm_vmcb + offsetof(struct vmcb, save.rax), env->regs[R_EAX]); 764 x86_stq_phys(cs, 765 env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]); 766 x86_stq_phys(cs, 767 env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]); 768 x86_stb_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.cpl), 769 env->hflags & HF_CPL_MASK); 770 771 /* Reload the host state from vm_hsave */ 772 env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK); 773 env->hflags &= ~HF_GUEST_MASK; 774 env->intercept = 0; 775 env->intercept_exceptions = 0; 776 cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ; 777 env->int_ctl = 0; 778 env->tsc_offset = 0; 779 780 env->gdt.base = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, 781 save.gdtr.base)); 782 env->gdt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb, 783 save.gdtr.limit)); 784 785 env->idt.base = x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, 786 save.idtr.base)); 787 env->idt.limit = x86_ldl_phys(cs, env->vm_hsave + offsetof(struct vmcb, 788 save.idtr.limit)); 789 790 cpu_x86_update_cr0(env, x86_ldq_phys(cs, 791 env->vm_hsave + offsetof(struct vmcb, 792 save.cr0)) | 793 CR0_PE_MASK); 794 cpu_x86_update_cr4(env, x86_ldq_phys(cs, 795 env->vm_hsave + offsetof(struct vmcb, 796 save.cr4))); 797 cpu_x86_update_cr3(env, x86_ldq_phys(cs, 798 env->vm_hsave + offsetof(struct vmcb, 799 save.cr3))); 800 /* we need to set the efer after the crs so the hidden flags get 801 set properly */ 802 cpu_load_efer(env, x86_ldq_phys(cs, env->vm_hsave + offsetof(struct vmcb, 803 save.efer))); 804 env->eflags = 0; 805 cpu_load_eflags(env, x86_ldq_phys(cs, 806 env->vm_hsave + offsetof(struct vmcb, 807 save.rflags)), 808 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK | 809 VM_MASK)); 810 811 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es), 812 R_ES); 813 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs), 814 R_CS); 815 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss), 816 R_SS); 817 svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds), 818 R_DS); 819 820 env->eip = x86_ldq_phys(cs, 821 env->vm_hsave + offsetof(struct vmcb, save.rip)); 822 env->regs[R_ESP] = x86_ldq_phys(cs, env->vm_hsave + 823 offsetof(struct vmcb, save.rsp)); 824 env->regs[R_EAX] = x86_ldq_phys(cs, env->vm_hsave + 825 offsetof(struct vmcb, save.rax)); 826 827 env->dr[6] = x86_ldq_phys(cs, 828 env->vm_hsave + offsetof(struct vmcb, save.dr6)); 829 env->dr[7] = x86_ldq_phys(cs, 830 env->vm_hsave + offsetof(struct vmcb, save.dr7)); 831 832 /* other setups */ 833 x86_stl_phys(cs, 834 env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info), 835 x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 836 control.event_inj))); 837 x86_stl_phys(cs, 838 env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err), 839 x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 840 control.event_inj_err))); 841 x86_stl_phys(cs, 842 env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0); 843 844 env->hflags2 &= ~HF2_GIF_MASK; 845 env->hflags2 &= ~HF2_VGIF_MASK; 846 /* FIXME: Resets the current ASID register to zero (host ASID). */ 847 848 /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */ 849 850 /* Clears the TSC_OFFSET inside the processor. */ 851 852 /* If the host is in PAE mode, the processor reloads the host's PDPEs 853 from the page table indicated the host's CR3. If the PDPEs contain 854 illegal state, the processor causes a shutdown. */ 855 856 /* Disables all breakpoints in the host DR7 register. */ 857 858 /* Checks the reloaded host state for consistency. */ 859 860 /* If the host's rIP reloaded by #VMEXIT is outside the limit of the 861 host's code segment or non-canonical (in the case of long mode), a 862 #GP fault is delivered inside the host. */ 863}