diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-08-19 15:56:31 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-08-19 15:56:31 +0100 |
commit | 5dfe4aa4eeb6a4f49c4e90b378c6dea5bd99dc1c (patch) | |
tree | 3ef11c8d79d45fc97df7c3ad6aa9fc2245295b4a | |
parent | 154ef9e3cc7bb902df177d4942f5af53da7af67b (diff) | |
download | xen-5dfe4aa4eeb6a4f49c4e90b378c6dea5bd99dc1c.tar.gz xen-5dfe4aa4eeb6a4f49c4e90b378c6dea5bd99dc1c.tar.bz2 xen-5dfe4aa4eeb6a4f49c4e90b378c6dea5bd99dc1c.zip |
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 <keir.fraser@citrix.com>
-rw-r--r-- | xen/arch/x86/x86_emulate/x86_emulate.c | 17 |
1 files changed, 13 insertions, 4 deletions
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, |