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.1 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/>.
20 #include "qemu/osdep.h"
21 #include "qemu/units.h"
23 #include "sysemu/kvm.h"
25 #include "mmu-hash64.h"
26 #include "mmu-hash32.h"
27 #include "exec/exec-all.h"
29 #include "helper_regs.h"
30 #include "qemu/error-report.h"
31 #include "qemu/main-loop.h"
32 #include "qemu/qemu-print.h"
34 #include "mmu-book3s-v3.h"
35 #include "mmu-radix64.h"
36 #include "exec/helper-proto.h"
37 #include "exec/cpu_ldst.h"
39 /* #define DEBUG_BATS */
40 /* #define DEBUG_SOFTWARE_TLB */
41 /* #define DUMP_PAGE_TABLES */
42 /* #define FLUSH_ALL_TLBS */
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 /* Software driven TLB helpers */
60 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState
*env
)
65 /* LOG_SWTLB("Invalidate all TLBs\n"); */
66 /* Invalidate all defined software TLB */
68 if (env
->id_tlbs
== 1) {
71 for (nr
= 0; nr
< max
; nr
++) {
72 tlb
= &env
->tlb
.tlb6
[nr
];
73 pte_invalidate(&tlb
->pte0
);
75 tlb_flush(env_cpu(env
));
78 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState
*env
,
80 int is_code
, int match_epn
)
82 #if !defined(FLUSH_ALL_TLBS)
83 CPUState
*cs
= env_cpu(env
);
87 /* Invalidate ITLB + DTLB, all ways */
88 for (way
= 0; way
< env
->nb_ways
; way
++) {
89 nr
= ppc6xx_tlb_getnum(env
, eaddr
, way
, is_code
);
90 tlb
= &env
->tlb
.tlb6
[nr
];
91 if (pte_is_valid(tlb
->pte0
) && (match_epn
== 0 || eaddr
== tlb
->EPN
)) {
92 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx
"\n", nr
,
94 pte_invalidate(&tlb
->pte0
);
95 tlb_flush_page(cs
, tlb
->EPN
);
99 /* XXX: PowerPC specification say this is valid as well */
100 ppc6xx_tlb_invalidate_all(env
);
104 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState
*env
,
105 target_ulong eaddr
, int is_code
)
107 ppc6xx_tlb_invalidate_virt2(env
, eaddr
, is_code
, 0);
110 static void ppc6xx_tlb_store(CPUPPCState
*env
, target_ulong EPN
, int way
,
111 int is_code
, target_ulong pte0
, target_ulong pte1
)
116 nr
= ppc6xx_tlb_getnum(env
, EPN
, way
, is_code
);
117 tlb
= &env
->tlb
.tlb6
[nr
];
118 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
119 " PTE1 " TARGET_FMT_lx
"\n", nr
, env
->nb_tlb
, EPN
, pte0
, pte1
);
120 /* Invalidate any pending reference in QEMU for this virtual address */
121 ppc6xx_tlb_invalidate_virt2(env
, EPN
, is_code
, 1);
125 /* Store last way for LRU mechanism */
129 /* Generic TLB search function for PowerPC embedded implementations */
130 static int ppcemb_tlb_search(CPUPPCState
*env
, target_ulong address
,
137 /* Default return value is no match */
139 for (i
= 0; i
< env
->nb_tlb
; i
++) {
140 tlb
= &env
->tlb
.tlbe
[i
];
141 if (ppcemb_tlb_check(env
, tlb
, &raddr
, address
, pid
, 0, i
) == 0) {
150 /* Helpers specific to PowerPC 40x implementations */
151 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState
*env
)
156 for (i
= 0; i
< env
->nb_tlb
; i
++) {
157 tlb
= &env
->tlb
.tlbe
[i
];
158 tlb
->prot
&= ~PAGE_VALID
;
160 tlb_flush(env_cpu(env
));
163 static void booke206_flush_tlb(CPUPPCState
*env
, int flags
,
164 const int check_iprot
)
168 ppcmas_tlb_t
*tlb
= env
->tlb
.tlbm
;
170 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
171 if (flags
& (1 << i
)) {
172 tlb_size
= booke206_tlb_size(env
, i
);
173 for (j
= 0; j
< tlb_size
; j
++) {
174 if (!check_iprot
|| !(tlb
[j
].mas1
& MAS1_IPROT
)) {
175 tlb
[j
].mas1
&= ~MAS1_VALID
;
179 tlb
+= booke206_tlb_size(env
, i
);
182 tlb_flush(env_cpu(env
));
185 static int get_physical_address(CPUPPCState
*env
, mmu_ctx_t
*ctx
,
186 target_ulong eaddr
, MMUAccessType access_type
,
189 return get_physical_address_wtlb(env
, ctx
, eaddr
, access_type
, type
, 0);
194 /*****************************************************************************/
195 /* BATs management */
196 #if !defined(FLUSH_ALL_TLBS)
197 static inline void do_invalidate_BAT(CPUPPCState
*env
, target_ulong BATu
,
200 CPUState
*cs
= env_cpu(env
);
201 target_ulong base
, end
, page
;
203 base
= BATu
& ~0x0001FFFF;
204 end
= base
+ mask
+ 0x00020000;
205 if (((end
- base
) >> TARGET_PAGE_BITS
) > 1024) {
206 /* Flushing 1024 4K pages is slower than a complete flush */
207 LOG_BATS("Flush all BATs\n");
209 LOG_BATS("Flush done\n");
212 LOG_BATS("Flush BAT from " TARGET_FMT_lx
" to " TARGET_FMT_lx
" ("
213 TARGET_FMT_lx
")\n", base
, end
, mask
);
214 for (page
= base
; page
!= end
; page
+= TARGET_PAGE_SIZE
) {
215 tlb_flush_page(cs
, page
);
217 LOG_BATS("Flush done\n");
221 static inline void dump_store_bat(CPUPPCState
*env
, char ID
, int ul
, int nr
,
224 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx
" (" TARGET_FMT_lx
")\n", ID
,
225 nr
, ul
== 0 ? 'u' : 'l', value
, env
->nip
);
228 void helper_store_ibatu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
232 dump_store_bat(env
, 'I', 0, nr
, value
);
233 if (env
->IBAT
[0][nr
] != value
) {
234 mask
= (value
<< 15) & 0x0FFE0000UL
;
235 #if !defined(FLUSH_ALL_TLBS)
236 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
239 * When storing valid upper BAT, mask BEPI and BRPN and
240 * invalidate all TLBs covered by this BAT
242 mask
= (value
<< 15) & 0x0FFE0000UL
;
243 env
->IBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
244 (value
& ~0x0001FFFFUL
& ~mask
);
245 env
->IBAT
[1][nr
] = (env
->IBAT
[1][nr
] & 0x0000007B) |
246 (env
->IBAT
[1][nr
] & ~0x0001FFFF & ~mask
);
247 #if !defined(FLUSH_ALL_TLBS)
248 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
250 tlb_flush(env_cpu(env
));
255 void helper_store_ibatl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
257 dump_store_bat(env
, 'I', 1, nr
, value
);
258 env
->IBAT
[1][nr
] = value
;
261 void helper_store_dbatu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
265 dump_store_bat(env
, 'D', 0, nr
, value
);
266 if (env
->DBAT
[0][nr
] != value
) {
268 * When storing valid upper BAT, mask BEPI and BRPN and
269 * invalidate all TLBs covered by this BAT
271 mask
= (value
<< 15) & 0x0FFE0000UL
;
272 #if !defined(FLUSH_ALL_TLBS)
273 do_invalidate_BAT(env
, env
->DBAT
[0][nr
], mask
);
275 mask
= (value
<< 15) & 0x0FFE0000UL
;
276 env
->DBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
277 (value
& ~0x0001FFFFUL
& ~mask
);
278 env
->DBAT
[1][nr
] = (env
->DBAT
[1][nr
] & 0x0000007B) |
279 (env
->DBAT
[1][nr
] & ~0x0001FFFF & ~mask
);
280 #if !defined(FLUSH_ALL_TLBS)
281 do_invalidate_BAT(env
, env
->DBAT
[0][nr
], mask
);
283 tlb_flush(env_cpu(env
));
288 void helper_store_dbatl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
290 dump_store_bat(env
, 'D', 1, nr
, value
);
291 env
->DBAT
[1][nr
] = value
;
294 void helper_store_601_batu(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
297 #if defined(FLUSH_ALL_TLBS)
301 dump_store_bat(env
, 'I', 0, nr
, value
);
302 if (env
->IBAT
[0][nr
] != value
) {
303 #if defined(FLUSH_ALL_TLBS)
306 mask
= (env
->IBAT
[1][nr
] << 17) & 0x0FFE0000UL
;
307 if (env
->IBAT
[1][nr
] & 0x40) {
308 /* Invalidate BAT only if it is valid */
309 #if !defined(FLUSH_ALL_TLBS)
310 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
316 * When storing valid upper BAT, mask BEPI and BRPN and
317 * invalidate all TLBs covered by this BAT
319 env
->IBAT
[0][nr
] = (value
& 0x00001FFFUL
) |
320 (value
& ~0x0001FFFFUL
& ~mask
);
321 env
->DBAT
[0][nr
] = env
->IBAT
[0][nr
];
322 if (env
->IBAT
[1][nr
] & 0x40) {
323 #if !defined(FLUSH_ALL_TLBS)
324 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
329 #if defined(FLUSH_ALL_TLBS)
331 tlb_flush(env_cpu(env
));
337 void helper_store_601_batl(CPUPPCState
*env
, uint32_t nr
, target_ulong value
)
339 #if !defined(FLUSH_ALL_TLBS)
345 dump_store_bat(env
, 'I', 1, nr
, value
);
346 if (env
->IBAT
[1][nr
] != value
) {
347 #if defined(FLUSH_ALL_TLBS)
350 if (env
->IBAT
[1][nr
] & 0x40) {
351 #if !defined(FLUSH_ALL_TLBS)
352 mask
= (env
->IBAT
[1][nr
] << 17) & 0x0FFE0000UL
;
353 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
359 #if !defined(FLUSH_ALL_TLBS)
360 mask
= (value
<< 17) & 0x0FFE0000UL
;
361 do_invalidate_BAT(env
, env
->IBAT
[0][nr
], mask
);
366 env
->IBAT
[1][nr
] = value
;
367 env
->DBAT
[1][nr
] = value
;
368 #if defined(FLUSH_ALL_TLBS)
370 tlb_flush(env_cpu(env
));
376 /*****************************************************************************/
378 void ppc_tlb_invalidate_all(CPUPPCState
*env
)
380 #if defined(TARGET_PPC64)
381 if (mmu_is_64bit(env
->mmu_model
)) {
382 env
->tlb_need_flush
= 0;
383 tlb_flush(env_cpu(env
));
385 #endif /* defined(TARGET_PPC64) */
386 switch (env
->mmu_model
) {
387 case POWERPC_MMU_SOFT_6xx
:
388 case POWERPC_MMU_SOFT_74xx
:
389 ppc6xx_tlb_invalidate_all(env
);
391 case POWERPC_MMU_SOFT_4xx
:
392 case POWERPC_MMU_SOFT_4xx_Z
:
393 ppc4xx_tlb_invalidate_all(env
);
395 case POWERPC_MMU_REAL
:
396 cpu_abort(env_cpu(env
), "No TLB for PowerPC 4xx in real mode\n");
398 case POWERPC_MMU_MPC8xx
:
400 cpu_abort(env_cpu(env
), "MPC8xx MMU model is not implemented\n");
402 case POWERPC_MMU_BOOKE
:
403 tlb_flush(env_cpu(env
));
405 case POWERPC_MMU_BOOKE206
:
406 booke206_flush_tlb(env
, -1, 0);
408 case POWERPC_MMU_32B
:
409 case POWERPC_MMU_601
:
410 env
->tlb_need_flush
= 0;
411 tlb_flush(env_cpu(env
));
415 cpu_abort(env_cpu(env
), "Unknown MMU model %x\n", env
->mmu_model
);
420 void ppc_tlb_invalidate_one(CPUPPCState
*env
, target_ulong addr
)
422 #if !defined(FLUSH_ALL_TLBS)
423 addr
&= TARGET_PAGE_MASK
;
424 #if defined(TARGET_PPC64)
425 if (mmu_is_64bit(env
->mmu_model
)) {
426 /* tlbie invalidate TLBs for all segments */
428 * XXX: given the fact that there are too many segments to invalidate,
429 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
430 * we just invalidate all TLBs
432 env
->tlb_need_flush
|= TLB_NEED_LOCAL_FLUSH
;
434 #endif /* defined(TARGET_PPC64) */
435 switch (env
->mmu_model
) {
436 case POWERPC_MMU_SOFT_6xx
:
437 case POWERPC_MMU_SOFT_74xx
:
438 ppc6xx_tlb_invalidate_virt(env
, addr
, 0);
439 if (env
->id_tlbs
== 1) {
440 ppc6xx_tlb_invalidate_virt(env
, addr
, 1);
443 case POWERPC_MMU_32B
:
444 case POWERPC_MMU_601
:
446 * Actual CPUs invalidate entire congruence classes based on
447 * the geometry of their TLBs and some OSes take that into
448 * account, we just mark the TLB to be flushed later (context
449 * synchronizing event or sync instruction on 32-bit).
451 env
->tlb_need_flush
|= TLB_NEED_LOCAL_FLUSH
;
454 /* Should never reach here with other MMU models */
458 ppc_tlb_invalidate_all(env
);
462 /*****************************************************************************/
463 /* Special registers manipulation */
465 /* Segment registers load and store */
466 target_ulong
helper_load_sr(CPUPPCState
*env
, target_ulong sr_num
)
468 #if defined(TARGET_PPC64)
469 if (mmu_is_64bit(env
->mmu_model
)) {
474 return env
->sr
[sr_num
];
477 void helper_store_sr(CPUPPCState
*env
, target_ulong srnum
, target_ulong value
)
479 qemu_log_mask(CPU_LOG_MMU
,
480 "%s: reg=%d " TARGET_FMT_lx
" " TARGET_FMT_lx
"\n", __func__
,
481 (int)srnum
, value
, env
->sr
[srnum
]);
482 #if defined(TARGET_PPC64)
483 if (mmu_is_64bit(env
->mmu_model
)) {
484 PowerPCCPU
*cpu
= env_archcpu(env
);
488 esid
= ((uint64_t)(srnum
& 0xf) << 28) | SLB_ESID_V
;
491 vsid
= (value
& 0xfffffff) << 12;
493 vsid
|= ((value
>> 27) & 0xf) << 8;
495 ppc_store_slb(cpu
, srnum
, esid
, vsid
);
498 if (env
->sr
[srnum
] != value
) {
499 env
->sr
[srnum
] = value
;
501 * Invalidating 256MB of virtual memory in 4kB pages is way
502 * longer than flushing the whole TLB.
504 #if !defined(FLUSH_ALL_TLBS) && 0
506 target_ulong page
, end
;
507 /* Invalidate 256 MB of virtual memory */
508 page
= (16 << 20) * srnum
;
509 end
= page
+ (16 << 20);
510 for (; page
!= end
; page
+= TARGET_PAGE_SIZE
) {
511 tlb_flush_page(env_cpu(env
), page
);
515 env
->tlb_need_flush
|= TLB_NEED_LOCAL_FLUSH
;
521 void helper_tlbia(CPUPPCState
*env
)
523 ppc_tlb_invalidate_all(env
);
526 void helper_tlbie(CPUPPCState
*env
, target_ulong addr
)
528 ppc_tlb_invalidate_one(env
, addr
);
531 void helper_tlbiva(CPUPPCState
*env
, target_ulong addr
)
533 /* tlbiva instruction only exists on BookE */
534 assert(env
->mmu_model
== POWERPC_MMU_BOOKE
);
536 cpu_abort(env_cpu(env
), "BookE MMU model is not implemented\n");
539 /* Software driven TLBs management */
540 /* PowerPC 602/603 software TLB load instructions helpers */
541 static void do_6xx_tlb(CPUPPCState
*env
, target_ulong new_EPN
, int is_code
)
543 target_ulong RPN
, CMP
, EPN
;
546 RPN
= env
->spr
[SPR_RPA
];
548 CMP
= env
->spr
[SPR_ICMP
];
549 EPN
= env
->spr
[SPR_IMISS
];
551 CMP
= env
->spr
[SPR_DCMP
];
552 EPN
= env
->spr
[SPR_DMISS
];
554 way
= (env
->spr
[SPR_SRR1
] >> 17) & 1;
555 (void)EPN
; /* avoid a compiler warning */
556 LOG_SWTLB("%s: EPN " TARGET_FMT_lx
" " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
557 " PTE1 " TARGET_FMT_lx
" way %d\n", __func__
, new_EPN
, EPN
, CMP
,
560 ppc6xx_tlb_store(env
, (uint32_t)(new_EPN
& TARGET_PAGE_MASK
),
561 way
, is_code
, CMP
, RPN
);
564 void helper_6xx_tlbd(CPUPPCState
*env
, target_ulong EPN
)
566 do_6xx_tlb(env
, EPN
, 0);
569 void helper_6xx_tlbi(CPUPPCState
*env
, target_ulong EPN
)
571 do_6xx_tlb(env
, EPN
, 1);
574 /* PowerPC 74xx software TLB load instructions helpers */
575 static void do_74xx_tlb(CPUPPCState
*env
, target_ulong new_EPN
, int is_code
)
577 target_ulong RPN
, CMP
, EPN
;
580 RPN
= env
->spr
[SPR_PTELO
];
581 CMP
= env
->spr
[SPR_PTEHI
];
582 EPN
= env
->spr
[SPR_TLBMISS
] & ~0x3;
583 way
= env
->spr
[SPR_TLBMISS
] & 0x3;
584 (void)EPN
; /* avoid a compiler warning */
585 LOG_SWTLB("%s: EPN " TARGET_FMT_lx
" " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
586 " PTE1 " TARGET_FMT_lx
" way %d\n", __func__
, new_EPN
, EPN
, CMP
,
589 ppc6xx_tlb_store(env
, (uint32_t)(new_EPN
& TARGET_PAGE_MASK
),
590 way
, is_code
, CMP
, RPN
);
593 void helper_74xx_tlbd(CPUPPCState
*env
, target_ulong EPN
)
595 do_74xx_tlb(env
, EPN
, 0);
598 void helper_74xx_tlbi(CPUPPCState
*env
, target_ulong EPN
)
600 do_74xx_tlb(env
, EPN
, 1);
603 /*****************************************************************************/
604 /* PowerPC 601 specific instructions (POWER bridge) */
606 target_ulong
helper_rac(CPUPPCState
*env
, target_ulong addr
)
610 target_ulong ret
= 0;
613 * We don't have to generate many instances of this instruction,
614 * as rac is supervisor only.
616 * XXX: FIX THIS: Pretend we have no BAT
618 nb_BATs
= env
->nb_BATs
;
620 if (get_physical_address(env
, &ctx
, addr
, 0, ACCESS_INT
) == 0) {
623 env
->nb_BATs
= nb_BATs
;
627 static inline target_ulong
booke_tlb_to_page_size(int size
)
629 return 1024 << (2 * size
);
632 static inline int booke_page_size_to_tlb(target_ulong page_size
)
670 #if defined(TARGET_PPC64)
671 case 0x000100000000ULL
:
674 case 0x000400000000ULL
:
677 case 0x001000000000ULL
:
680 case 0x004000000000ULL
:
683 case 0x010000000000ULL
:
695 /* Helpers for 4xx TLB management */
696 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
698 #define PPC4XX_TLBHI_V 0x00000040
699 #define PPC4XX_TLBHI_E 0x00000020
700 #define PPC4XX_TLBHI_SIZE_MIN 0
701 #define PPC4XX_TLBHI_SIZE_MAX 7
702 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
703 #define PPC4XX_TLBHI_SIZE_SHIFT 7
704 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
706 #define PPC4XX_TLBLO_EX 0x00000200
707 #define PPC4XX_TLBLO_WR 0x00000100
708 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
709 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
711 target_ulong
helper_4xx_tlbre_hi(CPUPPCState
*env
, target_ulong entry
)
717 entry
&= PPC4XX_TLB_ENTRY_MASK
;
718 tlb
= &env
->tlb
.tlbe
[entry
];
720 if (tlb
->prot
& PAGE_VALID
) {
721 ret
|= PPC4XX_TLBHI_V
;
723 size
= booke_page_size_to_tlb(tlb
->size
);
724 if (size
< PPC4XX_TLBHI_SIZE_MIN
|| size
> PPC4XX_TLBHI_SIZE_MAX
) {
725 size
= PPC4XX_TLBHI_SIZE_DEFAULT
;
727 ret
|= size
<< PPC4XX_TLBHI_SIZE_SHIFT
;
728 env
->spr
[SPR_40x_PID
] = tlb
->PID
;
732 target_ulong
helper_4xx_tlbre_lo(CPUPPCState
*env
, target_ulong entry
)
737 entry
&= PPC4XX_TLB_ENTRY_MASK
;
738 tlb
= &env
->tlb
.tlbe
[entry
];
740 if (tlb
->prot
& PAGE_EXEC
) {
741 ret
|= PPC4XX_TLBLO_EX
;
743 if (tlb
->prot
& PAGE_WRITE
) {
744 ret
|= PPC4XX_TLBLO_WR
;
749 void helper_4xx_tlbwe_hi(CPUPPCState
*env
, target_ulong entry
,
752 CPUState
*cs
= env_cpu(env
);
754 target_ulong page
, end
;
756 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx
"\n", __func__
, (int)entry
,
758 entry
&= PPC4XX_TLB_ENTRY_MASK
;
759 tlb
= &env
->tlb
.tlbe
[entry
];
760 /* Invalidate previous TLB (if it's valid) */
761 if (tlb
->prot
& PAGE_VALID
) {
762 end
= tlb
->EPN
+ tlb
->size
;
763 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx
" end "
764 TARGET_FMT_lx
"\n", __func__
, (int)entry
, tlb
->EPN
, end
);
765 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
766 tlb_flush_page(cs
, page
);
769 tlb
->size
= booke_tlb_to_page_size((val
>> PPC4XX_TLBHI_SIZE_SHIFT
)
770 & PPC4XX_TLBHI_SIZE_MASK
);
772 * We cannot handle TLB size < TARGET_PAGE_SIZE.
773 * If this ever occurs, we should implement TARGET_PAGE_BITS_VARY
775 if ((val
& PPC4XX_TLBHI_V
) && tlb
->size
< TARGET_PAGE_SIZE
) {
776 cpu_abort(cs
, "TLB size " TARGET_FMT_lu
" < %u "
777 "are not supported (%d)\n"
778 "Please implement TARGET_PAGE_BITS_VARY\n",
779 tlb
->size
, TARGET_PAGE_SIZE
, (int)((val
>> 7) & 0x7));
781 tlb
->EPN
= val
& ~(tlb
->size
- 1);
782 if (val
& PPC4XX_TLBHI_V
) {
783 tlb
->prot
|= PAGE_VALID
;
784 if (val
& PPC4XX_TLBHI_E
) {
785 /* XXX: TO BE FIXED */
787 "Little-endian TLB entries are not supported by now\n");
790 tlb
->prot
&= ~PAGE_VALID
;
792 tlb
->PID
= env
->spr
[SPR_40x_PID
]; /* PID */
793 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx
" EPN " TARGET_FMT_lx
794 " size " TARGET_FMT_lx
" prot %c%c%c%c PID %d\n", __func__
,
795 (int)entry
, tlb
->RPN
, tlb
->EPN
, tlb
->size
,
796 tlb
->prot
& PAGE_READ
? 'r' : '-',
797 tlb
->prot
& PAGE_WRITE
? 'w' : '-',
798 tlb
->prot
& PAGE_EXEC
? 'x' : '-',
799 tlb
->prot
& PAGE_VALID
? 'v' : '-', (int)tlb
->PID
);
800 /* Invalidate new TLB (if valid) */
801 if (tlb
->prot
& PAGE_VALID
) {
802 end
= tlb
->EPN
+ tlb
->size
;
803 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx
" end "
804 TARGET_FMT_lx
"\n", __func__
, (int)entry
, tlb
->EPN
, end
);
805 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
806 tlb_flush_page(cs
, page
);
811 void helper_4xx_tlbwe_lo(CPUPPCState
*env
, target_ulong entry
,
816 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx
"\n", __func__
, (int)entry
,
818 entry
&= PPC4XX_TLB_ENTRY_MASK
;
819 tlb
= &env
->tlb
.tlbe
[entry
];
820 tlb
->attr
= val
& PPC4XX_TLBLO_ATTR_MASK
;
821 tlb
->RPN
= val
& PPC4XX_TLBLO_RPN_MASK
;
822 tlb
->prot
= PAGE_READ
;
823 if (val
& PPC4XX_TLBLO_EX
) {
824 tlb
->prot
|= PAGE_EXEC
;
826 if (val
& PPC4XX_TLBLO_WR
) {
827 tlb
->prot
|= PAGE_WRITE
;
829 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx
" EPN " TARGET_FMT_lx
830 " size " TARGET_FMT_lx
" prot %c%c%c%c PID %d\n", __func__
,
831 (int)entry
, tlb
->RPN
, tlb
->EPN
, tlb
->size
,
832 tlb
->prot
& PAGE_READ
? 'r' : '-',
833 tlb
->prot
& PAGE_WRITE
? 'w' : '-',
834 tlb
->prot
& PAGE_EXEC
? 'x' : '-',
835 tlb
->prot
& PAGE_VALID
? 'v' : '-', (int)tlb
->PID
);
838 target_ulong
helper_4xx_tlbsx(CPUPPCState
*env
, target_ulong address
)
840 return ppcemb_tlb_search(env
, address
, env
->spr
[SPR_40x_PID
]);
843 /* PowerPC 440 TLB management */
844 void helper_440_tlbwe(CPUPPCState
*env
, uint32_t word
, target_ulong entry
,
848 target_ulong EPN
, RPN
, size
;
851 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx
"\n",
852 __func__
, word
, (int)entry
, value
);
855 tlb
= &env
->tlb
.tlbe
[entry
];
858 /* Just here to please gcc */
860 EPN
= value
& 0xFFFFFC00;
861 if ((tlb
->prot
& PAGE_VALID
) && EPN
!= tlb
->EPN
) {
865 size
= booke_tlb_to_page_size((value
>> 4) & 0xF);
866 if ((tlb
->prot
& PAGE_VALID
) && tlb
->size
< size
) {
871 tlb
->attr
|= (value
>> 8) & 1;
873 tlb
->prot
|= PAGE_VALID
;
875 if (tlb
->prot
& PAGE_VALID
) {
876 tlb
->prot
&= ~PAGE_VALID
;
880 tlb
->PID
= env
->spr
[SPR_440_MMUCR
] & 0x000000FF;
882 tlb_flush(env_cpu(env
));
886 RPN
= value
& 0xFFFFFC0F;
887 if ((tlb
->prot
& PAGE_VALID
) && tlb
->RPN
!= RPN
) {
888 tlb_flush(env_cpu(env
));
893 tlb
->attr
= (tlb
->attr
& 0x1) | (value
& 0x0000FF00);
894 tlb
->prot
= tlb
->prot
& PAGE_VALID
;
896 tlb
->prot
|= PAGE_READ
<< 4;
899 tlb
->prot
|= PAGE_WRITE
<< 4;
902 tlb
->prot
|= PAGE_EXEC
<< 4;
905 tlb
->prot
|= PAGE_READ
;
908 tlb
->prot
|= PAGE_WRITE
;
911 tlb
->prot
|= PAGE_EXEC
;
917 target_ulong
helper_440_tlbre(CPUPPCState
*env
, uint32_t word
,
925 tlb
= &env
->tlb
.tlbe
[entry
];
928 /* Just here to please gcc */
931 size
= booke_page_size_to_tlb(tlb
->size
);
932 if (size
< 0 || size
> 0xF) {
936 if (tlb
->attr
& 0x1) {
939 if (tlb
->prot
& PAGE_VALID
) {
942 env
->spr
[SPR_440_MMUCR
] &= ~0x000000FF;
943 env
->spr
[SPR_440_MMUCR
] |= tlb
->PID
;
949 ret
= tlb
->attr
& ~0x1;
950 if (tlb
->prot
& (PAGE_READ
<< 4)) {
953 if (tlb
->prot
& (PAGE_WRITE
<< 4)) {
956 if (tlb
->prot
& (PAGE_EXEC
<< 4)) {
959 if (tlb
->prot
& PAGE_READ
) {
962 if (tlb
->prot
& PAGE_WRITE
) {
965 if (tlb
->prot
& PAGE_EXEC
) {
973 target_ulong
helper_440_tlbsx(CPUPPCState
*env
, target_ulong address
)
975 return ppcemb_tlb_search(env
, address
, env
->spr
[SPR_440_MMUCR
] & 0xFF);
978 /* PowerPC BookE 2.06 TLB management */
980 static ppcmas_tlb_t
*booke206_cur_tlb(CPUPPCState
*env
)
982 uint32_t tlbncfg
= 0;
983 int esel
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_ESEL_MASK
) >> MAS0_ESEL_SHIFT
;
984 int ea
= (env
->spr
[SPR_BOOKE_MAS2
] & MAS2_EPN_MASK
);
987 tlb
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_TLBSEL_MASK
) >> MAS0_TLBSEL_SHIFT
;
988 tlbncfg
= env
->spr
[SPR_BOOKE_TLB0CFG
+ tlb
];
990 if ((tlbncfg
& TLBnCFG_HES
) && (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_HES
)) {
991 cpu_abort(env_cpu(env
), "we don't support HES yet\n");
994 return booke206_get_tlbm(env
, tlb
, ea
, esel
);
997 void helper_booke_setpid(CPUPPCState
*env
, uint32_t pidn
, target_ulong pid
)
999 env
->spr
[pidn
] = pid
;
1000 /* changing PIDs mean we're in a different address space now */
1001 tlb_flush(env_cpu(env
));
1004 void helper_booke_set_eplc(CPUPPCState
*env
, target_ulong val
)
1006 env
->spr
[SPR_BOOKE_EPLC
] = val
& EPID_MASK
;
1007 tlb_flush_by_mmuidx(env_cpu(env
), 1 << PPC_TLB_EPID_LOAD
);
1009 void helper_booke_set_epsc(CPUPPCState
*env
, target_ulong val
)
1011 env
->spr
[SPR_BOOKE_EPSC
] = val
& EPID_MASK
;
1012 tlb_flush_by_mmuidx(env_cpu(env
), 1 << PPC_TLB_EPID_STORE
);
1015 static inline void flush_page(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
)
1017 if (booke206_tlb_to_page_size(env
, tlb
) == TARGET_PAGE_SIZE
) {
1018 tlb_flush_page(env_cpu(env
), tlb
->mas2
& MAS2_EPN_MASK
);
1020 tlb_flush(env_cpu(env
));
1024 void helper_booke206_tlbwe(CPUPPCState
*env
)
1026 uint32_t tlbncfg
, tlbn
;
1028 uint32_t size_tlb
, size_ps
;
1032 switch (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_WQ_MASK
) {
1033 case MAS0_WQ_ALWAYS
:
1034 /* good to go, write that entry */
1037 /* XXX check if reserved */
1042 case MAS0_WQ_CLR_RSRV
:
1043 /* XXX clear entry */
1046 /* no idea what to do */
1050 if (((env
->spr
[SPR_BOOKE_MAS0
] & MAS0_ATSEL
) == MAS0_ATSEL_LRAT
) &&
1052 /* XXX we don't support direct LRAT setting yet */
1053 fprintf(stderr
, "cpu: don't support LRAT setting yet\n");
1057 tlbn
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_TLBSEL_MASK
) >> MAS0_TLBSEL_SHIFT
;
1058 tlbncfg
= env
->spr
[SPR_BOOKE_TLB0CFG
+ tlbn
];
1060 tlb
= booke206_cur_tlb(env
);
1063 raise_exception_err_ra(env
, POWERPC_EXCP_PROGRAM
,
1064 POWERPC_EXCP_INVAL
|
1065 POWERPC_EXCP_INVAL_INVAL
, GETPC());
1068 /* check that we support the targeted size */
1069 size_tlb
= (env
->spr
[SPR_BOOKE_MAS1
] & MAS1_TSIZE_MASK
) >> MAS1_TSIZE_SHIFT
;
1070 size_ps
= booke206_tlbnps(env
, tlbn
);
1071 if ((env
->spr
[SPR_BOOKE_MAS1
] & MAS1_VALID
) && (tlbncfg
& TLBnCFG_AVAIL
) &&
1072 !(size_ps
& (1 << size_tlb
))) {
1073 raise_exception_err_ra(env
, POWERPC_EXCP_PROGRAM
,
1074 POWERPC_EXCP_INVAL
|
1075 POWERPC_EXCP_INVAL_INVAL
, GETPC());
1079 cpu_abort(env_cpu(env
), "missing HV implementation\n");
1082 if (tlb
->mas1
& MAS1_VALID
) {
1084 * Invalidate the page in QEMU TLB if it was a valid entry.
1086 * In "PowerPC e500 Core Family Reference Manual, Rev. 1",
1087 * Section "12.4.2 TLB Write Entry (tlbwe) Instruction":
1088 * (https://www.nxp.com/docs/en/reference-manual/E500CORERM.pdf)
1090 * "Note that when an L2 TLB entry is written, it may be displacing an
1091 * already valid entry in the same L2 TLB location (a victim). If a
1092 * valid L1 TLB entry corresponds to the L2 MMU victim entry, that L1
1093 * TLB entry is automatically invalidated."
1095 flush_page(env
, tlb
);
1098 tlb
->mas7_3
= ((uint64_t)env
->spr
[SPR_BOOKE_MAS7
] << 32) |
1099 env
->spr
[SPR_BOOKE_MAS3
];
1100 tlb
->mas1
= env
->spr
[SPR_BOOKE_MAS1
];
1102 if ((env
->spr
[SPR_MMUCFG
] & MMUCFG_MAVN
) == MMUCFG_MAVN_V2
) {
1103 /* For TLB which has a fixed size TSIZE is ignored with MAV2 */
1104 booke206_fixed_size_tlbn(env
, tlbn
, tlb
);
1106 if (!(tlbncfg
& TLBnCFG_AVAIL
)) {
1107 /* force !AVAIL TLB entries to correct page size */
1108 tlb
->mas1
&= ~MAS1_TSIZE_MASK
;
1109 /* XXX can be configured in MMUCSR0 */
1110 tlb
->mas1
|= (tlbncfg
& TLBnCFG_MINSIZE
) >> 12;
1114 /* Make a mask from TLB size to discard invalid bits in EPN field */
1115 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
1116 /* Add a mask for page attributes */
1117 mask
|= MAS2_ACM
| MAS2_VLE
| MAS2_W
| MAS2_I
| MAS2_M
| MAS2_G
| MAS2_E
;
1121 * Executing a tlbwe instruction in 32-bit mode will set bits
1122 * 0:31 of the TLB EPN field to zero.
1127 tlb
->mas2
= env
->spr
[SPR_BOOKE_MAS2
] & mask
;
1129 if (!(tlbncfg
& TLBnCFG_IPROT
)) {
1130 /* no IPROT supported by TLB */
1131 tlb
->mas1
&= ~MAS1_IPROT
;
1134 flush_page(env
, tlb
);
1137 static inline void booke206_tlb_to_mas(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
)
1139 int tlbn
= booke206_tlbm_to_tlbn(env
, tlb
);
1140 int way
= booke206_tlbm_to_way(env
, tlb
);
1142 env
->spr
[SPR_BOOKE_MAS0
] = tlbn
<< MAS0_TLBSEL_SHIFT
;
1143 env
->spr
[SPR_BOOKE_MAS0
] |= way
<< MAS0_ESEL_SHIFT
;
1144 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
1146 env
->spr
[SPR_BOOKE_MAS1
] = tlb
->mas1
;
1147 env
->spr
[SPR_BOOKE_MAS2
] = tlb
->mas2
;
1148 env
->spr
[SPR_BOOKE_MAS3
] = tlb
->mas7_3
;
1149 env
->spr
[SPR_BOOKE_MAS7
] = tlb
->mas7_3
>> 32;
1152 void helper_booke206_tlbre(CPUPPCState
*env
)
1154 ppcmas_tlb_t
*tlb
= NULL
;
1156 tlb
= booke206_cur_tlb(env
);
1158 env
->spr
[SPR_BOOKE_MAS1
] = 0;
1160 booke206_tlb_to_mas(env
, tlb
);
1164 void helper_booke206_tlbsx(CPUPPCState
*env
, target_ulong address
)
1166 ppcmas_tlb_t
*tlb
= NULL
;
1171 spid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID_MASK
) >> MAS6_SPID_SHIFT
;
1172 sas
= env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SAS
;
1174 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
1175 int ways
= booke206_tlb_ways(env
, i
);
1177 for (j
= 0; j
< ways
; j
++) {
1178 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
1184 if (ppcmas_tlb_check(env
, tlb
, &raddr
, address
, spid
)) {
1188 if (sas
!= ((tlb
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
)) {
1192 booke206_tlb_to_mas(env
, tlb
);
1197 /* no entry found, fill with defaults */
1198 env
->spr
[SPR_BOOKE_MAS0
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TLBSELD_MASK
;
1199 env
->spr
[SPR_BOOKE_MAS1
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TSIZED_MASK
;
1200 env
->spr
[SPR_BOOKE_MAS2
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_WIMGED_MASK
;
1201 env
->spr
[SPR_BOOKE_MAS3
] = 0;
1202 env
->spr
[SPR_BOOKE_MAS7
] = 0;
1204 if (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SAS
) {
1205 env
->spr
[SPR_BOOKE_MAS1
] |= MAS1_TS
;
1208 env
->spr
[SPR_BOOKE_MAS1
] |= (env
->spr
[SPR_BOOKE_MAS6
] >> 16)
1211 /* next victim logic */
1212 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_ESEL_SHIFT
;
1214 env
->last_way
&= booke206_tlb_ways(env
, 0) - 1;
1215 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
1218 static inline void booke206_invalidate_ea_tlb(CPUPPCState
*env
, int tlbn
,
1222 int ways
= booke206_tlb_ways(env
, tlbn
);
1225 for (i
= 0; i
< ways
; i
++) {
1226 ppcmas_tlb_t
*tlb
= booke206_get_tlbm(env
, tlbn
, ea
, i
);
1230 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
1231 if (((tlb
->mas2
& MAS2_EPN_MASK
) == (ea
& mask
)) &&
1232 !(tlb
->mas1
& MAS1_IPROT
)) {
1233 tlb
->mas1
&= ~MAS1_VALID
;
1238 void helper_booke206_tlbivax(CPUPPCState
*env
, target_ulong address
)
1242 if (address
& 0x4) {
1243 /* flush all entries */
1244 if (address
& 0x8) {
1245 /* flush all of TLB1 */
1246 booke206_flush_tlb(env
, BOOKE206_FLUSH_TLB1
, 1);
1248 /* flush all of TLB0 */
1249 booke206_flush_tlb(env
, BOOKE206_FLUSH_TLB0
, 0);
1254 if (address
& 0x8) {
1255 /* flush TLB1 entries */
1256 booke206_invalidate_ea_tlb(env
, 1, address
);
1261 /* flush TLB0 entries */
1262 booke206_invalidate_ea_tlb(env
, 0, address
);
1264 tlb_flush_page(cs
, address
& MAS2_EPN_MASK
);
1269 void helper_booke206_tlbilx0(CPUPPCState
*env
, target_ulong address
)
1271 /* XXX missing LPID handling */
1272 booke206_flush_tlb(env
, -1, 1);
1275 void helper_booke206_tlbilx1(CPUPPCState
*env
, target_ulong address
)
1278 int tid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID
);
1279 ppcmas_tlb_t
*tlb
= env
->tlb
.tlbm
;
1282 /* XXX missing LPID handling */
1283 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
1284 tlb_size
= booke206_tlb_size(env
, i
);
1285 for (j
= 0; j
< tlb_size
; j
++) {
1286 if (!(tlb
[j
].mas1
& MAS1_IPROT
) &&
1287 ((tlb
[j
].mas1
& MAS1_TID_MASK
) == tid
)) {
1288 tlb
[j
].mas1
&= ~MAS1_VALID
;
1291 tlb
+= booke206_tlb_size(env
, i
);
1293 tlb_flush(env_cpu(env
));
1296 void helper_booke206_tlbilx3(CPUPPCState
*env
, target_ulong address
)
1300 int tid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID
);
1301 int pid
= tid
>> MAS6_SPID_SHIFT
;
1302 int sgs
= env
->spr
[SPR_BOOKE_MAS5
] & MAS5_SGS
;
1303 int ind
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SIND
) ? MAS1_IND
: 0;
1304 /* XXX check for unsupported isize and raise an invalid opcode then */
1305 int size
= env
->spr
[SPR_BOOKE_MAS6
] & MAS6_ISIZE_MASK
;
1306 /* XXX implement MAV2 handling */
1309 /* XXX missing LPID handling */
1310 /* flush by pid and ea */
1311 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
1312 int ways
= booke206_tlb_ways(env
, i
);
1314 for (j
= 0; j
< ways
; j
++) {
1315 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
1319 if ((ppcmas_tlb_check(env
, tlb
, NULL
, address
, pid
) != 0) ||
1320 (tlb
->mas1
& MAS1_IPROT
) ||
1321 ((tlb
->mas1
& MAS1_IND
) != ind
) ||
1322 ((tlb
->mas8
& MAS8_TGS
) != sgs
)) {
1325 if (mav2
&& ((tlb
->mas1
& MAS1_TSIZE_MASK
) != size
)) {
1326 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
1329 /* XXX e500mc doesn't match SAS, but other cores might */
1330 tlb
->mas1
&= ~MAS1_VALID
;
1333 tlb_flush(env_cpu(env
));
1336 void helper_booke206_tlbflush(CPUPPCState
*env
, target_ulong type
)
1341 flags
|= BOOKE206_FLUSH_TLB1
;
1345 flags
|= BOOKE206_FLUSH_TLB0
;
1348 booke206_flush_tlb(env
, flags
, 1);
1352 void helper_check_tlb_flush_local(CPUPPCState
*env
)
1354 check_tlb_flush(env
, false);
1357 void helper_check_tlb_flush_global(CPUPPCState
*env
)
1359 check_tlb_flush(env
, true);
1363 bool ppc_cpu_tlb_fill(CPUState
*cs
, vaddr eaddr
, int size
,
1364 MMUAccessType access_type
, int mmu_idx
,
1365 bool probe
, uintptr_t retaddr
)
1367 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
1369 int page_size
, prot
;
1371 if (ppc_xlate(cpu
, eaddr
, access_type
, &raddr
,
1372 &page_size
, &prot
, mmu_idx
, !probe
)) {
1373 tlb_set_page(cs
, eaddr
& TARGET_PAGE_MASK
, raddr
& TARGET_PAGE_MASK
,
1374 prot
, mmu_idx
, 1UL << page_size
);
1380 raise_exception_err_ra(&cpu
->env
, cs
->exception_index
,
1381 cpu
->env
.error_code
, retaddr
);