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