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