aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/emulate.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-08-26 14:10:17 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-08-26 14:10:17 +0100
commit81abef044859ef503a13d567ede25d8bf3875844 (patch)
treef869921e0b188598985b7b9ff3bfd898ddde667d /xen/arch/x86/hvm/emulate.c
parentd6b6a1137f3b4183ae6deaf89c8e50426742ffb3 (diff)
downloadxen-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.c29
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(