target-alpha: Fix load-locked/store-conditional.

Use an exception plus start_exclusive to implement the compare-and-swap.
This follows the example set by the MIPS and PPC ports.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
Richard Henderson 2010-04-07 15:42:26 -07:00 committed by Aurelien Jarno
parent 8aa3fa2038
commit 6910b8f66a
5 changed files with 193 additions and 79 deletions

View file

@ -2349,6 +2349,51 @@ void cpu_loop(CPUM68KState *env)
#endif /* TARGET_M68K */
#ifdef TARGET_ALPHA
static void do_store_exclusive(CPUAlphaState *env, int reg, int quad)
{
target_ulong addr, val, tmp;
target_siginfo_t info;
int ret = 0;
addr = env->lock_addr;
tmp = env->lock_st_addr;
env->lock_addr = -1;
env->lock_st_addr = 0;
start_exclusive();
mmap_lock();
if (addr == tmp) {
if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
goto do_sigsegv;
}
if (val == env->lock_value) {
tmp = env->ir[reg];
if (quad ? put_user_u64(tmp, addr) : put_user_u32(tmp, addr)) {
goto do_sigsegv;
}
ret = 1;
}
}
env->ir[reg] = ret;
env->pc += 4;
mmap_unlock();
end_exclusive();
return;
do_sigsegv:
mmap_unlock();
end_exclusive();
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = addr;
queue_signal(env, TARGET_SIGSEGV, &info);
}
void cpu_loop (CPUState *env)
{
int trapnr;
@ -2373,6 +2418,7 @@ void cpu_loop (CPUState *env)
exit(1);
break;
case EXCP_ARITH:
env->lock_addr = -1;
info.si_signo = TARGET_SIGFPE;
info.si_errno = 0;
info.si_code = TARGET_FPE_FLTINV;
@ -2384,6 +2430,7 @@ void cpu_loop (CPUState *env)
exit(1);
break;
case EXCP_DFAULT:
env->lock_addr = -1;
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = 0; /* ??? SEGV_MAPERR vs SEGV_ACCERR. */
@ -2407,6 +2454,7 @@ void cpu_loop (CPUState *env)
exit(1);
break;
case EXCP_UNALIGN:
env->lock_addr = -1;
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
@ -2415,6 +2463,7 @@ void cpu_loop (CPUState *env)
break;
case EXCP_OPCDEC:
do_sigill:
env->lock_addr = -1;
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPC;
@ -2425,6 +2474,7 @@ void cpu_loop (CPUState *env)
/* No-op. Linux simply re-enables the FPU. */
break;
case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
env->lock_addr = -1;
switch ((trapnr >> 6) | 0x80) {
case 0x80:
/* BPT */
@ -2514,11 +2564,16 @@ void cpu_loop (CPUState *env)
case EXCP_DEBUG:
info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
if (info.si_signo) {
env->lock_addr = -1;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
queue_signal(env, info.si_signo, &info);
}
break;
case EXCP_STL_C:
case EXCP_STQ_C:
do_store_exclusive(env, env->error_code, trapnr - EXCP_STL_C);
break;
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);