From fbb4a2e371f2fa7d3bbe479795d8c79a795f7cd3 Mon Sep 17 00:00:00 2001 From: pbrook Date: Thu, 29 May 2008 00:20:44 +0000 Subject: [PATCH] Implement ARM magic kernel page and TLS register. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4610 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/arm/syscall.h | 4 +- linux-user/main.c | 86 ++++++++++++++++++++++++++++++++++++---- target-arm/cpu.h | 5 +++ target-arm/translate.c | 11 ++++- 4 files changed, 96 insertions(+), 10 deletions(-) diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index e7f2e8deb4..f06da76dde 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 4087a11ff6..640b7fe775 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", diff --git a/target-arm/cpu.h b/target-arm/cpu.h index c26cad28b6..f7252f5c21 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -38,6 +38,7 @@ #define EXCP_FIQ 6 #define EXCP_BKPT 7 #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ +#define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ #define ARMV7M_EXCP_RESET 1 #define ARMV7M_EXCP_NMI 2 @@ -216,6 +217,10 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo, void cpu_lock(void); void cpu_unlock(void); +static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls) +{ + env->cp15.c13_tls2 = newtls; +} #define CPSR_M (0x1f) #define CPSR_T (1 << 5) diff --git a/target-arm/translate.c b/target-arm/translate.c index 29755de90b..be5b99b079 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -8583,7 +8583,16 @@ static inline int gen_intermediate_code_internal(CPUState *env, store_cpu_field(tmp, condexec_bits); } do { -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY + /* Intercept jump to the magic kernel page. */ + if (dc->pc >= 0xffff0000) { + /* We always get here via a jump, so know we are not in a + conditional execution block. */ + gen_exception(EXCP_KERNEL_TRAP); + dc->is_jmp = DISAS_UPDATE; + break; + } +#else if (dc->pc >= 0xfffffff0 && IS_M(env)) { /* We always get here via a jump, so know we are not in a conditional execution block. */