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