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