xref: /qemu/linux-user/alpha/cpu_loop.c (revision 727385c4)
1 /*
2  *  qemu user cpu loop
3  *
4  *  Copyright (c) 2003-2008 Fabrice Bellard
5  *
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.
10  *
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.
15  *
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/>.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "qemu-common.h"
22 #include "qemu.h"
23 #include "user-internals.h"
24 #include "cpu_loop-common.h"
25 #include "signal-common.h"
26 
27 void cpu_loop(CPUAlphaState *env)
28 {
29     CPUState *cs = env_cpu(env);
30     int trapnr;
31     target_siginfo_t info;
32     abi_long sysret;
33 
34     while (1) {
35         bool arch_interrupt = true;
36 
37         cpu_exec_start(cs);
38         trapnr = cpu_exec(cs);
39         cpu_exec_end(cs);
40         process_queued_cpu_work(cs);
41 
42         switch (trapnr) {
43         case EXCP_RESET:
44             fprintf(stderr, "Reset requested. Exit\n");
45             exit(EXIT_FAILURE);
46             break;
47         case EXCP_MCHK:
48             fprintf(stderr, "Machine check exception. Exit\n");
49             exit(EXIT_FAILURE);
50             break;
51         case EXCP_SMP_INTERRUPT:
52         case EXCP_CLK_INTERRUPT:
53         case EXCP_DEV_INTERRUPT:
54             fprintf(stderr, "External interrupt. Exit\n");
55             exit(EXIT_FAILURE);
56             break;
57         case EXCP_OPCDEC:
58         do_sigill:
59             info.si_signo = TARGET_SIGILL;
60             info.si_errno = 0;
61             info.si_code = TARGET_ILL_ILLOPC;
62             info._sifields._sigfault._addr = env->pc;
63             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
64             break;
65         case EXCP_ARITH:
66             info.si_signo = TARGET_SIGFPE;
67             info.si_errno = 0;
68             info.si_code = TARGET_FPE_FLTINV;
69             info._sifields._sigfault._addr = env->pc;
70             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
71             break;
72         case EXCP_FEN:
73             /* No-op.  Linux simply re-enables the FPU.  */
74             break;
75         case EXCP_CALL_PAL:
76             switch (env->error_code) {
77             case 0x80:
78                 /* BPT */
79                 info.si_signo = TARGET_SIGTRAP;
80                 info.si_errno = 0;
81                 info.si_code = TARGET_TRAP_BRKPT;
82                 info._sifields._sigfault._addr = env->pc;
83                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
84                 break;
85             case 0x81:
86                 /* BUGCHK */
87                 info.si_signo = TARGET_SIGTRAP;
88                 info.si_errno = 0;
89                 info.si_code = 0;
90                 info._sifields._sigfault._addr = env->pc;
91                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
92                 break;
93             case 0x83:
94                 /* CALLSYS */
95                 trapnr = env->ir[IR_V0];
96                 sysret = do_syscall(env, trapnr,
97                                     env->ir[IR_A0], env->ir[IR_A1],
98                                     env->ir[IR_A2], env->ir[IR_A3],
99                                     env->ir[IR_A4], env->ir[IR_A5],
100                                     0, 0);
101                 if (sysret == -TARGET_ERESTARTSYS) {
102                     env->pc -= 4;
103                     break;
104                 }
105                 if (sysret == -TARGET_QEMU_ESIGRETURN) {
106                     break;
107                 }
108                 /* Syscall writes 0 to V0 to bypass error check, similar
109                    to how this is handled internal to Linux kernel.
110                    (Ab)use trapnr temporarily as boolean indicating error.  */
111                 trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
112                 env->ir[IR_V0] = (trapnr ? -sysret : sysret);
113                 env->ir[IR_A3] = trapnr;
114                 break;
115             case 0x86:
116                 /* IMB */
117                 /* ??? We can probably elide the code using page_unprotect
118                    that is checking for self-modifying code.  Instead we
119                    could simply call tb_flush here.  Until we work out the
120                    changes required to turn off the extra write protection,
121                    this can be a no-op.  */
122                 break;
123             case 0x9E:
124                 /* RDUNIQUE */
125                 /* Handled in the translator for usermode.  */
126                 abort();
127             case 0x9F:
128                 /* WRUNIQUE */
129                 /* Handled in the translator for usermode.  */
130                 abort();
131             case 0xAA:
132                 /* GENTRAP */
133                 info.si_signo = TARGET_SIGFPE;
134                 switch (env->ir[IR_A0]) {
135                 case TARGET_GEN_INTOVF:
136                     info.si_code = TARGET_FPE_INTOVF;
137                     break;
138                 case TARGET_GEN_INTDIV:
139                     info.si_code = TARGET_FPE_INTDIV;
140                     break;
141                 case TARGET_GEN_FLTOVF:
142                     info.si_code = TARGET_FPE_FLTOVF;
143                     break;
144                 case TARGET_GEN_FLTUND:
145                     info.si_code = TARGET_FPE_FLTUND;
146                     break;
147                 case TARGET_GEN_FLTINV:
148                     info.si_code = TARGET_FPE_FLTINV;
149                     break;
150                 case TARGET_GEN_FLTINE:
151                     info.si_code = TARGET_FPE_FLTRES;
152                     break;
153                 case TARGET_GEN_ROPRAND:
154                     info.si_code = 0;
155                     break;
156                 default:
157                     info.si_signo = TARGET_SIGTRAP;
158                     info.si_code = 0;
159                     break;
160                 }
161                 info.si_errno = 0;
162                 info._sifields._sigfault._addr = env->pc;
163                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
164                 break;
165             default:
166                 goto do_sigill;
167             }
168             break;
169         case EXCP_DEBUG:
170             info.si_signo = TARGET_SIGTRAP;
171             info.si_errno = 0;
172             info.si_code = TARGET_TRAP_BRKPT;
173             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
174             break;
175         case EXCP_INTERRUPT:
176             /* Just indicate that signals should be handled asap.  */
177             break;
178         case EXCP_ATOMIC:
179             cpu_exec_step_atomic(cs);
180             arch_interrupt = false;
181             break;
182         default:
183             fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
184             cpu_dump_state(cs, stderr, 0);
185             exit(EXIT_FAILURE);
186         }
187         process_pending_signals (env);
188 
189         /* Most of the traps imply a transition through PALcode, which
190            implies an REI instruction has been executed.  Which means
191            that RX and LOCK_ADDR should be cleared.  But there are a
192            few exceptions for traps internal to QEMU.  */
193         if (arch_interrupt) {
194             env->flags &= ~ENV_FLAG_RX_FLAG;
195             env->lock_addr = -1;
196         }
197     }
198 }
199 
200 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
201 {
202     int i;
203 
204     for(i = 0; i < 28; i++) {
205         env->ir[i] = ((abi_ulong *)regs)[i];
206     }
207     env->ir[IR_SP] = regs->usp;
208     env->pc = regs->pc;
209 }
210