MIPS atomic instructions

Implement MIPS ll/sc instructions using atomic compare+exchange.

Signed-off-by: Paul Brook <paul@codesourcery.com>
This commit is contained in:
Paul Brook 2009-07-09 17:45:17 +01:00
parent ff867ddcbd
commit 590bc601d8
3 changed files with 124 additions and 24 deletions

View file

@ -1826,6 +1826,55 @@ static const uint8_t mips_syscall_args[] = {
#undef MIPS_SYS
static int do_store_exclusive(CPUMIPSState *env)
{
target_ulong addr;
target_ulong page_addr;
target_ulong val;
int flags;
int segv = 0;
int reg;
int d;
addr = env->CP0_LLAddr;
page_addr = addr & TARGET_PAGE_MASK;
start_exclusive();
mmap_lock();
flags = page_get_flags(page_addr);
if ((flags & PAGE_READ) == 0) {
segv = 1;
} else {
reg = env->llreg & 0x1f;
d = (env->llreg & 0x20) != 0;
if (d) {
segv = get_user_s64(val, addr);
} else {
segv = get_user_s32(val, addr);
}
if (!segv) {
if (val != env->llval) {
env->active_tc.gpr[reg] = 0;
} else {
if (d) {
segv = put_user_u64(env->llnewval, addr);
} else {
segv = put_user_u32(env->llnewval, addr);
}
if (!segv) {
env->active_tc.gpr[reg] = 1;
}
}
}
}
env->CP0_LLAddr = -1;
if (!segv) {
env->active_tc.PC += 4;
}
mmap_unlock();
end_exclusive();
return segv;
}
void cpu_loop(CPUMIPSState *env)
{
target_siginfo_t info;
@ -1833,7 +1882,9 @@ void cpu_loop(CPUMIPSState *env)
unsigned int syscall_num;
for(;;) {
cpu_exec_start(env);
trapnr = cpu_mips_exec(env);
cpu_exec_end(env);
switch(trapnr) {
case EXCP_SYSCALL:
syscall_num = env->active_tc.gpr[2] - 4000;
@ -1910,6 +1961,15 @@ void cpu_loop(CPUMIPSState *env)
}
}
break;
case EXCP_SC:
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->active_tc.PC;
queue_signal(env, info.si_signo, &info);
}
break;
default:
// error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",