From: Keir Fraser Date: Tue, 19 Aug 2008 14:56:31 +0000 (+0100) Subject: x86_emulate: Do not request emulation of REP instructions beyond the X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14144 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=5dfe4aa4eeb6a4f49c4e90b378c6dea5bd99dc1c;p=xen.git x86_emulate: Do not request emulation of REP instructions beyond the point at which the index register (SI/DI) wraps. This can cause a discontinuity in the address range accessed by the repeated instruction. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 6fc1955783..b307114dba 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -681,6 +681,15 @@ static void __put_rep_prefix( __put_rep_prefix(&_regs, ctxt->regs, ad_bytes, reps_completed); \ }) +/* Clip maximum repetitions so that the index register only just wraps. */ +#define truncate_ea_and_reps(ea, reps, bytes_per_rep) ({ \ + unsigned long __todo = (ctxt->regs->eflags & EF_DF) ? (ea) : ~(ea); \ + __todo = truncate_word(__todo, ad_bytes); \ + __todo = (__todo / (bytes_per_rep)) + 1; \ + (reps) = (__todo < (reps)) ? __todo : (reps); \ + truncate_word((ea), ad_bytes); \ +}) + /* Compatibility function: read guest memory, zero-extend result to a ulong. */ static int read_ulong( enum x86_segment seg, @@ -2385,7 +2394,7 @@ x86_emulate( unsigned int port = (uint16_t)_regs.edx; dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes; dst.mem.seg = x86_seg_es; - dst.mem.off = truncate_ea(_regs.edi); + dst.mem.off = truncate_ea_and_reps(_regs.edi, nr_reps, dst.bytes); if ( (rc = ioport_access_check(port, dst.bytes, ctxt, ops)) != 0 ) goto done; if ( (nr_reps > 1) && (ops->rep_ins != NULL) && @@ -2414,11 +2423,11 @@ x86_emulate( unsigned long nr_reps = get_rep_prefix(); unsigned int port = (uint16_t)_regs.edx; dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes; + ea.mem.off = truncate_ea_and_reps(_regs.esi, nr_reps, dst.bytes); if ( (rc = ioport_access_check(port, dst.bytes, ctxt, ops)) != 0 ) goto done; if ( (nr_reps > 1) && (ops->rep_outs != NULL) && - ((rc = ops->rep_outs(ea.mem.seg, truncate_ea(_regs.esi), - port, dst.bytes, + ((rc = ops->rep_outs(ea.mem.seg, ea.mem.off, port, dst.bytes, &nr_reps, ctxt)) != X86EMUL_UNHANDLEABLE) ) { if ( rc != 0 ) @@ -2569,7 +2578,7 @@ x86_emulate( unsigned long nr_reps = get_rep_prefix(); dst.bytes = (d & ByteOp) ? 1 : op_bytes; dst.mem.seg = x86_seg_es; - dst.mem.off = truncate_ea(_regs.edi); + dst.mem.off = truncate_ea_and_reps(_regs.edi, nr_reps, dst.bytes); if ( (nr_reps > 1) && (ops->rep_movs != NULL) && ((rc = ops->rep_movs(ea.mem.seg, truncate_ea(_regs.esi), dst.mem.seg, dst.mem.off, dst.bytes,