2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "sysemu/kvm.h"
23 #include "mmu-hash64.h"
24 #include "mmu-hash32.h"
28 //#define DEBUG_SOFTWARE_TLB
29 //#define DUMP_PAGE_TABLES
30 //#define DEBUG_SOFTWARE_TLB
31 //#define FLUSH_ALL_TLBS
34 # define LOG_MMU(...) qemu_log(__VA_ARGS__)
35 # define LOG_MMU_STATE(env) log_cpu_state((env), 0)
37 # define LOG_MMU(...) do { } while (0)
38 # define LOG_MMU_STATE(...) do { } while (0)
41 #ifdef DEBUG_SOFTWARE_TLB
42 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
44 # define LOG_SWTLB(...) do { } while (0)
48 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
50 # define LOG_BATS(...) do { } while (0)
53 /*****************************************************************************/
54 /* PowerPC MMU emulation */
55 #if defined(CONFIG_USER_ONLY)
56 int cpu_ppc_handle_mmu_fault(CPUPPCState
*env
, target_ulong address
, int rw
,
59 int exception
, error_code
;
62 exception
= POWERPC_EXCP_ISI
;
63 error_code
= 0x40000000;
65 exception
= POWERPC_EXCP_DSI
;
66 error_code
= 0x40000000;
68 error_code
|= 0x02000000;
70 env
->spr
[SPR_DAR
] = address
;
71 env
->spr
[SPR_DSISR
] = error_code
;
73 env
->exception_index
= exception
;
74 env
->error_code
= error_code
;
80 /* Common routines used by software and hardware TLBs emulation */
81 static inline int pte_is_valid(target_ulong pte0
)
83 return pte0
& 0x80000000 ? 1 : 0;
86 static inline void pte_invalidate(target_ulong
*pte0
)
91 #define PTE_PTEM_MASK 0x7FFFFFBF
92 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
94 int pp_check(int key
, int pp
, int nx
)
98 /* Compute access rights */
99 /* When pp is 3/7, the result is undefined. Set it to noaccess */
106 access
|= PAGE_WRITE
;
124 access
= PAGE_READ
| PAGE_WRITE
;
135 int check_prot(int prot
, int rw
, int access_type
)
139 if (access_type
== ACCESS_CODE
) {
140 if (prot
& PAGE_EXEC
) {
146 if (prot
& PAGE_WRITE
) {
152 if (prot
& PAGE_READ
) {
162 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t
*ctx
, target_ulong pte0
,
163 target_ulong pte1
, int h
, int rw
, int type
)
165 target_ulong ptem
, mmask
;
166 int access
, ret
, pteh
, ptev
, pp
;
169 /* Check validity and table match */
170 ptev
= pte_is_valid(pte0
);
171 pteh
= (pte0
>> 6) & 1;
172 if (ptev
&& h
== pteh
) {
173 /* Check vsid & api */
174 ptem
= pte0
& PTE_PTEM_MASK
;
175 mmask
= PTE_CHECK_MASK
;
176 pp
= pte1
& 0x00000003;
177 if (ptem
== ctx
->ptem
) {
178 if (ctx
->raddr
!= (hwaddr
)-1ULL) {
179 /* all matches should have equal RPN, WIMG & PP */
180 if ((ctx
->raddr
& mmask
) != (pte1
& mmask
)) {
181 qemu_log("Bad RPN/WIMG/PP\n");
185 /* Compute access rights */
186 access
= pp_check(ctx
->key
, pp
, ctx
->nx
);
187 /* Keep the matching PTE informations */
190 ret
= check_prot(ctx
->prot
, rw
, type
);
193 LOG_MMU("PTE access granted !\n");
195 /* Access right violation */
196 LOG_MMU("PTE access rejected\n");
204 static inline int pte_update_flags(mmu_ctx_t
*ctx
, target_ulong
*pte1p
,
209 /* Update page flags */
210 if (!(*pte1p
& 0x00000100)) {
211 /* Update accessed flag */
212 *pte1p
|= 0x00000100;
215 if (!(*pte1p
& 0x00000080)) {
216 if (rw
== 1 && ret
== 0) {
217 /* Update changed flag */
218 *pte1p
|= 0x00000080;
221 /* Force page fault for first write access */
222 ctx
->prot
&= ~PAGE_WRITE
;
229 /* Software driven TLB helpers */
230 static inline int ppc6xx_tlb_getnum(CPUPPCState
*env
, target_ulong eaddr
,
231 int way
, int is_code
)
235 /* Select TLB num in a way from address */
236 nr
= (eaddr
>> TARGET_PAGE_BITS
) & (env
->tlb_per_way
- 1);
238 nr
+= env
->tlb_per_way
* way
;
239 /* 6xx have separate TLBs for instructions and data */
240 if (is_code
&& env
->id_tlbs
== 1) {
247 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState
*env
)
252 /* LOG_SWTLB("Invalidate all TLBs\n"); */
253 /* Invalidate all defined software TLB */
255 if (env
->id_tlbs
== 1) {
258 for (nr
= 0; nr
< max
; nr
++) {
259 tlb
= &env
->tlb
.tlb6
[nr
];
260 pte_invalidate(&tlb
->pte0
);
265 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState
*env
,
267 int is_code
, int match_epn
)
269 #if !defined(FLUSH_ALL_TLBS)
273 /* Invalidate ITLB + DTLB, all ways */
274 for (way
= 0; way
< env
->nb_ways
; way
++) {
275 nr
= ppc6xx_tlb_getnum(env
, eaddr
, way
, is_code
);
276 tlb
= &env
->tlb
.tlb6
[nr
];
277 if (pte_is_valid(tlb
->pte0
) && (match_epn
== 0 || eaddr
== tlb
->EPN
)) {
278 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx
"\n", nr
,
280 pte_invalidate(&tlb
->pte0
);
281 tlb_flush_page(env
, tlb
->EPN
);
285 /* XXX: PowerPC specification say this is valid as well */
286 ppc6xx_tlb_invalidate_all(env
);
290 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState
*env
,
291 target_ulong eaddr
, int is_code
)
293 ppc6xx_tlb_invalidate_virt2(env
, eaddr
, is_code
, 0);
296 static void ppc6xx_tlb_store(CPUPPCState
*env
, target_ulong EPN
, int way
,
297 int is_code
, target_ulong pte0
, target_ulong pte1
)
302 nr
= ppc6xx_tlb_getnum(env
, EPN
, way
, is_code
);
303 tlb
= &env
->tlb
.tlb6
[nr
];
304 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
305 " PTE1 " TARGET_FMT_lx
"\n", nr
, env
->nb_tlb
, EPN
, pte0
, pte1
);
306 /* Invalidate any pending reference in QEMU for this virtual address */
307 ppc6xx_tlb_invalidate_virt2(env
, EPN
, is_code
, 1);
311 /* Store last way for LRU mechanism */
315 static inline int ppc6xx_tlb_check(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
316 target_ulong eaddr
, int rw
, int access_type
)
323 ret
= -1; /* No TLB found */
324 for (way
= 0; way
< env
->nb_ways
; way
++) {
325 nr
= ppc6xx_tlb_getnum(env
, eaddr
, way
,
326 access_type
== ACCESS_CODE
? 1 : 0);
327 tlb
= &env
->tlb
.tlb6
[nr
];
328 /* This test "emulates" the PTE index match for hardware TLBs */
329 if ((eaddr
& TARGET_PAGE_MASK
) != tlb
->EPN
) {
330 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx
" " TARGET_FMT_lx
331 "] <> " TARGET_FMT_lx
"\n", nr
, env
->nb_tlb
,
332 pte_is_valid(tlb
->pte0
) ? "valid" : "inval",
333 tlb
->EPN
, tlb
->EPN
+ TARGET_PAGE_SIZE
, eaddr
);
336 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx
" <> " TARGET_FMT_lx
" "
337 TARGET_FMT_lx
" %c %c\n", nr
, env
->nb_tlb
,
338 pte_is_valid(tlb
->pte0
) ? "valid" : "inval",
339 tlb
->EPN
, eaddr
, tlb
->pte1
,
340 rw
? 'S' : 'L', access_type
== ACCESS_CODE
? 'I' : 'D');
341 switch (ppc6xx_tlb_pte_check(ctx
, tlb
->pte0
, tlb
->pte1
, 0, rw
, access_type
)) {
343 /* TLB inconsistency */
346 /* Access violation */
356 /* XXX: we should go on looping to check all TLBs consistency
357 * but we can speed-up the whole thing as the
358 * result would be undefined if TLBs are not consistent.
367 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx
" prot=%01x ret=%d\n",
368 ctx
->raddr
& TARGET_PAGE_MASK
, ctx
->prot
, ret
);
369 /* Update page flags */
370 pte_update_flags(ctx
, &env
->tlb
.tlb6
[best
].pte1
, ret
, rw
);
376 /* Perform BAT hit & translation */
377 static inline void bat_size_prot(CPUPPCState
*env
, target_ulong
*blp
,
378 int *validp
, int *protp
, target_ulong
*BATu
,
384 bl
= (*BATu
& 0x00001FFC) << 15;
387 if (((msr_pr
== 0) && (*BATu
& 0x00000002)) ||
388 ((msr_pr
!= 0) && (*BATu
& 0x00000001))) {
390 pp
= *BATl
& 0x00000003;
392 prot
= PAGE_READ
| PAGE_EXEC
;
403 static inline void bat_601_size_prot(CPUPPCState
*env
, target_ulong
*blp
,
404 int *validp
, int *protp
,
405 target_ulong
*BATu
, target_ulong
*BATl
)
408 int key
, pp
, valid
, prot
;
410 bl
= (*BATl
& 0x0000003F) << 17;
411 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx
" msk " TARGET_FMT_lx
"\n",
412 (uint8_t)(*BATl
& 0x0000003F), bl
, ~bl
);
414 valid
= (*BATl
>> 6) & 1;
416 pp
= *BATu
& 0x00000003;
418 key
= (*BATu
>> 3) & 1;
420 key
= (*BATu
>> 2) & 1;
422 prot
= pp_check(key
, pp
, 0);
429 static inline int get_bat(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
430 target_ulong
virtual, int rw
, int type
)
432 target_ulong
*BATlt
, *BATut
, *BATu
, *BATl
;
433 target_ulong BEPIl
, BEPIu
, bl
;
437 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx
"\n", __func__
,
438 type
== ACCESS_CODE
? 'I' : 'D', virtual);
441 BATlt
= env
->IBAT
[1];
442 BATut
= env
->IBAT
[0];
445 BATlt
= env
->DBAT
[1];
446 BATut
= env
->DBAT
[0];
449 for (i
= 0; i
< env
->nb_BATs
; i
++) {
452 BEPIu
= *BATu
& 0xF0000000;
453 BEPIl
= *BATu
& 0x0FFE0000;
454 if (unlikely(env
->mmu_model
== POWERPC_MMU_601
)) {
455 bat_601_size_prot(env
, &bl
, &valid
, &prot
, BATu
, BATl
);
457 bat_size_prot(env
, &bl
, &valid
, &prot
, BATu
, BATl
);
459 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx
" BATu " TARGET_FMT_lx
460 " BATl " TARGET_FMT_lx
"\n", __func__
,
461 type
== ACCESS_CODE
? 'I' : 'D', i
, virtual, *BATu
, *BATl
);
462 if ((virtual & 0xF0000000) == BEPIu
&&
463 ((virtual & 0x0FFE0000) & ~bl
) == BEPIl
) {
466 /* Get physical address */
467 ctx
->raddr
= (*BATl
& 0xF0000000) |
468 ((virtual & 0x0FFE0000 & bl
) | (*BATl
& 0x0FFE0000)) |
469 (virtual & 0x0001F000);
470 /* Compute access rights */
472 ret
= check_prot(ctx
->prot
, rw
, type
);
474 LOG_BATS("BAT %d match: r " TARGET_FMT_plx
" prot=%c%c\n",
475 i
, ctx
->raddr
, ctx
->prot
& PAGE_READ
? 'R' : '-',
476 ctx
->prot
& PAGE_WRITE
? 'W' : '-');
483 #if defined(DEBUG_BATS)
484 if (qemu_log_enabled()) {
485 LOG_BATS("no BAT match for " TARGET_FMT_lx
":\n", virtual);
486 for (i
= 0; i
< 4; i
++) {
489 BEPIu
= *BATu
& 0xF0000000;
490 BEPIl
= *BATu
& 0x0FFE0000;
491 bl
= (*BATu
& 0x00001FFC) << 15;
492 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx
" BATu " TARGET_FMT_lx
493 " BATl " TARGET_FMT_lx
"\n\t" TARGET_FMT_lx
" "
494 TARGET_FMT_lx
" " TARGET_FMT_lx
"\n",
495 __func__
, type
== ACCESS_CODE
? 'I' : 'D', i
, virtual,
496 *BATu
, *BATl
, BEPIu
, BEPIl
, bl
);
505 static inline hwaddr
get_pteg_offset(CPUPPCState
*env
,
509 return (hash
* pte_size
* 8) & env
->htab_mask
;
512 /* PTE table lookup */
513 static inline int find_pte2(CPUPPCState
*env
, mmu_ctx_t
*ctx
, int is_64b
, int h
,
514 int rw
, int type
, int target_page_bits
)
517 target_ulong pte0
, pte1
;
521 ret
= -1; /* No entry found */
522 pteg_off
= get_pteg_offset(env
, ctx
->hash
[h
],
523 is_64b
? HASH_PTE_SIZE_64
: HASH_PTE_SIZE_32
);
524 for (i
= 0; i
< 8; i
++) {
525 #if defined(TARGET_PPC64)
527 if (env
->external_htab
) {
528 pte0
= ldq_p(env
->external_htab
+ pteg_off
+ (i
* 16));
529 pte1
= ldq_p(env
->external_htab
+ pteg_off
+ (i
* 16) + 8);
531 pte0
= ldq_phys(env
->htab_base
+ pteg_off
+ (i
* 16));
532 pte1
= ldq_phys(env
->htab_base
+ pteg_off
+ (i
* 16) + 8);
535 r
= pte64_check(ctx
, pte0
, pte1
, h
, rw
, type
);
536 LOG_MMU("Load pte from %016" HWADDR_PRIx
" => " TARGET_FMT_lx
" "
537 TARGET_FMT_lx
" %d %d %d " TARGET_FMT_lx
"\n",
538 pteg_off
+ (i
* 16), pte0
, pte1
, (int)(pte0
& 1), h
,
539 (int)((pte0
>> 1) & 1), ctx
->ptem
);
543 if (env
->external_htab
) {
544 pte0
= ldl_p(env
->external_htab
+ pteg_off
+ (i
* 8));
545 pte1
= ldl_p(env
->external_htab
+ pteg_off
+ (i
* 8) + 4);
547 pte0
= ldl_phys(env
->htab_base
+ pteg_off
+ (i
* 8));
548 pte1
= ldl_phys(env
->htab_base
+ pteg_off
+ (i
* 8) + 4);
550 r
= pte_check_hash32(ctx
, pte0
, pte1
, h
, rw
, type
);
551 LOG_MMU("Load pte from %08" HWADDR_PRIx
" => " TARGET_FMT_lx
" "
552 TARGET_FMT_lx
" %d %d %d " TARGET_FMT_lx
"\n",
553 pteg_off
+ (i
* 8), pte0
, pte1
, (int)(pte0
>> 31), h
,
554 (int)((pte0
>> 6) & 1), ctx
->ptem
);
558 /* PTE inconsistency */
561 /* Access violation */
571 /* XXX: we should go on looping to check all PTEs consistency
572 * but if we can speed-up the whole thing as the
573 * result would be undefined if PTEs are not consistent.
582 LOG_MMU("found PTE at addr %08" HWADDR_PRIx
" prot=%01x ret=%d\n",
583 ctx
->raddr
, ctx
->prot
, ret
);
584 /* Update page flags */
586 if (pte_update_flags(ctx
, &pte1
, ret
, rw
) == 1) {
587 #if defined(TARGET_PPC64)
589 if (env
->external_htab
) {
590 stq_p(env
->external_htab
+ pteg_off
+ (good
* 16) + 8,
593 stq_phys_notdirty(env
->htab_base
+ pteg_off
+
594 (good
* 16) + 8, pte1
);
599 if (env
->external_htab
) {
600 stl_p(env
->external_htab
+ pteg_off
+ (good
* 8) + 4,
603 stl_phys_notdirty(env
->htab_base
+ pteg_off
+
604 (good
* 8) + 4, pte1
);
610 /* We have a TLB that saves 4K pages, so let's
611 * split a huge page to 4k chunks */
612 if (target_page_bits
!= TARGET_PAGE_BITS
) {
613 ctx
->raddr
|= (ctx
->eaddr
& ((1 << target_page_bits
) - 1))
619 static inline int find_pte(CPUPPCState
*env
, mmu_ctx_t
*ctx
, int h
, int rw
,
620 int type
, int target_page_bits
)
622 #if defined(TARGET_PPC64)
623 if (env
->mmu_model
& POWERPC_MMU_64
) {
624 return find_pte2(env
, ctx
, 1, h
, rw
, type
, target_page_bits
);
628 return find_pte2(env
, ctx
, 0, h
, rw
, type
, target_page_bits
);
631 /* Perform segment based translation */
632 static inline int get_segment(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
633 target_ulong eaddr
, int rw
, int type
)
637 int ds
, pr
, target_page_bits
;
642 #if defined(TARGET_PPC64)
643 if (env
->mmu_model
& POWERPC_MMU_64
) {
645 target_ulong pageaddr
;
648 LOG_MMU("Check SLBs\n");
649 slb
= slb_lookup(env
, eaddr
);
654 if (slb
->vsid
& SLB_VSID_B
) {
655 vsid
= (slb
->vsid
& SLB_VSID_VSID
) >> SLB_VSID_SHIFT_1T
;
658 vsid
= (slb
->vsid
& SLB_VSID_VSID
) >> SLB_VSID_SHIFT
;
662 target_page_bits
= (slb
->vsid
& SLB_VSID_L
)
663 ? TARGET_PAGE_BITS_16M
: TARGET_PAGE_BITS
;
664 ctx
->key
= !!(pr
? (slb
->vsid
& SLB_VSID_KP
)
665 : (slb
->vsid
& SLB_VSID_KS
));
667 ctx
->nx
= !!(slb
->vsid
& SLB_VSID_N
);
669 pageaddr
= eaddr
& ((1ULL << segment_bits
)
670 - (1ULL << target_page_bits
));
671 if (slb
->vsid
& SLB_VSID_B
) {
672 hash
= vsid
^ (vsid
<< 25) ^ (pageaddr
>> target_page_bits
);
674 hash
= vsid
^ (pageaddr
>> target_page_bits
);
676 /* Only 5 bits of the page index are used in the AVPN */
677 ctx
->ptem
= (slb
->vsid
& SLB_VSID_PTEM
) |
678 ((pageaddr
>> 16) & ((1ULL << segment_bits
) - 0x80));
680 #endif /* defined(TARGET_PPC64) */
682 target_ulong sr
, pgidx
;
684 sr
= env
->sr
[eaddr
>> 28];
685 ctx
->key
= (((sr
& 0x20000000) && (pr
!= 0)) ||
686 ((sr
& 0x40000000) && (pr
== 0))) ? 1 : 0;
687 ds
= sr
& 0x80000000 ? 1 : 0;
688 ctx
->nx
= sr
& 0x10000000 ? 1 : 0;
689 vsid
= sr
& 0x00FFFFFF;
690 target_page_bits
= TARGET_PAGE_BITS
;
691 LOG_MMU("Check segment v=" TARGET_FMT_lx
" %d " TARGET_FMT_lx
" nip="
692 TARGET_FMT_lx
" lr=" TARGET_FMT_lx
693 " ir=%d dr=%d pr=%d %d t=%d\n",
694 eaddr
, (int)(eaddr
>> 28), sr
, env
->nip
, env
->lr
, (int)msr_ir
,
695 (int)msr_dr
, pr
!= 0 ? 1 : 0, rw
, type
);
696 pgidx
= (eaddr
& ~SEGMENT_MASK_256M
) >> target_page_bits
;
698 ctx
->ptem
= (vsid
<< 7) | (pgidx
>> 10);
700 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx
"\n",
701 ctx
->key
, ds
, ctx
->nx
, vsid
);
704 /* Check if instruction fetch is allowed, if needed */
705 if (type
!= ACCESS_CODE
|| ctx
->nx
== 0) {
706 /* Page address translation */
707 LOG_MMU("htab_base " TARGET_FMT_plx
" htab_mask " TARGET_FMT_plx
708 " hash " TARGET_FMT_plx
"\n",
709 env
->htab_base
, env
->htab_mask
, hash
);
711 ctx
->hash
[1] = ~hash
;
713 /* Initialize real address with an invalid value */
714 ctx
->raddr
= (hwaddr
)-1ULL;
715 if (unlikely(env
->mmu_model
== POWERPC_MMU_SOFT_6xx
||
716 env
->mmu_model
== POWERPC_MMU_SOFT_74xx
)) {
717 /* Software TLB search */
718 ret
= ppc6xx_tlb_check(env
, ctx
, eaddr
, rw
, type
);
720 LOG_MMU("0 htab=" TARGET_FMT_plx
"/" TARGET_FMT_plx
721 " vsid=" TARGET_FMT_lx
" ptem=" TARGET_FMT_lx
722 " hash=" TARGET_FMT_plx
"\n",
723 env
->htab_base
, env
->htab_mask
, vsid
, ctx
->ptem
,
725 /* Primary table lookup */
726 ret
= find_pte(env
, ctx
, 0, rw
, type
, target_page_bits
);
728 /* Secondary table lookup */
729 LOG_MMU("1 htab=" TARGET_FMT_plx
"/" TARGET_FMT_plx
730 " vsid=" TARGET_FMT_lx
" api=" TARGET_FMT_lx
731 " hash=" TARGET_FMT_plx
"\n", env
->htab_base
,
732 env
->htab_mask
, vsid
, ctx
->ptem
, ctx
->hash
[1]);
733 ret2
= find_pte(env
, ctx
, 1, rw
, type
,
740 #if defined(DUMP_PAGE_TABLES)
741 if (qemu_log_enabled()) {
743 uint32_t a0
, a1
, a2
, a3
;
745 qemu_log("Page table: " TARGET_FMT_plx
" len " TARGET_FMT_plx
746 "\n", sdr
, mask
+ 0x80);
747 for (curaddr
= sdr
; curaddr
< (sdr
+ mask
+ 0x80);
749 a0
= ldl_phys(curaddr
);
750 a1
= ldl_phys(curaddr
+ 4);
751 a2
= ldl_phys(curaddr
+ 8);
752 a3
= ldl_phys(curaddr
+ 12);
753 if (a0
!= 0 || a1
!= 0 || a2
!= 0 || a3
!= 0) {
754 qemu_log(TARGET_FMT_plx
": %08x %08x %08x %08x\n",
755 curaddr
, a0
, a1
, a2
, a3
);
761 LOG_MMU("No access allowed\n");
767 LOG_MMU("direct store...\n");
768 /* Direct-store segment : absolutely *BUGGY* for now */
770 /* Direct-store implies a 32-bit MMU.
771 * Check the Segment Register's bus unit ID (BUID).
773 sr
= env
->sr
[eaddr
>> 28];
774 if ((sr
& 0x1FF00000) >> 20 == 0x07f) {
775 /* Memory-forced I/O controller interface access */
776 /* If T=1 and BUID=x'07F', the 601 performs a memory access
777 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
779 ctx
->raddr
= ((sr
& 0xF) << 28) | (eaddr
& 0x0FFFFFFF);
780 ctx
->prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
786 /* Integer load/store : only access allowed */
789 /* No code fetch is allowed in direct-store areas */
792 /* Floating point load/store */
795 /* lwarx, ldarx or srwcx. */
798 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
799 /* Should make the instruction do no-op.
800 * As it already do no-op, it's quite easy :-)
808 qemu_log("ERROR: instruction should not need "
809 "address translation\n");
812 if ((rw
== 1 || ctx
->key
!= 1) && (rw
== 0 || ctx
->key
!= 0)) {
823 /* Generic TLB check function for embedded PowerPC implementations */
824 static int ppcemb_tlb_check(CPUPPCState
*env
, ppcemb_tlb_t
*tlb
,
826 target_ulong address
, uint32_t pid
, int ext
,
831 /* Check valid flag */
832 if (!(tlb
->prot
& PAGE_VALID
)) {
835 mask
= ~(tlb
->size
- 1);
836 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx
" PID %u <=> " TARGET_FMT_lx
837 " " TARGET_FMT_lx
" %u %x\n", __func__
, i
, address
, pid
, tlb
->EPN
,
838 mask
, (uint32_t)tlb
->PID
, tlb
->prot
);
840 if (tlb
->PID
!= 0 && tlb
->PID
!= pid
) {
843 /* Check effective address */
844 if ((address
& mask
) != tlb
->EPN
) {
847 *raddrp
= (tlb
->RPN
& mask
) | (address
& ~mask
);
849 /* Extend the physical address to 36 bits */
850 *raddrp
|= (uint64_t)(tlb
->RPN
& 0xF) << 32;
856 /* Generic TLB search function for PowerPC embedded implementations */
857 static int ppcemb_tlb_search(CPUPPCState
*env
, target_ulong address
,
864 /* Default return value is no match */
866 for (i
= 0; i
< env
->nb_tlb
; i
++) {
867 tlb
= &env
->tlb
.tlbe
[i
];
868 if (ppcemb_tlb_check(env
, tlb
, &raddr
, address
, pid
, 0, i
) == 0) {
877 /* Helpers specific to PowerPC 40x implementations */
878 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState
*env
)
883 for (i
= 0; i
< env
->nb_tlb
; i
++) {
884 tlb
= &env
->tlb
.tlbe
[i
];
885 tlb
->prot
&= ~PAGE_VALID
;
890 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState
*env
,
891 target_ulong eaddr
, uint32_t pid
)
893 #if !defined(FLUSH_ALL_TLBS)
896 target_ulong page
, end
;
899 for (i
= 0; i
< env
->nb_tlb
; i
++) {
900 tlb
= &env
->tlb
.tlbe
[i
];
901 if (ppcemb_tlb_check(env
, tlb
, &raddr
, eaddr
, pid
, 0, i
) == 0) {
902 end
= tlb
->EPN
+ tlb
->size
;
903 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
904 tlb_flush_page(env
, page
);
906 tlb
->prot
&= ~PAGE_VALID
;
911 ppc4xx_tlb_invalidate_all(env
);
915 static int mmu40x_get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
916 target_ulong address
, int rw
,
921 int i
, ret
, zsel
, zpr
, pr
;
924 raddr
= (hwaddr
)-1ULL;
926 for (i
= 0; i
< env
->nb_tlb
; i
++) {
927 tlb
= &env
->tlb
.tlbe
[i
];
928 if (ppcemb_tlb_check(env
, tlb
, &raddr
, address
,
929 env
->spr
[SPR_40x_PID
], 0, i
) < 0) {
932 zsel
= (tlb
->attr
>> 4) & 0xF;
933 zpr
= (env
->spr
[SPR_40x_ZPR
] >> (30 - (2 * zsel
))) & 0x3;
934 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
935 __func__
, i
, zsel
, zpr
, rw
, tlb
->attr
);
936 /* Check execute enable bit */
944 /* All accesses granted */
945 ctx
->prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
950 /* Raise Zone protection fault. */
951 env
->spr
[SPR_40x_ESR
] = 1 << 22;
959 /* Check from TLB entry */
960 ctx
->prot
= tlb
->prot
;
961 ret
= check_prot(ctx
->prot
, rw
, access_type
);
963 env
->spr
[SPR_40x_ESR
] = 0;
969 LOG_SWTLB("%s: access granted " TARGET_FMT_lx
" => " TARGET_FMT_plx
970 " %d %d\n", __func__
, address
, ctx
->raddr
, ctx
->prot
,
975 LOG_SWTLB("%s: access refused " TARGET_FMT_lx
" => " TARGET_FMT_plx
976 " %d %d\n", __func__
, address
, raddr
, ctx
->prot
, ret
);
981 void store_40x_sler(CPUPPCState
*env
, uint32_t val
)
983 /* XXX: TO BE FIXED */
984 if (val
!= 0x00000000) {
985 cpu_abort(env
, "Little-endian regions are not supported by now\n");
987 env
->spr
[SPR_405_SLER
] = val
;
990 static inline int mmubooke_check_tlb(CPUPPCState
*env
, ppcemb_tlb_t
*tlb
,
991 hwaddr
*raddr
, int *prot
,
992 target_ulong address
, int rw
,
993 int access_type
, int i
)
997 if (ppcemb_tlb_check(env
, tlb
, raddr
, address
,
998 env
->spr
[SPR_BOOKE_PID
],
999 !env
->nb_pids
, i
) >= 0) {
1003 if (env
->spr
[SPR_BOOKE_PID1
] &&
1004 ppcemb_tlb_check(env
, tlb
, raddr
, address
,
1005 env
->spr
[SPR_BOOKE_PID1
], 0, i
) >= 0) {
1009 if (env
->spr
[SPR_BOOKE_PID2
] &&
1010 ppcemb_tlb_check(env
, tlb
, raddr
, address
,
1011 env
->spr
[SPR_BOOKE_PID2
], 0, i
) >= 0) {
1015 LOG_SWTLB("%s: TLB entry not found\n", __func__
);
1021 prot2
= tlb
->prot
& 0xF;
1023 prot2
= (tlb
->prot
>> 4) & 0xF;
1026 /* Check the address space */
1027 if (access_type
== ACCESS_CODE
) {
1028 if (msr_ir
!= (tlb
->attr
& 1)) {
1029 LOG_SWTLB("%s: AS doesn't match\n", __func__
);
1034 if (prot2
& PAGE_EXEC
) {
1035 LOG_SWTLB("%s: good TLB!\n", __func__
);
1039 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__
, prot2
);
1042 if (msr_dr
!= (tlb
->attr
& 1)) {
1043 LOG_SWTLB("%s: AS doesn't match\n", __func__
);
1048 if ((!rw
&& prot2
& PAGE_READ
) || (rw
&& (prot2
& PAGE_WRITE
))) {
1049 LOG_SWTLB("%s: found TLB!\n", __func__
);
1053 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__
, prot2
);
1060 static int mmubooke_get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
1061 target_ulong address
, int rw
,
1069 raddr
= (hwaddr
)-1ULL;
1070 for (i
= 0; i
< env
->nb_tlb
; i
++) {
1071 tlb
= &env
->tlb
.tlbe
[i
];
1072 ret
= mmubooke_check_tlb(env
, tlb
, &raddr
, &ctx
->prot
, address
, rw
,
1081 LOG_SWTLB("%s: access granted " TARGET_FMT_lx
" => " TARGET_FMT_plx
1082 " %d %d\n", __func__
, address
, ctx
->raddr
, ctx
->prot
,
1085 LOG_SWTLB("%s: access refused " TARGET_FMT_lx
" => " TARGET_FMT_plx
1086 " %d %d\n", __func__
, address
, raddr
, ctx
->prot
, ret
);
1092 static void booke206_flush_tlb(CPUPPCState
*env
, int flags
,
1093 const int check_iprot
)
1097 ppcmas_tlb_t
*tlb
= env
->tlb
.tlbm
;
1099 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
1100 if (flags
& (1 << i
)) {
1101 tlb_size
= booke206_tlb_size(env
, i
);
1102 for (j
= 0; j
< tlb_size
; j
++) {
1103 if (!check_iprot
|| !(tlb
[j
].mas1
& MAS1_IPROT
)) {
1104 tlb
[j
].mas1
&= ~MAS1_VALID
;
1108 tlb
+= booke206_tlb_size(env
, i
);
1114 static hwaddr
booke206_tlb_to_page_size(CPUPPCState
*env
,
1119 tlbm_size
= (tlb
->mas1
& MAS1_TSIZE_MASK
) >> MAS1_TSIZE_SHIFT
;
1121 return 1024ULL << tlbm_size
;
1124 /* TLB check function for MAS based SoftTLBs */
1125 static int ppcmas_tlb_check(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
,
1127 target_ulong address
, uint32_t pid
)
1132 /* Check valid flag */
1133 if (!(tlb
->mas1
& MAS1_VALID
)) {
1137 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
1138 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx
" PID=0x%x MAS1=0x%x MAS2=0x%"
1139 PRIx64
" mask=0x" TARGET_FMT_lx
" MAS7_3=0x%" PRIx64
" MAS8=%x\n",
1140 __func__
, address
, pid
, tlb
->mas1
, tlb
->mas2
, mask
, tlb
->mas7_3
,
1144 tlb_pid
= (tlb
->mas1
& MAS1_TID_MASK
) >> MAS1_TID_SHIFT
;
1145 if (tlb_pid
!= 0 && tlb_pid
!= pid
) {
1149 /* Check effective address */
1150 if ((address
& mask
) != (tlb
->mas2
& MAS2_EPN_MASK
)) {
1155 *raddrp
= (tlb
->mas7_3
& mask
) | (address
& ~mask
);
1161 static int mmubooke206_check_tlb(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
,
1162 hwaddr
*raddr
, int *prot
,
1163 target_ulong address
, int rw
,
1169 if (ppcmas_tlb_check(env
, tlb
, raddr
, address
,
1170 env
->spr
[SPR_BOOKE_PID
]) >= 0) {
1174 if (env
->spr
[SPR_BOOKE_PID1
] &&
1175 ppcmas_tlb_check(env
, tlb
, raddr
, address
,
1176 env
->spr
[SPR_BOOKE_PID1
]) >= 0) {
1180 if (env
->spr
[SPR_BOOKE_PID2
] &&
1181 ppcmas_tlb_check(env
, tlb
, raddr
, address
,
1182 env
->spr
[SPR_BOOKE_PID2
]) >= 0) {
1186 LOG_SWTLB("%s: TLB entry not found\n", __func__
);
1192 if (tlb
->mas7_3
& MAS3_UR
) {
1195 if (tlb
->mas7_3
& MAS3_UW
) {
1196 prot2
|= PAGE_WRITE
;
1198 if (tlb
->mas7_3
& MAS3_UX
) {
1202 if (tlb
->mas7_3
& MAS3_SR
) {
1205 if (tlb
->mas7_3
& MAS3_SW
) {
1206 prot2
|= PAGE_WRITE
;
1208 if (tlb
->mas7_3
& MAS3_SX
) {
1213 /* Check the address space and permissions */
1214 if (access_type
== ACCESS_CODE
) {
1215 if (msr_ir
!= ((tlb
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
)) {
1216 LOG_SWTLB("%s: AS doesn't match\n", __func__
);
1221 if (prot2
& PAGE_EXEC
) {
1222 LOG_SWTLB("%s: good TLB!\n", __func__
);
1226 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__
, prot2
);
1229 if (msr_dr
!= ((tlb
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
)) {
1230 LOG_SWTLB("%s: AS doesn't match\n", __func__
);
1235 if ((!rw
&& prot2
& PAGE_READ
) || (rw
&& (prot2
& PAGE_WRITE
))) {
1236 LOG_SWTLB("%s: found TLB!\n", __func__
);
1240 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__
, prot2
);
1247 static int mmubooke206_get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
1248 target_ulong address
, int rw
,
1256 raddr
= (hwaddr
)-1ULL;
1258 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
1259 int ways
= booke206_tlb_ways(env
, i
);
1261 for (j
= 0; j
< ways
; j
++) {
1262 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
1266 ret
= mmubooke206_check_tlb(env
, tlb
, &raddr
, &ctx
->prot
, address
,
1278 LOG_SWTLB("%s: access granted " TARGET_FMT_lx
" => " TARGET_FMT_plx
1279 " %d %d\n", __func__
, address
, ctx
->raddr
, ctx
->prot
,
1282 LOG_SWTLB("%s: access refused " TARGET_FMT_lx
" => " TARGET_FMT_plx
1283 " %d %d\n", __func__
, address
, raddr
, ctx
->prot
, ret
);
1289 static const char *book3e_tsize_to_str
[32] = {
1290 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1291 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1292 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1296 static void mmubooke_dump_mmu(FILE *f
, fprintf_function cpu_fprintf
,
1299 ppcemb_tlb_t
*entry
;
1302 if (kvm_enabled() && !env
->kvm_sw_tlb
) {
1303 cpu_fprintf(f
, "Cannot access KVM TLB\n");
1307 cpu_fprintf(f
, "\nTLB:\n");
1308 cpu_fprintf(f
, "Effective Physical Size PID Prot "
1311 entry
= &env
->tlb
.tlbe
[0];
1312 for (i
= 0; i
< env
->nb_tlb
; i
++, entry
++) {
1315 uint64_t size
= (uint64_t)entry
->size
;
1318 /* Check valid flag */
1319 if (!(entry
->prot
& PAGE_VALID
)) {
1323 mask
= ~(entry
->size
- 1);
1324 ea
= entry
->EPN
& mask
;
1325 pa
= entry
->RPN
& mask
;
1326 /* Extend the physical address to 36 bits */
1327 pa
|= (hwaddr
)(entry
->RPN
& 0xF) << 32;
1330 snprintf(size_buf
, sizeof(size_buf
), "%3" PRId64
"M", size
/ 1024);
1332 snprintf(size_buf
, sizeof(size_buf
), "%3" PRId64
"k", size
);
1334 cpu_fprintf(f
, "0x%016" PRIx64
" 0x%016" PRIx64
" %s %-5u %08x %08x\n",
1335 (uint64_t)ea
, (uint64_t)pa
, size_buf
, (uint32_t)entry
->PID
,
1336 entry
->prot
, entry
->attr
);
1341 static void mmubooke206_dump_one_tlb(FILE *f
, fprintf_function cpu_fprintf
,
1342 CPUPPCState
*env
, int tlbn
, int offset
,
1345 ppcmas_tlb_t
*entry
;
1348 cpu_fprintf(f
, "\nTLB%d:\n", tlbn
);
1349 cpu_fprintf(f
, "Effective Physical Size TID TS SRWX"
1350 " URWX WIMGE U0123\n");
1352 entry
= &env
->tlb
.tlbm
[offset
];
1353 for (i
= 0; i
< tlbsize
; i
++, entry
++) {
1354 hwaddr ea
, pa
, size
;
1357 if (!(entry
->mas1
& MAS1_VALID
)) {
1361 tsize
= (entry
->mas1
& MAS1_TSIZE_MASK
) >> MAS1_TSIZE_SHIFT
;
1362 size
= 1024ULL << tsize
;
1363 ea
= entry
->mas2
& ~(size
- 1);
1364 pa
= entry
->mas7_3
& ~(size
- 1);
1366 cpu_fprintf(f
, "0x%016" PRIx64
" 0x%016" PRIx64
" %4s %-5u %1u S%c%c%c"
1367 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1368 (uint64_t)ea
, (uint64_t)pa
,
1369 book3e_tsize_to_str
[tsize
],
1370 (entry
->mas1
& MAS1_TID_MASK
) >> MAS1_TID_SHIFT
,
1371 (entry
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
,
1372 entry
->mas7_3
& MAS3_SR
? 'R' : '-',
1373 entry
->mas7_3
& MAS3_SW
? 'W' : '-',
1374 entry
->mas7_3
& MAS3_SX
? 'X' : '-',
1375 entry
->mas7_3
& MAS3_UR
? 'R' : '-',
1376 entry
->mas7_3
& MAS3_UW
? 'W' : '-',
1377 entry
->mas7_3
& MAS3_UX
? 'X' : '-',
1378 entry
->mas2
& MAS2_W
? 'W' : '-',
1379 entry
->mas2
& MAS2_I
? 'I' : '-',
1380 entry
->mas2
& MAS2_M
? 'M' : '-',
1381 entry
->mas2
& MAS2_G
? 'G' : '-',
1382 entry
->mas2
& MAS2_E
? 'E' : '-',
1383 entry
->mas7_3
& MAS3_U0
? '0' : '-',
1384 entry
->mas7_3
& MAS3_U1
? '1' : '-',
1385 entry
->mas7_3
& MAS3_U2
? '2' : '-',
1386 entry
->mas7_3
& MAS3_U3
? '3' : '-');
1390 static void mmubooke206_dump_mmu(FILE *f
, fprintf_function cpu_fprintf
,
1396 if (kvm_enabled() && !env
->kvm_sw_tlb
) {
1397 cpu_fprintf(f
, "Cannot access KVM TLB\n");
1401 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
1402 int size
= booke206_tlb_size(env
, i
);
1408 mmubooke206_dump_one_tlb(f
, cpu_fprintf
, env
, i
, offset
, size
);
1413 void dump_mmu(FILE *f
, fprintf_function cpu_fprintf
, CPUPPCState
*env
)
1415 switch (env
->mmu_model
) {
1416 case POWERPC_MMU_BOOKE
:
1417 mmubooke_dump_mmu(f
, cpu_fprintf
, env
);
1419 case POWERPC_MMU_BOOKE206
:
1420 mmubooke206_dump_mmu(f
, cpu_fprintf
, env
);
1422 #if defined(TARGET_PPC64)
1423 case POWERPC_MMU_64B
:
1424 case POWERPC_MMU_2_06
:
1425 case POWERPC_MMU_2_06d
:
1426 dump_slb(f
, cpu_fprintf
, env
);
1430 qemu_log_mask(LOG_UNIMP
, "%s: unimplemented\n", __func__
);
1434 static inline int check_physical(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
1435 target_ulong eaddr
, int rw
)
1440 ctx
->prot
= PAGE_READ
| PAGE_EXEC
;
1442 switch (env
->mmu_model
) {
1443 case POWERPC_MMU_32B
:
1444 case POWERPC_MMU_601
:
1445 case POWERPC_MMU_SOFT_6xx
:
1446 case POWERPC_MMU_SOFT_74xx
:
1447 case POWERPC_MMU_SOFT_4xx
:
1448 case POWERPC_MMU_REAL
:
1449 case POWERPC_MMU_BOOKE
:
1450 ctx
->prot
|= PAGE_WRITE
;
1452 #if defined(TARGET_PPC64)
1453 case POWERPC_MMU_64B
:
1454 case POWERPC_MMU_2_06
:
1455 case POWERPC_MMU_2_06d
:
1456 /* Real address are 60 bits long */
1457 ctx
->raddr
&= 0x0FFFFFFFFFFFFFFFULL
;
1458 ctx
->prot
|= PAGE_WRITE
;
1461 case POWERPC_MMU_SOFT_4xx_Z
:
1462 if (unlikely(msr_pe
!= 0)) {
1463 /* 403 family add some particular protections,
1464 * using PBL/PBU registers for accesses with no translation.
1467 /* Check PLB validity */
1468 (env
->pb
[0] < env
->pb
[1] &&
1469 /* and address in plb area */
1470 eaddr
>= env
->pb
[0] && eaddr
< env
->pb
[1]) ||
1471 (env
->pb
[2] < env
->pb
[3] &&
1472 eaddr
>= env
->pb
[2] && eaddr
< env
->pb
[3]) ? 1 : 0;
1473 if (in_plb
^ msr_px
) {
1474 /* Access in protected area */
1476 /* Access is not allowed */
1480 /* Read-write access is allowed */
1481 ctx
->prot
|= PAGE_WRITE
;
1485 case POWERPC_MMU_MPC8xx
:
1487 cpu_abort(env
, "MPC8xx MMU model is not implemented\n");
1489 case POWERPC_MMU_BOOKE206
:
1490 cpu_abort(env
, "BookE 2.06 MMU doesn't have physical real mode\n");
1493 cpu_abort(env
, "Unknown or invalid MMU model\n");
1500 static int get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
1501 target_ulong eaddr
, int rw
, int access_type
)
1506 qemu_log("%s\n", __func__
);
1508 if ((access_type
== ACCESS_CODE
&& msr_ir
== 0) ||
1509 (access_type
!= ACCESS_CODE
&& msr_dr
== 0)) {
1510 if (env
->mmu_model
== POWERPC_MMU_BOOKE
) {
1511 /* The BookE MMU always performs address translation. The
1512 IS and DS bits only affect the address space. */
1513 ret
= mmubooke_get_physical_address(env
, ctx
, eaddr
,
1515 } else if (env
->mmu_model
== POWERPC_MMU_BOOKE206
) {
1516 ret
= mmubooke206_get_physical_address(env
, ctx
, eaddr
, rw
,
1519 /* No address translation. */
1520 ret
= check_physical(env
, ctx
, eaddr
, rw
);
1524 switch (env
->mmu_model
) {
1525 case POWERPC_MMU_32B
:
1526 case POWERPC_MMU_601
:
1527 case POWERPC_MMU_SOFT_6xx
:
1528 case POWERPC_MMU_SOFT_74xx
:
1529 /* Try to find a BAT */
1530 if (env
->nb_BATs
!= 0) {
1531 ret
= get_bat(env
, ctx
, eaddr
, rw
, access_type
);
1533 #if defined(TARGET_PPC64)
1534 case POWERPC_MMU_64B
:
1535 case POWERPC_MMU_2_06
:
1536 case POWERPC_MMU_2_06d
:
1539 /* We didn't match any BAT entry or don't have BATs */
1540 ret
= get_segment(env
, ctx
, eaddr
, rw
, access_type
);
1543 case POWERPC_MMU_SOFT_4xx
:
1544 case POWERPC_MMU_SOFT_4xx_Z
:
1545 ret
= mmu40x_get_physical_address(env
, ctx
, eaddr
,
1548 case POWERPC_MMU_BOOKE
:
1549 ret
= mmubooke_get_physical_address(env
, ctx
, eaddr
,
1552 case POWERPC_MMU_BOOKE206
:
1553 ret
= mmubooke206_get_physical_address(env
, ctx
, eaddr
, rw
,
1556 case POWERPC_MMU_MPC8xx
:
1558 cpu_abort(env
, "MPC8xx MMU model is not implemented\n");
1560 case POWERPC_MMU_REAL
:
1561 cpu_abort(env
, "PowerPC in real mode do not do any translation\n");
1564 cpu_abort(env
, "Unknown or invalid MMU model\n");
1569 qemu_log("%s address " TARGET_FMT_lx
" => %d " TARGET_FMT_plx
"\n",
1570 __func__
, eaddr
, ret
, ctx
->raddr
);
1576 hwaddr
cpu_get_phys_page_debug(CPUPPCState
*env
, target_ulong addr
)
1580 if (unlikely(get_physical_address(env
, &ctx
, addr
, 0, ACCESS_INT
) != 0)) {
1584 return ctx
.raddr
& TARGET_PAGE_MASK
;
1587 static void booke206_update_mas_tlb_miss(CPUPPCState
*env
, target_ulong address
,
1590 env
->spr
[SPR_BOOKE_MAS0
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TLBSELD_MASK
;
1591 env
->spr
[SPR_BOOKE_MAS1
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TSIZED_MASK
;
1592 env
->spr
[SPR_BOOKE_MAS2
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_WIMGED_MASK
;
1593 env
->spr
[SPR_BOOKE_MAS3
] = 0;
1594 env
->spr
[SPR_BOOKE_MAS6
] = 0;
1595 env
->spr
[SPR_BOOKE_MAS7
] = 0;
1598 if (((rw
== 2) && msr_ir
) || ((rw
!= 2) && msr_dr
)) {
1599 env
->spr
[SPR_BOOKE_MAS1
] |= MAS1_TS
;
1600 env
->spr
[SPR_BOOKE_MAS6
] |= MAS6_SAS
;
1603 env
->spr
[SPR_BOOKE_MAS1
] |= MAS1_VALID
;
1604 env
->spr
[SPR_BOOKE_MAS2
] |= address
& MAS2_EPN_MASK
;
1606 switch (env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TIDSELD_PIDZ
) {
1607 case MAS4_TIDSELD_PID0
:
1608 env
->spr
[SPR_BOOKE_MAS1
] |= env
->spr
[SPR_BOOKE_PID
] << MAS1_TID_SHIFT
;
1610 case MAS4_TIDSELD_PID1
:
1611 env
->spr
[SPR_BOOKE_MAS1
] |= env
->spr
[SPR_BOOKE_PID1
] << MAS1_TID_SHIFT
;
1613 case MAS4_TIDSELD_PID2
:
1614 env
->spr
[SPR_BOOKE_MAS1
] |= env
->spr
[SPR_BOOKE_PID2
] << MAS1_TID_SHIFT
;
1618 env
->spr
[SPR_BOOKE_MAS6
] |= env
->spr
[SPR_BOOKE_PID
] << 16;
1620 /* next victim logic */
1621 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_ESEL_SHIFT
;
1623 env
->last_way
&= booke206_tlb_ways(env
, 0) - 1;
1624 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
1627 /* Perform address translation */
1628 int cpu_ppc_handle_mmu_fault(CPUPPCState
*env
, target_ulong address
, int rw
,
1638 access_type
= ACCESS_CODE
;
1641 access_type
= env
->access_type
;
1643 ret
= get_physical_address(env
, &ctx
, address
, rw
, access_type
);
1645 tlb_set_page(env
, address
& TARGET_PAGE_MASK
,
1646 ctx
.raddr
& TARGET_PAGE_MASK
, ctx
.prot
,
1647 mmu_idx
, TARGET_PAGE_SIZE
);
1649 } else if (ret
< 0) {
1651 if (access_type
== ACCESS_CODE
) {
1654 /* No matches in page tables or TLB */
1655 switch (env
->mmu_model
) {
1656 case POWERPC_MMU_SOFT_6xx
:
1657 env
->exception_index
= POWERPC_EXCP_IFTLB
;
1658 env
->error_code
= 1 << 18;
1659 env
->spr
[SPR_IMISS
] = address
;
1660 env
->spr
[SPR_ICMP
] = 0x80000000 | ctx
.ptem
;
1662 case POWERPC_MMU_SOFT_74xx
:
1663 env
->exception_index
= POWERPC_EXCP_IFTLB
;
1665 case POWERPC_MMU_SOFT_4xx
:
1666 case POWERPC_MMU_SOFT_4xx_Z
:
1667 env
->exception_index
= POWERPC_EXCP_ITLB
;
1668 env
->error_code
= 0;
1669 env
->spr
[SPR_40x_DEAR
] = address
;
1670 env
->spr
[SPR_40x_ESR
] = 0x00000000;
1672 case POWERPC_MMU_32B
:
1673 case POWERPC_MMU_601
:
1674 #if defined(TARGET_PPC64)
1675 case POWERPC_MMU_64B
:
1676 case POWERPC_MMU_2_06
:
1677 case POWERPC_MMU_2_06d
:
1679 env
->exception_index
= POWERPC_EXCP_ISI
;
1680 env
->error_code
= 0x40000000;
1682 case POWERPC_MMU_BOOKE206
:
1683 booke206_update_mas_tlb_miss(env
, address
, rw
);
1685 case POWERPC_MMU_BOOKE
:
1686 env
->exception_index
= POWERPC_EXCP_ITLB
;
1687 env
->error_code
= 0;
1688 env
->spr
[SPR_BOOKE_DEAR
] = address
;
1690 case POWERPC_MMU_MPC8xx
:
1692 cpu_abort(env
, "MPC8xx MMU model is not implemented\n");
1694 case POWERPC_MMU_REAL
:
1695 cpu_abort(env
, "PowerPC in real mode should never raise "
1696 "any MMU exceptions\n");
1699 cpu_abort(env
, "Unknown or invalid MMU model\n");
1704 /* Access rights violation */
1705 env
->exception_index
= POWERPC_EXCP_ISI
;
1706 env
->error_code
= 0x08000000;
1709 /* No execute protection violation */
1710 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
1711 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
1712 env
->spr
[SPR_BOOKE_ESR
] = 0x00000000;
1714 env
->exception_index
= POWERPC_EXCP_ISI
;
1715 env
->error_code
= 0x10000000;
1718 /* Direct store exception */
1719 /* No code fetch is allowed in direct-store areas */
1720 env
->exception_index
= POWERPC_EXCP_ISI
;
1721 env
->error_code
= 0x10000000;
1723 #if defined(TARGET_PPC64)
1725 /* No match in segment table */
1726 env
->exception_index
= POWERPC_EXCP_ISEG
;
1727 env
->error_code
= 0;
1734 /* No matches in page tables or TLB */
1735 switch (env
->mmu_model
) {
1736 case POWERPC_MMU_SOFT_6xx
:
1738 env
->exception_index
= POWERPC_EXCP_DSTLB
;
1739 env
->error_code
= 1 << 16;
1741 env
->exception_index
= POWERPC_EXCP_DLTLB
;
1742 env
->error_code
= 0;
1744 env
->spr
[SPR_DMISS
] = address
;
1745 env
->spr
[SPR_DCMP
] = 0x80000000 | ctx
.ptem
;
1747 env
->error_code
|= ctx
.key
<< 19;
1748 env
->spr
[SPR_HASH1
] = env
->htab_base
+
1749 get_pteg_offset(env
, ctx
.hash
[0], HASH_PTE_SIZE_32
);
1750 env
->spr
[SPR_HASH2
] = env
->htab_base
+
1751 get_pteg_offset(env
, ctx
.hash
[1], HASH_PTE_SIZE_32
);
1753 case POWERPC_MMU_SOFT_74xx
:
1755 env
->exception_index
= POWERPC_EXCP_DSTLB
;
1757 env
->exception_index
= POWERPC_EXCP_DLTLB
;
1760 /* Implement LRU algorithm */
1761 env
->error_code
= ctx
.key
<< 19;
1762 env
->spr
[SPR_TLBMISS
] = (address
& ~((target_ulong
)0x3)) |
1763 ((env
->last_way
+ 1) & (env
->nb_ways
- 1));
1764 env
->spr
[SPR_PTEHI
] = 0x80000000 | ctx
.ptem
;
1766 case POWERPC_MMU_SOFT_4xx
:
1767 case POWERPC_MMU_SOFT_4xx_Z
:
1768 env
->exception_index
= POWERPC_EXCP_DTLB
;
1769 env
->error_code
= 0;
1770 env
->spr
[SPR_40x_DEAR
] = address
;
1772 env
->spr
[SPR_40x_ESR
] = 0x00800000;
1774 env
->spr
[SPR_40x_ESR
] = 0x00000000;
1777 case POWERPC_MMU_32B
:
1778 case POWERPC_MMU_601
:
1779 #if defined(TARGET_PPC64)
1780 case POWERPC_MMU_64B
:
1781 case POWERPC_MMU_2_06
:
1782 case POWERPC_MMU_2_06d
:
1784 env
->exception_index
= POWERPC_EXCP_DSI
;
1785 env
->error_code
= 0;
1786 env
->spr
[SPR_DAR
] = address
;
1788 env
->spr
[SPR_DSISR
] = 0x42000000;
1790 env
->spr
[SPR_DSISR
] = 0x40000000;
1793 case POWERPC_MMU_MPC8xx
:
1795 cpu_abort(env
, "MPC8xx MMU model is not implemented\n");
1797 case POWERPC_MMU_BOOKE206
:
1798 booke206_update_mas_tlb_miss(env
, address
, rw
);
1800 case POWERPC_MMU_BOOKE
:
1801 env
->exception_index
= POWERPC_EXCP_DTLB
;
1802 env
->error_code
= 0;
1803 env
->spr
[SPR_BOOKE_DEAR
] = address
;
1804 env
->spr
[SPR_BOOKE_ESR
] = rw
? ESR_ST
: 0;
1806 case POWERPC_MMU_REAL
:
1807 cpu_abort(env
, "PowerPC in real mode should never raise "
1808 "any MMU exceptions\n");
1811 cpu_abort(env
, "Unknown or invalid MMU model\n");
1816 /* Access rights violation */
1817 env
->exception_index
= POWERPC_EXCP_DSI
;
1818 env
->error_code
= 0;
1819 if (env
->mmu_model
== POWERPC_MMU_SOFT_4xx
1820 || env
->mmu_model
== POWERPC_MMU_SOFT_4xx_Z
) {
1821 env
->spr
[SPR_40x_DEAR
] = address
;
1823 env
->spr
[SPR_40x_ESR
] |= 0x00800000;
1825 } else if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
1826 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
1827 env
->spr
[SPR_BOOKE_DEAR
] = address
;
1828 env
->spr
[SPR_BOOKE_ESR
] = rw
? ESR_ST
: 0;
1830 env
->spr
[SPR_DAR
] = address
;
1832 env
->spr
[SPR_DSISR
] = 0x0A000000;
1834 env
->spr
[SPR_DSISR
] = 0x08000000;
1839 /* Direct store exception */
1840 switch (access_type
) {
1842 /* Floating point load/store */
1843 env
->exception_index
= POWERPC_EXCP_ALIGN
;
1844 env
->error_code
= POWERPC_EXCP_ALIGN_FP
;
1845 env
->spr
[SPR_DAR
] = address
;
1848 /* lwarx, ldarx or stwcx. */
1849 env
->exception_index
= POWERPC_EXCP_DSI
;
1850 env
->error_code
= 0;
1851 env
->spr
[SPR_DAR
] = address
;
1853 env
->spr
[SPR_DSISR
] = 0x06000000;
1855 env
->spr
[SPR_DSISR
] = 0x04000000;
1859 /* eciwx or ecowx */
1860 env
->exception_index
= POWERPC_EXCP_DSI
;
1861 env
->error_code
= 0;
1862 env
->spr
[SPR_DAR
] = address
;
1864 env
->spr
[SPR_DSISR
] = 0x06100000;
1866 env
->spr
[SPR_DSISR
] = 0x04100000;
1870 printf("DSI: invalid exception (%d)\n", ret
);
1871 env
->exception_index
= POWERPC_EXCP_PROGRAM
;
1873 POWERPC_EXCP_INVAL
| POWERPC_EXCP_INVAL_INVAL
;
1874 env
->spr
[SPR_DAR
] = address
;
1878 #if defined(TARGET_PPC64)
1880 /* No match in segment table */
1881 env
->exception_index
= POWERPC_EXCP_DSEG
;
1882 env
->error_code
= 0;
1883 env
->spr
[SPR_DAR
] = address
;
1889 printf("%s: set exception to %d %02x\n", __func__
,
1890 env
->exception
, env
->error_code
);
1898 /*****************************************************************************/
1899 /* BATs management */
1900 #if !defined(FLUSH_ALL_TLBS)
1901 static inline void do_invalidate_BAT(CPUPPCState
*env
, target_ulong BATu
,
1904 target_ulong base
, end
, page
;
1906 base
= BATu
& ~0x0001FFFF;
1907 end
= base
+ mask
+ 0x00020000;
1908 LOG_BATS("Flush BAT from " TARGET_FMT_lx
" to " TARGET_FMT_lx
" ("
1909 TARGET_FMT_lx
")\n", base
, end
, mask
);
1910 for (page
= base
; page
!= end
; page
+= TARGET_PAGE_SIZE
) {
1911 tlb_flush_page(env
, page
);
1913 LOG_BATS("Flush done\n");
1917 static inline void dump_store_bat(CPUPPCState
*env
, char ID
, int ul
, int nr
,
1920 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx
" (" TARGET_FMT_lx
")\n", ID
,
1921 nr
, ul
== 0 ? 'u' : 'l', value
, env
->nip
);
1924 void helper_store_ibatu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1928 dump_store_bat(env
, 'I', 0, nr
, value
);
1929 if (env
->IBAT
[0][nr
] != value
) {
1930 mask
= (value
<< 15) & 0x0FFE0000UL
;
1931 #if !defined(FLUSH_ALL_TLBS)
1932 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
1934 /* When storing valid upper BAT, mask BEPI and BRPN
1935 * and invalidate all TLBs covered by this BAT
1937 mask
= (value
<< 15) & 0x0FFE0000UL
;
1938 env
->IBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
1939 (value
& ~0x0001FFFFUL
& ~mask
);
1940 env
->IBAT
[1][nr
] = (env
->IBAT
[1][nr
] & 0x0000007B) |
1941 (env
->IBAT
[1][nr
] & ~0x0001FFFF & ~mask
);
1942 #if !defined(FLUSH_ALL_TLBS)
1943 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
1950 void helper_store_ibatl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1952 dump_store_bat(env
, 'I', 1, nr
, value
);
1953 env
->IBAT
[1][nr
] = value
;
1956 void helper_store_dbatu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1960 dump_store_bat(env
, 'D', 0, nr
, value
);
1961 if (env
->DBAT
[0][nr
] != value
) {
1962 /* When storing valid upper BAT, mask BEPI and BRPN
1963 * and invalidate all TLBs covered by this BAT
1965 mask
= (value
<< 15) & 0x0FFE0000UL
;
1966 #if !defined(FLUSH_ALL_TLBS)
1967 do_invalidate_BAT(env
, env
->DBAT
[0][nr
], mask
);
1969 mask
= (value
<< 15) & 0x0FFE0000UL
;
1970 env
->DBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
1971 (value
& ~0x0001FFFFUL
& ~mask
);
1972 env
->DBAT
[1][nr
] = (env
->DBAT
[1][nr
] & 0x0000007B) |
1973 (env
->DBAT
[1][nr
] & ~0x0001FFFF & ~mask
);
1974 #if !defined(FLUSH_ALL_TLBS)
1975 do_invalidate_BAT(env
, env
->DBAT
[0][nr
], mask
);
1982 void helper_store_dbatl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1984 dump_store_bat(env
, 'D', 1, nr
, value
);
1985 env
->DBAT
[1][nr
] = value
;
1988 void helper_store_601_batu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1991 #if defined(FLUSH_ALL_TLBS)
1995 dump_store_bat(env
, 'I', 0, nr
, value
);
1996 if (env
->IBAT
[0][nr
] != value
) {
1997 #if defined(FLUSH_ALL_TLBS)
2000 mask
= (env
->IBAT
[1][nr
] << 17) & 0x0FFE0000UL
;
2001 if (env
->IBAT
[1][nr
] & 0x40) {
2002 /* Invalidate BAT only if it is valid */
2003 #if !defined(FLUSH_ALL_TLBS)
2004 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
2009 /* When storing valid upper BAT, mask BEPI and BRPN
2010 * and invalidate all TLBs covered by this BAT
2012 env
->IBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
2013 (value
& ~0x0001FFFFUL
& ~mask
);
2014 env
->DBAT
[0][nr
] = env
->IBAT
[0][nr
];
2015 if (env
->IBAT
[1][nr
] & 0x40) {
2016 #if !defined(FLUSH_ALL_TLBS)
2017 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
2022 #if defined(FLUSH_ALL_TLBS)
2030 void helper_store_601_batl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
2032 #if !defined(FLUSH_ALL_TLBS)
2038 dump_store_bat(env
, 'I', 1, nr
, value
);
2039 if (env
->IBAT
[1][nr
] != value
) {
2040 #if defined(FLUSH_ALL_TLBS)
2043 if (env
->IBAT
[1][nr
] & 0x40) {
2044 #if !defined(FLUSH_ALL_TLBS)
2045 mask
= (env
->IBAT
[1][nr
] << 17) & 0x0FFE0000UL
;
2046 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
2052 #if !defined(FLUSH_ALL_TLBS)
2053 mask
= (value
<< 17) & 0x0FFE0000UL
;
2054 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
2059 env
->IBAT
[1][nr
] = value
;
2060 env
->DBAT
[1][nr
] = value
;
2061 #if defined(FLUSH_ALL_TLBS)
2069 /*****************************************************************************/
2070 /* TLB management */
2071 void ppc_tlb_invalidate_all(CPUPPCState
*env
)
2073 switch (env
->mmu_model
) {
2074 case POWERPC_MMU_SOFT_6xx
:
2075 case POWERPC_MMU_SOFT_74xx
:
2076 ppc6xx_tlb_invalidate_all(env
);
2078 case POWERPC_MMU_SOFT_4xx
:
2079 case POWERPC_MMU_SOFT_4xx_Z
:
2080 ppc4xx_tlb_invalidate_all(env
);
2082 case POWERPC_MMU_REAL
:
2083 cpu_abort(env
, "No TLB for PowerPC 4xx in real mode\n");
2085 case POWERPC_MMU_MPC8xx
:
2087 cpu_abort(env
, "MPC8xx MMU model is not implemented\n");
2089 case POWERPC_MMU_BOOKE
:
2092 case POWERPC_MMU_BOOKE206
:
2093 booke206_flush_tlb(env
, -1, 0);
2095 case POWERPC_MMU_32B
:
2096 case POWERPC_MMU_601
:
2097 #if defined(TARGET_PPC64)
2098 case POWERPC_MMU_64B
:
2099 case POWERPC_MMU_2_06
:
2100 case POWERPC_MMU_2_06d
:
2101 #endif /* defined(TARGET_PPC64) */
2106 cpu_abort(env
, "Unknown MMU model\n");
2111 void ppc_tlb_invalidate_one(CPUPPCState
*env
, target_ulong addr
)
2113 #if !defined(FLUSH_ALL_TLBS)
2114 addr
&= TARGET_PAGE_MASK
;
2115 switch (env
->mmu_model
) {
2116 case POWERPC_MMU_SOFT_6xx
:
2117 case POWERPC_MMU_SOFT_74xx
:
2118 ppc6xx_tlb_invalidate_virt(env
, addr
, 0);
2119 if (env
->id_tlbs
== 1) {
2120 ppc6xx_tlb_invalidate_virt(env
, addr
, 1);
2123 case POWERPC_MMU_SOFT_4xx
:
2124 case POWERPC_MMU_SOFT_4xx_Z
:
2125 ppc4xx_tlb_invalidate_virt(env
, addr
, env
->spr
[SPR_40x_PID
]);
2127 case POWERPC_MMU_REAL
:
2128 cpu_abort(env
, "No TLB for PowerPC 4xx in real mode\n");
2130 case POWERPC_MMU_MPC8xx
:
2132 cpu_abort(env
, "MPC8xx MMU model is not implemented\n");
2134 case POWERPC_MMU_BOOKE
:
2136 cpu_abort(env
, "BookE MMU model is not implemented\n");
2138 case POWERPC_MMU_BOOKE206
:
2140 cpu_abort(env
, "BookE 2.06 MMU model is not implemented\n");
2142 case POWERPC_MMU_32B
:
2143 case POWERPC_MMU_601
:
2144 /* tlbie invalidate TLBs for all segments */
2145 addr
&= ~((target_ulong
)-1ULL << 28);
2146 /* XXX: this case should be optimized,
2147 * giving a mask to tlb_flush_page
2149 tlb_flush_page(env
, addr
| (0x0 << 28));
2150 tlb_flush_page(env
, addr
| (0x1 << 28));
2151 tlb_flush_page(env
, addr
| (0x2 << 28));
2152 tlb_flush_page(env
, addr
| (0x3 << 28));
2153 tlb_flush_page(env
, addr
| (0x4 << 28));
2154 tlb_flush_page(env
, addr
| (0x5 << 28));
2155 tlb_flush_page(env
, addr
| (0x6 << 28));
2156 tlb_flush_page(env
, addr
| (0x7 << 28));
2157 tlb_flush_page(env
, addr
| (0x8 << 28));
2158 tlb_flush_page(env
, addr
| (0x9 << 28));
2159 tlb_flush_page(env
, addr
| (0xA << 28));
2160 tlb_flush_page(env
, addr
| (0xB << 28));
2161 tlb_flush_page(env
, addr
| (0xC << 28));
2162 tlb_flush_page(env
, addr
| (0xD << 28));
2163 tlb_flush_page(env
, addr
| (0xE << 28));
2164 tlb_flush_page(env
, addr
| (0xF << 28));
2166 #if defined(TARGET_PPC64)
2167 case POWERPC_MMU_64B
:
2168 case POWERPC_MMU_2_06
:
2169 case POWERPC_MMU_2_06d
:
2170 /* tlbie invalidate TLBs for all segments */
2171 /* XXX: given the fact that there are too many segments to invalidate,
2172 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2173 * we just invalidate all TLBs
2177 #endif /* defined(TARGET_PPC64) */
2180 cpu_abort(env
, "Unknown MMU model\n");
2184 ppc_tlb_invalidate_all(env
);
2188 /*****************************************************************************/
2189 /* Special registers manipulation */
2190 void ppc_store_sdr1(CPUPPCState
*env
, target_ulong value
)
2192 LOG_MMU("%s: " TARGET_FMT_lx
"\n", __func__
, value
);
2193 if (env
->spr
[SPR_SDR1
] != value
) {
2194 env
->spr
[SPR_SDR1
] = value
;
2195 #if defined(TARGET_PPC64)
2196 if (env
->mmu_model
& POWERPC_MMU_64
) {
2197 target_ulong htabsize
= value
& SDR_64_HTABSIZE
;
2199 if (htabsize
> 28) {
2200 fprintf(stderr
, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2201 " stored in SDR1\n", htabsize
);
2204 env
->htab_mask
= (1ULL << (htabsize
+ 18)) - 1;
2205 env
->htab_base
= value
& SDR_64_HTABORG
;
2207 #endif /* defined(TARGET_PPC64) */
2209 /* FIXME: Should check for valid HTABMASK values */
2210 env
->htab_mask
= ((value
& SDR_32_HTABMASK
) << 16) | 0xFFFF;
2211 env
->htab_base
= value
& SDR_32_HTABORG
;
2217 /* Segment registers load and store */
2218 target_ulong
helper_load_sr(CPUPPCState
*env
, target_ulong sr_num
)
2220 #if defined(TARGET_PPC64)
2221 if (env
->mmu_model
& POWERPC_MMU_64
) {
2226 return env
->sr
[sr_num
];
2229 void helper_store_sr(CPUPPCState
*env
, target_ulong srnum
, target_ulong value
)
2231 LOG_MMU("%s: reg=%d " TARGET_FMT_lx
" " TARGET_FMT_lx
"\n", __func__
,
2232 (int)srnum
, value
, env
->sr
[srnum
]);
2233 #if defined(TARGET_PPC64)
2234 if (env
->mmu_model
& POWERPC_MMU_64
) {
2235 uint64_t rb
= 0, rs
= 0;
2238 rb
|= ((uint32_t)srnum
& 0xf) << 28;
2239 /* Set the valid bit */
2242 rb
|= (uint32_t)srnum
;
2245 rs
|= (value
& 0xfffffff) << 12;
2247 rs
|= ((value
>> 27) & 0xf) << 8;
2249 ppc_store_slb(env
, rb
, rs
);
2252 if (env
->sr
[srnum
] != value
) {
2253 env
->sr
[srnum
] = value
;
2254 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2255 flusing the whole TLB. */
2256 #if !defined(FLUSH_ALL_TLBS) && 0
2258 target_ulong page
, end
;
2259 /* Invalidate 256 MB of virtual memory */
2260 page
= (16 << 20) * srnum
;
2261 end
= page
+ (16 << 20);
2262 for (; page
!= end
; page
+= TARGET_PAGE_SIZE
) {
2263 tlb_flush_page(env
, page
);
2271 #endif /* !defined(CONFIG_USER_ONLY) */
2273 #if !defined(CONFIG_USER_ONLY)
2274 /* TLB management */
2275 void helper_tlbia(CPUPPCState
*env
)
2277 ppc_tlb_invalidate_all(env
);
2280 void helper_tlbie(CPUPPCState
*env
, target_ulong addr
)
2282 ppc_tlb_invalidate_one(env
, addr
);
2285 /* Software driven TLBs management */
2286 /* PowerPC 602/603 software TLB load instructions helpers */
2287 static void do_6xx_tlb(CPUPPCState
*env
, target_ulong new_EPN
, int is_code
)
2289 target_ulong RPN
, CMP
, EPN
;
2292 RPN
= env
->spr
[SPR_RPA
];
2294 CMP
= env
->spr
[SPR_ICMP
];
2295 EPN
= env
->spr
[SPR_IMISS
];
2297 CMP
= env
->spr
[SPR_DCMP
];
2298 EPN
= env
->spr
[SPR_DMISS
];
2300 way
= (env
->spr
[SPR_SRR1
] >> 17) & 1;
2301 (void)EPN
; /* avoid a compiler warning */
2302 LOG_SWTLB("%s: EPN " TARGET_FMT_lx
" " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
2303 " PTE1 " TARGET_FMT_lx
" way %d\n", __func__
, new_EPN
, EPN
, CMP
,
2305 /* Store this TLB */
2306 ppc6xx_tlb_store(env
, (uint32_t)(new_EPN
& TARGET_PAGE_MASK
),
2307 way
, is_code
, CMP
, RPN
);
2310 void helper_6xx_tlbd(CPUPPCState
*env
, target_ulong EPN
)
2312 do_6xx_tlb(env
, EPN
, 0);
2315 void helper_6xx_tlbi(CPUPPCState
*env
, target_ulong EPN
)
2317 do_6xx_tlb(env
, EPN
, 1);
2320 /* PowerPC 74xx software TLB load instructions helpers */
2321 static void do_74xx_tlb(CPUPPCState
*env
, target_ulong new_EPN
, int is_code
)
2323 target_ulong RPN
, CMP
, EPN
;
2326 RPN
= env
->spr
[SPR_PTELO
];
2327 CMP
= env
->spr
[SPR_PTEHI
];
2328 EPN
= env
->spr
[SPR_TLBMISS
] & ~0x3;
2329 way
= env
->spr
[SPR_TLBMISS
] & 0x3;
2330 (void)EPN
; /* avoid a compiler warning */
2331 LOG_SWTLB("%s: EPN " TARGET_FMT_lx
" " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
2332 " PTE1 " TARGET_FMT_lx
" way %d\n", __func__
, new_EPN
, EPN
, CMP
,
2334 /* Store this TLB */
2335 ppc6xx_tlb_store(env
, (uint32_t)(new_EPN
& TARGET_PAGE_MASK
),
2336 way
, is_code
, CMP
, RPN
);
2339 void helper_74xx_tlbd(CPUPPCState
*env
, target_ulong EPN
)
2341 do_74xx_tlb(env
, EPN
, 0);
2344 void helper_74xx_tlbi(CPUPPCState
*env
, target_ulong EPN
)
2346 do_74xx_tlb(env
, EPN
, 1);
2349 /*****************************************************************************/
2350 /* PowerPC 601 specific instructions (POWER bridge) */
2352 target_ulong
helper_rac(CPUPPCState
*env
, target_ulong addr
)
2356 target_ulong ret
= 0;
2358 /* We don't have to generate many instances of this instruction,
2359 * as rac is supervisor only.
2361 /* XXX: FIX THIS: Pretend we have no BAT */
2362 nb_BATs
= env
->nb_BATs
;
2364 if (get_physical_address(env
, &ctx
, addr
, 0, ACCESS_INT
) == 0) {
2367 env
->nb_BATs
= nb_BATs
;
2371 static inline target_ulong
booke_tlb_to_page_size(int size
)
2373 return 1024 << (2 * size
);
2376 static inline int booke_page_size_to_tlb(target_ulong page_size
)
2380 switch (page_size
) {
2414 #if defined(TARGET_PPC64)
2415 case 0x000100000000ULL
:
2418 case 0x000400000000ULL
:
2421 case 0x001000000000ULL
:
2424 case 0x004000000000ULL
:
2427 case 0x010000000000ULL
:
2439 /* Helpers for 4xx TLB management */
2440 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2442 #define PPC4XX_TLBHI_V 0x00000040
2443 #define PPC4XX_TLBHI_E 0x00000020
2444 #define PPC4XX_TLBHI_SIZE_MIN 0
2445 #define PPC4XX_TLBHI_SIZE_MAX 7
2446 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2447 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2448 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2450 #define PPC4XX_TLBLO_EX 0x00000200
2451 #define PPC4XX_TLBLO_WR 0x00000100
2452 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2453 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2455 target_ulong
helper_4xx_tlbre_hi(CPUPPCState
*env
, target_ulong entry
)
2461 entry
&= PPC4XX_TLB_ENTRY_MASK
;
2462 tlb
= &env
->tlb
.tlbe
[entry
];
2464 if (tlb
->prot
& PAGE_VALID
) {
2465 ret
|= PPC4XX_TLBHI_V
;
2467 size
= booke_page_size_to_tlb(tlb
->size
);
2468 if (size
< PPC4XX_TLBHI_SIZE_MIN
|| size
> PPC4XX_TLBHI_SIZE_MAX
) {
2469 size
= PPC4XX_TLBHI_SIZE_DEFAULT
;
2471 ret
|= size
<< PPC4XX_TLBHI_SIZE_SHIFT
;
2472 env
->spr
[SPR_40x_PID
] = tlb
->PID
;
2476 target_ulong
helper_4xx_tlbre_lo(CPUPPCState
*env
, target_ulong entry
)
2481 entry
&= PPC4XX_TLB_ENTRY_MASK
;
2482 tlb
= &env
->tlb
.tlbe
[entry
];
2484 if (tlb
->prot
& PAGE_EXEC
) {
2485 ret
|= PPC4XX_TLBLO_EX
;
2487 if (tlb
->prot
& PAGE_WRITE
) {
2488 ret
|= PPC4XX_TLBLO_WR
;
2493 void helper_4xx_tlbwe_hi(CPUPPCState
*env
, target_ulong entry
,
2497 target_ulong page
, end
;
2499 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx
"\n", __func__
, (int)entry
,
2501 entry
&= PPC4XX_TLB_ENTRY_MASK
;
2502 tlb
= &env
->tlb
.tlbe
[entry
];
2503 /* Invalidate previous TLB (if it's valid) */
2504 if (tlb
->prot
& PAGE_VALID
) {
2505 end
= tlb
->EPN
+ tlb
->size
;
2506 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx
" end "
2507 TARGET_FMT_lx
"\n", __func__
, (int)entry
, tlb
->EPN
, end
);
2508 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
2509 tlb_flush_page(env
, page
);
2512 tlb
->size
= booke_tlb_to_page_size((val
>> PPC4XX_TLBHI_SIZE_SHIFT
)
2513 & PPC4XX_TLBHI_SIZE_MASK
);
2514 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2515 * If this ever occurs, one should use the ppcemb target instead
2516 * of the ppc or ppc64 one
2518 if ((val
& PPC4XX_TLBHI_V
) && tlb
->size
< TARGET_PAGE_SIZE
) {
2519 cpu_abort(env
, "TLB size " TARGET_FMT_lu
" < %u "
2520 "are not supported (%d)\n",
2521 tlb
->size
, TARGET_PAGE_SIZE
, (int)((val
>> 7) & 0x7));
2523 tlb
->EPN
= val
& ~(tlb
->size
- 1);
2524 if (val
& PPC4XX_TLBHI_V
) {
2525 tlb
->prot
|= PAGE_VALID
;
2526 if (val
& PPC4XX_TLBHI_E
) {
2527 /* XXX: TO BE FIXED */
2529 "Little-endian TLB entries are not supported by now\n");
2532 tlb
->prot
&= ~PAGE_VALID
;
2534 tlb
->PID
= env
->spr
[SPR_40x_PID
]; /* PID */
2535 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx
" EPN " TARGET_FMT_lx
2536 " size " TARGET_FMT_lx
" prot %c%c%c%c PID %d\n", __func__
,
2537 (int)entry
, tlb
->RPN
, tlb
->EPN
, tlb
->size
,
2538 tlb
->prot
& PAGE_READ
? 'r' : '-',
2539 tlb
->prot
& PAGE_WRITE
? 'w' : '-',
2540 tlb
->prot
& PAGE_EXEC
? 'x' : '-',
2541 tlb
->prot
& PAGE_VALID
? 'v' : '-', (int)tlb
->PID
);
2542 /* Invalidate new TLB (if valid) */
2543 if (tlb
->prot
& PAGE_VALID
) {
2544 end
= tlb
->EPN
+ tlb
->size
;
2545 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx
" end "
2546 TARGET_FMT_lx
"\n", __func__
, (int)entry
, tlb
->EPN
, end
);
2547 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
2548 tlb_flush_page(env
, page
);
2553 void helper_4xx_tlbwe_lo(CPUPPCState
*env
, target_ulong entry
,
2558 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx
"\n", __func__
, (int)entry
,
2560 entry
&= PPC4XX_TLB_ENTRY_MASK
;
2561 tlb
= &env
->tlb
.tlbe
[entry
];
2562 tlb
->attr
= val
& PPC4XX_TLBLO_ATTR_MASK
;
2563 tlb
->RPN
= val
& PPC4XX_TLBLO_RPN_MASK
;
2564 tlb
->prot
= PAGE_READ
;
2565 if (val
& PPC4XX_TLBLO_EX
) {
2566 tlb
->prot
|= PAGE_EXEC
;
2568 if (val
& PPC4XX_TLBLO_WR
) {
2569 tlb
->prot
|= PAGE_WRITE
;
2571 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx
" EPN " TARGET_FMT_lx
2572 " size " TARGET_FMT_lx
" prot %c%c%c%c PID %d\n", __func__
,
2573 (int)entry
, tlb
->RPN
, tlb
->EPN
, tlb
->size
,
2574 tlb
->prot
& PAGE_READ
? 'r' : '-',
2575 tlb
->prot
& PAGE_WRITE
? 'w' : '-',
2576 tlb
->prot
& PAGE_EXEC
? 'x' : '-',
2577 tlb
->prot
& PAGE_VALID
? 'v' : '-', (int)tlb
->PID
);
2580 target_ulong
helper_4xx_tlbsx(CPUPPCState
*env
, target_ulong address
)
2582 return ppcemb_tlb_search(env
, address
, env
->spr
[SPR_40x_PID
]);
2585 /* PowerPC 440 TLB management */
2586 void helper_440_tlbwe(CPUPPCState
*env
, uint32_t word
, target_ulong entry
,
2590 target_ulong EPN
, RPN
, size
;
2593 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx
"\n",
2594 __func__
, word
, (int)entry
, value
);
2597 tlb
= &env
->tlb
.tlbe
[entry
];
2600 /* Just here to please gcc */
2602 EPN
= value
& 0xFFFFFC00;
2603 if ((tlb
->prot
& PAGE_VALID
) && EPN
!= tlb
->EPN
) {
2607 size
= booke_tlb_to_page_size((value
>> 4) & 0xF);
2608 if ((tlb
->prot
& PAGE_VALID
) && tlb
->size
< size
) {
2613 tlb
->attr
|= (value
>> 8) & 1;
2614 if (value
& 0x200) {
2615 tlb
->prot
|= PAGE_VALID
;
2617 if (tlb
->prot
& PAGE_VALID
) {
2618 tlb
->prot
&= ~PAGE_VALID
;
2622 tlb
->PID
= env
->spr
[SPR_440_MMUCR
] & 0x000000FF;
2623 if (do_flush_tlbs
) {
2628 RPN
= value
& 0xFFFFFC0F;
2629 if ((tlb
->prot
& PAGE_VALID
) && tlb
->RPN
!= RPN
) {
2635 tlb
->attr
= (tlb
->attr
& 0x1) | (value
& 0x0000FF00);
2636 tlb
->prot
= tlb
->prot
& PAGE_VALID
;
2638 tlb
->prot
|= PAGE_READ
<< 4;
2641 tlb
->prot
|= PAGE_WRITE
<< 4;
2644 tlb
->prot
|= PAGE_EXEC
<< 4;
2647 tlb
->prot
|= PAGE_READ
;
2650 tlb
->prot
|= PAGE_WRITE
;
2653 tlb
->prot
|= PAGE_EXEC
;
2659 target_ulong
helper_440_tlbre(CPUPPCState
*env
, uint32_t word
,
2667 tlb
= &env
->tlb
.tlbe
[entry
];
2670 /* Just here to please gcc */
2673 size
= booke_page_size_to_tlb(tlb
->size
);
2674 if (size
< 0 || size
> 0xF) {
2678 if (tlb
->attr
& 0x1) {
2681 if (tlb
->prot
& PAGE_VALID
) {
2684 env
->spr
[SPR_440_MMUCR
] &= ~0x000000FF;
2685 env
->spr
[SPR_440_MMUCR
] |= tlb
->PID
;
2691 ret
= tlb
->attr
& ~0x1;
2692 if (tlb
->prot
& (PAGE_READ
<< 4)) {
2695 if (tlb
->prot
& (PAGE_WRITE
<< 4)) {
2698 if (tlb
->prot
& (PAGE_EXEC
<< 4)) {
2701 if (tlb
->prot
& PAGE_READ
) {
2704 if (tlb
->prot
& PAGE_WRITE
) {
2707 if (tlb
->prot
& PAGE_EXEC
) {
2715 target_ulong
helper_440_tlbsx(CPUPPCState
*env
, target_ulong address
)
2717 return ppcemb_tlb_search(env
, address
, env
->spr
[SPR_440_MMUCR
] & 0xFF);
2720 /* PowerPC BookE 2.06 TLB management */
2722 static ppcmas_tlb_t
*booke206_cur_tlb(CPUPPCState
*env
)
2724 uint32_t tlbncfg
= 0;
2725 int esel
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_ESEL_MASK
) >> MAS0_ESEL_SHIFT
;
2726 int ea
= (env
->spr
[SPR_BOOKE_MAS2
] & MAS2_EPN_MASK
);
2729 tlb
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_TLBSEL_MASK
) >> MAS0_TLBSEL_SHIFT
;
2730 tlbncfg
= env
->spr
[SPR_BOOKE_TLB0CFG
+ tlb
];
2732 if ((tlbncfg
& TLBnCFG_HES
) && (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_HES
)) {
2733 cpu_abort(env
, "we don't support HES yet\n");
2736 return booke206_get_tlbm(env
, tlb
, ea
, esel
);
2739 void helper_booke_setpid(CPUPPCState
*env
, uint32_t pidn
, target_ulong pid
)
2741 env
->spr
[pidn
] = pid
;
2742 /* changing PIDs mean we're in a different address space now */
2746 void helper_booke206_tlbwe(CPUPPCState
*env
)
2748 uint32_t tlbncfg
, tlbn
;
2750 uint32_t size_tlb
, size_ps
;
2754 switch (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_WQ_MASK
) {
2755 case MAS0_WQ_ALWAYS
:
2756 /* good to go, write that entry */
2759 /* XXX check if reserved */
2764 case MAS0_WQ_CLR_RSRV
:
2765 /* XXX clear entry */
2768 /* no idea what to do */
2772 if (((env
->spr
[SPR_BOOKE_MAS0
] & MAS0_ATSEL
) == MAS0_ATSEL_LRAT
) &&
2774 /* XXX we don't support direct LRAT setting yet */
2775 fprintf(stderr
, "cpu: don't support LRAT setting yet\n");
2779 tlbn
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_TLBSEL_MASK
) >> MAS0_TLBSEL_SHIFT
;
2780 tlbncfg
= env
->spr
[SPR_BOOKE_TLB0CFG
+ tlbn
];
2782 tlb
= booke206_cur_tlb(env
);
2785 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
2786 POWERPC_EXCP_INVAL
|
2787 POWERPC_EXCP_INVAL_INVAL
);
2790 /* check that we support the targeted size */
2791 size_tlb
= (env
->spr
[SPR_BOOKE_MAS1
] & MAS1_TSIZE_MASK
) >> MAS1_TSIZE_SHIFT
;
2792 size_ps
= booke206_tlbnps(env
, tlbn
);
2793 if ((env
->spr
[SPR_BOOKE_MAS1
] & MAS1_VALID
) && (tlbncfg
& TLBnCFG_AVAIL
) &&
2794 !(size_ps
& (1 << size_tlb
))) {
2795 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
2796 POWERPC_EXCP_INVAL
|
2797 POWERPC_EXCP_INVAL_INVAL
);
2801 cpu_abort(env
, "missing HV implementation\n");
2803 tlb
->mas7_3
= ((uint64_t)env
->spr
[SPR_BOOKE_MAS7
] << 32) |
2804 env
->spr
[SPR_BOOKE_MAS3
];
2805 tlb
->mas1
= env
->spr
[SPR_BOOKE_MAS1
];
2808 if (!(tlbncfg
& TLBnCFG_AVAIL
)) {
2809 /* force !AVAIL TLB entries to correct page size */
2810 tlb
->mas1
&= ~MAS1_TSIZE_MASK
;
2811 /* XXX can be configured in MMUCSR0 */
2812 tlb
->mas1
|= (tlbncfg
& TLBnCFG_MINSIZE
) >> 12;
2815 /* Make a mask from TLB size to discard invalid bits in EPN field */
2816 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
2817 /* Add a mask for page attributes */
2818 mask
|= MAS2_ACM
| MAS2_VLE
| MAS2_W
| MAS2_I
| MAS2_M
| MAS2_G
| MAS2_E
;
2821 /* Executing a tlbwe instruction in 32-bit mode will set
2822 * bits 0:31 of the TLB EPN field to zero.
2827 tlb
->mas2
= env
->spr
[SPR_BOOKE_MAS2
] & mask
;
2829 if (!(tlbncfg
& TLBnCFG_IPROT
)) {
2830 /* no IPROT supported by TLB */
2831 tlb
->mas1
&= ~MAS1_IPROT
;
2834 if (booke206_tlb_to_page_size(env
, tlb
) == TARGET_PAGE_SIZE
) {
2835 tlb_flush_page(env
, tlb
->mas2
& MAS2_EPN_MASK
);
2841 static inline void booke206_tlb_to_mas(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
)
2843 int tlbn
= booke206_tlbm_to_tlbn(env
, tlb
);
2844 int way
= booke206_tlbm_to_way(env
, tlb
);
2846 env
->spr
[SPR_BOOKE_MAS0
] = tlbn
<< MAS0_TLBSEL_SHIFT
;
2847 env
->spr
[SPR_BOOKE_MAS0
] |= way
<< MAS0_ESEL_SHIFT
;
2848 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
2850 env
->spr
[SPR_BOOKE_MAS1
] = tlb
->mas1
;
2851 env
->spr
[SPR_BOOKE_MAS2
] = tlb
->mas2
;
2852 env
->spr
[SPR_BOOKE_MAS3
] = tlb
->mas7_3
;
2853 env
->spr
[SPR_BOOKE_MAS7
] = tlb
->mas7_3
>> 32;
2856 void helper_booke206_tlbre(CPUPPCState
*env
)
2858 ppcmas_tlb_t
*tlb
= NULL
;
2860 tlb
= booke206_cur_tlb(env
);
2862 env
->spr
[SPR_BOOKE_MAS1
] = 0;
2864 booke206_tlb_to_mas(env
, tlb
);
2868 void helper_booke206_tlbsx(CPUPPCState
*env
, target_ulong address
)
2870 ppcmas_tlb_t
*tlb
= NULL
;
2875 spid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID_MASK
) >> MAS6_SPID_SHIFT
;
2876 sas
= env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SAS
;
2878 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
2879 int ways
= booke206_tlb_ways(env
, i
);
2881 for (j
= 0; j
< ways
; j
++) {
2882 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
2888 if (ppcmas_tlb_check(env
, tlb
, &raddr
, address
, spid
)) {
2892 if (sas
!= ((tlb
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
)) {
2896 booke206_tlb_to_mas(env
, tlb
);
2901 /* no entry found, fill with defaults */
2902 env
->spr
[SPR_BOOKE_MAS0
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TLBSELD_MASK
;
2903 env
->spr
[SPR_BOOKE_MAS1
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TSIZED_MASK
;
2904 env
->spr
[SPR_BOOKE_MAS2
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_WIMGED_MASK
;
2905 env
->spr
[SPR_BOOKE_MAS3
] = 0;
2906 env
->spr
[SPR_BOOKE_MAS7
] = 0;
2908 if (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SAS
) {
2909 env
->spr
[SPR_BOOKE_MAS1
] |= MAS1_TS
;
2912 env
->spr
[SPR_BOOKE_MAS1
] |= (env
->spr
[SPR_BOOKE_MAS6
] >> 16)
2915 /* next victim logic */
2916 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_ESEL_SHIFT
;
2918 env
->last_way
&= booke206_tlb_ways(env
, 0) - 1;
2919 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
2922 static inline void booke206_invalidate_ea_tlb(CPUPPCState
*env
, int tlbn
,
2926 int ways
= booke206_tlb_ways(env
, tlbn
);
2929 for (i
= 0; i
< ways
; i
++) {
2930 ppcmas_tlb_t
*tlb
= booke206_get_tlbm(env
, tlbn
, ea
, i
);
2934 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
2935 if (((tlb
->mas2
& MAS2_EPN_MASK
) == (ea
& mask
)) &&
2936 !(tlb
->mas1
& MAS1_IPROT
)) {
2937 tlb
->mas1
&= ~MAS1_VALID
;
2942 void helper_booke206_tlbivax(CPUPPCState
*env
, target_ulong address
)
2944 if (address
& 0x4) {
2945 /* flush all entries */
2946 if (address
& 0x8) {
2947 /* flush all of TLB1 */
2948 booke206_flush_tlb(env
, BOOKE206_FLUSH_TLB1
, 1);
2950 /* flush all of TLB0 */
2951 booke206_flush_tlb(env
, BOOKE206_FLUSH_TLB0
, 0);
2956 if (address
& 0x8) {
2957 /* flush TLB1 entries */
2958 booke206_invalidate_ea_tlb(env
, 1, address
);
2961 /* flush TLB0 entries */
2962 booke206_invalidate_ea_tlb(env
, 0, address
);
2963 tlb_flush_page(env
, address
& MAS2_EPN_MASK
);
2967 void helper_booke206_tlbilx0(CPUPPCState
*env
, target_ulong address
)
2969 /* XXX missing LPID handling */
2970 booke206_flush_tlb(env
, -1, 1);
2973 void helper_booke206_tlbilx1(CPUPPCState
*env
, target_ulong address
)
2976 int tid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID
);
2977 ppcmas_tlb_t
*tlb
= env
->tlb
.tlbm
;
2980 /* XXX missing LPID handling */
2981 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
2982 tlb_size
= booke206_tlb_size(env
, i
);
2983 for (j
= 0; j
< tlb_size
; j
++) {
2984 if (!(tlb
[j
].mas1
& MAS1_IPROT
) &&
2985 ((tlb
[j
].mas1
& MAS1_TID_MASK
) == tid
)) {
2986 tlb
[j
].mas1
&= ~MAS1_VALID
;
2989 tlb
+= booke206_tlb_size(env
, i
);
2994 void helper_booke206_tlbilx3(CPUPPCState
*env
, target_ulong address
)
2998 int tid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID
);
2999 int pid
= tid
>> MAS6_SPID_SHIFT
;
3000 int sgs
= env
->spr
[SPR_BOOKE_MAS5
] & MAS5_SGS
;
3001 int ind
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SIND
) ? MAS1_IND
: 0;
3002 /* XXX check for unsupported isize and raise an invalid opcode then */
3003 int size
= env
->spr
[SPR_BOOKE_MAS6
] & MAS6_ISIZE_MASK
;
3004 /* XXX implement MAV2 handling */
3007 /* XXX missing LPID handling */
3008 /* flush by pid and ea */
3009 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
3010 int ways
= booke206_tlb_ways(env
, i
);
3012 for (j
= 0; j
< ways
; j
++) {
3013 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
3017 if ((ppcmas_tlb_check(env
, tlb
, NULL
, address
, pid
) != 0) ||
3018 (tlb
->mas1
& MAS1_IPROT
) ||
3019 ((tlb
->mas1
& MAS1_IND
) != ind
) ||
3020 ((tlb
->mas8
& MAS8_TGS
) != sgs
)) {
3023 if (mav2
&& ((tlb
->mas1
& MAS1_TSIZE_MASK
) != size
)) {
3024 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
3027 /* XXX e500mc doesn't match SAS, but other cores might */
3028 tlb
->mas1
&= ~MAS1_VALID
;
3034 void helper_booke206_tlbflush(CPUPPCState
*env
, uint32_t type
)
3039 flags
|= BOOKE206_FLUSH_TLB1
;
3043 flags
|= BOOKE206_FLUSH_TLB0
;
3046 booke206_flush_tlb(env
, flags
, 1);