aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-08-19 15:56:31 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-08-19 15:56:31 +0100
commit5dfe4aa4eeb6a4f49c4e90b378c6dea5bd99dc1c (patch)
tree3ef11c8d79d45fc97df7c3ad6aa9fc2245295b4a
parent154ef9e3cc7bb902df177d4942f5af53da7af67b (diff)
downloadxen-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.c17
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,