aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-01-22 19:26:52 +0000
committerKeir Fraser <keir.fraser@citrix.com>2008-01-22 19:26:52 +0000
commit46e8f7315381ca0a03a4ae94aec2d0fd3243d761 (patch)
treec85c5a8fdc32cc658794ffd7914a006de0564404
parenta258e82cda3a6d501dbf542343bf84c80e31af95 (diff)
parent4d7db972d7d1ac08c5c3d86404e2de07d53ee77a (diff)
downloadxen-46e8f7315381ca0a03a4ae94aec2d0fd3243d761.tar.gz
xen-46e8f7315381ca0a03a4ae94aec2d0fd3243d761.tar.bz2
xen-46e8f7315381ca0a03a4ae94aec2d0fd3243d761.zip
Merge with ia64 tree
-rw-r--r--xen/arch/x86/Rules.mk2
-rw-r--r--xen/arch/x86/hvm/vmx/realmode.c60
-rw-r--r--xen/arch/x86/x86_emulate.c159
-rw-r--r--xen/include/asm-x86/x86_emulate.h43
4 files changed, 219 insertions, 45 deletions
diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk
index 1925c2f1b9..ac66c253ca 100644
--- a/xen/arch/x86/Rules.mk
+++ b/xen/arch/x86/Rules.mk
@@ -11,7 +11,7 @@ xenoprof := y
#
pae ?= n
supervisor_mode_kernel ?= n
-vmxassist ?= y
+vmxassist ?= n
ifeq ($(vmxassist),y)
CFLAGS += -DVMXASSIST
diff --git a/xen/arch/x86/hvm/vmx/realmode.c b/xen/arch/x86/hvm/vmx/realmode.c
index a7f767926e..39b1fdb590 100644
--- a/xen/arch/x86/hvm/vmx/realmode.c
+++ b/xen/arch/x86/hvm/vmx/realmode.c
@@ -223,6 +223,64 @@ realmode_emulate_cmpxchg(
return realmode_emulate_write(seg, offset, new, bytes, ctxt);
}
+static int
+realmode_rep_ins(
+ uint16_t src_port,
+ enum x86_segment dst_seg,
+ unsigned long dst_offset,
+ unsigned int bytes_per_rep,
+ unsigned long *reps,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct realmode_emulate_ctxt *rm_ctxt =
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
+ struct vcpu *curr = current;
+ uint32_t paddr = rm_ctxt->seg_reg[dst_seg].base + dst_offset;
+
+ if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+ return X86EMUL_UNHANDLEABLE;
+
+ if ( !curr->arch.hvm_vmx.real_mode_io_completed )
+ {
+ curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
+ send_pio_req(src_port, *reps, bytes_per_rep,
+ paddr, IOREQ_READ,
+ !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
+ }
+
+ if ( !curr->arch.hvm_vmx.real_mode_io_completed )
+ return X86EMUL_RETRY;
+
+ curr->arch.hvm_vmx.real_mode_io_completed = 0;
+
+ return X86EMUL_OKAY;
+}
+
+static int
+realmode_rep_outs(
+ enum x86_segment src_seg,
+ unsigned long src_offset,
+ uint16_t dst_port,
+ unsigned int bytes_per_rep,
+ unsigned long *reps,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct realmode_emulate_ctxt *rm_ctxt =
+ container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
+ struct vcpu *curr = current;
+ uint32_t paddr = rm_ctxt->seg_reg[src_seg].base + src_offset;
+
+ if ( curr->arch.hvm_vmx.real_mode_io_in_progress )
+ return X86EMUL_UNHANDLEABLE;
+
+ curr->arch.hvm_vmx.real_mode_io_in_progress = 1;
+ send_pio_req(dst_port, *reps, bytes_per_rep,
+ paddr, IOREQ_WRITE,
+ !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
+
+ return X86EMUL_OKAY;
+}
+
static int
realmode_read_segment(
enum x86_segment seg,
@@ -420,6 +478,8 @@ static struct x86_emulate_ops realmode_emulator_ops = {
.insn_fetch = realmode_emulate_insn_fetch,
.write = realmode_emulate_write,
.cmpxchg = realmode_emulate_cmpxchg,
+ .rep_ins = realmode_rep_ins,
+ .rep_outs = realmode_rep_outs,
.read_segment = realmode_read_segment,
.write_segment = realmode_write_segment,
.read_io = realmode_read_io,
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c
index c1116017db..4c6f2e5125 100644
--- a/xen/arch/x86/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate.c
@@ -552,7 +552,7 @@ do { \
? (uint16_t)_regs.eip : (uint32_t)_regs.eip); \
} while (0)
-static int __handle_rep_prefix(
+static unsigned long __get_rep_prefix(
struct cpu_user_regs *int_regs,
struct cpu_user_regs *ext_regs,
int ad_bytes)
@@ -561,11 +561,36 @@ static int __handle_rep_prefix(
(ad_bytes == 4) ? (uint32_t)int_regs->ecx :
int_regs->ecx);
- if ( ecx-- == 0 )
- {
+ /* Skip the instruction if no repetitions are required. */
+ if ( ecx == 0 )
ext_regs->eip = int_regs->eip;
- return 1;
- }
+
+ return ecx;
+}
+
+#define get_rep_prefix() ({ \
+ unsigned long max_reps = 1; \
+ if ( rep_prefix ) \
+ max_reps = __get_rep_prefix(&_regs, ctxt->regs, ad_bytes); \
+ if ( max_reps == 0 ) \
+ goto done; \
+ max_reps; \
+})
+
+static void __put_rep_prefix(
+ struct cpu_user_regs *int_regs,
+ struct cpu_user_regs *ext_regs,
+ int ad_bytes,
+ unsigned long reps_completed)
+{
+ unsigned long ecx = ((ad_bytes == 2) ? (uint16_t)int_regs->ecx :
+ (ad_bytes == 4) ? (uint32_t)int_regs->ecx :
+ int_regs->ecx);
+
+ /* Reduce counter appropriately, and repeat instruction if non-zero. */
+ ecx -= reps_completed;
+ if ( ecx != 0 )
+ int_regs->eip = ext_regs->eip;
if ( ad_bytes == 2 )
*(uint16_t *)&int_regs->ecx = ecx;
@@ -573,15 +598,12 @@ static int __handle_rep_prefix(
int_regs->ecx = (uint32_t)ecx;
else
int_regs->ecx = ecx;
- int_regs->eip = ext_regs->eip;
- return 0;
}
-#define handle_rep_prefix() \
-do { \
- if ( rep_prefix && __handle_rep_prefix(&_regs, ctxt->regs, ad_bytes) ) \
- goto done; \
-} while (0)
+#define put_rep_prefix(reps_completed) ({ \
+ if ( rep_prefix ) \
+ __put_rep_prefix(&_regs, ctxt->regs, ad_bytes, reps_completed); \
+})
/*
* Unsigned multiplication with double-word result.
@@ -2051,35 +2073,63 @@ x86_emulate(
dst.mem.off = sp_pre_dec(dst.bytes);
break;
- case 0x6c ... 0x6d: /* ins %dx,%es:%edi */
- handle_rep_prefix();
+ case 0x6c ... 0x6d: /* ins %dx,%es:%edi */ {
+ unsigned long nr_reps = get_rep_prefix();
generate_exception_if(!mode_iopl(), EXC_GP);
- dst.type = OP_MEM;
dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
dst.mem.seg = x86_seg_es;
dst.mem.off = truncate_ea(_regs.edi);
- fail_if(ops->read_io == NULL);
- if ( (rc = ops->read_io((uint16_t)_regs.edx, dst.bytes,
- &dst.val, ctxt)) != 0 )
- goto done;
+ if ( (nr_reps > 1) && (ops->rep_ins != NULL) )
+ {
+ if ( (rc = ops->rep_ins((uint16_t)_regs.edx, dst.mem.seg,
+ dst.mem.off, dst.bytes,
+ &nr_reps, ctxt)) != 0 )
+ goto done;
+ }
+ else
+ {
+ fail_if(ops->read_io == NULL);
+ if ( (rc = ops->read_io((uint16_t)_regs.edx, dst.bytes,
+ &dst.val, ctxt)) != 0 )
+ goto done;
+ dst.type = OP_MEM;
+ nr_reps = 1;
+ }
register_address_increment(
- _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ _regs.edi,
+ nr_reps * ((_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes));
+ put_rep_prefix(nr_reps);
break;
+ }
- case 0x6e ... 0x6f: /* outs %esi,%dx */
- handle_rep_prefix();
+ case 0x6e ... 0x6f: /* outs %esi,%dx */ {
+ unsigned long nr_reps = get_rep_prefix();
generate_exception_if(!mode_iopl(), EXC_GP);
dst.bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
- if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
- &dst.val, dst.bytes, ctxt)) != 0 )
- goto done;
- fail_if(ops->write_io == NULL);
- if ( (rc = ops->write_io((uint16_t)_regs.edx, dst.bytes,
- dst.val, ctxt)) != 0 )
- goto done;
+ if ( (nr_reps > 1) && (ops->rep_outs != NULL) )
+ {
+ if ( (rc = ops->rep_outs(ea.mem.seg, truncate_ea(_regs.esi),
+ (uint16_t)_regs.edx, dst.bytes,
+ &nr_reps, ctxt)) != 0 )
+ goto done;
+ }
+ else
+ {
+ if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
+ &dst.val, dst.bytes, ctxt)) != 0 )
+ goto done;
+ fail_if(ops->write_io == NULL);
+ if ( (rc = ops->write_io((uint16_t)_regs.edx, dst.bytes,
+ dst.val, ctxt)) != 0 )
+ goto done;
+ nr_reps = 1;
+ }
register_address_increment(
- _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ _regs.esi,
+ nr_reps * ((_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes));
+ put_rep_prefix(nr_reps);
break;
+ }
case 0x70 ... 0x7f: /* jcc (short) */ {
int rel = insn_fetch_type(int8_t);
@@ -2202,24 +2252,39 @@ x86_emulate(
dst.val = (unsigned long)_regs.eax;
break;
- case 0xa4 ... 0xa5: /* movs */
- handle_rep_prefix();
- dst.type = OP_MEM;
+ case 0xa4 ... 0xa5: /* movs */ {
+ 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);
- if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
- &dst.val, dst.bytes, ctxt)) != 0 )
- goto done;
+ if ( (nr_reps > 1) && (ops->rep_movs != NULL) )
+ {
+ if ( (rc = ops->rep_movs(ea.mem.seg, truncate_ea(_regs.esi),
+ dst.mem.seg, dst.mem.off, dst.bytes,
+ &nr_reps, ctxt)) != 0 )
+ goto done;
+ }
+ else
+ {
+ if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
+ &dst.val, dst.bytes, ctxt)) != 0 )
+ goto done;
+ dst.type = OP_MEM;
+ nr_reps = 1;
+ }
register_address_increment(
- _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ _regs.esi,
+ nr_reps * ((_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes));
register_address_increment(
- _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ _regs.edi,
+ nr_reps * ((_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes));
+ put_rep_prefix(nr_reps);
break;
+ }
case 0xa6 ... 0xa7: /* cmps */ {
unsigned long next_eip = _regs.eip;
- handle_rep_prefix();
+ get_rep_prefix();
src.bytes = dst.bytes = (d & ByteOp) ? 1 : op_bytes;
if ( (rc = ops->read(ea.mem.seg, truncate_ea(_regs.esi),
&dst.val, dst.bytes, ctxt)) ||
@@ -2230,6 +2295,7 @@ x86_emulate(
_regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
register_address_increment(
_regs.edi, (_regs.eflags & EFLG_DF) ? -src.bytes : src.bytes);
+ put_rep_prefix(1);
/* cmp: dst - src ==> src=*%%edi,dst=*%%esi ==> *%%esi - *%%edi */
emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
if ( ((rep_prefix == REPE_PREFIX) && !(_regs.eflags & EFLG_ZF)) ||
@@ -2238,8 +2304,8 @@ x86_emulate(
break;
}
- case 0xaa ... 0xab: /* stos */
- handle_rep_prefix();
+ case 0xaa ... 0xab: /* stos */ {
+ /* unsigned long max_reps = */get_rep_prefix();
dst.type = OP_MEM;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.mem.seg = x86_seg_es;
@@ -2247,10 +2313,12 @@ x86_emulate(
dst.val = _regs.eax;
register_address_increment(
_regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ put_rep_prefix(1);
break;
+ }
- case 0xac ... 0xad: /* lods */
- handle_rep_prefix();
+ case 0xac ... 0xad: /* lods */ {
+ /* unsigned long max_reps = */get_rep_prefix();
dst.type = OP_REG;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.reg = (unsigned long *)&_regs.eax;
@@ -2259,11 +2327,13 @@ x86_emulate(
goto done;
register_address_increment(
_regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
+ put_rep_prefix(1);
break;
+ }
case 0xae ... 0xaf: /* scas */ {
unsigned long next_eip = _regs.eip;
- handle_rep_prefix();
+ get_rep_prefix();
src.bytes = dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.val = _regs.eax;
if ( (rc = ops->read(x86_seg_es, truncate_ea(_regs.edi),
@@ -2271,6 +2341,7 @@ x86_emulate(
goto done;
register_address_increment(
_regs.edi, (_regs.eflags & EFLG_DF) ? -src.bytes : src.bytes);
+ put_rep_prefix(1);
/* cmp: dst - src ==> src=*%%edi,dst=%%eax ==> %%eax - *%%edi */
emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
if ( ((rep_prefix == REPE_PREFIX) && !(_regs.eflags & EFLG_ZF)) ||
diff --git a/xen/include/asm-x86/x86_emulate.h b/xen/include/asm-x86/x86_emulate.h
index 2de071bd7f..a794e03d6f 100644
--- a/xen/include/asm-x86/x86_emulate.h
+++ b/xen/include/asm-x86/x86_emulate.h
@@ -175,6 +175,49 @@ struct x86_emulate_ops
struct x86_emulate_ctxt *ctxt);
/*
+ * rep_ins: Emulate INS: <src_port> -> <dst_seg:dst_offset>.
+ * @bytes_per_rep: [IN ] Bytes transferred per repetition.
+ * @reps: [IN ] Maximum repetitions to be emulated.
+ * [OUT] Number of repetitions actually emulated.
+ */
+ int (*rep_ins)(
+ uint16_t src_port,
+ enum x86_segment dst_seg,
+ unsigned long dst_offset,
+ unsigned int bytes_per_rep,
+ unsigned long *reps,
+ struct x86_emulate_ctxt *ctxt);
+
+ /*
+ * rep_outs: Emulate OUTS: <src_seg:src_offset> -> <dst_port>.
+ * @bytes_per_rep: [IN ] Bytes transferred per repetition.
+ * @reps: [IN ] Maximum repetitions to be emulated.
+ * [OUT] Number of repetitions actually emulated.
+ */
+ int (*rep_outs)(
+ enum x86_segment src_seg,
+ unsigned long src_offset,
+ uint16_t dst_port,
+ unsigned int bytes_per_rep,
+ unsigned long *reps,
+ struct x86_emulate_ctxt *ctxt);
+
+ /*
+ * rep_movs: Emulate MOVS: <src_seg:src_offset> -> <dst_seg:dst_offset>.
+ * @bytes_per_rep: [IN ] Bytes transferred per repetition.
+ * @reps: [IN ] Maximum repetitions to be emulated.
+ * [OUT] Number of repetitions actually emulated.
+ */
+ int (*rep_movs)(
+ enum x86_segment src_seg,
+ unsigned long src_offset,
+ enum x86_segment dst_seg,
+ unsigned long dst_offset,
+ unsigned int bytes_per_rep,
+ unsigned long *reps,
+ struct x86_emulate_ctxt *ctxt);
+
+ /*
* read_segment: Emulate a read of full context of a segment register.
* @reg: [OUT] Contents of segment register (visible and hidden state).
*/