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/>.
19 #include "qemu/osdep.h"
20 #include "qapi/error.h"
22 #include "exec/helper-proto.h"
23 #include "sysemu/kvm.h"
25 #include "mmu-hash64.h"
26 #include "mmu-hash32.h"
27 #include "exec/exec-all.h"
28 #include "exec/cpu_ldst.h"
30 #include "helper_regs.h"
34 //#define DEBUG_SOFTWARE_TLB
35 //#define DUMP_PAGE_TABLES
36 //#define FLUSH_ALL_TLBS
39 # define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
41 # define LOG_MMU_STATE(cpu) do { } while (0)
44 #ifdef DEBUG_SOFTWARE_TLB
45 # define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
47 # define LOG_SWTLB(...) do { } while (0)
51 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
53 # define LOG_BATS(...) do { } while (0)
56 /*****************************************************************************/
57 /* PowerPC MMU emulation */
59 /* Context used internally during MMU translations */
60 typedef struct mmu_ctx_t mmu_ctx_t
;
62 hwaddr raddr
; /* Real address */
63 hwaddr eaddr
; /* Effective address */
64 int prot
; /* Protection bits */
65 hwaddr hash
[2]; /* Pagetable hash values */
66 target_ulong ptem
; /* Virtual segment ID | API */
67 int key
; /* Access key */
68 int nx
; /* Non-execute area */
71 /* Common routines used by software and hardware TLBs emulation */
72 static inline int pte_is_valid(target_ulong pte0
)
74 return pte0
& 0x80000000 ? 1 : 0;
77 static inline void pte_invalidate(target_ulong
*pte0
)
82 #define PTE_PTEM_MASK 0x7FFFFFBF
83 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
85 static int pp_check(int key
, int pp
, int nx
)
89 /* Compute access rights */
112 access
= PAGE_READ
| PAGE_WRITE
;
123 static int check_prot(int prot
, int rw
, int access_type
)
127 if (access_type
== ACCESS_CODE
) {
128 if (prot
& PAGE_EXEC
) {
134 if (prot
& PAGE_WRITE
) {
140 if (prot
& PAGE_READ
) {
150 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t
*ctx
, target_ulong pte0
,
151 target_ulong pte1
, int h
, int rw
, int type
)
153 target_ulong ptem
, mmask
;
154 int access
, ret
, pteh
, ptev
, pp
;
157 /* Check validity and table match */
158 ptev
= pte_is_valid(pte0
);
159 pteh
= (pte0
>> 6) & 1;
160 if (ptev
&& h
== pteh
) {
161 /* Check vsid & api */
162 ptem
= pte0
& PTE_PTEM_MASK
;
163 mmask
= PTE_CHECK_MASK
;
164 pp
= pte1
& 0x00000003;
165 if (ptem
== ctx
->ptem
) {
166 if (ctx
->raddr
!= (hwaddr
)-1ULL) {
167 /* all matches should have equal RPN, WIMG & PP */
168 if ((ctx
->raddr
& mmask
) != (pte1
& mmask
)) {
169 qemu_log_mask(CPU_LOG_MMU
, "Bad RPN/WIMG/PP\n");
173 /* Compute access rights */
174 access
= pp_check(ctx
->key
, pp
, ctx
->nx
);
175 /* Keep the matching PTE informations */
178 ret
= check_prot(ctx
->prot
, rw
, type
);
181 qemu_log_mask(CPU_LOG_MMU
, "PTE access granted !\n");
183 /* Access right violation */
184 qemu_log_mask(CPU_LOG_MMU
, "PTE access rejected\n");
192 static int pte_update_flags(mmu_ctx_t
*ctx
, target_ulong
*pte1p
,
197 /* Update page flags */
198 if (!(*pte1p
& 0x00000100)) {
199 /* Update accessed flag */
200 *pte1p
|= 0x00000100;
203 if (!(*pte1p
& 0x00000080)) {
204 if (rw
== 1 && ret
== 0) {
205 /* Update changed flag */
206 *pte1p
|= 0x00000080;
209 /* Force page fault for first write access */
210 ctx
->prot
&= ~PAGE_WRITE
;
217 /* Software driven TLB helpers */
218 static inline int ppc6xx_tlb_getnum(CPUPPCState
*env
, target_ulong eaddr
,
219 int way
, int is_code
)
223 /* Select TLB num in a way from address */
224 nr
= (eaddr
>> TARGET_PAGE_BITS
) & (env
->tlb_per_way
- 1);
226 nr
+= env
->tlb_per_way
* way
;
227 /* 6xx have separate TLBs for instructions and data */
228 if (is_code
&& env
->id_tlbs
== 1) {
235 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState
*env
)
237 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
241 /* LOG_SWTLB("Invalidate all TLBs\n"); */
242 /* Invalidate all defined software TLB */
244 if (env
->id_tlbs
== 1) {
247 for (nr
= 0; nr
< max
; nr
++) {
248 tlb
= &env
->tlb
.tlb6
[nr
];
249 pte_invalidate(&tlb
->pte0
);
251 tlb_flush(CPU(cpu
), 1);
254 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState
*env
,
256 int is_code
, int match_epn
)
258 #if !defined(FLUSH_ALL_TLBS)
259 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
263 /* Invalidate ITLB + DTLB, all ways */
264 for (way
= 0; way
< env
->nb_ways
; way
++) {
265 nr
= ppc6xx_tlb_getnum(env
, eaddr
, way
, is_code
);
266 tlb
= &env
->tlb
.tlb6
[nr
];
267 if (pte_is_valid(tlb
->pte0
) && (match_epn
== 0 || eaddr
== tlb
->EPN
)) {
268 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx
"\n", nr
,
270 pte_invalidate(&tlb
->pte0
);
271 tlb_flush_page(cs
, tlb
->EPN
);
275 /* XXX: PowerPC specification say this is valid as well */
276 ppc6xx_tlb_invalidate_all(env
);
280 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState
*env
,
281 target_ulong eaddr
, int is_code
)
283 ppc6xx_tlb_invalidate_virt2(env
, eaddr
, is_code
, 0);
286 static void ppc6xx_tlb_store(CPUPPCState
*env
, target_ulong EPN
, int way
,
287 int is_code
, target_ulong pte0
, target_ulong pte1
)
292 nr
= ppc6xx_tlb_getnum(env
, EPN
, way
, is_code
);
293 tlb
= &env
->tlb
.tlb6
[nr
];
294 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
295 " PTE1 " TARGET_FMT_lx
"\n", nr
, env
->nb_tlb
, EPN
, pte0
, pte1
);
296 /* Invalidate any pending reference in QEMU for this virtual address */
297 ppc6xx_tlb_invalidate_virt2(env
, EPN
, is_code
, 1);
301 /* Store last way for LRU mechanism */
305 static inline int ppc6xx_tlb_check(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
306 target_ulong eaddr
, int rw
, int access_type
)
313 ret
= -1; /* No TLB found */
314 for (way
= 0; way
< env
->nb_ways
; way
++) {
315 nr
= ppc6xx_tlb_getnum(env
, eaddr
, way
,
316 access_type
== ACCESS_CODE
? 1 : 0);
317 tlb
= &env
->tlb
.tlb6
[nr
];
318 /* This test "emulates" the PTE index match for hardware TLBs */
319 if ((eaddr
& TARGET_PAGE_MASK
) != tlb
->EPN
) {
320 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx
" " TARGET_FMT_lx
321 "] <> " TARGET_FMT_lx
"\n", nr
, env
->nb_tlb
,
322 pte_is_valid(tlb
->pte0
) ? "valid" : "inval",
323 tlb
->EPN
, tlb
->EPN
+ TARGET_PAGE_SIZE
, eaddr
);
326 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx
" <> " TARGET_FMT_lx
" "
327 TARGET_FMT_lx
" %c %c\n", nr
, env
->nb_tlb
,
328 pte_is_valid(tlb
->pte0
) ? "valid" : "inval",
329 tlb
->EPN
, eaddr
, tlb
->pte1
,
330 rw
? 'S' : 'L', access_type
== ACCESS_CODE
? 'I' : 'D');
331 switch (ppc6xx_tlb_pte_check(ctx
, tlb
->pte0
, tlb
->pte1
, 0, rw
, access_type
)) {
333 /* TLB inconsistency */
336 /* Access violation */
346 /* XXX: we should go on looping to check all TLBs consistency
347 * but we can speed-up the whole thing as the
348 * result would be undefined if TLBs are not consistent.
357 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx
" prot=%01x ret=%d\n",
358 ctx
->raddr
& TARGET_PAGE_MASK
, ctx
->prot
, ret
);
359 /* Update page flags */
360 pte_update_flags(ctx
, &env
->tlb
.tlb6
[best
].pte1
, ret
, rw
);
366 /* Perform BAT hit & translation */
367 static inline void bat_size_prot(CPUPPCState
*env
, target_ulong
*blp
,
368 int *validp
, int *protp
, target_ulong
*BATu
,
374 bl
= (*BATu
& 0x00001FFC) << 15;
377 if (((msr_pr
== 0) && (*BATu
& 0x00000002)) ||
378 ((msr_pr
!= 0) && (*BATu
& 0x00000001))) {
380 pp
= *BATl
& 0x00000003;
382 prot
= PAGE_READ
| PAGE_EXEC
;
393 static int get_bat_6xx_tlb(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
394 target_ulong
virtual, int rw
, int type
)
396 target_ulong
*BATlt
, *BATut
, *BATu
, *BATl
;
397 target_ulong BEPIl
, BEPIu
, bl
;
401 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx
"\n", __func__
,
402 type
== ACCESS_CODE
? 'I' : 'D', virtual);
405 BATlt
= env
->IBAT
[1];
406 BATut
= env
->IBAT
[0];
409 BATlt
= env
->DBAT
[1];
410 BATut
= env
->DBAT
[0];
413 for (i
= 0; i
< env
->nb_BATs
; i
++) {
416 BEPIu
= *BATu
& 0xF0000000;
417 BEPIl
= *BATu
& 0x0FFE0000;
418 bat_size_prot(env
, &bl
, &valid
, &prot
, BATu
, BATl
);
419 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx
" BATu " TARGET_FMT_lx
420 " BATl " TARGET_FMT_lx
"\n", __func__
,
421 type
== ACCESS_CODE
? 'I' : 'D', i
, virtual, *BATu
, *BATl
);
422 if ((virtual & 0xF0000000) == BEPIu
&&
423 ((virtual & 0x0FFE0000) & ~bl
) == BEPIl
) {
426 /* Get physical address */
427 ctx
->raddr
= (*BATl
& 0xF0000000) |
428 ((virtual & 0x0FFE0000 & bl
) | (*BATl
& 0x0FFE0000)) |
429 (virtual & 0x0001F000);
430 /* Compute access rights */
432 ret
= check_prot(ctx
->prot
, rw
, type
);
434 LOG_BATS("BAT %d match: r " TARGET_FMT_plx
" prot=%c%c\n",
435 i
, ctx
->raddr
, ctx
->prot
& PAGE_READ
? 'R' : '-',
436 ctx
->prot
& PAGE_WRITE
? 'W' : '-');
443 #if defined(DEBUG_BATS)
444 if (qemu_log_enabled()) {
445 LOG_BATS("no BAT match for " TARGET_FMT_lx
":\n", virtual);
446 for (i
= 0; i
< 4; i
++) {
449 BEPIu
= *BATu
& 0xF0000000;
450 BEPIl
= *BATu
& 0x0FFE0000;
451 bl
= (*BATu
& 0x00001FFC) << 15;
452 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx
" BATu " TARGET_FMT_lx
453 " BATl " TARGET_FMT_lx
"\n\t" TARGET_FMT_lx
" "
454 TARGET_FMT_lx
" " TARGET_FMT_lx
"\n",
455 __func__
, type
== ACCESS_CODE
? 'I' : 'D', i
, virtual,
456 *BATu
, *BATl
, BEPIu
, BEPIl
, bl
);
465 /* Perform segment based translation */
466 static inline int get_segment_6xx_tlb(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
467 target_ulong eaddr
, int rw
, int type
)
471 int ds
, pr
, target_page_bits
;
473 target_ulong sr
, pgidx
;
478 sr
= env
->sr
[eaddr
>> 28];
479 ctx
->key
= (((sr
& 0x20000000) && (pr
!= 0)) ||
480 ((sr
& 0x40000000) && (pr
== 0))) ? 1 : 0;
481 ds
= sr
& 0x80000000 ? 1 : 0;
482 ctx
->nx
= sr
& 0x10000000 ? 1 : 0;
483 vsid
= sr
& 0x00FFFFFF;
484 target_page_bits
= TARGET_PAGE_BITS
;
485 qemu_log_mask(CPU_LOG_MMU
,
486 "Check segment v=" TARGET_FMT_lx
" %d " TARGET_FMT_lx
487 " nip=" TARGET_FMT_lx
" lr=" TARGET_FMT_lx
488 " ir=%d dr=%d pr=%d %d t=%d\n",
489 eaddr
, (int)(eaddr
>> 28), sr
, env
->nip
, env
->lr
, (int)msr_ir
,
490 (int)msr_dr
, pr
!= 0 ? 1 : 0, rw
, type
);
491 pgidx
= (eaddr
& ~SEGMENT_MASK_256M
) >> target_page_bits
;
493 ctx
->ptem
= (vsid
<< 7) | (pgidx
>> 10);
495 qemu_log_mask(CPU_LOG_MMU
,
496 "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx
"\n",
497 ctx
->key
, ds
, ctx
->nx
, vsid
);
500 /* Check if instruction fetch is allowed, if needed */
501 if (type
!= ACCESS_CODE
|| ctx
->nx
== 0) {
502 /* Page address translation */
503 qemu_log_mask(CPU_LOG_MMU
, "htab_base " TARGET_FMT_plx
504 " htab_mask " TARGET_FMT_plx
505 " hash " TARGET_FMT_plx
"\n",
506 env
->htab_base
, env
->htab_mask
, hash
);
508 ctx
->hash
[1] = ~hash
;
510 /* Initialize real address with an invalid value */
511 ctx
->raddr
= (hwaddr
)-1ULL;
512 /* Software TLB search */
513 ret
= ppc6xx_tlb_check(env
, ctx
, eaddr
, rw
, type
);
514 #if defined(DUMP_PAGE_TABLES)
515 if (qemu_log_mask(CPU_LOG_MMU
)) {
517 uint32_t a0
, a1
, a2
, a3
;
519 qemu_log("Page table: " TARGET_FMT_plx
" len " TARGET_FMT_plx
520 "\n", sdr
, mask
+ 0x80);
521 for (curaddr
= sdr
; curaddr
< (sdr
+ mask
+ 0x80);
523 a0
= ldl_phys(curaddr
);
524 a1
= ldl_phys(curaddr
+ 4);
525 a2
= ldl_phys(curaddr
+ 8);
526 a3
= ldl_phys(curaddr
+ 12);
527 if (a0
!= 0 || a1
!= 0 || a2
!= 0 || a3
!= 0) {
528 qemu_log(TARGET_FMT_plx
": %08x %08x %08x %08x\n",
529 curaddr
, a0
, a1
, a2
, a3
);
535 qemu_log_mask(CPU_LOG_MMU
, "No access allowed\n");
541 qemu_log_mask(CPU_LOG_MMU
, "direct store...\n");
542 /* Direct-store segment : absolutely *BUGGY* for now */
544 /* Direct-store implies a 32-bit MMU.
545 * Check the Segment Register's bus unit ID (BUID).
547 sr
= env
->sr
[eaddr
>> 28];
548 if ((sr
& 0x1FF00000) >> 20 == 0x07f) {
549 /* Memory-forced I/O controller interface access */
550 /* If T=1 and BUID=x'07F', the 601 performs a memory access
551 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
553 ctx
->raddr
= ((sr
& 0xF) << 28) | (eaddr
& 0x0FFFFFFF);
554 ctx
->prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
560 /* Integer load/store : only access allowed */
563 /* No code fetch is allowed in direct-store areas */
566 /* Floating point load/store */
569 /* lwarx, ldarx or srwcx. */
572 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
573 /* Should make the instruction do no-op.
574 * As it already do no-op, it's quite easy :-)
582 qemu_log_mask(CPU_LOG_MMU
, "ERROR: instruction should not need "
583 "address translation\n");
586 if ((rw
== 1 || ctx
->key
!= 1) && (rw
== 0 || ctx
->key
!= 0)) {
597 /* Generic TLB check function for embedded PowerPC implementations */
598 static int ppcemb_tlb_check(CPUPPCState
*env
, ppcemb_tlb_t
*tlb
,
600 target_ulong address
, uint32_t pid
, int ext
,
605 /* Check valid flag */
606 if (!(tlb
->prot
& PAGE_VALID
)) {
609 mask
= ~(tlb
->size
- 1);
610 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx
" PID %u <=> " TARGET_FMT_lx
611 " " TARGET_FMT_lx
" %u %x\n", __func__
, i
, address
, pid
, tlb
->EPN
,
612 mask
, (uint32_t)tlb
->PID
, tlb
->prot
);
614 if (tlb
->PID
!= 0 && tlb
->PID
!= pid
) {
617 /* Check effective address */
618 if ((address
& mask
) != tlb
->EPN
) {
621 *raddrp
= (tlb
->RPN
& mask
) | (address
& ~mask
);
623 /* Extend the physical address to 36 bits */
624 *raddrp
|= (uint64_t)(tlb
->RPN
& 0xF) << 32;
630 /* Generic TLB search function for PowerPC embedded implementations */
631 static int ppcemb_tlb_search(CPUPPCState
*env
, target_ulong address
,
638 /* Default return value is no match */
640 for (i
= 0; i
< env
->nb_tlb
; i
++) {
641 tlb
= &env
->tlb
.tlbe
[i
];
642 if (ppcemb_tlb_check(env
, tlb
, &raddr
, address
, pid
, 0, i
) == 0) {
651 /* Helpers specific to PowerPC 40x implementations */
652 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState
*env
)
654 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
658 for (i
= 0; i
< env
->nb_tlb
; i
++) {
659 tlb
= &env
->tlb
.tlbe
[i
];
660 tlb
->prot
&= ~PAGE_VALID
;
662 tlb_flush(CPU(cpu
), 1);
665 static int mmu40x_get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
666 target_ulong address
, int rw
,
671 int i
, ret
, zsel
, zpr
, pr
;
674 raddr
= (hwaddr
)-1ULL;
676 for (i
= 0; i
< env
->nb_tlb
; i
++) {
677 tlb
= &env
->tlb
.tlbe
[i
];
678 if (ppcemb_tlb_check(env
, tlb
, &raddr
, address
,
679 env
->spr
[SPR_40x_PID
], 0, i
) < 0) {
682 zsel
= (tlb
->attr
>> 4) & 0xF;
683 zpr
= (env
->spr
[SPR_40x_ZPR
] >> (30 - (2 * zsel
))) & 0x3;
684 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
685 __func__
, i
, zsel
, zpr
, rw
, tlb
->attr
);
686 /* Check execute enable bit */
694 /* All accesses granted */
695 ctx
->prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
700 /* Raise Zone protection fault. */
701 env
->spr
[SPR_40x_ESR
] = 1 << 22;
709 /* Check from TLB entry */
710 ctx
->prot
= tlb
->prot
;
711 ret
= check_prot(ctx
->prot
, rw
, access_type
);
713 env
->spr
[SPR_40x_ESR
] = 0;
719 LOG_SWTLB("%s: access granted " TARGET_FMT_lx
" => " TARGET_FMT_plx
720 " %d %d\n", __func__
, address
, ctx
->raddr
, ctx
->prot
,
725 LOG_SWTLB("%s: access refused " TARGET_FMT_lx
" => " TARGET_FMT_plx
726 " %d %d\n", __func__
, address
, raddr
, ctx
->prot
, ret
);
731 void store_40x_sler(CPUPPCState
*env
, uint32_t val
)
733 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
735 /* XXX: TO BE FIXED */
736 if (val
!= 0x00000000) {
737 cpu_abort(CPU(cpu
), "Little-endian regions are not supported by now\n");
739 env
->spr
[SPR_405_SLER
] = val
;
742 static inline int mmubooke_check_tlb(CPUPPCState
*env
, ppcemb_tlb_t
*tlb
,
743 hwaddr
*raddr
, int *prot
,
744 target_ulong address
, int rw
,
745 int access_type
, int i
)
749 if (ppcemb_tlb_check(env
, tlb
, raddr
, address
,
750 env
->spr
[SPR_BOOKE_PID
],
751 !env
->nb_pids
, i
) >= 0) {
755 if (env
->spr
[SPR_BOOKE_PID1
] &&
756 ppcemb_tlb_check(env
, tlb
, raddr
, address
,
757 env
->spr
[SPR_BOOKE_PID1
], 0, i
) >= 0) {
761 if (env
->spr
[SPR_BOOKE_PID2
] &&
762 ppcemb_tlb_check(env
, tlb
, raddr
, address
,
763 env
->spr
[SPR_BOOKE_PID2
], 0, i
) >= 0) {
767 LOG_SWTLB("%s: TLB entry not found\n", __func__
);
773 prot2
= tlb
->prot
& 0xF;
775 prot2
= (tlb
->prot
>> 4) & 0xF;
778 /* Check the address space */
779 if (access_type
== ACCESS_CODE
) {
780 if (msr_ir
!= (tlb
->attr
& 1)) {
781 LOG_SWTLB("%s: AS doesn't match\n", __func__
);
786 if (prot2
& PAGE_EXEC
) {
787 LOG_SWTLB("%s: good TLB!\n", __func__
);
791 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__
, prot2
);
794 if (msr_dr
!= (tlb
->attr
& 1)) {
795 LOG_SWTLB("%s: AS doesn't match\n", __func__
);
800 if ((!rw
&& prot2
& PAGE_READ
) || (rw
&& (prot2
& PAGE_WRITE
))) {
801 LOG_SWTLB("%s: found TLB!\n", __func__
);
805 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__
, prot2
);
812 static int mmubooke_get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
813 target_ulong address
, int rw
,
821 raddr
= (hwaddr
)-1ULL;
822 for (i
= 0; i
< env
->nb_tlb
; i
++) {
823 tlb
= &env
->tlb
.tlbe
[i
];
824 ret
= mmubooke_check_tlb(env
, tlb
, &raddr
, &ctx
->prot
, address
, rw
,
833 LOG_SWTLB("%s: access granted " TARGET_FMT_lx
" => " TARGET_FMT_plx
834 " %d %d\n", __func__
, address
, ctx
->raddr
, ctx
->prot
,
837 LOG_SWTLB("%s: access refused " TARGET_FMT_lx
" => " TARGET_FMT_plx
838 " %d %d\n", __func__
, address
, raddr
, ctx
->prot
, ret
);
844 static void booke206_flush_tlb(CPUPPCState
*env
, int flags
,
845 const int check_iprot
)
847 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
850 ppcmas_tlb_t
*tlb
= env
->tlb
.tlbm
;
852 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
853 if (flags
& (1 << i
)) {
854 tlb_size
= booke206_tlb_size(env
, i
);
855 for (j
= 0; j
< tlb_size
; j
++) {
856 if (!check_iprot
|| !(tlb
[j
].mas1
& MAS1_IPROT
)) {
857 tlb
[j
].mas1
&= ~MAS1_VALID
;
861 tlb
+= booke206_tlb_size(env
, i
);
864 tlb_flush(CPU(cpu
), 1);
867 static hwaddr
booke206_tlb_to_page_size(CPUPPCState
*env
,
872 tlbm_size
= (tlb
->mas1
& MAS1_TSIZE_MASK
) >> MAS1_TSIZE_SHIFT
;
874 return 1024ULL << tlbm_size
;
877 /* TLB check function for MAS based SoftTLBs */
878 static int ppcmas_tlb_check(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
,
879 hwaddr
*raddrp
, target_ulong address
,
886 /* In 32bit mode we can only address 32bit EAs */
887 address
= (uint32_t)address
;
890 /* Check valid flag */
891 if (!(tlb
->mas1
& MAS1_VALID
)) {
895 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
896 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx
" PID=0x%x MAS1=0x%x MAS2=0x%"
897 PRIx64
" mask=0x" TARGET_FMT_lx
" MAS7_3=0x%" PRIx64
" MAS8=%x\n",
898 __func__
, address
, pid
, tlb
->mas1
, tlb
->mas2
, mask
, tlb
->mas7_3
,
902 tlb_pid
= (tlb
->mas1
& MAS1_TID_MASK
) >> MAS1_TID_SHIFT
;
903 if (tlb_pid
!= 0 && tlb_pid
!= pid
) {
907 /* Check effective address */
908 if ((address
& mask
) != (tlb
->mas2
& MAS2_EPN_MASK
)) {
913 *raddrp
= (tlb
->mas7_3
& mask
) | (address
& ~mask
);
919 static int mmubooke206_check_tlb(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
,
920 hwaddr
*raddr
, int *prot
,
921 target_ulong address
, int rw
,
927 if (ppcmas_tlb_check(env
, tlb
, raddr
, address
,
928 env
->spr
[SPR_BOOKE_PID
]) >= 0) {
932 if (env
->spr
[SPR_BOOKE_PID1
] &&
933 ppcmas_tlb_check(env
, tlb
, raddr
, address
,
934 env
->spr
[SPR_BOOKE_PID1
]) >= 0) {
938 if (env
->spr
[SPR_BOOKE_PID2
] &&
939 ppcmas_tlb_check(env
, tlb
, raddr
, address
,
940 env
->spr
[SPR_BOOKE_PID2
]) >= 0) {
944 LOG_SWTLB("%s: TLB entry not found\n", __func__
);
950 if (tlb
->mas7_3
& MAS3_UR
) {
953 if (tlb
->mas7_3
& MAS3_UW
) {
956 if (tlb
->mas7_3
& MAS3_UX
) {
960 if (tlb
->mas7_3
& MAS3_SR
) {
963 if (tlb
->mas7_3
& MAS3_SW
) {
966 if (tlb
->mas7_3
& MAS3_SX
) {
971 /* Check the address space and permissions */
972 if (access_type
== ACCESS_CODE
) {
973 if (msr_ir
!= ((tlb
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
)) {
974 LOG_SWTLB("%s: AS doesn't match\n", __func__
);
979 if (prot2
& PAGE_EXEC
) {
980 LOG_SWTLB("%s: good TLB!\n", __func__
);
984 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__
, prot2
);
987 if (msr_dr
!= ((tlb
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
)) {
988 LOG_SWTLB("%s: AS doesn't match\n", __func__
);
993 if ((!rw
&& prot2
& PAGE_READ
) || (rw
&& (prot2
& PAGE_WRITE
))) {
994 LOG_SWTLB("%s: found TLB!\n", __func__
);
998 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__
, prot2
);
1005 static int mmubooke206_get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
1006 target_ulong address
, int rw
,
1014 raddr
= (hwaddr
)-1ULL;
1016 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
1017 int ways
= booke206_tlb_ways(env
, i
);
1019 for (j
= 0; j
< ways
; j
++) {
1020 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
1024 ret
= mmubooke206_check_tlb(env
, tlb
, &raddr
, &ctx
->prot
, address
,
1036 LOG_SWTLB("%s: access granted " TARGET_FMT_lx
" => " TARGET_FMT_plx
1037 " %d %d\n", __func__
, address
, ctx
->raddr
, ctx
->prot
,
1040 LOG_SWTLB("%s: access refused " TARGET_FMT_lx
" => " TARGET_FMT_plx
1041 " %d %d\n", __func__
, address
, raddr
, ctx
->prot
, ret
);
1047 static const char *book3e_tsize_to_str
[32] = {
1048 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1049 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1050 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1054 static void mmubooke_dump_mmu(FILE *f
, fprintf_function cpu_fprintf
,
1057 ppcemb_tlb_t
*entry
;
1060 if (kvm_enabled() && !env
->kvm_sw_tlb
) {
1061 cpu_fprintf(f
, "Cannot access KVM TLB\n");
1065 cpu_fprintf(f
, "\nTLB:\n");
1066 cpu_fprintf(f
, "Effective Physical Size PID Prot "
1069 entry
= &env
->tlb
.tlbe
[0];
1070 for (i
= 0; i
< env
->nb_tlb
; i
++, entry
++) {
1073 uint64_t size
= (uint64_t)entry
->size
;
1076 /* Check valid flag */
1077 if (!(entry
->prot
& PAGE_VALID
)) {
1081 mask
= ~(entry
->size
- 1);
1082 ea
= entry
->EPN
& mask
;
1083 pa
= entry
->RPN
& mask
;
1084 /* Extend the physical address to 36 bits */
1085 pa
|= (hwaddr
)(entry
->RPN
& 0xF) << 32;
1088 snprintf(size_buf
, sizeof(size_buf
), "%3" PRId64
"M", size
/ 1024);
1090 snprintf(size_buf
, sizeof(size_buf
), "%3" PRId64
"k", size
);
1092 cpu_fprintf(f
, "0x%016" PRIx64
" 0x%016" PRIx64
" %s %-5u %08x %08x\n",
1093 (uint64_t)ea
, (uint64_t)pa
, size_buf
, (uint32_t)entry
->PID
,
1094 entry
->prot
, entry
->attr
);
1099 static void mmubooke206_dump_one_tlb(FILE *f
, fprintf_function cpu_fprintf
,
1100 CPUPPCState
*env
, int tlbn
, int offset
,
1103 ppcmas_tlb_t
*entry
;
1106 cpu_fprintf(f
, "\nTLB%d:\n", tlbn
);
1107 cpu_fprintf(f
, "Effective Physical Size TID TS SRWX"
1108 " URWX WIMGE U0123\n");
1110 entry
= &env
->tlb
.tlbm
[offset
];
1111 for (i
= 0; i
< tlbsize
; i
++, entry
++) {
1112 hwaddr ea
, pa
, size
;
1115 if (!(entry
->mas1
& MAS1_VALID
)) {
1119 tsize
= (entry
->mas1
& MAS1_TSIZE_MASK
) >> MAS1_TSIZE_SHIFT
;
1120 size
= 1024ULL << tsize
;
1121 ea
= entry
->mas2
& ~(size
- 1);
1122 pa
= entry
->mas7_3
& ~(size
- 1);
1124 cpu_fprintf(f
, "0x%016" PRIx64
" 0x%016" PRIx64
" %4s %-5u %1u S%c%c%c"
1125 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1126 (uint64_t)ea
, (uint64_t)pa
,
1127 book3e_tsize_to_str
[tsize
],
1128 (entry
->mas1
& MAS1_TID_MASK
) >> MAS1_TID_SHIFT
,
1129 (entry
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
,
1130 entry
->mas7_3
& MAS3_SR
? 'R' : '-',
1131 entry
->mas7_3
& MAS3_SW
? 'W' : '-',
1132 entry
->mas7_3
& MAS3_SX
? 'X' : '-',
1133 entry
->mas7_3
& MAS3_UR
? 'R' : '-',
1134 entry
->mas7_3
& MAS3_UW
? 'W' : '-',
1135 entry
->mas7_3
& MAS3_UX
? 'X' : '-',
1136 entry
->mas2
& MAS2_W
? 'W' : '-',
1137 entry
->mas2
& MAS2_I
? 'I' : '-',
1138 entry
->mas2
& MAS2_M
? 'M' : '-',
1139 entry
->mas2
& MAS2_G
? 'G' : '-',
1140 entry
->mas2
& MAS2_E
? 'E' : '-',
1141 entry
->mas7_3
& MAS3_U0
? '0' : '-',
1142 entry
->mas7_3
& MAS3_U1
? '1' : '-',
1143 entry
->mas7_3
& MAS3_U2
? '2' : '-',
1144 entry
->mas7_3
& MAS3_U3
? '3' : '-');
1148 static void mmubooke206_dump_mmu(FILE *f
, fprintf_function cpu_fprintf
,
1154 if (kvm_enabled() && !env
->kvm_sw_tlb
) {
1155 cpu_fprintf(f
, "Cannot access KVM TLB\n");
1159 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
1160 int size
= booke206_tlb_size(env
, i
);
1166 mmubooke206_dump_one_tlb(f
, cpu_fprintf
, env
, i
, offset
, size
);
1171 static void mmu6xx_dump_BATs(FILE *f
, fprintf_function cpu_fprintf
,
1172 CPUPPCState
*env
, int type
)
1174 target_ulong
*BATlt
, *BATut
, *BATu
, *BATl
;
1175 target_ulong BEPIl
, BEPIu
, bl
;
1180 BATlt
= env
->IBAT
[1];
1181 BATut
= env
->IBAT
[0];
1184 BATlt
= env
->DBAT
[1];
1185 BATut
= env
->DBAT
[0];
1189 for (i
= 0; i
< env
->nb_BATs
; i
++) {
1192 BEPIu
= *BATu
& 0xF0000000;
1193 BEPIl
= *BATu
& 0x0FFE0000;
1194 bl
= (*BATu
& 0x00001FFC) << 15;
1195 cpu_fprintf(f
, "%s BAT%d BATu " TARGET_FMT_lx
1196 " BATl " TARGET_FMT_lx
"\n\t" TARGET_FMT_lx
" "
1197 TARGET_FMT_lx
" " TARGET_FMT_lx
"\n",
1198 type
== ACCESS_CODE
? "code" : "data", i
,
1199 *BATu
, *BATl
, BEPIu
, BEPIl
, bl
);
1203 static void mmu6xx_dump_mmu(FILE *f
, fprintf_function cpu_fprintf
,
1208 int type
, way
, entry
, i
;
1210 cpu_fprintf(f
, "HTAB base = 0x%"HWADDR_PRIx
"\n", env
->htab_base
);
1211 cpu_fprintf(f
, "HTAB mask = 0x%"HWADDR_PRIx
"\n", env
->htab_mask
);
1213 cpu_fprintf(f
, "\nSegment registers:\n");
1214 for (i
= 0; i
< 32; i
++) {
1216 if (sr
& 0x80000000) {
1217 cpu_fprintf(f
, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1218 "CNTLR_SPEC=0x%05x\n", i
,
1219 sr
& 0x80000000 ? 1 : 0, sr
& 0x40000000 ? 1 : 0,
1220 sr
& 0x20000000 ? 1 : 0, (uint32_t)((sr
>> 20) & 0x1FF),
1221 (uint32_t)(sr
& 0xFFFFF));
1223 cpu_fprintf(f
, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i
,
1224 sr
& 0x80000000 ? 1 : 0, sr
& 0x40000000 ? 1 : 0,
1225 sr
& 0x20000000 ? 1 : 0, sr
& 0x10000000 ? 1 : 0,
1226 (uint32_t)(sr
& 0x00FFFFFF));
1230 cpu_fprintf(f
, "\nBATs:\n");
1231 mmu6xx_dump_BATs(f
, cpu_fprintf
, env
, ACCESS_INT
);
1232 mmu6xx_dump_BATs(f
, cpu_fprintf
, env
, ACCESS_CODE
);
1234 if (env
->id_tlbs
!= 1) {
1235 cpu_fprintf(f
, "ERROR: 6xx MMU should have separated TLB"
1236 " for code and data\n");
1239 cpu_fprintf(f
, "\nTLBs [EPN EPN + SIZE]\n");
1241 for (type
= 0; type
< 2; type
++) {
1242 for (way
= 0; way
< env
->nb_ways
; way
++) {
1243 for (entry
= env
->nb_tlb
* type
+ env
->tlb_per_way
* way
;
1244 entry
< (env
->nb_tlb
* type
+ env
->tlb_per_way
* (way
+ 1));
1247 tlb
= &env
->tlb
.tlb6
[entry
];
1248 cpu_fprintf(f
, "%s TLB %02d/%02d way:%d %s ["
1249 TARGET_FMT_lx
" " TARGET_FMT_lx
"]\n",
1250 type
? "code" : "data", entry
% env
->nb_tlb
,
1252 pte_is_valid(tlb
->pte0
) ? "valid" : "inval",
1253 tlb
->EPN
, tlb
->EPN
+ TARGET_PAGE_SIZE
);
1259 void dump_mmu(FILE *f
, fprintf_function cpu_fprintf
, CPUPPCState
*env
)
1261 switch (env
->mmu_model
) {
1262 case POWERPC_MMU_BOOKE
:
1263 mmubooke_dump_mmu(f
, cpu_fprintf
, env
);
1265 case POWERPC_MMU_BOOKE206
:
1266 mmubooke206_dump_mmu(f
, cpu_fprintf
, env
);
1268 case POWERPC_MMU_SOFT_6xx
:
1269 case POWERPC_MMU_SOFT_74xx
:
1270 mmu6xx_dump_mmu(f
, cpu_fprintf
, env
);
1272 #if defined(TARGET_PPC64)
1273 case POWERPC_MMU_64B
:
1274 case POWERPC_MMU_2_03
:
1275 case POWERPC_MMU_2_06
:
1276 case POWERPC_MMU_2_06a
:
1277 case POWERPC_MMU_2_07
:
1278 case POWERPC_MMU_2_07a
:
1279 dump_slb(f
, cpu_fprintf
, ppc_env_get_cpu(env
));
1283 qemu_log_mask(LOG_UNIMP
, "%s: unimplemented\n", __func__
);
1287 static inline int check_physical(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
1288 target_ulong eaddr
, int rw
)
1293 ctx
->prot
= PAGE_READ
| PAGE_EXEC
;
1295 switch (env
->mmu_model
) {
1296 case POWERPC_MMU_SOFT_6xx
:
1297 case POWERPC_MMU_SOFT_74xx
:
1298 case POWERPC_MMU_SOFT_4xx
:
1299 case POWERPC_MMU_REAL
:
1300 case POWERPC_MMU_BOOKE
:
1301 ctx
->prot
|= PAGE_WRITE
;
1304 case POWERPC_MMU_SOFT_4xx_Z
:
1305 if (unlikely(msr_pe
!= 0)) {
1306 /* 403 family add some particular protections,
1307 * using PBL/PBU registers for accesses with no translation.
1310 /* Check PLB validity */
1311 (env
->pb
[0] < env
->pb
[1] &&
1312 /* and address in plb area */
1313 eaddr
>= env
->pb
[0] && eaddr
< env
->pb
[1]) ||
1314 (env
->pb
[2] < env
->pb
[3] &&
1315 eaddr
>= env
->pb
[2] && eaddr
< env
->pb
[3]) ? 1 : 0;
1316 if (in_plb
^ msr_px
) {
1317 /* Access in protected area */
1319 /* Access is not allowed */
1323 /* Read-write access is allowed */
1324 ctx
->prot
|= PAGE_WRITE
;
1330 /* Caller's checks mean we should never get here for other models */
1338 static int get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
1339 target_ulong eaddr
, int rw
, int access_type
)
1341 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
1343 bool real_mode
= (access_type
== ACCESS_CODE
&& msr_ir
== 0)
1344 || (access_type
!= ACCESS_CODE
&& msr_dr
== 0);
1347 qemu_log("%s\n", __func__
);
1350 switch (env
->mmu_model
) {
1351 case POWERPC_MMU_SOFT_6xx
:
1352 case POWERPC_MMU_SOFT_74xx
:
1354 ret
= check_physical(env
, ctx
, eaddr
, rw
);
1356 /* Try to find a BAT */
1357 if (env
->nb_BATs
!= 0) {
1358 ret
= get_bat_6xx_tlb(env
, ctx
, eaddr
, rw
, access_type
);
1361 /* We didn't match any BAT entry or don't have BATs */
1362 ret
= get_segment_6xx_tlb(env
, ctx
, eaddr
, rw
, access_type
);
1367 case POWERPC_MMU_SOFT_4xx
:
1368 case POWERPC_MMU_SOFT_4xx_Z
:
1370 ret
= check_physical(env
, ctx
, eaddr
, rw
);
1372 ret
= mmu40x_get_physical_address(env
, ctx
, eaddr
,
1376 case POWERPC_MMU_BOOKE
:
1377 ret
= mmubooke_get_physical_address(env
, ctx
, eaddr
,
1380 case POWERPC_MMU_BOOKE206
:
1381 ret
= mmubooke206_get_physical_address(env
, ctx
, eaddr
, rw
,
1384 case POWERPC_MMU_MPC8xx
:
1386 cpu_abort(CPU(cpu
), "MPC8xx MMU model is not implemented\n");
1388 case POWERPC_MMU_REAL
:
1390 ret
= check_physical(env
, ctx
, eaddr
, rw
);
1392 cpu_abort(CPU(cpu
), "PowerPC in real mode do not do any translation\n");
1396 cpu_abort(CPU(cpu
), "Unknown or invalid MMU model\n");
1400 qemu_log("%s address " TARGET_FMT_lx
" => %d " TARGET_FMT_plx
"\n",
1401 __func__
, eaddr
, ret
, ctx
->raddr
);
1407 hwaddr
ppc_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
1409 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
1410 CPUPPCState
*env
= &cpu
->env
;
1413 switch (env
->mmu_model
) {
1414 #if defined(TARGET_PPC64)
1415 case POWERPC_MMU_64B
:
1416 case POWERPC_MMU_2_03
:
1417 case POWERPC_MMU_2_06
:
1418 case POWERPC_MMU_2_06a
:
1419 case POWERPC_MMU_2_07
:
1420 case POWERPC_MMU_2_07a
:
1421 return ppc_hash64_get_phys_page_debug(cpu
, addr
);
1424 case POWERPC_MMU_32B
:
1425 case POWERPC_MMU_601
:
1426 return ppc_hash32_get_phys_page_debug(cpu
, addr
);
1432 if (unlikely(get_physical_address(env
, &ctx
, addr
, 0, ACCESS_INT
) != 0)) {
1434 /* Some MMUs have separate TLBs for code and data. If we only try an
1435 * ACCESS_INT, we may not be able to read instructions mapped by code
1436 * TLBs, so we also try a ACCESS_CODE.
1438 if (unlikely(get_physical_address(env
, &ctx
, addr
, 0,
1439 ACCESS_CODE
) != 0)) {
1444 return ctx
.raddr
& TARGET_PAGE_MASK
;
1447 static void booke206_update_mas_tlb_miss(CPUPPCState
*env
, target_ulong address
,
1450 env
->spr
[SPR_BOOKE_MAS0
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TLBSELD_MASK
;
1451 env
->spr
[SPR_BOOKE_MAS1
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TSIZED_MASK
;
1452 env
->spr
[SPR_BOOKE_MAS2
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_WIMGED_MASK
;
1453 env
->spr
[SPR_BOOKE_MAS3
] = 0;
1454 env
->spr
[SPR_BOOKE_MAS6
] = 0;
1455 env
->spr
[SPR_BOOKE_MAS7
] = 0;
1458 if (((rw
== 2) && msr_ir
) || ((rw
!= 2) && msr_dr
)) {
1459 env
->spr
[SPR_BOOKE_MAS1
] |= MAS1_TS
;
1460 env
->spr
[SPR_BOOKE_MAS6
] |= MAS6_SAS
;
1463 env
->spr
[SPR_BOOKE_MAS1
] |= MAS1_VALID
;
1464 env
->spr
[SPR_BOOKE_MAS2
] |= address
& MAS2_EPN_MASK
;
1466 switch (env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TIDSELD_PIDZ
) {
1467 case MAS4_TIDSELD_PID0
:
1468 env
->spr
[SPR_BOOKE_MAS1
] |= env
->spr
[SPR_BOOKE_PID
] << MAS1_TID_SHIFT
;
1470 case MAS4_TIDSELD_PID1
:
1471 env
->spr
[SPR_BOOKE_MAS1
] |= env
->spr
[SPR_BOOKE_PID1
] << MAS1_TID_SHIFT
;
1473 case MAS4_TIDSELD_PID2
:
1474 env
->spr
[SPR_BOOKE_MAS1
] |= env
->spr
[SPR_BOOKE_PID2
] << MAS1_TID_SHIFT
;
1478 env
->spr
[SPR_BOOKE_MAS6
] |= env
->spr
[SPR_BOOKE_PID
] << 16;
1480 /* next victim logic */
1481 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_ESEL_SHIFT
;
1483 env
->last_way
&= booke206_tlb_ways(env
, 0) - 1;
1484 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
1487 /* Perform address translation */
1488 static int cpu_ppc_handle_mmu_fault(CPUPPCState
*env
, target_ulong address
,
1489 int rw
, int mmu_idx
)
1491 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
1492 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
1500 access_type
= ACCESS_CODE
;
1503 access_type
= env
->access_type
;
1505 ret
= get_physical_address(env
, &ctx
, address
, rw
, access_type
);
1507 tlb_set_page(cs
, address
& TARGET_PAGE_MASK
,
1508 ctx
.raddr
& TARGET_PAGE_MASK
, ctx
.prot
,
1509 mmu_idx
, TARGET_PAGE_SIZE
);
1511 } else if (ret
< 0) {
1513 if (access_type
== ACCESS_CODE
) {
1516 /* No matches in page tables or TLB */
1517 switch (env
->mmu_model
) {
1518 case POWERPC_MMU_SOFT_6xx
:
1519 cs
->exception_index
= POWERPC_EXCP_IFTLB
;
1520 env
->error_code
= 1 << 18;
1521 env
->spr
[SPR_IMISS
] = address
;
1522 env
->spr
[SPR_ICMP
] = 0x80000000 | ctx
.ptem
;
1524 case POWERPC_MMU_SOFT_74xx
:
1525 cs
->exception_index
= POWERPC_EXCP_IFTLB
;
1527 case POWERPC_MMU_SOFT_4xx
:
1528 case POWERPC_MMU_SOFT_4xx_Z
:
1529 cs
->exception_index
= POWERPC_EXCP_ITLB
;
1530 env
->error_code
= 0;
1531 env
->spr
[SPR_40x_DEAR
] = address
;
1532 env
->spr
[SPR_40x_ESR
] = 0x00000000;
1534 case POWERPC_MMU_BOOKE206
:
1535 booke206_update_mas_tlb_miss(env
, address
, rw
);
1537 case POWERPC_MMU_BOOKE
:
1538 cs
->exception_index
= POWERPC_EXCP_ITLB
;
1539 env
->error_code
= 0;
1540 env
->spr
[SPR_BOOKE_DEAR
] = address
;
1542 case POWERPC_MMU_MPC8xx
:
1544 cpu_abort(cs
, "MPC8xx MMU model is not implemented\n");
1546 case POWERPC_MMU_REAL
:
1547 cpu_abort(cs
, "PowerPC in real mode should never raise "
1548 "any MMU exceptions\n");
1551 cpu_abort(cs
, "Unknown or invalid MMU model\n");
1556 /* Access rights violation */
1557 cs
->exception_index
= POWERPC_EXCP_ISI
;
1558 env
->error_code
= 0x08000000;
1561 /* No execute protection violation */
1562 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
1563 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
1564 env
->spr
[SPR_BOOKE_ESR
] = 0x00000000;
1566 cs
->exception_index
= POWERPC_EXCP_ISI
;
1567 env
->error_code
= 0x10000000;
1570 /* Direct store exception */
1571 /* No code fetch is allowed in direct-store areas */
1572 cs
->exception_index
= POWERPC_EXCP_ISI
;
1573 env
->error_code
= 0x10000000;
1579 /* No matches in page tables or TLB */
1580 switch (env
->mmu_model
) {
1581 case POWERPC_MMU_SOFT_6xx
:
1583 cs
->exception_index
= POWERPC_EXCP_DSTLB
;
1584 env
->error_code
= 1 << 16;
1586 cs
->exception_index
= POWERPC_EXCP_DLTLB
;
1587 env
->error_code
= 0;
1589 env
->spr
[SPR_DMISS
] = address
;
1590 env
->spr
[SPR_DCMP
] = 0x80000000 | ctx
.ptem
;
1592 env
->error_code
|= ctx
.key
<< 19;
1593 env
->spr
[SPR_HASH1
] = env
->htab_base
+
1594 get_pteg_offset32(cpu
, ctx
.hash
[0]);
1595 env
->spr
[SPR_HASH2
] = env
->htab_base
+
1596 get_pteg_offset32(cpu
, ctx
.hash
[1]);
1598 case POWERPC_MMU_SOFT_74xx
:
1600 cs
->exception_index
= POWERPC_EXCP_DSTLB
;
1602 cs
->exception_index
= POWERPC_EXCP_DLTLB
;
1605 /* Implement LRU algorithm */
1606 env
->error_code
= ctx
.key
<< 19;
1607 env
->spr
[SPR_TLBMISS
] = (address
& ~((target_ulong
)0x3)) |
1608 ((env
->last_way
+ 1) & (env
->nb_ways
- 1));
1609 env
->spr
[SPR_PTEHI
] = 0x80000000 | ctx
.ptem
;
1611 case POWERPC_MMU_SOFT_4xx
:
1612 case POWERPC_MMU_SOFT_4xx_Z
:
1613 cs
->exception_index
= POWERPC_EXCP_DTLB
;
1614 env
->error_code
= 0;
1615 env
->spr
[SPR_40x_DEAR
] = address
;
1617 env
->spr
[SPR_40x_ESR
] = 0x00800000;
1619 env
->spr
[SPR_40x_ESR
] = 0x00000000;
1622 case POWERPC_MMU_MPC8xx
:
1624 cpu_abort(cs
, "MPC8xx MMU model is not implemented\n");
1626 case POWERPC_MMU_BOOKE206
:
1627 booke206_update_mas_tlb_miss(env
, address
, rw
);
1629 case POWERPC_MMU_BOOKE
:
1630 cs
->exception_index
= POWERPC_EXCP_DTLB
;
1631 env
->error_code
= 0;
1632 env
->spr
[SPR_BOOKE_DEAR
] = address
;
1633 env
->spr
[SPR_BOOKE_ESR
] = rw
? ESR_ST
: 0;
1635 case POWERPC_MMU_REAL
:
1636 cpu_abort(cs
, "PowerPC in real mode should never raise "
1637 "any MMU exceptions\n");
1640 cpu_abort(cs
, "Unknown or invalid MMU model\n");
1645 /* Access rights violation */
1646 cs
->exception_index
= POWERPC_EXCP_DSI
;
1647 env
->error_code
= 0;
1648 if (env
->mmu_model
== POWERPC_MMU_SOFT_4xx
1649 || env
->mmu_model
== POWERPC_MMU_SOFT_4xx_Z
) {
1650 env
->spr
[SPR_40x_DEAR
] = address
;
1652 env
->spr
[SPR_40x_ESR
] |= 0x00800000;
1654 } else if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
1655 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
1656 env
->spr
[SPR_BOOKE_DEAR
] = address
;
1657 env
->spr
[SPR_BOOKE_ESR
] = rw
? ESR_ST
: 0;
1659 env
->spr
[SPR_DAR
] = address
;
1661 env
->spr
[SPR_DSISR
] = 0x0A000000;
1663 env
->spr
[SPR_DSISR
] = 0x08000000;
1668 /* Direct store exception */
1669 switch (access_type
) {
1671 /* Floating point load/store */
1672 cs
->exception_index
= POWERPC_EXCP_ALIGN
;
1673 env
->error_code
= POWERPC_EXCP_ALIGN_FP
;
1674 env
->spr
[SPR_DAR
] = address
;
1677 /* lwarx, ldarx or stwcx. */
1678 cs
->exception_index
= POWERPC_EXCP_DSI
;
1679 env
->error_code
= 0;
1680 env
->spr
[SPR_DAR
] = address
;
1682 env
->spr
[SPR_DSISR
] = 0x06000000;
1684 env
->spr
[SPR_DSISR
] = 0x04000000;
1688 /* eciwx or ecowx */
1689 cs
->exception_index
= POWERPC_EXCP_DSI
;
1690 env
->error_code
= 0;
1691 env
->spr
[SPR_DAR
] = address
;
1693 env
->spr
[SPR_DSISR
] = 0x06100000;
1695 env
->spr
[SPR_DSISR
] = 0x04100000;
1699 printf("DSI: invalid exception (%d)\n", ret
);
1700 cs
->exception_index
= POWERPC_EXCP_PROGRAM
;
1702 POWERPC_EXCP_INVAL
| POWERPC_EXCP_INVAL_INVAL
;
1703 env
->spr
[SPR_DAR
] = address
;
1710 printf("%s: set exception to %d %02x\n", __func__
,
1711 cs
->exception
, env
->error_code
);
1719 /*****************************************************************************/
1720 /* BATs management */
1721 #if !defined(FLUSH_ALL_TLBS)
1722 static inline void do_invalidate_BAT(CPUPPCState
*env
, target_ulong BATu
,
1725 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
1726 target_ulong base
, end
, page
;
1728 base
= BATu
& ~0x0001FFFF;
1729 end
= base
+ mask
+ 0x00020000;
1730 LOG_BATS("Flush BAT from " TARGET_FMT_lx
" to " TARGET_FMT_lx
" ("
1731 TARGET_FMT_lx
")\n", base
, end
, mask
);
1732 for (page
= base
; page
!= end
; page
+= TARGET_PAGE_SIZE
) {
1733 tlb_flush_page(cs
, page
);
1735 LOG_BATS("Flush done\n");
1739 static inline void dump_store_bat(CPUPPCState
*env
, char ID
, int ul
, int nr
,
1742 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx
" (" TARGET_FMT_lx
")\n", ID
,
1743 nr
, ul
== 0 ? 'u' : 'l', value
, env
->nip
);
1746 void helper_store_ibatu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1750 dump_store_bat(env
, 'I', 0, nr
, value
);
1751 if (env
->IBAT
[0][nr
] != value
) {
1752 mask
= (value
<< 15) & 0x0FFE0000UL
;
1753 #if !defined(FLUSH_ALL_TLBS)
1754 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
1756 /* When storing valid upper BAT, mask BEPI and BRPN
1757 * and invalidate all TLBs covered by this BAT
1759 mask
= (value
<< 15) & 0x0FFE0000UL
;
1760 env
->IBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
1761 (value
& ~0x0001FFFFUL
& ~mask
);
1762 env
->IBAT
[1][nr
] = (env
->IBAT
[1][nr
] & 0x0000007B) |
1763 (env
->IBAT
[1][nr
] & ~0x0001FFFF & ~mask
);
1764 #if !defined(FLUSH_ALL_TLBS)
1765 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
1772 void helper_store_ibatl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1774 dump_store_bat(env
, 'I', 1, nr
, value
);
1775 env
->IBAT
[1][nr
] = value
;
1778 void helper_store_dbatu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1782 dump_store_bat(env
, 'D', 0, nr
, value
);
1783 if (env
->DBAT
[0][nr
] != value
) {
1784 /* When storing valid upper BAT, mask BEPI and BRPN
1785 * and invalidate all TLBs covered by this BAT
1787 mask
= (value
<< 15) & 0x0FFE0000UL
;
1788 #if !defined(FLUSH_ALL_TLBS)
1789 do_invalidate_BAT(env
, env
->DBAT
[0][nr
], mask
);
1791 mask
= (value
<< 15) & 0x0FFE0000UL
;
1792 env
->DBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
1793 (value
& ~0x0001FFFFUL
& ~mask
);
1794 env
->DBAT
[1][nr
] = (env
->DBAT
[1][nr
] & 0x0000007B) |
1795 (env
->DBAT
[1][nr
] & ~0x0001FFFF & ~mask
);
1796 #if !defined(FLUSH_ALL_TLBS)
1797 do_invalidate_BAT(env
, env
->DBAT
[0][nr
], mask
);
1804 void helper_store_dbatl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1806 dump_store_bat(env
, 'D', 1, nr
, value
);
1807 env
->DBAT
[1][nr
] = value
;
1810 void helper_store_601_batu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1813 #if defined(FLUSH_ALL_TLBS)
1817 dump_store_bat(env
, 'I', 0, nr
, value
);
1818 if (env
->IBAT
[0][nr
] != value
) {
1819 #if defined(FLUSH_ALL_TLBS)
1822 mask
= (env
->IBAT
[1][nr
] << 17) & 0x0FFE0000UL
;
1823 if (env
->IBAT
[1][nr
] & 0x40) {
1824 /* Invalidate BAT only if it is valid */
1825 #if !defined(FLUSH_ALL_TLBS)
1826 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
1831 /* When storing valid upper BAT, mask BEPI and BRPN
1832 * and invalidate all TLBs covered by this BAT
1834 env
->IBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
1835 (value
& ~0x0001FFFFUL
& ~mask
);
1836 env
->DBAT
[0][nr
] = env
->IBAT
[0][nr
];
1837 if (env
->IBAT
[1][nr
] & 0x40) {
1838 #if !defined(FLUSH_ALL_TLBS)
1839 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
1844 #if defined(FLUSH_ALL_TLBS)
1852 void helper_store_601_batl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
1854 #if !defined(FLUSH_ALL_TLBS)
1860 dump_store_bat(env
, 'I', 1, nr
, value
);
1861 if (env
->IBAT
[1][nr
] != value
) {
1862 #if defined(FLUSH_ALL_TLBS)
1865 if (env
->IBAT
[1][nr
] & 0x40) {
1866 #if !defined(FLUSH_ALL_TLBS)
1867 mask
= (env
->IBAT
[1][nr
] << 17) & 0x0FFE0000UL
;
1868 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
1874 #if !defined(FLUSH_ALL_TLBS)
1875 mask
= (value
<< 17) & 0x0FFE0000UL
;
1876 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
1881 env
->IBAT
[1][nr
] = value
;
1882 env
->DBAT
[1][nr
] = value
;
1883 #if defined(FLUSH_ALL_TLBS)
1891 /*****************************************************************************/
1892 /* TLB management */
1893 void ppc_tlb_invalidate_all(CPUPPCState
*env
)
1895 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
1897 switch (env
->mmu_model
) {
1898 case POWERPC_MMU_SOFT_6xx
:
1899 case POWERPC_MMU_SOFT_74xx
:
1900 ppc6xx_tlb_invalidate_all(env
);
1902 case POWERPC_MMU_SOFT_4xx
:
1903 case POWERPC_MMU_SOFT_4xx_Z
:
1904 ppc4xx_tlb_invalidate_all(env
);
1906 case POWERPC_MMU_REAL
:
1907 cpu_abort(CPU(cpu
), "No TLB for PowerPC 4xx in real mode\n");
1909 case POWERPC_MMU_MPC8xx
:
1911 cpu_abort(CPU(cpu
), "MPC8xx MMU model is not implemented\n");
1913 case POWERPC_MMU_BOOKE
:
1914 tlb_flush(CPU(cpu
), 1);
1916 case POWERPC_MMU_BOOKE206
:
1917 booke206_flush_tlb(env
, -1, 0);
1919 case POWERPC_MMU_32B
:
1920 case POWERPC_MMU_601
:
1921 #if defined(TARGET_PPC64)
1922 case POWERPC_MMU_64B
:
1923 case POWERPC_MMU_2_03
:
1924 case POWERPC_MMU_2_06
:
1925 case POWERPC_MMU_2_06a
:
1926 case POWERPC_MMU_2_07
:
1927 case POWERPC_MMU_2_07a
:
1928 env
->tlb_need_flush
= 0;
1929 #endif /* defined(TARGET_PPC64) */
1930 tlb_flush(CPU(cpu
), 1);
1934 cpu_abort(CPU(cpu
), "Unknown MMU model\n");
1939 void ppc_tlb_invalidate_one(CPUPPCState
*env
, target_ulong addr
)
1941 #if !defined(FLUSH_ALL_TLBS)
1942 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
1945 addr
&= TARGET_PAGE_MASK
;
1946 switch (env
->mmu_model
) {
1947 case POWERPC_MMU_SOFT_6xx
:
1948 case POWERPC_MMU_SOFT_74xx
:
1949 ppc6xx_tlb_invalidate_virt(env
, addr
, 0);
1950 if (env
->id_tlbs
== 1) {
1951 ppc6xx_tlb_invalidate_virt(env
, addr
, 1);
1954 case POWERPC_MMU_32B
:
1955 case POWERPC_MMU_601
:
1956 /* tlbie invalidate TLBs for all segments */
1957 addr
&= ~((target_ulong
)-1ULL << 28);
1959 /* XXX: this case should be optimized,
1960 * giving a mask to tlb_flush_page
1962 tlb_flush_page(cs
, addr
| (0x0 << 28));
1963 tlb_flush_page(cs
, addr
| (0x1 << 28));
1964 tlb_flush_page(cs
, addr
| (0x2 << 28));
1965 tlb_flush_page(cs
, addr
| (0x3 << 28));
1966 tlb_flush_page(cs
, addr
| (0x4 << 28));
1967 tlb_flush_page(cs
, addr
| (0x5 << 28));
1968 tlb_flush_page(cs
, addr
| (0x6 << 28));
1969 tlb_flush_page(cs
, addr
| (0x7 << 28));
1970 tlb_flush_page(cs
, addr
| (0x8 << 28));
1971 tlb_flush_page(cs
, addr
| (0x9 << 28));
1972 tlb_flush_page(cs
, addr
| (0xA << 28));
1973 tlb_flush_page(cs
, addr
| (0xB << 28));
1974 tlb_flush_page(cs
, addr
| (0xC << 28));
1975 tlb_flush_page(cs
, addr
| (0xD << 28));
1976 tlb_flush_page(cs
, addr
| (0xE << 28));
1977 tlb_flush_page(cs
, addr
| (0xF << 28));
1979 #if defined(TARGET_PPC64)
1980 case POWERPC_MMU_64B
:
1981 case POWERPC_MMU_2_03
:
1982 case POWERPC_MMU_2_06
:
1983 case POWERPC_MMU_2_06a
:
1984 case POWERPC_MMU_2_07
:
1985 case POWERPC_MMU_2_07a
:
1986 /* tlbie invalidate TLBs for all segments */
1987 /* XXX: given the fact that there are too many segments to invalidate,
1988 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
1989 * we just invalidate all TLBs
1991 env
->tlb_need_flush
= 1;
1993 #endif /* defined(TARGET_PPC64) */
1995 /* Should never reach here with other MMU models */
1999 ppc_tlb_invalidate_all(env
);
2003 /*****************************************************************************/
2004 /* Special registers manipulation */
2005 void ppc_store_sdr1(CPUPPCState
*env
, target_ulong value
)
2007 qemu_log_mask(CPU_LOG_MMU
, "%s: " TARGET_FMT_lx
"\n", __func__
, value
);
2008 assert(!env
->external_htab
);
2009 env
->spr
[SPR_SDR1
] = value
;
2010 #if defined(TARGET_PPC64)
2011 if (env
->mmu_model
& POWERPC_MMU_64
) {
2012 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2013 Error
*local_err
= NULL
;
2015 ppc_hash64_set_sdr1(cpu
, value
, &local_err
);
2017 error_report_err(local_err
);
2018 error_free(local_err
);
2021 #endif /* defined(TARGET_PPC64) */
2023 /* FIXME: Should check for valid HTABMASK values */
2024 env
->htab_mask
= ((value
& SDR_32_HTABMASK
) << 16) | 0xFFFF;
2025 env
->htab_base
= value
& SDR_32_HTABORG
;
2029 /* Segment registers load and store */
2030 target_ulong
helper_load_sr(CPUPPCState
*env
, target_ulong sr_num
)
2032 #if defined(TARGET_PPC64)
2033 if (env
->mmu_model
& POWERPC_MMU_64
) {
2038 return env
->sr
[sr_num
];
2041 void helper_store_sr(CPUPPCState
*env
, target_ulong srnum
, target_ulong value
)
2043 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2045 qemu_log_mask(CPU_LOG_MMU
,
2046 "%s: reg=%d " TARGET_FMT_lx
" " TARGET_FMT_lx
"\n", __func__
,
2047 (int)srnum
, value
, env
->sr
[srnum
]);
2048 #if defined(TARGET_PPC64)
2049 if (env
->mmu_model
& POWERPC_MMU_64
) {
2050 uint64_t esid
, vsid
;
2053 esid
= ((uint64_t)(srnum
& 0xf) << 28) | SLB_ESID_V
;
2056 vsid
= (value
& 0xfffffff) << 12;
2058 vsid
|= ((value
>> 27) & 0xf) << 8;
2060 ppc_store_slb(cpu
, srnum
, esid
, vsid
);
2063 if (env
->sr
[srnum
] != value
) {
2064 env
->sr
[srnum
] = value
;
2065 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2066 flusing the whole TLB. */
2067 #if !defined(FLUSH_ALL_TLBS) && 0
2069 target_ulong page
, end
;
2070 /* Invalidate 256 MB of virtual memory */
2071 page
= (16 << 20) * srnum
;
2072 end
= page
+ (16 << 20);
2073 for (; page
!= end
; page
+= TARGET_PAGE_SIZE
) {
2074 tlb_flush_page(CPU(cpu
), page
);
2078 tlb_flush(CPU(cpu
), 1);
2083 /* TLB management */
2084 void helper_tlbia(CPUPPCState
*env
)
2086 ppc_tlb_invalidate_all(env
);
2089 void helper_tlbie(CPUPPCState
*env
, target_ulong addr
)
2091 ppc_tlb_invalidate_one(env
, addr
);
2094 void helper_tlbiva(CPUPPCState
*env
, target_ulong addr
)
2096 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2098 /* tlbiva instruction only exists on BookE */
2099 assert(env
->mmu_model
== POWERPC_MMU_BOOKE
);
2101 cpu_abort(CPU(cpu
), "BookE MMU model is not implemented\n");
2104 /* Software driven TLBs management */
2105 /* PowerPC 602/603 software TLB load instructions helpers */
2106 static void do_6xx_tlb(CPUPPCState
*env
, target_ulong new_EPN
, int is_code
)
2108 target_ulong RPN
, CMP
, EPN
;
2111 RPN
= env
->spr
[SPR_RPA
];
2113 CMP
= env
->spr
[SPR_ICMP
];
2114 EPN
= env
->spr
[SPR_IMISS
];
2116 CMP
= env
->spr
[SPR_DCMP
];
2117 EPN
= env
->spr
[SPR_DMISS
];
2119 way
= (env
->spr
[SPR_SRR1
] >> 17) & 1;
2120 (void)EPN
; /* avoid a compiler warning */
2121 LOG_SWTLB("%s: EPN " TARGET_FMT_lx
" " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
2122 " PTE1 " TARGET_FMT_lx
" way %d\n", __func__
, new_EPN
, EPN
, CMP
,
2124 /* Store this TLB */
2125 ppc6xx_tlb_store(env
, (uint32_t)(new_EPN
& TARGET_PAGE_MASK
),
2126 way
, is_code
, CMP
, RPN
);
2129 void helper_6xx_tlbd(CPUPPCState
*env
, target_ulong EPN
)
2131 do_6xx_tlb(env
, EPN
, 0);
2134 void helper_6xx_tlbi(CPUPPCState
*env
, target_ulong EPN
)
2136 do_6xx_tlb(env
, EPN
, 1);
2139 /* PowerPC 74xx software TLB load instructions helpers */
2140 static void do_74xx_tlb(CPUPPCState
*env
, target_ulong new_EPN
, int is_code
)
2142 target_ulong RPN
, CMP
, EPN
;
2145 RPN
= env
->spr
[SPR_PTELO
];
2146 CMP
= env
->spr
[SPR_PTEHI
];
2147 EPN
= env
->spr
[SPR_TLBMISS
] & ~0x3;
2148 way
= env
->spr
[SPR_TLBMISS
] & 0x3;
2149 (void)EPN
; /* avoid a compiler warning */
2150 LOG_SWTLB("%s: EPN " TARGET_FMT_lx
" " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
2151 " PTE1 " TARGET_FMT_lx
" way %d\n", __func__
, new_EPN
, EPN
, CMP
,
2153 /* Store this TLB */
2154 ppc6xx_tlb_store(env
, (uint32_t)(new_EPN
& TARGET_PAGE_MASK
),
2155 way
, is_code
, CMP
, RPN
);
2158 void helper_74xx_tlbd(CPUPPCState
*env
, target_ulong EPN
)
2160 do_74xx_tlb(env
, EPN
, 0);
2163 void helper_74xx_tlbi(CPUPPCState
*env
, target_ulong EPN
)
2165 do_74xx_tlb(env
, EPN
, 1);
2168 /*****************************************************************************/
2169 /* PowerPC 601 specific instructions (POWER bridge) */
2171 target_ulong
helper_rac(CPUPPCState
*env
, target_ulong addr
)
2175 target_ulong ret
= 0;
2177 /* We don't have to generate many instances of this instruction,
2178 * as rac is supervisor only.
2180 /* XXX: FIX THIS: Pretend we have no BAT */
2181 nb_BATs
= env
->nb_BATs
;
2183 if (get_physical_address(env
, &ctx
, addr
, 0, ACCESS_INT
) == 0) {
2186 env
->nb_BATs
= nb_BATs
;
2190 static inline target_ulong
booke_tlb_to_page_size(int size
)
2192 return 1024 << (2 * size
);
2195 static inline int booke_page_size_to_tlb(target_ulong page_size
)
2199 switch (page_size
) {
2233 #if defined(TARGET_PPC64)
2234 case 0x000100000000ULL
:
2237 case 0x000400000000ULL
:
2240 case 0x001000000000ULL
:
2243 case 0x004000000000ULL
:
2246 case 0x010000000000ULL
:
2258 /* Helpers for 4xx TLB management */
2259 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2261 #define PPC4XX_TLBHI_V 0x00000040
2262 #define PPC4XX_TLBHI_E 0x00000020
2263 #define PPC4XX_TLBHI_SIZE_MIN 0
2264 #define PPC4XX_TLBHI_SIZE_MAX 7
2265 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2266 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2267 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2269 #define PPC4XX_TLBLO_EX 0x00000200
2270 #define PPC4XX_TLBLO_WR 0x00000100
2271 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2272 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2274 target_ulong
helper_4xx_tlbre_hi(CPUPPCState
*env
, target_ulong entry
)
2280 entry
&= PPC4XX_TLB_ENTRY_MASK
;
2281 tlb
= &env
->tlb
.tlbe
[entry
];
2283 if (tlb
->prot
& PAGE_VALID
) {
2284 ret
|= PPC4XX_TLBHI_V
;
2286 size
= booke_page_size_to_tlb(tlb
->size
);
2287 if (size
< PPC4XX_TLBHI_SIZE_MIN
|| size
> PPC4XX_TLBHI_SIZE_MAX
) {
2288 size
= PPC4XX_TLBHI_SIZE_DEFAULT
;
2290 ret
|= size
<< PPC4XX_TLBHI_SIZE_SHIFT
;
2291 env
->spr
[SPR_40x_PID
] = tlb
->PID
;
2295 target_ulong
helper_4xx_tlbre_lo(CPUPPCState
*env
, target_ulong entry
)
2300 entry
&= PPC4XX_TLB_ENTRY_MASK
;
2301 tlb
= &env
->tlb
.tlbe
[entry
];
2303 if (tlb
->prot
& PAGE_EXEC
) {
2304 ret
|= PPC4XX_TLBLO_EX
;
2306 if (tlb
->prot
& PAGE_WRITE
) {
2307 ret
|= PPC4XX_TLBLO_WR
;
2312 void helper_4xx_tlbwe_hi(CPUPPCState
*env
, target_ulong entry
,
2315 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2316 CPUState
*cs
= CPU(cpu
);
2318 target_ulong page
, end
;
2320 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx
"\n", __func__
, (int)entry
,
2322 entry
&= PPC4XX_TLB_ENTRY_MASK
;
2323 tlb
= &env
->tlb
.tlbe
[entry
];
2324 /* Invalidate previous TLB (if it's valid) */
2325 if (tlb
->prot
& PAGE_VALID
) {
2326 end
= tlb
->EPN
+ tlb
->size
;
2327 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx
" end "
2328 TARGET_FMT_lx
"\n", __func__
, (int)entry
, tlb
->EPN
, end
);
2329 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
2330 tlb_flush_page(cs
, page
);
2333 tlb
->size
= booke_tlb_to_page_size((val
>> PPC4XX_TLBHI_SIZE_SHIFT
)
2334 & PPC4XX_TLBHI_SIZE_MASK
);
2335 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2336 * If this ever occurs, one should use the ppcemb target instead
2337 * of the ppc or ppc64 one
2339 if ((val
& PPC4XX_TLBHI_V
) && tlb
->size
< TARGET_PAGE_SIZE
) {
2340 cpu_abort(cs
, "TLB size " TARGET_FMT_lu
" < %u "
2341 "are not supported (%d)\n",
2342 tlb
->size
, TARGET_PAGE_SIZE
, (int)((val
>> 7) & 0x7));
2344 tlb
->EPN
= val
& ~(tlb
->size
- 1);
2345 if (val
& PPC4XX_TLBHI_V
) {
2346 tlb
->prot
|= PAGE_VALID
;
2347 if (val
& PPC4XX_TLBHI_E
) {
2348 /* XXX: TO BE FIXED */
2350 "Little-endian TLB entries are not supported by now\n");
2353 tlb
->prot
&= ~PAGE_VALID
;
2355 tlb
->PID
= env
->spr
[SPR_40x_PID
]; /* PID */
2356 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx
" EPN " TARGET_FMT_lx
2357 " size " TARGET_FMT_lx
" prot %c%c%c%c PID %d\n", __func__
,
2358 (int)entry
, tlb
->RPN
, tlb
->EPN
, tlb
->size
,
2359 tlb
->prot
& PAGE_READ
? 'r' : '-',
2360 tlb
->prot
& PAGE_WRITE
? 'w' : '-',
2361 tlb
->prot
& PAGE_EXEC
? 'x' : '-',
2362 tlb
->prot
& PAGE_VALID
? 'v' : '-', (int)tlb
->PID
);
2363 /* Invalidate new TLB (if valid) */
2364 if (tlb
->prot
& PAGE_VALID
) {
2365 end
= tlb
->EPN
+ tlb
->size
;
2366 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx
" end "
2367 TARGET_FMT_lx
"\n", __func__
, (int)entry
, tlb
->EPN
, end
);
2368 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
2369 tlb_flush_page(cs
, page
);
2374 void helper_4xx_tlbwe_lo(CPUPPCState
*env
, target_ulong entry
,
2379 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx
"\n", __func__
, (int)entry
,
2381 entry
&= PPC4XX_TLB_ENTRY_MASK
;
2382 tlb
= &env
->tlb
.tlbe
[entry
];
2383 tlb
->attr
= val
& PPC4XX_TLBLO_ATTR_MASK
;
2384 tlb
->RPN
= val
& PPC4XX_TLBLO_RPN_MASK
;
2385 tlb
->prot
= PAGE_READ
;
2386 if (val
& PPC4XX_TLBLO_EX
) {
2387 tlb
->prot
|= PAGE_EXEC
;
2389 if (val
& PPC4XX_TLBLO_WR
) {
2390 tlb
->prot
|= PAGE_WRITE
;
2392 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx
" EPN " TARGET_FMT_lx
2393 " size " TARGET_FMT_lx
" prot %c%c%c%c PID %d\n", __func__
,
2394 (int)entry
, tlb
->RPN
, tlb
->EPN
, tlb
->size
,
2395 tlb
->prot
& PAGE_READ
? 'r' : '-',
2396 tlb
->prot
& PAGE_WRITE
? 'w' : '-',
2397 tlb
->prot
& PAGE_EXEC
? 'x' : '-',
2398 tlb
->prot
& PAGE_VALID
? 'v' : '-', (int)tlb
->PID
);
2401 target_ulong
helper_4xx_tlbsx(CPUPPCState
*env
, target_ulong address
)
2403 return ppcemb_tlb_search(env
, address
, env
->spr
[SPR_40x_PID
]);
2406 /* PowerPC 440 TLB management */
2407 void helper_440_tlbwe(CPUPPCState
*env
, uint32_t word
, target_ulong entry
,
2410 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2412 target_ulong EPN
, RPN
, size
;
2415 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx
"\n",
2416 __func__
, word
, (int)entry
, value
);
2419 tlb
= &env
->tlb
.tlbe
[entry
];
2422 /* Just here to please gcc */
2424 EPN
= value
& 0xFFFFFC00;
2425 if ((tlb
->prot
& PAGE_VALID
) && EPN
!= tlb
->EPN
) {
2429 size
= booke_tlb_to_page_size((value
>> 4) & 0xF);
2430 if ((tlb
->prot
& PAGE_VALID
) && tlb
->size
< size
) {
2435 tlb
->attr
|= (value
>> 8) & 1;
2436 if (value
& 0x200) {
2437 tlb
->prot
|= PAGE_VALID
;
2439 if (tlb
->prot
& PAGE_VALID
) {
2440 tlb
->prot
&= ~PAGE_VALID
;
2444 tlb
->PID
= env
->spr
[SPR_440_MMUCR
] & 0x000000FF;
2445 if (do_flush_tlbs
) {
2446 tlb_flush(CPU(cpu
), 1);
2450 RPN
= value
& 0xFFFFFC0F;
2451 if ((tlb
->prot
& PAGE_VALID
) && tlb
->RPN
!= RPN
) {
2452 tlb_flush(CPU(cpu
), 1);
2457 tlb
->attr
= (tlb
->attr
& 0x1) | (value
& 0x0000FF00);
2458 tlb
->prot
= tlb
->prot
& PAGE_VALID
;
2460 tlb
->prot
|= PAGE_READ
<< 4;
2463 tlb
->prot
|= PAGE_WRITE
<< 4;
2466 tlb
->prot
|= PAGE_EXEC
<< 4;
2469 tlb
->prot
|= PAGE_READ
;
2472 tlb
->prot
|= PAGE_WRITE
;
2475 tlb
->prot
|= PAGE_EXEC
;
2481 target_ulong
helper_440_tlbre(CPUPPCState
*env
, uint32_t word
,
2489 tlb
= &env
->tlb
.tlbe
[entry
];
2492 /* Just here to please gcc */
2495 size
= booke_page_size_to_tlb(tlb
->size
);
2496 if (size
< 0 || size
> 0xF) {
2500 if (tlb
->attr
& 0x1) {
2503 if (tlb
->prot
& PAGE_VALID
) {
2506 env
->spr
[SPR_440_MMUCR
] &= ~0x000000FF;
2507 env
->spr
[SPR_440_MMUCR
] |= tlb
->PID
;
2513 ret
= tlb
->attr
& ~0x1;
2514 if (tlb
->prot
& (PAGE_READ
<< 4)) {
2517 if (tlb
->prot
& (PAGE_WRITE
<< 4)) {
2520 if (tlb
->prot
& (PAGE_EXEC
<< 4)) {
2523 if (tlb
->prot
& PAGE_READ
) {
2526 if (tlb
->prot
& PAGE_WRITE
) {
2529 if (tlb
->prot
& PAGE_EXEC
) {
2537 target_ulong
helper_440_tlbsx(CPUPPCState
*env
, target_ulong address
)
2539 return ppcemb_tlb_search(env
, address
, env
->spr
[SPR_440_MMUCR
] & 0xFF);
2542 /* PowerPC BookE 2.06 TLB management */
2544 static ppcmas_tlb_t
*booke206_cur_tlb(CPUPPCState
*env
)
2546 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2547 uint32_t tlbncfg
= 0;
2548 int esel
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_ESEL_MASK
) >> MAS0_ESEL_SHIFT
;
2549 int ea
= (env
->spr
[SPR_BOOKE_MAS2
] & MAS2_EPN_MASK
);
2552 tlb
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_TLBSEL_MASK
) >> MAS0_TLBSEL_SHIFT
;
2553 tlbncfg
= env
->spr
[SPR_BOOKE_TLB0CFG
+ tlb
];
2555 if ((tlbncfg
& TLBnCFG_HES
) && (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_HES
)) {
2556 cpu_abort(CPU(cpu
), "we don't support HES yet\n");
2559 return booke206_get_tlbm(env
, tlb
, ea
, esel
);
2562 void helper_booke_setpid(CPUPPCState
*env
, uint32_t pidn
, target_ulong pid
)
2564 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2566 env
->spr
[pidn
] = pid
;
2567 /* changing PIDs mean we're in a different address space now */
2568 tlb_flush(CPU(cpu
), 1);
2571 void helper_booke206_tlbwe(CPUPPCState
*env
)
2573 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2574 uint32_t tlbncfg
, tlbn
;
2576 uint32_t size_tlb
, size_ps
;
2580 switch (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_WQ_MASK
) {
2581 case MAS0_WQ_ALWAYS
:
2582 /* good to go, write that entry */
2585 /* XXX check if reserved */
2590 case MAS0_WQ_CLR_RSRV
:
2591 /* XXX clear entry */
2594 /* no idea what to do */
2598 if (((env
->spr
[SPR_BOOKE_MAS0
] & MAS0_ATSEL
) == MAS0_ATSEL_LRAT
) &&
2600 /* XXX we don't support direct LRAT setting yet */
2601 fprintf(stderr
, "cpu: don't support LRAT setting yet\n");
2605 tlbn
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_TLBSEL_MASK
) >> MAS0_TLBSEL_SHIFT
;
2606 tlbncfg
= env
->spr
[SPR_BOOKE_TLB0CFG
+ tlbn
];
2608 tlb
= booke206_cur_tlb(env
);
2611 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
2612 POWERPC_EXCP_INVAL
|
2613 POWERPC_EXCP_INVAL_INVAL
);
2616 /* check that we support the targeted size */
2617 size_tlb
= (env
->spr
[SPR_BOOKE_MAS1
] & MAS1_TSIZE_MASK
) >> MAS1_TSIZE_SHIFT
;
2618 size_ps
= booke206_tlbnps(env
, tlbn
);
2619 if ((env
->spr
[SPR_BOOKE_MAS1
] & MAS1_VALID
) && (tlbncfg
& TLBnCFG_AVAIL
) &&
2620 !(size_ps
& (1 << size_tlb
))) {
2621 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
2622 POWERPC_EXCP_INVAL
|
2623 POWERPC_EXCP_INVAL_INVAL
);
2627 cpu_abort(CPU(cpu
), "missing HV implementation\n");
2629 tlb
->mas7_3
= ((uint64_t)env
->spr
[SPR_BOOKE_MAS7
] << 32) |
2630 env
->spr
[SPR_BOOKE_MAS3
];
2631 tlb
->mas1
= env
->spr
[SPR_BOOKE_MAS1
];
2634 if (!(tlbncfg
& TLBnCFG_AVAIL
)) {
2635 /* force !AVAIL TLB entries to correct page size */
2636 tlb
->mas1
&= ~MAS1_TSIZE_MASK
;
2637 /* XXX can be configured in MMUCSR0 */
2638 tlb
->mas1
|= (tlbncfg
& TLBnCFG_MINSIZE
) >> 12;
2641 /* Make a mask from TLB size to discard invalid bits in EPN field */
2642 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
2643 /* Add a mask for page attributes */
2644 mask
|= MAS2_ACM
| MAS2_VLE
| MAS2_W
| MAS2_I
| MAS2_M
| MAS2_G
| MAS2_E
;
2647 /* Executing a tlbwe instruction in 32-bit mode will set
2648 * bits 0:31 of the TLB EPN field to zero.
2653 tlb
->mas2
= env
->spr
[SPR_BOOKE_MAS2
] & mask
;
2655 if (!(tlbncfg
& TLBnCFG_IPROT
)) {
2656 /* no IPROT supported by TLB */
2657 tlb
->mas1
&= ~MAS1_IPROT
;
2660 if (booke206_tlb_to_page_size(env
, tlb
) == TARGET_PAGE_SIZE
) {
2661 tlb_flush_page(CPU(cpu
), tlb
->mas2
& MAS2_EPN_MASK
);
2663 tlb_flush(CPU(cpu
), 1);
2667 static inline void booke206_tlb_to_mas(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
)
2669 int tlbn
= booke206_tlbm_to_tlbn(env
, tlb
);
2670 int way
= booke206_tlbm_to_way(env
, tlb
);
2672 env
->spr
[SPR_BOOKE_MAS0
] = tlbn
<< MAS0_TLBSEL_SHIFT
;
2673 env
->spr
[SPR_BOOKE_MAS0
] |= way
<< MAS0_ESEL_SHIFT
;
2674 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
2676 env
->spr
[SPR_BOOKE_MAS1
] = tlb
->mas1
;
2677 env
->spr
[SPR_BOOKE_MAS2
] = tlb
->mas2
;
2678 env
->spr
[SPR_BOOKE_MAS3
] = tlb
->mas7_3
;
2679 env
->spr
[SPR_BOOKE_MAS7
] = tlb
->mas7_3
>> 32;
2682 void helper_booke206_tlbre(CPUPPCState
*env
)
2684 ppcmas_tlb_t
*tlb
= NULL
;
2686 tlb
= booke206_cur_tlb(env
);
2688 env
->spr
[SPR_BOOKE_MAS1
] = 0;
2690 booke206_tlb_to_mas(env
, tlb
);
2694 void helper_booke206_tlbsx(CPUPPCState
*env
, target_ulong address
)
2696 ppcmas_tlb_t
*tlb
= NULL
;
2701 spid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID_MASK
) >> MAS6_SPID_SHIFT
;
2702 sas
= env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SAS
;
2704 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
2705 int ways
= booke206_tlb_ways(env
, i
);
2707 for (j
= 0; j
< ways
; j
++) {
2708 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
2714 if (ppcmas_tlb_check(env
, tlb
, &raddr
, address
, spid
)) {
2718 if (sas
!= ((tlb
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
)) {
2722 booke206_tlb_to_mas(env
, tlb
);
2727 /* no entry found, fill with defaults */
2728 env
->spr
[SPR_BOOKE_MAS0
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TLBSELD_MASK
;
2729 env
->spr
[SPR_BOOKE_MAS1
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TSIZED_MASK
;
2730 env
->spr
[SPR_BOOKE_MAS2
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_WIMGED_MASK
;
2731 env
->spr
[SPR_BOOKE_MAS3
] = 0;
2732 env
->spr
[SPR_BOOKE_MAS7
] = 0;
2734 if (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SAS
) {
2735 env
->spr
[SPR_BOOKE_MAS1
] |= MAS1_TS
;
2738 env
->spr
[SPR_BOOKE_MAS1
] |= (env
->spr
[SPR_BOOKE_MAS6
] >> 16)
2741 /* next victim logic */
2742 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_ESEL_SHIFT
;
2744 env
->last_way
&= booke206_tlb_ways(env
, 0) - 1;
2745 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
2748 static inline void booke206_invalidate_ea_tlb(CPUPPCState
*env
, int tlbn
,
2752 int ways
= booke206_tlb_ways(env
, tlbn
);
2755 for (i
= 0; i
< ways
; i
++) {
2756 ppcmas_tlb_t
*tlb
= booke206_get_tlbm(env
, tlbn
, ea
, i
);
2760 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
2761 if (((tlb
->mas2
& MAS2_EPN_MASK
) == (ea
& mask
)) &&
2762 !(tlb
->mas1
& MAS1_IPROT
)) {
2763 tlb
->mas1
&= ~MAS1_VALID
;
2768 void helper_booke206_tlbivax(CPUPPCState
*env
, target_ulong address
)
2770 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2772 if (address
& 0x4) {
2773 /* flush all entries */
2774 if (address
& 0x8) {
2775 /* flush all of TLB1 */
2776 booke206_flush_tlb(env
, BOOKE206_FLUSH_TLB1
, 1);
2778 /* flush all of TLB0 */
2779 booke206_flush_tlb(env
, BOOKE206_FLUSH_TLB0
, 0);
2784 if (address
& 0x8) {
2785 /* flush TLB1 entries */
2786 booke206_invalidate_ea_tlb(env
, 1, address
);
2787 tlb_flush(CPU(cpu
), 1);
2789 /* flush TLB0 entries */
2790 booke206_invalidate_ea_tlb(env
, 0, address
);
2791 tlb_flush_page(CPU(cpu
), address
& MAS2_EPN_MASK
);
2795 void helper_booke206_tlbilx0(CPUPPCState
*env
, target_ulong address
)
2797 /* XXX missing LPID handling */
2798 booke206_flush_tlb(env
, -1, 1);
2801 void helper_booke206_tlbilx1(CPUPPCState
*env
, target_ulong address
)
2803 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2805 int tid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID
);
2806 ppcmas_tlb_t
*tlb
= env
->tlb
.tlbm
;
2809 /* XXX missing LPID handling */
2810 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
2811 tlb_size
= booke206_tlb_size(env
, i
);
2812 for (j
= 0; j
< tlb_size
; j
++) {
2813 if (!(tlb
[j
].mas1
& MAS1_IPROT
) &&
2814 ((tlb
[j
].mas1
& MAS1_TID_MASK
) == tid
)) {
2815 tlb
[j
].mas1
&= ~MAS1_VALID
;
2818 tlb
+= booke206_tlb_size(env
, i
);
2820 tlb_flush(CPU(cpu
), 1);
2823 void helper_booke206_tlbilx3(CPUPPCState
*env
, target_ulong address
)
2825 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
2828 int tid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID
);
2829 int pid
= tid
>> MAS6_SPID_SHIFT
;
2830 int sgs
= env
->spr
[SPR_BOOKE_MAS5
] & MAS5_SGS
;
2831 int ind
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SIND
) ? MAS1_IND
: 0;
2832 /* XXX check for unsupported isize and raise an invalid opcode then */
2833 int size
= env
->spr
[SPR_BOOKE_MAS6
] & MAS6_ISIZE_MASK
;
2834 /* XXX implement MAV2 handling */
2837 /* XXX missing LPID handling */
2838 /* flush by pid and ea */
2839 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
2840 int ways
= booke206_tlb_ways(env
, i
);
2842 for (j
= 0; j
< ways
; j
++) {
2843 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
2847 if ((ppcmas_tlb_check(env
, tlb
, NULL
, address
, pid
) != 0) ||
2848 (tlb
->mas1
& MAS1_IPROT
) ||
2849 ((tlb
->mas1
& MAS1_IND
) != ind
) ||
2850 ((tlb
->mas8
& MAS8_TGS
) != sgs
)) {
2853 if (mav2
&& ((tlb
->mas1
& MAS1_TSIZE_MASK
) != size
)) {
2854 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2857 /* XXX e500mc doesn't match SAS, but other cores might */
2858 tlb
->mas1
&= ~MAS1_VALID
;
2861 tlb_flush(CPU(cpu
), 1);
2864 void helper_booke206_tlbflush(CPUPPCState
*env
, target_ulong type
)
2869 flags
|= BOOKE206_FLUSH_TLB1
;
2873 flags
|= BOOKE206_FLUSH_TLB0
;
2876 booke206_flush_tlb(env
, flags
, 1);
2880 void helper_check_tlb_flush(CPUPPCState
*env
)
2882 check_tlb_flush(env
);
2885 /*****************************************************************************/
2887 /* try to fill the TLB and return an exception if error. If retaddr is
2888 NULL, it means that the function was called in C code (i.e. not
2889 from generated code or from helper.c) */
2890 /* XXX: fix it to restore all registers */
2891 void tlb_fill(CPUState
*cs
, target_ulong addr
, int is_write
, int mmu_idx
,
2894 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
2895 PowerPCCPUClass
*pcc
= POWERPC_CPU_GET_CLASS(cs
);
2896 CPUPPCState
*env
= &cpu
->env
;
2899 if (pcc
->handle_mmu_fault
) {
2900 ret
= pcc
->handle_mmu_fault(cpu
, addr
, is_write
, mmu_idx
);
2902 ret
= cpu_ppc_handle_mmu_fault(env
, addr
, is_write
, mmu_idx
);
2904 if (unlikely(ret
!= 0)) {
2905 if (likely(retaddr
)) {
2906 /* now we have a real cpu fault */
2907 cpu_restore_state(cs
, retaddr
);
2909 helper_raise_exception_err(env
, cs
->exception_index
, env
->error_code
);