blob: b803475060ed779ee86fc3e2990b61a669d61a12 [file] [log] [blame]
Blue Swirlad71ed62012-05-30 04:23:22 +00001/*
2 * PowerPC exception emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19#include "cpu.h"
Richard Henderson2ef61752014-04-07 22:31:41 -070020#include "exec/helper-proto.h"
Paolo Bonzinif08b6172014-03-28 19:42:10 +010021#include "exec/cpu_ldst.h"
Blue Swirlad71ed62012-05-30 04:23:22 +000022
23#include "helper_regs.h"
24
25//#define DEBUG_OP
26//#define DEBUG_EXCEPTIONS
27
Blue Swirlc79c73f2012-05-30 04:23:25 +000028#ifdef DEBUG_EXCEPTIONS
29# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
30#else
31# define LOG_EXCP(...) do { } while (0)
32#endif
33
34/*****************************************************************************/
35/* PowerPC Hypercall emulation */
36
Andreas Färber1b146702012-05-03 06:03:45 +020037void (*cpu_ppc_hypercall)(PowerPCCPU *);
Blue Swirlc79c73f2012-05-30 04:23:25 +000038
39/*****************************************************************************/
40/* Exception processing */
41#if defined(CONFIG_USER_ONLY)
Andreas Färber97a8ea52013-02-02 10:57:51 +010042void ppc_cpu_do_interrupt(CPUState *cs)
Blue Swirlc79c73f2012-05-30 04:23:25 +000043{
Andreas Färber97a8ea52013-02-02 10:57:51 +010044 PowerPCCPU *cpu = POWERPC_CPU(cs);
45 CPUPPCState *env = &cpu->env;
46
Andreas Färber27103422013-08-26 08:31:06 +020047 cs->exception_index = POWERPC_EXCP_NONE;
Blue Swirlc79c73f2012-05-30 04:23:25 +000048 env->error_code = 0;
49}
50
Richard Henderson458dd762014-09-13 09:45:32 -070051static void ppc_hw_interrupt(CPUPPCState *env)
Blue Swirlc79c73f2012-05-30 04:23:25 +000052{
Andreas Färber27103422013-08-26 08:31:06 +020053 CPUState *cs = CPU(ppc_env_get_cpu(env));
54
55 cs->exception_index = POWERPC_EXCP_NONE;
Blue Swirlc79c73f2012-05-30 04:23:25 +000056 env->error_code = 0;
57}
58#else /* defined(CONFIG_USER_ONLY) */
59static inline void dump_syscall(CPUPPCState *env)
60{
61 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
62 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
63 " nip=" TARGET_FMT_lx "\n",
64 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
65 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
66 ppc_dump_gpr(env, 6), env->nip);
67}
68
69/* Note that this function should be greatly optimized
70 * when called with a constant excp, from ppc_hw_interrupt
71 */
Andreas Färber5c26a5b2012-05-03 05:55:58 +020072static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
Blue Swirlc79c73f2012-05-30 04:23:25 +000073{
Andreas Färber27103422013-08-26 08:31:06 +020074 CPUState *cs = CPU(cpu);
Andreas Färber5c26a5b2012-05-03 05:55:58 +020075 CPUPPCState *env = &cpu->env;
Blue Swirlc79c73f2012-05-30 04:23:25 +000076 target_ulong msr, new_msr, vector;
77 int srr0, srr1, asrr0, asrr1;
78 int lpes0, lpes1, lev;
79
80 if (0) {
81 /* XXX: find a suitable condition to enable the hypervisor mode */
82 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
83 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
84 } else {
85 /* Those values ensure we won't enter the hypervisor mode */
86 lpes0 = 0;
87 lpes1 = 1;
88 }
89
90 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
91 " => %08x (%02x)\n", env->nip, excp, env->error_code);
92
93 /* new srr1 value excluding must-be-zero bits */
Scott Wooda1bb7382012-12-21 16:15:41 +000094 if (excp_model == POWERPC_EXCP_BOOKE) {
95 msr = env->msr;
96 } else {
97 msr = env->msr & ~0x783f0000ULL;
98 }
Blue Swirlc79c73f2012-05-30 04:23:25 +000099
100 /* new interrupt handler msr */
101 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
102
103 /* target registers */
104 srr0 = SPR_SRR0;
105 srr1 = SPR_SRR1;
106 asrr0 = -1;
107 asrr1 = -1;
108
109 switch (excp) {
110 case POWERPC_EXCP_NONE:
111 /* Should never happen */
112 return;
113 case POWERPC_EXCP_CRITICAL: /* Critical input */
114 switch (excp_model) {
115 case POWERPC_EXCP_40x:
116 srr0 = SPR_40x_SRR2;
117 srr1 = SPR_40x_SRR3;
118 break;
119 case POWERPC_EXCP_BOOKE:
120 srr0 = SPR_BOOKE_CSRR0;
121 srr1 = SPR_BOOKE_CSRR1;
122 break;
123 case POWERPC_EXCP_G2:
124 break;
125 default:
126 goto excp_invalid;
127 }
128 goto store_next;
129 case POWERPC_EXCP_MCHECK: /* Machine check exception */
130 if (msr_me == 0) {
131 /* Machine check exception is not enabled.
132 * Enter checkstop state.
133 */
134 if (qemu_log_enabled()) {
135 qemu_log("Machine check while not allowed. "
136 "Entering checkstop state\n");
137 } else {
138 fprintf(stderr, "Machine check while not allowed. "
139 "Entering checkstop state\n");
140 }
Andreas Färber259186a2013-01-17 18:51:17 +0100141 cs->halted = 1;
142 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000143 }
144 if (0) {
145 /* XXX: find a suitable condition to enable the hypervisor mode */
146 new_msr |= (target_ulong)MSR_HVB;
147 }
148
149 /* machine check exceptions don't have ME set */
150 new_msr &= ~((target_ulong)1 << MSR_ME);
151
152 /* XXX: should also have something loaded in DAR / DSISR */
153 switch (excp_model) {
154 case POWERPC_EXCP_40x:
155 srr0 = SPR_40x_SRR2;
156 srr1 = SPR_40x_SRR3;
157 break;
158 case POWERPC_EXCP_BOOKE:
Scott Wooda1bb7382012-12-21 16:15:41 +0000159 /* FIXME: choose one or the other based on CPU type */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000160 srr0 = SPR_BOOKE_MCSRR0;
161 srr1 = SPR_BOOKE_MCSRR1;
162 asrr0 = SPR_BOOKE_CSRR0;
163 asrr1 = SPR_BOOKE_CSRR1;
164 break;
165 default:
166 break;
167 }
168 goto store_next;
169 case POWERPC_EXCP_DSI: /* Data storage exception */
170 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
171 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
172 if (lpes1 == 0) {
173 new_msr |= (target_ulong)MSR_HVB;
174 }
175 goto store_next;
176 case POWERPC_EXCP_ISI: /* Instruction storage exception */
177 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
178 "\n", msr, env->nip);
179 if (lpes1 == 0) {
180 new_msr |= (target_ulong)MSR_HVB;
181 }
182 msr |= env->error_code;
183 goto store_next;
184 case POWERPC_EXCP_EXTERNAL: /* External input */
Edgar E. Iglesiasfdfba1a2013-11-15 14:46:38 +0100185 cs = CPU(cpu);
186
Blue Swirlc79c73f2012-05-30 04:23:25 +0000187 if (lpes0 == 1) {
188 new_msr |= (target_ulong)MSR_HVB;
189 }
Alexander Graf68c2dd72013-01-04 11:21:04 +0100190 if (env->mpic_proxy) {
191 /* IACK the IRQ on delivery */
Edgar E. Iglesiasfdfba1a2013-11-15 14:46:38 +0100192 env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
Alexander Graf68c2dd72013-01-04 11:21:04 +0100193 }
Blue Swirlc79c73f2012-05-30 04:23:25 +0000194 goto store_next;
195 case POWERPC_EXCP_ALIGN: /* Alignment exception */
196 if (lpes1 == 0) {
197 new_msr |= (target_ulong)MSR_HVB;
198 }
199 /* XXX: this is false */
200 /* Get rS/rD and rA from faulting opcode */
Blue Swirl2f5a1892012-05-30 04:23:40 +0000201 env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
202 & 0x03FF0000) >> 16;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000203 goto store_current;
204 case POWERPC_EXCP_PROGRAM: /* Program exception */
205 switch (env->error_code & ~0xF) {
206 case POWERPC_EXCP_FP:
207 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
208 LOG_EXCP("Ignore floating point exception\n");
Andreas Färber27103422013-08-26 08:31:06 +0200209 cs->exception_index = POWERPC_EXCP_NONE;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000210 env->error_code = 0;
211 return;
212 }
213 if (lpes1 == 0) {
214 new_msr |= (target_ulong)MSR_HVB;
215 }
216 msr |= 0x00100000;
217 if (msr_fe0 == msr_fe1) {
218 goto store_next;
219 }
220 msr |= 0x00010000;
221 break;
222 case POWERPC_EXCP_INVAL:
223 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
224 if (lpes1 == 0) {
225 new_msr |= (target_ulong)MSR_HVB;
226 }
227 msr |= 0x00080000;
228 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
229 break;
230 case POWERPC_EXCP_PRIV:
231 if (lpes1 == 0) {
232 new_msr |= (target_ulong)MSR_HVB;
233 }
234 msr |= 0x00040000;
235 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
236 break;
237 case POWERPC_EXCP_TRAP:
238 if (lpes1 == 0) {
239 new_msr |= (target_ulong)MSR_HVB;
240 }
241 msr |= 0x00020000;
242 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
243 break;
244 default:
245 /* Should never occur */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200246 cpu_abort(cs, "Invalid program exception %d. Aborting\n",
Blue Swirlc79c73f2012-05-30 04:23:25 +0000247 env->error_code);
248 break;
249 }
250 goto store_current;
251 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
252 if (lpes1 == 0) {
253 new_msr |= (target_ulong)MSR_HVB;
254 }
255 goto store_current;
256 case POWERPC_EXCP_SYSCALL: /* System call exception */
257 dump_syscall(env);
258 lev = env->error_code;
259 if ((lev == 1) && cpu_ppc_hypercall) {
Andreas Färber1b146702012-05-03 06:03:45 +0200260 cpu_ppc_hypercall(cpu);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000261 return;
262 }
263 if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
264 new_msr |= (target_ulong)MSR_HVB;
265 }
266 goto store_next;
267 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
268 goto store_current;
269 case POWERPC_EXCP_DECR: /* Decrementer exception */
270 if (lpes1 == 0) {
271 new_msr |= (target_ulong)MSR_HVB;
272 }
273 goto store_next;
274 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
275 /* FIT on 4xx */
276 LOG_EXCP("FIT exception\n");
277 goto store_next;
278 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
279 LOG_EXCP("WDT exception\n");
280 switch (excp_model) {
281 case POWERPC_EXCP_BOOKE:
282 srr0 = SPR_BOOKE_CSRR0;
283 srr1 = SPR_BOOKE_CSRR1;
284 break;
285 default:
286 break;
287 }
288 goto store_next;
289 case POWERPC_EXCP_DTLB: /* Data TLB error */
290 goto store_next;
291 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
292 goto store_next;
293 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
294 switch (excp_model) {
295 case POWERPC_EXCP_BOOKE:
Scott Wooda1bb7382012-12-21 16:15:41 +0000296 /* FIXME: choose one or the other based on CPU type */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000297 srr0 = SPR_BOOKE_DSRR0;
298 srr1 = SPR_BOOKE_DSRR1;
299 asrr0 = SPR_BOOKE_CSRR0;
300 asrr1 = SPR_BOOKE_CSRR1;
301 break;
302 default:
303 break;
304 }
305 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200306 cpu_abort(cs, "Debug exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000307 goto store_next;
308 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
309 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
310 goto store_current;
311 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
312 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200313 cpu_abort(cs, "Embedded floating point data exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000314 "is not implemented yet !\n");
315 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
316 goto store_next;
317 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
318 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200319 cpu_abort(cs, "Embedded floating point round exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000320 "is not implemented yet !\n");
321 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
322 goto store_next;
323 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
324 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200325 cpu_abort(cs,
Blue Swirlc79c73f2012-05-30 04:23:25 +0000326 "Performance counter exception is not implemented yet !\n");
327 goto store_next;
328 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
329 goto store_next;
330 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
331 srr0 = SPR_BOOKE_CSRR0;
332 srr1 = SPR_BOOKE_CSRR1;
333 goto store_next;
334 case POWERPC_EXCP_RESET: /* System reset exception */
335 if (msr_pow) {
336 /* indicate that we resumed from power save mode */
337 msr |= 0x10000;
338 } else {
339 new_msr &= ~((target_ulong)1 << MSR_ME);
340 }
341
342 if (0) {
343 /* XXX: find a suitable condition to enable the hypervisor mode */
344 new_msr |= (target_ulong)MSR_HVB;
345 }
346 goto store_next;
347 case POWERPC_EXCP_DSEG: /* Data segment exception */
348 if (lpes1 == 0) {
349 new_msr |= (target_ulong)MSR_HVB;
350 }
351 goto store_next;
352 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
353 if (lpes1 == 0) {
354 new_msr |= (target_ulong)MSR_HVB;
355 }
356 goto store_next;
357 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
358 srr0 = SPR_HSRR0;
359 srr1 = SPR_HSRR1;
360 new_msr |= (target_ulong)MSR_HVB;
361 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
362 goto store_next;
363 case POWERPC_EXCP_TRACE: /* Trace exception */
364 if (lpes1 == 0) {
365 new_msr |= (target_ulong)MSR_HVB;
366 }
367 goto store_next;
368 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
369 srr0 = SPR_HSRR0;
370 srr1 = SPR_HSRR1;
371 new_msr |= (target_ulong)MSR_HVB;
372 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
373 goto store_next;
374 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
375 srr0 = SPR_HSRR0;
376 srr1 = SPR_HSRR1;
377 new_msr |= (target_ulong)MSR_HVB;
378 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
379 goto store_next;
380 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
381 srr0 = SPR_HSRR0;
382 srr1 = SPR_HSRR1;
383 new_msr |= (target_ulong)MSR_HVB;
384 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
385 goto store_next;
386 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
387 srr0 = SPR_HSRR0;
388 srr1 = SPR_HSRR1;
389 new_msr |= (target_ulong)MSR_HVB;
390 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
391 goto store_next;
392 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
393 if (lpes1 == 0) {
394 new_msr |= (target_ulong)MSR_HVB;
395 }
396 goto store_current;
Tom Musta1f298712013-10-22 22:06:17 +1100397 case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
398 if (lpes1 == 0) {
399 new_msr |= (target_ulong)MSR_HVB;
400 }
401 goto store_current;
Alexey Kardashevskiy7019cb32014-06-04 22:50:56 +1000402 case POWERPC_EXCP_FU: /* Facility unavailable exception */
403 if (lpes1 == 0) {
404 new_msr |= (target_ulong)MSR_HVB;
405 }
406 goto store_current;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000407 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
408 LOG_EXCP("PIT exception\n");
409 goto store_next;
410 case POWERPC_EXCP_IO: /* IO error exception */
411 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200412 cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000413 goto store_next;
414 case POWERPC_EXCP_RUNM: /* Run mode exception */
415 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200416 cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000417 goto store_next;
418 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
419 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200420 cpu_abort(cs, "602 emulation trap exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000421 "is not implemented yet !\n");
422 goto store_next;
423 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
424 if (lpes1 == 0) { /* XXX: check this */
425 new_msr |= (target_ulong)MSR_HVB;
426 }
427 switch (excp_model) {
428 case POWERPC_EXCP_602:
429 case POWERPC_EXCP_603:
430 case POWERPC_EXCP_603E:
431 case POWERPC_EXCP_G2:
432 goto tlb_miss_tgpr;
433 case POWERPC_EXCP_7x5:
434 goto tlb_miss;
435 case POWERPC_EXCP_74xx:
436 goto tlb_miss_74xx;
437 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200438 cpu_abort(cs, "Invalid instruction TLB miss exception\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000439 break;
440 }
441 break;
442 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
443 if (lpes1 == 0) { /* XXX: check this */
444 new_msr |= (target_ulong)MSR_HVB;
445 }
446 switch (excp_model) {
447 case POWERPC_EXCP_602:
448 case POWERPC_EXCP_603:
449 case POWERPC_EXCP_603E:
450 case POWERPC_EXCP_G2:
451 goto tlb_miss_tgpr;
452 case POWERPC_EXCP_7x5:
453 goto tlb_miss;
454 case POWERPC_EXCP_74xx:
455 goto tlb_miss_74xx;
456 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200457 cpu_abort(cs, "Invalid data load TLB miss exception\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000458 break;
459 }
460 break;
461 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
462 if (lpes1 == 0) { /* XXX: check this */
463 new_msr |= (target_ulong)MSR_HVB;
464 }
465 switch (excp_model) {
466 case POWERPC_EXCP_602:
467 case POWERPC_EXCP_603:
468 case POWERPC_EXCP_603E:
469 case POWERPC_EXCP_G2:
470 tlb_miss_tgpr:
471 /* Swap temporary saved registers with GPRs */
472 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
473 new_msr |= (target_ulong)1 << MSR_TGPR;
474 hreg_swap_gpr_tgpr(env);
475 }
476 goto tlb_miss;
477 case POWERPC_EXCP_7x5:
478 tlb_miss:
479#if defined(DEBUG_SOFTWARE_TLB)
480 if (qemu_log_enabled()) {
481 const char *es;
482 target_ulong *miss, *cmp;
483 int en;
484
485 if (excp == POWERPC_EXCP_IFTLB) {
486 es = "I";
487 en = 'I';
488 miss = &env->spr[SPR_IMISS];
489 cmp = &env->spr[SPR_ICMP];
490 } else {
491 if (excp == POWERPC_EXCP_DLTLB) {
492 es = "DL";
493 } else {
494 es = "DS";
495 }
496 en = 'D';
497 miss = &env->spr[SPR_DMISS];
498 cmp = &env->spr[SPR_DCMP];
499 }
500 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
501 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
502 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
503 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
504 env->error_code);
505 }
506#endif
507 msr |= env->crf[0] << 28;
508 msr |= env->error_code; /* key, D/I, S/L bits */
509 /* Set way using a LRU mechanism */
510 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
511 break;
512 case POWERPC_EXCP_74xx:
513 tlb_miss_74xx:
514#if defined(DEBUG_SOFTWARE_TLB)
515 if (qemu_log_enabled()) {
516 const char *es;
517 target_ulong *miss, *cmp;
518 int en;
519
520 if (excp == POWERPC_EXCP_IFTLB) {
521 es = "I";
522 en = 'I';
523 miss = &env->spr[SPR_TLBMISS];
524 cmp = &env->spr[SPR_PTEHI];
525 } else {
526 if (excp == POWERPC_EXCP_DLTLB) {
527 es = "DL";
528 } else {
529 es = "DS";
530 }
531 en = 'D';
532 miss = &env->spr[SPR_TLBMISS];
533 cmp = &env->spr[SPR_PTEHI];
534 }
535 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
536 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
537 env->error_code);
538 }
539#endif
540 msr |= env->error_code; /* key bit */
541 break;
542 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200543 cpu_abort(cs, "Invalid data store TLB miss exception\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000544 break;
545 }
546 goto store_next;
547 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
548 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200549 cpu_abort(cs, "Floating point assist exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000550 "is not implemented yet !\n");
551 goto store_next;
552 case POWERPC_EXCP_DABR: /* Data address breakpoint */
553 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200554 cpu_abort(cs, "DABR exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000555 goto store_next;
556 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
557 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200558 cpu_abort(cs, "IABR exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000559 goto store_next;
560 case POWERPC_EXCP_SMI: /* System management interrupt */
561 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200562 cpu_abort(cs, "SMI exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000563 goto store_next;
564 case POWERPC_EXCP_THERM: /* Thermal interrupt */
565 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200566 cpu_abort(cs, "Thermal management exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000567 "is not implemented yet !\n");
568 goto store_next;
569 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
570 if (lpes1 == 0) {
571 new_msr |= (target_ulong)MSR_HVB;
572 }
573 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200574 cpu_abort(cs,
Blue Swirlc79c73f2012-05-30 04:23:25 +0000575 "Performance counter exception is not implemented yet !\n");
576 goto store_next;
577 case POWERPC_EXCP_VPUA: /* Vector assist exception */
578 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200579 cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000580 goto store_next;
581 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
582 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200583 cpu_abort(cs,
Blue Swirlc79c73f2012-05-30 04:23:25 +0000584 "970 soft-patch exception is not implemented yet !\n");
585 goto store_next;
586 case POWERPC_EXCP_MAINT: /* Maintenance exception */
587 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200588 cpu_abort(cs,
Blue Swirlc79c73f2012-05-30 04:23:25 +0000589 "970 maintenance exception is not implemented yet !\n");
590 goto store_next;
591 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
592 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200593 cpu_abort(cs, "Maskable external exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000594 "is not implemented yet !\n");
595 goto store_next;
596 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
597 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200598 cpu_abort(cs, "Non maskable external exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000599 "is not implemented yet !\n");
600 goto store_next;
601 default:
602 excp_invalid:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200603 cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000604 break;
605 store_current:
606 /* save current instruction location */
607 env->spr[srr0] = env->nip - 4;
608 break;
609 store_next:
610 /* save next instruction location */
611 env->spr[srr0] = env->nip;
612 break;
613 }
614 /* Save MSR */
615 env->spr[srr1] = msr;
616 /* If any alternate SRR register are defined, duplicate saved values */
617 if (asrr0 != -1) {
618 env->spr[asrr0] = env->spr[srr0];
619 }
620 if (asrr1 != -1) {
621 env->spr[asrr1] = env->spr[srr1];
622 }
Alexey Kardashevskiyd5ac4f52014-06-04 22:51:05 +1000623
624 if (env->spr[SPR_LPCR] & LPCR_AIL) {
625 new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
626 } else if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
627 /* If we disactivated any translation, flush TLBs */
Andreas Färber00c8cb02013-09-04 02:19:44 +0200628 tlb_flush(cs, 1);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000629 }
630
Anton Blanchard1e0c7e52013-08-07 10:47:01 +1000631#ifdef TARGET_PPC64
632 if (excp_model == POWERPC_EXCP_POWER7) {
633 if (env->spr[SPR_LPCR] & LPCR_ILE) {
634 new_msr |= (target_ulong)1 << MSR_LE;
635 }
636 } else if (msr_ile) {
637 new_msr |= (target_ulong)1 << MSR_LE;
638 }
639#else
Blue Swirlc79c73f2012-05-30 04:23:25 +0000640 if (msr_ile) {
641 new_msr |= (target_ulong)1 << MSR_LE;
642 }
Anton Blanchard1e0c7e52013-08-07 10:47:01 +1000643#endif
Blue Swirlc79c73f2012-05-30 04:23:25 +0000644
645 /* Jump to handler */
646 vector = env->excp_vectors[excp];
647 if (vector == (target_ulong)-1ULL) {
Andreas Färbera47dddd2013-09-03 17:38:47 +0200648 cpu_abort(cs, "Raised an exception without defined vector %d\n",
Blue Swirlc79c73f2012-05-30 04:23:25 +0000649 excp);
650 }
651 vector |= env->excp_prefix;
652#if defined(TARGET_PPC64)
653 if (excp_model == POWERPC_EXCP_BOOKE) {
Alexander Grafe42a61f2012-06-20 21:20:29 +0200654 if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
655 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000656 new_msr |= (target_ulong)1 << MSR_CM;
Alexander Grafe42a61f2012-06-20 21:20:29 +0200657 } else {
658 vector = (uint32_t)vector;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000659 }
660 } else {
661 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
662 vector = (uint32_t)vector;
663 } else {
664 new_msr |= (target_ulong)1 << MSR_SF;
665 }
666 }
667#endif
668 /* XXX: we don't use hreg_store_msr here as already have treated
669 * any special case that could occur. Just store MSR and update hflags
670 */
671 env->msr = new_msr & env->msr_mask;
672 hreg_compute_hflags(env);
673 env->nip = vector;
674 /* Reset exception state */
Andreas Färber27103422013-08-26 08:31:06 +0200675 cs->exception_index = POWERPC_EXCP_NONE;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000676 env->error_code = 0;
677
678 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
679 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
680 /* XXX: The BookE changes address space when switching modes,
681 we should probably implement that as different MMU indexes,
682 but for the moment we do it the slow way and flush all. */
Andreas Färber00c8cb02013-09-04 02:19:44 +0200683 tlb_flush(cs, 1);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000684 }
685}
686
Andreas Färber97a8ea52013-02-02 10:57:51 +0100687void ppc_cpu_do_interrupt(CPUState *cs)
Blue Swirlc79c73f2012-05-30 04:23:25 +0000688{
Andreas Färber97a8ea52013-02-02 10:57:51 +0100689 PowerPCCPU *cpu = POWERPC_CPU(cs);
690 CPUPPCState *env = &cpu->env;
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200691
Andreas Färber27103422013-08-26 08:31:06 +0200692 powerpc_excp(cpu, env->excp_model, cs->exception_index);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000693}
694
Richard Henderson458dd762014-09-13 09:45:32 -0700695static void ppc_hw_interrupt(CPUPPCState *env)
Blue Swirlc79c73f2012-05-30 04:23:25 +0000696{
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200697 PowerPCCPU *cpu = ppc_env_get_cpu(env);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000698 int hdice;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000699#if 0
Andreas Färber259186a2013-01-17 18:51:17 +0100700 CPUState *cs = CPU(cpu);
701
Blue Swirlc79c73f2012-05-30 04:23:25 +0000702 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
Andreas Färber259186a2013-01-17 18:51:17 +0100703 __func__, env, env->pending_interrupts,
704 cs->interrupt_request, (int)msr_me, (int)msr_ee);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000705#endif
706 /* External reset */
707 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
708 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200709 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000710 return;
711 }
712 /* Machine check exception */
713 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
714 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200715 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000716 return;
717 }
718#if 0 /* TODO */
719 /* External debug exception */
720 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
721 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200722 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000723 return;
724 }
725#endif
726 if (0) {
727 /* XXX: find a suitable condition to enable the hypervisor mode */
728 hdice = env->spr[SPR_LPCR] & 1;
729 } else {
730 hdice = 0;
731 }
732 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
733 /* Hypervisor decrementer exception */
734 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200735 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000736 return;
737 }
738 }
739 if (msr_ce != 0) {
740 /* External critical interrupt */
741 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
742 /* Taking a critical external interrupt does not clear the external
743 * critical interrupt status
744 */
745#if 0
746 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
747#endif
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200748 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000749 return;
750 }
751 }
752 if (msr_ee != 0) {
753 /* Watchdog timer on embedded PowerPC */
754 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
755 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200756 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000757 return;
758 }
759 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
760 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200761 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000762 return;
763 }
764 /* Fixed interval timer on embedded PowerPC */
765 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
766 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200767 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000768 return;
769 }
770 /* Programmable interval timer on embedded PowerPC */
771 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
772 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200773 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000774 return;
775 }
776 /* Decrementer exception */
777 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
Alexander Grafe81a9822014-04-06 01:32:06 +0200778 if (ppc_decr_clear_on_delivery(env)) {
779 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
780 }
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200781 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000782 return;
783 }
784 /* External interrupt */
785 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
786 /* Taking an external interrupt does not clear the external
787 * interrupt status
788 */
789#if 0
790 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
791#endif
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200792 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000793 return;
794 }
795 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
796 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200797 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000798 return;
799 }
800 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
801 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200802 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000803 return;
804 }
805 /* Thermal interrupt */
806 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
807 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200808 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000809 return;
810 }
811 }
812}
Alexey Kardashevskiy34316482014-08-20 22:16:36 +1000813
814void ppc_cpu_do_system_reset(CPUState *cs)
815{
816 PowerPCCPU *cpu = POWERPC_CPU(cs);
817 CPUPPCState *env = &cpu->env;
818
819 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
820}
Blue Swirlc79c73f2012-05-30 04:23:25 +0000821#endif /* !CONFIG_USER_ONLY */
822
Richard Henderson458dd762014-09-13 09:45:32 -0700823bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
824{
825 PowerPCCPU *cpu = POWERPC_CPU(cs);
826 CPUPPCState *env = &cpu->env;
827
828 if (interrupt_request & CPU_INTERRUPT_HARD) {
829 ppc_hw_interrupt(env);
830 if (env->pending_interrupts == 0) {
831 cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
832 }
833 return true;
834 }
835 return false;
836}
837
Blue Swirlc79c73f2012-05-30 04:23:25 +0000838#if defined(DEBUG_OP)
839static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
840{
841 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
842 TARGET_FMT_lx "\n", RA, msr);
843}
844#endif
845
Blue Swirlad71ed62012-05-30 04:23:22 +0000846/*****************************************************************************/
847/* Exceptions processing helpers */
848
Blue Swirle5f17ac2012-05-30 04:23:23 +0000849void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
850 uint32_t error_code)
Blue Swirlad71ed62012-05-30 04:23:22 +0000851{
Andreas Färber27103422013-08-26 08:31:06 +0200852 CPUState *cs = CPU(ppc_env_get_cpu(env));
853
Blue Swirlad71ed62012-05-30 04:23:22 +0000854#if 0
855 printf("Raise exception %3x code : %d\n", exception, error_code);
856#endif
Andreas Färber27103422013-08-26 08:31:06 +0200857 cs->exception_index = exception;
Blue Swirlad71ed62012-05-30 04:23:22 +0000858 env->error_code = error_code;
Andreas Färber5638d182013-08-27 17:52:12 +0200859 cpu_loop_exit(cs);
Blue Swirlad71ed62012-05-30 04:23:22 +0000860}
861
Blue Swirle5f17ac2012-05-30 04:23:23 +0000862void helper_raise_exception(CPUPPCState *env, uint32_t exception)
Blue Swirlad71ed62012-05-30 04:23:22 +0000863{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000864 helper_raise_exception_err(env, exception, 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000865}
866
867#if !defined(CONFIG_USER_ONLY)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000868void helper_store_msr(CPUPPCState *env, target_ulong val)
Blue Swirlad71ed62012-05-30 04:23:22 +0000869{
Andreas Färber259186a2013-01-17 18:51:17 +0100870 CPUState *cs;
871
Blue Swirlad71ed62012-05-30 04:23:22 +0000872 val = hreg_store_msr(env, val, 0);
873 if (val != 0) {
Andreas Färber259186a2013-01-17 18:51:17 +0100874 cs = CPU(ppc_env_get_cpu(env));
875 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirle5f17ac2012-05-30 04:23:23 +0000876 helper_raise_exception(env, val);
Blue Swirlad71ed62012-05-30 04:23:22 +0000877 }
878}
879
Blue Swirle5f17ac2012-05-30 04:23:23 +0000880static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
Blue Swirlad71ed62012-05-30 04:23:22 +0000881 target_ulong msrm, int keep_msrh)
882{
Andreas Färber259186a2013-01-17 18:51:17 +0100883 CPUState *cs = CPU(ppc_env_get_cpu(env));
884
Blue Swirlad71ed62012-05-30 04:23:22 +0000885#if defined(TARGET_PPC64)
Alexander Grafe42a61f2012-06-20 21:20:29 +0200886 if (msr_is_64bit(env, msr)) {
Blue Swirlad71ed62012-05-30 04:23:22 +0000887 nip = (uint64_t)nip;
888 msr &= (uint64_t)msrm;
889 } else {
890 nip = (uint32_t)nip;
891 msr = (uint32_t)(msr & msrm);
892 if (keep_msrh) {
893 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
894 }
895 }
896#else
897 nip = (uint32_t)nip;
898 msr &= (uint32_t)msrm;
899#endif
900 /* XXX: beware: this is false if VLE is supported */
901 env->nip = nip & ~((target_ulong)0x00000003);
902 hreg_store_msr(env, msr, 1);
903#if defined(DEBUG_OP)
904 cpu_dump_rfi(env->nip, env->msr);
905#endif
906 /* No need to raise an exception here,
907 * as rfi is always the last insn of a TB
908 */
Andreas Färber259186a2013-01-17 18:51:17 +0100909 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirlad71ed62012-05-30 04:23:22 +0000910}
911
Blue Swirle5f17ac2012-05-30 04:23:23 +0000912void helper_rfi(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000913{
Scott Wooda1bb7382012-12-21 16:15:41 +0000914 if (env->excp_model == POWERPC_EXCP_BOOKE) {
915 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
916 ~((target_ulong)0), 0);
917 } else {
918 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
919 ~((target_ulong)0x783F0000), 1);
920 }
Blue Swirlad71ed62012-05-30 04:23:22 +0000921}
922
923#if defined(TARGET_PPC64)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000924void helper_rfid(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000925{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000926 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
Blue Swirlad71ed62012-05-30 04:23:22 +0000927 ~((target_ulong)0x783F0000), 0);
928}
929
Blue Swirle5f17ac2012-05-30 04:23:23 +0000930void helper_hrfid(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000931{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000932 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
Blue Swirlad71ed62012-05-30 04:23:22 +0000933 ~((target_ulong)0x783F0000), 0);
934}
935#endif
936
937/*****************************************************************************/
938/* Embedded PowerPC specific helpers */
Blue Swirle5f17ac2012-05-30 04:23:23 +0000939void helper_40x_rfci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000940{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000941 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
Blue Swirlad71ed62012-05-30 04:23:22 +0000942 ~((target_ulong)0xFFFF0000), 0);
943}
944
Blue Swirle5f17ac2012-05-30 04:23:23 +0000945void helper_rfci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000946{
Scott Wooda1bb7382012-12-21 16:15:41 +0000947 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
948 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000949}
950
Blue Swirle5f17ac2012-05-30 04:23:23 +0000951void helper_rfdi(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000952{
Scott Wooda1bb7382012-12-21 16:15:41 +0000953 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
954 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
955 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000956}
957
Blue Swirle5f17ac2012-05-30 04:23:23 +0000958void helper_rfmci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000959{
Scott Wooda1bb7382012-12-21 16:15:41 +0000960 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
961 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
962 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000963}
964#endif
965
Blue Swirle5f17ac2012-05-30 04:23:23 +0000966void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
967 uint32_t flags)
Blue Swirlad71ed62012-05-30 04:23:22 +0000968{
969 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
970 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
971 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
972 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
973 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
Blue Swirle5f17ac2012-05-30 04:23:23 +0000974 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
975 POWERPC_EXCP_TRAP);
Blue Swirlad71ed62012-05-30 04:23:22 +0000976 }
977}
978
979#if defined(TARGET_PPC64)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000980void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
981 uint32_t flags)
Blue Swirlad71ed62012-05-30 04:23:22 +0000982{
983 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
984 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
985 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
986 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
987 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
Blue Swirle5f17ac2012-05-30 04:23:23 +0000988 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
989 POWERPC_EXCP_TRAP);
Blue Swirlad71ed62012-05-30 04:23:22 +0000990 }
991}
992#endif
993
994#if !defined(CONFIG_USER_ONLY)
995/*****************************************************************************/
996/* PowerPC 601 specific instructions (POWER bridge) */
997
Blue Swirle5f17ac2012-05-30 04:23:23 +0000998void helper_rfsvc(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000999{
Blue Swirle5f17ac2012-05-30 04:23:23 +00001000 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
Blue Swirlad71ed62012-05-30 04:23:22 +00001001}
1002
1003/* Embedded.Processor Control */
1004static int dbell2irq(target_ulong rb)
1005{
1006 int msg = rb & DBELL_TYPE_MASK;
1007 int irq = -1;
1008
1009 switch (msg) {
1010 case DBELL_TYPE_DBELL:
1011 irq = PPC_INTERRUPT_DOORBELL;
1012 break;
1013 case DBELL_TYPE_DBELL_CRIT:
1014 irq = PPC_INTERRUPT_CDOORBELL;
1015 break;
1016 case DBELL_TYPE_G_DBELL:
1017 case DBELL_TYPE_G_DBELL_CRIT:
1018 case DBELL_TYPE_G_DBELL_MC:
1019 /* XXX implement */
1020 default:
1021 break;
1022 }
1023
1024 return irq;
1025}
1026
Blue Swirle5f17ac2012-05-30 04:23:23 +00001027void helper_msgclr(CPUPPCState *env, target_ulong rb)
Blue Swirlad71ed62012-05-30 04:23:22 +00001028{
1029 int irq = dbell2irq(rb);
1030
1031 if (irq < 0) {
1032 return;
1033 }
1034
1035 env->pending_interrupts &= ~(1 << irq);
1036}
1037
1038void helper_msgsnd(target_ulong rb)
1039{
1040 int irq = dbell2irq(rb);
1041 int pir = rb & DBELL_PIRTAG_MASK;
Andreas Färber182735e2013-05-29 22:29:20 +02001042 CPUState *cs;
Blue Swirlad71ed62012-05-30 04:23:22 +00001043
1044 if (irq < 0) {
1045 return;
1046 }
1047
Andreas Färberbdc44642013-06-24 23:50:24 +02001048 CPU_FOREACH(cs) {
Andreas Färber182735e2013-05-29 22:29:20 +02001049 PowerPCCPU *cpu = POWERPC_CPU(cs);
1050 CPUPPCState *cenv = &cpu->env;
1051
Blue Swirlad71ed62012-05-30 04:23:22 +00001052 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1053 cenv->pending_interrupts |= 1 << irq;
Andreas Färber182735e2013-05-29 22:29:20 +02001054 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
Blue Swirlad71ed62012-05-30 04:23:22 +00001055 }
1056 }
1057}
1058#endif