[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-3.1-testing] hvm: For functions which translate virtual addresses to machine
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1198794744 0 # Node ID 874a20ac1ffdb23f75421900cb0113e7dc5204a9 # Parent 5e8068c541fc4123646150af21e175412cf962d2 hvm: For functions which translate virtual addresses to machine addresses, page faults should only be raised when the gva->gfn translation fails. These should be distinguished from gfn->mfn translation failures. The main effect of this is to change the behaviour of functions derived from __hvm_copy(), which now returns a three-way enumeration, and also can automatically inject #PF when the gva->gfn translation fails. Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> xen-unstable changeset: 16662:e818c24cec03 xen-unstable date: Thu Dec 27 12:00:30 2007 +0000 --- xen/arch/x86/hvm/hvm.c | 73 +++++++++++++++++++++++--------------- xen/arch/x86/hvm/io.c | 22 ++++++----- xen/arch/x86/hvm/platform.c | 22 +++++++---- xen/arch/x86/hvm/svm/svm.c | 11 +++-- xen/arch/x86/hvm/vmx/vmx.c | 7 ++- xen/arch/x86/mm/shadow/common.c | 18 ++++++--- xen/arch/x86/mm/shadow/multi.c | 35 +++++++++++------- xen/include/asm-x86/hvm/support.h | 33 +++++++++++++++-- 8 files changed, 148 insertions(+), 73 deletions(-) diff -r 5e8068c541fc -r 874a20ac1ffd xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Thu Dec 27 21:55:38 2007 +0000 +++ b/xen/arch/x86/hvm/hvm.c Thu Dec 27 22:32:24 2007 +0000 @@ -562,11 +562,12 @@ void hvm_triple_fault(void) * @virt = addr is *virtual* (TRUE) or *guest physical* (FALSE)? * Returns number of bytes failed to copy (0 == complete success). */ -static int __hvm_copy(void *buf, paddr_t addr, int size, int dir, int virt) +static enum hvm_copy_result __hvm_copy( + void *buf, paddr_t addr, int size, int dir, int virt, int *ptodo) { unsigned long gfn, mfn; char *p; - int count, todo; + int count, todo, rc = HVMCOPY_okay; todo = size; while ( todo > 0 ) @@ -574,14 +575,26 @@ static int __hvm_copy(void *buf, paddr_t count = min_t(int, PAGE_SIZE - (addr & ~PAGE_MASK), todo); if ( virt ) + { gfn = paging_gva_to_gfn(current, addr); + if ( gfn == INVALID_GFN ) + { + rc = HVMCOPY_bad_gva_to_gfn; + goto out; + } + } else + { gfn = addr >> PAGE_SHIFT; - + } + mfn = get_mfn_from_gpfn(gfn); if ( mfn == INVALID_MFN ) - return todo; + { + rc = HVMCOPY_bad_gfn_to_mfn; + goto out; + } p = (char *)map_domain_page(mfn) + (addr & ~PAGE_MASK); @@ -600,29 +613,35 @@ static int __hvm_copy(void *buf, paddr_t todo -= count; } - return 0; -} - -int hvm_copy_to_guest_phys(paddr_t paddr, void *buf, int size) -{ - return __hvm_copy(buf, paddr, size, 1, 0); -} - -int hvm_copy_from_guest_phys(void *buf, paddr_t paddr, int size) -{ - return __hvm_copy(buf, paddr, size, 0, 0); -} - -int hvm_copy_to_guest_virt(unsigned long vaddr, void *buf, int size) -{ - return __hvm_copy(buf, vaddr, size, 1, 1); -} - -int hvm_copy_from_guest_virt(void *buf, unsigned long vaddr, int size) -{ - return __hvm_copy(buf, vaddr, size, 0, 1); -} - + out: + if ( ptodo ) + *ptodo = todo; + return rc; +} + +enum hvm_copy_result hvm_copy_to_guest_phys( + paddr_t paddr, void *buf, int size) +{ + return __hvm_copy(buf, paddr, size, 1, 0, NULL); +} + +enum hvm_copy_result hvm_copy_from_guest_phys( + void *buf, paddr_t paddr, int size) +{ + return __hvm_copy(buf, paddr, size, 0, 0, NULL); +} + +enum hvm_copy_result hvm_copy_to_guest_virt( + unsigned long vaddr, void *buf, int size, int *ptodo) +{ + return __hvm_copy(buf, vaddr, size, 1, 1, ptodo); +} + +enum hvm_copy_result hvm_copy_from_guest_virt( + void *buf, unsigned long vaddr, int size, int *ptodo) +{ + return __hvm_copy(buf, vaddr, size, 0, 1, ptodo); +} /* HVM specific printbuf. Mostly used for hvmloader chit-chat. */ void hvm_print_line(struct vcpu *v, const char c) diff -r 5e8068c541fc -r 874a20ac1ffd xen/arch/x86/hvm/io.c --- a/xen/arch/x86/hvm/io.c Thu Dec 27 21:55:38 2007 +0000 +++ b/xen/arch/x86/hvm/io.c Thu Dec 27 22:32:24 2007 +0000 @@ -432,12 +432,14 @@ static void hvm_pio_assist(struct cpu_us unsigned long addr = pio_opp->addr; if ( hvm_paging_enabled(current) ) { - int rv = hvm_copy_to_guest_virt(addr, &p->data, p->size); - if ( rv != 0 ) + int rv, todo; + rv = hvm_copy_to_guest_virt(addr, &p->data, p->size, + &todo); + if ( rv == HVMCOPY_bad_gva_to_gfn ) { /* Failed on the page-spanning copy. Inject PF into * the guest for the address where we failed. */ - addr += p->size - rv; + addr += p->size - todo; gdprintk(XENLOG_DEBUG, "Pagefault writing non-io side " "of a page-spanning PIO: va=%#lx\n", addr); hvm_inject_exception(TRAP_page_fault, @@ -563,12 +565,13 @@ static void hvm_mmio_assist(struct cpu_u if (hvm_paging_enabled(current)) { - int rv = hvm_copy_to_guest_virt(addr, &p->data, p->size); - if ( rv != 0 ) + int rv, todo; + rv = hvm_copy_to_guest_virt(addr, &p->data, p->size, &todo); + if ( rv == HVMCOPY_bad_gva_to_gfn ) { /* Failed on the page-spanning copy. Inject PF into * the guest for the address where we failed. */ - addr += p->size - rv; + addr += p->size - todo; gdprintk(XENLOG_DEBUG, "Pagefault writing non-io side of " "a page-spanning MMIO: va=%#lx\n", addr); hvm_inject_exception(TRAP_page_fault, @@ -806,10 +809,11 @@ static void hvm_mmio_assist(struct cpu_u mmio_opp->addr += hvm_get_segment_base(current, x86_seg_ss); { unsigned long addr = mmio_opp->addr; - int rv = hvm_copy_to_guest_virt(addr, &p->data, size); - if ( rv != 0 ) + int rv, todo; + rv = hvm_copy_to_guest_virt(addr, &p->data, size, &todo); + if ( rv == HVMCOPY_bad_gva_to_gfn ) { - addr += p->size - rv; + addr += p->size - todo; gdprintk(XENLOG_DEBUG, "Pagefault emulating PUSH from MMIO:" " va=%#lx\n", addr); hvm_inject_exception(TRAP_page_fault, PFEC_write_access, addr); diff -r 5e8068c541fc -r 874a20ac1ffd xen/arch/x86/hvm/platform.c --- a/xen/arch/x86/hvm/platform.c Thu Dec 27 21:55:38 2007 +0000 +++ b/xen/arch/x86/hvm/platform.c Thu Dec 27 22:32:24 2007 +0000 @@ -829,11 +829,12 @@ static int mmio_decode(int address_bytes } } -int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip, int inst_len) +int inst_copy_from_guest( + unsigned char *buf, unsigned long guest_eip, int inst_len) { if ( inst_len > MAX_INST_LEN || inst_len <= 0 ) return 0; - if ( hvm_copy_from_guest_virt(buf, guest_eip, inst_len) ) + if ( hvm_copy_from_guest_virt(buf, guest_eip, inst_len, NULL) ) return 0; return inst_len; } @@ -1147,15 +1148,16 @@ void handle_mmio(paddr_t gpa) if ( dir == IOREQ_WRITE ) { if ( hvm_paging_enabled(v) ) { - int rv = hvm_copy_from_guest_virt(&value, addr, size); - if ( rv != 0 ) + int rv, todo; + rv = hvm_copy_from_guest_virt(&value, addr, size, &todo); + if ( rv == HVMCOPY_bad_gva_to_gfn ) { /* Failed on the page-spanning copy. Inject PF into * the guest for the address where we failed */ regs->eip -= inst_len; /* do not advance %eip */ regs->eflags |= X86_EFLAGS_RF; /* RF was set by #PF */ /* Must set CR2 at the failing address */ - addr += size - rv; + addr += size - todo; gdprintk(XENLOG_DEBUG, "Pagefault on non-io side of a " "page-spanning MMIO: va=%#lx\n", addr); hvm_inject_exception(TRAP_page_fault, 0, addr); @@ -1319,24 +1321,30 @@ DEFINE_PER_CPU(int, guest_handles_in_xen this. */ unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len) { + int todo; + if ( this_cpu(guest_handles_in_xen_space) ) { memcpy(to, from, len); return 0; } - return hvm_copy_to_guest_virt((unsigned long)to, (void *)from, len); + hvm_copy_to_guest_virt((unsigned long)to, (void *)from, len, &todo); + return todo; } unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len) { + int todo; + if ( this_cpu(guest_handles_in_xen_space) ) { memcpy(to, from, len); return 0; } - return hvm_copy_from_guest_virt(to, (unsigned long)from, len); + hvm_copy_from_guest_virt(to, (unsigned long)from, len, &todo); + return todo; } /* diff -r 5e8068c541fc -r 874a20ac1ffd xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Thu Dec 27 21:55:38 2007 +0000 +++ b/xen/arch/x86/hvm/svm/svm.c Thu Dec 27 22:32:24 2007 +0000 @@ -1602,12 +1602,13 @@ static void svm_io_instruction(struct vc { if ( hvm_paging_enabled(current) ) { - int rv = hvm_copy_from_guest_virt(&value, addr, size); - if ( rv != 0 ) + int rv, todo; + rv = hvm_copy_from_guest_virt(&value, addr, size, &todo); + if ( rv == HVMCOPY_bad_gva_to_gfn ) { /* Failed on the page-spanning copy. Inject PF into * the guest for the address where we failed. */ - addr += size - rv; + addr += size - todo; gdprintk(XENLOG_DEBUG, "Pagefault reading non-io side " "of a page-spanning PIO: va=%#lx\n", addr); svm_hvm_inject_exception(TRAP_page_fault, 0, addr); @@ -2087,7 +2088,7 @@ static int svm_cr_access(struct vcpu *v, offset = ( addr_size == 4 ) ? offset : ( offset & 0xFFFF ); addr = hvm_get_segment_base(v, seg); addr += offset; - hvm_copy_to_guest_virt(addr,&value,2); + hvm_copy_to_guest_virt(addr, &value, 2, NULL); } else { @@ -2103,7 +2104,7 @@ static int svm_cr_access(struct vcpu *v, } __update_guest_eip(vmcb, inst_len); - + return result; } diff -r 5e8068c541fc -r 874a20ac1ffd xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Thu Dec 27 21:55:38 2007 +0000 +++ b/xen/arch/x86/hvm/vmx/vmx.c Thu Dec 27 22:32:24 2007 +0000 @@ -1718,12 +1718,13 @@ static void vmx_send_str_pio(struct cpu_ { if ( hvm_paging_enabled(current) ) { - int rv = hvm_copy_from_guest_virt(&value, addr, size); - if ( rv != 0 ) + int rv, todo; + rv = hvm_copy_from_guest_virt(&value, addr, size, &todo); + if ( rv == HVMCOPY_bad_gva_to_gfn ) { /* Failed on the page-spanning copy. Inject PF into * the guest for the address where we failed. */ - addr += size - rv; + addr += size - todo; gdprintk(XENLOG_DEBUG, "Pagefault reading non-io side " "of a page-spanning PIO: va=%#lx\n", addr); vmx_inject_exception(TRAP_page_fault, 0, addr); diff -r 5e8068c541fc -r 874a20ac1ffd xen/arch/x86/mm/shadow/common.c --- a/xen/arch/x86/mm/shadow/common.c Thu Dec 27 21:55:38 2007 +0000 +++ b/xen/arch/x86/mm/shadow/common.c Thu Dec 27 22:32:24 2007 +0000 @@ -204,7 +204,7 @@ hvm_read(enum x86_segment seg, struct sh_emulate_ctxt *sh_ctxt) { unsigned long addr; - int rc, errcode; + int rc, errcode, todo; rc = hvm_translate_linear_addr( seg, offset, bytes, access_type, sh_ctxt, &addr); @@ -216,8 +216,16 @@ hvm_read(enum x86_segment seg, // It entirely ignores the permissions in the page tables. // In this case, that is only a user vs supervisor access check. // - if ( (rc = hvm_copy_from_guest_virt(val, addr, bytes)) == 0 ) + rc = hvm_copy_from_guest_virt(val, addr, bytes, &todo); + switch ( rc ) + { + case HVMCOPY_okay: return X86EMUL_OKAY; + case HVMCOPY_bad_gva_to_gfn: + break; + default: + return X86EMUL_UNHANDLEABLE; + } /* If we got here, there was nothing mapped here, or a bad GFN * was mapped here. This should never happen: we're here because @@ -226,7 +234,7 @@ hvm_read(enum x86_segment seg, errcode = ring_3(sh_ctxt->ctxt.regs) ? PFEC_user_mode : 0; if ( access_type == hvm_access_insn_fetch ) errcode |= PFEC_insn_fetch; - hvm_inject_exception(TRAP_page_fault, errcode, addr + bytes - rc); + hvm_inject_exception(TRAP_page_fault, errcode, addr + bytes - todo); return X86EMUL_EXCEPTION; } @@ -458,7 +466,7 @@ struct x86_emulate_ops *shadow_init_emul x86_seg_cs, regs->eip, sizeof(sh_ctxt->insn_buf), hvm_access_insn_fetch, sh_ctxt, &addr) && !hvm_copy_from_guest_virt( - sh_ctxt->insn_buf, addr, sizeof(sh_ctxt->insn_buf))) + sh_ctxt->insn_buf, addr, sizeof(sh_ctxt->insn_buf), NULL)) ? sizeof(sh_ctxt->insn_buf) : 0; return &hvm_shadow_emulator_ops; @@ -486,7 +494,7 @@ void shadow_continue_emulation(struct sh x86_seg_cs, regs->eip, sizeof(sh_ctxt->insn_buf), hvm_access_insn_fetch, sh_ctxt, &addr) && !hvm_copy_from_guest_virt( - sh_ctxt->insn_buf, addr, sizeof(sh_ctxt->insn_buf))) + sh_ctxt->insn_buf, addr, sizeof(sh_ctxt->insn_buf), NULL)) ? sizeof(sh_ctxt->insn_buf) : 0; sh_ctxt->insn_buf_eip = regs->eip; } diff -r 5e8068c541fc -r 874a20ac1ffd xen/arch/x86/mm/shadow/multi.c --- a/xen/arch/x86/mm/shadow/multi.c Thu Dec 27 21:55:38 2007 +0000 +++ b/xen/arch/x86/mm/shadow/multi.c Thu Dec 27 22:32:24 2007 +0000 @@ -3954,10 +3954,13 @@ int sh_remove_l3_shadow(struct vcpu *v, /* Check that the user is allowed to perform this write. * Returns a mapped pointer to write to, and the mfn it's on, * or NULL for error. */ -static inline void * emulate_map_dest(struct vcpu *v, - unsigned long vaddr, - struct sh_emulate_ctxt *sh_ctxt, - mfn_t *mfnp) +#define MAPPING_UNHANDLEABLE ((void *)0) +#define MAPPING_EXCEPTION ((void *)1) +#define emulate_map_dest_failed(rc) ((unsigned long)(rc) <= 1) +static inline void *emulate_map_dest(struct vcpu *v, + unsigned long vaddr, + struct sh_emulate_ctxt *sh_ctxt, + mfn_t *mfnp) { walk_t gw; u32 flags, errcode; @@ -3966,7 +3969,7 @@ static inline void * emulate_map_dest(st /* We don't emulate user-mode writes to page tables */ if ( ring_3(sh_ctxt->ctxt.regs) ) - return NULL; + return MAPPING_UNHANDLEABLE; #if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) /* Try the virtual TLB first */ @@ -4019,14 +4022,14 @@ static inline void * emulate_map_dest(st return sh_map_domain_page(mfn) + (vaddr & ~PAGE_MASK); } else - return NULL; + return MAPPING_UNHANDLEABLE; page_fault: if ( is_hvm_vcpu(v) ) hvm_inject_exception(TRAP_page_fault, errcode, vaddr); else propagate_page_fault(vaddr, errcode); - return NULL; + return MAPPING_EXCEPTION; } static int safe_not_to_verify_write(mfn_t gmfn, void *dst, void *src, @@ -4071,8 +4074,10 @@ sh_x86_emulate_write(struct vcpu *v, uns ASSERT(shadow_locked_by_me(v->domain)); ASSERT(((vaddr & ~PAGE_MASK) + bytes) <= PAGE_SIZE); - if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL ) - return X86EMUL_EXCEPTION; + addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn); + if ( emulate_map_dest_failed(addr) ) + return ((addr == MAPPING_EXCEPTION) ? + X86EMUL_EXCEPTION : X86EMUL_UNHANDLEABLE); skip = safe_not_to_verify_write(mfn, addr, src, bytes); memcpy(addr, src, bytes); @@ -4107,8 +4112,10 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u if ( vaddr & (bytes-1) ) return X86EMUL_UNHANDLEABLE; - if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL ) - return X86EMUL_EXCEPTION; + addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn); + if ( emulate_map_dest_failed(addr) ) + return ((addr == MAPPING_EXCEPTION) ? + X86EMUL_EXCEPTION : X86EMUL_UNHANDLEABLE); skip = safe_not_to_verify_write(mfn, &new, &old, bytes); @@ -4163,8 +4170,10 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, if ( vaddr & 7 ) return X86EMUL_UNHANDLEABLE; - if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL ) - return X86EMUL_EXCEPTION; + addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn); + if ( emulate_map_dest_failed(addr) ) + return ((addr == MAPPING_EXCEPTION) ? + X86EMUL_EXCEPTION : X86EMUL_UNHANDLEABLE); old = (((u64) old_hi) << 32) | (u64) old_lo; new = (((u64) new_hi) << 32) | (u64) new_lo; diff -r 5e8068c541fc -r 874a20ac1ffd xen/include/asm-x86/hvm/support.h --- a/xen/include/asm-x86/hvm/support.h Thu Dec 27 21:55:38 2007 +0000 +++ b/xen/include/asm-x86/hvm/support.h Thu Dec 27 22:32:24 2007 +0000 @@ -219,10 +219,35 @@ void hvm_enable(struct hvm_function_tabl void hvm_enable(struct hvm_function_table *); void hvm_disable(void); -int hvm_copy_to_guest_phys(paddr_t paddr, void *buf, int size); -int hvm_copy_from_guest_phys(void *buf, paddr_t paddr, int size); -int hvm_copy_to_guest_virt(unsigned long vaddr, void *buf, int size); -int hvm_copy_from_guest_virt(void *buf, unsigned long vaddr, int size); +enum hvm_copy_result { + HVMCOPY_okay = 0, + HVMCOPY_bad_gva_to_gfn, + HVMCOPY_bad_gfn_to_mfn +}; + +/* + * Copy to/from a guest physical address. + * Returns HVMCOPY_okay, else HVMCOPY_bad_gfn_to_mfn if the given physical + * address range does not map entirely onto ordinary machine memory. + */ +enum hvm_copy_result hvm_copy_to_guest_phys( + paddr_t paddr, void *buf, int size); +enum hvm_copy_result hvm_copy_from_guest_phys( + void *buf, paddr_t paddr, int size); + +/* + * Copy to/from a guest virtual address. + * Returns: + * HVMCOPY_okay: Copy was entirely successful. + * HVMCOPY_bad_gfn_to_mfn: Some guest physical address did not map to + * ordinary machine memory. + * HVMCOPY_bad_gva_to_gfn: Some guest virtual address did not have a valid + * mapping to a guest physical address. + */ +enum hvm_copy_result hvm_copy_to_guest_virt( + unsigned long vaddr, void *buf, int size, int *ptodo); +enum hvm_copy_result hvm_copy_from_guest_virt( + void *buf, unsigned long vaddr, int size, int *ptodo); void hvm_print_line(struct vcpu *v, const char c); void hlt_timer_fn(void *data); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |