?? vmx.c
字號:
vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); rdmsrl(MSR_IA32_SYSENTER_ESP, a); vmcs_writel(HOST_IA32_SYSENTER_ESP, a); /* 22.2.3 */ rdmsrl(MSR_IA32_SYSENTER_EIP, a); vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */ for (i = 0; i < NR_VMX_MSR; ++i) { u32 index = vmx_msr_index[i]; u32 data_low, data_high; u64 data; int j = vmx->nmsrs; if (rdmsr_safe(index, &data_low, &data_high) < 0) continue; if (wrmsr_safe(index, data_low, data_high) < 0) continue; data = data_low | ((u64)data_high << 32); vmx->host_msrs[j].index = index; vmx->host_msrs[j].reserved = 0; vmx->host_msrs[j].data = data; vmx->guest_msrs[j] = vmx->host_msrs[j]; ++vmx->nmsrs; } setup_msrs(vmx); vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl); /* 22.2.1, 20.8.1 */ vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl); vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */#ifdef CONFIG_X86_64 vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0); if (vm_need_tpr_shadow(vmx->vcpu.kvm)) vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, page_to_phys(vmx->vcpu.apic->regs_page)); vmcs_write32(TPR_THRESHOLD, 0);#endif vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); vmx->vcpu.cr0 = 0x60000010; vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode vmx_set_cr4(&vmx->vcpu, 0);#ifdef CONFIG_X86_64 vmx_set_efer(&vmx->vcpu, 0);#endif vmx_fpu_activate(&vmx->vcpu); update_exception_bitmap(&vmx->vcpu); return 0;out: return ret;}static void vmx_vcpu_reset(struct kvm_vcpu *vcpu){ struct vcpu_vmx *vmx = to_vmx(vcpu); vmx_vcpu_setup(vmx);}static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq){ u16 ent[2]; u16 cs; u16 ip; unsigned long flags; unsigned long ss_base = vmcs_readl(GUEST_SS_BASE); u16 sp = vmcs_readl(GUEST_RSP); u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT); if (sp > ss_limit || sp < 6 ) { vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n", __FUNCTION__, vmcs_readl(GUEST_RSP), vmcs_readl(GUEST_SS_BASE), vmcs_read32(GUEST_SS_LIMIT)); return; } if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) != X86EMUL_CONTINUE) { vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__); return; } flags = vmcs_readl(GUEST_RFLAGS); cs = vmcs_readl(GUEST_CS_BASE) >> 4; ip = vmcs_readl(GUEST_RIP); if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE || emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE || emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) { vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__); return; } vmcs_writel(GUEST_RFLAGS, flags & ~( X86_EFLAGS_IF | X86_EFLAGS_AC | X86_EFLAGS_TF)); vmcs_write16(GUEST_CS_SELECTOR, ent[1]) ; vmcs_writel(GUEST_CS_BASE, ent[1] << 4); vmcs_writel(GUEST_RIP, ent[0]); vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));}static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq){ if (vcpu->rmode.active) { inject_rmode_irq(vcpu, irq); return; } vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);}static void kvm_do_inject_irq(struct kvm_vcpu *vcpu){ int word_index = __ffs(vcpu->irq_summary); int bit_index = __ffs(vcpu->irq_pending[word_index]); int irq = word_index * BITS_PER_LONG + bit_index; clear_bit(bit_index, &vcpu->irq_pending[word_index]); if (!vcpu->irq_pending[word_index]) clear_bit(word_index, &vcpu->irq_summary); vmx_inject_irq(vcpu, irq);}static void do_interrupt_requests(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ u32 cpu_based_vm_exec_control; vcpu->interrupt_window_open = ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); if (vcpu->interrupt_window_open && vcpu->irq_summary && !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK)) /* * If interrupts enabled, and not blocked by sti or mov ss. Good. */ kvm_do_inject_irq(vcpu); cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); if (!vcpu->interrupt_window_open && (vcpu->irq_summary || kvm_run->request_interrupt_window)) /* * Interrupts blocked. Wait for unblock. */ cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; else cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);}static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu){ struct kvm_guest_debug *dbg = &vcpu->guest_debug; set_debugreg(dbg->bp[0], 0); set_debugreg(dbg->bp[1], 1); set_debugreg(dbg->bp[2], 2); set_debugreg(dbg->bp[3], 3); if (dbg->singlestep) { unsigned long flags; flags = vmcs_readl(GUEST_RFLAGS); flags |= X86_EFLAGS_TF | X86_EFLAGS_RF; vmcs_writel(GUEST_RFLAGS, flags); }}static int handle_rmode_exception(struct kvm_vcpu *vcpu, int vec, u32 err_code){ if (!vcpu->rmode.active) return 0; /* * Instruction with address size override prefix opcode 0x67 * Cause the #SS fault with 0 error code in VM86 mode. */ if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0) if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE) return 1; return 0;}static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ u32 intr_info, error_code; unsigned long cr2, rip; u32 vect_info; enum emulation_result er; int r; vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); intr_info = vmcs_read32(VM_EXIT_INTR_INFO); if ((vect_info & VECTORING_INFO_VALID_MASK) && !is_page_fault(intr_info)) { printk(KERN_ERR "%s: unexpected, vectoring info 0x%x " "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); } if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { int irq = vect_info & VECTORING_INFO_VECTOR_MASK; set_bit(irq, vcpu->irq_pending); set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); } if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */ return 1; /* already handled by vmx_vcpu_run() */ if (is_no_device(intr_info)) { vmx_fpu_activate(vcpu); return 1; } error_code = 0; rip = vmcs_readl(GUEST_RIP); if (intr_info & INTR_INFO_DELIEVER_CODE_MASK) error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); if (is_page_fault(intr_info)) { cr2 = vmcs_readl(EXIT_QUALIFICATION); mutex_lock(&vcpu->kvm->lock); r = kvm_mmu_page_fault(vcpu, cr2, error_code); if (r < 0) { mutex_unlock(&vcpu->kvm->lock); return r; } if (!r) { mutex_unlock(&vcpu->kvm->lock); return 1; } er = emulate_instruction(vcpu, kvm_run, cr2, error_code); mutex_unlock(&vcpu->kvm->lock); switch (er) { case EMULATE_DONE: return 1; case EMULATE_DO_MMIO: ++vcpu->stat.mmio_exits; return 0; case EMULATE_FAIL: kvm_report_emulation_failure(vcpu, "pagetable"); break; default: BUG(); } } if (vcpu->rmode.active && handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK, error_code)) { if (vcpu->halt_request) { vcpu->halt_request = 0; return kvm_emulate_halt(vcpu); } return 1; } if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) { return 0; } kvm_run->exit_reason = KVM_EXIT_EXCEPTION; kvm_run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK; kvm_run->ex.error_code = error_code; return 0;}static int handle_external_interrupt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ ++vcpu->stat.irq_exits; return 1;}static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; return 0;}static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ unsigned long exit_qualification; int size, down, in, string, rep; unsigned port; ++vcpu->stat.io_exits; exit_qualification = vmcs_readl(EXIT_QUALIFICATION); string = (exit_qualification & 16) != 0; if (string) { if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) return 0; return 1; } size = (exit_qualification & 7) + 1; in = (exit_qualification & 8) != 0; down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; rep = (exit_qualification & 32) != 0; port = exit_qualification >> 16; return kvm_emulate_pio(vcpu, kvm_run, in, size, port);}static voidvmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall){ /* * Patch in the VMCALL instruction: */ hypercall[0] = 0x0f; hypercall[1] = 0x01; hypercall[2] = 0xc1; hypercall[3] = 0xc3;}static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ unsigned long exit_qualification; int cr; int reg; exit_qualification = vmcs_readl(EXIT_QUALIFICATION); cr = exit_qualification & 15; reg = (exit_qualification >> 8) & 15; switch ((exit_qualification >> 4) & 3) { case 0: /* mov to cr */ switch (cr) { case 0: vcpu_load_rsp_rip(vcpu); set_cr0(vcpu, vcpu->regs[reg]); skip_emulated_instruction(vcpu); return 1; case 3: vcpu_load_rsp_rip(vcpu); set_cr3(vcpu, vcpu->regs[reg]); skip_emulated_instruction(vcpu); return 1; case 4: vcpu_load_rsp_rip(vcpu); set_cr4(vcpu, vcpu->regs[reg]); skip_emulated_instruction(vcpu); return 1; case 8: vcpu_load_rsp_rip(vcpu); set_cr8(vcpu, vcpu->regs[reg]); skip_emulated_instruction(vcpu); kvm_run->exit_reason = KVM_EXIT_SET_TPR; return 0; }; break; case 2: /* clts */ vcpu_load_rsp_rip(vcpu); vmx_fpu_deactivate(vcpu); vcpu->cr0 &= ~X86_CR0_TS; vmcs_writel(CR0_READ_SHADOW, vcpu->cr0); vmx_fpu_activate(vcpu); skip_emulated_instruction(vcpu); return 1; case 1: /*mov from cr*/ switch (cr) { case 3: vcpu_load_rsp_rip(vcpu); vcpu->regs[reg] = vcpu->cr3; vcpu_put_rsp_rip(vcpu); skip_emulated_instruction(vcpu); return 1; case 8: vcpu_load_rsp_rip(vcpu); vcpu->regs[reg] = get_cr8(vcpu); vcpu_put_rsp_rip(vcpu); skip_emulated_instruction(vcpu); return 1; } break; case 3: /* lmsw */ lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f); skip_emulated_instruction(vcpu); return 1; default: break; } kvm_run->exit_reason = 0; pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n", (int)(exit_qualification >> 4) & 3, cr); return 0;}static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ unsigned long exit_qualification; unsigned long val; int dr, reg; /* * FIXME: this code assumes the host is debugging the guest. * need to deal with guest debugging itself too. */ exit_qualification = vmcs_readl(EXIT_QUALIFICATION); dr = exit_qualification & 7; reg = (exit_qualification >> 8) & 15; vcpu_load_rsp_rip(vcpu); if (exit_qualification & 16) { /* mov from dr */ switch (dr) { case 6: val = 0xffff0ff0; break; case 7: val = 0x400; break; default: val = 0; } vcpu->regs[reg] = val; } else { /* mov to dr */ } vcpu_put_rsp_rip(vcpu); skip_emulated_instruction(vcpu); return 1;}static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ kvm_emulate_cpuid(vcpu); return 1;}static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ u32 ecx = vcpu->regs[VCPU_REGS_RCX]; u64 data; if (vmx_get_msr(vcpu, ecx, &data)) { vmx_inject_gp(vcpu, 0); return 1; } /* FIXME: handling of bits 32:63 of rax, rdx */ vcpu->regs[VCPU_REGS_RAX] = data & -1u; vcpu->regs[VCPU_REGS_RDX] = (data >> 32) & -1u; skip_emulated_instruction(vcpu); return 1;}static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ u32 ecx = vcpu->regs[VCPU_REGS_RCX]; u64 data = (vcpu->regs[VCPU_REGS_RAX] & -1u) | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32); if (vmx_set_msr(vcpu, ecx, data) != 0) { vmx_inject_gp(vcpu, 0); return 1; } skip_emulated_instruction(vcpu); return 1;}static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ return 1;}static int handle_interrupt_window(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ u32 cpu_based_vm_exec_control; /* clear pending irq */ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); /* * If the user space waits to inject interrupts, exit as soon as * possible */ if (kvm_run->request_interrupt_window && !vcpu->irq_summary) { kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; ++vcpu->stat.irq_window_exits; return 0; } return 1;}static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run){ skip_emulated_instruction(vcpu); return kvm_emulate_halt(vcpu);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -