]> Git Repo - qemu.git/blame - target/ppc/mmu_helper.c
target/ppc: Manage external HPT via virtual hypervisor
[qemu.git] / target / ppc / mmu_helper.c
CommitLineData
ec19c4d1
BS
1/*
2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
0d75590d 19#include "qemu/osdep.h"
da34e65c 20#include "qapi/error.h"
ec19c4d1 21#include "cpu.h"
2ef6175a 22#include "exec/helper-proto.h"
9c17d615 23#include "sysemu/kvm.h"
8cbbe385 24#include "kvm_ppc.h"
10b46525 25#include "mmu-hash64.h"
9d7c3f4a 26#include "mmu-hash32.h"
63c91552 27#include "exec/exec-all.h"
f08b6170 28#include "exec/cpu_ldst.h"
508127e2 29#include "exec/log.h"
cd0c6f47 30#include "helper_regs.h"
ec19c4d1 31
8cbbe385
BS
32//#define DEBUG_MMU
33//#define DEBUG_BATS
ec19c4d1 34//#define DEBUG_SOFTWARE_TLB
8cbbe385 35//#define DUMP_PAGE_TABLES
8cbbe385
BS
36//#define FLUSH_ALL_TLBS
37
38#ifdef DEBUG_MMU
48880da6 39# define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
8cbbe385 40#else
77710e7a 41# define LOG_MMU_STATE(cpu) do { } while (0)
8cbbe385 42#endif
ec19c4d1
BS
43
44#ifdef DEBUG_SOFTWARE_TLB
48880da6 45# define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
ec19c4d1
BS
46#else
47# define LOG_SWTLB(...) do { } while (0)
48#endif
49
8cbbe385 50#ifdef DEBUG_BATS
48880da6 51# define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
8cbbe385
BS
52#else
53# define LOG_BATS(...) do { } while (0)
54#endif
55
8cbbe385
BS
56/*****************************************************************************/
57/* PowerPC MMU emulation */
5dc68eb0
DG
58
59/* Context used internally during MMU translations */
60typedef struct mmu_ctx_t mmu_ctx_t;
61struct mmu_ctx_t {
62 hwaddr raddr; /* Real address */
63 hwaddr eaddr; /* Effective address */
64 int prot; /* Protection bits */
65 hwaddr hash[2]; /* Pagetable hash values */
66 target_ulong ptem; /* Virtual segment ID | API */
67 int key; /* Access key */
68 int nx; /* Non-execute area */
69};
70
8cbbe385
BS
71/* Common routines used by software and hardware TLBs emulation */
72static inline int pte_is_valid(target_ulong pte0)
73{
74 return pte0 & 0x80000000 ? 1 : 0;
75}
76
77static inline void pte_invalidate(target_ulong *pte0)
78{
79 *pte0 &= ~0x80000000;
80}
81
8cbbe385
BS
82#define PTE_PTEM_MASK 0x7FFFFFBF
83#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
8cbbe385 84
496272a7 85static int pp_check(int key, int pp, int nx)
8cbbe385
BS
86{
87 int access;
88
89 /* Compute access rights */
8cbbe385
BS
90 access = 0;
91 if (key == 0) {
92 switch (pp) {
93 case 0x0:
94 case 0x1:
95 case 0x2:
96 access |= PAGE_WRITE;
97 /* No break here */
98 case 0x3:
8cbbe385
BS
99 access |= PAGE_READ;
100 break;
101 }
102 } else {
103 switch (pp) {
104 case 0x0:
8cbbe385
BS
105 access = 0;
106 break;
107 case 0x1:
108 case 0x3:
109 access = PAGE_READ;
110 break;
111 case 0x2:
112 access = PAGE_READ | PAGE_WRITE;
113 break;
114 }
115 }
116 if (nx == 0) {
117 access |= PAGE_EXEC;
118 }
119
120 return access;
121}
122
496272a7 123static int check_prot(int prot, int rw, int access_type)
8cbbe385
BS
124{
125 int ret;
126
127 if (access_type == ACCESS_CODE) {
128 if (prot & PAGE_EXEC) {
129 ret = 0;
130 } else {
131 ret = -2;
132 }
133 } else if (rw) {
134 if (prot & PAGE_WRITE) {
135 ret = 0;
136 } else {
137 ret = -2;
138 }
139 } else {
140 if (prot & PAGE_READ) {
141 ret = 0;
142 } else {
143 ret = -2;
144 }
145 }
146
147 return ret;
148}
149
9d7c3f4a
DG
150static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
151 target_ulong pte1, int h, int rw, int type)
8cbbe385
BS
152{
153 target_ulong ptem, mmask;
154 int access, ret, pteh, ptev, pp;
155
156 ret = -1;
157 /* Check validity and table match */
9d7c3f4a
DG
158 ptev = pte_is_valid(pte0);
159 pteh = (pte0 >> 6) & 1;
8cbbe385
BS
160 if (ptev && h == pteh) {
161 /* Check vsid & api */
9d7c3f4a
DG
162 ptem = pte0 & PTE_PTEM_MASK;
163 mmask = PTE_CHECK_MASK;
164 pp = pte1 & 0x00000003;
8cbbe385 165 if (ptem == ctx->ptem) {
a8170e5e 166 if (ctx->raddr != (hwaddr)-1ULL) {
8cbbe385
BS
167 /* all matches should have equal RPN, WIMG & PP */
168 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
48880da6 169 qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
8cbbe385
BS
170 return -3;
171 }
172 }
173 /* Compute access rights */
174 access = pp_check(ctx->key, pp, ctx->nx);
175 /* Keep the matching PTE informations */
176 ctx->raddr = pte1;
177 ctx->prot = access;
178 ret = check_prot(ctx->prot, rw, type);
179 if (ret == 0) {
180 /* Access granted */
339aaf5b 181 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
8cbbe385
BS
182 } else {
183 /* Access right violation */
339aaf5b 184 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
8cbbe385
BS
185 }
186 }
187 }
188
189 return ret;
190}
191
496272a7
DG
192static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
193 int ret, int rw)
8cbbe385
BS
194{
195 int store = 0;
196
197 /* Update page flags */
198 if (!(*pte1p & 0x00000100)) {
199 /* Update accessed flag */
200 *pte1p |= 0x00000100;
201 store = 1;
202 }
203 if (!(*pte1p & 0x00000080)) {
204 if (rw == 1 && ret == 0) {
205 /* Update changed flag */
206 *pte1p |= 0x00000080;
207 store = 1;
208 } else {
209 /* Force page fault for first write access */
210 ctx->prot &= ~PAGE_WRITE;
211 }
212 }
213
214 return store;
215}
216
217/* Software driven TLB helpers */
218static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
219 int way, int is_code)
220{
221 int nr;
222
223 /* Select TLB num in a way from address */
224 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
225 /* Select TLB way */
226 nr += env->tlb_per_way * way;
227 /* 6xx have separate TLBs for instructions and data */
228 if (is_code && env->id_tlbs == 1) {
229 nr += env->nb_tlb;
230 }
231
232 return nr;
233}
234
235static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
236{
00c8cb0a 237 PowerPCCPU *cpu = ppc_env_get_cpu(env);
8cbbe385
BS
238 ppc6xx_tlb_t *tlb;
239 int nr, max;
240
241 /* LOG_SWTLB("Invalidate all TLBs\n"); */
242 /* Invalidate all defined software TLB */
243 max = env->nb_tlb;
244 if (env->id_tlbs == 1) {
245 max *= 2;
246 }
247 for (nr = 0; nr < max; nr++) {
248 tlb = &env->tlb.tlb6[nr];
249 pte_invalidate(&tlb->pte0);
250 }
d10eb08f 251 tlb_flush(CPU(cpu));
8cbbe385
BS
252}
253
254static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
255 target_ulong eaddr,
256 int is_code, int match_epn)
257{
258#if !defined(FLUSH_ALL_TLBS)
31b030d4 259 CPUState *cs = CPU(ppc_env_get_cpu(env));
8cbbe385
BS
260 ppc6xx_tlb_t *tlb;
261 int way, nr;
262
263 /* Invalidate ITLB + DTLB, all ways */
264 for (way = 0; way < env->nb_ways; way++) {
265 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
266 tlb = &env->tlb.tlb6[nr];
267 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
268 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
269 env->nb_tlb, eaddr);
270 pte_invalidate(&tlb->pte0);
31b030d4 271 tlb_flush_page(cs, tlb->EPN);
8cbbe385
BS
272 }
273 }
274#else
275 /* XXX: PowerPC specification say this is valid as well */
276 ppc6xx_tlb_invalidate_all(env);
277#endif
278}
279
280static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
281 target_ulong eaddr, int is_code)
282{
283 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
284}
285
9aa5b158
BS
286static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
287 int is_code, target_ulong pte0, target_ulong pte1)
8cbbe385
BS
288{
289 ppc6xx_tlb_t *tlb;
290 int nr;
291
292 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
293 tlb = &env->tlb.tlb6[nr];
294 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
295 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
296 /* Invalidate any pending reference in QEMU for this virtual address */
297 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
298 tlb->pte0 = pte0;
299 tlb->pte1 = pte1;
300 tlb->EPN = EPN;
301 /* Store last way for LRU mechanism */
302 env->last_way = way;
303}
304
305static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
306 target_ulong eaddr, int rw, int access_type)
307{
308 ppc6xx_tlb_t *tlb;
309 int nr, best, way;
310 int ret;
311
312 best = -1;
313 ret = -1; /* No TLB found */
314 for (way = 0; way < env->nb_ways; way++) {
315 nr = ppc6xx_tlb_getnum(env, eaddr, way,
316 access_type == ACCESS_CODE ? 1 : 0);
317 tlb = &env->tlb.tlb6[nr];
318 /* This test "emulates" the PTE index match for hardware TLBs */
319 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
320 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
321 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
322 pte_is_valid(tlb->pte0) ? "valid" : "inval",
323 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
324 continue;
325 }
326 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
327 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
328 pte_is_valid(tlb->pte0) ? "valid" : "inval",
329 tlb->EPN, eaddr, tlb->pte1,
330 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
9d7c3f4a 331 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
8cbbe385
BS
332 case -3:
333 /* TLB inconsistency */
334 return -1;
335 case -2:
336 /* Access violation */
337 ret = -2;
338 best = nr;
339 break;
340 case -1:
341 default:
342 /* No match */
343 break;
344 case 0:
345 /* access granted */
346 /* XXX: we should go on looping to check all TLBs consistency
347 * but we can speed-up the whole thing as the
348 * result would be undefined if TLBs are not consistent.
349 */
350 ret = 0;
351 best = nr;
352 goto done;
353 }
354 }
355 if (best != -1) {
356 done:
357 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
358 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
359 /* Update page flags */
360 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
361 }
362
363 return ret;
364}
365
366/* Perform BAT hit & translation */
367static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
368 int *validp, int *protp, target_ulong *BATu,
369 target_ulong *BATl)
370{
371 target_ulong bl;
372 int pp, valid, prot;
373
374 bl = (*BATu & 0x00001FFC) << 15;
375 valid = 0;
376 prot = 0;
377 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
378 ((msr_pr != 0) && (*BATu & 0x00000001))) {
379 valid = 1;
380 pp = *BATl & 0x00000003;
381 if (pp != 0) {
382 prot = PAGE_READ | PAGE_EXEC;
383 if (pp == 0x2) {
384 prot |= PAGE_WRITE;
385 }
386 }
387 }
388 *blp = bl;
389 *validp = valid;
390 *protp = prot;
391}
392
98132796
DG
393static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
394 target_ulong virtual, int rw, int type)
8cbbe385
BS
395{
396 target_ulong *BATlt, *BATut, *BATu, *BATl;
397 target_ulong BEPIl, BEPIu, bl;
398 int i, valid, prot;
399 int ret = -1;
400
401 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
402 type == ACCESS_CODE ? 'I' : 'D', virtual);
403 switch (type) {
404 case ACCESS_CODE:
405 BATlt = env->IBAT[1];
406 BATut = env->IBAT[0];
407 break;
408 default:
409 BATlt = env->DBAT[1];
410 BATut = env->DBAT[0];
411 break;
412 }
413 for (i = 0; i < env->nb_BATs; i++) {
414 BATu = &BATut[i];
415 BATl = &BATlt[i];
416 BEPIu = *BATu & 0xF0000000;
417 BEPIl = *BATu & 0x0FFE0000;
98132796 418 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
8cbbe385
BS
419 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
420 " BATl " TARGET_FMT_lx "\n", __func__,
421 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
422 if ((virtual & 0xF0000000) == BEPIu &&
423 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
424 /* BAT matches */
425 if (valid != 0) {
426 /* Get physical address */
427 ctx->raddr = (*BATl & 0xF0000000) |
428 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
429 (virtual & 0x0001F000);
430 /* Compute access rights */
431 ctx->prot = prot;
432 ret = check_prot(ctx->prot, rw, type);
433 if (ret == 0) {
434 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
435 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
436 ctx->prot & PAGE_WRITE ? 'W' : '-');
437 }
438 break;
439 }
440 }
441 }
442 if (ret < 0) {
443#if defined(DEBUG_BATS)
444 if (qemu_log_enabled()) {
445 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
446 for (i = 0; i < 4; i++) {
447 BATu = &BATut[i];
448 BATl = &BATlt[i];
449 BEPIu = *BATu & 0xF0000000;
450 BEPIl = *BATu & 0x0FFE0000;
451 bl = (*BATu & 0x00001FFC) << 15;
452 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
453 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
454 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
455 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
456 *BATu, *BATl, BEPIu, BEPIl, bl);
457 }
458 }
459#endif
460 }
461 /* No hit */
462 return ret;
463}
464
8cbbe385 465/* Perform segment based translation */
0480884f
DG
466static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
467 target_ulong eaddr, int rw, int type)
8cbbe385 468{
36778660 469 PowerPCCPU *cpu = ppc_env_get_cpu(env);
a8170e5e 470 hwaddr hash;
8cbbe385
BS
471 target_ulong vsid;
472 int ds, pr, target_page_bits;
0480884f
DG
473 int ret;
474 target_ulong sr, pgidx;
8cbbe385
BS
475
476 pr = msr_pr;
477 ctx->eaddr = eaddr;
8cbbe385 478
0480884f
DG
479 sr = env->sr[eaddr >> 28];
480 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
481 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
482 ds = sr & 0x80000000 ? 1 : 0;
483 ctx->nx = sr & 0x10000000 ? 1 : 0;
484 vsid = sr & 0x00FFFFFF;
485 target_page_bits = TARGET_PAGE_BITS;
339aaf5b
AP
486 qemu_log_mask(CPU_LOG_MMU,
487 "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
488 " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
0480884f
DG
489 " ir=%d dr=%d pr=%d %d t=%d\n",
490 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
491 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
492 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
493 hash = vsid ^ pgidx;
494 ctx->ptem = (vsid << 7) | (pgidx >> 10);
8cbbe385 495
339aaf5b
AP
496 qemu_log_mask(CPU_LOG_MMU,
497 "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
8cbbe385
BS
498 ctx->key, ds, ctx->nx, vsid);
499 ret = -1;
500 if (!ds) {
501 /* Check if instruction fetch is allowed, if needed */
502 if (type != ACCESS_CODE || ctx->nx == 0) {
503 /* Page address translation */
339aaf5b
AP
504 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
505 " htab_mask " TARGET_FMT_plx
8cbbe385 506 " hash " TARGET_FMT_plx "\n",
36778660 507 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
8cbbe385
BS
508 ctx->hash[0] = hash;
509 ctx->hash[1] = ~hash;
510
511 /* Initialize real address with an invalid value */
a8170e5e 512 ctx->raddr = (hwaddr)-1ULL;
0480884f
DG
513 /* Software TLB search */
514 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
8cbbe385 515#if defined(DUMP_PAGE_TABLES)
9207113d
MCA
516 if (qemu_loglevel_mask(CPU_LOG_MMU)) {
517 CPUState *cs = ENV_GET_CPU(env);
a8170e5e 518 hwaddr curaddr;
8cbbe385
BS
519 uint32_t a0, a1, a2, a3;
520
521 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
36778660
DG
522 "\n", ppc_hash32_hpt_base(cpu),
523 ppc_hash32_hpt_mask(env) + 0x80);
524 for (curaddr = ppc_hash32_hpt_base(cpu);
525 curaddr < (ppc_hash32_hpt_base(cpu)
526 + ppc_hash32_hpt_mask(cpu) + 0x80);
8cbbe385 527 curaddr += 16) {
9207113d
MCA
528 a0 = ldl_phys(cs->as, curaddr);
529 a1 = ldl_phys(cs->as, curaddr + 4);
530 a2 = ldl_phys(cs->as, curaddr + 8);
531 a3 = ldl_phys(cs->as, curaddr + 12);
8cbbe385
BS
532 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
533 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
534 curaddr, a0, a1, a2, a3);
535 }
536 }
537 }
538#endif
539 } else {
339aaf5b 540 qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
8cbbe385
BS
541 ret = -3;
542 }
543 } else {
544 target_ulong sr;
545
339aaf5b 546 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
8cbbe385
BS
547 /* Direct-store segment : absolutely *BUGGY* for now */
548
549 /* Direct-store implies a 32-bit MMU.
550 * Check the Segment Register's bus unit ID (BUID).
551 */
552 sr = env->sr[eaddr >> 28];
553 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
554 /* Memory-forced I/O controller interface access */
555 /* If T=1 and BUID=x'07F', the 601 performs a memory access
556 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
557 */
558 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
559 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
560 return 0;
561 }
562
563 switch (type) {
564 case ACCESS_INT:
565 /* Integer load/store : only access allowed */
566 break;
567 case ACCESS_CODE:
568 /* No code fetch is allowed in direct-store areas */
569 return -4;
570 case ACCESS_FLOAT:
571 /* Floating point load/store */
572 return -4;
573 case ACCESS_RES:
574 /* lwarx, ldarx or srwcx. */
575 return -4;
576 case ACCESS_CACHE:
577 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
578 /* Should make the instruction do no-op.
579 * As it already do no-op, it's quite easy :-)
580 */
581 ctx->raddr = eaddr;
582 return 0;
583 case ACCESS_EXT:
584 /* eciwx or ecowx */
585 return -4;
586 default:
48880da6
PB
587 qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
588 "address translation\n");
8cbbe385
BS
589 return -4;
590 }
591 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
592 ctx->raddr = eaddr;
593 ret = 2;
594 } else {
595 ret = -2;
596 }
597 }
598
599 return ret;
600}
601
602/* Generic TLB check function for embedded PowerPC implementations */
9aa5b158 603static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
a8170e5e 604 hwaddr *raddrp,
9aa5b158
BS
605 target_ulong address, uint32_t pid, int ext,
606 int i)
8cbbe385
BS
607{
608 target_ulong mask;
609
610 /* Check valid flag */
611 if (!(tlb->prot & PAGE_VALID)) {
612 return -1;
613 }
614 mask = ~(tlb->size - 1);
615 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
616 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
617 mask, (uint32_t)tlb->PID, tlb->prot);
618 /* Check PID */
619 if (tlb->PID != 0 && tlb->PID != pid) {
620 return -1;
621 }
622 /* Check effective address */
623 if ((address & mask) != tlb->EPN) {
624 return -1;
625 }
626 *raddrp = (tlb->RPN & mask) | (address & ~mask);
8cbbe385
BS
627 if (ext) {
628 /* Extend the physical address to 36 bits */
4be403c8 629 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
8cbbe385 630 }
8cbbe385
BS
631
632 return 0;
633}
634
635/* Generic TLB search function for PowerPC embedded implementations */
9aa5b158
BS
636static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
637 uint32_t pid)
8cbbe385
BS
638{
639 ppcemb_tlb_t *tlb;
a8170e5e 640 hwaddr raddr;
8cbbe385
BS
641 int i, ret;
642
643 /* Default return value is no match */
644 ret = -1;
645 for (i = 0; i < env->nb_tlb; i++) {
646 tlb = &env->tlb.tlbe[i];
647 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
648 ret = i;
649 break;
650 }
651 }
652
653 return ret;
654}
655
656/* Helpers specific to PowerPC 40x implementations */
657static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
658{
00c8cb0a 659 PowerPCCPU *cpu = ppc_env_get_cpu(env);
8cbbe385
BS
660 ppcemb_tlb_t *tlb;
661 int i;
662
663 for (i = 0; i < env->nb_tlb; i++) {
664 tlb = &env->tlb.tlbe[i];
665 tlb->prot &= ~PAGE_VALID;
666 }
d10eb08f 667 tlb_flush(CPU(cpu));
8cbbe385
BS
668}
669
8cbbe385
BS
670static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
671 target_ulong address, int rw,
672 int access_type)
673{
674 ppcemb_tlb_t *tlb;
a8170e5e 675 hwaddr raddr;
8cbbe385
BS
676 int i, ret, zsel, zpr, pr;
677
678 ret = -1;
a8170e5e 679 raddr = (hwaddr)-1ULL;
8cbbe385
BS
680 pr = msr_pr;
681 for (i = 0; i < env->nb_tlb; i++) {
682 tlb = &env->tlb.tlbe[i];
683 if (ppcemb_tlb_check(env, tlb, &raddr, address,
684 env->spr[SPR_40x_PID], 0, i) < 0) {
685 continue;
686 }
687 zsel = (tlb->attr >> 4) & 0xF;
688 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
689 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
690 __func__, i, zsel, zpr, rw, tlb->attr);
691 /* Check execute enable bit */
692 switch (zpr) {
693 case 0x2:
694 if (pr != 0) {
695 goto check_perms;
696 }
697 /* No break here */
698 case 0x3:
699 /* All accesses granted */
700 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
701 ret = 0;
702 break;
703 case 0x0:
704 if (pr != 0) {
705 /* Raise Zone protection fault. */
706 env->spr[SPR_40x_ESR] = 1 << 22;
707 ctx->prot = 0;
708 ret = -2;
709 break;
710 }
711 /* No break here */
712 case 0x1:
713 check_perms:
714 /* Check from TLB entry */
715 ctx->prot = tlb->prot;
716 ret = check_prot(ctx->prot, rw, access_type);
717 if (ret == -2) {
718 env->spr[SPR_40x_ESR] = 0;
719 }
720 break;
721 }
722 if (ret >= 0) {
723 ctx->raddr = raddr;
724 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
725 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
726 ret);
727 return 0;
728 }
729 }
730 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
731 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
732
733 return ret;
734}
735
736void store_40x_sler(CPUPPCState *env, uint32_t val)
737{
a47dddd7
AF
738 PowerPCCPU *cpu = ppc_env_get_cpu(env);
739
8cbbe385
BS
740 /* XXX: TO BE FIXED */
741 if (val != 0x00000000) {
a47dddd7 742 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
8cbbe385
BS
743 }
744 env->spr[SPR_405_SLER] = val;
745}
746
747static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
a8170e5e 748 hwaddr *raddr, int *prot,
8cbbe385
BS
749 target_ulong address, int rw,
750 int access_type, int i)
751{
752 int ret, prot2;
753
754 if (ppcemb_tlb_check(env, tlb, raddr, address,
755 env->spr[SPR_BOOKE_PID],
756 !env->nb_pids, i) >= 0) {
757 goto found_tlb;
758 }
759
760 if (env->spr[SPR_BOOKE_PID1] &&
761 ppcemb_tlb_check(env, tlb, raddr, address,
762 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
763 goto found_tlb;
764 }
765
766 if (env->spr[SPR_BOOKE_PID2] &&
767 ppcemb_tlb_check(env, tlb, raddr, address,
768 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
769 goto found_tlb;
770 }
771
772 LOG_SWTLB("%s: TLB entry not found\n", __func__);
773 return -1;
774
775found_tlb:
776
777 if (msr_pr != 0) {
778 prot2 = tlb->prot & 0xF;
779 } else {
780 prot2 = (tlb->prot >> 4) & 0xF;
781 }
782
783 /* Check the address space */
784 if (access_type == ACCESS_CODE) {
785 if (msr_ir != (tlb->attr & 1)) {
786 LOG_SWTLB("%s: AS doesn't match\n", __func__);
787 return -1;
788 }
789
790 *prot = prot2;
791 if (prot2 & PAGE_EXEC) {
792 LOG_SWTLB("%s: good TLB!\n", __func__);
793 return 0;
794 }
795
796 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
797 ret = -3;
798 } else {
799 if (msr_dr != (tlb->attr & 1)) {
800 LOG_SWTLB("%s: AS doesn't match\n", __func__);
801 return -1;
802 }
803
804 *prot = prot2;
805 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
806 LOG_SWTLB("%s: found TLB!\n", __func__);
807 return 0;
808 }
809
810 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
811 ret = -2;
812 }
813
814 return ret;
815}
816
817static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
818 target_ulong address, int rw,
819 int access_type)
820{
821 ppcemb_tlb_t *tlb;
a8170e5e 822 hwaddr raddr;
8cbbe385
BS
823 int i, ret;
824
825 ret = -1;
a8170e5e 826 raddr = (hwaddr)-1ULL;
8cbbe385
BS
827 for (i = 0; i < env->nb_tlb; i++) {
828 tlb = &env->tlb.tlbe[i];
829 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
830 access_type, i);
0a4c7740 831 if (ret != -1) {
8cbbe385
BS
832 break;
833 }
834 }
835
836 if (ret >= 0) {
837 ctx->raddr = raddr;
838 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
839 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
840 ret);
841 } else {
842 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
843 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
844 }
845
846 return ret;
847}
848
6575c289
BS
849static void booke206_flush_tlb(CPUPPCState *env, int flags,
850 const int check_iprot)
8cbbe385 851{
00c8cb0a 852 PowerPCCPU *cpu = ppc_env_get_cpu(env);
8cbbe385
BS
853 int tlb_size;
854 int i, j;
855 ppcmas_tlb_t *tlb = env->tlb.tlbm;
856
857 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
858 if (flags & (1 << i)) {
859 tlb_size = booke206_tlb_size(env, i);
860 for (j = 0; j < tlb_size; j++) {
861 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
862 tlb[j].mas1 &= ~MAS1_VALID;
863 }
864 }
865 }
866 tlb += booke206_tlb_size(env, i);
867 }
868
d10eb08f 869 tlb_flush(CPU(cpu));
8cbbe385
BS
870}
871
6575c289
BS
872static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
873 ppcmas_tlb_t *tlb)
8cbbe385
BS
874{
875 int tlbm_size;
876
877 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
878
879 return 1024ULL << tlbm_size;
880}
881
882/* TLB check function for MAS based SoftTLBs */
213c7180 883static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
da89a1cf
AG
884 hwaddr *raddrp, target_ulong address,
885 uint32_t pid)
8cbbe385 886{
da89a1cf 887 hwaddr mask;
8cbbe385
BS
888 uint32_t tlb_pid;
889
deb6ed13
AG
890 if (!msr_cm) {
891 /* In 32bit mode we can only address 32bit EAs */
892 address = (uint32_t)address;
893 }
894
8cbbe385
BS
895 /* Check valid flag */
896 if (!(tlb->mas1 & MAS1_VALID)) {
897 return -1;
898 }
899
900 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
901 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
9207113d
MCA
902 PRIx64 " mask=0x%" HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%"
903 PRIx32 "\n", __func__, address, pid, tlb->mas1, tlb->mas2, mask,
904 tlb->mas7_3, tlb->mas8);
8cbbe385
BS
905
906 /* Check PID */
907 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
908 if (tlb_pid != 0 && tlb_pid != pid) {
909 return -1;
910 }
911
912 /* Check effective address */
913 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
914 return -1;
915 }
916
917 if (raddrp) {
918 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
919 }
920
921 return 0;
922}
923
924static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
a8170e5e 925 hwaddr *raddr, int *prot,
8cbbe385
BS
926 target_ulong address, int rw,
927 int access_type)
928{
929 int ret;
930 int prot2 = 0;
931
932 if (ppcmas_tlb_check(env, tlb, raddr, address,
933 env->spr[SPR_BOOKE_PID]) >= 0) {
934 goto found_tlb;
935 }
936
937 if (env->spr[SPR_BOOKE_PID1] &&
938 ppcmas_tlb_check(env, tlb, raddr, address,
939 env->spr[SPR_BOOKE_PID1]) >= 0) {
940 goto found_tlb;
941 }
942
943 if (env->spr[SPR_BOOKE_PID2] &&
944 ppcmas_tlb_check(env, tlb, raddr, address,
945 env->spr[SPR_BOOKE_PID2]) >= 0) {
946 goto found_tlb;
947 }
948
949 LOG_SWTLB("%s: TLB entry not found\n", __func__);
950 return -1;
951
952found_tlb:
953
954 if (msr_pr != 0) {
955 if (tlb->mas7_3 & MAS3_UR) {
956 prot2 |= PAGE_READ;
957 }
958 if (tlb->mas7_3 & MAS3_UW) {
959 prot2 |= PAGE_WRITE;
960 }
961 if (tlb->mas7_3 & MAS3_UX) {
962 prot2 |= PAGE_EXEC;
963 }
964 } else {
965 if (tlb->mas7_3 & MAS3_SR) {
966 prot2 |= PAGE_READ;
967 }
968 if (tlb->mas7_3 & MAS3_SW) {
969 prot2 |= PAGE_WRITE;
970 }
971 if (tlb->mas7_3 & MAS3_SX) {
972 prot2 |= PAGE_EXEC;
973 }
974 }
975
976 /* Check the address space and permissions */
977 if (access_type == ACCESS_CODE) {
978 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
979 LOG_SWTLB("%s: AS doesn't match\n", __func__);
980 return -1;
981 }
982
983 *prot = prot2;
984 if (prot2 & PAGE_EXEC) {
985 LOG_SWTLB("%s: good TLB!\n", __func__);
986 return 0;
987 }
988
989 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
990 ret = -3;
991 } else {
992 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
993 LOG_SWTLB("%s: AS doesn't match\n", __func__);
994 return -1;
995 }
996
997 *prot = prot2;
998 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
999 LOG_SWTLB("%s: found TLB!\n", __func__);
1000 return 0;
1001 }
1002
1003 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1004 ret = -2;
1005 }
1006
1007 return ret;
1008}
1009
1010static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1011 target_ulong address, int rw,
1012 int access_type)
1013{
1014 ppcmas_tlb_t *tlb;
a8170e5e 1015 hwaddr raddr;
8cbbe385
BS
1016 int i, j, ret;
1017
1018 ret = -1;
a8170e5e 1019 raddr = (hwaddr)-1ULL;
8cbbe385
BS
1020
1021 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1022 int ways = booke206_tlb_ways(env, i);
1023
1024 for (j = 0; j < ways; j++) {
1025 tlb = booke206_get_tlbm(env, i, address, j);
1026 if (!tlb) {
1027 continue;
1028 }
1029 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1030 rw, access_type);
1031 if (ret != -1) {
1032 goto found_tlb;
1033 }
1034 }
1035 }
1036
1037found_tlb:
1038
1039 if (ret >= 0) {
1040 ctx->raddr = raddr;
1041 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1042 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1043 ret);
1044 } else {
1045 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1046 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1047 }
1048
1049 return ret;
1050}
1051
1052static const char *book3e_tsize_to_str[32] = {
1053 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1054 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1055 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1056 "1T", "2T"
1057};
1058
1059static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1060 CPUPPCState *env)
1061{
1062 ppcemb_tlb_t *entry;
1063 int i;
1064
1065 if (kvm_enabled() && !env->kvm_sw_tlb) {
1066 cpu_fprintf(f, "Cannot access KVM TLB\n");
1067 return;
1068 }
1069
1070 cpu_fprintf(f, "\nTLB:\n");
1071 cpu_fprintf(f, "Effective Physical Size PID Prot "
1072 "Attr\n");
1073
1074 entry = &env->tlb.tlbe[0];
1075 for (i = 0; i < env->nb_tlb; i++, entry++) {
a8170e5e 1076 hwaddr ea, pa;
8cbbe385
BS
1077 target_ulong mask;
1078 uint64_t size = (uint64_t)entry->size;
1079 char size_buf[20];
1080
1081 /* Check valid flag */
1082 if (!(entry->prot & PAGE_VALID)) {
1083 continue;
1084 }
1085
1086 mask = ~(entry->size - 1);
1087 ea = entry->EPN & mask;
1088 pa = entry->RPN & mask;
8cbbe385 1089 /* Extend the physical address to 36 bits */
a8170e5e 1090 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
8cbbe385
BS
1091 size /= 1024;
1092 if (size >= 1024) {
1093 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1094 } else {
1095 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1096 }
1097 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1098 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1099 entry->prot, entry->attr);
1100 }
1101
1102}
1103
1104static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1105 CPUPPCState *env, int tlbn, int offset,
1106 int tlbsize)
1107{
1108 ppcmas_tlb_t *entry;
1109 int i;
1110
1111 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1112 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1113 " URWX WIMGE U0123\n");
1114
1115 entry = &env->tlb.tlbm[offset];
1116 for (i = 0; i < tlbsize; i++, entry++) {
a8170e5e 1117 hwaddr ea, pa, size;
8cbbe385
BS
1118 int tsize;
1119
1120 if (!(entry->mas1 & MAS1_VALID)) {
1121 continue;
1122 }
1123
1124 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1125 size = 1024ULL << tsize;
1126 ea = entry->mas2 & ~(size - 1);
1127 pa = entry->mas7_3 & ~(size - 1);
1128
1129 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1130 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1131 (uint64_t)ea, (uint64_t)pa,
1132 book3e_tsize_to_str[tsize],
1133 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1134 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1135 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1136 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1137 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1138 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1139 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1140 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1141 entry->mas2 & MAS2_W ? 'W' : '-',
1142 entry->mas2 & MAS2_I ? 'I' : '-',
1143 entry->mas2 & MAS2_M ? 'M' : '-',
1144 entry->mas2 & MAS2_G ? 'G' : '-',
1145 entry->mas2 & MAS2_E ? 'E' : '-',
1146 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1147 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1148 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1149 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1150 }
1151}
1152
1153static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1154 CPUPPCState *env)
1155{
1156 int offset = 0;
1157 int i;
1158
1159 if (kvm_enabled() && !env->kvm_sw_tlb) {
1160 cpu_fprintf(f, "Cannot access KVM TLB\n");
1161 return;
1162 }
1163
1164 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1165 int size = booke206_tlb_size(env, i);
1166
1167 if (size == 0) {
1168 continue;
1169 }
1170
1171 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1172 offset += size;
1173 }
1174}
1175
886b7577
FC
1176static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1177 CPUPPCState *env, int type)
1178{
1179 target_ulong *BATlt, *BATut, *BATu, *BATl;
1180 target_ulong BEPIl, BEPIu, bl;
1181 int i;
1182
1183 switch (type) {
1184 case ACCESS_CODE:
1185 BATlt = env->IBAT[1];
1186 BATut = env->IBAT[0];
1187 break;
1188 default:
1189 BATlt = env->DBAT[1];
1190 BATut = env->DBAT[0];
1191 break;
1192 }
1193
1194 for (i = 0; i < env->nb_BATs; i++) {
1195 BATu = &BATut[i];
1196 BATl = &BATlt[i];
1197 BEPIu = *BATu & 0xF0000000;
1198 BEPIl = *BATu & 0x0FFE0000;
1199 bl = (*BATu & 0x00001FFC) << 15;
1200 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1201 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1202 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1203 type == ACCESS_CODE ? "code" : "data", i,
1204 *BATu, *BATl, BEPIu, BEPIl, bl);
1205 }
1206}
1207
1208static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1209 CPUPPCState *env)
1210{
36778660 1211 PowerPCCPU *cpu = ppc_env_get_cpu(env);
886b7577
FC
1212 ppc6xx_tlb_t *tlb;
1213 target_ulong sr;
1214 int type, way, entry, i;
1215
36778660
DG
1216 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
1217 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
886b7577
FC
1218
1219 cpu_fprintf(f, "\nSegment registers:\n");
1220 for (i = 0; i < 32; i++) {
1221 sr = env->sr[i];
1222 if (sr & 0x80000000) {
1223 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1224 "CNTLR_SPEC=0x%05x\n", i,
1225 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1226 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1227 (uint32_t)(sr & 0xFFFFF));
1228 } else {
1229 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1230 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1231 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1232 (uint32_t)(sr & 0x00FFFFFF));
1233 }
1234 }
1235
1236 cpu_fprintf(f, "\nBATs:\n");
1237 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1238 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1239
1240 if (env->id_tlbs != 1) {
1241 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1242 " for code and data\n");
1243 }
1244
1245 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1246
1247 for (type = 0; type < 2; type++) {
1248 for (way = 0; way < env->nb_ways; way++) {
1249 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1250 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1251 entry++) {
1252
1253 tlb = &env->tlb.tlb6[entry];
1254 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1255 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1256 type ? "code" : "data", entry % env->nb_tlb,
1257 env->nb_tlb, way,
1258 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1259 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1260 }
1261 }
1262 }
1263}
1264
8cbbe385
BS
1265void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1266{
1267 switch (env->mmu_model) {
1268 case POWERPC_MMU_BOOKE:
1269 mmubooke_dump_mmu(f, cpu_fprintf, env);
1270 break;
1271 case POWERPC_MMU_BOOKE206:
1272 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1273 break;
886b7577
FC
1274 case POWERPC_MMU_SOFT_6xx:
1275 case POWERPC_MMU_SOFT_74xx:
1276 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1277 break;
8cbbe385
BS
1278#if defined(TARGET_PPC64)
1279 case POWERPC_MMU_64B:
aa4bb587 1280 case POWERPC_MMU_2_03:
8cbbe385 1281 case POWERPC_MMU_2_06:
ba3ecda0 1282 case POWERPC_MMU_2_06a:
aa4bb587 1283 case POWERPC_MMU_2_07:
ba3ecda0 1284 case POWERPC_MMU_2_07a:
7ef23068 1285 dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
8cbbe385
BS
1286 break;
1287#endif
1288 default:
1289 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1290 }
1291}
1292
1293static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1294 target_ulong eaddr, int rw)
1295{
1296 int in_plb, ret;
1297
1298 ctx->raddr = eaddr;
1299 ctx->prot = PAGE_READ | PAGE_EXEC;
1300 ret = 0;
1301 switch (env->mmu_model) {
8cbbe385
BS
1302 case POWERPC_MMU_SOFT_6xx:
1303 case POWERPC_MMU_SOFT_74xx:
1304 case POWERPC_MMU_SOFT_4xx:
1305 case POWERPC_MMU_REAL:
1306 case POWERPC_MMU_BOOKE:
1307 ctx->prot |= PAGE_WRITE;
1308 break;
629bd516 1309
8cbbe385
BS
1310 case POWERPC_MMU_SOFT_4xx_Z:
1311 if (unlikely(msr_pe != 0)) {
1312 /* 403 family add some particular protections,
1313 * using PBL/PBU registers for accesses with no translation.
1314 */
1315 in_plb =
1316 /* Check PLB validity */
1317 (env->pb[0] < env->pb[1] &&
1318 /* and address in plb area */
1319 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1320 (env->pb[2] < env->pb[3] &&
1321 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1322 if (in_plb ^ msr_px) {
1323 /* Access in protected area */
1324 if (rw == 1) {
1325 /* Access is not allowed */
1326 ret = -2;
1327 }
1328 } else {
1329 /* Read-write access is allowed */
1330 ctx->prot |= PAGE_WRITE;
1331 }
1332 }
1333 break;
629bd516 1334
8cbbe385 1335 default:
629bd516
DG
1336 /* Caller's checks mean we should never get here for other models */
1337 abort();
8cbbe385
BS
1338 return -1;
1339 }
1340
1341 return ret;
1342}
1343
6575c289
BS
1344static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1345 target_ulong eaddr, int rw, int access_type)
8cbbe385 1346{
a47dddd7 1347 PowerPCCPU *cpu = ppc_env_get_cpu(env);
44bc9107
DG
1348 int ret = -1;
1349 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1350 || (access_type != ACCESS_CODE && msr_dr == 0);
8cbbe385
BS
1351
1352#if 0
1353 qemu_log("%s\n", __func__);
1354#endif
44bc9107
DG
1355
1356 switch (env->mmu_model) {
44bc9107
DG
1357 case POWERPC_MMU_SOFT_6xx:
1358 case POWERPC_MMU_SOFT_74xx:
1359 if (real_mode) {
1360 ret = check_physical(env, ctx, eaddr, rw);
1361 } else {
8cbbe385
BS
1362 /* Try to find a BAT */
1363 if (env->nb_BATs != 0) {
98132796 1364 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
8cbbe385 1365 }
0480884f
DG
1366 if (ret < 0) {
1367 /* We didn't match any BAT entry or don't have BATs */
1368 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1369 }
44bc9107
DG
1370 }
1371 break;
0480884f 1372
44bc9107
DG
1373 case POWERPC_MMU_SOFT_4xx:
1374 case POWERPC_MMU_SOFT_4xx_Z:
1375 if (real_mode) {
1376 ret = check_physical(env, ctx, eaddr, rw);
1377 } else {
8cbbe385
BS
1378 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1379 rw, access_type);
44bc9107
DG
1380 }
1381 break;
1382 case POWERPC_MMU_BOOKE:
1383 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1384 rw, access_type);
1385 break;
1386 case POWERPC_MMU_BOOKE206:
1387 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
8cbbe385 1388 access_type);
44bc9107
DG
1389 break;
1390 case POWERPC_MMU_MPC8xx:
1391 /* XXX: TODO */
a47dddd7 1392 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
44bc9107
DG
1393 break;
1394 case POWERPC_MMU_REAL:
1395 if (real_mode) {
1396 ret = check_physical(env, ctx, eaddr, rw);
1397 } else {
a47dddd7 1398 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
8cbbe385 1399 }
44bc9107
DG
1400 return -1;
1401 default:
a47dddd7 1402 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
44bc9107 1403 return -1;
8cbbe385
BS
1404 }
1405#if 0
1406 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1407 __func__, eaddr, ret, ctx->raddr);
1408#endif
1409
1410 return ret;
1411}
1412
00b941e5 1413hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
8cbbe385 1414{
00b941e5
AF
1415 PowerPCCPU *cpu = POWERPC_CPU(cs);
1416 CPUPPCState *env = &cpu->env;
8cbbe385
BS
1417 mmu_ctx_t ctx;
1418
f2ad6be8
DG
1419 switch (env->mmu_model) {
1420#if defined(TARGET_PPC64)
1421 case POWERPC_MMU_64B:
aa4bb587 1422 case POWERPC_MMU_2_03:
f2ad6be8 1423 case POWERPC_MMU_2_06:
ba3ecda0 1424 case POWERPC_MMU_2_06a:
aa4bb587 1425 case POWERPC_MMU_2_07:
ba3ecda0 1426 case POWERPC_MMU_2_07a:
7ef23068 1427 return ppc_hash64_get_phys_page_debug(cpu, addr);
f2ad6be8
DG
1428#endif
1429
1430 case POWERPC_MMU_32B:
1431 case POWERPC_MMU_601:
7ef23068 1432 return ppc_hash32_get_phys_page_debug(cpu, addr);
f2ad6be8
DG
1433
1434 default:
1435 ;
1436 }
1437
8cbbe385 1438 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
b177d8b7
FC
1439
1440 /* Some MMUs have separate TLBs for code and data. If we only try an
1441 * ACCESS_INT, we may not be able to read instructions mapped by code
1442 * TLBs, so we also try a ACCESS_CODE.
1443 */
1444 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1445 ACCESS_CODE) != 0)) {
1446 return -1;
1447 }
8cbbe385
BS
1448 }
1449
1450 return ctx.raddr & TARGET_PAGE_MASK;
1451}
1452
1453static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1454 int rw)
1455{
1456 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1457 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1458 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1459 env->spr[SPR_BOOKE_MAS3] = 0;
1460 env->spr[SPR_BOOKE_MAS6] = 0;
1461 env->spr[SPR_BOOKE_MAS7] = 0;
1462
1463 /* AS */
1464 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1465 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1466 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1467 }
1468
1469 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1470 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1471
1472 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1473 case MAS4_TIDSELD_PID0:
1474 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1475 break;
1476 case MAS4_TIDSELD_PID1:
1477 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1478 break;
1479 case MAS4_TIDSELD_PID2:
1480 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1481 break;
1482 }
1483
1484 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1485
1486 /* next victim logic */
1487 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1488 env->last_way++;
1489 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1490 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1491}
1492
1493/* Perform address translation */
eb20c1c6
DG
1494static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1495 int rw, int mmu_idx)
8cbbe385 1496{
27103424 1497 CPUState *cs = CPU(ppc_env_get_cpu(env));
7ef23068 1498 PowerPCCPU *cpu = POWERPC_CPU(cs);
8cbbe385
BS
1499 mmu_ctx_t ctx;
1500 int access_type;
1501 int ret = 0;
1502
1503 if (rw == 2) {
1504 /* code access */
1505 rw = 0;
1506 access_type = ACCESS_CODE;
1507 } else {
1508 /* data access */
1509 access_type = env->access_type;
1510 }
1511 ret = get_physical_address(env, &ctx, address, rw, access_type);
1512 if (ret == 0) {
0c591eb0 1513 tlb_set_page(cs, address & TARGET_PAGE_MASK,
8cbbe385
BS
1514 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1515 mmu_idx, TARGET_PAGE_SIZE);
1516 ret = 0;
1517 } else if (ret < 0) {
27103424 1518 LOG_MMU_STATE(cs);
8cbbe385
BS
1519 if (access_type == ACCESS_CODE) {
1520 switch (ret) {
1521 case -1:
1522 /* No matches in page tables or TLB */
1523 switch (env->mmu_model) {
1524 case POWERPC_MMU_SOFT_6xx:
27103424 1525 cs->exception_index = POWERPC_EXCP_IFTLB;
8cbbe385
BS
1526 env->error_code = 1 << 18;
1527 env->spr[SPR_IMISS] = address;
1528 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1529 goto tlb_miss;
1530 case POWERPC_MMU_SOFT_74xx:
27103424 1531 cs->exception_index = POWERPC_EXCP_IFTLB;
8cbbe385
BS
1532 goto tlb_miss_74xx;
1533 case POWERPC_MMU_SOFT_4xx:
1534 case POWERPC_MMU_SOFT_4xx_Z:
27103424 1535 cs->exception_index = POWERPC_EXCP_ITLB;
8cbbe385
BS
1536 env->error_code = 0;
1537 env->spr[SPR_40x_DEAR] = address;
1538 env->spr[SPR_40x_ESR] = 0x00000000;
1539 break;
8cbbe385
BS
1540 case POWERPC_MMU_BOOKE206:
1541 booke206_update_mas_tlb_miss(env, address, rw);
1542 /* fall through */
1543 case POWERPC_MMU_BOOKE:
27103424 1544 cs->exception_index = POWERPC_EXCP_ITLB;
8cbbe385
BS
1545 env->error_code = 0;
1546 env->spr[SPR_BOOKE_DEAR] = address;
1547 return -1;
1548 case POWERPC_MMU_MPC8xx:
1549 /* XXX: TODO */
a47dddd7 1550 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
8cbbe385
BS
1551 break;
1552 case POWERPC_MMU_REAL:
a47dddd7 1553 cpu_abort(cs, "PowerPC in real mode should never raise "
8cbbe385
BS
1554 "any MMU exceptions\n");
1555 return -1;
1556 default:
a47dddd7 1557 cpu_abort(cs, "Unknown or invalid MMU model\n");
8cbbe385
BS
1558 return -1;
1559 }
1560 break;
1561 case -2:
1562 /* Access rights violation */
27103424 1563 cs->exception_index = POWERPC_EXCP_ISI;
8cbbe385
BS
1564 env->error_code = 0x08000000;
1565 break;
1566 case -3:
1567 /* No execute protection violation */
1568 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1569 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1570 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1571 }
27103424 1572 cs->exception_index = POWERPC_EXCP_ISI;
8cbbe385
BS
1573 env->error_code = 0x10000000;
1574 break;
1575 case -4:
1576 /* Direct store exception */
1577 /* No code fetch is allowed in direct-store areas */
27103424 1578 cs->exception_index = POWERPC_EXCP_ISI;
8cbbe385
BS
1579 env->error_code = 0x10000000;
1580 break;
8cbbe385
BS
1581 }
1582 } else {
1583 switch (ret) {
1584 case -1:
1585 /* No matches in page tables or TLB */
1586 switch (env->mmu_model) {
1587 case POWERPC_MMU_SOFT_6xx:
1588 if (rw == 1) {
27103424 1589 cs->exception_index = POWERPC_EXCP_DSTLB;
8cbbe385
BS
1590 env->error_code = 1 << 16;
1591 } else {
27103424 1592 cs->exception_index = POWERPC_EXCP_DLTLB;
8cbbe385
BS
1593 env->error_code = 0;
1594 }
1595 env->spr[SPR_DMISS] = address;
1596 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1597 tlb_miss:
1598 env->error_code |= ctx.key << 19;
36778660 1599 env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
7ef23068 1600 get_pteg_offset32(cpu, ctx.hash[0]);
36778660 1601 env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
7ef23068 1602 get_pteg_offset32(cpu, ctx.hash[1]);
8cbbe385
BS
1603 break;
1604 case POWERPC_MMU_SOFT_74xx:
1605 if (rw == 1) {
27103424 1606 cs->exception_index = POWERPC_EXCP_DSTLB;
8cbbe385 1607 } else {
27103424 1608 cs->exception_index = POWERPC_EXCP_DLTLB;
8cbbe385
BS
1609 }
1610 tlb_miss_74xx:
1611 /* Implement LRU algorithm */
1612 env->error_code = ctx.key << 19;
1613 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1614 ((env->last_way + 1) & (env->nb_ways - 1));
1615 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1616 break;
1617 case POWERPC_MMU_SOFT_4xx:
1618 case POWERPC_MMU_SOFT_4xx_Z:
27103424 1619 cs->exception_index = POWERPC_EXCP_DTLB;
8cbbe385
BS
1620 env->error_code = 0;
1621 env->spr[SPR_40x_DEAR] = address;
1622 if (rw) {
1623 env->spr[SPR_40x_ESR] = 0x00800000;
1624 } else {
1625 env->spr[SPR_40x_ESR] = 0x00000000;
1626 }
1627 break;
8cbbe385
BS
1628 case POWERPC_MMU_MPC8xx:
1629 /* XXX: TODO */
a47dddd7 1630 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
8cbbe385
BS
1631 break;
1632 case POWERPC_MMU_BOOKE206:
1633 booke206_update_mas_tlb_miss(env, address, rw);
1634 /* fall through */
1635 case POWERPC_MMU_BOOKE:
27103424 1636 cs->exception_index = POWERPC_EXCP_DTLB;
8cbbe385
BS
1637 env->error_code = 0;
1638 env->spr[SPR_BOOKE_DEAR] = address;
1639 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1640 return -1;
1641 case POWERPC_MMU_REAL:
a47dddd7 1642 cpu_abort(cs, "PowerPC in real mode should never raise "
8cbbe385
BS
1643 "any MMU exceptions\n");
1644 return -1;
1645 default:
a47dddd7 1646 cpu_abort(cs, "Unknown or invalid MMU model\n");
8cbbe385
BS
1647 return -1;
1648 }
1649 break;
1650 case -2:
1651 /* Access rights violation */
27103424 1652 cs->exception_index = POWERPC_EXCP_DSI;
8cbbe385
BS
1653 env->error_code = 0;
1654 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1655 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1656 env->spr[SPR_40x_DEAR] = address;
1657 if (rw) {
1658 env->spr[SPR_40x_ESR] |= 0x00800000;
1659 }
1660 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1661 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1662 env->spr[SPR_BOOKE_DEAR] = address;
1663 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1664 } else {
1665 env->spr[SPR_DAR] = address;
1666 if (rw == 1) {
1667 env->spr[SPR_DSISR] = 0x0A000000;
1668 } else {
1669 env->spr[SPR_DSISR] = 0x08000000;
1670 }
1671 }
1672 break;
1673 case -4:
1674 /* Direct store exception */
1675 switch (access_type) {
1676 case ACCESS_FLOAT:
1677 /* Floating point load/store */
27103424 1678 cs->exception_index = POWERPC_EXCP_ALIGN;
8cbbe385
BS
1679 env->error_code = POWERPC_EXCP_ALIGN_FP;
1680 env->spr[SPR_DAR] = address;
1681 break;
1682 case ACCESS_RES:
1683 /* lwarx, ldarx or stwcx. */
27103424 1684 cs->exception_index = POWERPC_EXCP_DSI;
8cbbe385
BS
1685 env->error_code = 0;
1686 env->spr[SPR_DAR] = address;
1687 if (rw == 1) {
1688 env->spr[SPR_DSISR] = 0x06000000;
1689 } else {
1690 env->spr[SPR_DSISR] = 0x04000000;
1691 }
1692 break;
1693 case ACCESS_EXT:
1694 /* eciwx or ecowx */
27103424 1695 cs->exception_index = POWERPC_EXCP_DSI;
8cbbe385
BS
1696 env->error_code = 0;
1697 env->spr[SPR_DAR] = address;
1698 if (rw == 1) {
1699 env->spr[SPR_DSISR] = 0x06100000;
1700 } else {
1701 env->spr[SPR_DSISR] = 0x04100000;
1702 }
1703 break;
1704 default:
1705 printf("DSI: invalid exception (%d)\n", ret);
27103424 1706 cs->exception_index = POWERPC_EXCP_PROGRAM;
8cbbe385
BS
1707 env->error_code =
1708 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1709 env->spr[SPR_DAR] = address;
1710 break;
1711 }
1712 break;
8cbbe385
BS
1713 }
1714 }
1715#if 0
1716 printf("%s: set exception to %d %02x\n", __func__,
27103424 1717 cs->exception, env->error_code);
8cbbe385
BS
1718#endif
1719 ret = 1;
1720 }
1721
1722 return ret;
1723}
1724
1725/*****************************************************************************/
1726/* BATs management */
1727#if !defined(FLUSH_ALL_TLBS)
1728static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1729 target_ulong mask)
1730{
31b030d4 1731 CPUState *cs = CPU(ppc_env_get_cpu(env));
8cbbe385
BS
1732 target_ulong base, end, page;
1733
1734 base = BATu & ~0x0001FFFF;
1735 end = base + mask + 0x00020000;
1736 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1737 TARGET_FMT_lx ")\n", base, end, mask);
1738 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
31b030d4 1739 tlb_flush_page(cs, page);
8cbbe385
BS
1740 }
1741 LOG_BATS("Flush done\n");
1742}
1743#endif
1744
1745static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1746 target_ulong value)
1747{
1748 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1749 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1750}
1751
9aa5b158 1752void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
8cbbe385
BS
1753{
1754 target_ulong mask;
9207113d
MCA
1755#if defined(FLUSH_ALL_TLBS)
1756 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1757#endif
8cbbe385
BS
1758
1759 dump_store_bat(env, 'I', 0, nr, value);
1760 if (env->IBAT[0][nr] != value) {
1761 mask = (value << 15) & 0x0FFE0000UL;
1762#if !defined(FLUSH_ALL_TLBS)
1763 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1764#endif
1765 /* When storing valid upper BAT, mask BEPI and BRPN
1766 * and invalidate all TLBs covered by this BAT
1767 */
1768 mask = (value << 15) & 0x0FFE0000UL;
1769 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1770 (value & ~0x0001FFFFUL & ~mask);
1771 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1772 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1773#if !defined(FLUSH_ALL_TLBS)
1774 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1775#else
d10eb08f 1776 tlb_flush(CPU(cpu));
8cbbe385
BS
1777#endif
1778 }
1779}
1780
9aa5b158 1781void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
8cbbe385
BS
1782{
1783 dump_store_bat(env, 'I', 1, nr, value);
1784 env->IBAT[1][nr] = value;
1785}
1786
9aa5b158 1787void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
8cbbe385
BS
1788{
1789 target_ulong mask;
9207113d
MCA
1790#if defined(FLUSH_ALL_TLBS)
1791 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1792#endif
8cbbe385
BS
1793
1794 dump_store_bat(env, 'D', 0, nr, value);
1795 if (env->DBAT[0][nr] != value) {
1796 /* When storing valid upper BAT, mask BEPI and BRPN
1797 * and invalidate all TLBs covered by this BAT
1798 */
1799 mask = (value << 15) & 0x0FFE0000UL;
1800#if !defined(FLUSH_ALL_TLBS)
1801 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1802#endif
1803 mask = (value << 15) & 0x0FFE0000UL;
1804 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1805 (value & ~0x0001FFFFUL & ~mask);
1806 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1807 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1808#if !defined(FLUSH_ALL_TLBS)
1809 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1810#else
d10eb08f 1811 tlb_flush(CPU(cpu));
8cbbe385
BS
1812#endif
1813 }
1814}
1815
9aa5b158 1816void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
8cbbe385
BS
1817{
1818 dump_store_bat(env, 'D', 1, nr, value);
1819 env->DBAT[1][nr] = value;
1820}
1821
9aa5b158 1822void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
8cbbe385
BS
1823{
1824 target_ulong mask;
1825#if defined(FLUSH_ALL_TLBS)
9207113d 1826 PowerPCCPU *cpu = ppc_env_get_cpu(env);
8cbbe385
BS
1827 int do_inval;
1828#endif
1829
1830 dump_store_bat(env, 'I', 0, nr, value);
1831 if (env->IBAT[0][nr] != value) {
1832#if defined(FLUSH_ALL_TLBS)
1833 do_inval = 0;
1834#endif
1835 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1836 if (env->IBAT[1][nr] & 0x40) {
1837 /* Invalidate BAT only if it is valid */
1838#if !defined(FLUSH_ALL_TLBS)
1839 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1840#else
1841 do_inval = 1;
1842#endif
1843 }
1844 /* When storing valid upper BAT, mask BEPI and BRPN
1845 * and invalidate all TLBs covered by this BAT
1846 */
1847 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1848 (value & ~0x0001FFFFUL & ~mask);
1849 env->DBAT[0][nr] = env->IBAT[0][nr];
1850 if (env->IBAT[1][nr] & 0x40) {
1851#if !defined(FLUSH_ALL_TLBS)
1852 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1853#else
1854 do_inval = 1;
1855#endif
1856 }
1857#if defined(FLUSH_ALL_TLBS)
1858 if (do_inval) {
d10eb08f 1859 tlb_flush(CPU(cpu));
8cbbe385
BS
1860 }
1861#endif
1862 }
1863}
1864
9aa5b158 1865void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
8cbbe385 1866{
cca48a93 1867#if !defined(FLUSH_ALL_TLBS)
8cbbe385 1868 target_ulong mask;
cca48a93 1869#else
9207113d 1870 PowerPCCPU *cpu = ppc_env_get_cpu(env);
8cbbe385
BS
1871 int do_inval;
1872#endif
1873
1874 dump_store_bat(env, 'I', 1, nr, value);
1875 if (env->IBAT[1][nr] != value) {
1876#if defined(FLUSH_ALL_TLBS)
1877 do_inval = 0;
1878#endif
1879 if (env->IBAT[1][nr] & 0x40) {
1880#if !defined(FLUSH_ALL_TLBS)
1881 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1882 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1883#else
1884 do_inval = 1;
1885#endif
1886 }
1887 if (value & 0x40) {
1888#if !defined(FLUSH_ALL_TLBS)
1889 mask = (value << 17) & 0x0FFE0000UL;
1890 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1891#else
1892 do_inval = 1;
1893#endif
1894 }
1895 env->IBAT[1][nr] = value;
1896 env->DBAT[1][nr] = value;
1897#if defined(FLUSH_ALL_TLBS)
1898 if (do_inval) {
d10eb08f 1899 tlb_flush(CPU(cpu));
8cbbe385
BS
1900 }
1901#endif
1902 }
1903}
1904
1905/*****************************************************************************/
1906/* TLB management */
1907void ppc_tlb_invalidate_all(CPUPPCState *env)
1908{
a47dddd7
AF
1909 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1910
8cbbe385
BS
1911 switch (env->mmu_model) {
1912 case POWERPC_MMU_SOFT_6xx:
1913 case POWERPC_MMU_SOFT_74xx:
1914 ppc6xx_tlb_invalidate_all(env);
1915 break;
1916 case POWERPC_MMU_SOFT_4xx:
1917 case POWERPC_MMU_SOFT_4xx_Z:
1918 ppc4xx_tlb_invalidate_all(env);
1919 break;
1920 case POWERPC_MMU_REAL:
a47dddd7 1921 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
8cbbe385
BS
1922 break;
1923 case POWERPC_MMU_MPC8xx:
1924 /* XXX: TODO */
a47dddd7 1925 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
8cbbe385
BS
1926 break;
1927 case POWERPC_MMU_BOOKE:
d10eb08f 1928 tlb_flush(CPU(cpu));
8cbbe385
BS
1929 break;
1930 case POWERPC_MMU_BOOKE206:
1931 booke206_flush_tlb(env, -1, 0);
1932 break;
1933 case POWERPC_MMU_32B:
1934 case POWERPC_MMU_601:
1935#if defined(TARGET_PPC64)
8cbbe385 1936 case POWERPC_MMU_64B:
aa4bb587 1937 case POWERPC_MMU_2_03:
8cbbe385 1938 case POWERPC_MMU_2_06:
ba3ecda0 1939 case POWERPC_MMU_2_06a:
aa4bb587 1940 case POWERPC_MMU_2_07:
ba3ecda0 1941 case POWERPC_MMU_2_07a:
86cf1e9f 1942 case POWERPC_MMU_3_00:
8cbbe385 1943#endif /* defined(TARGET_PPC64) */
c5a8d8f3 1944 env->tlb_need_flush = 0;
d10eb08f 1945 tlb_flush(CPU(cpu));
8cbbe385
BS
1946 break;
1947 default:
1948 /* XXX: TODO */
706d6467 1949 cpu_abort(CPU(cpu), "Unknown MMU model %d\n", env->mmu_model);
8cbbe385
BS
1950 break;
1951 }
1952}
1953
1954void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1955{
1956#if !defined(FLUSH_ALL_TLBS)
1957 addr &= TARGET_PAGE_MASK;
1958 switch (env->mmu_model) {
1959 case POWERPC_MMU_SOFT_6xx:
1960 case POWERPC_MMU_SOFT_74xx:
1961 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1962 if (env->id_tlbs == 1) {
1963 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1964 }
1965 break;
8cbbe385
BS
1966 case POWERPC_MMU_32B:
1967 case POWERPC_MMU_601:
c5a8d8f3
BH
1968 /* Actual CPUs invalidate entire congruence classes based on the
1969 * geometry of their TLBs and some OSes take that into account,
1970 * we just mark the TLB to be flushed later (context synchronizing
1971 * event or sync instruction on 32-bit).
3dcfb74f 1972 */
a8a6d53e 1973 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
8cbbe385
BS
1974 break;
1975#if defined(TARGET_PPC64)
8cbbe385 1976 case POWERPC_MMU_64B:
aa4bb587 1977 case POWERPC_MMU_2_03:
8cbbe385 1978 case POWERPC_MMU_2_06:
ba3ecda0 1979 case POWERPC_MMU_2_06a:
aa4bb587 1980 case POWERPC_MMU_2_07:
ba3ecda0 1981 case POWERPC_MMU_2_07a:
86cf1e9f 1982 case POWERPC_MMU_3_00:
8cbbe385
BS
1983 /* tlbie invalidate TLBs for all segments */
1984 /* XXX: given the fact that there are too many segments to invalidate,
1985 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
1986 * we just invalidate all TLBs
1987 */
a8a6d53e 1988 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
8cbbe385
BS
1989 break;
1990#endif /* defined(TARGET_PPC64) */
1991 default:
041d95f4
DG
1992 /* Should never reach here with other MMU models */
1993 assert(0);
8cbbe385
BS
1994 }
1995#else
1996 ppc_tlb_invalidate_all(env);
1997#endif
1998}
1999
2000/*****************************************************************************/
2001/* Special registers manipulation */
8cbbe385
BS
2002void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2003{
e57ca75c 2004 PowerPCCPU *cpu = ppc_env_get_cpu(env);
339aaf5b 2005 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
e57ca75c 2006 assert(!cpu->vhyp);
8cbbe385 2007#if defined(TARGET_PPC64)
2828c4cd 2008 if (env->mmu_model & POWERPC_MMU_64) {
e5c0d3ce
DG
2009 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2010 Error *local_err = NULL;
8cbbe385 2011
e5c0d3ce
DG
2012 ppc_hash64_set_sdr1(cpu, value, &local_err);
2013 if (local_err) {
2014 error_report_err(local_err);
2015 error_free(local_err);
36778660 2016 return;
8cbbe385 2017 }
8cbbe385 2018 }
36778660
DG
2019#endif /* defined(TARGET_PPC64) */
2020 /* FIXME: Should check for valid HTABMASK values in 32-bit case */
2021 env->spr[SPR_SDR1] = value;
8cbbe385
BS
2022}
2023
9aa5b158
BS
2024/* Segment registers load and store */
2025target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
8cbbe385 2026{
9aa5b158
BS
2027#if defined(TARGET_PPC64)
2028 if (env->mmu_model & POWERPC_MMU_64) {
2029 /* XXX */
2030 return 0;
2031 }
8cbbe385 2032#endif
9aa5b158
BS
2033 return env->sr[sr_num];
2034}
8cbbe385 2035
9aa5b158 2036void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
8cbbe385 2037{
339aaf5b
AP
2038 qemu_log_mask(CPU_LOG_MMU,
2039 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
9aa5b158 2040 (int)srnum, value, env->sr[srnum]);
8cbbe385
BS
2041#if defined(TARGET_PPC64)
2042 if (env->mmu_model & POWERPC_MMU_64) {
c5a8d8f3 2043 PowerPCCPU *cpu = ppc_env_get_cpu(env);
bcd81230 2044 uint64_t esid, vsid;
8cbbe385
BS
2045
2046 /* ESID = srnum */
bcd81230 2047 esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
8cbbe385
BS
2048
2049 /* VSID = VSID */
bcd81230 2050 vsid = (value & 0xfffffff) << 12;
8cbbe385 2051 /* flags = flags */
bcd81230 2052 vsid |= ((value >> 27) & 0xf) << 8;
8cbbe385 2053
bcd81230 2054 ppc_store_slb(cpu, srnum, esid, vsid);
8cbbe385
BS
2055 } else
2056#endif
2057 if (env->sr[srnum] != value) {
2058 env->sr[srnum] = value;
2059/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2060 flusing the whole TLB. */
2061#if !defined(FLUSH_ALL_TLBS) && 0
2062 {
2063 target_ulong page, end;
2064 /* Invalidate 256 MB of virtual memory */
2065 page = (16 << 20) * srnum;
2066 end = page + (16 << 20);
2067 for (; page != end; page += TARGET_PAGE_SIZE) {
00c8cb0a 2068 tlb_flush_page(CPU(cpu), page);
8cbbe385
BS
2069 }
2070 }
2071#else
a8a6d53e 2072 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
8cbbe385
BS
2073#endif
2074 }
2075}
8cbbe385 2076
ec19c4d1 2077/* TLB management */
c6c7cf05 2078void helper_tlbia(CPUPPCState *env)
ec19c4d1
BS
2079{
2080 ppc_tlb_invalidate_all(env);
2081}
2082
c6c7cf05 2083void helper_tlbie(CPUPPCState *env, target_ulong addr)
ec19c4d1
BS
2084{
2085 ppc_tlb_invalidate_one(env, addr);
2086}
2087
4693364f
DG
2088void helper_tlbiva(CPUPPCState *env, target_ulong addr)
2089{
2090 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2091
2092 /* tlbiva instruction only exists on BookE */
2093 assert(env->mmu_model == POWERPC_MMU_BOOKE);
2094 /* XXX: TODO */
2095 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
2096}
2097
ec19c4d1
BS
2098/* Software driven TLBs management */
2099/* PowerPC 602/603 software TLB load instructions helpers */
c6c7cf05 2100static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
ec19c4d1
BS
2101{
2102 target_ulong RPN, CMP, EPN;
2103 int way;
2104
2105 RPN = env->spr[SPR_RPA];
2106 if (is_code) {
2107 CMP = env->spr[SPR_ICMP];
2108 EPN = env->spr[SPR_IMISS];
2109 } else {
2110 CMP = env->spr[SPR_DCMP];
2111 EPN = env->spr[SPR_DMISS];
2112 }
2113 way = (env->spr[SPR_SRR1] >> 17) & 1;
2114 (void)EPN; /* avoid a compiler warning */
2115 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2116 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2117 RPN, way);
2118 /* Store this TLB */
2119 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2120 way, is_code, CMP, RPN);
2121}
2122
c6c7cf05 2123void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
ec19c4d1 2124{
c6c7cf05 2125 do_6xx_tlb(env, EPN, 0);
ec19c4d1
BS
2126}
2127
c6c7cf05 2128void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
ec19c4d1 2129{
c6c7cf05 2130 do_6xx_tlb(env, EPN, 1);
ec19c4d1
BS
2131}
2132
2133/* PowerPC 74xx software TLB load instructions helpers */
c6c7cf05 2134static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
ec19c4d1
BS
2135{
2136 target_ulong RPN, CMP, EPN;
2137 int way;
2138
2139 RPN = env->spr[SPR_PTELO];
2140 CMP = env->spr[SPR_PTEHI];
2141 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2142 way = env->spr[SPR_TLBMISS] & 0x3;
2143 (void)EPN; /* avoid a compiler warning */
2144 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2145 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2146 RPN, way);
2147 /* Store this TLB */
2148 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2149 way, is_code, CMP, RPN);
2150}
2151
c6c7cf05 2152void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
ec19c4d1 2153{
c6c7cf05 2154 do_74xx_tlb(env, EPN, 0);
ec19c4d1
BS
2155}
2156
c6c7cf05 2157void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
ec19c4d1 2158{
c6c7cf05 2159 do_74xx_tlb(env, EPN, 1);
ec19c4d1
BS
2160}
2161
2162/*****************************************************************************/
2163/* PowerPC 601 specific instructions (POWER bridge) */
2164
c6c7cf05 2165target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
ec19c4d1
BS
2166{
2167 mmu_ctx_t ctx;
2168 int nb_BATs;
2169 target_ulong ret = 0;
2170
2171 /* We don't have to generate many instances of this instruction,
2172 * as rac is supervisor only.
2173 */
2174 /* XXX: FIX THIS: Pretend we have no BAT */
2175 nb_BATs = env->nb_BATs;
2176 env->nb_BATs = 0;
2177 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2178 ret = ctx.raddr;
2179 }
2180 env->nb_BATs = nb_BATs;
2181 return ret;
2182}
2183
2184static inline target_ulong booke_tlb_to_page_size(int size)
2185{
2186 return 1024 << (2 * size);
2187}
2188
2189static inline int booke_page_size_to_tlb(target_ulong page_size)
2190{
2191 int size;
2192
2193 switch (page_size) {
2194 case 0x00000400UL:
2195 size = 0x0;
2196 break;
2197 case 0x00001000UL:
2198 size = 0x1;
2199 break;
2200 case 0x00004000UL:
2201 size = 0x2;
2202 break;
2203 case 0x00010000UL:
2204 size = 0x3;
2205 break;
2206 case 0x00040000UL:
2207 size = 0x4;
2208 break;
2209 case 0x00100000UL:
2210 size = 0x5;
2211 break;
2212 case 0x00400000UL:
2213 size = 0x6;
2214 break;
2215 case 0x01000000UL:
2216 size = 0x7;
2217 break;
2218 case 0x04000000UL:
2219 size = 0x8;
2220 break;
2221 case 0x10000000UL:
2222 size = 0x9;
2223 break;
2224 case 0x40000000UL:
2225 size = 0xA;
2226 break;
2227#if defined(TARGET_PPC64)
2228 case 0x000100000000ULL:
2229 size = 0xB;
2230 break;
2231 case 0x000400000000ULL:
2232 size = 0xC;
2233 break;
2234 case 0x001000000000ULL:
2235 size = 0xD;
2236 break;
2237 case 0x004000000000ULL:
2238 size = 0xE;
2239 break;
2240 case 0x010000000000ULL:
2241 size = 0xF;
2242 break;
2243#endif
2244 default:
2245 size = -1;
2246 break;
2247 }
2248
2249 return size;
2250}
2251
2252/* Helpers for 4xx TLB management */
2253#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2254
2255#define PPC4XX_TLBHI_V 0x00000040
2256#define PPC4XX_TLBHI_E 0x00000020
2257#define PPC4XX_TLBHI_SIZE_MIN 0
2258#define PPC4XX_TLBHI_SIZE_MAX 7
2259#define PPC4XX_TLBHI_SIZE_DEFAULT 1
2260#define PPC4XX_TLBHI_SIZE_SHIFT 7
2261#define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2262
2263#define PPC4XX_TLBLO_EX 0x00000200
2264#define PPC4XX_TLBLO_WR 0x00000100
2265#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2266#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2267
c6c7cf05 2268target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
ec19c4d1
BS
2269{
2270 ppcemb_tlb_t *tlb;
2271 target_ulong ret;
2272 int size;
2273
2274 entry &= PPC4XX_TLB_ENTRY_MASK;
2275 tlb = &env->tlb.tlbe[entry];
2276 ret = tlb->EPN;
2277 if (tlb->prot & PAGE_VALID) {
2278 ret |= PPC4XX_TLBHI_V;
2279 }
2280 size = booke_page_size_to_tlb(tlb->size);
2281 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2282 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2283 }
2284 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2285 env->spr[SPR_40x_PID] = tlb->PID;
2286 return ret;
2287}
2288
c6c7cf05 2289target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
ec19c4d1
BS
2290{
2291 ppcemb_tlb_t *tlb;
2292 target_ulong ret;
2293
2294 entry &= PPC4XX_TLB_ENTRY_MASK;
2295 tlb = &env->tlb.tlbe[entry];
2296 ret = tlb->RPN;
2297 if (tlb->prot & PAGE_EXEC) {
2298 ret |= PPC4XX_TLBLO_EX;
2299 }
2300 if (tlb->prot & PAGE_WRITE) {
2301 ret |= PPC4XX_TLBLO_WR;
2302 }
2303 return ret;
2304}
2305
c6c7cf05
BS
2306void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2307 target_ulong val)
ec19c4d1 2308{
a47dddd7 2309 PowerPCCPU *cpu = ppc_env_get_cpu(env);
31b030d4 2310 CPUState *cs = CPU(cpu);
ec19c4d1
BS
2311 ppcemb_tlb_t *tlb;
2312 target_ulong page, end;
2313
2314 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2315 val);
2316 entry &= PPC4XX_TLB_ENTRY_MASK;
2317 tlb = &env->tlb.tlbe[entry];
2318 /* Invalidate previous TLB (if it's valid) */
2319 if (tlb->prot & PAGE_VALID) {
2320 end = tlb->EPN + tlb->size;
2321 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2322 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2323 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
31b030d4 2324 tlb_flush_page(cs, page);
ec19c4d1
BS
2325 }
2326 }
2327 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2328 & PPC4XX_TLBHI_SIZE_MASK);
2329 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2330 * If this ever occurs, one should use the ppcemb target instead
2331 * of the ppc or ppc64 one
2332 */
2333 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
31b030d4 2334 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
ec19c4d1
BS
2335 "are not supported (%d)\n",
2336 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2337 }
2338 tlb->EPN = val & ~(tlb->size - 1);
2339 if (val & PPC4XX_TLBHI_V) {
2340 tlb->prot |= PAGE_VALID;
2341 if (val & PPC4XX_TLBHI_E) {
2342 /* XXX: TO BE FIXED */
31b030d4 2343 cpu_abort(cs,
ec19c4d1
BS
2344 "Little-endian TLB entries are not supported by now\n");
2345 }
2346 } else {
2347 tlb->prot &= ~PAGE_VALID;
2348 }
2349 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2350 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2351 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2352 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2353 tlb->prot & PAGE_READ ? 'r' : '-',
2354 tlb->prot & PAGE_WRITE ? 'w' : '-',
2355 tlb->prot & PAGE_EXEC ? 'x' : '-',
2356 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2357 /* Invalidate new TLB (if valid) */
2358 if (tlb->prot & PAGE_VALID) {
2359 end = tlb->EPN + tlb->size;
2360 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2361 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2362 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
31b030d4 2363 tlb_flush_page(cs, page);
ec19c4d1
BS
2364 }
2365 }
2366}
2367
c6c7cf05
BS
2368void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2369 target_ulong val)
ec19c4d1
BS
2370{
2371 ppcemb_tlb_t *tlb;
2372
2373 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2374 val);
2375 entry &= PPC4XX_TLB_ENTRY_MASK;
2376 tlb = &env->tlb.tlbe[entry];
2377 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2378 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2379 tlb->prot = PAGE_READ;
2380 if (val & PPC4XX_TLBLO_EX) {
2381 tlb->prot |= PAGE_EXEC;
2382 }
2383 if (val & PPC4XX_TLBLO_WR) {
2384 tlb->prot |= PAGE_WRITE;
2385 }
2386 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2387 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2388 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2389 tlb->prot & PAGE_READ ? 'r' : '-',
2390 tlb->prot & PAGE_WRITE ? 'w' : '-',
2391 tlb->prot & PAGE_EXEC ? 'x' : '-',
2392 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2393}
2394
c6c7cf05 2395target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
2396{
2397 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2398}
2399
2400/* PowerPC 440 TLB management */
c6c7cf05
BS
2401void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2402 target_ulong value)
ec19c4d1 2403{
00c8cb0a 2404 PowerPCCPU *cpu = ppc_env_get_cpu(env);
ec19c4d1
BS
2405 ppcemb_tlb_t *tlb;
2406 target_ulong EPN, RPN, size;
2407 int do_flush_tlbs;
2408
2409 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2410 __func__, word, (int)entry, value);
2411 do_flush_tlbs = 0;
2412 entry &= 0x3F;
2413 tlb = &env->tlb.tlbe[entry];
2414 switch (word) {
2415 default:
2416 /* Just here to please gcc */
2417 case 0:
2418 EPN = value & 0xFFFFFC00;
2419 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2420 do_flush_tlbs = 1;
2421 }
2422 tlb->EPN = EPN;
2423 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2424 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2425 do_flush_tlbs = 1;
2426 }
2427 tlb->size = size;
2428 tlb->attr &= ~0x1;
2429 tlb->attr |= (value >> 8) & 1;
2430 if (value & 0x200) {
2431 tlb->prot |= PAGE_VALID;
2432 } else {
2433 if (tlb->prot & PAGE_VALID) {
2434 tlb->prot &= ~PAGE_VALID;
2435 do_flush_tlbs = 1;
2436 }
2437 }
2438 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2439 if (do_flush_tlbs) {
d10eb08f 2440 tlb_flush(CPU(cpu));
ec19c4d1
BS
2441 }
2442 break;
2443 case 1:
2444 RPN = value & 0xFFFFFC0F;
2445 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
d10eb08f 2446 tlb_flush(CPU(cpu));
ec19c4d1
BS
2447 }
2448 tlb->RPN = RPN;
2449 break;
2450 case 2:
2451 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2452 tlb->prot = tlb->prot & PAGE_VALID;
2453 if (value & 0x1) {
2454 tlb->prot |= PAGE_READ << 4;
2455 }
2456 if (value & 0x2) {
2457 tlb->prot |= PAGE_WRITE << 4;
2458 }
2459 if (value & 0x4) {
2460 tlb->prot |= PAGE_EXEC << 4;
2461 }
2462 if (value & 0x8) {
2463 tlb->prot |= PAGE_READ;
2464 }
2465 if (value & 0x10) {
2466 tlb->prot |= PAGE_WRITE;
2467 }
2468 if (value & 0x20) {
2469 tlb->prot |= PAGE_EXEC;
2470 }
2471 break;
2472 }
2473}
2474
c6c7cf05
BS
2475target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2476 target_ulong entry)
ec19c4d1
BS
2477{
2478 ppcemb_tlb_t *tlb;
2479 target_ulong ret;
2480 int size;
2481
2482 entry &= 0x3F;
2483 tlb = &env->tlb.tlbe[entry];
2484 switch (word) {
2485 default:
2486 /* Just here to please gcc */
2487 case 0:
2488 ret = tlb->EPN;
2489 size = booke_page_size_to_tlb(tlb->size);
2490 if (size < 0 || size > 0xF) {
2491 size = 1;
2492 }
2493 ret |= size << 4;
2494 if (tlb->attr & 0x1) {
2495 ret |= 0x100;
2496 }
2497 if (tlb->prot & PAGE_VALID) {
2498 ret |= 0x200;
2499 }
2500 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2501 env->spr[SPR_440_MMUCR] |= tlb->PID;
2502 break;
2503 case 1:
2504 ret = tlb->RPN;
2505 break;
2506 case 2:
2507 ret = tlb->attr & ~0x1;
2508 if (tlb->prot & (PAGE_READ << 4)) {
2509 ret |= 0x1;
2510 }
2511 if (tlb->prot & (PAGE_WRITE << 4)) {
2512 ret |= 0x2;
2513 }
2514 if (tlb->prot & (PAGE_EXEC << 4)) {
2515 ret |= 0x4;
2516 }
2517 if (tlb->prot & PAGE_READ) {
2518 ret |= 0x8;
2519 }
2520 if (tlb->prot & PAGE_WRITE) {
2521 ret |= 0x10;
2522 }
2523 if (tlb->prot & PAGE_EXEC) {
2524 ret |= 0x20;
2525 }
2526 break;
2527 }
2528 return ret;
2529}
2530
c6c7cf05 2531target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
2532{
2533 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2534}
2535
2536/* PowerPC BookE 2.06 TLB management */
2537
2538static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2539{
a47dddd7 2540 PowerPCCPU *cpu = ppc_env_get_cpu(env);
ec19c4d1
BS
2541 uint32_t tlbncfg = 0;
2542 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2543 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2544 int tlb;
2545
2546 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2547 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2548
2549 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
a47dddd7 2550 cpu_abort(CPU(cpu), "we don't support HES yet\n");
ec19c4d1
BS
2551 }
2552
2553 return booke206_get_tlbm(env, tlb, ea, esel);
2554}
2555
c6c7cf05 2556void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
ec19c4d1 2557{
00c8cb0a
AF
2558 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2559
ec19c4d1
BS
2560 env->spr[pidn] = pid;
2561 /* changing PIDs mean we're in a different address space now */
d10eb08f 2562 tlb_flush(CPU(cpu));
ec19c4d1
BS
2563}
2564
c6c7cf05 2565void helper_booke206_tlbwe(CPUPPCState *env)
ec19c4d1 2566{
a47dddd7 2567 PowerPCCPU *cpu = ppc_env_get_cpu(env);
ec19c4d1
BS
2568 uint32_t tlbncfg, tlbn;
2569 ppcmas_tlb_t *tlb;
2570 uint32_t size_tlb, size_ps;
77c2cf33
FC
2571 target_ulong mask;
2572
ec19c4d1
BS
2573
2574 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2575 case MAS0_WQ_ALWAYS:
2576 /* good to go, write that entry */
2577 break;
2578 case MAS0_WQ_COND:
2579 /* XXX check if reserved */
2580 if (0) {
2581 return;
2582 }
2583 break;
2584 case MAS0_WQ_CLR_RSRV:
2585 /* XXX clear entry */
2586 return;
2587 default:
2588 /* no idea what to do */
2589 return;
2590 }
2591
2592 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2593 !msr_gs) {
2594 /* XXX we don't support direct LRAT setting yet */
2595 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2596 return;
2597 }
2598
2599 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2600 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2601
2602 tlb = booke206_cur_tlb(env);
2603
2604 if (!tlb) {
8c8966e2
BH
2605 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
2606 POWERPC_EXCP_INVAL |
2607 POWERPC_EXCP_INVAL_INVAL, GETPC());
ec19c4d1
BS
2608 }
2609
2610 /* check that we support the targeted size */
2611 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2612 size_ps = booke206_tlbnps(env, tlbn);
2613 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2614 !(size_ps & (1 << size_tlb))) {
8c8966e2
BH
2615 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
2616 POWERPC_EXCP_INVAL |
2617 POWERPC_EXCP_INVAL_INVAL, GETPC());
ec19c4d1
BS
2618 }
2619
2620 if (msr_gs) {
a47dddd7 2621 cpu_abort(CPU(cpu), "missing HV implementation\n");
ec19c4d1
BS
2622 }
2623 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2624 env->spr[SPR_BOOKE_MAS3];
2625 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2626
2627 /* MAV 1.0 only */
2628 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2629 /* force !AVAIL TLB entries to correct page size */
2630 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2631 /* XXX can be configured in MMUCSR0 */
2632 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2633 }
2634
77c2cf33
FC
2635 /* Make a mask from TLB size to discard invalid bits in EPN field */
2636 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2637 /* Add a mask for page attributes */
2638 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2639
2640 if (!msr_cm) {
2641 /* Executing a tlbwe instruction in 32-bit mode will set
2642 * bits 0:31 of the TLB EPN field to zero.
2643 */
2644 mask &= 0xffffffff;
2645 }
2646
2647 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
ec19c4d1
BS
2648
2649 if (!(tlbncfg & TLBnCFG_IPROT)) {
2650 /* no IPROT supported by TLB */
2651 tlb->mas1 &= ~MAS1_IPROT;
2652 }
2653
2654 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
31b030d4 2655 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
ec19c4d1 2656 } else {
d10eb08f 2657 tlb_flush(CPU(cpu));
ec19c4d1
BS
2658 }
2659}
2660
2661static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2662{
2663 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2664 int way = booke206_tlbm_to_way(env, tlb);
2665
2666 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2667 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2668 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2669
2670 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2671 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2672 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2673 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2674}
2675
c6c7cf05 2676void helper_booke206_tlbre(CPUPPCState *env)
ec19c4d1
BS
2677{
2678 ppcmas_tlb_t *tlb = NULL;
2679
2680 tlb = booke206_cur_tlb(env);
2681 if (!tlb) {
2682 env->spr[SPR_BOOKE_MAS1] = 0;
2683 } else {
2684 booke206_tlb_to_mas(env, tlb);
2685 }
2686}
2687
c6c7cf05 2688void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
2689{
2690 ppcmas_tlb_t *tlb = NULL;
2691 int i, j;
a8170e5e 2692 hwaddr raddr;
ec19c4d1
BS
2693 uint32_t spid, sas;
2694
2695 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2696 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2697
2698 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2699 int ways = booke206_tlb_ways(env, i);
2700
2701 for (j = 0; j < ways; j++) {
2702 tlb = booke206_get_tlbm(env, i, address, j);
2703
2704 if (!tlb) {
2705 continue;
2706 }
2707
2708 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2709 continue;
2710 }
2711
2712 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2713 continue;
2714 }
2715
2716 booke206_tlb_to_mas(env, tlb);
2717 return;
2718 }
2719 }
2720
2721 /* no entry found, fill with defaults */
2722 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2723 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2724 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2725 env->spr[SPR_BOOKE_MAS3] = 0;
2726 env->spr[SPR_BOOKE_MAS7] = 0;
2727
2728 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2729 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2730 }
2731
2732 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2733 << MAS1_TID_SHIFT;
2734
2735 /* next victim logic */
2736 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2737 env->last_way++;
2738 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2739 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2740}
2741
2742static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2743 uint32_t ea)
2744{
2745 int i;
2746 int ways = booke206_tlb_ways(env, tlbn);
2747 target_ulong mask;
2748
2749 for (i = 0; i < ways; i++) {
2750 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2751 if (!tlb) {
2752 continue;
2753 }
2754 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2755 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2756 !(tlb->mas1 & MAS1_IPROT)) {
2757 tlb->mas1 &= ~MAS1_VALID;
2758 }
2759 }
2760}
2761
c6c7cf05 2762void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
ec19c4d1 2763{
d76ab5e1 2764 CPUState *cs;
31b030d4 2765
ec19c4d1
BS
2766 if (address & 0x4) {
2767 /* flush all entries */
2768 if (address & 0x8) {
2769 /* flush all of TLB1 */
2770 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2771 } else {
2772 /* flush all of TLB0 */
2773 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2774 }
2775 return;
2776 }
2777
2778 if (address & 0x8) {
2779 /* flush TLB1 entries */
2780 booke206_invalidate_ea_tlb(env, 1, address);
d76ab5e1 2781 CPU_FOREACH(cs) {
d10eb08f 2782 tlb_flush(cs);
d76ab5e1 2783 }
ec19c4d1
BS
2784 } else {
2785 /* flush TLB0 entries */
2786 booke206_invalidate_ea_tlb(env, 0, address);
d76ab5e1
ND
2787 CPU_FOREACH(cs) {
2788 tlb_flush_page(cs, address & MAS2_EPN_MASK);
2789 }
ec19c4d1
BS
2790 }
2791}
2792
c6c7cf05 2793void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
2794{
2795 /* XXX missing LPID handling */
2796 booke206_flush_tlb(env, -1, 1);
2797}
2798
c6c7cf05 2799void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
ec19c4d1 2800{
00c8cb0a 2801 PowerPCCPU *cpu = ppc_env_get_cpu(env);
ec19c4d1
BS
2802 int i, j;
2803 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2804 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2805 int tlb_size;
2806
2807 /* XXX missing LPID handling */
2808 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2809 tlb_size = booke206_tlb_size(env, i);
2810 for (j = 0; j < tlb_size; j++) {
2811 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2812 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2813 tlb[j].mas1 &= ~MAS1_VALID;
2814 }
2815 }
2816 tlb += booke206_tlb_size(env, i);
2817 }
d10eb08f 2818 tlb_flush(CPU(cpu));
ec19c4d1
BS
2819}
2820
c6c7cf05 2821void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
ec19c4d1 2822{
00c8cb0a 2823 PowerPCCPU *cpu = ppc_env_get_cpu(env);
ec19c4d1
BS
2824 int i, j;
2825 ppcmas_tlb_t *tlb;
2826 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2827 int pid = tid >> MAS6_SPID_SHIFT;
2828 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2829 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2830 /* XXX check for unsupported isize and raise an invalid opcode then */
2831 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2832 /* XXX implement MAV2 handling */
2833 bool mav2 = false;
2834
2835 /* XXX missing LPID handling */
2836 /* flush by pid and ea */
2837 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2838 int ways = booke206_tlb_ways(env, i);
2839
2840 for (j = 0; j < ways; j++) {
2841 tlb = booke206_get_tlbm(env, i, address, j);
2842 if (!tlb) {
2843 continue;
2844 }
2845 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2846 (tlb->mas1 & MAS1_IPROT) ||
2847 ((tlb->mas1 & MAS1_IND) != ind) ||
2848 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2849 continue;
2850 }
2851 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2852 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2853 continue;
2854 }
2855 /* XXX e500mc doesn't match SAS, but other cores might */
2856 tlb->mas1 &= ~MAS1_VALID;
2857 }
2858 }
d10eb08f 2859 tlb_flush(CPU(cpu));
ec19c4d1
BS
2860}
2861
a721d390 2862void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
ec19c4d1
BS
2863{
2864 int flags = 0;
2865
2866 if (type & 2) {
2867 flags |= BOOKE206_FLUSH_TLB1;
2868 }
2869
2870 if (type & 4) {
2871 flags |= BOOKE206_FLUSH_TLB0;
2872 }
2873
2874 booke206_flush_tlb(env, flags, 1);
2875}
eb20c1c6
DG
2876
2877
e3cffe6f 2878void helper_check_tlb_flush_local(CPUPPCState *env)
cd0c6f47 2879{
e3cffe6f
ND
2880 check_tlb_flush(env, false);
2881}
2882
2883void helper_check_tlb_flush_global(CPUPPCState *env)
2884{
2885 check_tlb_flush(env, true);
cd0c6f47
BH
2886}
2887
eb20c1c6
DG
2888/*****************************************************************************/
2889
eb20c1c6
DG
2890/* try to fill the TLB and return an exception if error. If retaddr is
2891 NULL, it means that the function was called in C code (i.e. not
2892 from generated code or from helper.c) */
2893/* XXX: fix it to restore all registers */
b35399bb
SS
2894void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
2895 int mmu_idx, uintptr_t retaddr)
eb20c1c6 2896{
d5a11fef
AF
2897 PowerPCCPU *cpu = POWERPC_CPU(cs);
2898 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2899 CPUPPCState *env = &cpu->env;
eb20c1c6
DG
2900 int ret;
2901
b632a148 2902 if (pcc->handle_mmu_fault) {
b35399bb 2903 ret = pcc->handle_mmu_fault(cpu, addr, access_type, mmu_idx);
b632a148 2904 } else {
b35399bb 2905 ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
b632a148 2906 }
eb20c1c6 2907 if (unlikely(ret != 0)) {
bd6fefe7
BH
2908 raise_exception_err_ra(env, cs->exception_index, env->error_code,
2909 retaddr);
eb20c1c6
DG
2910 }
2911}
This page took 0.750886 seconds and 4 git commands to generate.