[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86_emulate: Support CMPXCHG16B.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1208871256 -3600 # Node ID 6271ba3bb4b63b10b94301a6e22f421b9b36dfa3 # Parent ee2f56063f5c6442b60de439b8a204076409b461 x86_emulate: Support CMPXCHG16B. Also clean up cmpxchg() callback handling so we can get rid of teh specific cmpxchg8b handler. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx> Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- tools/tests/test_x86_emulator.c | 48 ++-------------- xen/arch/x86/hvm/emulate.c | 8 ++ xen/arch/x86/mm.c | 26 ++------- xen/arch/x86/mm/shadow/common.c | 94 +++++++++++++-------------------- xen/arch/x86/mm/shadow/multi.c | 11 ++- xen/arch/x86/x86_emulate/x86_emulate.c | 85 +++++++++++++---------------- xen/arch/x86/x86_emulate/x86_emulate.h | 33 ++--------- xen/include/asm-x86/paging.h | 2 8 files changed, 111 insertions(+), 196 deletions(-) diff -r ee2f56063f5c -r 6271ba3bb4b6 tools/tests/test_x86_emulator.c --- a/tools/tests/test_x86_emulator.c Tue Apr 22 11:46:41 2008 +0100 +++ b/tools/tests/test_x86_emulator.c Tue Apr 22 14:34:16 2008 +0100 @@ -26,14 +26,8 @@ static int read( unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - unsigned long addr = offset; - switch ( bytes ) - { - case 1: *val = *(uint8_t *)addr; break; - case 2: *val = *(uint16_t *)addr; break; - case 4: *val = *(uint32_t *)addr; break; - case 8: *val = *(unsigned long *)addr; break; - } + *val = 0; + memcpy(val, (void *)offset, bytes); return X86EMUL_OKAY; } @@ -44,48 +38,19 @@ static int write( unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - unsigned long addr = offset; - switch ( bytes ) - { - case 1: *(uint8_t *)addr = (uint8_t)val; break; - case 2: *(uint16_t *)addr = (uint16_t)val; break; - case 4: *(uint32_t *)addr = (uint32_t)val; break; - case 8: *(unsigned long *)addr = val; break; - } + memcpy((void *)offset, &val, bytes); return X86EMUL_OKAY; } static int cmpxchg( unsigned int seg, unsigned long offset, - unsigned long old, - unsigned long new, + void *old, + void *new, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - unsigned long addr = offset; - switch ( bytes ) - { - case 1: *(uint8_t *)addr = (uint8_t)new; break; - case 2: *(uint16_t *)addr = (uint16_t)new; break; - case 4: *(uint32_t *)addr = (uint32_t)new; break; - case 8: *(unsigned long *)addr = new; break; - } - return X86EMUL_OKAY; -} - -static int cmpxchg8b( - unsigned int seg, - unsigned long offset, - unsigned long old_lo, - unsigned long old_hi, - unsigned long new_lo, - unsigned long new_hi, - struct x86_emulate_ctxt *ctxt) -{ - unsigned long addr = offset; - ((unsigned long *)addr)[0] = new_lo; - ((unsigned long *)addr)[1] = new_hi; + memcpy((void *)offset, new, bytes); return X86EMUL_OKAY; } @@ -94,7 +59,6 @@ static struct x86_emulate_ops emulops = .insn_fetch = read, .write = write, .cmpxchg = cmpxchg, - .cmpxchg8b = cmpxchg8b }; int main(int argc, char **argv) diff -r ee2f56063f5c -r 6271ba3bb4b6 xen/arch/x86/hvm/emulate.c --- a/xen/arch/x86/hvm/emulate.c Tue Apr 22 11:46:41 2008 +0100 +++ b/xen/arch/x86/hvm/emulate.c Tue Apr 22 14:34:16 2008 +0100 @@ -437,11 +437,15 @@ static int hvmemul_cmpxchg( static int hvmemul_cmpxchg( enum x86_segment seg, unsigned long offset, - unsigned long old, - unsigned long new, + void *p_old, + void *p_new, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { + unsigned long new = 0; + if ( bytes > sizeof(new) ) + return X86EMUL_UNHANDLEABLE; + memcpy(&new, p_new, bytes); /* Fix this in case the guest is really relying on r-m-w atomicity. */ return hvmemul_write(seg, offset, new, bytes, ctxt); } diff -r ee2f56063f5c -r 6271ba3bb4b6 xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Tue Apr 22 11:46:41 2008 +0100 +++ b/xen/arch/x86/mm.c Tue Apr 22 14:34:16 2008 +0100 @@ -3616,29 +3616,18 @@ static int ptwr_emulated_cmpxchg( static int ptwr_emulated_cmpxchg( enum x86_segment seg, unsigned long offset, - unsigned long old, - unsigned long new, + void *p_old, + void *p_new, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { + paddr_t old = 0, new = 0; + if ( bytes > sizeof(paddr_t) ) + return X86EMUL_UNHANDLEABLE; + memcpy(&old, p_old, bytes); + memcpy(&new, p_new, bytes); return ptwr_emulated_update( offset, old, new, bytes, 1, - container_of(ctxt, struct ptwr_emulate_ctxt, ctxt)); -} - -static int ptwr_emulated_cmpxchg8b( - enum x86_segment seg, - unsigned long offset, - unsigned long old, - unsigned long old_hi, - unsigned long new, - unsigned long new_hi, - struct x86_emulate_ctxt *ctxt) -{ - if ( CONFIG_PAGING_LEVELS == 2 ) - return X86EMUL_UNHANDLEABLE; - return ptwr_emulated_update( - offset, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1, container_of(ctxt, struct ptwr_emulate_ctxt, ctxt)); } @@ -3647,7 +3636,6 @@ static struct x86_emulate_ops ptwr_emula .insn_fetch = ptwr_emulated_read, .write = ptwr_emulated_write, .cmpxchg = ptwr_emulated_cmpxchg, - .cmpxchg8b = ptwr_emulated_cmpxchg8b }; /* Write page fault handler: check if guest is trying to modify a PTE. */ diff -r ee2f56063f5c -r 6271ba3bb4b6 xen/arch/x86/mm/shadow/common.c --- a/xen/arch/x86/mm/shadow/common.c Tue Apr 22 11:46:41 2008 +0100 +++ b/xen/arch/x86/mm/shadow/common.c Tue Apr 22 14:34:16 2008 +0100 @@ -239,15 +239,15 @@ static int static int hvm_emulate_cmpxchg(enum x86_segment seg, unsigned long offset, - unsigned long old, - unsigned long new, + void *p_old, + void *p_new, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { struct sh_emulate_ctxt *sh_ctxt = container_of(ctxt, struct sh_emulate_ctxt, ctxt); struct vcpu *v = current; - unsigned long addr; + unsigned long addr, old[2], new[2]; int rc; if ( !is_x86_user_segment(seg) ) @@ -258,35 +258,21 @@ hvm_emulate_cmpxchg(enum x86_segment seg if ( rc ) return rc; - return v->arch.paging.mode->shadow.x86_emulate_cmpxchg( - v, addr, old, new, bytes, sh_ctxt); -} - -static int -hvm_emulate_cmpxchg8b(enum x86_segment seg, - unsigned long offset, - unsigned long old_lo, - unsigned long old_hi, - unsigned long new_lo, - unsigned long new_hi, - struct x86_emulate_ctxt *ctxt) -{ - struct sh_emulate_ctxt *sh_ctxt = - container_of(ctxt, struct sh_emulate_ctxt, ctxt); - struct vcpu *v = current; - unsigned long addr; - int rc; - - if ( !is_x86_user_segment(seg) ) - return X86EMUL_UNHANDLEABLE; - - rc = hvm_translate_linear_addr( - seg, offset, 8, hvm_access_write, sh_ctxt, &addr); - if ( rc ) - return rc; - - return v->arch.paging.mode->shadow.x86_emulate_cmpxchg8b( - v, addr, old_lo, old_hi, new_lo, new_hi, sh_ctxt); + old[0] = new[0] = 0; + memcpy(old, p_old, bytes); + memcpy(new, p_new, bytes); + + if ( bytes <= sizeof(long) ) + return v->arch.paging.mode->shadow.x86_emulate_cmpxchg( + v, addr, old[0], new[0], bytes, sh_ctxt); + +#ifdef __i386__ + if ( bytes == 8 ) + return v->arch.paging.mode->shadow.x86_emulate_cmpxchg8b( + v, addr, old[0], old[1], new[0], new[1], sh_ctxt); +#endif + + return X86EMUL_UNHANDLEABLE; } static struct x86_emulate_ops hvm_shadow_emulator_ops = { @@ -294,7 +280,6 @@ static struct x86_emulate_ops hvm_shadow .insn_fetch = hvm_emulate_insn_fetch, .write = hvm_emulate_write, .cmpxchg = hvm_emulate_cmpxchg, - .cmpxchg8b = hvm_emulate_cmpxchg8b, }; static int @@ -338,36 +323,34 @@ static int static int pv_emulate_cmpxchg(enum x86_segment seg, unsigned long offset, - unsigned long old, - unsigned long new, + void *p_old, + void *p_new, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { struct sh_emulate_ctxt *sh_ctxt = container_of(ctxt, struct sh_emulate_ctxt, ctxt); + unsigned long old[2], new[2]; struct vcpu *v = current; + if ( !is_x86_user_segment(seg) ) return X86EMUL_UNHANDLEABLE; - return v->arch.paging.mode->shadow.x86_emulate_cmpxchg( - v, offset, old, new, bytes, sh_ctxt); -} - -static int -pv_emulate_cmpxchg8b(enum x86_segment seg, - unsigned long offset, - unsigned long old_lo, - unsigned long old_hi, - unsigned long new_lo, - unsigned long new_hi, - struct x86_emulate_ctxt *ctxt) -{ - struct sh_emulate_ctxt *sh_ctxt = - container_of(ctxt, struct sh_emulate_ctxt, ctxt); - struct vcpu *v = current; - if ( !is_x86_user_segment(seg) ) - return X86EMUL_UNHANDLEABLE; - return v->arch.paging.mode->shadow.x86_emulate_cmpxchg8b( - v, offset, old_lo, old_hi, new_lo, new_hi, sh_ctxt); + + old[0] = new[0] = 0; + memcpy(old, p_old, bytes); + memcpy(new, p_new, bytes); + + if ( bytes <= sizeof(long) ) + return v->arch.paging.mode->shadow.x86_emulate_cmpxchg( + v, offset, old[0], new[0], bytes, sh_ctxt); + +#ifdef __i386__ + if ( bytes == 8 ) + return v->arch.paging.mode->shadow.x86_emulate_cmpxchg8b( + v, offset, old[0], old[1], new[0], new[1], sh_ctxt); +#endif + + return X86EMUL_UNHANDLEABLE; } static struct x86_emulate_ops pv_shadow_emulator_ops = { @@ -375,7 +358,6 @@ static struct x86_emulate_ops pv_shadow_ .insn_fetch = pv_emulate_read, .write = pv_emulate_write, .cmpxchg = pv_emulate_cmpxchg, - .cmpxchg8b = pv_emulate_cmpxchg8b, }; struct x86_emulate_ops *shadow_init_emulation( diff -r ee2f56063f5c -r 6271ba3bb4b6 xen/arch/x86/mm/shadow/multi.c --- a/xen/arch/x86/mm/shadow/multi.c Tue Apr 22 11:46:41 2008 +0100 +++ b/xen/arch/x86/mm/shadow/multi.c Tue Apr 22 14:34:16 2008 +0100 @@ -4365,7 +4365,7 @@ static void emulate_unmap_dest(struct vc atomic_inc(&v->domain->arch.paging.shadow.gtable_dirty_version); } -int +static int sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src, u32 bytes, struct sh_emulate_ctxt *sh_ctxt) { @@ -4389,7 +4389,7 @@ sh_x86_emulate_write(struct vcpu *v, uns return X86EMUL_OKAY; } -int +static int sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr, unsigned long old, unsigned long new, unsigned int bytes, struct sh_emulate_ctxt *sh_ctxt) @@ -4432,7 +4432,8 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u return rv; } -int +#ifdef __i386__ +static int sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr, unsigned long old_lo, unsigned long old_hi, unsigned long new_lo, unsigned long new_hi, @@ -4465,7 +4466,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, shadow_unlock(v->domain); return rv; } - +#endif /**************************************************************************/ /* Audit tools */ @@ -4738,7 +4739,9 @@ struct paging_mode sh_paging_mode = { .shadow.detach_old_tables = sh_detach_old_tables, .shadow.x86_emulate_write = sh_x86_emulate_write, .shadow.x86_emulate_cmpxchg = sh_x86_emulate_cmpxchg, +#ifdef __i386__ .shadow.x86_emulate_cmpxchg8b = sh_x86_emulate_cmpxchg8b, +#endif .shadow.make_monitor_table = sh_make_monitor_table, .shadow.destroy_monitor_table = sh_destroy_monitor_table, #if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC diff -r ee2f56063f5c -r 6271ba3bb4b6 xen/arch/x86/x86_emulate/x86_emulate.c --- a/xen/arch/x86/x86_emulate/x86_emulate.c Tue Apr 22 11:46:41 2008 +0100 +++ b/xen/arch/x86/x86_emulate/x86_emulate.c Tue Apr 22 14:34:16 2008 +0100 @@ -907,6 +907,7 @@ protmode_load_seg( struct { uint32_t a, b; } desc; unsigned long val; uint8_t dpl, rpl, cpl; + uint32_t new_desc_b; int rc, fault_type = EXC_TS; /* NULL selector? */ @@ -989,10 +990,11 @@ protmode_load_seg( } /* Ensure Accessed flag is set. */ + new_desc_b = desc.b | 0x100; rc = ((desc.b & 0x100) ? X86EMUL_OKAY : ops->cmpxchg( - x86_seg_none, desctab.base + (sel & 0xfff8) + 4, desc.b, - desc.b | 0x100, 4, ctxt)); + x86_seg_none, desctab.base + (sel & 0xfff8) + 4, + &desc.b, &new_desc_b, 4, ctxt)); } while ( rc == X86EMUL_CMPXCHG_FAILED ); if ( rc ) @@ -2092,8 +2094,8 @@ x86_emulate( /* nothing to do */; else if ( lock_prefix ) rc = ops->cmpxchg( - dst.mem.seg, dst.mem.off, dst.orig_val, - dst.val, dst.bytes, ctxt); + dst.mem.seg, dst.mem.off, &dst.orig_val, + &dst.val, dst.bytes, ctxt); else rc = ops->write( dst.mem.seg, dst.mem.off, dst.val, dst.bytes, ctxt); @@ -3459,60 +3461,49 @@ x86_emulate( src.val = x86_seg_gs; goto pop_seg; - case 0xc7: /* Grp9 (cmpxchg8b) */ -#if defined(__i386__) - { - unsigned long old_lo, old_hi; + case 0xc7: /* Grp9 (cmpxchg8b/cmpxchg16b) */ { + unsigned long old[2], exp[2], new[2]; + unsigned int i; + generate_exception_if((modrm_reg & 7) != 1, EXC_UD, -1); generate_exception_if(ea.type != OP_MEM, EXC_UD, -1); - if ( (rc = ops->read(ea.mem.seg, ea.mem.off+0, &old_lo, 4, ctxt)) || - (rc = ops->read(ea.mem.seg, ea.mem.off+4, &old_hi, 4, ctxt)) ) - goto done; - if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) ) - { - _regs.eax = old_lo; - _regs.edx = old_hi; + op_bytes *= 2; + + /* Get actual old value. */ + for ( i = 0; i < (op_bytes/sizeof(long)); i++ ) + if ( (rc = ops->read(ea.mem.seg, ea.mem.off + i*sizeof(long), + &old[i], sizeof(long), ctxt)) != 0 ) + goto done; + + /* Get expected and proposed values. */ + if ( op_bytes == 8 ) + { + ((uint32_t *)exp)[0] = _regs.eax; ((uint32_t *)exp)[1] = _regs.edx; + ((uint32_t *)new)[0] = _regs.ebx; ((uint32_t *)new)[1] = _regs.ecx; + } + else + { + exp[0] = _regs.eax; exp[1] = _regs.edx; + new[0] = _regs.ebx; new[1] = _regs.ecx; + } + + if ( memcmp(old, exp, op_bytes) ) + { + /* Expected != actual: store actual to rDX:rAX and clear ZF. */ + _regs.eax = (op_bytes == 8) ? ((uint32_t *)old)[0] : old[0]; + _regs.edx = (op_bytes == 8) ? ((uint32_t *)old)[1] : old[1]; _regs.eflags &= ~EFLG_ZF; } - else if ( ops->cmpxchg8b == NULL ) - { - rc = X86EMUL_UNHANDLEABLE; - goto done; - } else { - if ( (rc = ops->cmpxchg8b(ea.mem.seg, ea.mem.off, old_lo, old_hi, - _regs.ebx, _regs.ecx, ctxt)) != 0 ) + /* Expected == actual: attempt atomic cmpxchg and set ZF. */ + if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old, + new, op_bytes, ctxt)) != 0 ) goto done; _regs.eflags |= EFLG_ZF; } break; } -#elif defined(__x86_64__) - { - unsigned long old, new; - generate_exception_if((modrm_reg & 7) != 1, EXC_UD, -1); - generate_exception_if(ea.type != OP_MEM, EXC_UD, -1); - if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &old, 8, ctxt)) != 0 ) - goto done; - if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) || - ((uint32_t)(old>>32) != (uint32_t)_regs.edx) ) - { - _regs.eax = (uint32_t)(old>>0); - _regs.edx = (uint32_t)(old>>32); - _regs.eflags &= ~EFLG_ZF; - } - else - { - new = (_regs.ecx<<32)|(uint32_t)_regs.ebx; - if ( (rc = ops->cmpxchg(ea.mem.seg, ea.mem.off, old, - new, 8, ctxt)) != 0 ) - goto done; - _regs.eflags |= EFLG_ZF; - } - break; - } -#endif case 0xc8 ... 0xcf: /* bswap */ dst.type = OP_REG; diff -r ee2f56063f5c -r 6271ba3bb4b6 xen/arch/x86/x86_emulate/x86_emulate.h --- a/xen/arch/x86/x86_emulate/x86_emulate.h Tue Apr 22 11:46:41 2008 +0100 +++ b/xen/arch/x86/x86_emulate/x86_emulate.h Tue Apr 22 14:34:16 2008 +0100 @@ -110,8 +110,7 @@ enum x86_emulate_fpu_type { * some out-of-band mechanism, unknown to the emulator. The memop signals * failure by returning X86EMUL_EXCEPTION to the emulator, which will * then immediately bail. - * 2. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only - * cmpxchg8b_emulated need support 8-byte accesses. + * 2. Valid access sizes are 1, 2, 4 and 8 (x86/64 only) bytes. * 3. The emulator cannot handle 64-bit mode emulation on an x86/32 system. */ struct x86_emulate_ops @@ -159,34 +158,16 @@ struct x86_emulate_ops /* * cmpxchg: Emulate an atomic (LOCKed) CMPXCHG operation. - * @old: [IN ] Value expected to be current at @addr. - * @new: [IN ] Value to write to @addr. + * @p_old: [IN ] Pointer to value expected to be current at @addr. + * @p_new: [IN ] Pointer to value to write to @addr. + * @bytes: [IN ] Operation size (up to 8 (x86/32) or 16 (x86/64) bytes). */ int (*cmpxchg)( enum x86_segment seg, unsigned long offset, - unsigned long old, - unsigned long new, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt); - - /* - * cmpxchg8b: Emulate an atomic (LOCKed) CMPXCHG8B operation. - * @old: [IN ] Value expected to be current at @addr. - * @new: [IN ] Value to write to @addr. - * NOTES: - * 1. This function is only ever called when emulating a real CMPXCHG8B. - * 2. This function is *never* called on x86/64 systems. - * 2. Not defining this function (i.e., specifying NULL) is equivalent - * to defining a function that always returns X86EMUL_UNHANDLEABLE. - */ - int (*cmpxchg8b)( - enum x86_segment seg, - unsigned long offset, - unsigned long old_lo, - unsigned long old_hi, - unsigned long new_lo, - unsigned long new_hi, + void *p_old, + void *p_new, + unsigned int bytes, struct x86_emulate_ctxt *ctxt); /* diff -r ee2f56063f5c -r 6271ba3bb4b6 xen/include/asm-x86/paging.h --- a/xen/include/asm-x86/paging.h Tue Apr 22 11:46:41 2008 +0100 +++ b/xen/include/asm-x86/paging.h Tue Apr 22 14:34:16 2008 +0100 @@ -83,12 +83,14 @@ struct shadow_paging_mode { unsigned long new, unsigned int bytes, struct sh_emulate_ctxt *sh_ctxt); +#ifdef __i386__ int (*x86_emulate_cmpxchg8b )(struct vcpu *v, unsigned long va, unsigned long old_lo, unsigned long old_hi, unsigned long new_lo, unsigned long new_hi, struct sh_emulate_ctxt *sh_ctxt); +#endif mfn_t (*make_monitor_table )(struct vcpu *v); void (*destroy_monitor_table )(struct vcpu *v, mfn_t mmfn); int (*guess_wrmap )(struct vcpu *v, _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |