]> git.proxmox.com Git - qemu.git/blame - target-ppc/helper.c
Update version for 1.1.0-rc4 release
[qemu.git] / target-ppc / helper.c
CommitLineData
79aceca5 1/*
3fc6c082 2 * PowerPC emulation helpers for qemu.
5fafdf24 3 *
76a66253 4 * Copyright (c) 2003-2007 Jocelyn Mayer
79aceca5
FB
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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
79aceca5 18 */
fdabc366
FB
19
20#include "cpu.h"
0411a972 21#include "helper_regs.h"
d76d1650 22#include "kvm.h"
e97c3636
DG
23#include "kvm_ppc.h"
24#include "cpus.h"
9a64fbe4
FB
25
26//#define DEBUG_MMU
27//#define DEBUG_BATS
6b542af7 28//#define DEBUG_SLB
76a66253 29//#define DEBUG_SOFTWARE_TLB
0411a972 30//#define DUMP_PAGE_TABLES
9a64fbe4 31//#define DEBUG_EXCEPTIONS
fdabc366 32//#define FLUSH_ALL_TLBS
9a64fbe4 33
d12d51d5 34#ifdef DEBUG_MMU
93fcfe39
AL
35# define LOG_MMU(...) qemu_log(__VA_ARGS__)
36# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
d12d51d5
AL
37#else
38# define LOG_MMU(...) do { } while (0)
39# define LOG_MMU_STATE(...) do { } while (0)
40#endif
41
42
43#ifdef DEBUG_SOFTWARE_TLB
93fcfe39 44# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
45#else
46# define LOG_SWTLB(...) do { } while (0)
47#endif
48
49#ifdef DEBUG_BATS
93fcfe39 50# define LOG_BATS(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
51#else
52# define LOG_BATS(...) do { } while (0)
53#endif
54
55#ifdef DEBUG_SLB
93fcfe39 56# define LOG_SLB(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
57#else
58# define LOG_SLB(...) do { } while (0)
59#endif
60
61#ifdef DEBUG_EXCEPTIONS
93fcfe39 62# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
63#else
64# define LOG_EXCP(...) do { } while (0)
65#endif
66
d569956e
DG
67/*****************************************************************************/
68/* PowerPC Hypercall emulation */
69
1328c2bf 70void (*cpu_ppc_hypercall)(CPUPPCState *);
d12d51d5 71
64adab3f 72/*****************************************************************************/
3fc6c082 73/* PowerPC MMU emulation */
a541f297 74
d9bce9d9 75#if defined(CONFIG_USER_ONLY)
1328c2bf 76int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
97b348e7 77 int mmu_idx)
24741ef3
FB
78{
79 int exception, error_code;
d9bce9d9 80
24741ef3 81 if (rw == 2) {
e1833e1f 82 exception = POWERPC_EXCP_ISI;
8f793433 83 error_code = 0x40000000;
24741ef3 84 } else {
e1833e1f 85 exception = POWERPC_EXCP_DSI;
8f793433 86 error_code = 0x40000000;
24741ef3
FB
87 if (rw)
88 error_code |= 0x02000000;
89 env->spr[SPR_DAR] = address;
90 env->spr[SPR_DSISR] = error_code;
91 }
92 env->exception_index = exception;
93 env->error_code = error_code;
76a66253 94
24741ef3
FB
95 return 1;
96}
76a66253 97
24741ef3 98#else
76a66253 99/* Common routines used by software and hardware TLBs emulation */
636aa200 100static inline int pte_is_valid(target_ulong pte0)
76a66253
JM
101{
102 return pte0 & 0x80000000 ? 1 : 0;
103}
104
636aa200 105static inline void pte_invalidate(target_ulong *pte0)
76a66253
JM
106{
107 *pte0 &= ~0x80000000;
108}
109
caa4039c 110#if defined(TARGET_PPC64)
636aa200 111static inline int pte64_is_valid(target_ulong pte0)
caa4039c
JM
112{
113 return pte0 & 0x0000000000000001ULL ? 1 : 0;
114}
115
636aa200 116static inline void pte64_invalidate(target_ulong *pte0)
caa4039c
JM
117{
118 *pte0 &= ~0x0000000000000001ULL;
119}
120#endif
121
76a66253
JM
122#define PTE_PTEM_MASK 0x7FFFFFBF
123#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
caa4039c
JM
124#if defined(TARGET_PPC64)
125#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
126#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
127#endif
76a66253 128
636aa200 129static inline int pp_check(int key, int pp, int nx)
b227a8e9
JM
130{
131 int access;
132
133 /* Compute access rights */
134 /* When pp is 3/7, the result is undefined. Set it to noaccess */
135 access = 0;
136 if (key == 0) {
137 switch (pp) {
138 case 0x0:
139 case 0x1:
140 case 0x2:
141 access |= PAGE_WRITE;
142 /* No break here */
143 case 0x3:
144 case 0x6:
145 access |= PAGE_READ;
146 break;
147 }
148 } else {
149 switch (pp) {
150 case 0x0:
151 case 0x6:
152 access = 0;
153 break;
154 case 0x1:
155 case 0x3:
156 access = PAGE_READ;
157 break;
158 case 0x2:
159 access = PAGE_READ | PAGE_WRITE;
160 break;
161 }
162 }
163 if (nx == 0)
164 access |= PAGE_EXEC;
165
166 return access;
167}
168
636aa200 169static inline int check_prot(int prot, int rw, int access_type)
b227a8e9
JM
170{
171 int ret;
172
173 if (access_type == ACCESS_CODE) {
174 if (prot & PAGE_EXEC)
175 ret = 0;
176 else
177 ret = -2;
178 } else if (rw) {
179 if (prot & PAGE_WRITE)
180 ret = 0;
181 else
182 ret = -2;
183 } else {
184 if (prot & PAGE_READ)
185 ret = 0;
186 else
187 ret = -2;
188 }
189
190 return ret;
191}
192
c227f099 193static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
636aa200 194 target_ulong pte1, int h, int rw, int type)
76a66253 195{
caa4039c 196 target_ulong ptem, mmask;
b227a8e9 197 int access, ret, pteh, ptev, pp;
76a66253 198
76a66253
JM
199 ret = -1;
200 /* Check validity and table match */
caa4039c
JM
201#if defined(TARGET_PPC64)
202 if (is_64b) {
203 ptev = pte64_is_valid(pte0);
204 pteh = (pte0 >> 1) & 1;
205 } else
206#endif
207 {
208 ptev = pte_is_valid(pte0);
209 pteh = (pte0 >> 6) & 1;
210 }
211 if (ptev && h == pteh) {
76a66253 212 /* Check vsid & api */
caa4039c
JM
213#if defined(TARGET_PPC64)
214 if (is_64b) {
215 ptem = pte0 & PTE64_PTEM_MASK;
216 mmask = PTE64_CHECK_MASK;
b227a8e9 217 pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
29c8ca6f 218 ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
b227a8e9 219 ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
caa4039c
JM
220 } else
221#endif
222 {
223 ptem = pte0 & PTE_PTEM_MASK;
224 mmask = PTE_CHECK_MASK;
b227a8e9 225 pp = pte1 & 0x00000003;
caa4039c
JM
226 }
227 if (ptem == ctx->ptem) {
c227f099 228 if (ctx->raddr != (target_phys_addr_t)-1ULL) {
76a66253 229 /* all matches should have equal RPN, WIMG & PP */
caa4039c 230 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
93fcfe39 231 qemu_log("Bad RPN/WIMG/PP\n");
76a66253
JM
232 return -3;
233 }
234 }
235 /* Compute access rights */
b227a8e9 236 access = pp_check(ctx->key, pp, ctx->nx);
76a66253
JM
237 /* Keep the matching PTE informations */
238 ctx->raddr = pte1;
239 ctx->prot = access;
b227a8e9
JM
240 ret = check_prot(ctx->prot, rw, type);
241 if (ret == 0) {
76a66253 242 /* Access granted */
d12d51d5 243 LOG_MMU("PTE access granted !\n");
76a66253
JM
244 } else {
245 /* Access right violation */
d12d51d5 246 LOG_MMU("PTE access rejected\n");
76a66253
JM
247 }
248 }
249 }
250
251 return ret;
252}
253
c227f099 254static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
636aa200 255 target_ulong pte1, int h, int rw, int type)
caa4039c 256{
b227a8e9 257 return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
caa4039c
JM
258}
259
260#if defined(TARGET_PPC64)
c227f099 261static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
636aa200 262 target_ulong pte1, int h, int rw, int type)
caa4039c 263{
b227a8e9 264 return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
caa4039c
JM
265}
266#endif
267
c227f099 268static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
636aa200 269 int ret, int rw)
76a66253
JM
270{
271 int store = 0;
272
273 /* Update page flags */
274 if (!(*pte1p & 0x00000100)) {
275 /* Update accessed flag */
276 *pte1p |= 0x00000100;
277 store = 1;
278 }
279 if (!(*pte1p & 0x00000080)) {
280 if (rw == 1 && ret == 0) {
281 /* Update changed flag */
282 *pte1p |= 0x00000080;
283 store = 1;
284 } else {
285 /* Force page fault for first write access */
286 ctx->prot &= ~PAGE_WRITE;
287 }
288 }
289
290 return store;
291}
292
293/* Software driven TLB helpers */
1328c2bf 294static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr, int way,
636aa200 295 int is_code)
76a66253
JM
296{
297 int nr;
298
299 /* Select TLB num in a way from address */
300 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
301 /* Select TLB way */
302 nr += env->tlb_per_way * way;
303 /* 6xx have separate TLBs for instructions and data */
304 if (is_code && env->id_tlbs == 1)
305 nr += env->nb_tlb;
306
307 return nr;
308}
309
1328c2bf 310static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
76a66253 311{
c227f099 312 ppc6xx_tlb_t *tlb;
76a66253
JM
313 int nr, max;
314
d12d51d5 315 //LOG_SWTLB("Invalidate all TLBs\n");
76a66253
JM
316 /* Invalidate all defined software TLB */
317 max = env->nb_tlb;
318 if (env->id_tlbs == 1)
319 max *= 2;
320 for (nr = 0; nr < max; nr++) {
1c53accc 321 tlb = &env->tlb.tlb6[nr];
76a66253
JM
322 pte_invalidate(&tlb->pte0);
323 }
76a66253 324 tlb_flush(env, 1);
76a66253
JM
325}
326
1328c2bf 327static inline void __ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
636aa200
BS
328 target_ulong eaddr,
329 int is_code, int match_epn)
76a66253 330{
4a057712 331#if !defined(FLUSH_ALL_TLBS)
c227f099 332 ppc6xx_tlb_t *tlb;
76a66253
JM
333 int way, nr;
334
76a66253
JM
335 /* Invalidate ITLB + DTLB, all ways */
336 for (way = 0; way < env->nb_ways; way++) {
337 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
1c53accc 338 tlb = &env->tlb.tlb6[nr];
76a66253 339 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
90e189ec
BS
340 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
341 env->nb_tlb, eaddr);
76a66253
JM
342 pte_invalidate(&tlb->pte0);
343 tlb_flush_page(env, tlb->EPN);
344 }
345 }
346#else
347 /* XXX: PowerPC specification say this is valid as well */
348 ppc6xx_tlb_invalidate_all(env);
349#endif
350}
351
1328c2bf 352static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
636aa200 353 target_ulong eaddr, int is_code)
76a66253
JM
354{
355 __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
356}
357
1328c2bf 358void ppc6xx_tlb_store (CPUPPCState *env, target_ulong EPN, int way, int is_code,
76a66253
JM
359 target_ulong pte0, target_ulong pte1)
360{
c227f099 361 ppc6xx_tlb_t *tlb;
76a66253
JM
362 int nr;
363
364 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
1c53accc 365 tlb = &env->tlb.tlb6[nr];
90e189ec
BS
366 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
367 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
5cbdb3a3 368 /* Invalidate any pending reference in QEMU for this virtual address */
76a66253
JM
369 __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
370 tlb->pte0 = pte0;
371 tlb->pte1 = pte1;
372 tlb->EPN = EPN;
76a66253
JM
373 /* Store last way for LRU mechanism */
374 env->last_way = way;
375}
376
1328c2bf 377static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
636aa200 378 target_ulong eaddr, int rw, int access_type)
76a66253 379{
c227f099 380 ppc6xx_tlb_t *tlb;
76a66253
JM
381 int nr, best, way;
382 int ret;
d9bce9d9 383
76a66253
JM
384 best = -1;
385 ret = -1; /* No TLB found */
386 for (way = 0; way < env->nb_ways; way++) {
387 nr = ppc6xx_tlb_getnum(env, eaddr, way,
388 access_type == ACCESS_CODE ? 1 : 0);
1c53accc 389 tlb = &env->tlb.tlb6[nr];
76a66253
JM
390 /* This test "emulates" the PTE index match for hardware TLBs */
391 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
90e189ec
BS
392 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
393 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
394 pte_is_valid(tlb->pte0) ? "valid" : "inval",
395 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
76a66253
JM
396 continue;
397 }
90e189ec
BS
398 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
399 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
400 pte_is_valid(tlb->pte0) ? "valid" : "inval",
401 tlb->EPN, eaddr, tlb->pte1,
402 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
b227a8e9 403 switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
76a66253
JM
404 case -3:
405 /* TLB inconsistency */
406 return -1;
407 case -2:
408 /* Access violation */
409 ret = -2;
410 best = nr;
411 break;
412 case -1:
413 default:
414 /* No match */
415 break;
416 case 0:
417 /* access granted */
418 /* XXX: we should go on looping to check all TLBs consistency
419 * but we can speed-up the whole thing as the
420 * result would be undefined if TLBs are not consistent.
421 */
422 ret = 0;
423 best = nr;
424 goto done;
425 }
426 }
427 if (best != -1) {
428 done:
90e189ec
BS
429 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
430 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
76a66253 431 /* Update page flags */
1c53accc 432 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
76a66253
JM
433 }
434
435 return ret;
436}
437
9a64fbe4 438/* Perform BAT hit & translation */
1328c2bf 439static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp, int *validp,
636aa200
BS
440 int *protp, target_ulong *BATu,
441 target_ulong *BATl)
faadf50e
JM
442{
443 target_ulong bl;
444 int pp, valid, prot;
445
446 bl = (*BATu & 0x00001FFC) << 15;
447 valid = 0;
448 prot = 0;
449 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
450 ((msr_pr != 0) && (*BATu & 0x00000001))) {
451 valid = 1;
452 pp = *BATl & 0x00000003;
453 if (pp != 0) {
454 prot = PAGE_READ | PAGE_EXEC;
455 if (pp == 0x2)
456 prot |= PAGE_WRITE;
457 }
458 }
459 *blp = bl;
460 *validp = valid;
461 *protp = prot;
462}
463
1328c2bf 464static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
636aa200
BS
465 int *validp, int *protp,
466 target_ulong *BATu, target_ulong *BATl)
faadf50e
JM
467{
468 target_ulong bl;
469 int key, pp, valid, prot;
470
471 bl = (*BATl & 0x0000003F) << 17;
90e189ec
BS
472 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
473 (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
faadf50e
JM
474 prot = 0;
475 valid = (*BATl >> 6) & 1;
476 if (valid) {
477 pp = *BATu & 0x00000003;
478 if (msr_pr == 0)
479 key = (*BATu >> 3) & 1;
480 else
481 key = (*BATu >> 2) & 1;
482 prot = pp_check(key, pp, 0);
483 }
484 *blp = bl;
485 *validp = valid;
486 *protp = prot;
487}
488
1328c2bf 489static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong virtual,
636aa200 490 int rw, int type)
9a64fbe4 491{
76a66253 492 target_ulong *BATlt, *BATut, *BATu, *BATl;
05f92404 493 target_ulong BEPIl, BEPIu, bl;
faadf50e 494 int i, valid, prot;
9a64fbe4
FB
495 int ret = -1;
496
90e189ec
BS
497 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
498 type == ACCESS_CODE ? 'I' : 'D', virtual);
9a64fbe4
FB
499 switch (type) {
500 case ACCESS_CODE:
501 BATlt = env->IBAT[1];
502 BATut = env->IBAT[0];
503 break;
504 default:
505 BATlt = env->DBAT[1];
506 BATut = env->DBAT[0];
507 break;
508 }
faadf50e 509 for (i = 0; i < env->nb_BATs; i++) {
9a64fbe4
FB
510 BATu = &BATut[i];
511 BATl = &BATlt[i];
512 BEPIu = *BATu & 0xF0000000;
513 BEPIl = *BATu & 0x0FFE0000;
faadf50e
JM
514 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
515 bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
516 } else {
517 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
518 }
90e189ec
BS
519 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
520 " BATl " TARGET_FMT_lx "\n", __func__,
521 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
9a64fbe4
FB
522 if ((virtual & 0xF0000000) == BEPIu &&
523 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
524 /* BAT matches */
faadf50e 525 if (valid != 0) {
9a64fbe4 526 /* Get physical address */
76a66253 527 ctx->raddr = (*BATl & 0xF0000000) |
9a64fbe4 528 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
a541f297 529 (virtual & 0x0001F000);
b227a8e9 530 /* Compute access rights */
faadf50e 531 ctx->prot = prot;
b227a8e9 532 ret = check_prot(ctx->prot, rw, type);
d12d51d5 533 if (ret == 0)
90e189ec 534 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
d12d51d5
AL
535 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
536 ctx->prot & PAGE_WRITE ? 'W' : '-');
9a64fbe4
FB
537 break;
538 }
539 }
540 }
541 if (ret < 0) {
d12d51d5 542#if defined(DEBUG_BATS)
0bf9e31a 543 if (qemu_log_enabled()) {
90e189ec 544 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
4a057712
JM
545 for (i = 0; i < 4; i++) {
546 BATu = &BATut[i];
547 BATl = &BATlt[i];
548 BEPIu = *BATu & 0xF0000000;
549 BEPIl = *BATu & 0x0FFE0000;
550 bl = (*BATu & 0x00001FFC) << 15;
90e189ec 551 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
b2bedb21 552 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
90e189ec 553 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
0bf9e31a
BS
554 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
555 *BATu, *BATl, BEPIu, BEPIl, bl);
4a057712 556 }
9a64fbe4
FB
557 }
558#endif
9a64fbe4
FB
559 }
560 /* No hit */
561 return ret;
562}
563
1328c2bf 564static inline target_phys_addr_t get_pteg_offset(CPUPPCState *env,
fda6a0ec
DG
565 target_phys_addr_t hash,
566 int pte_size)
567{
568 return (hash * pte_size * 8) & env->htab_mask;
569}
570
9a64fbe4 571/* PTE table lookup */
1328c2bf 572static inline int _find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
fda6a0ec 573 int rw, int type, int target_page_bits)
9a64fbe4 574{
fda6a0ec
DG
575 target_phys_addr_t pteg_off;
576 target_ulong pte0, pte1;
76a66253 577 int i, good = -1;
caa4039c 578 int ret, r;
9a64fbe4 579
76a66253 580 ret = -1; /* No entry found */
fda6a0ec
DG
581 pteg_off = get_pteg_offset(env, ctx->hash[h],
582 is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
9a64fbe4 583 for (i = 0; i < 8; i++) {
caa4039c
JM
584#if defined(TARGET_PPC64)
585 if (is_64b) {
f43e3525
DG
586 if (env->external_htab) {
587 pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
588 pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
589 } else {
590 pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
591 pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
592 }
5b5aba4f 593
b227a8e9 594 r = pte64_check(ctx, pte0, pte1, h, rw, type);
90e189ec
BS
595 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
596 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
decb4714 597 pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
90e189ec 598 (int)((pte0 >> 1) & 1), ctx->ptem);
caa4039c
JM
599 } else
600#endif
601 {
f43e3525
DG
602 if (env->external_htab) {
603 pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
604 pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
605 } else {
606 pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
607 pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
608 }
b227a8e9 609 r = pte32_check(ctx, pte0, pte1, h, rw, type);
90e189ec
BS
610 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
611 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
decb4714 612 pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
90e189ec 613 (int)((pte0 >> 6) & 1), ctx->ptem);
12de9a39 614 }
caa4039c 615 switch (r) {
76a66253
JM
616 case -3:
617 /* PTE inconsistency */
618 return -1;
619 case -2:
620 /* Access violation */
621 ret = -2;
622 good = i;
623 break;
624 case -1:
625 default:
626 /* No PTE match */
627 break;
628 case 0:
629 /* access granted */
630 /* XXX: we should go on looping to check all PTEs consistency
631 * but if we can speed-up the whole thing as the
632 * result would be undefined if PTEs are not consistent.
633 */
634 ret = 0;
635 good = i;
636 goto done;
9a64fbe4
FB
637 }
638 }
639 if (good != -1) {
76a66253 640 done:
90e189ec
BS
641 LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
642 ctx->raddr, ctx->prot, ret);
9a64fbe4 643 /* Update page flags */
76a66253 644 pte1 = ctx->raddr;
caa4039c
JM
645 if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
646#if defined(TARGET_PPC64)
647 if (is_64b) {
f43e3525
DG
648 if (env->external_htab) {
649 stq_p(env->external_htab + pteg_off + (good * 16) + 8,
650 pte1);
651 } else {
652 stq_phys_notdirty(env->htab_base + pteg_off +
653 (good * 16) + 8, pte1);
654 }
caa4039c
JM
655 } else
656#endif
657 {
f43e3525
DG
658 if (env->external_htab) {
659 stl_p(env->external_htab + pteg_off + (good * 8) + 4,
660 pte1);
661 } else {
662 stl_phys_notdirty(env->htab_base + pteg_off +
663 (good * 8) + 4, pte1);
664 }
caa4039c
JM
665 }
666 }
9a64fbe4
FB
667 }
668
eb6ea4b2
NW
669 /* We have a TLB that saves 4K pages, so let's
670 * split a huge page to 4k chunks */
671 if (target_page_bits != TARGET_PAGE_BITS) {
672 ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
673 & TARGET_PAGE_MASK;
674 }
9a64fbe4 675 return ret;
79aceca5
FB
676}
677
1328c2bf 678static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
636aa200 679 int type, int target_page_bits)
caa4039c
JM
680{
681#if defined(TARGET_PPC64)
add78955 682 if (env->mmu_model & POWERPC_MMU_64)
256cebe5 683 return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
caa4039c
JM
684#endif
685
256cebe5 686 return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
caa4039c
JM
687}
688
caa4039c 689#if defined(TARGET_PPC64)
8500e3a9 690static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
caa4039c 691{
cdaee006 692 uint64_t esid_256M, esid_1T;
81762d6d 693 int n;
caa4039c 694
90e189ec 695 LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
81762d6d 696
cdaee006
DG
697 esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
698 esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
81762d6d 699
eacc3249 700 for (n = 0; n < env->slb_nr; n++) {
81762d6d
DG
701 ppc_slb_t *slb = &env->slb[n];
702
703 LOG_SLB("%s: slot %d %016" PRIx64 " %016"
704 PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
cdaee006
DG
705 /* We check for 1T matches on all MMUs here - if the MMU
706 * doesn't have 1T segment support, we will have prevented 1T
707 * entries from being inserted in the slbmte code. */
708 if (((slb->esid == esid_256M) &&
709 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
710 || ((slb->esid == esid_1T) &&
711 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
8500e3a9 712 return slb;
caa4039c 713 }
caa4039c
JM
714 }
715
8500e3a9 716 return NULL;
79aceca5 717}
12de9a39 718
eacc3249
JM
719void ppc_slb_invalidate_all (CPUPPCState *env)
720{
eacc3249
JM
721 int n, do_invalidate;
722
723 do_invalidate = 0;
2c1ee068
JM
724 /* XXX: Warning: slbia never invalidates the first segment */
725 for (n = 1; n < env->slb_nr; n++) {
81762d6d 726 ppc_slb_t *slb = &env->slb[n];
8eee0af9 727
81762d6d
DG
728 if (slb->esid & SLB_ESID_V) {
729 slb->esid &= ~SLB_ESID_V;
eacc3249
JM
730 /* XXX: given the fact that segment size is 256 MB or 1TB,
731 * and we still don't have a tlb_flush_mask(env, n, mask)
5cbdb3a3 732 * in QEMU, we just invalidate all TLBs
eacc3249
JM
733 */
734 do_invalidate = 1;
735 }
eacc3249
JM
736 }
737 if (do_invalidate)
738 tlb_flush(env, 1);
739}
740
741void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
742{
81762d6d 743 ppc_slb_t *slb;
eacc3249 744
8500e3a9
DG
745 slb = slb_lookup(env, T0);
746 if (!slb) {
81762d6d 747 return;
eacc3249 748 }
eacc3249 749
81762d6d
DG
750 if (slb->esid & SLB_ESID_V) {
751 slb->esid &= ~SLB_ESID_V;
12de9a39 752
81762d6d
DG
753 /* XXX: given the fact that segment size is 256 MB or 1TB,
754 * and we still don't have a tlb_flush_mask(env, n, mask)
5cbdb3a3 755 * in QEMU, we just invalidate all TLBs
81762d6d
DG
756 */
757 tlb_flush(env, 1);
758 }
12de9a39
JM
759}
760
81762d6d 761int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
12de9a39 762{
81762d6d 763 int slot = rb & 0xfff;
81762d6d 764 ppc_slb_t *slb = &env->slb[slot];
f6b868fc 765
cdaee006
DG
766 if (rb & (0x1000 - env->slb_nr)) {
767 return -1; /* Reserved bits set or slot too high */
768 }
769 if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
770 return -1; /* Bad segment size */
771 }
772 if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
773 return -1; /* 1T segment on MMU that doesn't support it */
81762d6d 774 }
f6b868fc 775
cdaee006
DG
776 /* Mask out the slot number as we store the entry */
777 slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
81762d6d 778 slb->vsid = rs;
f6b868fc 779
90e189ec 780 LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
81762d6d
DG
781 " %016" PRIx64 "\n", __func__, slot, rb, rs,
782 slb->esid, slb->vsid);
f6b868fc 783
81762d6d 784 return 0;
12de9a39 785}
efdef95f
DG
786
787int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
788{
789 int slot = rb & 0xfff;
790 ppc_slb_t *slb = &env->slb[slot];
791
792 if (slot >= env->slb_nr) {
793 return -1;
794 }
795
796 *rt = slb->esid;
797 return 0;
798}
799
800int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
801{
802 int slot = rb & 0xfff;
803 ppc_slb_t *slb = &env->slb[slot];
804
805 if (slot >= env->slb_nr) {
806 return -1;
807 }
808
809 *rt = slb->vsid;
810 return 0;
811}
caa4039c 812#endif /* defined(TARGET_PPC64) */
79aceca5 813
9a64fbe4 814/* Perform segment based translation */
1328c2bf 815static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
636aa200 816 target_ulong eaddr, int rw, int type)
79aceca5 817{
bb593904 818 target_phys_addr_t hash;
256cebe5 819 target_ulong vsid;
fda6a0ec 820 int ds, pr, target_page_bits;
caa4039c
JM
821 int ret, ret2;
822
0411a972 823 pr = msr_pr;
256cebe5 824 ctx->eaddr = eaddr;
caa4039c 825#if defined(TARGET_PPC64)
add78955 826 if (env->mmu_model & POWERPC_MMU_64) {
8500e3a9 827 ppc_slb_t *slb;
256cebe5 828 target_ulong pageaddr;
cdaee006 829 int segment_bits;
81762d6d 830
d12d51d5 831 LOG_MMU("Check SLBs\n");
8500e3a9
DG
832 slb = slb_lookup(env, eaddr);
833 if (!slb) {
834 return -5;
835 }
836
cdaee006
DG
837 if (slb->vsid & SLB_VSID_B) {
838 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
839 segment_bits = 40;
840 } else {
841 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
842 segment_bits = 28;
843 }
844
8500e3a9
DG
845 target_page_bits = (slb->vsid & SLB_VSID_L)
846 ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
847 ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
848 : (slb->vsid & SLB_VSID_KS));
caa4039c 849 ds = 0;
8500e3a9 850 ctx->nx = !!(slb->vsid & SLB_VSID_N);
256cebe5 851
cdaee006
DG
852 pageaddr = eaddr & ((1ULL << segment_bits)
853 - (1ULL << target_page_bits));
854 if (slb->vsid & SLB_VSID_B) {
855 hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
856 } else {
857 hash = vsid ^ (pageaddr >> target_page_bits);
858 }
256cebe5 859 /* Only 5 bits of the page index are used in the AVPN */
cdaee006
DG
860 ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
861 ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
caa4039c
JM
862 } else
863#endif /* defined(TARGET_PPC64) */
864 {
256cebe5
DG
865 target_ulong sr, pgidx;
866
caa4039c 867 sr = env->sr[eaddr >> 28];
0411a972
JM
868 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
869 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
caa4039c 870 ds = sr & 0x80000000 ? 1 : 0;
b227a8e9 871 ctx->nx = sr & 0x10000000 ? 1 : 0;
caa4039c 872 vsid = sr & 0x00FFFFFF;
5b5aba4f 873 target_page_bits = TARGET_PAGE_BITS;
90e189ec
BS
874 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
875 TARGET_FMT_lx " lr=" TARGET_FMT_lx
876 " ir=%d dr=%d pr=%d %d t=%d\n",
877 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
878 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
256cebe5
DG
879 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
880 hash = vsid ^ pgidx;
881 ctx->ptem = (vsid << 7) | (pgidx >> 10);
caa4039c 882 }
90e189ec
BS
883 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
884 ctx->key, ds, ctx->nx, vsid);
caa4039c
JM
885 ret = -1;
886 if (!ds) {
9a64fbe4 887 /* Check if instruction fetch is allowed, if needed */
b227a8e9 888 if (type != ACCESS_CODE || ctx->nx == 0) {
9a64fbe4 889 /* Page address translation */
bb593904
DG
890 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
891 " hash " TARGET_FMT_plx "\n",
892 env->htab_base, env->htab_mask, hash);
fda6a0ec
DG
893 ctx->hash[0] = hash;
894 ctx->hash[1] = ~hash;
895
76a66253 896 /* Initialize real address with an invalid value */
c227f099 897 ctx->raddr = (target_phys_addr_t)-1ULL;
7dbe11ac
JM
898 if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
899 env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
76a66253
JM
900 /* Software TLB search */
901 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
76a66253 902 } else {
bb593904 903 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
256cebe5 904 " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
fda6a0ec 905 " hash=" TARGET_FMT_plx "\n",
256cebe5 906 env->htab_base, env->htab_mask, vsid, ctx->ptem,
fda6a0ec 907 ctx->hash[0]);
76a66253 908 /* Primary table lookup */
5b5aba4f 909 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
76a66253
JM
910 if (ret < 0) {
911 /* Secondary table lookup */
d12d51d5 912 if (eaddr != 0xEFFFFFFF)
bb593904
DG
913 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
914 " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
decb4714 915 " hash=" TARGET_FMT_plx "\n", env->htab_base,
256cebe5 916 env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
5b5aba4f
BS
917 ret2 = find_pte(env, ctx, 1, rw, type,
918 target_page_bits);
76a66253
JM
919 if (ret2 != -1)
920 ret = ret2;
921 }
9a64fbe4 922 }
0411a972 923#if defined (DUMP_PAGE_TABLES)
93fcfe39 924 if (qemu_log_enabled()) {
c227f099 925 target_phys_addr_t curaddr;
b33c17e1 926 uint32_t a0, a1, a2, a3;
90e189ec
BS
927 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
928 "\n", sdr, mask + 0x80);
b33c17e1
JM
929 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
930 curaddr += 16) {
931 a0 = ldl_phys(curaddr);
932 a1 = ldl_phys(curaddr + 4);
933 a2 = ldl_phys(curaddr + 8);
934 a3 = ldl_phys(curaddr + 12);
935 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
90e189ec
BS
936 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
937 curaddr, a0, a1, a2, a3);
12de9a39 938 }
b33c17e1
JM
939 }
940 }
12de9a39 941#endif
9a64fbe4 942 } else {
d12d51d5 943 LOG_MMU("No access allowed\n");
76a66253 944 ret = -3;
9a64fbe4
FB
945 }
946 } else {
826e7b82 947 target_ulong sr;
d12d51d5 948 LOG_MMU("direct store...\n");
9a64fbe4 949 /* Direct-store segment : absolutely *BUGGY* for now */
826e7b82
HP
950
951 /* Direct-store implies a 32-bit MMU.
952 * Check the Segment Register's bus unit ID (BUID).
953 */
954 sr = env->sr[eaddr >> 28];
955 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
956 /* Memory-forced I/O controller interface access */
957 /* If T=1 and BUID=x'07F', the 601 performs a memory access
958 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
959 */
960 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
961 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
962 return 0;
963 }
964
9a64fbe4
FB
965 switch (type) {
966 case ACCESS_INT:
967 /* Integer load/store : only access allowed */
968 break;
969 case ACCESS_CODE:
970 /* No code fetch is allowed in direct-store areas */
971 return -4;
972 case ACCESS_FLOAT:
973 /* Floating point load/store */
974 return -4;
975 case ACCESS_RES:
976 /* lwarx, ldarx or srwcx. */
977 return -4;
978 case ACCESS_CACHE:
979 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
980 /* Should make the instruction do no-op.
981 * As it already do no-op, it's quite easy :-)
982 */
76a66253 983 ctx->raddr = eaddr;
9a64fbe4
FB
984 return 0;
985 case ACCESS_EXT:
986 /* eciwx or ecowx */
987 return -4;
988 default:
93fcfe39 989 qemu_log("ERROR: instruction should not need "
9a64fbe4 990 "address translation\n");
9a64fbe4
FB
991 return -4;
992 }
76a66253
JM
993 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
994 ctx->raddr = eaddr;
9a64fbe4
FB
995 ret = 2;
996 } else {
997 ret = -2;
998 }
79aceca5 999 }
9a64fbe4
FB
1000
1001 return ret;
79aceca5
FB
1002}
1003
c294fc58 1004/* Generic TLB check function for embedded PowerPC implementations */
1328c2bf 1005int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
01662f3e
AG
1006 target_phys_addr_t *raddrp,
1007 target_ulong address, uint32_t pid, int ext,
1008 int i)
c294fc58
JM
1009{
1010 target_ulong mask;
1011
1012 /* Check valid flag */
1013 if (!(tlb->prot & PAGE_VALID)) {
c294fc58
JM
1014 return -1;
1015 }
1016 mask = ~(tlb->size - 1);
90e189ec 1017 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
01662f3e
AG
1018 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
1019 mask, (uint32_t)tlb->PID, tlb->prot);
c294fc58 1020 /* Check PID */
36081602 1021 if (tlb->PID != 0 && tlb->PID != pid)
c294fc58
JM
1022 return -1;
1023 /* Check effective address */
1024 if ((address & mask) != tlb->EPN)
1025 return -1;
1026 *raddrp = (tlb->RPN & mask) | (address & ~mask);
9706285b 1027#if (TARGET_PHYS_ADDR_BITS >= 36)
36081602
JM
1028 if (ext) {
1029 /* Extend the physical address to 36 bits */
c227f099 1030 *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
36081602 1031 }
9706285b 1032#endif
c294fc58
JM
1033
1034 return 0;
1035}
1036
1037/* Generic TLB search function for PowerPC embedded implementations */
36081602 1038int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
c294fc58 1039{
c227f099
AL
1040 ppcemb_tlb_t *tlb;
1041 target_phys_addr_t raddr;
c294fc58
JM
1042 int i, ret;
1043
1044 /* Default return value is no match */
1045 ret = -1;
a750fc0b 1046 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1047 tlb = &env->tlb.tlbe[i];
36081602 1048 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
c294fc58
JM
1049 ret = i;
1050 break;
1051 }
1052 }
1053
1054 return ret;
1055}
1056
daf4f96e 1057/* Helpers specific to PowerPC 40x implementations */
1328c2bf 1058static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
a750fc0b 1059{
c227f099 1060 ppcemb_tlb_t *tlb;
a750fc0b
JM
1061 int i;
1062
1063 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1064 tlb = &env->tlb.tlbe[i];
daf4f96e 1065 tlb->prot &= ~PAGE_VALID;
a750fc0b 1066 }
daf4f96e 1067 tlb_flush(env, 1);
a750fc0b
JM
1068}
1069
1328c2bf 1070static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
636aa200 1071 target_ulong eaddr, uint32_t pid)
0a032cbe 1072{
daf4f96e 1073#if !defined(FLUSH_ALL_TLBS)
c227f099
AL
1074 ppcemb_tlb_t *tlb;
1075 target_phys_addr_t raddr;
daf4f96e 1076 target_ulong page, end;
0a032cbe
JM
1077 int i;
1078
1079 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1080 tlb = &env->tlb.tlbe[i];
daf4f96e 1081 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
0a032cbe
JM
1082 end = tlb->EPN + tlb->size;
1083 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
1084 tlb_flush_page(env, page);
0a032cbe 1085 tlb->prot &= ~PAGE_VALID;
daf4f96e 1086 break;
0a032cbe
JM
1087 }
1088 }
daf4f96e
JM
1089#else
1090 ppc4xx_tlb_invalidate_all(env);
1091#endif
0a032cbe
JM
1092}
1093
1328c2bf 1094static int mmu40x_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx,
e96efcfc 1095 target_ulong address, int rw, int access_type)
a8dea12f 1096{
c227f099
AL
1097 ppcemb_tlb_t *tlb;
1098 target_phys_addr_t raddr;
0411a972 1099 int i, ret, zsel, zpr, pr;
3b46e624 1100
c55e9aef 1101 ret = -1;
c227f099 1102 raddr = (target_phys_addr_t)-1ULL;
0411a972 1103 pr = msr_pr;
a8dea12f 1104 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1105 tlb = &env->tlb.tlbe[i];
36081602
JM
1106 if (ppcemb_tlb_check(env, tlb, &raddr, address,
1107 env->spr[SPR_40x_PID], 0, i) < 0)
a8dea12f 1108 continue;
a8dea12f 1109 zsel = (tlb->attr >> 4) & 0xF;
ec5c3e48 1110 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
d12d51d5 1111 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
a8dea12f 1112 __func__, i, zsel, zpr, rw, tlb->attr);
b227a8e9
JM
1113 /* Check execute enable bit */
1114 switch (zpr) {
1115 case 0x2:
0411a972 1116 if (pr != 0)
b227a8e9
JM
1117 goto check_perms;
1118 /* No break here */
1119 case 0x3:
1120 /* All accesses granted */
1121 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1122 ret = 0;
1123 break;
1124 case 0x0:
0411a972 1125 if (pr != 0) {
dcbc9a70
EI
1126 /* Raise Zone protection fault. */
1127 env->spr[SPR_40x_ESR] = 1 << 22;
b227a8e9
JM
1128 ctx->prot = 0;
1129 ret = -2;
a8dea12f
JM
1130 break;
1131 }
b227a8e9
JM
1132 /* No break here */
1133 case 0x1:
1134 check_perms:
1135 /* Check from TLB entry */
b227a8e9 1136 ctx->prot = tlb->prot;
b227a8e9 1137 ret = check_prot(ctx->prot, rw, access_type);
dcbc9a70
EI
1138 if (ret == -2)
1139 env->spr[SPR_40x_ESR] = 0;
b227a8e9 1140 break;
a8dea12f
JM
1141 }
1142 if (ret >= 0) {
1143 ctx->raddr = raddr;
90e189ec
BS
1144 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1145 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1146 ret);
c55e9aef 1147 return 0;
a8dea12f
JM
1148 }
1149 }
90e189ec
BS
1150 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1151 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
3b46e624 1152
a8dea12f
JM
1153 return ret;
1154}
1155
c294fc58
JM
1156void store_40x_sler (CPUPPCState *env, uint32_t val)
1157{
1158 /* XXX: TO BE FIXED */
1159 if (val != 0x00000000) {
1160 cpu_abort(env, "Little-endian regions are not supported by now\n");
1161 }
1162 env->spr[SPR_405_SLER] = val;
1163}
1164
1328c2bf 1165static inline int mmubooke_check_tlb (CPUPPCState *env, ppcemb_tlb_t *tlb,
01662f3e
AG
1166 target_phys_addr_t *raddr, int *prot,
1167 target_ulong address, int rw,
1168 int access_type, int i)
1169{
1170 int ret, _prot;
1171
1172 if (ppcemb_tlb_check(env, tlb, raddr, address,
1173 env->spr[SPR_BOOKE_PID],
1174 !env->nb_pids, i) >= 0) {
1175 goto found_tlb;
1176 }
1177
1178 if (env->spr[SPR_BOOKE_PID1] &&
1179 ppcemb_tlb_check(env, tlb, raddr, address,
1180 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
1181 goto found_tlb;
1182 }
1183
1184 if (env->spr[SPR_BOOKE_PID2] &&
1185 ppcemb_tlb_check(env, tlb, raddr, address,
1186 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
1187 goto found_tlb;
1188 }
1189
1190 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1191 return -1;
1192
1193found_tlb:
1194
1195 if (msr_pr != 0) {
1196 _prot = tlb->prot & 0xF;
1197 } else {
1198 _prot = (tlb->prot >> 4) & 0xF;
1199 }
1200
1201 /* Check the address space */
1202 if (access_type == ACCESS_CODE) {
1203 if (msr_ir != (tlb->attr & 1)) {
1204 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1205 return -1;
1206 }
1207
1208 *prot = _prot;
1209 if (_prot & PAGE_EXEC) {
1210 LOG_SWTLB("%s: good TLB!\n", __func__);
1211 return 0;
1212 }
1213
1214 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
1215 ret = -3;
1216 } else {
1217 if (msr_dr != (tlb->attr & 1)) {
1218 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1219 return -1;
1220 }
1221
1222 *prot = _prot;
1223 if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
1224 LOG_SWTLB("%s: found TLB!\n", __func__);
1225 return 0;
1226 }
1227
1228 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
1229 ret = -2;
1230 }
1231
1232 return ret;
1233}
1234
1328c2bf 1235static int mmubooke_get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx,
93220573
AJ
1236 target_ulong address, int rw,
1237 int access_type)
5eb7995e 1238{
c227f099
AL
1239 ppcemb_tlb_t *tlb;
1240 target_phys_addr_t raddr;
01662f3e 1241 int i, ret;
5eb7995e
JM
1242
1243 ret = -1;
c227f099 1244 raddr = (target_phys_addr_t)-1ULL;
5eb7995e 1245 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1246 tlb = &env->tlb.tlbe[i];
01662f3e
AG
1247 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
1248 access_type, i);
1249 if (!ret) {
1250 break;
1251 }
1252 }
1253
1254 if (ret >= 0) {
1255 ctx->raddr = raddr;
1256 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1257 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1258 ret);
1259 } else {
1260 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1261 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1262 }
1263
1264 return ret;
1265}
1266
1328c2bf 1267void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot)
01662f3e
AG
1268{
1269 int tlb_size;
1270 int i, j;
1c53accc 1271 ppcmas_tlb_t *tlb = env->tlb.tlbm;
01662f3e
AG
1272
1273 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1274 if (flags & (1 << i)) {
1275 tlb_size = booke206_tlb_size(env, i);
1276 for (j = 0; j < tlb_size; j++) {
1c53accc
AG
1277 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
1278 tlb[j].mas1 &= ~MAS1_VALID;
01662f3e 1279 }
5eb7995e 1280 }
01662f3e
AG
1281 }
1282 tlb += booke206_tlb_size(env, i);
1283 }
1284
1285 tlb_flush(env, 1);
1286}
1287
1328c2bf 1288target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb)
d1e256fe 1289{
2bd9543c 1290 int tlbm_size;
d1e256fe 1291
21a0b6ed 1292 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
d1e256fe 1293
2bd9543c 1294 return 1024ULL << tlbm_size;
d1e256fe
AG
1295}
1296
1297/* TLB check function for MAS based SoftTLBs */
1328c2bf 1298int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
d1e256fe
AG
1299 target_phys_addr_t *raddrp,
1300 target_ulong address, uint32_t pid)
1301{
1302 target_ulong mask;
1303 uint32_t tlb_pid;
1304
1305 /* Check valid flag */
1306 if (!(tlb->mas1 & MAS1_VALID)) {
1307 return -1;
1308 }
1309
1310 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
1311 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
1312 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
1313 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
1314 tlb->mas8);
1315
1316 /* Check PID */
1317 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
1318 if (tlb_pid != 0 && tlb_pid != pid) {
1319 return -1;
1320 }
1321
1322 /* Check effective address */
1323 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
1324 return -1;
1325 }
ffba8786
AG
1326
1327 if (raddrp) {
1328 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
1329 }
d1e256fe
AG
1330
1331 return 0;
1332}
1333
1328c2bf 1334static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
d1e256fe
AG
1335 target_phys_addr_t *raddr, int *prot,
1336 target_ulong address, int rw,
1337 int access_type)
1338{
1339 int ret;
1340 int _prot = 0;
1341
1342 if (ppcmas_tlb_check(env, tlb, raddr, address,
1343 env->spr[SPR_BOOKE_PID]) >= 0) {
1344 goto found_tlb;
1345 }
1346
1347 if (env->spr[SPR_BOOKE_PID1] &&
1348 ppcmas_tlb_check(env, tlb, raddr, address,
1349 env->spr[SPR_BOOKE_PID1]) >= 0) {
1350 goto found_tlb;
1351 }
1352
1353 if (env->spr[SPR_BOOKE_PID2] &&
1354 ppcmas_tlb_check(env, tlb, raddr, address,
1355 env->spr[SPR_BOOKE_PID2]) >= 0) {
1356 goto found_tlb;
1357 }
1358
1359 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1360 return -1;
1361
1362found_tlb:
1363
1364 if (msr_pr != 0) {
1365 if (tlb->mas7_3 & MAS3_UR) {
1366 _prot |= PAGE_READ;
1367 }
1368 if (tlb->mas7_3 & MAS3_UW) {
1369 _prot |= PAGE_WRITE;
1370 }
1371 if (tlb->mas7_3 & MAS3_UX) {
1372 _prot |= PAGE_EXEC;
1373 }
1374 } else {
1375 if (tlb->mas7_3 & MAS3_SR) {
1376 _prot |= PAGE_READ;
1377 }
1378 if (tlb->mas7_3 & MAS3_SW) {
1379 _prot |= PAGE_WRITE;
1380 }
1381 if (tlb->mas7_3 & MAS3_SX) {
1382 _prot |= PAGE_EXEC;
1383 }
1384 }
1385
1386 /* Check the address space and permissions */
1387 if (access_type == ACCESS_CODE) {
1388 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1389 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1390 return -1;
1391 }
1392
1393 *prot = _prot;
1394 if (_prot & PAGE_EXEC) {
1395 LOG_SWTLB("%s: good TLB!\n", __func__);
1396 return 0;
1397 }
1398
1399 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
1400 ret = -3;
1401 } else {
1402 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1403 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1404 return -1;
1405 }
1406
1407 *prot = _prot;
1408 if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
1409 LOG_SWTLB("%s: found TLB!\n", __func__);
1410 return 0;
1411 }
1412
1413 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
1414 ret = -2;
1415 }
1416
1417 return ret;
1418}
1419
1328c2bf 1420static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
d1e256fe
AG
1421 target_ulong address, int rw,
1422 int access_type)
01662f3e 1423{
d1e256fe 1424 ppcmas_tlb_t *tlb;
01662f3e
AG
1425 target_phys_addr_t raddr;
1426 int i, j, ret;
1427
1428 ret = -1;
1429 raddr = (target_phys_addr_t)-1ULL;
1430
1431 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1432 int ways = booke206_tlb_ways(env, i);
1433
1434 for (j = 0; j < ways; j++) {
d1e256fe 1435 tlb = booke206_get_tlbm(env, i, address, j);
3f162d11
AG
1436 if (!tlb) {
1437 continue;
1438 }
d1e256fe
AG
1439 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1440 rw, access_type);
01662f3e
AG
1441 if (ret != -1) {
1442 goto found_tlb;
5eb7995e 1443 }
5eb7995e
JM
1444 }
1445 }
01662f3e
AG
1446
1447found_tlb:
1448
1449 if (ret >= 0) {
5eb7995e 1450 ctx->raddr = raddr;
01662f3e
AG
1451 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1452 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1453 ret);
1454 } else {
1455 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1456 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1457 }
5eb7995e
JM
1458
1459 return ret;
1460}
1461
bebabbc7
SW
1462static const char *book3e_tsize_to_str[32] = {
1463 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1464 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1465 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1466 "1T", "2T"
1467};
1468
a7388162
FR
1469static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1470 CPUPPCState *env)
1471{
1472 ppcemb_tlb_t *entry;
1473 int i;
1474
1475 if (kvm_enabled() && !env->kvm_sw_tlb) {
1476 cpu_fprintf(f, "Cannot access KVM TLB\n");
1477 return;
1478 }
1479
1480 cpu_fprintf(f, "\nTLB:\n");
1481 cpu_fprintf(f, "Effective Physical Size PID Prot "
1482 "Attr\n");
1483
1484 entry = &env->tlb.tlbe[0];
1485 for (i = 0; i < env->nb_tlb; i++, entry++) {
1486 target_phys_addr_t ea, pa;
1487 target_ulong mask;
1488 uint64_t size = (uint64_t)entry->size;
1489 char size_buf[20];
1490
1491 /* Check valid flag */
1492 if (!(entry->prot & PAGE_VALID)) {
1493 continue;
1494 }
1495
1496 mask = ~(entry->size - 1);
1497 ea = entry->EPN & mask;
1498 pa = entry->RPN & mask;
1499#if (TARGET_PHYS_ADDR_BITS >= 36)
1500 /* Extend the physical address to 36 bits */
1501 pa |= (target_phys_addr_t)(entry->RPN & 0xF) << 32;
1502#endif
1503 size /= 1024;
1504 if (size >= 1024) {
1505 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1506 } else {
1507 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1508 }
1509 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1510 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1511 entry->prot, entry->attr);
1512 }
1513
1514}
1515
bebabbc7 1516static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1328c2bf 1517 CPUPPCState *env, int tlbn, int offset,
bebabbc7
SW
1518 int tlbsize)
1519{
1520 ppcmas_tlb_t *entry;
1521 int i;
1522
1523 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1524 cpu_fprintf(f, "Effective Physical Size TID TS SRWX URWX WIMGE U0123\n");
1525
1526 entry = &env->tlb.tlbm[offset];
1527 for (i = 0; i < tlbsize; i++, entry++) {
1528 target_phys_addr_t ea, pa, size;
1529 int tsize;
1530
1531 if (!(entry->mas1 & MAS1_VALID)) {
1532 continue;
1533 }
1534
1535 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1536 size = 1024ULL << tsize;
1537 ea = entry->mas2 & ~(size - 1);
1538 pa = entry->mas7_3 & ~(size - 1);
1539
1540 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1541 (uint64_t)ea, (uint64_t)pa,
1542 book3e_tsize_to_str[tsize],
1543 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1544 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1545 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1546 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1547 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1548 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1549 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1550 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1551 entry->mas2 & MAS2_W ? 'W' : '-',
1552 entry->mas2 & MAS2_I ? 'I' : '-',
1553 entry->mas2 & MAS2_M ? 'M' : '-',
1554 entry->mas2 & MAS2_G ? 'G' : '-',
1555 entry->mas2 & MAS2_E ? 'E' : '-',
1556 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1557 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1558 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1559 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1560 }
1561}
1562
1563static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1328c2bf 1564 CPUPPCState *env)
bebabbc7
SW
1565{
1566 int offset = 0;
1567 int i;
1568
1569 if (kvm_enabled() && !env->kvm_sw_tlb) {
1570 cpu_fprintf(f, "Cannot access KVM TLB\n");
1571 return;
1572 }
1573
1574 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1575 int size = booke206_tlb_size(env, i);
1576
1577 if (size == 0) {
1578 continue;
1579 }
1580
1581 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1582 offset += size;
1583 }
1584}
1585
4e9200a0
NA
1586#if defined(TARGET_PPC64)
1587static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1328c2bf 1588 CPUPPCState *env)
4e9200a0
NA
1589{
1590 int i;
1591 uint64_t slbe, slbv;
1592
1593 cpu_synchronize_state(env);
1594
1595 cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
1596 for (i = 0; i < env->slb_nr; i++) {
1597 slbe = env->slb[i].esid;
1598 slbv = env->slb[i].vsid;
1599 if (slbe == 0 && slbv == 0) {
1600 continue;
1601 }
1602 cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
1603 i, slbe, slbv);
1604 }
1605}
1606#endif
1607
1328c2bf 1608void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
bebabbc7
SW
1609{
1610 switch (env->mmu_model) {
a7388162
FR
1611 case POWERPC_MMU_BOOKE:
1612 mmubooke_dump_mmu(f, cpu_fprintf, env);
1613 break;
bebabbc7
SW
1614 case POWERPC_MMU_BOOKE206:
1615 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1616 break;
4e9200a0
NA
1617#if defined(TARGET_PPC64)
1618 case POWERPC_MMU_64B:
1619 case POWERPC_MMU_2_06:
1620 mmubooks_dump_mmu(f, cpu_fprintf, env);
1621 break;
1622#endif
bebabbc7
SW
1623 default:
1624 cpu_fprintf(f, "%s: unimplemented\n", __func__);
1625 }
1626}
1627
1328c2bf 1628static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
636aa200 1629 target_ulong eaddr, int rw)
76a66253
JM
1630{
1631 int in_plb, ret;
3b46e624 1632
76a66253 1633 ctx->raddr = eaddr;
b227a8e9 1634 ctx->prot = PAGE_READ | PAGE_EXEC;
76a66253 1635 ret = 0;
a750fc0b
JM
1636 switch (env->mmu_model) {
1637 case POWERPC_MMU_32B:
faadf50e 1638 case POWERPC_MMU_601:
a750fc0b 1639 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 1640 case POWERPC_MMU_SOFT_74xx:
a750fc0b 1641 case POWERPC_MMU_SOFT_4xx:
b4095fed 1642 case POWERPC_MMU_REAL:
7dbe11ac 1643 case POWERPC_MMU_BOOKE:
caa4039c
JM
1644 ctx->prot |= PAGE_WRITE;
1645 break;
1646#if defined(TARGET_PPC64)
add78955 1647 case POWERPC_MMU_620:
a750fc0b 1648 case POWERPC_MMU_64B:
9d52e907 1649 case POWERPC_MMU_2_06:
caa4039c 1650 /* Real address are 60 bits long */
a750fc0b 1651 ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
caa4039c
JM
1652 ctx->prot |= PAGE_WRITE;
1653 break;
9706285b 1654#endif
a750fc0b 1655 case POWERPC_MMU_SOFT_4xx_Z:
caa4039c
JM
1656 if (unlikely(msr_pe != 0)) {
1657 /* 403 family add some particular protections,
1658 * using PBL/PBU registers for accesses with no translation.
1659 */
1660 in_plb =
1661 /* Check PLB validity */
1662 (env->pb[0] < env->pb[1] &&
1663 /* and address in plb area */
1664 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1665 (env->pb[2] < env->pb[3] &&
1666 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1667 if (in_plb ^ msr_px) {
1668 /* Access in protected area */
1669 if (rw == 1) {
1670 /* Access is not allowed */
1671 ret = -2;
1672 }
1673 } else {
1674 /* Read-write access is allowed */
1675 ctx->prot |= PAGE_WRITE;
76a66253 1676 }
76a66253 1677 }
e1833e1f 1678 break;
b4095fed
JM
1679 case POWERPC_MMU_MPC8xx:
1680 /* XXX: TODO */
1681 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1682 break;
01662f3e
AG
1683 case POWERPC_MMU_BOOKE206:
1684 cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
caa4039c
JM
1685 break;
1686 default:
1687 cpu_abort(env, "Unknown or invalid MMU model\n");
1688 return -1;
76a66253
JM
1689 }
1690
1691 return ret;
1692}
1693
1328c2bf 1694int get_physical_address (CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
faadf50e 1695 int rw, int access_type)
9a64fbe4
FB
1696{
1697 int ret;
0411a972 1698
514fb8c1 1699#if 0
93fcfe39 1700 qemu_log("%s\n", __func__);
d9bce9d9 1701#endif
4b3686fa
FB
1702 if ((access_type == ACCESS_CODE && msr_ir == 0) ||
1703 (access_type != ACCESS_CODE && msr_dr == 0)) {
a586e548
EI
1704 if (env->mmu_model == POWERPC_MMU_BOOKE) {
1705 /* The BookE MMU always performs address translation. The
1706 IS and DS bits only affect the address space. */
1707 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1708 rw, access_type);
01662f3e
AG
1709 } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
1710 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
d1e256fe 1711 access_type);
a586e548
EI
1712 } else {
1713 /* No address translation. */
1714 ret = check_physical(env, ctx, eaddr, rw);
1715 }
9a64fbe4 1716 } else {
c55e9aef 1717 ret = -1;
a750fc0b
JM
1718 switch (env->mmu_model) {
1719 case POWERPC_MMU_32B:
faadf50e 1720 case POWERPC_MMU_601:
a750fc0b 1721 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 1722 case POWERPC_MMU_SOFT_74xx:
94855937
BS
1723 /* Try to find a BAT */
1724 if (env->nb_BATs != 0)
1725 ret = get_bat(env, ctx, eaddr, rw, access_type);
c55e9aef 1726#if defined(TARGET_PPC64)
add78955 1727 case POWERPC_MMU_620:
a750fc0b 1728 case POWERPC_MMU_64B:
9d52e907 1729 case POWERPC_MMU_2_06:
c55e9aef 1730#endif
a8dea12f 1731 if (ret < 0) {
c55e9aef 1732 /* We didn't match any BAT entry or don't have BATs */
a8dea12f
JM
1733 ret = get_segment(env, ctx, eaddr, rw, access_type);
1734 }
1735 break;
a750fc0b
JM
1736 case POWERPC_MMU_SOFT_4xx:
1737 case POWERPC_MMU_SOFT_4xx_Z:
36081602 1738 ret = mmu40x_get_physical_address(env, ctx, eaddr,
a8dea12f
JM
1739 rw, access_type);
1740 break;
a750fc0b 1741 case POWERPC_MMU_BOOKE:
5eb7995e
JM
1742 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1743 rw, access_type);
1744 break;
01662f3e
AG
1745 case POWERPC_MMU_BOOKE206:
1746 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1747 access_type);
1748 break;
b4095fed
JM
1749 case POWERPC_MMU_MPC8xx:
1750 /* XXX: TODO */
1751 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1752 break;
b4095fed
JM
1753 case POWERPC_MMU_REAL:
1754 cpu_abort(env, "PowerPC in real mode do not do any translation\n");
2662a059 1755 return -1;
c55e9aef
JM
1756 default:
1757 cpu_abort(env, "Unknown or invalid MMU model\n");
a8dea12f 1758 return -1;
9a64fbe4
FB
1759 }
1760 }
514fb8c1 1761#if 0
90e189ec
BS
1762 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1763 __func__, eaddr, ret, ctx->raddr);
76a66253 1764#endif
d9bce9d9 1765
9a64fbe4
FB
1766 return ret;
1767}
1768
1328c2bf 1769target_phys_addr_t cpu_get_phys_page_debug (CPUPPCState *env, target_ulong addr)
a6b025d3 1770{
c227f099 1771 mmu_ctx_t ctx;
a6b025d3 1772
faadf50e 1773 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
a6b025d3 1774 return -1;
76a66253
JM
1775
1776 return ctx.raddr & TARGET_PAGE_MASK;
a6b025d3 1777}
9a64fbe4 1778
1328c2bf 1779static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
01662f3e
AG
1780 int rw)
1781{
1782 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1783 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1784 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1785 env->spr[SPR_BOOKE_MAS3] = 0;
1786 env->spr[SPR_BOOKE_MAS6] = 0;
1787 env->spr[SPR_BOOKE_MAS7] = 0;
1788
1789 /* AS */
1790 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1791 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1792 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1793 }
1794
1795 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1796 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1797
1798 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1799 case MAS4_TIDSELD_PID0:
1800 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1801 break;
1802 case MAS4_TIDSELD_PID1:
1803 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1804 break;
1805 case MAS4_TIDSELD_PID2:
1806 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1807 break;
1808 }
1809
1810 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1811
1812 /* next victim logic */
1813 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1814 env->last_way++;
1815 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1816 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1817}
1818
9a64fbe4 1819/* Perform address translation */
1328c2bf 1820int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
97b348e7 1821 int mmu_idx)
9a64fbe4 1822{
c227f099 1823 mmu_ctx_t ctx;
a541f297 1824 int access_type;
9a64fbe4 1825 int ret = 0;
d9bce9d9 1826
b769d8fe
FB
1827 if (rw == 2) {
1828 /* code access */
1829 rw = 0;
1830 access_type = ACCESS_CODE;
1831 } else {
1832 /* data access */
b4cec7b4 1833 access_type = env->access_type;
b769d8fe 1834 }
faadf50e 1835 ret = get_physical_address(env, &ctx, address, rw, access_type);
9a64fbe4 1836 if (ret == 0) {
d4c430a8
PB
1837 tlb_set_page(env, address & TARGET_PAGE_MASK,
1838 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1839 mmu_idx, TARGET_PAGE_SIZE);
1840 ret = 0;
9a64fbe4 1841 } else if (ret < 0) {
d12d51d5 1842 LOG_MMU_STATE(env);
9a64fbe4 1843 if (access_type == ACCESS_CODE) {
9a64fbe4
FB
1844 switch (ret) {
1845 case -1:
76a66253 1846 /* No matches in page tables or TLB */
a750fc0b
JM
1847 switch (env->mmu_model) {
1848 case POWERPC_MMU_SOFT_6xx:
8f793433
JM
1849 env->exception_index = POWERPC_EXCP_IFTLB;
1850 env->error_code = 1 << 18;
76a66253
JM
1851 env->spr[SPR_IMISS] = address;
1852 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
76a66253 1853 goto tlb_miss;
7dbe11ac 1854 case POWERPC_MMU_SOFT_74xx:
8f793433 1855 env->exception_index = POWERPC_EXCP_IFTLB;
7dbe11ac 1856 goto tlb_miss_74xx;
a750fc0b
JM
1857 case POWERPC_MMU_SOFT_4xx:
1858 case POWERPC_MMU_SOFT_4xx_Z:
8f793433
JM
1859 env->exception_index = POWERPC_EXCP_ITLB;
1860 env->error_code = 0;
a8dea12f
JM
1861 env->spr[SPR_40x_DEAR] = address;
1862 env->spr[SPR_40x_ESR] = 0x00000000;
c55e9aef 1863 break;
a750fc0b 1864 case POWERPC_MMU_32B:
faadf50e 1865 case POWERPC_MMU_601:
c55e9aef 1866#if defined(TARGET_PPC64)
add78955 1867 case POWERPC_MMU_620:
a750fc0b 1868 case POWERPC_MMU_64B:
9d52e907 1869 case POWERPC_MMU_2_06:
c55e9aef 1870#endif
8f793433
JM
1871 env->exception_index = POWERPC_EXCP_ISI;
1872 env->error_code = 0x40000000;
1873 break;
01662f3e
AG
1874 case POWERPC_MMU_BOOKE206:
1875 booke206_update_mas_tlb_miss(env, address, rw);
1876 /* fall through */
a750fc0b 1877 case POWERPC_MMU_BOOKE:
a586e548
EI
1878 env->exception_index = POWERPC_EXCP_ITLB;
1879 env->error_code = 0;
1880 env->spr[SPR_BOOKE_DEAR] = address;
c55e9aef 1881 return -1;
b4095fed
JM
1882 case POWERPC_MMU_MPC8xx:
1883 /* XXX: TODO */
1884 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1885 break;
1886 case POWERPC_MMU_REAL:
1887 cpu_abort(env, "PowerPC in real mode should never raise "
1888 "any MMU exceptions\n");
2662a059 1889 return -1;
c55e9aef
JM
1890 default:
1891 cpu_abort(env, "Unknown or invalid MMU model\n");
1892 return -1;
76a66253 1893 }
9a64fbe4
FB
1894 break;
1895 case -2:
1896 /* Access rights violation */
8f793433
JM
1897 env->exception_index = POWERPC_EXCP_ISI;
1898 env->error_code = 0x08000000;
9a64fbe4
FB
1899 break;
1900 case -3:
76a66253 1901 /* No execute protection violation */
01662f3e
AG
1902 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1903 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
a586e548
EI
1904 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1905 }
8f793433
JM
1906 env->exception_index = POWERPC_EXCP_ISI;
1907 env->error_code = 0x10000000;
9a64fbe4
FB
1908 break;
1909 case -4:
1910 /* Direct store exception */
1911 /* No code fetch is allowed in direct-store areas */
8f793433
JM
1912 env->exception_index = POWERPC_EXCP_ISI;
1913 env->error_code = 0x10000000;
2be0071f 1914 break;
e1833e1f 1915#if defined(TARGET_PPC64)
2be0071f
FB
1916 case -5:
1917 /* No match in segment table */
add78955
JM
1918 if (env->mmu_model == POWERPC_MMU_620) {
1919 env->exception_index = POWERPC_EXCP_ISI;
1920 /* XXX: this might be incorrect */
1921 env->error_code = 0x40000000;
1922 } else {
1923 env->exception_index = POWERPC_EXCP_ISEG;
1924 env->error_code = 0;
1925 }
9a64fbe4 1926 break;
e1833e1f 1927#endif
9a64fbe4
FB
1928 }
1929 } else {
9a64fbe4
FB
1930 switch (ret) {
1931 case -1:
76a66253 1932 /* No matches in page tables or TLB */
a750fc0b
JM
1933 switch (env->mmu_model) {
1934 case POWERPC_MMU_SOFT_6xx:
76a66253 1935 if (rw == 1) {
8f793433
JM
1936 env->exception_index = POWERPC_EXCP_DSTLB;
1937 env->error_code = 1 << 16;
76a66253 1938 } else {
8f793433
JM
1939 env->exception_index = POWERPC_EXCP_DLTLB;
1940 env->error_code = 0;
76a66253
JM
1941 }
1942 env->spr[SPR_DMISS] = address;
1943 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1944 tlb_miss:
8f793433 1945 env->error_code |= ctx.key << 19;
fda6a0ec
DG
1946 env->spr[SPR_HASH1] = env->htab_base +
1947 get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
1948 env->spr[SPR_HASH2] = env->htab_base +
1949 get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
8f793433 1950 break;
7dbe11ac
JM
1951 case POWERPC_MMU_SOFT_74xx:
1952 if (rw == 1) {
8f793433 1953 env->exception_index = POWERPC_EXCP_DSTLB;
7dbe11ac 1954 } else {
8f793433 1955 env->exception_index = POWERPC_EXCP_DLTLB;
7dbe11ac
JM
1956 }
1957 tlb_miss_74xx:
1958 /* Implement LRU algorithm */
8f793433 1959 env->error_code = ctx.key << 19;
7dbe11ac
JM
1960 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1961 ((env->last_way + 1) & (env->nb_ways - 1));
1962 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
7dbe11ac 1963 break;
a750fc0b
JM
1964 case POWERPC_MMU_SOFT_4xx:
1965 case POWERPC_MMU_SOFT_4xx_Z:
8f793433
JM
1966 env->exception_index = POWERPC_EXCP_DTLB;
1967 env->error_code = 0;
a8dea12f
JM
1968 env->spr[SPR_40x_DEAR] = address;
1969 if (rw)
1970 env->spr[SPR_40x_ESR] = 0x00800000;
1971 else
1972 env->spr[SPR_40x_ESR] = 0x00000000;
c55e9aef 1973 break;
a750fc0b 1974 case POWERPC_MMU_32B:
faadf50e 1975 case POWERPC_MMU_601:
c55e9aef 1976#if defined(TARGET_PPC64)
add78955 1977 case POWERPC_MMU_620:
a750fc0b 1978 case POWERPC_MMU_64B:
9d52e907 1979 case POWERPC_MMU_2_06:
c55e9aef 1980#endif
8f793433
JM
1981 env->exception_index = POWERPC_EXCP_DSI;
1982 env->error_code = 0;
1983 env->spr[SPR_DAR] = address;
1984 if (rw == 1)
1985 env->spr[SPR_DSISR] = 0x42000000;
1986 else
1987 env->spr[SPR_DSISR] = 0x40000000;
1988 break;
b4095fed
JM
1989 case POWERPC_MMU_MPC8xx:
1990 /* XXX: TODO */
1991 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1992 break;
01662f3e
AG
1993 case POWERPC_MMU_BOOKE206:
1994 booke206_update_mas_tlb_miss(env, address, rw);
1995 /* fall through */
a750fc0b 1996 case POWERPC_MMU_BOOKE:
a586e548
EI
1997 env->exception_index = POWERPC_EXCP_DTLB;
1998 env->error_code = 0;
1999 env->spr[SPR_BOOKE_DEAR] = address;
542df9bf 2000 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
c55e9aef 2001 return -1;
b4095fed
JM
2002 case POWERPC_MMU_REAL:
2003 cpu_abort(env, "PowerPC in real mode should never raise "
2004 "any MMU exceptions\n");
2662a059 2005 return -1;
c55e9aef
JM
2006 default:
2007 cpu_abort(env, "Unknown or invalid MMU model\n");
2008 return -1;
76a66253 2009 }
9a64fbe4
FB
2010 break;
2011 case -2:
2012 /* Access rights violation */
8f793433
JM
2013 env->exception_index = POWERPC_EXCP_DSI;
2014 env->error_code = 0;
dcbc9a70
EI
2015 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
2016 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
2017 env->spr[SPR_40x_DEAR] = address;
2018 if (rw) {
2019 env->spr[SPR_40x_ESR] |= 0x00800000;
2020 }
01662f3e
AG
2021 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
2022 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
a586e548 2023 env->spr[SPR_BOOKE_DEAR] = address;
542df9bf 2024 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
dcbc9a70
EI
2025 } else {
2026 env->spr[SPR_DAR] = address;
2027 if (rw == 1) {
2028 env->spr[SPR_DSISR] = 0x0A000000;
2029 } else {
2030 env->spr[SPR_DSISR] = 0x08000000;
2031 }
2032 }
9a64fbe4
FB
2033 break;
2034 case -4:
2035 /* Direct store exception */
2036 switch (access_type) {
2037 case ACCESS_FLOAT:
2038 /* Floating point load/store */
8f793433
JM
2039 env->exception_index = POWERPC_EXCP_ALIGN;
2040 env->error_code = POWERPC_EXCP_ALIGN_FP;
2041 env->spr[SPR_DAR] = address;
9a64fbe4
FB
2042 break;
2043 case ACCESS_RES:
8f793433
JM
2044 /* lwarx, ldarx or stwcx. */
2045 env->exception_index = POWERPC_EXCP_DSI;
2046 env->error_code = 0;
2047 env->spr[SPR_DAR] = address;
2048 if (rw == 1)
2049 env->spr[SPR_DSISR] = 0x06000000;
2050 else
2051 env->spr[SPR_DSISR] = 0x04000000;
9a64fbe4
FB
2052 break;
2053 case ACCESS_EXT:
2054 /* eciwx or ecowx */
8f793433
JM
2055 env->exception_index = POWERPC_EXCP_DSI;
2056 env->error_code = 0;
2057 env->spr[SPR_DAR] = address;
2058 if (rw == 1)
2059 env->spr[SPR_DSISR] = 0x06100000;
2060 else
2061 env->spr[SPR_DSISR] = 0x04100000;
9a64fbe4
FB
2062 break;
2063 default:
76a66253 2064 printf("DSI: invalid exception (%d)\n", ret);
8f793433
JM
2065 env->exception_index = POWERPC_EXCP_PROGRAM;
2066 env->error_code =
2067 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
2068 env->spr[SPR_DAR] = address;
9a64fbe4
FB
2069 break;
2070 }
fdabc366 2071 break;
e1833e1f 2072#if defined(TARGET_PPC64)
2be0071f
FB
2073 case -5:
2074 /* No match in segment table */
add78955
JM
2075 if (env->mmu_model == POWERPC_MMU_620) {
2076 env->exception_index = POWERPC_EXCP_DSI;
2077 env->error_code = 0;
2078 env->spr[SPR_DAR] = address;
2079 /* XXX: this might be incorrect */
2080 if (rw == 1)
2081 env->spr[SPR_DSISR] = 0x42000000;
2082 else
2083 env->spr[SPR_DSISR] = 0x40000000;
2084 } else {
2085 env->exception_index = POWERPC_EXCP_DSEG;
2086 env->error_code = 0;
2087 env->spr[SPR_DAR] = address;
2088 }
2be0071f 2089 break;
e1833e1f 2090#endif
9a64fbe4 2091 }
9a64fbe4
FB
2092 }
2093#if 0
8f793433
JM
2094 printf("%s: set exception to %d %02x\n", __func__,
2095 env->exception, env->error_code);
9a64fbe4 2096#endif
9a64fbe4
FB
2097 ret = 1;
2098 }
76a66253 2099
9a64fbe4
FB
2100 return ret;
2101}
2102
3fc6c082
FB
2103/*****************************************************************************/
2104/* BATs management */
2105#if !defined(FLUSH_ALL_TLBS)
636aa200
BS
2106static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
2107 target_ulong mask)
3fc6c082
FB
2108{
2109 target_ulong base, end, page;
76a66253 2110
3fc6c082
FB
2111 base = BATu & ~0x0001FFFF;
2112 end = base + mask + 0x00020000;
90e189ec
BS
2113 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
2114 TARGET_FMT_lx ")\n", base, end, mask);
3fc6c082
FB
2115 for (page = base; page != end; page += TARGET_PAGE_SIZE)
2116 tlb_flush_page(env, page);
d12d51d5 2117 LOG_BATS("Flush done\n");
3fc6c082
FB
2118}
2119#endif
2120
636aa200
BS
2121static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
2122 target_ulong value)
3fc6c082 2123{
90e189ec
BS
2124 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
2125 nr, ul == 0 ? 'u' : 'l', value, env->nip);
3fc6c082
FB
2126}
2127
45d827d2 2128void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
2129{
2130 target_ulong mask;
2131
2132 dump_store_bat(env, 'I', 0, nr, value);
2133 if (env->IBAT[0][nr] != value) {
2134 mask = (value << 15) & 0x0FFE0000UL;
2135#if !defined(FLUSH_ALL_TLBS)
2136 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2137#endif
2138 /* When storing valid upper BAT, mask BEPI and BRPN
2139 * and invalidate all TLBs covered by this BAT
2140 */
2141 mask = (value << 15) & 0x0FFE0000UL;
2142 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
2143 (value & ~0x0001FFFFUL & ~mask);
2144 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
2145 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
2146#if !defined(FLUSH_ALL_TLBS)
2147 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
76a66253 2148#else
3fc6c082
FB
2149 tlb_flush(env, 1);
2150#endif
2151 }
2152}
2153
45d827d2 2154void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
2155{
2156 dump_store_bat(env, 'I', 1, nr, value);
2157 env->IBAT[1][nr] = value;
2158}
2159
45d827d2 2160void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
2161{
2162 target_ulong mask;
2163
2164 dump_store_bat(env, 'D', 0, nr, value);
2165 if (env->DBAT[0][nr] != value) {
2166 /* When storing valid upper BAT, mask BEPI and BRPN
2167 * and invalidate all TLBs covered by this BAT
2168 */
2169 mask = (value << 15) & 0x0FFE0000UL;
2170#if !defined(FLUSH_ALL_TLBS)
2171 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
2172#endif
2173 mask = (value << 15) & 0x0FFE0000UL;
2174 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
2175 (value & ~0x0001FFFFUL & ~mask);
2176 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
2177 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
2178#if !defined(FLUSH_ALL_TLBS)
2179 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
2180#else
2181 tlb_flush(env, 1);
2182#endif
2183 }
2184}
2185
45d827d2 2186void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
2187{
2188 dump_store_bat(env, 'D', 1, nr, value);
2189 env->DBAT[1][nr] = value;
2190}
2191
45d827d2 2192void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
056401ea
JM
2193{
2194 target_ulong mask;
05f92404 2195#if defined(FLUSH_ALL_TLBS)
056401ea 2196 int do_inval;
05f92404 2197#endif
056401ea
JM
2198
2199 dump_store_bat(env, 'I', 0, nr, value);
2200 if (env->IBAT[0][nr] != value) {
05f92404 2201#if defined(FLUSH_ALL_TLBS)
056401ea 2202 do_inval = 0;
05f92404 2203#endif
056401ea
JM
2204 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
2205 if (env->IBAT[1][nr] & 0x40) {
2206 /* Invalidate BAT only if it is valid */
2207#if !defined(FLUSH_ALL_TLBS)
2208 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2209#else
2210 do_inval = 1;
2211#endif
2212 }
2213 /* When storing valid upper BAT, mask BEPI and BRPN
2214 * and invalidate all TLBs covered by this BAT
2215 */
2216 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
2217 (value & ~0x0001FFFFUL & ~mask);
2218 env->DBAT[0][nr] = env->IBAT[0][nr];
2219 if (env->IBAT[1][nr] & 0x40) {
2220#if !defined(FLUSH_ALL_TLBS)
2221 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2222#else
2223 do_inval = 1;
2224#endif
2225 }
2226#if defined(FLUSH_ALL_TLBS)
2227 if (do_inval)
2228 tlb_flush(env, 1);
2229#endif
2230 }
2231}
2232
45d827d2 2233void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
056401ea
JM
2234{
2235 target_ulong mask;
05f92404 2236#if defined(FLUSH_ALL_TLBS)
056401ea 2237 int do_inval;
05f92404 2238#endif
056401ea
JM
2239
2240 dump_store_bat(env, 'I', 1, nr, value);
2241 if (env->IBAT[1][nr] != value) {
05f92404 2242#if defined(FLUSH_ALL_TLBS)
056401ea 2243 do_inval = 0;
05f92404 2244#endif
056401ea
JM
2245 if (env->IBAT[1][nr] & 0x40) {
2246#if !defined(FLUSH_ALL_TLBS)
2247 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
2248 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2249#else
2250 do_inval = 1;
2251#endif
2252 }
2253 if (value & 0x40) {
2254#if !defined(FLUSH_ALL_TLBS)
2255 mask = (value << 17) & 0x0FFE0000UL;
2256 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2257#else
2258 do_inval = 1;
2259#endif
2260 }
2261 env->IBAT[1][nr] = value;
2262 env->DBAT[1][nr] = value;
2263#if defined(FLUSH_ALL_TLBS)
2264 if (do_inval)
2265 tlb_flush(env, 1);
2266#endif
2267 }
2268}
2269
0a032cbe
JM
2270/*****************************************************************************/
2271/* TLB management */
2272void ppc_tlb_invalidate_all (CPUPPCState *env)
2273{
daf4f96e
JM
2274 switch (env->mmu_model) {
2275 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 2276 case POWERPC_MMU_SOFT_74xx:
0a032cbe 2277 ppc6xx_tlb_invalidate_all(env);
daf4f96e
JM
2278 break;
2279 case POWERPC_MMU_SOFT_4xx:
2280 case POWERPC_MMU_SOFT_4xx_Z:
0a032cbe 2281 ppc4xx_tlb_invalidate_all(env);
daf4f96e 2282 break;
b4095fed 2283 case POWERPC_MMU_REAL:
7dbe11ac
JM
2284 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
2285 break;
b4095fed
JM
2286 case POWERPC_MMU_MPC8xx:
2287 /* XXX: TODO */
2288 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2289 break;
7dbe11ac 2290 case POWERPC_MMU_BOOKE:
a586e548 2291 tlb_flush(env, 1);
7dbe11ac 2292 break;
01662f3e
AG
2293 case POWERPC_MMU_BOOKE206:
2294 booke206_flush_tlb(env, -1, 0);
7dbe11ac 2295 break;
7dbe11ac 2296 case POWERPC_MMU_32B:
faadf50e 2297 case POWERPC_MMU_601:
00af685f 2298#if defined(TARGET_PPC64)
add78955 2299 case POWERPC_MMU_620:
7dbe11ac 2300 case POWERPC_MMU_64B:
9d52e907 2301 case POWERPC_MMU_2_06:
00af685f 2302#endif /* defined(TARGET_PPC64) */
0a032cbe 2303 tlb_flush(env, 1);
daf4f96e 2304 break;
00af685f
JM
2305 default:
2306 /* XXX: TODO */
12de9a39 2307 cpu_abort(env, "Unknown MMU model\n");
00af685f 2308 break;
0a032cbe
JM
2309 }
2310}
2311
daf4f96e
JM
2312void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
2313{
2314#if !defined(FLUSH_ALL_TLBS)
2315 addr &= TARGET_PAGE_MASK;
2316 switch (env->mmu_model) {
2317 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 2318 case POWERPC_MMU_SOFT_74xx:
daf4f96e
JM
2319 ppc6xx_tlb_invalidate_virt(env, addr, 0);
2320 if (env->id_tlbs == 1)
2321 ppc6xx_tlb_invalidate_virt(env, addr, 1);
2322 break;
2323 case POWERPC_MMU_SOFT_4xx:
2324 case POWERPC_MMU_SOFT_4xx_Z:
2325 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
2326 break;
b4095fed 2327 case POWERPC_MMU_REAL:
7dbe11ac
JM
2328 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
2329 break;
b4095fed
JM
2330 case POWERPC_MMU_MPC8xx:
2331 /* XXX: TODO */
2332 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2333 break;
7dbe11ac
JM
2334 case POWERPC_MMU_BOOKE:
2335 /* XXX: TODO */
b4095fed 2336 cpu_abort(env, "BookE MMU model is not implemented\n");
7dbe11ac 2337 break;
01662f3e 2338 case POWERPC_MMU_BOOKE206:
7dbe11ac 2339 /* XXX: TODO */
01662f3e 2340 cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
7dbe11ac
JM
2341 break;
2342 case POWERPC_MMU_32B:
faadf50e 2343 case POWERPC_MMU_601:
daf4f96e 2344 /* tlbie invalidate TLBs for all segments */
6f2d8978 2345 addr &= ~((target_ulong)-1ULL << 28);
daf4f96e
JM
2346 /* XXX: this case should be optimized,
2347 * giving a mask to tlb_flush_page
2348 */
2349 tlb_flush_page(env, addr | (0x0 << 28));
2350 tlb_flush_page(env, addr | (0x1 << 28));
2351 tlb_flush_page(env, addr | (0x2 << 28));
2352 tlb_flush_page(env, addr | (0x3 << 28));
2353 tlb_flush_page(env, addr | (0x4 << 28));
2354 tlb_flush_page(env, addr | (0x5 << 28));
2355 tlb_flush_page(env, addr | (0x6 << 28));
2356 tlb_flush_page(env, addr | (0x7 << 28));
2357 tlb_flush_page(env, addr | (0x8 << 28));
2358 tlb_flush_page(env, addr | (0x9 << 28));
2359 tlb_flush_page(env, addr | (0xA << 28));
2360 tlb_flush_page(env, addr | (0xB << 28));
2361 tlb_flush_page(env, addr | (0xC << 28));
2362 tlb_flush_page(env, addr | (0xD << 28));
2363 tlb_flush_page(env, addr | (0xE << 28));
2364 tlb_flush_page(env, addr | (0xF << 28));
7dbe11ac 2365 break;
00af685f 2366#if defined(TARGET_PPC64)
add78955 2367 case POWERPC_MMU_620:
7dbe11ac 2368 case POWERPC_MMU_64B:
9d52e907 2369 case POWERPC_MMU_2_06:
7dbe11ac
JM
2370 /* tlbie invalidate TLBs for all segments */
2371 /* XXX: given the fact that there are too many segments to invalidate,
5cbdb3a3 2372 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
7dbe11ac
JM
2373 * we just invalidate all TLBs
2374 */
2375 tlb_flush(env, 1);
2376 break;
00af685f
JM
2377#endif /* defined(TARGET_PPC64) */
2378 default:
2379 /* XXX: TODO */
12de9a39 2380 cpu_abort(env, "Unknown MMU model\n");
00af685f 2381 break;
daf4f96e
JM
2382 }
2383#else
2384 ppc_tlb_invalidate_all(env);
2385#endif
2386}
2387
3fc6c082
FB
2388/*****************************************************************************/
2389/* Special registers manipulation */
d9bce9d9 2390#if defined(TARGET_PPC64)
d9bce9d9
JM
2391void ppc_store_asr (CPUPPCState *env, target_ulong value)
2392{
2393 if (env->asr != value) {
2394 env->asr = value;
2395 tlb_flush(env, 1);
2396 }
2397}
2398#endif
2399
45d827d2 2400void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
3fc6c082 2401{
90e189ec 2402 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
bb593904
DG
2403 if (env->spr[SPR_SDR1] != value) {
2404 env->spr[SPR_SDR1] = value;
2405#if defined(TARGET_PPC64)
2406 if (env->mmu_model & POWERPC_MMU_64) {
2407 target_ulong htabsize = value & SDR_64_HTABSIZE;
2408
2409 if (htabsize > 28) {
2410 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2411 " stored in SDR1\n", htabsize);
2412 htabsize = 28;
2413 }
2414 env->htab_mask = (1ULL << (htabsize + 18)) - 1;
2415 env->htab_base = value & SDR_64_HTABORG;
2416 } else
2417#endif /* defined(TARGET_PPC64) */
2418 {
2419 /* FIXME: Should check for valid HTABMASK values */
2420 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2421 env->htab_base = value & SDR_32_HTABORG;
2422 }
76a66253 2423 tlb_flush(env, 1);
3fc6c082
FB
2424 }
2425}
2426
f6b868fc
BS
2427#if defined(TARGET_PPC64)
2428target_ulong ppc_load_sr (CPUPPCState *env, int slb_nr)
2429{
2430 // XXX
2431 return 0;
2432}
2433#endif
2434
45d827d2 2435void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
3fc6c082 2436{
90e189ec
BS
2437 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2438 srnum, value, env->sr[srnum]);
f6b868fc
BS
2439#if defined(TARGET_PPC64)
2440 if (env->mmu_model & POWERPC_MMU_64) {
2441 uint64_t rb = 0, rs = 0;
2442
2443 /* ESID = srnum */
2444 rb |= ((uint32_t)srnum & 0xf) << 28;
2445 /* Set the valid bit */
2446 rb |= 1 << 27;
2447 /* Index = ESID */
2448 rb |= (uint32_t)srnum;
2449
2450 /* VSID = VSID */
2451 rs |= (value & 0xfffffff) << 12;
2452 /* flags = flags */
decb4714 2453 rs |= ((value >> 27) & 0xf) << 8;
f6b868fc
BS
2454
2455 ppc_store_slb(env, rb, rs);
2456 } else
2457#endif
3fc6c082
FB
2458 if (env->sr[srnum] != value) {
2459 env->sr[srnum] = value;
bf1752ef
AJ
2460/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2461 flusing the whole TLB. */
3fc6c082
FB
2462#if !defined(FLUSH_ALL_TLBS) && 0
2463 {
2464 target_ulong page, end;
2465 /* Invalidate 256 MB of virtual memory */
2466 page = (16 << 20) * srnum;
2467 end = page + (16 << 20);
2468 for (; page != end; page += TARGET_PAGE_SIZE)
2469 tlb_flush_page(env, page);
2470 }
2471#else
76a66253 2472 tlb_flush(env, 1);
3fc6c082
FB
2473#endif
2474 }
2475}
76a66253 2476#endif /* !defined (CONFIG_USER_ONLY) */
3fc6c082 2477
76a66253 2478/* GDBstub can read and write MSR... */
0411a972 2479void ppc_store_msr (CPUPPCState *env, target_ulong value)
3fc6c082 2480{
a4f30719 2481 hreg_store_msr(env, value, 0);
3fc6c082
FB
2482}
2483
2484/*****************************************************************************/
2485/* Exception processing */
18fba28c 2486#if defined (CONFIG_USER_ONLY)
1328c2bf 2487void do_interrupt (CPUPPCState *env)
79aceca5 2488{
e1833e1f
JM
2489 env->exception_index = POWERPC_EXCP_NONE;
2490 env->error_code = 0;
18fba28c 2491}
47103572 2492
1328c2bf 2493void ppc_hw_interrupt (CPUPPCState *env)
47103572 2494{
e1833e1f
JM
2495 env->exception_index = POWERPC_EXCP_NONE;
2496 env->error_code = 0;
47103572 2497}
76a66253 2498#else /* defined (CONFIG_USER_ONLY) */
1328c2bf 2499static inline void dump_syscall(CPUPPCState *env)
d094807b 2500{
b11ebf64
BS
2501 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
2502 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
2503 " nip=" TARGET_FMT_lx "\n",
90e189ec
BS
2504 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
2505 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
2506 ppc_dump_gpr(env, 6), env->nip);
d094807b
FB
2507}
2508
e1833e1f
JM
2509/* Note that this function should be greatly optimized
2510 * when called with a constant excp, from ppc_hw_interrupt
2511 */
1328c2bf 2512static inline void powerpc_excp(CPUPPCState *env, int excp_model, int excp)
18fba28c 2513{
0411a972 2514 target_ulong msr, new_msr, vector;
e1833e1f 2515 int srr0, srr1, asrr0, asrr1;
a4f30719 2516 int lpes0, lpes1, lev;
79aceca5 2517
b172c56a
JM
2518 if (0) {
2519 /* XXX: find a suitable condition to enable the hypervisor mode */
2520 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
2521 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
2522 } else {
2523 /* Those values ensure we won't enter the hypervisor mode */
2524 lpes0 = 0;
2525 lpes1 = 1;
2526 }
2527
90e189ec
BS
2528 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
2529 " => %08x (%02x)\n", env->nip, excp, env->error_code);
41557447
AG
2530
2531 /* new srr1 value excluding must-be-zero bits */
2532 msr = env->msr & ~0x783f0000ULL;
2533
2534 /* new interrupt handler msr */
2535 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
2536
2537 /* target registers */
e1833e1f
JM
2538 srr0 = SPR_SRR0;
2539 srr1 = SPR_SRR1;
2540 asrr0 = -1;
2541 asrr1 = -1;
41557447 2542
9a64fbe4 2543 switch (excp) {
e1833e1f
JM
2544 case POWERPC_EXCP_NONE:
2545 /* Should never happen */
2546 return;
2547 case POWERPC_EXCP_CRITICAL: /* Critical input */
e1833e1f 2548 switch (excp_model) {
a750fc0b 2549 case POWERPC_EXCP_40x:
e1833e1f
JM
2550 srr0 = SPR_40x_SRR2;
2551 srr1 = SPR_40x_SRR3;
c62db105 2552 break;
a750fc0b 2553 case POWERPC_EXCP_BOOKE:
e1833e1f
JM
2554 srr0 = SPR_BOOKE_CSRR0;
2555 srr1 = SPR_BOOKE_CSRR1;
c62db105 2556 break;
e1833e1f 2557 case POWERPC_EXCP_G2:
c62db105 2558 break;
e1833e1f
JM
2559 default:
2560 goto excp_invalid;
2be0071f 2561 }
9a64fbe4 2562 goto store_next;
e1833e1f
JM
2563 case POWERPC_EXCP_MCHECK: /* Machine check exception */
2564 if (msr_me == 0) {
e63ecc6f
JM
2565 /* Machine check exception is not enabled.
2566 * Enter checkstop state.
2567 */
93fcfe39
AL
2568 if (qemu_log_enabled()) {
2569 qemu_log("Machine check while not allowed. "
e63ecc6f
JM
2570 "Entering checkstop state\n");
2571 } else {
2572 fprintf(stderr, "Machine check while not allowed. "
2573 "Entering checkstop state\n");
2574 }
2575 env->halted = 1;
2576 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
e1833e1f 2577 }
b172c56a
JM
2578 if (0) {
2579 /* XXX: find a suitable condition to enable the hypervisor mode */
a4f30719 2580 new_msr |= (target_ulong)MSR_HVB;
b172c56a 2581 }
41557447
AG
2582
2583 /* machine check exceptions don't have ME set */
2584 new_msr &= ~((target_ulong)1 << MSR_ME);
2585
e1833e1f
JM
2586 /* XXX: should also have something loaded in DAR / DSISR */
2587 switch (excp_model) {
a750fc0b 2588 case POWERPC_EXCP_40x:
e1833e1f
JM
2589 srr0 = SPR_40x_SRR2;
2590 srr1 = SPR_40x_SRR3;
c62db105 2591 break;
a750fc0b 2592 case POWERPC_EXCP_BOOKE:
e1833e1f
JM
2593 srr0 = SPR_BOOKE_MCSRR0;
2594 srr1 = SPR_BOOKE_MCSRR1;
2595 asrr0 = SPR_BOOKE_CSRR0;
2596 asrr1 = SPR_BOOKE_CSRR1;
c62db105
JM
2597 break;
2598 default:
2599 break;
2be0071f 2600 }
e1833e1f
JM
2601 goto store_next;
2602 case POWERPC_EXCP_DSI: /* Data storage exception */
90e189ec
BS
2603 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
2604 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
e1833e1f 2605 if (lpes1 == 0)
a4f30719 2606 new_msr |= (target_ulong)MSR_HVB;
a541f297 2607 goto store_next;
e1833e1f 2608 case POWERPC_EXCP_ISI: /* Instruction storage exception */
90e189ec
BS
2609 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
2610 "\n", msr, env->nip);
e1833e1f 2611 if (lpes1 == 0)
a4f30719 2612 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2613 msr |= env->error_code;
9a64fbe4 2614 goto store_next;
e1833e1f 2615 case POWERPC_EXCP_EXTERNAL: /* External input */
e1833e1f 2616 if (lpes0 == 1)
a4f30719 2617 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2618 goto store_next;
e1833e1f 2619 case POWERPC_EXCP_ALIGN: /* Alignment exception */
e1833e1f 2620 if (lpes1 == 0)
a4f30719 2621 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2622 /* XXX: this is false */
2623 /* Get rS/rD and rA from faulting opcode */
2624 env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
9a64fbe4 2625 goto store_current;
e1833e1f 2626 case POWERPC_EXCP_PROGRAM: /* Program exception */
9a64fbe4 2627 switch (env->error_code & ~0xF) {
e1833e1f
JM
2628 case POWERPC_EXCP_FP:
2629 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
d12d51d5 2630 LOG_EXCP("Ignore floating point exception\n");
7c58044c
JM
2631 env->exception_index = POWERPC_EXCP_NONE;
2632 env->error_code = 0;
9a64fbe4 2633 return;
76a66253 2634 }
e1833e1f 2635 if (lpes1 == 0)
a4f30719 2636 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2637 msr |= 0x00100000;
5b52b991
JM
2638 if (msr_fe0 == msr_fe1)
2639 goto store_next;
2640 msr |= 0x00010000;
76a66253 2641 break;
e1833e1f 2642 case POWERPC_EXCP_INVAL:
90e189ec 2643 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
e1833e1f 2644 if (lpes1 == 0)
a4f30719 2645 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2646 msr |= 0x00080000;
e8906f35 2647 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
76a66253 2648 break;
e1833e1f 2649 case POWERPC_EXCP_PRIV:
e1833e1f 2650 if (lpes1 == 0)
a4f30719 2651 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2652 msr |= 0x00040000;
e8906f35 2653 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
76a66253 2654 break;
e1833e1f 2655 case POWERPC_EXCP_TRAP:
e1833e1f 2656 if (lpes1 == 0)
a4f30719 2657 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2658 msr |= 0x00020000;
e8906f35 2659 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
9a64fbe4
FB
2660 break;
2661 default:
2662 /* Should never occur */
e1833e1f
JM
2663 cpu_abort(env, "Invalid program exception %d. Aborting\n",
2664 env->error_code);
76a66253
JM
2665 break;
2666 }
5b52b991 2667 goto store_current;
e1833e1f 2668 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
e1833e1f 2669 if (lpes1 == 0)
a4f30719 2670 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2671 goto store_current;
2672 case POWERPC_EXCP_SYSCALL: /* System call exception */
93fcfe39 2673 dump_syscall(env);
f9fdea6b 2674 lev = env->error_code;
d569956e
DG
2675 if ((lev == 1) && cpu_ppc_hypercall) {
2676 cpu_ppc_hypercall(env);
2677 return;
2678 }
e1833e1f 2679 if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
a4f30719 2680 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2681 goto store_next;
2682 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
e1833e1f
JM
2683 goto store_current;
2684 case POWERPC_EXCP_DECR: /* Decrementer exception */
e1833e1f 2685 if (lpes1 == 0)
a4f30719 2686 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2687 goto store_next;
2688 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
2689 /* FIT on 4xx */
d12d51d5 2690 LOG_EXCP("FIT exception\n");
9a64fbe4 2691 goto store_next;
e1833e1f 2692 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
d12d51d5 2693 LOG_EXCP("WDT exception\n");
e1833e1f
JM
2694 switch (excp_model) {
2695 case POWERPC_EXCP_BOOKE:
2696 srr0 = SPR_BOOKE_CSRR0;
2697 srr1 = SPR_BOOKE_CSRR1;
2698 break;
2699 default:
2700 break;
2701 }
2be0071f 2702 goto store_next;
e1833e1f 2703 case POWERPC_EXCP_DTLB: /* Data TLB error */
e1833e1f
JM
2704 goto store_next;
2705 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
e1833e1f
JM
2706 goto store_next;
2707 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
2708 switch (excp_model) {
2709 case POWERPC_EXCP_BOOKE:
2710 srr0 = SPR_BOOKE_DSRR0;
2711 srr1 = SPR_BOOKE_DSRR1;
2712 asrr0 = SPR_BOOKE_CSRR0;
2713 asrr1 = SPR_BOOKE_CSRR1;
2714 break;
2715 default:
2716 break;
2717 }
2be0071f 2718 /* XXX: TODO */
e1833e1f 2719 cpu_abort(env, "Debug exception is not implemented yet !\n");
2be0071f 2720 goto store_next;
e1833e1f 2721 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
e8906f35 2722 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
e1833e1f
JM
2723 goto store_current;
2724 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
2be0071f 2725 /* XXX: TODO */
e1833e1f 2726 cpu_abort(env, "Embedded floating point data exception "
2be0071f 2727 "is not implemented yet !\n");
e8906f35 2728 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
2be0071f 2729 goto store_next;
e1833e1f 2730 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
2be0071f 2731 /* XXX: TODO */
e1833e1f
JM
2732 cpu_abort(env, "Embedded floating point round exception "
2733 "is not implemented yet !\n");
e8906f35 2734 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
9a64fbe4 2735 goto store_next;
e1833e1f 2736 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
2be0071f
FB
2737 /* XXX: TODO */
2738 cpu_abort(env,
e1833e1f 2739 "Performance counter exception is not implemented yet !\n");
9a64fbe4 2740 goto store_next;
e1833e1f 2741 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
2be0071f 2742 goto store_next;
e1833e1f 2743 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
a9abd717
AG
2744 srr0 = SPR_BOOKE_CSRR0;
2745 srr1 = SPR_BOOKE_CSRR1;
e1833e1f 2746 goto store_next;
e1833e1f 2747 case POWERPC_EXCP_RESET: /* System reset exception */
41557447
AG
2748 if (msr_pow) {
2749 /* indicate that we resumed from power save mode */
2750 msr |= 0x10000;
2751 } else {
2752 new_msr &= ~((target_ulong)1 << MSR_ME);
2753 }
2754
a4f30719
JM
2755 if (0) {
2756 /* XXX: find a suitable condition to enable the hypervisor mode */
2757 new_msr |= (target_ulong)MSR_HVB;
2758 }
e1833e1f 2759 goto store_next;
e1833e1f 2760 case POWERPC_EXCP_DSEG: /* Data segment exception */
e1833e1f 2761 if (lpes1 == 0)
a4f30719 2762 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2763 goto store_next;
2764 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
e1833e1f 2765 if (lpes1 == 0)
a4f30719 2766 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2767 goto store_next;
e1833e1f
JM
2768 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
2769 srr0 = SPR_HSRR0;
f9fdea6b 2770 srr1 = SPR_HSRR1;
a4f30719 2771 new_msr |= (target_ulong)MSR_HVB;
41557447 2772 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
b172c56a 2773 goto store_next;
e1833e1f 2774 case POWERPC_EXCP_TRACE: /* Trace exception */
e1833e1f 2775 if (lpes1 == 0)
a4f30719 2776 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2777 goto store_next;
e1833e1f
JM
2778 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
2779 srr0 = SPR_HSRR0;
f9fdea6b 2780 srr1 = SPR_HSRR1;
a4f30719 2781 new_msr |= (target_ulong)MSR_HVB;
41557447 2782 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2783 goto store_next;
2784 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
2785 srr0 = SPR_HSRR0;
f9fdea6b 2786 srr1 = SPR_HSRR1;
a4f30719 2787 new_msr |= (target_ulong)MSR_HVB;
41557447 2788 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2789 goto store_next;
2790 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
2791 srr0 = SPR_HSRR0;
f9fdea6b 2792 srr1 = SPR_HSRR1;
a4f30719 2793 new_msr |= (target_ulong)MSR_HVB;
41557447 2794 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2795 goto store_next;
2796 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
2797 srr0 = SPR_HSRR0;
f9fdea6b 2798 srr1 = SPR_HSRR1;
a4f30719 2799 new_msr |= (target_ulong)MSR_HVB;
41557447 2800 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f 2801 goto store_next;
e1833e1f 2802 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
e1833e1f 2803 if (lpes1 == 0)
a4f30719 2804 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2805 goto store_current;
2806 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
d12d51d5 2807 LOG_EXCP("PIT exception\n");
e1833e1f
JM
2808 goto store_next;
2809 case POWERPC_EXCP_IO: /* IO error exception */
2810 /* XXX: TODO */
2811 cpu_abort(env, "601 IO error exception is not implemented yet !\n");
2812 goto store_next;
2813 case POWERPC_EXCP_RUNM: /* Run mode exception */
2814 /* XXX: TODO */
2815 cpu_abort(env, "601 run mode exception is not implemented yet !\n");
2816 goto store_next;
2817 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
2818 /* XXX: TODO */
2819 cpu_abort(env, "602 emulation trap exception "
2820 "is not implemented yet !\n");
2821 goto store_next;
2822 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
a4f30719
JM
2823 if (lpes1 == 0) /* XXX: check this */
2824 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2825 switch (excp_model) {
a750fc0b
JM
2826 case POWERPC_EXCP_602:
2827 case POWERPC_EXCP_603:
2828 case POWERPC_EXCP_603E:
2829 case POWERPC_EXCP_G2:
e1833e1f 2830 goto tlb_miss_tgpr;
a750fc0b 2831 case POWERPC_EXCP_7x5:
76a66253 2832 goto tlb_miss;
7dbe11ac
JM
2833 case POWERPC_EXCP_74xx:
2834 goto tlb_miss_74xx;
2be0071f 2835 default:
e1833e1f 2836 cpu_abort(env, "Invalid instruction TLB miss exception\n");
2be0071f
FB
2837 break;
2838 }
e1833e1f
JM
2839 break;
2840 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
a4f30719
JM
2841 if (lpes1 == 0) /* XXX: check this */
2842 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2843 switch (excp_model) {
a750fc0b
JM
2844 case POWERPC_EXCP_602:
2845 case POWERPC_EXCP_603:
2846 case POWERPC_EXCP_603E:
2847 case POWERPC_EXCP_G2:
e1833e1f 2848 goto tlb_miss_tgpr;
a750fc0b 2849 case POWERPC_EXCP_7x5:
76a66253 2850 goto tlb_miss;
7dbe11ac
JM
2851 case POWERPC_EXCP_74xx:
2852 goto tlb_miss_74xx;
2be0071f 2853 default:
e1833e1f 2854 cpu_abort(env, "Invalid data load TLB miss exception\n");
2be0071f
FB
2855 break;
2856 }
e1833e1f
JM
2857 break;
2858 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
a4f30719
JM
2859 if (lpes1 == 0) /* XXX: check this */
2860 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2861 switch (excp_model) {
a750fc0b
JM
2862 case POWERPC_EXCP_602:
2863 case POWERPC_EXCP_603:
2864 case POWERPC_EXCP_603E:
2865 case POWERPC_EXCP_G2:
e1833e1f 2866 tlb_miss_tgpr:
76a66253 2867 /* Swap temporary saved registers with GPRs */
0411a972
JM
2868 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
2869 new_msr |= (target_ulong)1 << MSR_TGPR;
2870 hreg_swap_gpr_tgpr(env);
2871 }
e1833e1f
JM
2872 goto tlb_miss;
2873 case POWERPC_EXCP_7x5:
2874 tlb_miss:
2be0071f 2875#if defined (DEBUG_SOFTWARE_TLB)
93fcfe39 2876 if (qemu_log_enabled()) {
0bf9e31a 2877 const char *es;
76a66253
JM
2878 target_ulong *miss, *cmp;
2879 int en;
1e6784f9 2880 if (excp == POWERPC_EXCP_IFTLB) {
76a66253
JM
2881 es = "I";
2882 en = 'I';
2883 miss = &env->spr[SPR_IMISS];
2884 cmp = &env->spr[SPR_ICMP];
2885 } else {
1e6784f9 2886 if (excp == POWERPC_EXCP_DLTLB)
76a66253
JM
2887 es = "DL";
2888 else
2889 es = "DS";
2890 en = 'D';
2891 miss = &env->spr[SPR_DMISS];
2892 cmp = &env->spr[SPR_DCMP];
2893 }
90e189ec
BS
2894 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
2895 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
2896 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
2897 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
2898 env->error_code);
2be0071f 2899 }
9a64fbe4 2900#endif
2be0071f
FB
2901 msr |= env->crf[0] << 28;
2902 msr |= env->error_code; /* key, D/I, S/L bits */
2903 /* Set way using a LRU mechanism */
76a66253 2904 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
c62db105 2905 break;
7dbe11ac
JM
2906 case POWERPC_EXCP_74xx:
2907 tlb_miss_74xx:
2908#if defined (DEBUG_SOFTWARE_TLB)
93fcfe39 2909 if (qemu_log_enabled()) {
0bf9e31a 2910 const char *es;
7dbe11ac
JM
2911 target_ulong *miss, *cmp;
2912 int en;
2913 if (excp == POWERPC_EXCP_IFTLB) {
2914 es = "I";
2915 en = 'I';
0411a972
JM
2916 miss = &env->spr[SPR_TLBMISS];
2917 cmp = &env->spr[SPR_PTEHI];
7dbe11ac
JM
2918 } else {
2919 if (excp == POWERPC_EXCP_DLTLB)
2920 es = "DL";
2921 else
2922 es = "DS";
2923 en = 'D';
2924 miss = &env->spr[SPR_TLBMISS];
2925 cmp = &env->spr[SPR_PTEHI];
2926 }
90e189ec
BS
2927 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
2928 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
2929 env->error_code);
7dbe11ac
JM
2930 }
2931#endif
2932 msr |= env->error_code; /* key bit */
2933 break;
2be0071f 2934 default:
e1833e1f 2935 cpu_abort(env, "Invalid data store TLB miss exception\n");
2be0071f
FB
2936 break;
2937 }
e1833e1f
JM
2938 goto store_next;
2939 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
2940 /* XXX: TODO */
2941 cpu_abort(env, "Floating point assist exception "
2942 "is not implemented yet !\n");
2943 goto store_next;
b4095fed
JM
2944 case POWERPC_EXCP_DABR: /* Data address breakpoint */
2945 /* XXX: TODO */
2946 cpu_abort(env, "DABR exception is not implemented yet !\n");
2947 goto store_next;
e1833e1f
JM
2948 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
2949 /* XXX: TODO */
2950 cpu_abort(env, "IABR exception is not implemented yet !\n");
2951 goto store_next;
2952 case POWERPC_EXCP_SMI: /* System management interrupt */
2953 /* XXX: TODO */
2954 cpu_abort(env, "SMI exception is not implemented yet !\n");
2955 goto store_next;
2956 case POWERPC_EXCP_THERM: /* Thermal interrupt */
2957 /* XXX: TODO */
2958 cpu_abort(env, "Thermal management exception "
2959 "is not implemented yet !\n");
2960 goto store_next;
2961 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
e1833e1f 2962 if (lpes1 == 0)
a4f30719 2963 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2964 /* XXX: TODO */
2965 cpu_abort(env,
2966 "Performance counter exception is not implemented yet !\n");
2967 goto store_next;
2968 case POWERPC_EXCP_VPUA: /* Vector assist exception */
2969 /* XXX: TODO */
2970 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
2971 goto store_next;
2972 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
2973 /* XXX: TODO */
2974 cpu_abort(env,
2975 "970 soft-patch exception is not implemented yet !\n");
2976 goto store_next;
2977 case POWERPC_EXCP_MAINT: /* Maintenance exception */
2978 /* XXX: TODO */
2979 cpu_abort(env,
2980 "970 maintenance exception is not implemented yet !\n");
2981 goto store_next;
b4095fed
JM
2982 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
2983 /* XXX: TODO */
2984 cpu_abort(env, "Maskable external exception "
2985 "is not implemented yet !\n");
2986 goto store_next;
2987 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
2988 /* XXX: TODO */
2989 cpu_abort(env, "Non maskable external exception "
2990 "is not implemented yet !\n");
2991 goto store_next;
2be0071f 2992 default:
e1833e1f
JM
2993 excp_invalid:
2994 cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
2995 break;
9a64fbe4 2996 store_current:
2be0071f 2997 /* save current instruction location */
e1833e1f 2998 env->spr[srr0] = env->nip - 4;
9a64fbe4
FB
2999 break;
3000 store_next:
2be0071f 3001 /* save next instruction location */
e1833e1f 3002 env->spr[srr0] = env->nip;
9a64fbe4
FB
3003 break;
3004 }
e1833e1f
JM
3005 /* Save MSR */
3006 env->spr[srr1] = msr;
3007 /* If any alternate SRR register are defined, duplicate saved values */
3008 if (asrr0 != -1)
3009 env->spr[asrr0] = env->spr[srr0];
3010 if (asrr1 != -1)
3011 env->spr[asrr1] = env->spr[srr1];
2be0071f 3012 /* If we disactivated any translation, flush TLBs */
52d631dc 3013 if (msr & ((1 << MSR_IR) | (1 << MSR_DR)))
2be0071f 3014 tlb_flush(env, 1);
41557447
AG
3015
3016 if (msr_ile) {
0411a972 3017 new_msr |= (target_ulong)1 << MSR_LE;
41557447
AG
3018 }
3019
e1833e1f
JM
3020 /* Jump to handler */
3021 vector = env->excp_vectors[excp];
6f2d8978 3022 if (vector == (target_ulong)-1ULL) {
e1833e1f
JM
3023 cpu_abort(env, "Raised an exception without defined vector %d\n",
3024 excp);
3025 }
3026 vector |= env->excp_prefix;
c62db105 3027#if defined(TARGET_PPC64)
e1833e1f 3028 if (excp_model == POWERPC_EXCP_BOOKE) {
0411a972 3029 if (!msr_icm) {
e1833e1f 3030 vector = (uint32_t)vector;
0411a972
JM
3031 } else {
3032 new_msr |= (target_ulong)1 << MSR_CM;
3033 }
c62db105 3034 } else {
6ce0ca12 3035 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
e1833e1f 3036 vector = (uint32_t)vector;
0411a972
JM
3037 } else {
3038 new_msr |= (target_ulong)1 << MSR_SF;
3039 }
c62db105 3040 }
e1833e1f 3041#endif
0411a972
JM
3042 /* XXX: we don't use hreg_store_msr here as already have treated
3043 * any special case that could occur. Just store MSR and update hflags
3044 */
a4f30719 3045 env->msr = new_msr & env->msr_mask;
0411a972 3046 hreg_compute_hflags(env);
e1833e1f
JM
3047 env->nip = vector;
3048 /* Reset exception state */
3049 env->exception_index = POWERPC_EXCP_NONE;
3050 env->error_code = 0;
a586e548 3051
01662f3e
AG
3052 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
3053 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
a586e548
EI
3054 /* XXX: The BookE changes address space when switching modes,
3055 we should probably implement that as different MMU indexes,
3056 but for the moment we do it the slow way and flush all. */
3057 tlb_flush(env, 1);
3058 }
fb0eaffc 3059}
47103572 3060
1328c2bf 3061void do_interrupt (CPUPPCState *env)
47103572 3062{
e1833e1f
JM
3063 powerpc_excp(env, env->excp_model, env->exception_index);
3064}
47103572 3065
e1833e1f
JM
3066void ppc_hw_interrupt (CPUPPCState *env)
3067{
f9fdea6b 3068 int hdice;
f9fdea6b 3069
0411a972 3070#if 0
93fcfe39 3071 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
a496775f 3072 __func__, env, env->pending_interrupts,
0411a972 3073 env->interrupt_request, (int)msr_me, (int)msr_ee);
47103572 3074#endif
e1833e1f 3075 /* External reset */
47103572 3076 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
47103572 3077 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
e1833e1f
JM
3078 powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
3079 return;
3080 }
3081 /* Machine check exception */
3082 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
3083 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
3084 powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
3085 return;
47103572 3086 }
e1833e1f
JM
3087#if 0 /* TODO */
3088 /* External debug exception */
3089 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
3090 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
3091 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
3092 return;
3093 }
3094#endif
b172c56a
JM
3095 if (0) {
3096 /* XXX: find a suitable condition to enable the hypervisor mode */
3097 hdice = env->spr[SPR_LPCR] & 1;
3098 } else {
3099 hdice = 0;
3100 }
f9fdea6b 3101 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
47103572
JM
3102 /* Hypervisor decrementer exception */
3103 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
47103572 3104 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
e1833e1f
JM
3105 powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
3106 return;
3107 }
3108 }
e1833e1f
JM
3109 if (msr_ce != 0) {
3110 /* External critical interrupt */
3111 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
3112 /* Taking a critical external interrupt does not clear the external
3113 * critical interrupt status
3114 */
3115#if 0
3116 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
47103572 3117#endif
e1833e1f
JM
3118 powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
3119 return;
3120 }
3121 }
3122 if (msr_ee != 0) {
3123 /* Watchdog timer on embedded PowerPC */
3124 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
3125 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
3126 powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
3127 return;
3128 }
e1833e1f
JM
3129 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
3130 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
3131 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
3132 return;
3133 }
e1833e1f
JM
3134 /* Fixed interval timer on embedded PowerPC */
3135 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
3136 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
3137 powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
3138 return;
3139 }
3140 /* Programmable interval timer on embedded PowerPC */
3141 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
3142 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
3143 powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
3144 return;
3145 }
47103572
JM
3146 /* Decrementer exception */
3147 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
47103572 3148 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
e1833e1f
JM
3149 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
3150 return;
3151 }
47103572 3152 /* External interrupt */
e1833e1f 3153 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
e9df014c
JM
3154 /* Taking an external interrupt does not clear the external
3155 * interrupt status
3156 */
3157#if 0
47103572 3158 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
e9df014c 3159#endif
e1833e1f
JM
3160 powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
3161 return;
3162 }
e1833e1f
JM
3163 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
3164 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
3165 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
3166 return;
47103572 3167 }
e1833e1f
JM
3168 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
3169 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
3170 powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
3171 return;
3172 }
3173 /* Thermal interrupt */
3174 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
3175 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
3176 powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
3177 return;
3178 }
47103572 3179 }
47103572 3180}
18fba28c 3181#endif /* !CONFIG_USER_ONLY */
a496775f 3182
4a057712
JM
3183void cpu_dump_rfi (target_ulong RA, target_ulong msr)
3184{
90e189ec
BS
3185 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
3186 TARGET_FMT_lx "\n", RA, msr);
a496775f
JM
3187}
3188
1bba0dc9 3189void cpu_state_reset(CPUPPCState *env)
0a032cbe 3190{
a1389542 3191 cpu_reset(ENV_GET_CPU(env));
0a032cbe
JM
3192}
3193
aaed909a 3194CPUPPCState *cpu_ppc_init (const char *cpu_model)
0a032cbe 3195{
1d0cb67d 3196 PowerPCCPU *cpu;
0a032cbe 3197 CPUPPCState *env;
c227f099 3198 const ppc_def_t *def;
aaed909a
FB
3199
3200 def = cpu_ppc_find_by_name(cpu_model);
3201 if (!def)
3202 return NULL;
0a032cbe 3203
1d0cb67d
AF
3204 cpu = POWERPC_CPU(object_new(TYPE_POWERPC_CPU));
3205 env = &cpu->env;
6cca7ad6 3206
d5ab9713
JK
3207 if (tcg_enabled()) {
3208 ppc_translate_init();
3209 }
6cca7ad6 3210
01ba9816 3211 env->cpu_model_str = cpu_model;
aaed909a 3212 cpu_ppc_register_internal(env, def);
d76d1650 3213
0bf46a40 3214 qemu_init_vcpu(env);
d76d1650 3215
0a032cbe
JM
3216 return env;
3217}