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