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