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