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