4 * Copyright (c) 2003-2008 Fabrice Bellard
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.
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.
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/>.
20 #include "qemu/osdep.h"
22 #include "cpu_loop-common.h"
24 static inline uint64_t cpu_ppc_get_tb(CPUPPCState
*env
)
26 return cpu_get_host_ticks();
29 uint64_t cpu_ppc_load_tbl(CPUPPCState
*env
)
31 return cpu_ppc_get_tb(env
);
34 uint32_t cpu_ppc_load_tbu(CPUPPCState
*env
)
36 return cpu_ppc_get_tb(env
) >> 32;
39 uint64_t cpu_ppc_load_atbl(CPUPPCState
*env
)
41 return cpu_ppc_get_tb(env
);
44 uint32_t cpu_ppc_load_atbu(CPUPPCState
*env
)
46 return cpu_ppc_get_tb(env
) >> 32;
49 uint32_t cpu_ppc601_load_rtcu(CPUPPCState
*env
)
50 __attribute__ (( alias ("cpu_ppc_load_tbu") ));
52 uint32_t cpu_ppc601_load_rtcl(CPUPPCState
*env
)
54 return cpu_ppc_load_tbl(env
) & 0x3FFFFF80;
57 /* XXX: to be fixed */
58 int ppc_dcr_read (ppc_dcr_t
*dcr_env
, int dcrn
, uint32_t *valp
)
63 int ppc_dcr_write (ppc_dcr_t
*dcr_env
, int dcrn
, uint32_t val
)
68 static int do_store_exclusive(CPUPPCState
*env
)
71 target_ulong page_addr
;
72 target_ulong val
, val2
__attribute__((unused
)) = 0;
76 addr
= env
->reserve_ea
;
77 page_addr
= addr
& TARGET_PAGE_MASK
;
80 flags
= page_get_flags(page_addr
);
81 if ((flags
& PAGE_READ
) == 0) {
84 int reg
= env
->reserve_info
& 0x1f;
85 int size
= env
->reserve_info
>> 5;
88 if (addr
== env
->reserve_addr
) {
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;
96 segv
= get_user_u64(val
, addr
);
98 segv
= get_user_u64(val2
, addr
+ 8);
105 if (!segv
&& val
== env
->reserve_val
) {
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;
114 if (val2
== env
->reserve_val2
) {
117 val
= env
->gpr
[reg
+1];
119 val2
= env
->gpr
[reg
+1];
121 segv
= put_user_u64(val
, addr
);
123 segv
= put_user_u64(val2
, addr
+ 8);
136 env
->crf
[0] = (stored
<< 1) | xer_so
;
137 env
->reserve_addr
= (target_ulong
)-1;
147 void cpu_loop(CPUPPCState
*env
)
149 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
150 target_siginfo_t info
;
156 trapnr
= cpu_exec(cs
);
158 process_queued_cpu_work(cs
);
161 case POWERPC_EXCP_NONE
:
164 case POWERPC_EXCP_CRITICAL
: /* Critical input */
165 cpu_abort(cs
, "Critical interrupt while in user mode. "
168 case POWERPC_EXCP_MCHECK
: /* Machine check exception */
169 cpu_abort(cs
, "Machine check exception while in user mode. "
172 case POWERPC_EXCP_DSI
: /* Data storage exception */
173 /* XXX: check this. Seems bugged */
174 switch (env
->error_code
& 0xFF000000) {
177 info
.si_signo
= TARGET_SIGSEGV
;
179 info
.si_code
= TARGET_SEGV_MAPERR
;
182 info
.si_signo
= TARGET_SIGILL
;
184 info
.si_code
= TARGET_ILL_ILLADR
;
187 info
.si_signo
= TARGET_SIGSEGV
;
189 info
.si_code
= TARGET_SEGV_ACCERR
;
192 /* Let's send a regular segfault... */
193 EXCP_DUMP(env
, "Invalid segfault errno (%02x)\n",
195 info
.si_signo
= TARGET_SIGSEGV
;
197 info
.si_code
= TARGET_SEGV_MAPERR
;
200 info
._sifields
._sigfault
._addr
= env
->spr
[SPR_DAR
];
201 queue_signal(env
, info
.si_signo
, QEMU_SI_FAULT
, &info
);
203 case POWERPC_EXCP_ISI
: /* Instruction storage exception */
204 /* XXX: check this */
205 switch (env
->error_code
& 0xFF000000) {
207 info
.si_signo
= TARGET_SIGSEGV
;
209 info
.si_code
= TARGET_SEGV_MAPERR
;
213 info
.si_signo
= TARGET_SIGSEGV
;
215 info
.si_code
= TARGET_SEGV_ACCERR
;
218 /* Let's send a regular segfault... */
219 EXCP_DUMP(env
, "Invalid segfault errno (%02x)\n",
221 info
.si_signo
= TARGET_SIGSEGV
;
223 info
.si_code
= TARGET_SEGV_MAPERR
;
226 info
._sifields
._sigfault
._addr
= env
->nip
- 4;
227 queue_signal(env
, info
.si_signo
, QEMU_SI_FAULT
, &info
);
229 case POWERPC_EXCP_EXTERNAL
: /* External input */
230 cpu_abort(cs
, "External interrupt while in user mode. "
233 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
234 /* XXX: check this */
235 info
.si_signo
= TARGET_SIGBUS
;
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
);
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
;
248 switch (env
->error_code
& 0xF) {
249 case POWERPC_EXCP_FP_OX
:
250 info
.si_code
= TARGET_FPE_FLTOVF
;
252 case POWERPC_EXCP_FP_UX
:
253 info
.si_code
= TARGET_FPE_FLTUND
;
255 case POWERPC_EXCP_FP_ZX
:
256 case POWERPC_EXCP_FP_VXZDZ
:
257 info
.si_code
= TARGET_FPE_FLTDIV
;
259 case POWERPC_EXCP_FP_XX
:
260 info
.si_code
= TARGET_FPE_FLTRES
;
262 case POWERPC_EXCP_FP_VXSOFT
:
263 info
.si_code
= TARGET_FPE_FLTINV
;
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
;
275 EXCP_DUMP(env
, "Unknown floating point exception (%02x)\n",
280 case POWERPC_EXCP_INVAL
:
281 info
.si_signo
= TARGET_SIGILL
;
283 switch (env
->error_code
& 0xF) {
284 case POWERPC_EXCP_INVAL_INVAL
:
285 info
.si_code
= TARGET_ILL_ILLOPC
;
287 case POWERPC_EXCP_INVAL_LSWX
:
288 info
.si_code
= TARGET_ILL_ILLOPN
;
290 case POWERPC_EXCP_INVAL_SPR
:
291 info
.si_code
= TARGET_ILL_PRVREG
;
293 case POWERPC_EXCP_INVAL_FP
:
294 info
.si_code
= TARGET_ILL_COPROC
;
297 EXCP_DUMP(env
, "Unknown invalid operation (%02x)\n",
298 env
->error_code
& 0xF);
299 info
.si_code
= TARGET_ILL_ILLADR
;
303 case POWERPC_EXCP_PRIV
:
304 info
.si_signo
= TARGET_SIGILL
;
306 switch (env
->error_code
& 0xF) {
307 case POWERPC_EXCP_PRIV_OPC
:
308 info
.si_code
= TARGET_ILL_PRVOPC
;
310 case POWERPC_EXCP_PRIV_REG
:
311 info
.si_code
= TARGET_ILL_PRVREG
;
314 EXCP_DUMP(env
, "Unknown privilege violation (%02x)\n",
315 env
->error_code
& 0xF);
316 info
.si_code
= TARGET_ILL_PRVOPC
;
320 case POWERPC_EXCP_TRAP
:
321 cpu_abort(cs
, "Tried to call a TRAP\n");
324 /* Should not happen ! */
325 cpu_abort(cs
, "Unknown program exception (%02x)\n",
329 info
._sifields
._sigfault
._addr
= env
->nip
;
330 queue_signal(env
, info
.si_signo
, QEMU_SI_FAULT
, &info
);
332 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
333 info
.si_signo
= TARGET_SIGILL
;
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
);
339 case POWERPC_EXCP_SYSCALL
: /* System call exception */
340 cpu_abort(cs
, "Syscall exception while in user mode. "
343 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
344 info
.si_signo
= TARGET_SIGILL
;
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
);
350 case POWERPC_EXCP_DECR
: /* Decrementer exception */
351 cpu_abort(cs
, "Decrementer interrupt while in user mode. "
354 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
355 cpu_abort(cs
, "Fix interval timer interrupt while in user mode. "
358 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
359 cpu_abort(cs
, "Watchdog timer interrupt while in user mode. "
362 case POWERPC_EXCP_DTLB
: /* Data TLB error */
363 cpu_abort(cs
, "Data TLB exception while in user mode. "
366 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
367 cpu_abort(cs
, "Instruction TLB exception while in user mode. "
370 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavail. */
371 info
.si_signo
= TARGET_SIGILL
;
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
);
377 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data IRQ */
378 cpu_abort(cs
, "Embedded floating-point data IRQ not handled\n");
380 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round IRQ */
381 cpu_abort(cs
, "Embedded floating-point round IRQ not handled\n");
383 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor IRQ */
384 cpu_abort(cs
, "Performance monitor exception not handled\n");
386 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
387 cpu_abort(cs
, "Doorbell interrupt while in user mode. "
390 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
391 cpu_abort(cs
, "Doorbell critical interrupt while in user mode. "
394 case POWERPC_EXCP_RESET
: /* System reset exception */
395 cpu_abort(cs
, "Reset interrupt while in user mode. "
398 case POWERPC_EXCP_DSEG
: /* Data segment exception */
399 cpu_abort(cs
, "Data segment exception while in user mode. "
402 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
403 cpu_abort(cs
, "Instruction segment exception "
404 "while in user mode. Aborting\n");
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");
411 case POWERPC_EXCP_TRACE
: /* Trace exception */
413 * we use this exception to emulate step-by-step execution mode.
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");
421 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage excp */
422 cpu_abort(cs
, "Hypervisor instruction storage exception "
423 "while in user mode. Aborting\n");
425 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
426 cpu_abort(cs
, "Hypervisor data segment exception "
427 "while in user mode. Aborting\n");
429 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment excp */
430 cpu_abort(cs
, "Hypervisor instruction segment exception "
431 "while in user mode. Aborting\n");
433 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
434 info
.si_signo
= TARGET_SIGILL
;
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
);
440 case POWERPC_EXCP_PIT
: /* Programmable interval timer IRQ */
441 cpu_abort(cs
, "Programmable interval timer interrupt "
442 "while in user mode. Aborting\n");
444 case POWERPC_EXCP_IO
: /* IO error exception */
445 cpu_abort(cs
, "IO error exception while in user mode. "
448 case POWERPC_EXCP_RUNM
: /* Run mode exception */
449 cpu_abort(cs
, "Run mode exception while in user mode. "
452 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
453 cpu_abort(cs
, "Emulation trap exception not handled\n");
455 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
456 cpu_abort(cs
, "Instruction fetch TLB exception "
457 "while in user-mode. Aborting");
459 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
460 cpu_abort(cs
, "Data load TLB exception while in user-mode. "
463 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
464 cpu_abort(cs
, "Data store TLB exception while in user-mode. "
467 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
468 cpu_abort(cs
, "Floating-point assist exception not handled\n");
470 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
471 cpu_abort(cs
, "Instruction address breakpoint exception "
474 case POWERPC_EXCP_SMI
: /* System management interrupt */
475 cpu_abort(cs
, "System management interrupt while in user mode. "
478 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
479 cpu_abort(cs
, "Thermal interrupt interrupt while in user mode. "
482 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor IRQ */
483 cpu_abort(cs
, "Performance monitor exception not handled\n");
485 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
486 cpu_abort(cs
, "Vector assist exception not handled\n");
488 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
489 cpu_abort(cs
, "Soft patch exception not handled\n");
491 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
492 cpu_abort(cs
, "Maintenance exception while in user mode. "
495 case POWERPC_EXCP_STOP
: /* stop translation */
496 /* We did invalidate the instruction cache. Go on */
498 case POWERPC_EXCP_BRANCH
: /* branch instruction: */
499 /* We just stopped because of a branch. Go on */
501 case POWERPC_EXCP_SYSCALL_USER
:
502 /* system call in user-mode emulation */
504 * PPC ABI uses overflow flag in cr0 to signal an error
509 ret
= do_syscall(env
, env
->gpr
[0], env
->gpr
[3], env
->gpr
[4],
510 env
->gpr
[5], env
->gpr
[6], env
->gpr
[7],
512 if (ret
== -TARGET_ERESTARTSYS
) {
516 if (ret
== (target_ulong
)(-TARGET_QEMU_ESIGRETURN
)) {
517 /* Returning from a successful sigreturn syscall.
518 Avoid corrupting register state. */
521 if (ret
> (target_ulong
)(-515)) {
527 case POWERPC_EXCP_STCX
:
528 if (do_store_exclusive(env
)) {
529 info
.si_signo
= TARGET_SIGSEGV
;
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
);
540 sig
= gdb_handlesig(cs
, TARGET_SIGTRAP
);
544 info
.si_code
= TARGET_TRAP_BRKPT
;
545 queue_signal(env
, info
.si_signo
, QEMU_SI_FAULT
, &info
);
550 /* just indicate that signals should be handled asap */
553 cpu_exec_step_atomic(cs
);
556 cpu_abort(cs
, "Unknown exception 0x%x. Aborting\n", trapnr
);
559 process_pending_signals(env
);
563 void target_cpu_copy_regs(CPUArchState
*env
, struct target_pt_regs
*regs
)
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
);
572 env
->msr
|= (target_ulong
)1 << flag
;
575 env
->nip
= regs
->nip
;
576 for(i
= 0; i
< 32; i
++) {
577 env
->gpr
[i
] = regs
->gpr
[i
];