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