root / target-ppc / excp_helper.c @ 7d08d856
History | View | Annotate | Download (34.2 kB)
1 | ad71ed68 | Blue Swirl | /*
|
---|---|---|---|
2 | ad71ed68 | Blue Swirl | * PowerPC exception emulation helpers for QEMU.
|
3 | ad71ed68 | Blue Swirl | *
|
4 | ad71ed68 | Blue Swirl | * Copyright (c) 2003-2007 Jocelyn Mayer
|
5 | ad71ed68 | Blue Swirl | *
|
6 | ad71ed68 | Blue Swirl | * This library is free software; you can redistribute it and/or
|
7 | ad71ed68 | Blue Swirl | * modify it under the terms of the GNU Lesser General Public
|
8 | ad71ed68 | Blue Swirl | * License as published by the Free Software Foundation; either
|
9 | ad71ed68 | Blue Swirl | * version 2 of the License, or (at your option) any later version.
|
10 | ad71ed68 | Blue Swirl | *
|
11 | ad71ed68 | Blue Swirl | * This library is distributed in the hope that it will be useful,
|
12 | ad71ed68 | Blue Swirl | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | ad71ed68 | Blue Swirl | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | ad71ed68 | Blue Swirl | * Lesser General Public License for more details.
|
15 | ad71ed68 | Blue Swirl | *
|
16 | ad71ed68 | Blue Swirl | * You should have received a copy of the GNU Lesser General Public
|
17 | ad71ed68 | Blue Swirl | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
18 | ad71ed68 | Blue Swirl | */
|
19 | ad71ed68 | Blue Swirl | #include "cpu.h" |
20 | ad71ed68 | Blue Swirl | #include "helper.h" |
21 | ad71ed68 | Blue Swirl | |
22 | ad71ed68 | Blue Swirl | #include "helper_regs.h" |
23 | ad71ed68 | Blue Swirl | |
24 | ad71ed68 | Blue Swirl | //#define DEBUG_OP
|
25 | ad71ed68 | Blue Swirl | //#define DEBUG_EXCEPTIONS
|
26 | ad71ed68 | Blue Swirl | |
27 | c79c73f6 | Blue Swirl | #ifdef DEBUG_EXCEPTIONS
|
28 | c79c73f6 | Blue Swirl | # define LOG_EXCP(...) qemu_log(__VA_ARGS__)
|
29 | c79c73f6 | Blue Swirl | #else
|
30 | c79c73f6 | Blue Swirl | # define LOG_EXCP(...) do { } while (0) |
31 | c79c73f6 | Blue Swirl | #endif
|
32 | c79c73f6 | Blue Swirl | |
33 | c79c73f6 | Blue Swirl | /*****************************************************************************/
|
34 | c79c73f6 | Blue Swirl | /* PowerPC Hypercall emulation */
|
35 | c79c73f6 | Blue Swirl | |
36 | 1b14670a | Andreas Färber | void (*cpu_ppc_hypercall)(PowerPCCPU *);
|
37 | c79c73f6 | Blue Swirl | |
38 | c79c73f6 | Blue Swirl | /*****************************************************************************/
|
39 | c79c73f6 | Blue Swirl | /* Exception processing */
|
40 | c79c73f6 | Blue Swirl | #if defined(CONFIG_USER_ONLY)
|
41 | 97a8ea5a | Andreas Färber | void ppc_cpu_do_interrupt(CPUState *cs)
|
42 | c79c73f6 | Blue Swirl | { |
43 | 97a8ea5a | Andreas Färber | PowerPCCPU *cpu = POWERPC_CPU(cs); |
44 | 97a8ea5a | Andreas Färber | CPUPPCState *env = &cpu->env; |
45 | 97a8ea5a | Andreas Färber | |
46 | c79c73f6 | Blue Swirl | env->exception_index = POWERPC_EXCP_NONE; |
47 | c79c73f6 | Blue Swirl | env->error_code = 0;
|
48 | c79c73f6 | Blue Swirl | } |
49 | c79c73f6 | Blue Swirl | |
50 | c79c73f6 | Blue Swirl | void ppc_hw_interrupt(CPUPPCState *env)
|
51 | c79c73f6 | Blue Swirl | { |
52 | c79c73f6 | Blue Swirl | env->exception_index = POWERPC_EXCP_NONE; |
53 | c79c73f6 | Blue Swirl | env->error_code = 0;
|
54 | c79c73f6 | Blue Swirl | } |
55 | c79c73f6 | Blue Swirl | #else /* defined(CONFIG_USER_ONLY) */ |
56 | c79c73f6 | Blue Swirl | static inline void dump_syscall(CPUPPCState *env) |
57 | c79c73f6 | Blue Swirl | { |
58 | c79c73f6 | Blue Swirl | qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64 |
59 | c79c73f6 | Blue Swirl | " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64 |
60 | c79c73f6 | Blue Swirl | " nip=" TARGET_FMT_lx "\n", |
61 | c79c73f6 | Blue Swirl | ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), |
62 | c79c73f6 | Blue Swirl | ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), |
63 | c79c73f6 | Blue Swirl | ppc_dump_gpr(env, 6), env->nip);
|
64 | c79c73f6 | Blue Swirl | } |
65 | c79c73f6 | Blue Swirl | |
66 | c79c73f6 | Blue Swirl | /* Note that this function should be greatly optimized
|
67 | c79c73f6 | Blue Swirl | * when called with a constant excp, from ppc_hw_interrupt
|
68 | c79c73f6 | Blue Swirl | */
|
69 | 5c26a5b3 | Andreas Färber | static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) |
70 | c79c73f6 | Blue Swirl | { |
71 | 5c26a5b3 | Andreas Färber | CPUPPCState *env = &cpu->env; |
72 | 259186a7 | Andreas Färber | CPUState *cs; |
73 | c79c73f6 | Blue Swirl | target_ulong msr, new_msr, vector; |
74 | c79c73f6 | Blue Swirl | int srr0, srr1, asrr0, asrr1;
|
75 | c79c73f6 | Blue Swirl | int lpes0, lpes1, lev;
|
76 | c79c73f6 | Blue Swirl | |
77 | c79c73f6 | Blue Swirl | if (0) { |
78 | c79c73f6 | Blue Swirl | /* XXX: find a suitable condition to enable the hypervisor mode */
|
79 | c79c73f6 | Blue Swirl | lpes0 = (env->spr[SPR_LPCR] >> 1) & 1; |
80 | c79c73f6 | Blue Swirl | lpes1 = (env->spr[SPR_LPCR] >> 2) & 1; |
81 | c79c73f6 | Blue Swirl | } else {
|
82 | c79c73f6 | Blue Swirl | /* Those values ensure we won't enter the hypervisor mode */
|
83 | c79c73f6 | Blue Swirl | lpes0 = 0;
|
84 | c79c73f6 | Blue Swirl | lpes1 = 1;
|
85 | c79c73f6 | Blue Swirl | } |
86 | c79c73f6 | Blue Swirl | |
87 | c79c73f6 | Blue Swirl | qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
|
88 | c79c73f6 | Blue Swirl | " => %08x (%02x)\n", env->nip, excp, env->error_code);
|
89 | c79c73f6 | Blue Swirl | |
90 | c79c73f6 | Blue Swirl | /* new srr1 value excluding must-be-zero bits */
|
91 | a1bb7384 | Scott Wood | if (excp_model == POWERPC_EXCP_BOOKE) {
|
92 | a1bb7384 | Scott Wood | msr = env->msr; |
93 | a1bb7384 | Scott Wood | } else {
|
94 | a1bb7384 | Scott Wood | msr = env->msr & ~0x783f0000ULL;
|
95 | a1bb7384 | Scott Wood | } |
96 | c79c73f6 | Blue Swirl | |
97 | c79c73f6 | Blue Swirl | /* new interrupt handler msr */
|
98 | c79c73f6 | Blue Swirl | new_msr = env->msr & ((target_ulong)1 << MSR_ME);
|
99 | c79c73f6 | Blue Swirl | |
100 | c79c73f6 | Blue Swirl | /* target registers */
|
101 | c79c73f6 | Blue Swirl | srr0 = SPR_SRR0; |
102 | c79c73f6 | Blue Swirl | srr1 = SPR_SRR1; |
103 | c79c73f6 | Blue Swirl | asrr0 = -1;
|
104 | c79c73f6 | Blue Swirl | asrr1 = -1;
|
105 | c79c73f6 | Blue Swirl | |
106 | c79c73f6 | Blue Swirl | switch (excp) {
|
107 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_NONE:
|
108 | c79c73f6 | Blue Swirl | /* Should never happen */
|
109 | c79c73f6 | Blue Swirl | return;
|
110 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_CRITICAL: /* Critical input */ |
111 | c79c73f6 | Blue Swirl | switch (excp_model) {
|
112 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_40x:
|
113 | c79c73f6 | Blue Swirl | srr0 = SPR_40x_SRR2; |
114 | c79c73f6 | Blue Swirl | srr1 = SPR_40x_SRR3; |
115 | c79c73f6 | Blue Swirl | break;
|
116 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_BOOKE:
|
117 | c79c73f6 | Blue Swirl | srr0 = SPR_BOOKE_CSRR0; |
118 | c79c73f6 | Blue Swirl | srr1 = SPR_BOOKE_CSRR1; |
119 | c79c73f6 | Blue Swirl | break;
|
120 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_G2:
|
121 | c79c73f6 | Blue Swirl | break;
|
122 | c79c73f6 | Blue Swirl | default:
|
123 | c79c73f6 | Blue Swirl | goto excp_invalid;
|
124 | c79c73f6 | Blue Swirl | } |
125 | c79c73f6 | Blue Swirl | goto store_next;
|
126 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_MCHECK: /* Machine check exception */ |
127 | c79c73f6 | Blue Swirl | if (msr_me == 0) { |
128 | c79c73f6 | Blue Swirl | /* Machine check exception is not enabled.
|
129 | c79c73f6 | Blue Swirl | * Enter checkstop state.
|
130 | c79c73f6 | Blue Swirl | */
|
131 | c79c73f6 | Blue Swirl | if (qemu_log_enabled()) {
|
132 | c79c73f6 | Blue Swirl | qemu_log("Machine check while not allowed. "
|
133 | c79c73f6 | Blue Swirl | "Entering checkstop state\n");
|
134 | c79c73f6 | Blue Swirl | } else {
|
135 | c79c73f6 | Blue Swirl | fprintf(stderr, "Machine check while not allowed. "
|
136 | c79c73f6 | Blue Swirl | "Entering checkstop state\n");
|
137 | c79c73f6 | Blue Swirl | } |
138 | 259186a7 | Andreas Färber | cs = CPU(cpu); |
139 | 259186a7 | Andreas Färber | cs->halted = 1;
|
140 | 259186a7 | Andreas Färber | cs->interrupt_request |= CPU_INTERRUPT_EXITTB; |
141 | c79c73f6 | Blue Swirl | } |
142 | c79c73f6 | Blue Swirl | if (0) { |
143 | c79c73f6 | Blue Swirl | /* XXX: find a suitable condition to enable the hypervisor mode */
|
144 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
145 | c79c73f6 | Blue Swirl | } |
146 | c79c73f6 | Blue Swirl | |
147 | c79c73f6 | Blue Swirl | /* machine check exceptions don't have ME set */
|
148 | c79c73f6 | Blue Swirl | new_msr &= ~((target_ulong)1 << MSR_ME);
|
149 | c79c73f6 | Blue Swirl | |
150 | c79c73f6 | Blue Swirl | /* XXX: should also have something loaded in DAR / DSISR */
|
151 | c79c73f6 | Blue Swirl | switch (excp_model) {
|
152 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_40x:
|
153 | c79c73f6 | Blue Swirl | srr0 = SPR_40x_SRR2; |
154 | c79c73f6 | Blue Swirl | srr1 = SPR_40x_SRR3; |
155 | c79c73f6 | Blue Swirl | break;
|
156 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_BOOKE:
|
157 | a1bb7384 | Scott Wood | /* FIXME: choose one or the other based on CPU type */
|
158 | c79c73f6 | Blue Swirl | srr0 = SPR_BOOKE_MCSRR0; |
159 | c79c73f6 | Blue Swirl | srr1 = SPR_BOOKE_MCSRR1; |
160 | c79c73f6 | Blue Swirl | asrr0 = SPR_BOOKE_CSRR0; |
161 | c79c73f6 | Blue Swirl | asrr1 = SPR_BOOKE_CSRR1; |
162 | c79c73f6 | Blue Swirl | break;
|
163 | c79c73f6 | Blue Swirl | default:
|
164 | c79c73f6 | Blue Swirl | break;
|
165 | c79c73f6 | Blue Swirl | } |
166 | c79c73f6 | Blue Swirl | goto store_next;
|
167 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DSI: /* Data storage exception */ |
168 | c79c73f6 | Blue Swirl | LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx |
169 | c79c73f6 | Blue Swirl | "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
|
170 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
171 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
172 | c79c73f6 | Blue Swirl | } |
173 | c79c73f6 | Blue Swirl | goto store_next;
|
174 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_ISI: /* Instruction storage exception */ |
175 | c79c73f6 | Blue Swirl | LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx |
176 | c79c73f6 | Blue Swirl | "\n", msr, env->nip);
|
177 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
178 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
179 | c79c73f6 | Blue Swirl | } |
180 | c79c73f6 | Blue Swirl | msr |= env->error_code; |
181 | c79c73f6 | Blue Swirl | goto store_next;
|
182 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_EXTERNAL: /* External input */ |
183 | c79c73f6 | Blue Swirl | if (lpes0 == 1) { |
184 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
185 | c79c73f6 | Blue Swirl | } |
186 | 68c2dd70 | Alexander Graf | if (env->mpic_proxy) {
|
187 | 68c2dd70 | Alexander Graf | /* IACK the IRQ on delivery */
|
188 | 68c2dd70 | Alexander Graf | env->spr[SPR_BOOKE_EPR] = ldl_phys(env->mpic_iack); |
189 | 68c2dd70 | Alexander Graf | } |
190 | c79c73f6 | Blue Swirl | goto store_next;
|
191 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_ALIGN: /* Alignment exception */ |
192 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
193 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
194 | c79c73f6 | Blue Swirl | } |
195 | c79c73f6 | Blue Swirl | /* XXX: this is false */
|
196 | c79c73f6 | Blue Swirl | /* Get rS/rD and rA from faulting opcode */
|
197 | 2f5a189c | Blue Swirl | env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
|
198 | 2f5a189c | Blue Swirl | & 0x03FF0000) >> 16; |
199 | c79c73f6 | Blue Swirl | goto store_current;
|
200 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_PROGRAM: /* Program exception */ |
201 | c79c73f6 | Blue Swirl | switch (env->error_code & ~0xF) { |
202 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_FP:
|
203 | c79c73f6 | Blue Swirl | if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) { |
204 | c79c73f6 | Blue Swirl | LOG_EXCP("Ignore floating point exception\n");
|
205 | c79c73f6 | Blue Swirl | env->exception_index = POWERPC_EXCP_NONE; |
206 | c79c73f6 | Blue Swirl | env->error_code = 0;
|
207 | c79c73f6 | Blue Swirl | return;
|
208 | c79c73f6 | Blue Swirl | } |
209 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
210 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
211 | c79c73f6 | Blue Swirl | } |
212 | c79c73f6 | Blue Swirl | msr |= 0x00100000;
|
213 | c79c73f6 | Blue Swirl | if (msr_fe0 == msr_fe1) {
|
214 | c79c73f6 | Blue Swirl | goto store_next;
|
215 | c79c73f6 | Blue Swirl | } |
216 | c79c73f6 | Blue Swirl | msr |= 0x00010000;
|
217 | c79c73f6 | Blue Swirl | break;
|
218 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_INVAL:
|
219 | c79c73f6 | Blue Swirl | LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip); |
220 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
221 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
222 | c79c73f6 | Blue Swirl | } |
223 | c79c73f6 | Blue Swirl | msr |= 0x00080000;
|
224 | c79c73f6 | Blue Swirl | env->spr[SPR_BOOKE_ESR] = ESR_PIL; |
225 | c79c73f6 | Blue Swirl | break;
|
226 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_PRIV:
|
227 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
228 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
229 | c79c73f6 | Blue Swirl | } |
230 | c79c73f6 | Blue Swirl | msr |= 0x00040000;
|
231 | c79c73f6 | Blue Swirl | env->spr[SPR_BOOKE_ESR] = ESR_PPR; |
232 | c79c73f6 | Blue Swirl | break;
|
233 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_TRAP:
|
234 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
235 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
236 | c79c73f6 | Blue Swirl | } |
237 | c79c73f6 | Blue Swirl | msr |= 0x00020000;
|
238 | c79c73f6 | Blue Swirl | env->spr[SPR_BOOKE_ESR] = ESR_PTR; |
239 | c79c73f6 | Blue Swirl | break;
|
240 | c79c73f6 | Blue Swirl | default:
|
241 | c79c73f6 | Blue Swirl | /* Should never occur */
|
242 | c79c73f6 | Blue Swirl | cpu_abort(env, "Invalid program exception %d. Aborting\n",
|
243 | c79c73f6 | Blue Swirl | env->error_code); |
244 | c79c73f6 | Blue Swirl | break;
|
245 | c79c73f6 | Blue Swirl | } |
246 | c79c73f6 | Blue Swirl | goto store_current;
|
247 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */ |
248 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
249 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
250 | c79c73f6 | Blue Swirl | } |
251 | c79c73f6 | Blue Swirl | goto store_current;
|
252 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_SYSCALL: /* System call exception */ |
253 | c79c73f6 | Blue Swirl | dump_syscall(env); |
254 | c79c73f6 | Blue Swirl | lev = env->error_code; |
255 | c79c73f6 | Blue Swirl | if ((lev == 1) && cpu_ppc_hypercall) { |
256 | 1b14670a | Andreas Färber | cpu_ppc_hypercall(cpu); |
257 | c79c73f6 | Blue Swirl | return;
|
258 | c79c73f6 | Blue Swirl | } |
259 | c79c73f6 | Blue Swirl | if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) { |
260 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
261 | c79c73f6 | Blue Swirl | } |
262 | c79c73f6 | Blue Swirl | goto store_next;
|
263 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */ |
264 | c79c73f6 | Blue Swirl | goto store_current;
|
265 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DECR: /* Decrementer exception */ |
266 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
267 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
268 | c79c73f6 | Blue Swirl | } |
269 | c79c73f6 | Blue Swirl | goto store_next;
|
270 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ |
271 | c79c73f6 | Blue Swirl | /* FIT on 4xx */
|
272 | c79c73f6 | Blue Swirl | LOG_EXCP("FIT exception\n");
|
273 | c79c73f6 | Blue Swirl | goto store_next;
|
274 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ |
275 | c79c73f6 | Blue Swirl | LOG_EXCP("WDT exception\n");
|
276 | c79c73f6 | Blue Swirl | switch (excp_model) {
|
277 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_BOOKE:
|
278 | c79c73f6 | Blue Swirl | srr0 = SPR_BOOKE_CSRR0; |
279 | c79c73f6 | Blue Swirl | srr1 = SPR_BOOKE_CSRR1; |
280 | c79c73f6 | Blue Swirl | break;
|
281 | c79c73f6 | Blue Swirl | default:
|
282 | c79c73f6 | Blue Swirl | break;
|
283 | c79c73f6 | Blue Swirl | } |
284 | c79c73f6 | Blue Swirl | goto store_next;
|
285 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DTLB: /* Data TLB error */ |
286 | c79c73f6 | Blue Swirl | goto store_next;
|
287 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_ITLB: /* Instruction TLB error */ |
288 | c79c73f6 | Blue Swirl | goto store_next;
|
289 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DEBUG: /* Debug interrupt */ |
290 | c79c73f6 | Blue Swirl | switch (excp_model) {
|
291 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_BOOKE:
|
292 | a1bb7384 | Scott Wood | /* FIXME: choose one or the other based on CPU type */
|
293 | c79c73f6 | Blue Swirl | srr0 = SPR_BOOKE_DSRR0; |
294 | c79c73f6 | Blue Swirl | srr1 = SPR_BOOKE_DSRR1; |
295 | c79c73f6 | Blue Swirl | asrr0 = SPR_BOOKE_CSRR0; |
296 | c79c73f6 | Blue Swirl | asrr1 = SPR_BOOKE_CSRR1; |
297 | c79c73f6 | Blue Swirl | break;
|
298 | c79c73f6 | Blue Swirl | default:
|
299 | c79c73f6 | Blue Swirl | break;
|
300 | c79c73f6 | Blue Swirl | } |
301 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
302 | c79c73f6 | Blue Swirl | cpu_abort(env, "Debug exception is not implemented yet !\n");
|
303 | c79c73f6 | Blue Swirl | goto store_next;
|
304 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ |
305 | c79c73f6 | Blue Swirl | env->spr[SPR_BOOKE_ESR] = ESR_SPV; |
306 | c79c73f6 | Blue Swirl | goto store_current;
|
307 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */ |
308 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
309 | c79c73f6 | Blue Swirl | cpu_abort(env, "Embedded floating point data exception "
|
310 | c79c73f6 | Blue Swirl | "is not implemented yet !\n");
|
311 | c79c73f6 | Blue Swirl | env->spr[SPR_BOOKE_ESR] = ESR_SPV; |
312 | c79c73f6 | Blue Swirl | goto store_next;
|
313 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */ |
314 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
315 | c79c73f6 | Blue Swirl | cpu_abort(env, "Embedded floating point round exception "
|
316 | c79c73f6 | Blue Swirl | "is not implemented yet !\n");
|
317 | c79c73f6 | Blue Swirl | env->spr[SPR_BOOKE_ESR] = ESR_SPV; |
318 | c79c73f6 | Blue Swirl | goto store_next;
|
319 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */ |
320 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
321 | c79c73f6 | Blue Swirl | cpu_abort(env, |
322 | c79c73f6 | Blue Swirl | "Performance counter exception is not implemented yet !\n");
|
323 | c79c73f6 | Blue Swirl | goto store_next;
|
324 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ |
325 | c79c73f6 | Blue Swirl | goto store_next;
|
326 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ |
327 | c79c73f6 | Blue Swirl | srr0 = SPR_BOOKE_CSRR0; |
328 | c79c73f6 | Blue Swirl | srr1 = SPR_BOOKE_CSRR1; |
329 | c79c73f6 | Blue Swirl | goto store_next;
|
330 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_RESET: /* System reset exception */ |
331 | c79c73f6 | Blue Swirl | if (msr_pow) {
|
332 | c79c73f6 | Blue Swirl | /* indicate that we resumed from power save mode */
|
333 | c79c73f6 | Blue Swirl | msr |= 0x10000;
|
334 | c79c73f6 | Blue Swirl | } else {
|
335 | c79c73f6 | Blue Swirl | new_msr &= ~((target_ulong)1 << MSR_ME);
|
336 | c79c73f6 | Blue Swirl | } |
337 | c79c73f6 | Blue Swirl | |
338 | c79c73f6 | Blue Swirl | if (0) { |
339 | c79c73f6 | Blue Swirl | /* XXX: find a suitable condition to enable the hypervisor mode */
|
340 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
341 | c79c73f6 | Blue Swirl | } |
342 | c79c73f6 | Blue Swirl | goto store_next;
|
343 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DSEG: /* Data segment exception */ |
344 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
345 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
346 | c79c73f6 | Blue Swirl | } |
347 | c79c73f6 | Blue Swirl | goto store_next;
|
348 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_ISEG: /* Instruction segment exception */ |
349 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
350 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
351 | c79c73f6 | Blue Swirl | } |
352 | c79c73f6 | Blue Swirl | goto store_next;
|
353 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */ |
354 | c79c73f6 | Blue Swirl | srr0 = SPR_HSRR0; |
355 | c79c73f6 | Blue Swirl | srr1 = SPR_HSRR1; |
356 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
357 | c79c73f6 | Blue Swirl | new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
358 | c79c73f6 | Blue Swirl | goto store_next;
|
359 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_TRACE: /* Trace exception */ |
360 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
361 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
362 | c79c73f6 | Blue Swirl | } |
363 | c79c73f6 | Blue Swirl | goto store_next;
|
364 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ |
365 | c79c73f6 | Blue Swirl | srr0 = SPR_HSRR0; |
366 | c79c73f6 | Blue Swirl | srr1 = SPR_HSRR1; |
367 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
368 | c79c73f6 | Blue Swirl | new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
369 | c79c73f6 | Blue Swirl | goto store_next;
|
370 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */ |
371 | c79c73f6 | Blue Swirl | srr0 = SPR_HSRR0; |
372 | c79c73f6 | Blue Swirl | srr1 = SPR_HSRR1; |
373 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
374 | c79c73f6 | Blue Swirl | new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
375 | c79c73f6 | Blue Swirl | goto store_next;
|
376 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */ |
377 | c79c73f6 | Blue Swirl | srr0 = SPR_HSRR0; |
378 | c79c73f6 | Blue Swirl | srr1 = SPR_HSRR1; |
379 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
380 | c79c73f6 | Blue Swirl | new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
381 | c79c73f6 | Blue Swirl | goto store_next;
|
382 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */ |
383 | c79c73f6 | Blue Swirl | srr0 = SPR_HSRR0; |
384 | c79c73f6 | Blue Swirl | srr1 = SPR_HSRR1; |
385 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
386 | c79c73f6 | Blue Swirl | new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
387 | c79c73f6 | Blue Swirl | goto store_next;
|
388 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_VPU: /* Vector unavailable exception */ |
389 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
390 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
391 | c79c73f6 | Blue Swirl | } |
392 | c79c73f6 | Blue Swirl | goto store_current;
|
393 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */ |
394 | c79c73f6 | Blue Swirl | LOG_EXCP("PIT exception\n");
|
395 | c79c73f6 | Blue Swirl | goto store_next;
|
396 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_IO: /* IO error exception */ |
397 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
398 | c79c73f6 | Blue Swirl | cpu_abort(env, "601 IO error exception is not implemented yet !\n");
|
399 | c79c73f6 | Blue Swirl | goto store_next;
|
400 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_RUNM: /* Run mode exception */ |
401 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
402 | c79c73f6 | Blue Swirl | cpu_abort(env, "601 run mode exception is not implemented yet !\n");
|
403 | c79c73f6 | Blue Swirl | goto store_next;
|
404 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_EMUL: /* Emulation trap exception */ |
405 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
406 | c79c73f6 | Blue Swirl | cpu_abort(env, "602 emulation trap exception "
|
407 | c79c73f6 | Blue Swirl | "is not implemented yet !\n");
|
408 | c79c73f6 | Blue Swirl | goto store_next;
|
409 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */ |
410 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { /* XXX: check this */ |
411 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
412 | c79c73f6 | Blue Swirl | } |
413 | c79c73f6 | Blue Swirl | switch (excp_model) {
|
414 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_602:
|
415 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_603:
|
416 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_603E:
|
417 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_G2:
|
418 | c79c73f6 | Blue Swirl | goto tlb_miss_tgpr;
|
419 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_7x5:
|
420 | c79c73f6 | Blue Swirl | goto tlb_miss;
|
421 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_74xx:
|
422 | c79c73f6 | Blue Swirl | goto tlb_miss_74xx;
|
423 | c79c73f6 | Blue Swirl | default:
|
424 | c79c73f6 | Blue Swirl | cpu_abort(env, "Invalid instruction TLB miss exception\n");
|
425 | c79c73f6 | Blue Swirl | break;
|
426 | c79c73f6 | Blue Swirl | } |
427 | c79c73f6 | Blue Swirl | break;
|
428 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DLTLB: /* Data load TLB miss */ |
429 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { /* XXX: check this */ |
430 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
431 | c79c73f6 | Blue Swirl | } |
432 | c79c73f6 | Blue Swirl | switch (excp_model) {
|
433 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_602:
|
434 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_603:
|
435 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_603E:
|
436 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_G2:
|
437 | c79c73f6 | Blue Swirl | goto tlb_miss_tgpr;
|
438 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_7x5:
|
439 | c79c73f6 | Blue Swirl | goto tlb_miss;
|
440 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_74xx:
|
441 | c79c73f6 | Blue Swirl | goto tlb_miss_74xx;
|
442 | c79c73f6 | Blue Swirl | default:
|
443 | c79c73f6 | Blue Swirl | cpu_abort(env, "Invalid data load TLB miss exception\n");
|
444 | c79c73f6 | Blue Swirl | break;
|
445 | c79c73f6 | Blue Swirl | } |
446 | c79c73f6 | Blue Swirl | break;
|
447 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DSTLB: /* Data store TLB miss */ |
448 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { /* XXX: check this */ |
449 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
450 | c79c73f6 | Blue Swirl | } |
451 | c79c73f6 | Blue Swirl | switch (excp_model) {
|
452 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_602:
|
453 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_603:
|
454 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_603E:
|
455 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_G2:
|
456 | c79c73f6 | Blue Swirl | tlb_miss_tgpr:
|
457 | c79c73f6 | Blue Swirl | /* Swap temporary saved registers with GPRs */
|
458 | c79c73f6 | Blue Swirl | if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) { |
459 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)1 << MSR_TGPR;
|
460 | c79c73f6 | Blue Swirl | hreg_swap_gpr_tgpr(env); |
461 | c79c73f6 | Blue Swirl | } |
462 | c79c73f6 | Blue Swirl | goto tlb_miss;
|
463 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_7x5:
|
464 | c79c73f6 | Blue Swirl | tlb_miss:
|
465 | c79c73f6 | Blue Swirl | #if defined(DEBUG_SOFTWARE_TLB)
|
466 | c79c73f6 | Blue Swirl | if (qemu_log_enabled()) {
|
467 | c79c73f6 | Blue Swirl | const char *es; |
468 | c79c73f6 | Blue Swirl | target_ulong *miss, *cmp; |
469 | c79c73f6 | Blue Swirl | int en;
|
470 | c79c73f6 | Blue Swirl | |
471 | c79c73f6 | Blue Swirl | if (excp == POWERPC_EXCP_IFTLB) {
|
472 | c79c73f6 | Blue Swirl | es = "I";
|
473 | c79c73f6 | Blue Swirl | en = 'I';
|
474 | c79c73f6 | Blue Swirl | miss = &env->spr[SPR_IMISS]; |
475 | c79c73f6 | Blue Swirl | cmp = &env->spr[SPR_ICMP]; |
476 | c79c73f6 | Blue Swirl | } else {
|
477 | c79c73f6 | Blue Swirl | if (excp == POWERPC_EXCP_DLTLB) {
|
478 | c79c73f6 | Blue Swirl | es = "DL";
|
479 | c79c73f6 | Blue Swirl | } else {
|
480 | c79c73f6 | Blue Swirl | es = "DS";
|
481 | c79c73f6 | Blue Swirl | } |
482 | c79c73f6 | Blue Swirl | en = 'D';
|
483 | c79c73f6 | Blue Swirl | miss = &env->spr[SPR_DMISS]; |
484 | c79c73f6 | Blue Swirl | cmp = &env->spr[SPR_DCMP]; |
485 | c79c73f6 | Blue Swirl | } |
486 | c79c73f6 | Blue Swirl | qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " |
487 | c79c73f6 | Blue Swirl | TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 " |
488 | c79c73f6 | Blue Swirl | TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
|
489 | c79c73f6 | Blue Swirl | env->spr[SPR_HASH1], env->spr[SPR_HASH2], |
490 | c79c73f6 | Blue Swirl | env->error_code); |
491 | c79c73f6 | Blue Swirl | } |
492 | c79c73f6 | Blue Swirl | #endif
|
493 | c79c73f6 | Blue Swirl | msr |= env->crf[0] << 28; |
494 | c79c73f6 | Blue Swirl | msr |= env->error_code; /* key, D/I, S/L bits */
|
495 | c79c73f6 | Blue Swirl | /* Set way using a LRU mechanism */
|
496 | c79c73f6 | Blue Swirl | msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17; |
497 | c79c73f6 | Blue Swirl | break;
|
498 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_74xx:
|
499 | c79c73f6 | Blue Swirl | tlb_miss_74xx:
|
500 | c79c73f6 | Blue Swirl | #if defined(DEBUG_SOFTWARE_TLB)
|
501 | c79c73f6 | Blue Swirl | if (qemu_log_enabled()) {
|
502 | c79c73f6 | Blue Swirl | const char *es; |
503 | c79c73f6 | Blue Swirl | target_ulong *miss, *cmp; |
504 | c79c73f6 | Blue Swirl | int en;
|
505 | c79c73f6 | Blue Swirl | |
506 | c79c73f6 | Blue Swirl | if (excp == POWERPC_EXCP_IFTLB) {
|
507 | c79c73f6 | Blue Swirl | es = "I";
|
508 | c79c73f6 | Blue Swirl | en = 'I';
|
509 | c79c73f6 | Blue Swirl | miss = &env->spr[SPR_TLBMISS]; |
510 | c79c73f6 | Blue Swirl | cmp = &env->spr[SPR_PTEHI]; |
511 | c79c73f6 | Blue Swirl | } else {
|
512 | c79c73f6 | Blue Swirl | if (excp == POWERPC_EXCP_DLTLB) {
|
513 | c79c73f6 | Blue Swirl | es = "DL";
|
514 | c79c73f6 | Blue Swirl | } else {
|
515 | c79c73f6 | Blue Swirl | es = "DS";
|
516 | c79c73f6 | Blue Swirl | } |
517 | c79c73f6 | Blue Swirl | en = 'D';
|
518 | c79c73f6 | Blue Swirl | miss = &env->spr[SPR_TLBMISS]; |
519 | c79c73f6 | Blue Swirl | cmp = &env->spr[SPR_PTEHI]; |
520 | c79c73f6 | Blue Swirl | } |
521 | c79c73f6 | Blue Swirl | qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC " |
522 | c79c73f6 | Blue Swirl | TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
|
523 | c79c73f6 | Blue Swirl | env->error_code); |
524 | c79c73f6 | Blue Swirl | } |
525 | c79c73f6 | Blue Swirl | #endif
|
526 | c79c73f6 | Blue Swirl | msr |= env->error_code; /* key bit */
|
527 | c79c73f6 | Blue Swirl | break;
|
528 | c79c73f6 | Blue Swirl | default:
|
529 | c79c73f6 | Blue Swirl | cpu_abort(env, "Invalid data store TLB miss exception\n");
|
530 | c79c73f6 | Blue Swirl | break;
|
531 | c79c73f6 | Blue Swirl | } |
532 | c79c73f6 | Blue Swirl | goto store_next;
|
533 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_FPA: /* Floating-point assist exception */ |
534 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
535 | c79c73f6 | Blue Swirl | cpu_abort(env, "Floating point assist exception "
|
536 | c79c73f6 | Blue Swirl | "is not implemented yet !\n");
|
537 | c79c73f6 | Blue Swirl | goto store_next;
|
538 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_DABR: /* Data address breakpoint */ |
539 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
540 | c79c73f6 | Blue Swirl | cpu_abort(env, "DABR exception is not implemented yet !\n");
|
541 | c79c73f6 | Blue Swirl | goto store_next;
|
542 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_IABR: /* Instruction address breakpoint */ |
543 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
544 | c79c73f6 | Blue Swirl | cpu_abort(env, "IABR exception is not implemented yet !\n");
|
545 | c79c73f6 | Blue Swirl | goto store_next;
|
546 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_SMI: /* System management interrupt */ |
547 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
548 | c79c73f6 | Blue Swirl | cpu_abort(env, "SMI exception is not implemented yet !\n");
|
549 | c79c73f6 | Blue Swirl | goto store_next;
|
550 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_THERM: /* Thermal interrupt */ |
551 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
552 | c79c73f6 | Blue Swirl | cpu_abort(env, "Thermal management exception "
|
553 | c79c73f6 | Blue Swirl | "is not implemented yet !\n");
|
554 | c79c73f6 | Blue Swirl | goto store_next;
|
555 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */ |
556 | c79c73f6 | Blue Swirl | if (lpes1 == 0) { |
557 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)MSR_HVB; |
558 | c79c73f6 | Blue Swirl | } |
559 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
560 | c79c73f6 | Blue Swirl | cpu_abort(env, |
561 | c79c73f6 | Blue Swirl | "Performance counter exception is not implemented yet !\n");
|
562 | c79c73f6 | Blue Swirl | goto store_next;
|
563 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_VPUA: /* Vector assist exception */ |
564 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
565 | c79c73f6 | Blue Swirl | cpu_abort(env, "VPU assist exception is not implemented yet !\n");
|
566 | c79c73f6 | Blue Swirl | goto store_next;
|
567 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_SOFTP: /* Soft patch exception */ |
568 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
569 | c79c73f6 | Blue Swirl | cpu_abort(env, |
570 | c79c73f6 | Blue Swirl | "970 soft-patch exception is not implemented yet !\n");
|
571 | c79c73f6 | Blue Swirl | goto store_next;
|
572 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_MAINT: /* Maintenance exception */ |
573 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
574 | c79c73f6 | Blue Swirl | cpu_abort(env, |
575 | c79c73f6 | Blue Swirl | "970 maintenance exception is not implemented yet !\n");
|
576 | c79c73f6 | Blue Swirl | goto store_next;
|
577 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */ |
578 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
579 | c79c73f6 | Blue Swirl | cpu_abort(env, "Maskable external exception "
|
580 | c79c73f6 | Blue Swirl | "is not implemented yet !\n");
|
581 | c79c73f6 | Blue Swirl | goto store_next;
|
582 | c79c73f6 | Blue Swirl | case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */ |
583 | c79c73f6 | Blue Swirl | /* XXX: TODO */
|
584 | c79c73f6 | Blue Swirl | cpu_abort(env, "Non maskable external exception "
|
585 | c79c73f6 | Blue Swirl | "is not implemented yet !\n");
|
586 | c79c73f6 | Blue Swirl | goto store_next;
|
587 | c79c73f6 | Blue Swirl | default:
|
588 | c79c73f6 | Blue Swirl | excp_invalid:
|
589 | c79c73f6 | Blue Swirl | cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
|
590 | c79c73f6 | Blue Swirl | break;
|
591 | c79c73f6 | Blue Swirl | store_current:
|
592 | c79c73f6 | Blue Swirl | /* save current instruction location */
|
593 | c79c73f6 | Blue Swirl | env->spr[srr0] = env->nip - 4;
|
594 | c79c73f6 | Blue Swirl | break;
|
595 | c79c73f6 | Blue Swirl | store_next:
|
596 | c79c73f6 | Blue Swirl | /* save next instruction location */
|
597 | c79c73f6 | Blue Swirl | env->spr[srr0] = env->nip; |
598 | c79c73f6 | Blue Swirl | break;
|
599 | c79c73f6 | Blue Swirl | } |
600 | c79c73f6 | Blue Swirl | /* Save MSR */
|
601 | c79c73f6 | Blue Swirl | env->spr[srr1] = msr; |
602 | c79c73f6 | Blue Swirl | /* If any alternate SRR register are defined, duplicate saved values */
|
603 | c79c73f6 | Blue Swirl | if (asrr0 != -1) { |
604 | c79c73f6 | Blue Swirl | env->spr[asrr0] = env->spr[srr0]; |
605 | c79c73f6 | Blue Swirl | } |
606 | c79c73f6 | Blue Swirl | if (asrr1 != -1) { |
607 | c79c73f6 | Blue Swirl | env->spr[asrr1] = env->spr[srr1]; |
608 | c79c73f6 | Blue Swirl | } |
609 | c79c73f6 | Blue Swirl | /* If we disactivated any translation, flush TLBs */
|
610 | c79c73f6 | Blue Swirl | if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) { |
611 | c79c73f6 | Blue Swirl | tlb_flush(env, 1);
|
612 | c79c73f6 | Blue Swirl | } |
613 | c79c73f6 | Blue Swirl | |
614 | c79c73f6 | Blue Swirl | if (msr_ile) {
|
615 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)1 << MSR_LE;
|
616 | c79c73f6 | Blue Swirl | } |
617 | c79c73f6 | Blue Swirl | |
618 | c79c73f6 | Blue Swirl | /* Jump to handler */
|
619 | c79c73f6 | Blue Swirl | vector = env->excp_vectors[excp]; |
620 | c79c73f6 | Blue Swirl | if (vector == (target_ulong)-1ULL) { |
621 | c79c73f6 | Blue Swirl | cpu_abort(env, "Raised an exception without defined vector %d\n",
|
622 | c79c73f6 | Blue Swirl | excp); |
623 | c79c73f6 | Blue Swirl | } |
624 | c79c73f6 | Blue Swirl | vector |= env->excp_prefix; |
625 | c79c73f6 | Blue Swirl | #if defined(TARGET_PPC64)
|
626 | c79c73f6 | Blue Swirl | if (excp_model == POWERPC_EXCP_BOOKE) {
|
627 | e42a61f1 | Alexander Graf | if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
|
628 | e42a61f1 | Alexander Graf | /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
|
629 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)1 << MSR_CM;
|
630 | e42a61f1 | Alexander Graf | } else {
|
631 | e42a61f1 | Alexander Graf | vector = (uint32_t)vector; |
632 | c79c73f6 | Blue Swirl | } |
633 | c79c73f6 | Blue Swirl | } else {
|
634 | c79c73f6 | Blue Swirl | if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
|
635 | c79c73f6 | Blue Swirl | vector = (uint32_t)vector; |
636 | c79c73f6 | Blue Swirl | } else {
|
637 | c79c73f6 | Blue Swirl | new_msr |= (target_ulong)1 << MSR_SF;
|
638 | c79c73f6 | Blue Swirl | } |
639 | c79c73f6 | Blue Swirl | } |
640 | c79c73f6 | Blue Swirl | #endif
|
641 | c79c73f6 | Blue Swirl | /* XXX: we don't use hreg_store_msr here as already have treated
|
642 | c79c73f6 | Blue Swirl | * any special case that could occur. Just store MSR and update hflags
|
643 | c79c73f6 | Blue Swirl | */
|
644 | c79c73f6 | Blue Swirl | env->msr = new_msr & env->msr_mask; |
645 | c79c73f6 | Blue Swirl | hreg_compute_hflags(env); |
646 | c79c73f6 | Blue Swirl | env->nip = vector; |
647 | c79c73f6 | Blue Swirl | /* Reset exception state */
|
648 | c79c73f6 | Blue Swirl | env->exception_index = POWERPC_EXCP_NONE; |
649 | c79c73f6 | Blue Swirl | env->error_code = 0;
|
650 | c79c73f6 | Blue Swirl | |
651 | c79c73f6 | Blue Swirl | if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
|
652 | c79c73f6 | Blue Swirl | (env->mmu_model == POWERPC_MMU_BOOKE206)) { |
653 | c79c73f6 | Blue Swirl | /* XXX: The BookE changes address space when switching modes,
|
654 | c79c73f6 | Blue Swirl | we should probably implement that as different MMU indexes,
|
655 | c79c73f6 | Blue Swirl | but for the moment we do it the slow way and flush all. */
|
656 | c79c73f6 | Blue Swirl | tlb_flush(env, 1);
|
657 | c79c73f6 | Blue Swirl | } |
658 | c79c73f6 | Blue Swirl | } |
659 | c79c73f6 | Blue Swirl | |
660 | 97a8ea5a | Andreas Färber | void ppc_cpu_do_interrupt(CPUState *cs)
|
661 | c79c73f6 | Blue Swirl | { |
662 | 97a8ea5a | Andreas Färber | PowerPCCPU *cpu = POWERPC_CPU(cs); |
663 | 97a8ea5a | Andreas Färber | CPUPPCState *env = &cpu->env; |
664 | 5c26a5b3 | Andreas Färber | |
665 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, env->exception_index); |
666 | c79c73f6 | Blue Swirl | } |
667 | c79c73f6 | Blue Swirl | |
668 | c79c73f6 | Blue Swirl | void ppc_hw_interrupt(CPUPPCState *env)
|
669 | c79c73f6 | Blue Swirl | { |
670 | 5c26a5b3 | Andreas Färber | PowerPCCPU *cpu = ppc_env_get_cpu(env); |
671 | c79c73f6 | Blue Swirl | int hdice;
|
672 | c79c73f6 | Blue Swirl | #if 0
|
673 | 259186a7 | Andreas Färber | CPUState *cs = CPU(cpu);
|
674 | 259186a7 | Andreas Färber | |
675 | c79c73f6 | Blue Swirl | qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
|
676 | 259186a7 | Andreas Färber | __func__, env, env->pending_interrupts,
|
677 | 259186a7 | Andreas Färber | cs->interrupt_request, (int)msr_me, (int)msr_ee);
|
678 | c79c73f6 | Blue Swirl | #endif
|
679 | c79c73f6 | Blue Swirl | /* External reset */
|
680 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { |
681 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
|
682 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET); |
683 | c79c73f6 | Blue Swirl | return;
|
684 | c79c73f6 | Blue Swirl | } |
685 | c79c73f6 | Blue Swirl | /* Machine check exception */
|
686 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { |
687 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
|
688 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK); |
689 | c79c73f6 | Blue Swirl | return;
|
690 | c79c73f6 | Blue Swirl | } |
691 | c79c73f6 | Blue Swirl | #if 0 /* TODO */
|
692 | c79c73f6 | Blue Swirl | /* External debug exception */
|
693 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
|
694 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
|
695 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
|
696 | c79c73f6 | Blue Swirl | return;
|
697 | c79c73f6 | Blue Swirl | }
|
698 | c79c73f6 | Blue Swirl | #endif
|
699 | c79c73f6 | Blue Swirl | if (0) { |
700 | c79c73f6 | Blue Swirl | /* XXX: find a suitable condition to enable the hypervisor mode */
|
701 | c79c73f6 | Blue Swirl | hdice = env->spr[SPR_LPCR] & 1;
|
702 | c79c73f6 | Blue Swirl | } else {
|
703 | c79c73f6 | Blue Swirl | hdice = 0;
|
704 | c79c73f6 | Blue Swirl | } |
705 | c79c73f6 | Blue Swirl | if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) { |
706 | c79c73f6 | Blue Swirl | /* Hypervisor decrementer exception */
|
707 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { |
708 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
|
709 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR); |
710 | c79c73f6 | Blue Swirl | return;
|
711 | c79c73f6 | Blue Swirl | } |
712 | c79c73f6 | Blue Swirl | } |
713 | c79c73f6 | Blue Swirl | if (msr_ce != 0) { |
714 | c79c73f6 | Blue Swirl | /* External critical interrupt */
|
715 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { |
716 | c79c73f6 | Blue Swirl | /* Taking a critical external interrupt does not clear the external
|
717 | c79c73f6 | Blue Swirl | * critical interrupt status
|
718 | c79c73f6 | Blue Swirl | */
|
719 | c79c73f6 | Blue Swirl | #if 0
|
720 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
|
721 | c79c73f6 | Blue Swirl | #endif
|
722 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL); |
723 | c79c73f6 | Blue Swirl | return;
|
724 | c79c73f6 | Blue Swirl | } |
725 | c79c73f6 | Blue Swirl | } |
726 | c79c73f6 | Blue Swirl | if (msr_ee != 0) { |
727 | c79c73f6 | Blue Swirl | /* Watchdog timer on embedded PowerPC */
|
728 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { |
729 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
|
730 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT); |
731 | c79c73f6 | Blue Swirl | return;
|
732 | c79c73f6 | Blue Swirl | } |
733 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { |
734 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
|
735 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI); |
736 | c79c73f6 | Blue Swirl | return;
|
737 | c79c73f6 | Blue Swirl | } |
738 | c79c73f6 | Blue Swirl | /* Fixed interval timer on embedded PowerPC */
|
739 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { |
740 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
|
741 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT); |
742 | c79c73f6 | Blue Swirl | return;
|
743 | c79c73f6 | Blue Swirl | } |
744 | c79c73f6 | Blue Swirl | /* Programmable interval timer on embedded PowerPC */
|
745 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { |
746 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
|
747 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT); |
748 | c79c73f6 | Blue Swirl | return;
|
749 | c79c73f6 | Blue Swirl | } |
750 | c79c73f6 | Blue Swirl | /* Decrementer exception */
|
751 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { |
752 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
|
753 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR); |
754 | c79c73f6 | Blue Swirl | return;
|
755 | c79c73f6 | Blue Swirl | } |
756 | c79c73f6 | Blue Swirl | /* External interrupt */
|
757 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { |
758 | c79c73f6 | Blue Swirl | /* Taking an external interrupt does not clear the external
|
759 | c79c73f6 | Blue Swirl | * interrupt status
|
760 | c79c73f6 | Blue Swirl | */
|
761 | c79c73f6 | Blue Swirl | #if 0
|
762 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
|
763 | c79c73f6 | Blue Swirl | #endif
|
764 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL); |
765 | c79c73f6 | Blue Swirl | return;
|
766 | c79c73f6 | Blue Swirl | } |
767 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { |
768 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
|
769 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI); |
770 | c79c73f6 | Blue Swirl | return;
|
771 | c79c73f6 | Blue Swirl | } |
772 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { |
773 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
|
774 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM); |
775 | c79c73f6 | Blue Swirl | return;
|
776 | c79c73f6 | Blue Swirl | } |
777 | c79c73f6 | Blue Swirl | /* Thermal interrupt */
|
778 | c79c73f6 | Blue Swirl | if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { |
779 | c79c73f6 | Blue Swirl | env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
|
780 | 5c26a5b3 | Andreas Färber | powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM); |
781 | c79c73f6 | Blue Swirl | return;
|
782 | c79c73f6 | Blue Swirl | } |
783 | c79c73f6 | Blue Swirl | } |
784 | c79c73f6 | Blue Swirl | } |
785 | c79c73f6 | Blue Swirl | #endif /* !CONFIG_USER_ONLY */ |
786 | c79c73f6 | Blue Swirl | |
787 | c79c73f6 | Blue Swirl | #if defined(DEBUG_OP)
|
788 | c79c73f6 | Blue Swirl | static void cpu_dump_rfi(target_ulong RA, target_ulong msr) |
789 | c79c73f6 | Blue Swirl | { |
790 | c79c73f6 | Blue Swirl | qemu_log("Return from exception at " TARGET_FMT_lx " with flags " |
791 | c79c73f6 | Blue Swirl | TARGET_FMT_lx "\n", RA, msr);
|
792 | c79c73f6 | Blue Swirl | } |
793 | c79c73f6 | Blue Swirl | #endif
|
794 | c79c73f6 | Blue Swirl | |
795 | ad71ed68 | Blue Swirl | /*****************************************************************************/
|
796 | ad71ed68 | Blue Swirl | /* Exceptions processing helpers */
|
797 | ad71ed68 | Blue Swirl | |
798 | e5f17ac6 | Blue Swirl | void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
|
799 | e5f17ac6 | Blue Swirl | uint32_t error_code) |
800 | ad71ed68 | Blue Swirl | { |
801 | ad71ed68 | Blue Swirl | #if 0
|
802 | ad71ed68 | Blue Swirl | printf("Raise exception %3x code : %d\n", exception, error_code);
|
803 | ad71ed68 | Blue Swirl | #endif
|
804 | ad71ed68 | Blue Swirl | env->exception_index = exception; |
805 | ad71ed68 | Blue Swirl | env->error_code = error_code; |
806 | ad71ed68 | Blue Swirl | cpu_loop_exit(env); |
807 | ad71ed68 | Blue Swirl | } |
808 | ad71ed68 | Blue Swirl | |
809 | e5f17ac6 | Blue Swirl | void helper_raise_exception(CPUPPCState *env, uint32_t exception)
|
810 | ad71ed68 | Blue Swirl | { |
811 | e5f17ac6 | Blue Swirl | helper_raise_exception_err(env, exception, 0);
|
812 | ad71ed68 | Blue Swirl | } |
813 | ad71ed68 | Blue Swirl | |
814 | ad71ed68 | Blue Swirl | #if !defined(CONFIG_USER_ONLY)
|
815 | e5f17ac6 | Blue Swirl | void helper_store_msr(CPUPPCState *env, target_ulong val)
|
816 | ad71ed68 | Blue Swirl | { |
817 | 259186a7 | Andreas Färber | CPUState *cs; |
818 | 259186a7 | Andreas Färber | |
819 | ad71ed68 | Blue Swirl | val = hreg_store_msr(env, val, 0);
|
820 | ad71ed68 | Blue Swirl | if (val != 0) { |
821 | 259186a7 | Andreas Färber | cs = CPU(ppc_env_get_cpu(env)); |
822 | 259186a7 | Andreas Färber | cs->interrupt_request |= CPU_INTERRUPT_EXITTB; |
823 | e5f17ac6 | Blue Swirl | helper_raise_exception(env, val); |
824 | ad71ed68 | Blue Swirl | } |
825 | ad71ed68 | Blue Swirl | } |
826 | ad71ed68 | Blue Swirl | |
827 | e5f17ac6 | Blue Swirl | static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, |
828 | ad71ed68 | Blue Swirl | target_ulong msrm, int keep_msrh)
|
829 | ad71ed68 | Blue Swirl | { |
830 | 259186a7 | Andreas Färber | CPUState *cs = CPU(ppc_env_get_cpu(env)); |
831 | 259186a7 | Andreas Färber | |
832 | ad71ed68 | Blue Swirl | #if defined(TARGET_PPC64)
|
833 | e42a61f1 | Alexander Graf | if (msr_is_64bit(env, msr)) {
|
834 | ad71ed68 | Blue Swirl | nip = (uint64_t)nip; |
835 | ad71ed68 | Blue Swirl | msr &= (uint64_t)msrm; |
836 | ad71ed68 | Blue Swirl | } else {
|
837 | ad71ed68 | Blue Swirl | nip = (uint32_t)nip; |
838 | ad71ed68 | Blue Swirl | msr = (uint32_t)(msr & msrm); |
839 | ad71ed68 | Blue Swirl | if (keep_msrh) {
|
840 | ad71ed68 | Blue Swirl | msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
|
841 | ad71ed68 | Blue Swirl | } |
842 | ad71ed68 | Blue Swirl | } |
843 | ad71ed68 | Blue Swirl | #else
|
844 | ad71ed68 | Blue Swirl | nip = (uint32_t)nip; |
845 | ad71ed68 | Blue Swirl | msr &= (uint32_t)msrm; |
846 | ad71ed68 | Blue Swirl | #endif
|
847 | ad71ed68 | Blue Swirl | /* XXX: beware: this is false if VLE is supported */
|
848 | ad71ed68 | Blue Swirl | env->nip = nip & ~((target_ulong)0x00000003);
|
849 | ad71ed68 | Blue Swirl | hreg_store_msr(env, msr, 1);
|
850 | ad71ed68 | Blue Swirl | #if defined(DEBUG_OP)
|
851 | ad71ed68 | Blue Swirl | cpu_dump_rfi(env->nip, env->msr); |
852 | ad71ed68 | Blue Swirl | #endif
|
853 | ad71ed68 | Blue Swirl | /* No need to raise an exception here,
|
854 | ad71ed68 | Blue Swirl | * as rfi is always the last insn of a TB
|
855 | ad71ed68 | Blue Swirl | */
|
856 | 259186a7 | Andreas Färber | cs->interrupt_request |= CPU_INTERRUPT_EXITTB; |
857 | ad71ed68 | Blue Swirl | } |
858 | ad71ed68 | Blue Swirl | |
859 | e5f17ac6 | Blue Swirl | void helper_rfi(CPUPPCState *env)
|
860 | ad71ed68 | Blue Swirl | { |
861 | a1bb7384 | Scott Wood | if (env->excp_model == POWERPC_EXCP_BOOKE) {
|
862 | a1bb7384 | Scott Wood | do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], |
863 | a1bb7384 | Scott Wood | ~((target_ulong)0), 0); |
864 | a1bb7384 | Scott Wood | } else {
|
865 | a1bb7384 | Scott Wood | do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], |
866 | a1bb7384 | Scott Wood | ~((target_ulong)0x783F0000), 1); |
867 | a1bb7384 | Scott Wood | } |
868 | ad71ed68 | Blue Swirl | } |
869 | ad71ed68 | Blue Swirl | |
870 | ad71ed68 | Blue Swirl | #if defined(TARGET_PPC64)
|
871 | e5f17ac6 | Blue Swirl | void helper_rfid(CPUPPCState *env)
|
872 | ad71ed68 | Blue Swirl | { |
873 | e5f17ac6 | Blue Swirl | do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1], |
874 | ad71ed68 | Blue Swirl | ~((target_ulong)0x783F0000), 0); |
875 | ad71ed68 | Blue Swirl | } |
876 | ad71ed68 | Blue Swirl | |
877 | e5f17ac6 | Blue Swirl | void helper_hrfid(CPUPPCState *env)
|
878 | ad71ed68 | Blue Swirl | { |
879 | e5f17ac6 | Blue Swirl | do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1], |
880 | ad71ed68 | Blue Swirl | ~((target_ulong)0x783F0000), 0); |
881 | ad71ed68 | Blue Swirl | } |
882 | ad71ed68 | Blue Swirl | #endif
|
883 | ad71ed68 | Blue Swirl | |
884 | ad71ed68 | Blue Swirl | /*****************************************************************************/
|
885 | ad71ed68 | Blue Swirl | /* Embedded PowerPC specific helpers */
|
886 | e5f17ac6 | Blue Swirl | void helper_40x_rfci(CPUPPCState *env)
|
887 | ad71ed68 | Blue Swirl | { |
888 | e5f17ac6 | Blue Swirl | do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3], |
889 | ad71ed68 | Blue Swirl | ~((target_ulong)0xFFFF0000), 0); |
890 | ad71ed68 | Blue Swirl | } |
891 | ad71ed68 | Blue Swirl | |
892 | e5f17ac6 | Blue Swirl | void helper_rfci(CPUPPCState *env)
|
893 | ad71ed68 | Blue Swirl | { |
894 | a1bb7384 | Scott Wood | do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1], |
895 | a1bb7384 | Scott Wood | ~((target_ulong)0), 0); |
896 | ad71ed68 | Blue Swirl | } |
897 | ad71ed68 | Blue Swirl | |
898 | e5f17ac6 | Blue Swirl | void helper_rfdi(CPUPPCState *env)
|
899 | ad71ed68 | Blue Swirl | { |
900 | a1bb7384 | Scott Wood | /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
|
901 | a1bb7384 | Scott Wood | do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1], |
902 | a1bb7384 | Scott Wood | ~((target_ulong)0), 0); |
903 | ad71ed68 | Blue Swirl | } |
904 | ad71ed68 | Blue Swirl | |
905 | e5f17ac6 | Blue Swirl | void helper_rfmci(CPUPPCState *env)
|
906 | ad71ed68 | Blue Swirl | { |
907 | a1bb7384 | Scott Wood | /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
|
908 | a1bb7384 | Scott Wood | do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1], |
909 | a1bb7384 | Scott Wood | ~((target_ulong)0), 0); |
910 | ad71ed68 | Blue Swirl | } |
911 | ad71ed68 | Blue Swirl | #endif
|
912 | ad71ed68 | Blue Swirl | |
913 | e5f17ac6 | Blue Swirl | void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
|
914 | e5f17ac6 | Blue Swirl | uint32_t flags) |
915 | ad71ed68 | Blue Swirl | { |
916 | ad71ed68 | Blue Swirl | if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) || |
917 | ad71ed68 | Blue Swirl | ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
|
918 | ad71ed68 | Blue Swirl | ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
|
919 | ad71ed68 | Blue Swirl | ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
|
920 | ad71ed68 | Blue Swirl | ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
|
921 | e5f17ac6 | Blue Swirl | helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
922 | e5f17ac6 | Blue Swirl | POWERPC_EXCP_TRAP); |
923 | ad71ed68 | Blue Swirl | } |
924 | ad71ed68 | Blue Swirl | } |
925 | ad71ed68 | Blue Swirl | |
926 | ad71ed68 | Blue Swirl | #if defined(TARGET_PPC64)
|
927 | e5f17ac6 | Blue Swirl | void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
|
928 | e5f17ac6 | Blue Swirl | uint32_t flags) |
929 | ad71ed68 | Blue Swirl | { |
930 | ad71ed68 | Blue Swirl | if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) || |
931 | ad71ed68 | Blue Swirl | ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
|
932 | ad71ed68 | Blue Swirl | ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
|
933 | ad71ed68 | Blue Swirl | ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
|
934 | ad71ed68 | Blue Swirl | ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
|
935 | e5f17ac6 | Blue Swirl | helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
936 | e5f17ac6 | Blue Swirl | POWERPC_EXCP_TRAP); |
937 | ad71ed68 | Blue Swirl | } |
938 | ad71ed68 | Blue Swirl | } |
939 | ad71ed68 | Blue Swirl | #endif
|
940 | ad71ed68 | Blue Swirl | |
941 | ad71ed68 | Blue Swirl | #if !defined(CONFIG_USER_ONLY)
|
942 | ad71ed68 | Blue Swirl | /*****************************************************************************/
|
943 | ad71ed68 | Blue Swirl | /* PowerPC 601 specific instructions (POWER bridge) */
|
944 | ad71ed68 | Blue Swirl | |
945 | e5f17ac6 | Blue Swirl | void helper_rfsvc(CPUPPCState *env)
|
946 | ad71ed68 | Blue Swirl | { |
947 | e5f17ac6 | Blue Swirl | do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0); |
948 | ad71ed68 | Blue Swirl | } |
949 | ad71ed68 | Blue Swirl | |
950 | ad71ed68 | Blue Swirl | /* Embedded.Processor Control */
|
951 | ad71ed68 | Blue Swirl | static int dbell2irq(target_ulong rb) |
952 | ad71ed68 | Blue Swirl | { |
953 | ad71ed68 | Blue Swirl | int msg = rb & DBELL_TYPE_MASK;
|
954 | ad71ed68 | Blue Swirl | int irq = -1; |
955 | ad71ed68 | Blue Swirl | |
956 | ad71ed68 | Blue Swirl | switch (msg) {
|
957 | ad71ed68 | Blue Swirl | case DBELL_TYPE_DBELL:
|
958 | ad71ed68 | Blue Swirl | irq = PPC_INTERRUPT_DOORBELL; |
959 | ad71ed68 | Blue Swirl | break;
|
960 | ad71ed68 | Blue Swirl | case DBELL_TYPE_DBELL_CRIT:
|
961 | ad71ed68 | Blue Swirl | irq = PPC_INTERRUPT_CDOORBELL; |
962 | ad71ed68 | Blue Swirl | break;
|
963 | ad71ed68 | Blue Swirl | case DBELL_TYPE_G_DBELL:
|
964 | ad71ed68 | Blue Swirl | case DBELL_TYPE_G_DBELL_CRIT:
|
965 | ad71ed68 | Blue Swirl | case DBELL_TYPE_G_DBELL_MC:
|
966 | ad71ed68 | Blue Swirl | /* XXX implement */
|
967 | ad71ed68 | Blue Swirl | default:
|
968 | ad71ed68 | Blue Swirl | break;
|
969 | ad71ed68 | Blue Swirl | } |
970 | ad71ed68 | Blue Swirl | |
971 | ad71ed68 | Blue Swirl | return irq;
|
972 | ad71ed68 | Blue Swirl | } |
973 | ad71ed68 | Blue Swirl | |
974 | e5f17ac6 | Blue Swirl | void helper_msgclr(CPUPPCState *env, target_ulong rb)
|
975 | ad71ed68 | Blue Swirl | { |
976 | ad71ed68 | Blue Swirl | int irq = dbell2irq(rb);
|
977 | ad71ed68 | Blue Swirl | |
978 | ad71ed68 | Blue Swirl | if (irq < 0) { |
979 | ad71ed68 | Blue Swirl | return;
|
980 | ad71ed68 | Blue Swirl | } |
981 | ad71ed68 | Blue Swirl | |
982 | ad71ed68 | Blue Swirl | env->pending_interrupts &= ~(1 << irq);
|
983 | ad71ed68 | Blue Swirl | } |
984 | ad71ed68 | Blue Swirl | |
985 | ad71ed68 | Blue Swirl | void helper_msgsnd(target_ulong rb)
|
986 | ad71ed68 | Blue Swirl | { |
987 | ad71ed68 | Blue Swirl | int irq = dbell2irq(rb);
|
988 | ad71ed68 | Blue Swirl | int pir = rb & DBELL_PIRTAG_MASK;
|
989 | ad71ed68 | Blue Swirl | CPUPPCState *cenv; |
990 | ad71ed68 | Blue Swirl | |
991 | ad71ed68 | Blue Swirl | if (irq < 0) { |
992 | ad71ed68 | Blue Swirl | return;
|
993 | ad71ed68 | Blue Swirl | } |
994 | ad71ed68 | Blue Swirl | |
995 | ad71ed68 | Blue Swirl | for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { |
996 | ad71ed68 | Blue Swirl | if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
|
997 | ad71ed68 | Blue Swirl | cenv->pending_interrupts |= 1 << irq;
|
998 | c3affe56 | Andreas Färber | cpu_interrupt(CPU(ppc_env_get_cpu(cenv)), CPU_INTERRUPT_HARD); |
999 | ad71ed68 | Blue Swirl | } |
1000 | ad71ed68 | Blue Swirl | } |
1001 | ad71ed68 | Blue Swirl | } |
1002 | ad71ed68 | Blue Swirl | #endif |