int __vmx_vmexit_inject_exception(uint32_t vector, uint32_t error, uint64_t cr2) { __vmx_prepare_event_injection(vm_entry_ctrls.int_info, VMCS_EVT_INFO_TYPE_HW_EXCP, vector); switch(vector) { case PF_EXCP: vm_state.cr2.raw = cr2; vmcs_dirty(vm_state.cr2); case DF_EXCP: case TS_EXCP: case NP_EXCP: case SS_EXCP: case GP_EXCP: case AC_EXCP: vm_entry_ctrls.int_info.dec = 1; vm_entry_ctrls.err_code.raw = error; vmcs_dirty(vm_entry_ctrls.err_code); break; default: break; } debug(VMX_EXCP, "inject exception #%d err 0x%x\n", vector, error); return 1; }
static int __vmx_vmexit_lgdt(dt_reg_t *dt_reg) { if(vmx_cpl) return VM_FAIL; debug(VMX_DT, "lgdt 0x%X:0x%x\n", dt_reg->base.raw, dt_reg->limit); vm_state.gdtr.base.raw = dt_reg->base.raw; vm_state.gdtr.limit.wlow = dt_reg->limit; vmcs_dirty(vm_state.gdtr.base); vmcs_dirty(vm_state.gdtr.limit); return VM_DONE; }
/* ** Hardware exec traps are checked before ** insn execution. But hardware data, i/o ** and single-step traps are checked after. ** ** If we emulated an insn, we may loose ** a #DB condition, so take care here. ** ** We do not inject #DB, we use pending db */ static int vmx_db_check_pending_any() { if(!__vmexit_on_insn()) { #ifdef CONFIG_VMX_DB_DBG if(vm_state.rflags.tf) { vmcs_read(vm_state.activity); vmcs_read(vm_state.interrupt); debug(VMX_DB, "TF is set, pending #DB: be:%d bs:%d sti:%d mss:%d activity:0x%x\n" ,vm_state.dbg_excp.be, vm_state.dbg_excp.bs ,vm_state.interrupt.sti, vm_state.interrupt.mss ,vm_state.activity.raw); } #endif return VM_IGNORE; } if(vmx_db_check_pending_stp() == VM_DONE) { debug(VMX_DB, "pending #DB: set stp\n"); vm_state.dbg_excp.bs = 1; vmcs_dirty(vm_state.dbg_excp); } /* XXX: missing data/io */ return VM_DONE; }
void __vmx_clear_event_injection() { if(!vm_entry_ctrls.int_info.v) return; if(vm_entry_ctrls.int_info.type == VMCS_EVT_INFO_TYPE_HW_EXCP && vm_entry_ctrls.int_info.vector == PF_EXCP) vmcs_clear(vm_state.cr2); vm_entry_ctrls.int_info.v = 0; vmcs_dirty(vm_entry_ctrls.int_info); }
static int __vmx_vmexit_lidt(dt_reg_t *dt_reg) { if(vmx_cpl) return VM_FAIL; debug(VMX_DT, "lidt 0x%X:0x%x\n", dt_reg->base.raw, dt_reg->limit); if(info->vm.idt_limit != dt_reg->limit) info->vm.idt_limit = dt_reg->limit; vm_state.idtr.base.raw = dt_reg->base.raw; vmcs_dirty(vm_state.idtr.base); return VM_DONE; }
/* ** Hardware exec traps are checked before ** insn execution. But hardware data, i/o ** and single-step traps are checked after. ** ** If we emulated an insn, we may loose ** a #DB condition, so take care here. ** ** We do not inject #DB, we use pending db */ static int vmx_db_check_pending_any() { if(!__vmexit_on_insn()) return VM_IGNORE; /* XXX: missing data/io */ if(vmx_db_check_pending_stp() == VM_DONE) { vm_state.dbg_excp.bs = 1; vmcs_dirty(vm_state.dbg_excp); } return VM_DONE; }
void vmx_vmcs_dirty_entry() { vmcs_dirty(vm_entry_ctrls.msr_load_addr); vmcs_dirty(vm_entry_ctrls.entry); vmcs_dirty(vm_entry_ctrls.msr_load_count); vmcs_dirty(vm_entry_ctrls.int_info); vmcs_dirty(vm_entry_ctrls.err_code); vmcs_dirty(vm_entry_ctrls.insn_len); }
static int __vmx_vmexit_resolve_msr_sysenter_cs(uint8_t wr) { if(wr) { vm_state.ia32_sysenter_cs.raw = info->vm.cpu.gpr->rax.low; vmcs_dirty(vm_state.ia32_sysenter_cs); } else { vmcs_read(vm_state.ia32_sysenter_cs); info->vm.cpu.gpr->rax.low = vm_state.ia32_sysenter_cs.raw; } return VM_DONE; }
static int __vmx_vmexit_resolve_msr_perf(uint8_t wr) { if(wr) { vm_state.ia32_perf.low = info->vm.cpu.gpr->rax.low; vm_state.ia32_perf.high = info->vm.cpu.gpr->rdx.low; vmcs_dirty(vm_state.ia32_perf); } else { vmcs_read(vm_state.ia32_perf); info->vm.cpu.gpr->rax.low = vm_state.ia32_perf.low; info->vm.cpu.gpr->rdx.low = vm_state.ia32_perf.high; } return VM_DONE; }
static int __vmx_vmexit_resolve_msr_dbgctl(uint8_t wr) { if(wr) { vm_state.ia32_dbgctl.low = info->vm.cpu.gpr->rax.low; vm_state.ia32_dbgctl.high = info->vm.cpu.gpr->rdx.low; /* check in vmx_check_dbgctl() */ vmcs_dirty(vm_state.ia32_dbgctl); } else { vmcs_read(vm_state.ia32_dbgctl); info->vm.cpu.gpr->rax.low = vm_state.ia32_dbgctl.low; info->vm.cpu.gpr->rdx.low = vm_state.ia32_dbgctl.high; } return VM_DONE; }
static void vmx_vmexit_post_hdl(raw64_t tsc) { vmx_db_check_pending(); if(controller() & (VM_FAIL|VM_FAULT)) vmx_vmexit_failure(); vmx_check_dbgctl(); vm_state.rsp.raw = info->vm.cpu.gpr->rsp.raw; vmcs_dirty(vm_state.rsp); info->vm.cpu.emu_sts = EMU_STS_AVL; info->vmm.ctrl.vmexit_cnt.raw++; vmx_vmexit_tsc_rebase(tsc); vmx_vmcs_commit(info); }
/* ** Vol. 3C-32.2 (Virtualization of System Resources) */ void vmx_check_dbgctl() { vmcs_read(vm_state.activity); vmcs_read(vm_state.interrupt); #ifdef CONFIG_VMX_DB_DBG vmcs_read(vm_state.dbg_excp); if(vm_state.dbg_excp.be || vm_state.dbg_excp.bs) debug(VMX_DB, "pending #DB: be:%d bs:%d 0x%X\n" ,vm_state.dbg_excp.be, vm_state.dbg_excp.bs ,vm_state.dbg_excp.raw); #endif if(!vm_state.interrupt.sti && !vm_state.interrupt.mss && vm_state.activity.raw != VMX_VMCS_GUEST_ACTIVITY_STATE_HALT) return; #ifdef CONFIG_VMX_DB_DBG debug(VMX_DB, "pending #DB: sti:%d mss:%d activity:0x%x\n" ,vm_state.interrupt.sti, vm_state.interrupt.mss ,vm_state.activity.raw); #endif vmcs_read(vm_state.ia32_dbgctl); vmcs_read(vm_state.dbg_excp); if(vm_state.rflags.tf && !vm_state.ia32_dbgctl.btf) { debug(VMX_DB, "pending #DB (sti/mss/hlt): set sstep\n"); vm_state.dbg_excp.bs = 1; } else if(vm_state.dbg_excp.bs) { debug(VMX_DB, "pending #DB (sti/mss/hlt): clr sstep\n"); vm_state.dbg_excp.bs = 0; } vmcs_dirty(vm_state.dbg_excp); }
/* ** Vol. 3C-32.2 (Virtualization of System Resources) */ void vmx_check_dbgctl() { vmcs_read(vm_state.activity); vmcs_read(vm_state.interrupt); if(!vm_state.interrupt.sti && !vm_state.interrupt.mss && vm_state.activity.raw != VMX_VMCS_GUEST_ACTIVITY_STATE_HALT) return; vmcs_read(vm_state.ia32_dbgctl); vmcs_read(vm_state.dbg_excp); if(vm_state.rflags.tf && !vm_state.ia32_dbgctl.btf) { debug(VMX_DB, "setting pending #DB for sstep\n"); vm_state.dbg_excp.bs = 1; } if(!vm_state.rflags.tf || vm_state.ia32_dbgctl.btf) vm_state.dbg_excp.bs = 0; vmcs_dirty(vm_state.dbg_excp); }
int vmx_vmexit_idt_deliver() { vmcs_read(vm_exit_info.idt_info); if(!vm_exit_info.idt_info.v) { vmcs_read(vm_exit_info.int_info); if(vm_exit_info.int_info.nmi && vm_exit_info.int_info.vector != DF_EXCP) { vmcs_read(vm_state.interrupt); vm_state.interrupt.nmi = 1; vmcs_dirty(vm_state.interrupt); } return VM_DONE; } if(__rmode()) return __vmx_vmexit_idt_deliver_rmode(); return __vmx_vmexit_idt_deliver_pmode(); }
static int __vmx_vmexit_resolve_msr_efer(uint8_t wr) { if(wr) { ia32_efer_msr_t update; update.low = info->vm.efer.low ^ info->vm.cpu.gpr->rax.low; info->vm.efer.low = info->vm.cpu.gpr->rax.low; info->vm.efer.high = info->vm.cpu.gpr->rdx.low; vm_state.ia32_efer.low = info->vm.efer.low; vm_state.ia32_efer.high = info->vm.efer.high; vmcs_read(vm_entry_ctrls.entry); vm_state.ia32_efer.lme = vm_state.ia32_efer.lma = vm_entry_ctrls.entry.ia32e; vmcs_dirty(vm_state.ia32_efer); if(info->vm.efer.lma && !info->vm.efer.lme) info->vm.efer.lma = 0; if(update.lme && __cr0.pg) { debug(VMX_MSR, "modifying LME while paging-on #GP\n"); __inject_exception(GP_EXCP, 0, 0); return VM_FAULT; } } else { info->vm.cpu.gpr->rax.low = info->vm.efer.low; info->vm.cpu.gpr->rdx.low = info->vm.efer.high; } return VM_DONE; }
int __vmx_vmexit_idt_deliver_pmode() { vmcs_read(vm_entry_ctrls.int_info); /* ** cpu was delivering ** we have nothing to inject ** so we resume delivering */ if(!vm_entry_ctrls.int_info.v) { debug(VMX_IDT, "idt[0x%x:%d] eax 0x%x\n" ,vm_exit_info.idt_info.vector ,vm_exit_info.idt_info.type ,info->vm.cpu.gpr->rax.low); if(vm_exit_info.idt_info.type == VMCS_EVT_INFO_TYPE_SW_INT) { vm_entry_ctrls.insn_len.raw = 2; vmcs_dirty(vm_entry_ctrls.insn_len); } if(vm_exit_info.idt_info.v_err) { vmcs_read(vm_exit_info.idt_err_code); vm_entry_ctrls.err_code.raw = vm_exit_info.idt_err_code.raw; vmcs_dirty(vm_entry_ctrls.err_code); } /* ** - interrupt shadow ** - read 31.7.1.1 reflecting exceptions to guest software */ debug_warning(); vm_entry_ctrls.int_info.raw = vm_exit_info.idt_info.raw; vm_entry_ctrls.int_info.r = 0; /* take care of reserved bits */ vmcs_dirty(vm_entry_ctrls.int_info); return VM_DONE; } debug(VMX_IDT, "already injecting: %d (%d)\n" ,vm_entry_ctrls.int_info.vector, vm_entry_ctrls.int_info.type); /* ** cpu was delivering ** we have something to inject */ /* /\* exception (to be injected) while delivering exception *\/ */ /* if(vm_exit_info.idt_info.type == VMCS_EVT_INFO_TYPE_HW_EXCP && */ /* vm_entry_ctrls.int_info.type == VMCS_EVT_INFO_TYPE_HW_EXCP) */ /* { */ /* uint8_t e1 = vm_exit_info.idt_info.vector; */ /* uint8_t e2 = vm_entry_ctrls.int_info.vector; */ /* if(triple_fault(e1)) */ /* { */ /* debug(VMX, "triple-fault\n"); */ /* return VM_FAIL; */ /* } */ /* if(double_fault(e1, e2)) */ /* { */ /* debug(VMX, "double-fault: %d raised while %d\n", e2, e1); */ /* return __vmx_vmexit_inject_exception(DOUBLEFAULT_EXCEPTION, 0, 0); */ /* } */ /* /\* handled serially *\/ */ /* debug(VMX_IDT, "handle serially: deliver(%d:%d)/inject(%d:%d)\n" */ /* , vm_exit_info.idt_info.type, vm_exit_info.idt_info.vector */ /* , vm_entry_ctrls.int_info.type, vm_entry_ctrls.int_info.vector); */ /* return VM_DONE; */ /* } */ /* /\* */ /* if(vm_exit_info.idt_info.type == VMCS_EVT_INFORMATION_TYPE_HW_INT && */ /* vm_entry_ctrls.int_info.type == VMCS_EVT_INFORMATION_TYPE_HW_EXCP) */ /* { */ /* } */ /* *\/ */ debug(VMX_IDT, "idt deliver PM: unhandled scenario\n"); return VM_FAIL; }
void vmx_vmcs_dirty_guest() { vmcs_dirty(vm_state.es.selector); vmcs_dirty(vm_state.cs.selector); vmcs_dirty(vm_state.ss.selector); vmcs_dirty(vm_state.ds.selector); vmcs_dirty(vm_state.fs.selector); vmcs_dirty(vm_state.gs.selector); vmcs_dirty(vm_state.ldtr.selector); vmcs_dirty(vm_state.tr.selector); vmcs_dirty(vm_state.vmcs_link_ptr); vmcs_dirty(vm_state.ia32_dbgctl); if(vm_entry_ctrls.entry.load_ia32_pat) vmcs_dirty(vm_state.ia32_pat); if(vm_entry_ctrls.entry.load_ia32_efer) vmcs_dirty(vm_state.ia32_efer); if(vm_entry_ctrls.entry.load_ia32_perf) vmcs_dirty(vm_state.ia32_perf); vmcs_dirty(vm_state.pdpe_0); vmcs_dirty(vm_state.pdpe_1); vmcs_dirty(vm_state.pdpe_2); vmcs_dirty(vm_state.pdpe_3); vmcs_dirty(vm_state.es.limit); vmcs_dirty(vm_state.cs.limit); vmcs_dirty(vm_state.ss.limit); vmcs_dirty(vm_state.ds.limit); vmcs_dirty(vm_state.fs.limit); vmcs_dirty(vm_state.gs.limit); vmcs_dirty(vm_state.ldtr.limit); vmcs_dirty(vm_state.tr.limit); vmcs_dirty(vm_state.gdtr.limit); vmcs_dirty(vm_state.idtr.limit); vmcs_dirty(vm_state.es.attributes); vmcs_dirty(vm_state.cs.attributes); vmcs_dirty(vm_state.ss.attributes); vmcs_dirty(vm_state.ds.attributes); vmcs_dirty(vm_state.fs.attributes); vmcs_dirty(vm_state.gs.attributes); vmcs_dirty(vm_state.ldtr.attributes); vmcs_dirty(vm_state.tr.attributes); vmcs_dirty(vm_state.interrupt); vmcs_dirty(vm_state.activity); #ifdef CONFIG_VMX_FEAT_VMCS_SMBASE vmcs_dirty(vm_state.smbase); #endif vmcs_dirty(vm_state.ia32_sysenter_cs); if(info->vm.vmx_fx_pin.allow_1.preempt) vmcs_dirty(vm_state.preempt_timer); vmx_set_fixed(vm_state.cr0.low, info->vm.vmx_fx_cr0); vmcs_dirty(vm_state.cr0); vmcs_dirty(vm_state.cr3); vmx_set_fixed(vm_state.cr4.low, info->vm.vmx_fx_cr4); vmcs_dirty(vm_state.cr4); vmcs_dirty(vm_state.es.base); vmcs_dirty(vm_state.cs.base); vmcs_dirty(vm_state.ss.base); vmcs_dirty(vm_state.ds.base); vmcs_dirty(vm_state.fs.base); vmcs_dirty(vm_state.gs.base); vmcs_dirty(vm_state.tr.base); vmcs_dirty(vm_state.ldtr.base); vmcs_dirty(vm_state.gdtr.base); vmcs_dirty(vm_state.idtr.base); vmcs_dirty(vm_state.dr7); vmcs_dirty(vm_state.rsp); vmcs_dirty(vm_state.rip); vmcs_dirty(vm_state.rflags); vmcs_dirty(vm_state.dbg_excp); vmcs_dirty(vm_state.ia32_sysenter_esp); vmcs_dirty(vm_state.ia32_sysenter_eip); /* Fake fields */ vmcs_dirty(vm_state.cr2); vmcs_dirty(vm_state.dr6); }
void vmx_vmcs_dirty_exec() { vmcs_dirty(vm_exec_ctrls.vpid); vmcs_dirty(vm_exec_ctrls.io_bitmap_a); vmcs_dirty(vm_exec_ctrls.io_bitmap_b); vmcs_dirty(vm_exec_ctrls.msr_bitmap); #ifdef CONFIG_VMX_FEAT_VMCS_EXEC_PTR vmcs_dirty(vm_exec_ctrls.executive_vmcs_ptr); #endif vmcs_dirty(vm_exec_ctrls.tsc_offset); if(info->vm.vmx_fx_proc.allow_1.tprs) vmcs_dirty(vm_exec_ctrls.vapic_addr); if(info->vm.vmx_fx_proc2.allow_1.vapic) vmcs_dirty(vm_exec_ctrls.apic_addr); vmcs_dirty(vm_exec_ctrls.eptp); vmcs_dirty(vm_exec_ctrls.pin); vmcs_dirty(vm_exec_ctrls.proc); vmcs_dirty(vm_exec_ctrls.excp_bitmap); vmcs_dirty(vm_exec_ctrls.pagefault_err_code_mask); vmcs_dirty(vm_exec_ctrls.pagefault_err_code_match); vmcs_dirty(vm_exec_ctrls.cr3_target_count); vmcs_dirty(vm_exec_ctrls.tpr_threshold); vmcs_dirty(vm_exec_ctrls.proc2); /* vmcs_dirty(vm_exec_ctrls.ple_gap); */ /* vmcs_dirty(vm_exec_ctrls.ple_win); */ vmcs_dirty(vm_exec_ctrls.cr0_mask); vmcs_dirty(vm_exec_ctrls.cr4_mask); vmcs_dirty(vm_exec_ctrls.cr0_read_shadow); vmcs_dirty(vm_exec_ctrls.cr4_read_shadow); vmcs_dirty(vm_exec_ctrls.cr3_target_0); vmcs_dirty(vm_exec_ctrls.cr3_target_1); vmcs_dirty(vm_exec_ctrls.cr3_target_2); vmcs_dirty(vm_exec_ctrls.cr3_target_3); }