aboutsummaryrefslogtreecommitdiff
path: root/linux-user/alpha
diff options
context:
space:
mode:
authorLaurent Vivier <laurent@vivier.eu>2018-04-11 20:56:46 +0200
committerLaurent Vivier <laurent@vivier.eu>2018-04-30 09:48:22 +0200
commite256aefe0ddefca4618d75951f948890f9b1f186 (patch)
tree276efb98219e5a9c3f6988d7ff64b329e5d8e3cd /linux-user/alpha
parentff9803b13b5663f70299b769e3e6059d2ea31e80 (diff)
linux-user: move alpha cpu loop to alpha directory
No code change, only move code from main.c to alpha/cpu_loop.c. Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-Id: <20180411185651.21351-15-laurent@vivier.eu>
Diffstat (limited to 'linux-user/alpha')
-rw-r--r--linux-user/alpha/cpu_loop.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/linux-user/alpha/cpu_loop.c b/linux-user/alpha/cpu_loop.c
index b7700a5561..b87fcaea87 100644
--- a/linux-user/alpha/cpu_loop.c
+++ b/linux-user/alpha/cpu_loop.c
@@ -21,6 +21,205 @@
#include "qemu.h"
#include "cpu_loop-common.h"
+void cpu_loop(CPUAlphaState *env)
+{
+ CPUState *cs = CPU(alpha_env_get_cpu(env));
+ int trapnr;
+ target_siginfo_t info;
+ abi_long sysret;
+
+ while (1) {
+ bool arch_interrupt = true;
+
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_RESET:
+ fprintf(stderr, "Reset requested. Exit\n");
+ exit(EXIT_FAILURE);
+ break;
+ case EXCP_MCHK:
+ fprintf(stderr, "Machine check exception. Exit\n");
+ exit(EXIT_FAILURE);
+ break;
+ case EXCP_SMP_INTERRUPT:
+ case EXCP_CLK_INTERRUPT:
+ case EXCP_DEV_INTERRUPT:
+ fprintf(stderr, "External interrupt. Exit\n");
+ exit(EXIT_FAILURE);
+ break;
+ case EXCP_MMFAULT:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
+ ? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
+ info._sifields._sigfault._addr = env->trap_arg0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_UNALIGN:
+ info.si_signo = TARGET_SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_BUS_ADRALN;
+ info._sifields._sigfault._addr = env->trap_arg0;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_OPCDEC:
+ do_sigill:
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPC;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_ARITH:
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_FLTINV;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case EXCP_FEN:
+ /* No-op. Linux simply re-enables the FPU. */
+ break;
+ case EXCP_CALL_PAL:
+ switch (env->error_code) {
+ case 0x80:
+ /* BPT */
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case 0x81:
+ /* BUGCHK */
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = 0;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ case 0x83:
+ /* CALLSYS */
+ trapnr = env->ir[IR_V0];
+ sysret = do_syscall(env, trapnr,
+ env->ir[IR_A0], env->ir[IR_A1],
+ env->ir[IR_A2], env->ir[IR_A3],
+ env->ir[IR_A4], env->ir[IR_A5],
+ 0, 0);
+ if (sysret == -TARGET_ERESTARTSYS) {
+ env->pc -= 4;
+ break;
+ }
+ if (sysret == -TARGET_QEMU_ESIGRETURN) {
+ break;
+ }
+ /* Syscall writes 0 to V0 to bypass error check, similar
+ to how this is handled internal to Linux kernel.
+ (Ab)use trapnr temporarily as boolean indicating error. */
+ trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
+ env->ir[IR_V0] = (trapnr ? -sysret : sysret);
+ env->ir[IR_A3] = trapnr;
+ break;
+ case 0x86:
+ /* IMB */
+ /* ??? We can probably elide the code using page_unprotect
+ that is checking for self-modifying code. Instead we
+ could simply call tb_flush here. Until we work out the
+ changes required to turn off the extra write protection,
+ this can be a no-op. */
+ break;
+ case 0x9E:
+ /* RDUNIQUE */
+ /* Handled in the translator for usermode. */
+ abort();
+ case 0x9F:
+ /* WRUNIQUE */
+ /* Handled in the translator for usermode. */
+ abort();
+ case 0xAA:
+ /* GENTRAP */
+ info.si_signo = TARGET_SIGFPE;
+ switch (env->ir[IR_A0]) {
+ case TARGET_GEN_INTOVF:
+ info.si_code = TARGET_FPE_INTOVF;
+ break;
+ case TARGET_GEN_INTDIV:
+ info.si_code = TARGET_FPE_INTDIV;
+ break;
+ case TARGET_GEN_FLTOVF:
+ info.si_code = TARGET_FPE_FLTOVF;
+ break;
+ case TARGET_GEN_FLTUND:
+ info.si_code = TARGET_FPE_FLTUND;
+ break;
+ case TARGET_GEN_FLTINV:
+ info.si_code = TARGET_FPE_FLTINV;
+ break;
+ case TARGET_GEN_FLTINE:
+ info.si_code = TARGET_FPE_FLTRES;
+ break;
+ case TARGET_GEN_ROPRAND:
+ info.si_code = 0;
+ break;
+ default:
+ info.si_signo = TARGET_SIGTRAP;
+ info.si_code = 0;
+ break;
+ }
+ info.si_errno = 0;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ default:
+ goto do_sigill;
+ }
+ break;
+ case EXCP_DEBUG:
+ info.si_signo = gdb_handlesig(cs, TARGET_SIGTRAP);
+ if (info.si_signo) {
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ } else {
+ arch_interrupt = false;
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* Just indicate that signals should be handled asap. */
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ arch_interrupt = false;
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ exit(EXIT_FAILURE);
+ }
+ process_pending_signals (env);
+
+ /* Most of the traps imply a transition through PALcode, which
+ implies an REI instruction has been executed. Which means
+ that RX and LOCK_ADDR should be cleared. But there are a
+ few exceptions for traps internal to QEMU. */
+ if (arch_interrupt) {
+ env->flags &= ~ENV_FLAG_RX_FLAG;
+ env->lock_addr = -1;
+ }
+ }
+}
+
void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
{
+ int i;
+
+ for(i = 0; i < 28; i++) {
+ env->ir[i] = ((abi_ulong *)regs)[i];
+ }
+ env->ir[IR_SP] = regs->usp;
+ env->pc = regs->pc;
}