From 63fe48c27f747a946f953b02ac38bec79c5c3ffe Mon Sep 17 00:00:00 2001 From: Yin Fengwei Date: Tue, 7 Aug 2018 11:36:06 +0800 Subject: [PATCH] hv: get correct fault address for copy_to/from_gva When doing copy_to/from_gva, it's possible the guest no page happens on none-first page. In this case, we need get correct fault address from gva2gpa. Signed-off-by: Yin Fengwei Reviewed-by: Jason Chen CJ Acked-by: Anthony Xu Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/guest.c | 12 +++++++----- hypervisor/arch/x86/guest/instr_emul.c | 5 +++-- hypervisor/arch/x86/guest/ucode.c | 12 +++++++----- hypervisor/debug/dump.c | 8 ++++---- hypervisor/debug/shell.c | 5 +++-- hypervisor/include/arch/x86/guest/guest.h | 4 ++-- 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/hypervisor/arch/x86/guest/guest.c b/hypervisor/arch/x86/guest/guest.c index 16765c05b..ef837dbad 100644 --- a/hypervisor/arch/x86/guest/guest.c +++ b/hypervisor/arch/x86/guest/guest.c @@ -375,7 +375,8 @@ static inline int copy_gpa(struct vm *vm, void *h_ptr_arg, uint64_t gpa_arg, } static inline int copy_gva(struct vcpu *vcpu, void *h_ptr_arg, uint64_t gva_arg, - uint32_t size_arg, uint32_t *err_code, bool cp_from_vm) + uint32_t size_arg, uint32_t *err_code, uint64_t *fault_addr, + bool cp_from_vm) { void *h_ptr = h_ptr_arg; uint64_t gpa = 0UL; @@ -396,6 +397,7 @@ static inline int copy_gva(struct vcpu *vcpu, void *h_ptr_arg, uint64_t gva_arg, while (size > 0U) { ret = gva2gpa(vcpu, gva, &gpa, err_code); if (ret < 0) { + *fault_addr = gva; pr_err("error[%d] in GVA2GPA, err_code=0x%x", ret, *err_code); return ret; @@ -433,15 +435,15 @@ int copy_to_gpa(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size) } int copy_from_gva(struct vcpu *vcpu, void *h_ptr, uint64_t gva, - uint32_t size, uint32_t *err_code) + uint32_t size, uint32_t *err_code, uint64_t *fault_addr) { - return copy_gva(vcpu, h_ptr, gva, size, err_code, 1); + return copy_gva(vcpu, h_ptr, gva, size, err_code, fault_addr, 1); } int copy_to_gva(struct vcpu *vcpu, void *h_ptr, uint64_t gva, - uint32_t size, uint32_t *err_code) + uint32_t size, uint32_t *err_code, uint64_t *fault_addr) { - return copy_gva(vcpu, h_ptr, gva, size, err_code, 0); + return copy_gva(vcpu, h_ptr, gva, size, err_code, fault_addr, 0); } void init_e820(void) diff --git a/hypervisor/arch/x86/guest/instr_emul.c b/hypervisor/arch/x86/guest/instr_emul.c index 82c6fd71b..2ebe3d7d7 100644 --- a/hypervisor/arch/x86/guest/instr_emul.c +++ b/hypervisor/arch/x86/guest/instr_emul.c @@ -1773,6 +1773,7 @@ static int vie_init(struct instr_emul_vie *vie, struct vcpu *vcpu) uint64_t guest_rip_gva = vcpu_get_rip(vcpu); uint32_t inst_len = vcpu->arch_vcpu.inst_len; uint32_t err_code; + uint64_t fault_addr; int ret; if (inst_len > VIE_INST_SIZE || inst_len == 0U) { @@ -1785,10 +1786,10 @@ static int vie_init(struct instr_emul_vie *vie, struct vcpu *vcpu) err_code = PAGE_FAULT_ID_FLAG; ret = copy_from_gva(vcpu, vie->inst, guest_rip_gva, - inst_len, &err_code); + inst_len, &err_code, &fault_addr); if (ret < 0) { if (ret == -EFAULT) { - vcpu_inject_pf(vcpu, guest_rip_gva, err_code); + vcpu_inject_pf(vcpu, fault_addr, err_code); } return ret; } diff --git a/hypervisor/arch/x86/guest/ucode.c b/hypervisor/arch/x86/guest/ucode.c index a408c3461..dfa816698 100644 --- a/hypervisor/arch/x86/guest/ucode.c +++ b/hypervisor/arch/x86/guest/ucode.c @@ -27,7 +27,7 @@ uint64_t get_microcode_version(void) ((uhdr.data_size != 0U) ? uhdr.data_size : 2000U) void acrn_update_ucode(struct vcpu *vcpu, uint64_t v) { - uint64_t gva; + uint64_t gva, fault_addr; struct ucode_header uhdr; uint32_t data_page_num; size_t data_size; @@ -38,10 +38,11 @@ void acrn_update_ucode(struct vcpu *vcpu, uint64_t v) gva = v - sizeof(struct ucode_header); err_code = 0U; - err = copy_from_gva(vcpu, &uhdr, gva, sizeof(uhdr), &err_code); + err = copy_from_gva(vcpu, &uhdr, gva, sizeof(uhdr), &err_code, + &fault_addr); if (err < 0) { if (err == -EFAULT) { - vcpu_inject_pf(vcpu, gva, err_code); + vcpu_inject_pf(vcpu, fault_addr, err_code); } return; } @@ -56,10 +57,11 @@ void acrn_update_ucode(struct vcpu *vcpu, uint64_t v) } err_code = 0U; - err = copy_from_gva(vcpu, ucode_ptr, gva, data_size, &err_code); + err = copy_from_gva(vcpu, ucode_ptr, gva, data_size, &err_code, + &fault_addr); if (err < 0) { if (err == -EFAULT) { - vcpu_inject_pf(vcpu, gva, err_code); + vcpu_inject_pf(vcpu, fault_addr, err_code); } return; } diff --git a/hypervisor/debug/dump.c b/hypervisor/debug/dump.c index 71d47b7f4..1ae4859cb 100644 --- a/hypervisor/debug/dump.c +++ b/hypervisor/debug/dump.c @@ -97,11 +97,11 @@ static void dump_guest_reg(struct vcpu *vcpu) static void dump_guest_stack(struct vcpu *vcpu) { uint32_t i; - uint64_t tmp[DUMP_STACK_SIZE]; + uint64_t tmp[DUMP_STACK_SIZE], fault_addr; uint32_t err_code = 0; if (copy_from_gva(vcpu, tmp, vcpu_get_gpreg(vcpu, CPU_REG_RSP), - DUMP_STACK_SIZE, &err_code) < 0) { + DUMP_STACK_SIZE, &err_code, &fault_addr) < 0) { printf("\r\nUnabled to Copy Guest Stack:\r\n"); return; } @@ -143,11 +143,11 @@ static void show_guest_call_trace(struct vcpu *vcpu) * if the address is invalid, it will cause hv page fault * then halt system */ while ((count < CALL_TRACE_HIERARCHY_MAX) && (bp != 0)) { - uint64_t parent_bp = 0UL; + uint64_t parent_bp = 0UL, fault_addr; err_code = 0U; err = copy_from_gva(vcpu, &parent_bp, bp, sizeof(parent_bp), - &err_code); + &err_code, &fault_addr); if (err < 0) { printf("\r\nUnabled to get Guest parent BP\r\n"); return; diff --git a/hypervisor/debug/shell.c b/hypervisor/debug/shell.c index ebb1328d3..5e1dbe6f8 100644 --- a/hypervisor/debug/shell.c +++ b/hypervisor/debug/shell.c @@ -592,7 +592,7 @@ int shell_vcpu_dumpreg(int argc, char **argv) char temp_str[MAX_STR_SIZE]; struct vm *vm; struct vcpu *vcpu; - uint64_t i; + uint64_t i, fault_addr; uint64_t tmp[DUMPREG_SP_SIZE]; uint32_t err_code = 0; @@ -676,7 +676,8 @@ int shell_vcpu_dumpreg(int argc, char **argv) /* dump sp */ status = copy_from_gva(vcpu, tmp, vcpu_get_gpreg(vcpu, CPU_REG_RSP), - DUMPREG_SP_SIZE*sizeof(uint64_t), &err_code); + DUMPREG_SP_SIZE*sizeof(uint64_t), &err_code, + &fault_addr); if (status < 0) { /* copy_from_gva fail */ shell_puts("Cannot handle user gva yet!\r\n"); diff --git a/hypervisor/include/arch/x86/guest/guest.h b/hypervisor/include/arch/x86/guest/guest.h index c50a1697b..583ac302c 100644 --- a/hypervisor/include/arch/x86/guest/guest.h +++ b/hypervisor/include/arch/x86/guest/guest.h @@ -113,9 +113,9 @@ extern vm_sw_loader_t vm_sw_loader; int copy_from_gpa(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size); int copy_to_gpa(struct vm *vm, void *h_ptr, uint64_t gpa, uint32_t size); int copy_from_gva(struct vcpu *vcpu, void *h_ptr, uint64_t gva, - uint32_t size, uint32_t *err_code); + uint32_t size, uint32_t *err_code, uint64_t *fault_addr); int copy_to_gva(struct vcpu *vcpu, void *h_ptr, uint64_t gva, - uint32_t size, uint32_t *err_code); + uint32_t size, uint32_t *err_code, uint64_t *fault_addr); uint64_t create_guest_init_gdt(struct vm *vm, uint32_t *limit);