aboutsummaryrefslogtreecommitdiff
path: root/linux-user/main.c
diff options
context:
space:
mode:
authorLaurent Vivier <laurent@vivier.eu>2018-04-11 20:56:36 +0200
committerLaurent Vivier <laurent@vivier.eu>2018-04-30 09:48:01 +0200
commitd9673512267d081f01fe1e450ac0891ba7d005aa (patch)
treed6083cb90eb032eba9f93ea9aae26a3eb9402635 /linux-user/main.c
parent3c439b1762e6ec80f3f96a6fef53474c5a6f3757 (diff)
linux-user: move arm cpu loop to arm directory
No code change, only move code from main.c to arm/cpu_loop.c and duplicate some macro defined for both arm and aarch64. Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20180411185651.21351-5-laurent@vivier.eu>
Diffstat (limited to 'linux-user/main.c')
-rw-r--r--linux-user/main.c433
1 files changed, 2 insertions, 431 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index b4f08b226c..45d1588958 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -149,416 +149,6 @@ void fork_end(int child)
}
}
-#ifdef TARGET_ARM
-
-#define get_user_code_u32(x, gaddr, env) \
- ({ abi_long __r = get_user_u32((x), (gaddr)); \
- if (!__r && bswap_code(arm_sctlr_b(env))) { \
- (x) = bswap32(x); \
- } \
- __r; \
- })
-
-#define get_user_code_u16(x, gaddr, env) \
- ({ abi_long __r = get_user_u16((x), (gaddr)); \
- if (!__r && bswap_code(arm_sctlr_b(env))) { \
- (x) = bswap16(x); \
- } \
- __r; \
- })
-
-#define get_user_data_u32(x, gaddr, env) \
- ({ abi_long __r = get_user_u32((x), (gaddr)); \
- if (!__r && arm_cpu_bswap_data(env)) { \
- (x) = bswap32(x); \
- } \
- __r; \
- })
-
-#define get_user_data_u16(x, gaddr, env) \
- ({ abi_long __r = get_user_u16((x), (gaddr)); \
- if (!__r && arm_cpu_bswap_data(env)) { \
- (x) = bswap16(x); \
- } \
- __r; \
- })
-
-#define put_user_data_u32(x, gaddr, env) \
- ({ typeof(x) __x = (x); \
- if (arm_cpu_bswap_data(env)) { \
- __x = bswap32(__x); \
- } \
- put_user_u32(__x, (gaddr)); \
- })
-
-#define put_user_data_u16(x, gaddr, env) \
- ({ typeof(x) __x = (x); \
- if (arm_cpu_bswap_data(env)) { \
- __x = bswap16(__x); \
- } \
- put_user_u16(__x, (gaddr)); \
- })
-
-#ifdef TARGET_ABI32
-/* Commpage handling -- there is no commpage for AArch64 */
-
-/*
- * See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
- * Input:
- * r0 = pointer to oldval
- * r1 = pointer to newval
- * r2 = pointer to target value
- *
- * Output:
- * r0 = 0 if *ptr was changed, non-0 if no exchange happened
- * C set if *ptr was changed, clear if no exchange happened
- *
- * Note segv's in kernel helpers are a bit tricky, we can set the
- * data address sensibly but the PC address is just the entry point.
- */
-static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
-{
- uint64_t oldval, newval, val;
- uint32_t addr, cpsr;
- target_siginfo_t info;
-
- /* Based on the 32 bit code in do_kernel_trap */
-
- /* XXX: This only works between threads, not between processes.
- It's probably possible to implement this with native host
- operations. However things like ldrex/strex are much harder so
- there's not much point trying. */
- start_exclusive();
- cpsr = cpsr_read(env);
- addr = env->regs[2];
-
- if (get_user_u64(oldval, env->regs[0])) {
- env->exception.vaddress = env->regs[0];
- goto segv;
- };
-
- if (get_user_u64(newval, env->regs[1])) {
- env->exception.vaddress = env->regs[1];
- goto segv;
- };
-
- if (get_user_u64(val, addr)) {
- env->exception.vaddress = addr;
- goto segv;
- }
-
- if (val == oldval) {
- val = newval;
-
- if (put_user_u64(val, addr)) {
- env->exception.vaddress = addr;
- goto segv;
- };
-
- env->regs[0] = 0;
- cpsr |= CPSR_C;
- } else {
- env->regs[0] = -1;
- cpsr &= ~CPSR_C;
- }
- cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
- end_exclusive();
- return;
-
-segv:
- end_exclusive();
- /* We get the PC of the entry address - which is as good as anything,
- on a real kernel what you get depends on which mode it uses. */
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->exception.vaddress;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
-}
-
-/* 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 */
- /* XXX: This only works between threads, not between processes.
- It's probably possible to implement this with native host
- operations. However things like ldrex/strex are much harder so
- there's not much point trying. */
- start_exclusive();
- 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, CPSRWriteByInstr);
- end_exclusive();
- break;
- case 0xffff0fe0: /* __kernel_get_tls */
- env->regs[0] = cpu_get_tls(env);
- break;
- case 0xffff0f60: /* __kernel_cmpxchg64 */
- arm_kernel_cmpxchg64_helper(env);
- 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)
-{
- CPUState *cs = CPU(arm_env_get_cpu(env));
- int trapnr;
- unsigned int n, insn;
- target_siginfo_t info;
- uint32_t addr;
- abi_ulong ret;
-
- for(;;) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch(trapnr) {
- case EXCP_UDEF:
- case EXCP_NOCP:
- case EXCP_INVSTATE:
- {
- TaskState *ts = cs->opaque;
- uint32_t opcode;
- int rc;
-
- /* we handle the FPU emulation here, as Linux */
- /* we get the opcode */
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u32(opcode, env->regs[15], env);
-
- rc = EmulateAll(opcode, &ts->fpa, env);
- if (rc == 0) { /* illegal instruction */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->regs[15];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- } else if (rc < 0) { /* FP exception */
- int arm_fpe=0;
-
- /* translate softfloat flags to FPSR flags */
- if (-rc & float_flag_invalid)
- arm_fpe |= BIT_IOC;
- if (-rc & float_flag_divbyzero)
- arm_fpe |= BIT_DZC;
- if (-rc & float_flag_overflow)
- arm_fpe |= BIT_OFC;
- if (-rc & float_flag_underflow)
- arm_fpe |= BIT_UFC;
- if (-rc & float_flag_inexact)
- arm_fpe |= BIT_IXC;
-
- FPSR fpsr = ts->fpa.fpsr;
- //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
-
- if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
-
- /* ordered by priority, least first */
- if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
- if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
- if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
- if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
- if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
-
- info._sifields._sigfault._addr = env->regs[15];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- } else {
- env->regs[15] += 4;
- }
-
- /* accumulate unenabled exceptions */
- if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
- fpsr |= BIT_IXC;
- if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
- fpsr |= BIT_UFC;
- if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
- fpsr |= BIT_OFC;
- if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
- fpsr |= BIT_DZC;
- if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
- fpsr |= BIT_IOC;
- ts->fpa.fpsr=fpsr;
- } else { /* everything OK */
- /* increment PC */
- env->regs[15] += 4;
- }
- }
- break;
- case EXCP_SWI:
- case EXCP_BKPT:
- {
- env->eabi = 1;
- /* system call */
- if (trapnr == EXCP_BKPT) {
- if (env->thumb) {
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u16(insn, env->regs[15], env);
- n = insn & 0xff;
- env->regs[15] += 2;
- } else {
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u32(insn, env->regs[15], env);
- n = (insn & 0xf) | ((insn >> 4) & 0xff0);
- env->regs[15] += 4;
- }
- } else {
- if (env->thumb) {
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u16(insn, env->regs[15] - 2, env);
- n = insn & 0xff;
- } else {
- /* FIXME - what to do if get_user() fails? */
- get_user_code_u32(insn, env->regs[15] - 4, env);
- n = insn & 0xffffff;
- }
- }
-
- if (n == ARM_NR_cacheflush) {
- /* nop */
- } else if (n == ARM_NR_semihosting
- || n == ARM_NR_thumb_semihosting) {
- env->regs[0] = do_arm_semihosting (env);
- } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
- /* linux syscall */
- if (env->thumb || n == 0) {
- n = env->regs[7];
- } else {
- n -= ARM_SYSCALL_BASE;
- env->eabi = 0;
- }
- if ( n > ARM_NR_BASE) {
- switch (n) {
- case ARM_NR_cacheflush:
- /* nop */
- break;
- case ARM_NR_set_tls:
- cpu_set_tls(env, env->regs[0]);
- env->regs[0] = 0;
- break;
- case ARM_NR_breakpoint:
- env->regs[15] -= env->thumb ? 2 : 4;
- goto excp_debug;
- default:
- gemu_log("qemu: Unsupported ARM syscall: 0x%x\n",
- n);
- env->regs[0] = -TARGET_ENOSYS;
- break;
- }
- } else {
- ret = do_syscall(env,
- n,
- env->regs[0],
- env->regs[1],
- env->regs[2],
- env->regs[3],
- env->regs[4],
- env->regs[5],
- 0, 0);
- if (ret == -TARGET_ERESTARTSYS) {
- env->regs[15] -= env->thumb ? 2 : 4;
- } else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->regs[0] = ret;
- }
- }
- } else {
- goto error;
- }
- }
- break;
- case EXCP_SEMIHOST:
- env->regs[0] = do_arm_semihosting(env);
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_PREFETCH_ABORT:
- case EXCP_DATA_ABORT:
- addr = env->exception.vaddress;
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = addr;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- break;
- case EXCP_DEBUG:
- excp_debug:
- {
- int sig;
-
- sig = gdb_handlesig(cs, TARGET_SIGTRAP);
- if (sig)
- {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- }
- }
- break;
- case EXCP_KERNEL_TRAP:
- if (do_kernel_trap(env))
- goto error;
- break;
- case EXCP_YIELD:
- /* nothing to do here for user-mode, just resume guest code */
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- error:
- EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
- abort();
- }
- process_pending_signals(env);
- }
-}
-#endif /* ndef TARGET_ABI32 */
-
-#endif
-
#ifdef TARGET_SPARC
#define SPARC64_STACK_BIAS 2047
@@ -4412,26 +4002,7 @@ int main(int argc, char **argv, char **envp)
target_cpu_copy_regs(env, regs);
-#if defined(TARGET_ARM) && !defined(TARGET_AARCH64)
- {
- int i;
- cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
- CPSRWriteByInstr);
- for(i = 0; i < 16; i++) {
- env->regs[i] = regs->uregs[i];
- }
-#ifdef TARGET_WORDS_BIGENDIAN
- /* Enable BE8. */
- if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
- && (info->elf_flags & EF_ARM_BE8)) {
- env->uncached_cpsr |= CPSR_E;
- env->cp15.sctlr_el[1] |= SCTLR_E0E;
- } else {
- env->cp15.sctlr_el[1] |= SCTLR_B;
- }
-#endif
- }
-#elif defined(TARGET_SPARC)
+#if defined(TARGET_SPARC)
{
int i;
env->pc = regs->pc;
@@ -4667,7 +4238,7 @@ int main(int argc, char **argv, char **envp)
}
#endif
-#if (defined(TARGET_ARM) && !defined(TARGET_AARCH64)) || defined(TARGET_M68K)
+#if defined(TARGET_M68K)
ts->stack_base = info->start_stack;
ts->heap_base = info->brk;
/* This will be filled in on the first SYS_HEAPINFO call. */