diff options
author | Paul Brook <paul@codesourcery.com> | 2009-11-22 21:35:13 +0000 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2009-11-22 21:35:13 +0000 |
commit | 426f5abcaa15d0e59475fdb33b2a4a5fdf492d05 (patch) | |
tree | ef9eb63ac19b7ba19fe533d514d3571f21de2b3d /linux-user/main.c | |
parent | eee4850422d1d18276c1f4dbb6153b568efcb8b9 (diff) |
ARM atomic ops rewrite
Implement ARMv6 atomic ops (ldrex/strex) using the same trick as PPC.
Signed-off-by: Paul Brook <paul@codesourcery.com>
Diffstat (limited to 'linux-user/main.c')
-rw-r--r-- | linux-user/main.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/linux-user/main.c b/linux-user/main.c index 67336d71ff..2b8bab1b63 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -524,6 +524,81 @@ do_kernel_trap(CPUARMState *env) return 0; } +static int do_strex(CPUARMState *env) +{ + uint32_t val; + int size; + int rc = 1; + int segv = 0; + uint32_t addr; + start_exclusive(); + addr = env->exclusive_addr; + if (addr != env->exclusive_test) { + goto fail; + } + size = env->exclusive_info & 0xf; + switch (size) { + case 0: + segv = get_user_u8(val, addr); + break; + case 1: + segv = get_user_u16(val, addr); + break; + case 2: + case 3: + segv = get_user_u32(val, addr); + break; + } + if (segv) { + env->cp15.c6_data = addr; + goto done; + } + if (val != env->exclusive_val) { + goto fail; + } + if (size == 3) { + segv = get_user_u32(val, addr + 4); + if (segv) { + env->cp15.c6_data = addr + 4; + goto done; + } + if (val != env->exclusive_high) { + goto fail; + } + } + val = env->regs[(env->exclusive_info >> 8) & 0xf]; + switch (size) { + case 0: + segv = put_user_u8(val, addr); + break; + case 1: + segv = put_user_u16(val, addr); + break; + case 2: + case 3: + segv = put_user_u32(val, addr); + break; + } + if (segv) { + env->cp15.c6_data = addr; + goto done; + } + if (size == 3) { + val = env->regs[(env->exclusive_info >> 12) & 0xf]; + segv = put_user_u32(val, addr); + if (segv) { + env->cp15.c6_data = addr + 4; + goto done; + } + } + rc = 0; +fail: + env->regs[(env->exclusive_info >> 4) & 0xf] = rc; +done: + end_exclusive(); + return segv; +} + void cpu_loop(CPUARMState *env) { int trapnr; @@ -717,6 +792,11 @@ void cpu_loop(CPUARMState *env) if (do_kernel_trap(env)) goto error; break; + case EXCP_STREX: + if (do_strex(env)) { + addr = env->cp15.c6_data; + goto do_segv; + } default: error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |