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