diff options
Diffstat (limited to 'target/microblaze/translate.c')
-rw-r--r-- | target/microblaze/translate.c | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index f6ff2591c3..a96cb21d96 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1075,14 +1075,16 @@ static void dec_store(DisasContext *dc) swx_skip = gen_new_label(); tcg_gen_brcond_tl(TCG_COND_NE, env_res_addr, addr, swx_skip); - /* Compare the value loaded at lwx with current contents of - the reserved location. - FIXME: This only works for system emulation where we can expect - this compare and the following write to be atomic. For user - emulation we need to add atomicity between threads. */ + /* + * Compare the value loaded at lwx with current contents of + * the reserved location. + */ tval = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(tval, addr, cpu_mmu_index(&dc->cpu->env, false), - MO_TEUL); + + tcg_gen_atomic_cmpxchg_i32(tval, addr, env_res_val, + cpu_R[dc->rd], mem_index, + mop); + tcg_gen_brcond_i32(TCG_COND_NE, env_res_val, tval, swx_skip); write_carryi(dc, 0); tcg_temp_free_i32(tval); @@ -1108,7 +1110,10 @@ static void dec_store(DisasContext *dc) break; } } - tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); + + if (!ex) { + tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); + } /* Verify alignment if needed. */ if (dc->cpu->cfg.unaligned_exceptions && size > 1) { @@ -1229,13 +1234,27 @@ static void dec_br(DisasContext *dc) /* Memory barrier. */ mbar = (dc->ir >> 16) & 31; if (mbar == 2 && dc->imm == 4) { + uint16_t mbar_imm = dc->rd; + + LOG_DIS("mbar %d\n", mbar_imm); + + /* Data access memory barrier. */ + if ((mbar_imm & 2) == 0) { + tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); + } + /* mbar IMM & 16 decodes to sleep. */ - if (dc->rd & 16) { + if (mbar_imm & 16) { TCGv_i32 tmp_hlt = tcg_const_i32(EXCP_HLT); TCGv_i32 tmp_1 = tcg_const_i32(1); LOG_DIS("sleep\n"); + if (trap_userspace(dc, true)) { + /* Sleep is a privileged instruction. */ + return; + } + t_sync_flags(dc); tcg_gen_st_i32(tmp_1, cpu_env, -offsetof(MicroBlazeCPU, env) @@ -1246,7 +1265,6 @@ static void dec_br(DisasContext *dc) tcg_temp_free_i32(tmp_1); return; } - LOG_DIS("mbar %d\n", dc->rd); /* Break the TB. */ dc->cpustate_changed = 1; return; |