linux-user/nios2: Handle special qemu syscall return values
[qemu.git] / linux-user / nios2 / cpu_loop.c
blob2963fc62b4b70fa43a20dfaa37297d7fcc952fc0
1 /*
2 * qemu user cpu loop
4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qemu.h"
22 #include "user-internals.h"
23 #include "cpu_loop-common.h"
24 #include "signal-common.h"
26 void cpu_loop(CPUNios2State *env)
28 CPUState *cs = env_cpu(env);
29 target_siginfo_t info;
30 int trapnr, ret;
32 for (;;) {
33 cpu_exec_start(cs);
34 trapnr = cpu_exec(cs);
35 cpu_exec_end(cs);
37 switch (trapnr) {
38 case EXCP_INTERRUPT:
39 /* just indicate that signals should be handled asap */
40 break;
42 case EXCP_TRAP:
44 * TODO: This advance should be done in the translator, as
45 * hardware produces an advanced pc as part of all exceptions.
47 env->regs[R_PC] += 4;
49 switch (env->error_code) {
50 case 0:
51 qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
53 ret = do_syscall(env, env->regs[2],
54 env->regs[4], env->regs[5], env->regs[6],
55 env->regs[7], env->regs[8], env->regs[9],
56 0, 0);
58 if (ret == -QEMU_ESIGRETURN) {
59 /* rt_sigreturn has set all state. */
60 break;
62 if (ret == -QEMU_ERESTARTSYS) {
63 env->regs[R_PC] -= 4;
64 break;
67 * See the code after translate_rc_and_ret: all negative
68 * values are errors (aided by userspace restricted to 2G),
69 * errno is returned positive in r2, and error indication
70 * is a boolean in r7.
72 env->regs[2] = abs(ret);
73 env->regs[7] = ret < 0;
74 break;
76 case 1:
77 qemu_log_mask(CPU_LOG_INT, "\nTrap 1\n");
78 force_sig_fault(TARGET_SIGUSR1, 0, env->regs[R_PC]);
79 break;
80 case 2:
81 qemu_log_mask(CPU_LOG_INT, "\nTrap 2\n");
82 force_sig_fault(TARGET_SIGUSR2, 0, env->regs[R_PC]);
83 break;
84 case 31:
85 qemu_log_mask(CPU_LOG_INT, "\nTrap 31\n");
86 /* Match kernel's breakpoint_c(). */
87 env->regs[R_PC] -= 4;
88 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[R_PC]);
89 break;
90 default:
91 qemu_log_mask(CPU_LOG_INT, "\nTrap %d\n", env->error_code);
92 force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP,
93 env->regs[R_PC]);
94 break;
96 case 16: /* QEMU specific, for __kuser_cmpxchg */
98 abi_ptr g = env->regs[4];
99 uint32_t *h, n, o;
101 if (g & 0x3) {
102 force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, g);
103 break;
105 ret = page_get_flags(g);
106 if (!(ret & PAGE_VALID)) {
107 force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, g);
108 break;
110 if (!(ret & PAGE_READ) || !(ret & PAGE_WRITE)) {
111 force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_ACCERR, g);
112 break;
114 h = g2h(cs, g);
115 o = env->regs[5];
116 n = env->regs[6];
117 env->regs[2] = qatomic_cmpxchg(h, o, n) - o;
119 break;
121 break;
123 case EXCP_DEBUG:
124 info.si_signo = TARGET_SIGTRAP;
125 info.si_errno = 0;
126 info.si_code = TARGET_TRAP_BRKPT;
127 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
128 break;
129 case 0xaa:
131 info.si_signo = TARGET_SIGSEGV;
132 info.si_errno = 0;
133 /* TODO: check env->error_code */
134 info.si_code = TARGET_SEGV_MAPERR;
135 info._sifields._sigfault._addr = env->regs[R_PC];
136 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
138 break;
139 default:
140 EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
141 trapnr);
142 abort();
145 process_pending_signals(env);
149 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
151 env->regs[0] = 0;
152 env->regs[1] = regs->r1;
153 env->regs[2] = regs->r2;
154 env->regs[3] = regs->r3;
155 env->regs[4] = regs->r4;
156 env->regs[5] = regs->r5;
157 env->regs[6] = regs->r6;
158 env->regs[7] = regs->r7;
159 env->regs[8] = regs->r8;
160 env->regs[9] = regs->r9;
161 env->regs[10] = regs->r10;
162 env->regs[11] = regs->r11;
163 env->regs[12] = regs->r12;
164 env->regs[13] = regs->r13;
165 env->regs[14] = regs->r14;
166 env->regs[15] = regs->r15;
167 /* TODO: unsigned long orig_r2; */
168 env->regs[R_RA] = regs->ra;
169 env->regs[R_FP] = regs->fp;
170 env->regs[R_SP] = regs->sp;
171 env->regs[R_GP] = regs->gp;
172 env->regs[CR_ESTATUS] = regs->estatus;
173 env->regs[R_PC] = regs->ea;
174 /* TODO: unsigned long orig_r7; */