diff --git a/hypervisor/arch/x86/ept.c b/hypervisor/arch/x86/ept.c index e574bfaaa..ba637ca72 100644 --- a/hypervisor/arch/x86/ept.c +++ b/hypervisor/arch/x86/ept.c @@ -321,7 +321,7 @@ static int dm_emulate_mmio_pre(struct vcpu *vcpu, uint64_t exit_qual) int ept_violation_vmexit_handler(struct vcpu *vcpu) { - int status = -EINVAL; + int status = -EINVAL, ret; uint64_t exit_qual; uint64_t gpa; struct list_head *pos; @@ -361,8 +361,14 @@ int ept_violation_vmexit_handler(struct vcpu *vcpu) */ mmio->paddr = gpa; - mmio->access_size = decode_instruction(vcpu); - if (mmio->access_size == 0) + ret = decode_instruction(vcpu); + if (ret > 0) + mmio->access_size = ret; + else if (ret == -EFAULT) { + pr_info("page fault happen during decode_instruction"); + status = 0; + goto out; + } else goto out; list_for_each(pos, &vcpu->vm->mmio_list) { diff --git a/hypervisor/arch/x86/guest/instr_emul.c b/hypervisor/arch/x86/guest/instr_emul.c index 87ee48416..431066e18 100644 --- a/hypervisor/arch/x86/guest/instr_emul.c +++ b/hypervisor/arch/x86/guest/instr_emul.c @@ -1674,11 +1674,16 @@ vie_calculate_gla(enum vm_cpu_mode cpu_mode, enum vm_reg_name seg, return 0; } -void -vie_init(struct vie *vie, const char *inst_bytes, uint32_t inst_length) +int +vie_init(struct vie *vie, struct vcpu *vcpu) { - ASSERT(inst_length <= VIE_INST_SIZE, - "%s: invalid instruction length (%d)", __func__, inst_length); + uint32_t inst_len = vcpu->arch_vcpu.inst_len; + + if (inst_len > VIE_INST_SIZE) { + pr_err("%s: invalid instruction length (%d)", + __func__, inst_len); + return -EINVAL; + } memset(vie, 0, sizeof(struct vie)); @@ -1686,11 +1691,24 @@ vie_init(struct vie *vie, const char *inst_bytes, uint32_t inst_length) vie->index_register = VM_REG_LAST; vie->segment_register = VM_REG_LAST; - if (inst_length) { - memcpy_s((char *)vie->inst, VIE_INST_SIZE, - (char *)inst_bytes, inst_length); - vie->num_valid = inst_length; + if (inst_len) { + int ret; + uint64_t guest_rip_gva = + vcpu->arch_vcpu.contexts[vcpu->arch_vcpu.cur_context].rip; + uint32_t err_code; + + err_code = PAGE_FAULT_ID_FLAG; + ret = copy_from_gva(vcpu, vie->inst, guest_rip_gva, + inst_len, &err_code); + if (ret == -EFAULT) { + vcpu_inject_pf(vcpu, guest_rip_gva, err_code); + return ret; + } else if (ret < 0) + return ret; + vie->num_valid = inst_len; } + + return 0; } static int diff --git a/hypervisor/arch/x86/guest/instr_emul.h b/hypervisor/arch/x86/guest/instr_emul.h index b222ab565..cdff96e0f 100644 --- a/hypervisor/arch/x86/guest/instr_emul.h +++ b/hypervisor/arch/x86/guest/instr_emul.h @@ -72,7 +72,7 @@ int vie_calculate_gla(enum vm_cpu_mode cpu_mode, enum vm_reg_name seg, struct seg_desc *desc, uint64_t off, int length, int addrsize, int prot, uint64_t *gla); -void vie_init(struct vie *vie, const char *inst_bytes, uint32_t inst_length); +int vie_init(struct vie *vie, struct vcpu *vcpu); /* * Decode the instruction fetched into 'vie' so it can be emulated. @@ -90,6 +90,6 @@ int __decode_instruction(struct vcpu *vcpu, uint64_t gla, enum vm_cpu_mode cpu_mode, int csd, struct vie *vie); int emulate_instruction(struct vcpu *vcpu); -uint8_t decode_instruction(struct vcpu *vcpu); +int decode_instruction(struct vcpu *vcpu); #endif /* _VMM_INSTRUCTION_EMUL_H_ */ diff --git a/hypervisor/arch/x86/guest/instr_emul_wrapper.c b/hypervisor/arch/x86/guest/instr_emul_wrapper.c index 7925532f5..648ca20d0 100644 --- a/hypervisor/arch/x86/guest/instr_emul_wrapper.c +++ b/hypervisor/arch/x86/guest/instr_emul_wrapper.c @@ -307,35 +307,25 @@ int vm_gva2gpa(struct vcpu *vcpu, uint64_t gva, uint64_t *gpa, return gva2gpa(vcpu, gva, gpa, err_code); } -uint8_t decode_instruction(struct vcpu *vcpu) +int decode_instruction(struct vcpu *vcpu) { - uint64_t guest_rip_gva, guest_rip_gpa; - char *guest_rip_hva; struct emul_cnx *emul_cnx; uint32_t csar; int retval = 0; enum vm_cpu_mode cpu_mode; - int error; - uint32_t err_code; - guest_rip_gva = - vcpu->arch_vcpu.contexts[vcpu->arch_vcpu.cur_context].rip; - - err_code = PAGE_FAULT_ID_FLAG; - error = gva2gpa(vcpu, guest_rip_gva, &guest_rip_gpa, &err_code); - if (error) { - pr_err("gva2gpa failed for guest_rip_gva 0x%016llx:", - guest_rip_gva); - return 0; - } - - guest_rip_hva = GPA2HVA(vcpu->vm, guest_rip_gpa); emul_cnx = &per_cpu(g_inst_ctxt, vcpu->pcpu_id); emul_cnx->vcpu = vcpu; - /* by now, HVA <-> HPA is 1:1 mapping, so use hpa is OK*/ - vie_init(&emul_cnx->vie, guest_rip_hva, - vcpu->arch_vcpu.inst_len); + retval = vie_init(&emul_cnx->vie, vcpu); + if (retval < 0) { + if (retval != -EFAULT) { + pr_err("decode instruction failed @ 0x%016llx:", + vcpu->arch_vcpu. + contexts[vcpu->arch_vcpu.cur_context].rip); + } + return retval; + } get_guest_paging_info(vcpu, emul_cnx); csar = exec_vmread(VMX_GUEST_CS_ATTR); @@ -346,8 +336,8 @@ uint8_t decode_instruction(struct vcpu *vcpu) if (retval != 0) { pr_err("decode instruction failed @ 0x%016llx:", - exec_vmread(VMX_GUEST_RIP)); - return 0; + vcpu->arch_vcpu.contexts[vcpu->arch_vcpu.cur_context].rip); + return -EINVAL; } return emul_cnx->vie.opsize; diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 98f3b792e..d1743f872 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -2198,7 +2198,7 @@ apicv_inject_pir(struct vlapic *vlapic) int apic_access_vmexit_handler(struct vcpu *vcpu) { - int access_type, offset; + int access_type, offset = 0, ret; uint64_t qual; struct vlapic *vlapic; @@ -2211,7 +2211,13 @@ int apic_access_vmexit_handler(struct vcpu *vcpu) vlapic = vcpu->arch_vcpu.vlapic; - decode_instruction(vcpu); + ret = decode_instruction(vcpu); + /* apic access should already fetched instruction, decode_instruction + * will not trigger #PF, so if it failed, just return error_no + */ + if (ret < 0) + return ret; + if (access_type == 1) { if (!emulate_instruction(vcpu)) vlapic_write(vlapic, 1, offset, vcpu->mmio.value);