target/ppc: Remove POWERPC_EXCP_STCX
Always use the gen_conditional_store implementation that uses atomic_cmpxchg. Make sure and clear reserve_addr across most interrupts crossing the cpu_loop. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
		
							parent
							
								
									4a9b3c5dd3
								
							
						
					
					
						commit
						14db18997e
					
				@ -65,99 +65,23 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
 | 
				
			|||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int do_store_exclusive(CPUPPCState *env)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    target_ulong addr;
 | 
					 | 
				
			||||||
    target_ulong page_addr;
 | 
					 | 
				
			||||||
    target_ulong val, val2 __attribute__((unused)) = 0;
 | 
					 | 
				
			||||||
    int flags;
 | 
					 | 
				
			||||||
    int segv = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    addr = env->reserve_ea;
 | 
					 | 
				
			||||||
    page_addr = addr & TARGET_PAGE_MASK;
 | 
					 | 
				
			||||||
    start_exclusive();
 | 
					 | 
				
			||||||
    mmap_lock();
 | 
					 | 
				
			||||||
    flags = page_get_flags(page_addr);
 | 
					 | 
				
			||||||
    if ((flags & PAGE_READ) == 0) {
 | 
					 | 
				
			||||||
        segv = 1;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        int reg = env->reserve_info & 0x1f;
 | 
					 | 
				
			||||||
        int size = env->reserve_info >> 5;
 | 
					 | 
				
			||||||
        int stored = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (addr == env->reserve_addr) {
 | 
					 | 
				
			||||||
            switch (size) {
 | 
					 | 
				
			||||||
            case 1: segv = get_user_u8(val, addr); break;
 | 
					 | 
				
			||||||
            case 2: segv = get_user_u16(val, addr); break;
 | 
					 | 
				
			||||||
            case 4: segv = get_user_u32(val, addr); break;
 | 
					 | 
				
			||||||
#if defined(TARGET_PPC64)
 | 
					 | 
				
			||||||
            case 8: segv = get_user_u64(val, addr); break;
 | 
					 | 
				
			||||||
            case 16: {
 | 
					 | 
				
			||||||
                segv = get_user_u64(val, addr);
 | 
					 | 
				
			||||||
                if (!segv) {
 | 
					 | 
				
			||||||
                    segv = get_user_u64(val2, addr + 8);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
            default: abort();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (!segv && val == env->reserve_val) {
 | 
					 | 
				
			||||||
                val = env->gpr[reg];
 | 
					 | 
				
			||||||
                switch (size) {
 | 
					 | 
				
			||||||
                case 1: segv = put_user_u8(val, addr); break;
 | 
					 | 
				
			||||||
                case 2: segv = put_user_u16(val, addr); break;
 | 
					 | 
				
			||||||
                case 4: segv = put_user_u32(val, addr); break;
 | 
					 | 
				
			||||||
#if defined(TARGET_PPC64)
 | 
					 | 
				
			||||||
                case 8: segv = put_user_u64(val, addr); break;
 | 
					 | 
				
			||||||
                case 16: {
 | 
					 | 
				
			||||||
                    if (val2 == env->reserve_val2) {
 | 
					 | 
				
			||||||
                        if (msr_le) {
 | 
					 | 
				
			||||||
                            val2 = val;
 | 
					 | 
				
			||||||
                            val = env->gpr[reg+1];
 | 
					 | 
				
			||||||
                        } else {
 | 
					 | 
				
			||||||
                            val2 = env->gpr[reg+1];
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        segv = put_user_u64(val, addr);
 | 
					 | 
				
			||||||
                        if (!segv) {
 | 
					 | 
				
			||||||
                            segv = put_user_u64(val2, addr + 8);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                default: abort();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (!segv) {
 | 
					 | 
				
			||||||
                    stored = 1;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        env->crf[0] = (stored << 1) | xer_so;
 | 
					 | 
				
			||||||
        env->reserve_addr = (target_ulong)-1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!segv) {
 | 
					 | 
				
			||||||
        env->nip += 4;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    mmap_unlock();
 | 
					 | 
				
			||||||
    end_exclusive();
 | 
					 | 
				
			||||||
    return segv;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void cpu_loop(CPUPPCState *env)
 | 
					void cpu_loop(CPUPPCState *env)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *cs = CPU(ppc_env_get_cpu(env));
 | 
					    CPUState *cs = CPU(ppc_env_get_cpu(env));
 | 
				
			||||||
    target_siginfo_t info;
 | 
					    target_siginfo_t info;
 | 
				
			||||||
    int trapnr;
 | 
					    int trapnr, sig;
 | 
				
			||||||
    target_ulong ret;
 | 
					    target_ulong ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for(;;) {
 | 
					    for(;;) {
 | 
				
			||||||
 | 
					        bool arch_interrupt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        cpu_exec_start(cs);
 | 
					        cpu_exec_start(cs);
 | 
				
			||||||
        trapnr = cpu_exec(cs);
 | 
					        trapnr = cpu_exec(cs);
 | 
				
			||||||
        cpu_exec_end(cs);
 | 
					        cpu_exec_end(cs);
 | 
				
			||||||
        process_queued_cpu_work(cs);
 | 
					        process_queued_cpu_work(cs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch(trapnr) {
 | 
					        arch_interrupt = true;
 | 
				
			||||||
 | 
					        switch (trapnr) {
 | 
				
			||||||
        case POWERPC_EXCP_NONE:
 | 
					        case POWERPC_EXCP_NONE:
 | 
				
			||||||
            /* Just go on */
 | 
					            /* Just go on */
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -524,26 +448,15 @@ void cpu_loop(CPUPPCState *env)
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            env->gpr[3] = ret;
 | 
					            env->gpr[3] = ret;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case POWERPC_EXCP_STCX:
 | 
					 | 
				
			||||||
            if (do_store_exclusive(env)) {
 | 
					 | 
				
			||||||
                info.si_signo = TARGET_SIGSEGV;
 | 
					 | 
				
			||||||
                info.si_errno = 0;
 | 
					 | 
				
			||||||
                info.si_code = TARGET_SEGV_MAPERR;
 | 
					 | 
				
			||||||
                info._sifields._sigfault._addr = env->nip;
 | 
					 | 
				
			||||||
                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        case EXCP_DEBUG:
 | 
					        case EXCP_DEBUG:
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                int sig;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            sig = gdb_handlesig(cs, TARGET_SIGTRAP);
 | 
					            sig = gdb_handlesig(cs, TARGET_SIGTRAP);
 | 
				
			||||||
            if (sig) {
 | 
					            if (sig) {
 | 
				
			||||||
                info.si_signo = sig;
 | 
					                info.si_signo = sig;
 | 
				
			||||||
                info.si_errno = 0;
 | 
					                info.si_errno = 0;
 | 
				
			||||||
                info.si_code = TARGET_TRAP_BRKPT;
 | 
					                info.si_code = TARGET_TRAP_BRKPT;
 | 
				
			||||||
                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
					                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 | 
				
			||||||
                  }
 | 
					            } else {
 | 
				
			||||||
 | 
					                arch_interrupt = false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case EXCP_INTERRUPT:
 | 
					        case EXCP_INTERRUPT:
 | 
				
			||||||
@ -551,12 +464,22 @@ void cpu_loop(CPUPPCState *env)
 | 
				
			|||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case EXCP_ATOMIC:
 | 
					        case EXCP_ATOMIC:
 | 
				
			||||||
            cpu_exec_step_atomic(cs);
 | 
					            cpu_exec_step_atomic(cs);
 | 
				
			||||||
 | 
					            arch_interrupt = false;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
 | 
					            cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        process_pending_signals(env);
 | 
					        process_pending_signals(env);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Most of the traps imply a transition through kernel mode,
 | 
				
			||||||
 | 
					         * which implies an REI instruction has been executed.  Which
 | 
				
			||||||
 | 
					         * means that RX and LOCK_ADDR should be cleared.  But there
 | 
				
			||||||
 | 
					         * are a few exceptions for traps internal to QEMU.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if (arch_interrupt) {
 | 
				
			||||||
 | 
					            env->reserve_addr = -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -196,7 +196,6 @@ enum {
 | 
				
			|||||||
    /* QEMU exceptions: special cases we want to stop translation            */
 | 
					    /* QEMU exceptions: special cases we want to stop translation            */
 | 
				
			||||||
    POWERPC_EXCP_SYNC         = 0x202, /* context synchronizing instruction  */
 | 
					    POWERPC_EXCP_SYNC         = 0x202, /* context synchronizing instruction  */
 | 
				
			||||||
    POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only      */
 | 
					    POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only      */
 | 
				
			||||||
    POWERPC_EXCP_STCX         = 0x204 /* Conditional stores in user mode     */
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Exceptions error codes                                                    */
 | 
					/* Exceptions error codes                                                    */
 | 
				
			||||||
@ -994,10 +993,6 @@ struct CPUPPCState {
 | 
				
			|||||||
    /* Reservation value */
 | 
					    /* Reservation value */
 | 
				
			||||||
    target_ulong reserve_val;
 | 
					    target_ulong reserve_val;
 | 
				
			||||||
    target_ulong reserve_val2;
 | 
					    target_ulong reserve_val2;
 | 
				
			||||||
    /* Reservation store address */
 | 
					 | 
				
			||||||
    target_ulong reserve_ea;
 | 
					 | 
				
			||||||
    /* Reserved store source register and size */
 | 
					 | 
				
			||||||
    target_ulong reserve_info;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Those ones are used in supervisor mode only */
 | 
					    /* Those ones are used in supervisor mode only */
 | 
				
			||||||
    /* machine state register */
 | 
					    /* machine state register */
 | 
				
			||||||
 | 
				
			|||||||
@ -3201,19 +3201,6 @@ ST_ATOMIC(stwat, DEF_MEMOP(MO_UL), i32, trunc_tl_i32)
 | 
				
			|||||||
ST_ATOMIC(stdat, DEF_MEMOP(MO_Q), i64, mov_i64)
 | 
					ST_ATOMIC(stdat, DEF_MEMOP(MO_Q), i64, mov_i64)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_USER_ONLY)
 | 
					 | 
				
			||||||
static void gen_conditional_store(DisasContext *ctx, TCGv EA,
 | 
					 | 
				
			||||||
                                  int reg, int memop)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    TCGv t0 = tcg_temp_new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tcg_gen_st_tl(EA, cpu_env, offsetof(CPUPPCState, reserve_ea));
 | 
					 | 
				
			||||||
    tcg_gen_movi_tl(t0, (MEMOP_GET_SIZE(memop) << 5) | reg);
 | 
					 | 
				
			||||||
    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, reserve_info));
 | 
					 | 
				
			||||||
    tcg_temp_free(t0);
 | 
					 | 
				
			||||||
    gen_exception_err(ctx, POWERPC_EXCP_STCX, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
static void gen_conditional_store(DisasContext *ctx, TCGv EA,
 | 
					static void gen_conditional_store(DisasContext *ctx, TCGv EA,
 | 
				
			||||||
                                  int reg, int memop)
 | 
					                                  int reg, int memop)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -3244,7 +3231,6 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA,
 | 
				
			|||||||
    gen_set_label(l2);
 | 
					    gen_set_label(l2);
 | 
				
			||||||
    tcg_gen_movi_tl(cpu_reserve, -1);
 | 
					    tcg_gen_movi_tl(cpu_reserve, -1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STCX(name, memop)                                   \
 | 
					#define STCX(name, memop)                                   \
 | 
				
			||||||
static void gen_##name(DisasContext *ctx)                   \
 | 
					static void gen_##name(DisasContext *ctx)                   \
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user