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