xref: /openbmc/qemu/linux-user/ppc/cpu_loop.c (revision 91654e61)
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 static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
28 {
29     return cpu_get_host_ticks();
30 }
31 
32 uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
33 {
34     return cpu_ppc_get_tb(env);
35 }
36 
37 uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
38 {
39     return cpu_ppc_get_tb(env) >> 32;
40 }
41 
42 uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
43 {
44     return cpu_ppc_get_tb(env);
45 }
46 
47 uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
48 {
49     return cpu_ppc_get_tb(env) >> 32;
50 }
51 
52 uint64_t cpu_ppc_load_vtb(CPUPPCState *env)
53 {
54     return cpu_ppc_get_tb(env);
55 }
56 
57 uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
58 __attribute__ (( alias ("cpu_ppc_load_tbu") ));
59 
60 uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
61 {
62     return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
63 }
64 
65 /* XXX: to be fixed */
66 int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
67 {
68     return -1;
69 }
70 
71 int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
72 {
73     return -1;
74 }
75 
76 void cpu_loop(CPUPPCState *env)
77 {
78     CPUState *cs = env_cpu(env);
79     int trapnr, si_signo, si_code;
80     target_ulong ret;
81 
82     for(;;) {
83         bool arch_interrupt;
84 
85         cpu_exec_start(cs);
86         trapnr = cpu_exec(cs);
87         cpu_exec_end(cs);
88         process_queued_cpu_work(cs);
89 
90         arch_interrupt = true;
91         switch (trapnr) {
92         case POWERPC_EXCP_NONE:
93             /* Just go on */
94             break;
95         case POWERPC_EXCP_CRITICAL: /* Critical input                        */
96             cpu_abort(cs, "Critical interrupt while in user mode. "
97                       "Aborting\n");
98             break;
99         case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
100             cpu_abort(cs, "Machine check exception while in user mode. "
101                       "Aborting\n");
102             break;
103         case POWERPC_EXCP_DSI:      /* Data storage exception                */
104         case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
105             /* FIXME: handle maperr in ppc_cpu_record_sigsegv. */
106             force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
107                             env->spr[SPR_DAR]);
108             break;
109         case POWERPC_EXCP_EXTERNAL: /* External input                        */
110             cpu_abort(cs, "External interrupt while in user mode. "
111                       "Aborting\n");
112             break;
113         case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
114         case POWERPC_EXCP_HV_EMU:   /* HV emulation                          */
115             /* XXX: check this */
116             switch (env->error_code & ~0xF) {
117             case POWERPC_EXCP_FP:
118                 si_signo = TARGET_SIGFPE;
119                 switch (env->error_code & 0xF) {
120                 case POWERPC_EXCP_FP_OX:
121                     si_code = TARGET_FPE_FLTOVF;
122                     break;
123                 case POWERPC_EXCP_FP_UX:
124                     si_code = TARGET_FPE_FLTUND;
125                     break;
126                 case POWERPC_EXCP_FP_ZX:
127                 case POWERPC_EXCP_FP_VXZDZ:
128                     si_code = TARGET_FPE_FLTDIV;
129                     break;
130                 case POWERPC_EXCP_FP_XX:
131                     si_code = TARGET_FPE_FLTRES;
132                     break;
133                 case POWERPC_EXCP_FP_VXSOFT:
134                     si_code = TARGET_FPE_FLTINV;
135                     break;
136                 case POWERPC_EXCP_FP_VXSNAN:
137                 case POWERPC_EXCP_FP_VXISI:
138                 case POWERPC_EXCP_FP_VXIDI:
139                 case POWERPC_EXCP_FP_VXIMZ:
140                 case POWERPC_EXCP_FP_VXVC:
141                 case POWERPC_EXCP_FP_VXSQRT:
142                 case POWERPC_EXCP_FP_VXCVI:
143                     si_code = TARGET_FPE_FLTSUB;
144                     break;
145                 default:
146                     EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
147                               env->error_code);
148                     si_code = 0;
149                     break;
150                 }
151                 break;
152             case POWERPC_EXCP_INVAL:
153                 si_signo = TARGET_SIGILL;
154                 switch (env->error_code & 0xF) {
155                 case POWERPC_EXCP_INVAL_INVAL:
156                     si_code = TARGET_ILL_ILLOPC;
157                     break;
158                 case POWERPC_EXCP_INVAL_LSWX:
159                     si_code = TARGET_ILL_ILLOPN;
160                     break;
161                 case POWERPC_EXCP_INVAL_SPR:
162                     si_code = TARGET_ILL_PRVREG;
163                     break;
164                 case POWERPC_EXCP_INVAL_FP:
165                     si_code = TARGET_ILL_COPROC;
166                     break;
167                 default:
168                     EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
169                               env->error_code & 0xF);
170                     si_code = TARGET_ILL_ILLADR;
171                     break;
172                 }
173                 break;
174             case POWERPC_EXCP_PRIV:
175                 si_signo = TARGET_SIGILL;
176                 switch (env->error_code & 0xF) {
177                 case POWERPC_EXCP_PRIV_OPC:
178                     si_code = TARGET_ILL_PRVOPC;
179                     break;
180                 case POWERPC_EXCP_PRIV_REG:
181                     si_code = TARGET_ILL_PRVREG;
182                     break;
183                 default:
184                     EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
185                               env->error_code & 0xF);
186                     si_code = TARGET_ILL_PRVOPC;
187                     break;
188                 }
189                 break;
190             case POWERPC_EXCP_TRAP:
191                 cpu_abort(cs, "Tried to call a TRAP\n");
192                 break;
193             default:
194                 /* Should not happen ! */
195                 cpu_abort(cs, "Unknown program exception (%02x)\n",
196                           env->error_code);
197                 break;
198             }
199             force_sig_fault(si_signo, si_code, env->nip);
200             break;
201         case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
202         case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
203         case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
204         case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
205             force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->nip);
206             break;
207         case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
208         case POWERPC_EXCP_SYSCALL_VECTORED:
209             cpu_abort(cs, "Syscall exception while in user mode. "
210                       "Aborting\n");
211             break;
212         case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
213             cpu_abort(cs, "Decrementer interrupt while in user mode. "
214                       "Aborting\n");
215             break;
216         case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
217             cpu_abort(cs, "Fix interval timer interrupt while in user mode. "
218                       "Aborting\n");
219             break;
220         case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
221             cpu_abort(cs, "Watchdog timer interrupt while in user mode. "
222                       "Aborting\n");
223             break;
224         case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
225             cpu_abort(cs, "Data TLB exception while in user mode. "
226                       "Aborting\n");
227             break;
228         case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
229             cpu_abort(cs, "Instruction TLB exception while in user mode. "
230                       "Aborting\n");
231             break;
232         case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
233             cpu_abort(cs, "Embedded floating-point data IRQ not handled\n");
234             break;
235         case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
236             cpu_abort(cs, "Embedded floating-point round IRQ not handled\n");
237             break;
238         case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
239             cpu_abort(cs, "Performance monitor exception not handled\n");
240             break;
241         case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
242             cpu_abort(cs, "Doorbell interrupt while in user mode. "
243                        "Aborting\n");
244             break;
245         case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
246             cpu_abort(cs, "Doorbell critical interrupt while in user mode. "
247                       "Aborting\n");
248             break;
249         case POWERPC_EXCP_RESET:    /* System reset exception                */
250             cpu_abort(cs, "Reset interrupt while in user mode. "
251                       "Aborting\n");
252             break;
253         case POWERPC_EXCP_DSEG:     /* Data segment exception                */
254             cpu_abort(cs, "Data segment exception while in user mode. "
255                       "Aborting\n");
256             break;
257         case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
258             cpu_abort(cs, "Instruction segment exception "
259                       "while in user mode. Aborting\n");
260             break;
261         /* PowerPC 64 with hypervisor mode support */
262         case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
263             cpu_abort(cs, "Hypervisor decrementer interrupt "
264                       "while in user mode. Aborting\n");
265             break;
266         case POWERPC_EXCP_TRACE:    /* Trace exception                       */
267             /* Nothing to do:
268              * we use this exception to emulate step-by-step execution mode.
269              */
270             break;
271         /* PowerPC 64 with hypervisor mode support */
272         case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
273             cpu_abort(cs, "Hypervisor data storage exception "
274                       "while in user mode. Aborting\n");
275             break;
276         case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
277             cpu_abort(cs, "Hypervisor instruction storage exception "
278                       "while in user mode. Aborting\n");
279             break;
280         case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
281             cpu_abort(cs, "Hypervisor data segment exception "
282                       "while in user mode. Aborting\n");
283             break;
284         case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
285             cpu_abort(cs, "Hypervisor instruction segment exception "
286                       "while in user mode. Aborting\n");
287             break;
288         case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
289             cpu_abort(cs, "Programmable interval timer interrupt "
290                       "while in user mode. Aborting\n");
291             break;
292         case POWERPC_EXCP_IO:       /* IO error exception                    */
293             cpu_abort(cs, "IO error exception while in user mode. "
294                       "Aborting\n");
295             break;
296         case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
297             cpu_abort(cs, "Run mode exception while in user mode. "
298                       "Aborting\n");
299             break;
300         case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
301             cpu_abort(cs, "Emulation trap exception not handled\n");
302             break;
303         case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
304             cpu_abort(cs, "Instruction fetch TLB exception "
305                       "while in user-mode. Aborting");
306             break;
307         case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
308             cpu_abort(cs, "Data load TLB exception while in user-mode. "
309                       "Aborting");
310             break;
311         case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
312             cpu_abort(cs, "Data store TLB exception while in user-mode. "
313                       "Aborting");
314             break;
315         case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
316             cpu_abort(cs, "Floating-point assist exception not handled\n");
317             break;
318         case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
319             cpu_abort(cs, "Instruction address breakpoint exception "
320                       "not handled\n");
321             break;
322         case POWERPC_EXCP_SMI:      /* System management interrupt           */
323             cpu_abort(cs, "System management interrupt while in user mode. "
324                       "Aborting\n");
325             break;
326         case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
327             cpu_abort(cs, "Thermal interrupt interrupt while in user mode. "
328                       "Aborting\n");
329             break;
330         case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
331             cpu_abort(cs, "Performance monitor exception not handled\n");
332             break;
333         case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
334             cpu_abort(cs, "Vector assist exception not handled\n");
335             break;
336         case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
337             cpu_abort(cs, "Soft patch exception not handled\n");
338             break;
339         case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
340             cpu_abort(cs, "Maintenance exception while in user mode. "
341                       "Aborting\n");
342             break;
343         case POWERPC_EXCP_SYSCALL_USER:
344             /* system call in user-mode emulation */
345             /* WARNING:
346              * PPC ABI uses overflow flag in cr0 to signal an error
347              * in syscalls.
348              */
349             env->crf[0] &= ~0x1;
350             env->nip += 4;
351             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
352                              env->gpr[5], env->gpr[6], env->gpr[7],
353                              env->gpr[8], 0, 0);
354             if (ret == -QEMU_ERESTARTSYS) {
355                 env->nip -= 4;
356                 break;
357             }
358             if (ret == (target_ulong)(-QEMU_ESIGRETURN)) {
359                 /* Returning from a successful sigreturn syscall.
360                    Avoid corrupting register state.  */
361                 break;
362             }
363             if (ret > (target_ulong)(-515)) {
364                 env->crf[0] |= 0x1;
365                 ret = -ret;
366             }
367             env->gpr[3] = ret;
368             break;
369         case EXCP_DEBUG:
370             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->nip);
371             break;
372         case EXCP_INTERRUPT:
373             /* just indicate that signals should be handled asap */
374             break;
375         case EXCP_ATOMIC:
376             cpu_exec_step_atomic(cs);
377             arch_interrupt = false;
378             break;
379         default:
380             cpu_abort(cs, "Unknown exception 0x%x. Aborting\n", trapnr);
381             break;
382         }
383         process_pending_signals(env);
384 
385         /* Most of the traps imply a transition through kernel mode,
386          * which implies an REI instruction has been executed.  Which
387          * means that RX and LOCK_ADDR should be cleared.  But there
388          * are a few exceptions for traps internal to QEMU.
389          */
390         if (arch_interrupt) {
391             env->reserve_addr = -1;
392         }
393     }
394 }
395 
396 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
397 {
398     int i;
399 
400 #if defined(TARGET_PPC64)
401     int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF;
402 #if defined(TARGET_ABI32)
403     ppc_store_msr(env, env->msr & ~((target_ulong)1 << flag));
404 #else
405     ppc_store_msr(env, env->msr | (target_ulong)1 << flag);
406 #endif
407 #endif
408 
409     env->nip = regs->nip;
410     for(i = 0; i < 32; i++) {
411         env->gpr[i] = regs->gpr[i];
412     }
413 }
414