diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2007-11-26 17:54:54 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2007-11-26 17:54:54 +0000 |
commit | 70d9b1077f1a4586092851badeca60703b57eccf (patch) | |
tree | b2c658c67ebe08114b2d6b30ae25eaf66a72e4f7 /xen/arch/x86/x86_emulate.c | |
parent | a209260781bec2fa050c0ed9f38171373e8d81a2 (diff) | |
download | xen-70d9b1077f1a4586092851badeca60703b57eccf.tar.gz xen-70d9b1077f1a4586092851badeca60703b57eccf.tar.bz2 xen-70d9b1077f1a4586092851badeca60703b57eccf.zip |
x86_emulate: Emulate LMSW and SMSW.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/x86_emulate.c')
-rw-r--r-- | xen/arch/x86/x86_emulate.c | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 1397732a7f..763d73774f 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -2666,6 +2666,7 @@ x86_emulate( { case 0x01: /* Grp7 */ { struct segment_register reg; + unsigned long base, limit, cr0, cr0w; switch ( modrm_reg & 7 ) { @@ -2691,11 +2692,12 @@ x86_emulate( fail_if(ops->write_segment == NULL); memset(®, 0, sizeof(reg)); if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, - (unsigned long *)®.limit, 2, ctxt)) || + &limit, 2, ctxt)) || (rc = ops->read(ea.mem.seg, ea.mem.off+2, - (unsigned long *)®.base, - mode_64bit() ? 8 : 4, ctxt)) ) + &base, mode_64bit() ? 8 : 4, ctxt)) ) goto done; + reg.base = base; + reg.limit = limit; if ( op_bytes == 2 ) reg.base &= 0xffffff; if ( (rc = ops->write_segment((modrm_reg & 1) ? @@ -2703,6 +2705,29 @@ x86_emulate( ®, ctxt)) ) goto done; break; + case 4: /* smsw */ + dst = ea; + dst.bytes = 2; + fail_if(ops->read_cr == NULL); + if ( (rc = ops->read_cr(0, &dst.val, ctxt)) ) + goto done; + d |= Mov; /* force writeback */ + break; + case 6: /* lmsw */ + fail_if(ops->read_cr == NULL); + fail_if(ops->write_cr == NULL); + if ( (rc = ops->read_cr(0, &cr0, ctxt)) ) + goto done; + if ( ea.type == OP_REG ) + cr0w = *ea.reg; + else if ( (rc = ops->read(ea.mem.seg, ea.mem.off, + &cr0w, 2, ctxt)) ) + goto done; + cr0 &= 0xffff0000; + cr0 |= (uint16_t)cr0w; + if ( (rc = ops->write_cr(0, cr0, ctxt)) ) + goto done; + break; default: goto cannot_emulate; } |