diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-08-26 14:10:17 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-08-26 14:10:17 +0100 |
commit | 81abef044859ef503a13d567ede25d8bf3875844 (patch) | |
tree | f869921e0b188598985b7b9ff3bfd898ddde667d /xen/arch/x86/hvm/emulate.c | |
parent | d6b6a1137f3b4183ae6deaf89c8e50426742ffb3 (diff) | |
download | xen-81abef044859ef503a13d567ede25d8bf3875844.tar.gz xen-81abef044859ef503a13d567ede25d8bf3875844.tar.bz2 xen-81abef044859ef503a13d567ede25d8bf3875844.zip |
x86 hvm: Emulate RAM-to-RAM REP MOVS copies efficiently.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/hvm/emulate.c')
-rw-r--r-- | xen/arch/x86/hvm/emulate.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index 86ad14bc93..7761fb856b 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -575,7 +575,8 @@ static int hvmemul_rep_movs( paddr_t sgpa, dgpa; uint32_t pfec = PFEC_page_present; p2m_type_t p2mt; - int rc; + int rc, df = !!(ctxt->regs->eflags & X86_EFLAGS_DF); + char *buf; rc = hvmemul_virtual_to_linear( src_seg, src_offset, bytes_per_rep, reps, hvm_access_read, @@ -606,15 +607,29 @@ static int hvmemul_rep_movs( (void)gfn_to_mfn_current(sgpa >> PAGE_SHIFT, &p2mt); if ( !p2m_is_ram(p2mt) ) return hvmemul_do_mmio( - sgpa, reps, bytes_per_rep, dgpa, IOREQ_READ, - !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL); + sgpa, reps, bytes_per_rep, dgpa, IOREQ_READ, df, NULL); (void)gfn_to_mfn_current(dgpa >> PAGE_SHIFT, &p2mt); - if ( p2m_is_ram(p2mt) ) + if ( !p2m_is_ram(p2mt) ) + return hvmemul_do_mmio( + dgpa, reps, bytes_per_rep, sgpa, IOREQ_WRITE, df, NULL); + + if ( df ) + { + sgpa -= (*reps - 1) * bytes_per_rep; + dgpa -= (*reps - 1) * bytes_per_rep; + } + + buf = xmalloc_bytes(*reps * bytes_per_rep); + if ( buf == NULL ) return X86EMUL_UNHANDLEABLE; - return hvmemul_do_mmio( - dgpa, reps, bytes_per_rep, sgpa, IOREQ_WRITE, - !!(ctxt->regs->eflags & X86_EFLAGS_DF), NULL); + + hvm_copy_from_guest_phys(buf, sgpa, *reps * bytes_per_rep); + hvm_copy_to_guest_phys(dgpa, buf, *reps * bytes_per_rep); + + xfree(buf); + + return X86EMUL_OKAY; } static int hvmemul_read_segment( |