diff options
Diffstat (limited to 'linux-user/aarch64/cpu_loop.c')
-rw-r--r-- | linux-user/aarch64/cpu_loop.c | 191 |
1 files changed, 136 insertions, 55 deletions
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index fea43ce..7f66a87 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -27,18 +27,144 @@ #include "target/arm/syndrome.h" #include "target/arm/cpu-features.h" +/* Use the exception syndrome to map a cpu exception to a signal. */ +static void signal_for_exception(CPUARMState *env, vaddr addr) +{ + uint32_t syn = env->exception.syndrome; + int si_code, si_signo; + + /* Let signal delivery see that ESR is live. */ + env->cp15.esr_el[1] = syn; + + switch (syn_get_ec(syn)) { + case EC_DATAABORT: + case EC_INSNABORT: + /* Both EC have the same format for FSC, or close enough. */ + switch (extract32(syn, 0, 6)) { + case 0x04 ... 0x07: /* Translation fault, level {0-3} */ + si_signo = TARGET_SIGSEGV; + si_code = TARGET_SEGV_MAPERR; + break; + case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */ + case 0x0d ... 0x0f: /* Permission fault, level {1-3} */ + si_signo = TARGET_SIGSEGV; + si_code = TARGET_SEGV_ACCERR; + break; + case 0x11: /* Synchronous Tag Check Fault */ + si_signo = TARGET_SIGSEGV; + si_code = TARGET_SEGV_MTESERR; + break; + case 0x21: /* Alignment fault */ + si_signo = TARGET_SIGBUS; + si_code = TARGET_BUS_ADRALN; + break; + default: + g_assert_not_reached(); + } + break; + + case EC_PCALIGNMENT: + si_signo = TARGET_SIGBUS; + si_code = TARGET_BUS_ADRALN; + break; + + case EC_UNCATEGORIZED: /* E.g. undefined instruction */ + case EC_SYSTEMREGISTERTRAP: /* E.g. inaccessible register */ + case EC_SMETRAP: /* E.g. invalid insn in streaming state */ + case EC_BTITRAP: /* E.g. invalid guarded branch target */ + case EC_ILLEGALSTATE: + /* + * Illegal state happens via an ERET from a privileged mode, + * so is not normally possible from user-only. However, gdbstub + * is not prevented from writing CPSR_IL, aka PSTATE.IL, which + * would generate a trap from the next translated block. + * In the kernel, default case -> el0_inv -> bad_el0_sync. + */ + si_signo = TARGET_SIGILL; + si_code = TARGET_ILL_ILLOPC; + break; + + case EC_PACFAIL: + si_signo = TARGET_SIGILL; + si_code = TARGET_ILL_ILLOPN; + break; + + case EC_GCS: + si_signo = TARGET_SIGSEGV; + si_code = TARGET_SEGV_CPERR; + break; + + case EC_MOP: + /* + * FIXME: The kernel fixes up wrong-option exceptions. + * For QEMU linux-user mode, you can only get these if + * the process is doing something silly (not executing + * the MOPS instructions in the required P/M/E sequence), + * so it is not a problem in practice that we do not. + * + * We ought ideally to implement the same "rewind to the + * start of the sequence" logic that the kernel does in + * arm64_mops_reset_regs(). In the meantime, deliver + * the guest a SIGILL, with the same ILLOPN si_code + * we've always used for this. + */ + si_signo = TARGET_SIGILL; + si_code = TARGET_ILL_ILLOPN; + break; + + case EC_WFX_TRAP: /* user-only WFI implemented as NOP */ + case EC_CP15RTTRAP: /* AArch32 */ + case EC_CP15RRTTRAP: /* AArch32 */ + case EC_CP14RTTRAP: /* AArch32 */ + case EC_CP14DTTRAP: /* AArch32 */ + case EC_ADVSIMDFPACCESSTRAP: /* user-only does not disable fpu */ + case EC_FPIDTRAP: /* AArch32 */ + case EC_PACTRAP: /* user-only does not disable pac regs */ + case EC_BXJTRAP: /* AArch32 */ + case EC_CP14RRTTRAP: /* AArch32 */ + case EC_AA32_SVC: /* AArch32 */ + case EC_AA32_HVC: /* AArch32 */ + case EC_AA32_SMC: /* AArch32 */ + case EC_AA64_SVC: /* generates EXCP_SWI */ + case EC_AA64_HVC: /* user-only generates EC_UNCATEGORIZED */ + case EC_AA64_SMC: /* user-only generates EC_UNCATEGORIZED */ + case EC_SVEACCESSTRAP: /* user-only does not disable sve */ + case EC_ERETTRAP: /* user-only generates EC_UNCATEGORIZED */ + case EC_GPC: /* user-only has no EL3 gpc tables */ + case EC_INSNABORT_SAME_EL: /* el0 cannot trap to el0 */ + case EC_DATAABORT_SAME_EL: /* el0 cannot trap to el0 */ + case EC_SPALIGNMENT: /* sp alignment checks not implemented */ + case EC_AA32_FPTRAP: /* fp exceptions not implemented */ + case EC_AA64_FPTRAP: /* fp exceptions not implemented */ + case EC_SERROR: /* user-only does not have hw faults */ + case EC_BREAKPOINT: /* user-only does not have hw debug */ + case EC_BREAKPOINT_SAME_EL: /* user-only does not have hw debug */ + case EC_SOFTWARESTEP: /* user-only does not have hw debug */ + case EC_SOFTWARESTEP_SAME_EL: /* user-only does not have hw debug */ + case EC_WATCHPOINT: /* user-only does not have hw debug */ + case EC_WATCHPOINT_SAME_EL: /* user-only does not have hw debug */ + case EC_AA32_BKPT: /* AArch32 */ + case EC_VECTORCATCH: /* AArch32 */ + case EC_AA64_BKPT: /* generates EXCP_BKPT */ + default: + g_assert_not_reached(); + } + + force_sig_fault(si_signo, si_code, addr); +} + /* AArch64 main loop */ void cpu_loop(CPUARMState *env) { CPUState *cs = env_cpu(env); - int trapnr, ec, fsc, si_code, si_signo; + int trapnr; abi_long ret; for (;;) { cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); - process_queued_cpu_work(cs); + qemu_process_cpu_events(cs); switch (trapnr) { case EXCP_SWI: @@ -63,46 +189,11 @@ void cpu_loop(CPUARMState *env) /* just indicate that signals should be handled asap */ break; case EXCP_UDEF: - force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc); + signal_for_exception(env, env->pc); break; case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: - ec = syn_get_ec(env->exception.syndrome); - switch (ec) { - case EC_DATAABORT: - case EC_INSNABORT: - /* Both EC have the same format for FSC, or close enough. */ - fsc = extract32(env->exception.syndrome, 0, 6); - switch (fsc) { - case 0x04 ... 0x07: /* Translation fault, level {0-3} */ - si_signo = TARGET_SIGSEGV; - si_code = TARGET_SEGV_MAPERR; - break; - case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */ - case 0x0d ... 0x0f: /* Permission fault, level {1-3} */ - si_signo = TARGET_SIGSEGV; - si_code = TARGET_SEGV_ACCERR; - break; - case 0x11: /* Synchronous Tag Check Fault */ - si_signo = TARGET_SIGSEGV; - si_code = TARGET_SEGV_MTESERR; - break; - case 0x21: /* Alignment fault */ - si_signo = TARGET_SIGBUS; - si_code = TARGET_BUS_ADRALN; - break; - default: - g_assert_not_reached(); - } - break; - case EC_PCALIGNMENT: - si_signo = TARGET_SIGBUS; - si_code = TARGET_BUS_ADRALN; - break; - default: - g_assert_not_reached(); - } - force_sig_fault(si_signo, si_code, env->exception.vaddress); + signal_for_exception(env, env->exception.vaddress); break; case EXCP_DEBUG: case EXCP_BKPT: @@ -137,13 +228,10 @@ void cpu_loop(CPUARMState *env) } } -void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs) +void init_main_thread(CPUState *cs, struct image_info *info) { + CPUARMState *env = cpu_env(cs); ARMCPU *cpu = env_archcpu(env); - CPUState *cs = env_cpu(env); - TaskState *ts = get_task_state(cs); - struct image_info *info = ts->info; - int i; if (!(arm_feature(env, ARM_FEATURE_AARCH64))) { fprintf(stderr, @@ -151,14 +239,12 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs) exit(EXIT_FAILURE); } - for (i = 0; i < 31; i++) { - env->xregs[i] = regs->regs[i]; - } - env->pc = regs->pc; - env->xregs[31] = regs->sp; + env->pc = info->entry & ~0x3ULL; + env->xregs[31] = info->start_stack; + #if TARGET_BIG_ENDIAN env->cp15.sctlr_el[1] |= SCTLR_E0E; - for (i = 1; i < 4; ++i) { + for (int i = 1; i < 4; ++i) { env->cp15.sctlr_el[i] |= SCTLR_EE; } arm_rebuild_hflags(env); @@ -167,9 +253,4 @@ void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs) if (cpu_isar_feature(aa64_pauth, cpu)) { qemu_guest_getrandom_nofail(&env->keys, sizeof(env->keys)); } - - ts->stack_base = info->start_stack; - ts->heap_base = info->brk; - /* This will be filled in on the first SYS_HEAPINFO call. */ - ts->heap_limit = 0; } |