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