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