[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [for-4.7] x86/emulate: synchronize LOCKed instruction emulation
LOCK-prefixed instructions are currenly allowed to run in parallel in x86_emulate(), which can lead the guest into an undefined state. This patch fixes the issue. Signed-off-by: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> --- tools/tests/x86_emulator/test_x86_emulator.c | 12 ++++++++++++ xen/arch/x86/hvm/emulate.c | 26 ++++++++++++++++++++++++++ xen/arch/x86/mm.c | 3 +++ xen/arch/x86/mm/shadow/common.c | 4 ++++ xen/arch/x86/x86_emulate/x86_emulate.c | 23 ++++++++++++++++++++++- xen/arch/x86/x86_emulate/x86_emulate.h | 8 ++++++++ xen/common/domain.c | 2 ++ xen/include/asm-x86/domain.h | 4 ++++ xen/include/asm-x86/hvm/emulate.h | 3 +++ 9 files changed, 84 insertions(+), 1 deletion(-) diff --git a/tools/tests/x86_emulator/test_x86_emulator.c b/tools/tests/x86_emulator/test_x86_emulator.c index 86e298f..22e963b 100644 --- a/tools/tests/x86_emulator/test_x86_emulator.c +++ b/tools/tests/x86_emulator/test_x86_emulator.c @@ -9,6 +9,8 @@ #define __packed __attribute__((packed)) +typedef bool bool_t; + #include "x86_emulate/x86_emulate.h" #include "blowfish.h" @@ -160,6 +162,14 @@ int get_fpu( return X86EMUL_OKAY; } +static void smp_lock(bool_t locked) +{ +} + +static void smp_unlock(bool_t locked) +{ +} + static struct x86_emulate_ops emulops = { .read = read, .insn_fetch = fetch, @@ -167,6 +177,8 @@ static struct x86_emulate_ops emulops = { .cmpxchg = cmpxchg, .cpuid = cpuid, .get_fpu = get_fpu, + .smp_lock = smp_lock, + .smp_unlock = smp_unlock, }; int main(int argc, char **argv) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index cc0b841..02096d5 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -25,6 +25,8 @@ #include <asm/hvm/svm/svm.h> #include <asm/vm_event.h> +DEFINE_PERCPU_RWLOCK_GLOBAL(emulate_locked_rwlock); + static void hvmtrace_io_assist(const ioreq_t *p) { unsigned int size, event; @@ -1616,6 +1618,26 @@ static int hvmemul_vmfunc( return rc; } +void emulate_smp_lock(bool_t locked) +{ + struct domain *d = current->domain; + + if ( locked ) + percpu_write_lock(emulate_locked_rwlock, &d->arch.emulate_lock); + else + percpu_read_lock(emulate_locked_rwlock, &d->arch.emulate_lock); +} + +void emulate_smp_unlock(bool_t locked) +{ + struct domain *d = current->domain; + + if ( locked ) + percpu_write_unlock(emulate_locked_rwlock, &d->arch.emulate_lock); + else + percpu_read_unlock(emulate_locked_rwlock, &d->arch.emulate_lock); +} + static const struct x86_emulate_ops hvm_emulate_ops = { .read = hvmemul_read, .insn_fetch = hvmemul_insn_fetch, @@ -1641,6 +1663,8 @@ static const struct x86_emulate_ops hvm_emulate_ops = { .put_fpu = hvmemul_put_fpu, .invlpg = hvmemul_invlpg, .vmfunc = hvmemul_vmfunc, + .smp_lock = emulate_smp_lock, + .smp_unlock = emulate_smp_unlock, }; static const struct x86_emulate_ops hvm_emulate_ops_no_write = { @@ -1668,6 +1692,8 @@ static const struct x86_emulate_ops hvm_emulate_ops_no_write = { .put_fpu = hvmemul_put_fpu, .invlpg = hvmemul_invlpg, .vmfunc = hvmemul_vmfunc, + .smp_lock = emulate_smp_lock, + .smp_unlock = emulate_smp_unlock, }; static int _hvm_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt, diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index bca7532..52a3c5d 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -112,6 +112,7 @@ #include <asm/ldt.h> #include <asm/x86_emulate.h> #include <asm/e820.h> +#include <asm/hvm/emulate.h> #include <asm/hypercall.h> #include <asm/shared.h> #include <asm/mem_sharing.h> @@ -5319,6 +5320,8 @@ static const struct x86_emulate_ops ptwr_emulate_ops = { .insn_fetch = ptwr_emulated_read, .write = ptwr_emulated_write, .cmpxchg = ptwr_emulated_cmpxchg, + .smp_lock = emulate_smp_lock, + .smp_unlock = emulate_smp_unlock, }; /* Write page fault handler: check if guest is trying to modify a PTE. */ diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index ec87fb4..6d18430 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -283,6 +283,8 @@ static const struct x86_emulate_ops hvm_shadow_emulator_ops = { .insn_fetch = hvm_emulate_insn_fetch, .write = hvm_emulate_write, .cmpxchg = hvm_emulate_cmpxchg, + .smp_lock = emulate_smp_lock, + .smp_unlock = emulate_smp_unlock, }; static int @@ -351,6 +353,8 @@ static const struct x86_emulate_ops pv_shadow_emulator_ops = { .insn_fetch = pv_emulate_read, .write = pv_emulate_write, .cmpxchg = pv_emulate_cmpxchg, + .smp_lock = emulate_smp_lock, + .smp_unlock = emulate_smp_unlock, }; const struct x86_emulate_ops *shadow_init_emulation( diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c b/xen/arch/x86/x86_emulate/x86_emulate.c index 10a2959..aab934f 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -1520,6 +1520,8 @@ x86_emulate( struct operand ea = { .type = OP_MEM, .reg = REG_POISON }; ea.mem.seg = x86_seg_ds; /* gcc may reject anon union initializer */ + ASSERT(ops->smp_lock && ops->smp_unlock); + ctxt->retire.byte = 0; op_bytes = def_op_bytes = ad_bytes = def_ad_bytes = ctxt->addr_size/8; @@ -1589,6 +1591,8 @@ x86_emulate( } done_prefixes: + ops->smp_lock(lock_prefix); + if ( rex_prefix & REX_W ) op_bytes = 8; @@ -2052,7 +2056,10 @@ x86_emulate( generate_exception_if(mode_64bit() && !twobyte, EXC_UD, -1); fail_if(ops->read_segment == NULL); if ( (rc = ops->read_segment(src.val, ®, ctxt)) != 0 ) + { + ops->smp_unlock(lock_prefix); return rc; + } /* 64-bit mode: PUSH defaults to a 64-bit operand. */ if ( mode_64bit() && (op_bytes == 4) ) op_bytes = 8; @@ -2074,7 +2081,10 @@ x86_emulate( &dst.val, op_bytes, ctxt, ops)) != 0 ) goto done; if ( (rc = load_seg(src.val, dst.val, 0, NULL, ctxt, ops)) != 0 ) + { + ops->smp_unlock(lock_prefix); return rc; + } break; case 0x0e: /* push %%cs */ @@ -2380,7 +2390,12 @@ x86_emulate( } /* Write back the memory destination with implicit LOCK prefix. */ dst.val = src.val; - lock_prefix = 1; + if ( !lock_prefix ) + { + ops->smp_unlock(lock_prefix); + lock_prefix = 1; + ops->smp_lock(lock_prefix); + } break; case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ @@ -3859,6 +3874,9 @@ x86_emulate( done: _put_fpu(); put_stub(stub); + + ops->smp_unlock(lock_prefix); + return rc; twobyte_insn: @@ -4767,5 +4785,8 @@ x86_emulate( cannot_emulate: _put_fpu(); put_stub(stub); + + ops->smp_unlock(lock_prefix); + return X86EMUL_UNHANDLEABLE; } diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h index 3a1bb46..e515840 100644 --- a/xen/arch/x86/x86_emulate/x86_emulate.h +++ b/xen/arch/x86/x86_emulate/x86_emulate.h @@ -400,6 +400,14 @@ struct x86_emulate_ops /* vmfunc: Emulate VMFUNC via given set of EAX ECX inputs */ int (*vmfunc)( struct x86_emulate_ctxt *ctxt); + + /* smp_lock: Take a write lock if locked, read lock otherwise. */ + void (*smp_lock)( + bool_t locked); + + /* smp_unlock: Write unlock if locked, read unlock otherwise. */ + void (*smp_unlock)( + bool_t locked); }; struct cpu_user_regs; diff --git a/xen/common/domain.c b/xen/common/domain.c index 45273d4..0f98256 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -272,6 +272,8 @@ struct domain *domain_create(domid_t domid, unsigned int domcr_flags, TRACE_1D(TRC_DOM0_DOM_ADD, d->domain_id); + percpu_rwlock_resource_init(&d->arch.emulate_lock, emulate_locked_rwlock); + lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain"); if ( (err = xsm_alloc_security_domain(d)) != 0 ) diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index d393ed2..04312ae 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -271,6 +271,8 @@ struct monitor_write_data { uint64_t cr4; }; +DECLARE_PERCPU_RWLOCK_GLOBAL(emulate_locked_rwlock); + struct arch_domain { struct page_info *perdomain_l3_pg; @@ -409,6 +411,8 @@ struct arch_domain /* Emulated devices enabled bitmap. */ uint32_t emulation_flags; + + percpu_rwlock_t emulate_lock; } __cacheline_aligned; #define has_vlapic(d) (!!((d)->arch.emulation_flags & XEN_X86_EMU_LAPIC)) diff --git a/xen/include/asm-x86/hvm/emulate.h b/xen/include/asm-x86/hvm/emulate.h index 142d1b6..863f01d 100644 --- a/xen/include/asm-x86/hvm/emulate.h +++ b/xen/include/asm-x86/hvm/emulate.h @@ -67,6 +67,9 @@ int hvmemul_do_pio_buffer(uint16_t port, void hvm_dump_emulation_state(const char *prefix, struct hvm_emulate_ctxt *hvmemul_ctxt); +void emulate_smp_lock(bool_t locked); +void emulate_smp_unlock(bool_t locked); + #endif /* __ASM_X86_HVM_EMULATE_H__ */ /* -- 1.9.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |