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