diff options
author | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-29 00:20:44 +0000 |
---|---|---|
committer | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-29 00:20:44 +0000 |
commit | fbb4a2e371f2fa7d3bbe479795d8c79a795f7cd3 (patch) | |
tree | 7ac6203fe8fd1adb8b844da4073ae7919bfe83a2 /linux-user | |
parent | ce5232c5c281552039466be5eadf93a712eb7611 (diff) | |
download | hqemu-fbb4a2e371f2fa7d3bbe479795d8c79a795f7cd3.zip hqemu-fbb4a2e371f2fa7d3bbe479795d8c79a795f7cd3.tar.gz |
Implement ARM magic kernel page and TLS register.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4610 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/arm/syscall.h | 4 | ||||
-rw-r--r-- | linux-user/main.c | 86 |
2 files changed, 81 insertions, 9 deletions
diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index e7f2e8d..f06da76 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -28,7 +28,9 @@ struct target_pt_regs { #define ARM_SYSCALL_BASE 0x900000 #define ARM_THUMB_SYSCALL 0 -#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2) +#define ARM_NR_BASE 0xf0000 +#define ARM_NR_cacheflush (ARM_NR_BASE + 2) +#define ARM_NR_set_tls (ARM_NR_BASE + 5) #define ARM_NR_semihosting 0x123456 #define ARM_NR_thumb_semihosting 0xAB diff --git a/linux-user/main.c b/linux-user/main.c index 4087a11..640b7fe 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -365,6 +365,55 @@ static void arm_cache_flush(abi_ulong start, abi_ulong last) } } +/* Handle a jump to the kernel code page. */ +static int +do_kernel_trap(CPUARMState *env) +{ + uint32_t addr; + uint32_t cpsr; + uint32_t val; + + switch (env->regs[15]) { + case 0xffff0fa0: /* __kernel_memory_barrier */ + /* ??? No-op. Will need to do better for SMP. */ + break; + case 0xffff0fc0: /* __kernel_cmpxchg */ + /* ??? This is not really atomic. However we don't support + threads anyway, so it doesn't realy matter. */ + cpsr = cpsr_read(env); + addr = env->regs[2]; + /* FIXME: This should SEGV if the access fails. */ + if (get_user_u32(val, addr)) + val = ~env->regs[0]; + if (val == env->regs[0]) { + val = env->regs[1]; + /* FIXME: Check for segfaults. */ + put_user_u32(val, addr); + env->regs[0] = 0; + cpsr |= CPSR_C; + } else { + env->regs[0] = -1; + cpsr &= ~CPSR_C; + } + cpsr_write(env, cpsr, CPSR_C); + break; + case 0xffff0fe0: /* __kernel_get_tls */ + env->regs[0] = env->cp15.c13_tls2; + break; + default: + return 1; + } + /* Jump back to the caller. */ + addr = env->regs[14]; + if (addr & 1) { + env->thumb = 1; + addr &= ~1; + } + env->regs[15] = addr; + + return 0; +} + void cpu_loop(CPUARMState *env) { int trapnr; @@ -489,14 +538,31 @@ void cpu_loop(CPUARMState *env) n -= ARM_SYSCALL_BASE; env->eabi = 0; } - env->regs[0] = do_syscall(env, - n, - env->regs[0], - env->regs[1], - env->regs[2], - env->regs[3], - env->regs[4], - env->regs[5]); + if ( n > ARM_NR_BASE) { + switch (n) { + case ARM_NR_cacheflush: + arm_cache_flush(env->regs[0], env->regs[1]); + break; + case ARM_NR_set_tls: + cpu_set_tls(env, env->regs[0]); + env->regs[0] = 0; + break; + default: + gemu_log("qemu: Unsupported ARM syscall: 0x%x\n", + n); + env->regs[0] = -TARGET_ENOSYS; + break; + } + } else { + env->regs[0] = do_syscall(env, + n, + env->regs[0], + env->regs[1], + env->regs[2], + env->regs[3], + env->regs[4], + env->regs[5]); + } } else { goto error; } @@ -535,6 +601,10 @@ void cpu_loop(CPUARMState *env) } } break; + case EXCP_KERNEL_TRAP: + if (do_kernel_trap(env)) + goto error; + break; default: error: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |