summaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorPaul Brook <paul@codesourcery.com>2009-11-22 21:35:13 +0000
committerPaul Brook <paul@codesourcery.com>2009-11-22 21:35:13 +0000
commit426f5abcaa15d0e59475fdb33b2a4a5fdf492d05 (patch)
treeef9eb63ac19b7ba19fe533d514d3571f21de2b3d /linux-user
parenteee4850422d1d18276c1f4dbb6153b568efcb8b9 (diff)
downloadqemu-426f5abcaa15d0e59475fdb33b2a4a5fdf492d05.tar.gz
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')
-rw-r--r--linux-user/main.c80
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",