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/>.
22 //#define DEBUG_SOFTWARE_TLB
24 #ifdef DEBUG_SOFTWARE_TLB
25 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
27 # define LOG_SWTLB(...) do { } while (0)
30 /*****************************************************************************/
33 #if !defined(CONFIG_USER_ONLY)
34 void helper_store_ibatu(CPUPPCState
*env
, uint32_t nr
, target_ulong val
)
36 ppc_store_ibatu(env
, nr
, val
);
39 void helper_store_ibatl(CPUPPCState
*env
, uint32_t nr
, target_ulong val
)
41 ppc_store_ibatl(env
, nr
, val
);
44 void helper_store_dbatu(CPUPPCState
*env
, uint32_t nr
, target_ulong val
)
46 ppc_store_dbatu(env
, nr
, val
);
49 void helper_store_dbatl(CPUPPCState
*env
, uint32_t nr
, target_ulong val
)
51 ppc_store_dbatl(env
, nr
, val
);
54 void helper_store_601_batl(CPUPPCState
*env
, uint32_t nr
, target_ulong val
)
56 ppc_store_ibatl_601(env
, nr
, val
);
59 void helper_store_601_batu(CPUPPCState
*env
, uint32_t nr
, target_ulong val
)
61 ppc_store_ibatu_601(env
, nr
, val
);
64 /* Segment registers load and store */
65 target_ulong
helper_load_sr(CPUPPCState
*env
, target_ulong sr_num
)
67 #if defined(TARGET_PPC64)
68 if (env
->mmu_model
& POWERPC_MMU_64
) {
69 return ppc_load_sr(env
, sr_num
);
72 return env
->sr
[sr_num
];
75 void helper_store_sr(CPUPPCState
*env
, target_ulong sr_num
, target_ulong val
)
77 ppc_store_sr(env
, sr_num
, val
);
81 #if defined(TARGET_PPC64)
82 void helper_store_slb(CPUPPCState
*env
, target_ulong rb
, target_ulong rs
)
84 if (ppc_store_slb(env
, rb
, rs
) < 0) {
85 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
90 target_ulong
helper_load_slb_esid(CPUPPCState
*env
, target_ulong rb
)
94 if (ppc_load_slb_esid(env
, rb
, &rt
) < 0) {
95 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
101 target_ulong
helper_load_slb_vsid(CPUPPCState
*env
, target_ulong rb
)
105 if (ppc_load_slb_vsid(env
, rb
, &rt
) < 0) {
106 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
112 void helper_slbia(CPUPPCState
*env
)
114 ppc_slb_invalidate_all(env
);
117 void helper_slbie(CPUPPCState
*env
, target_ulong addr
)
119 ppc_slb_invalidate_one(env
, addr
);
122 #endif /* defined(TARGET_PPC64) */
125 void helper_tlbia(CPUPPCState
*env
)
127 ppc_tlb_invalidate_all(env
);
130 void helper_tlbie(CPUPPCState
*env
, target_ulong addr
)
132 ppc_tlb_invalidate_one(env
, addr
);
135 /* Software driven TLBs management */
136 /* PowerPC 602/603 software TLB load instructions helpers */
137 static void do_6xx_tlb(CPUPPCState
*env
, target_ulong new_EPN
, int is_code
)
139 target_ulong RPN
, CMP
, EPN
;
142 RPN
= env
->spr
[SPR_RPA
];
144 CMP
= env
->spr
[SPR_ICMP
];
145 EPN
= env
->spr
[SPR_IMISS
];
147 CMP
= env
->spr
[SPR_DCMP
];
148 EPN
= env
->spr
[SPR_DMISS
];
150 way
= (env
->spr
[SPR_SRR1
] >> 17) & 1;
151 (void)EPN
; /* avoid a compiler warning */
152 LOG_SWTLB("%s: EPN " TARGET_FMT_lx
" " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
153 " PTE1 " TARGET_FMT_lx
" way %d\n", __func__
, new_EPN
, EPN
, CMP
,
156 ppc6xx_tlb_store(env
, (uint32_t)(new_EPN
& TARGET_PAGE_MASK
),
157 way
, is_code
, CMP
, RPN
);
160 void helper_6xx_tlbd(CPUPPCState
*env
, target_ulong EPN
)
162 do_6xx_tlb(env
, EPN
, 0);
165 void helper_6xx_tlbi(CPUPPCState
*env
, target_ulong EPN
)
167 do_6xx_tlb(env
, EPN
, 1);
170 /* PowerPC 74xx software TLB load instructions helpers */
171 static void do_74xx_tlb(CPUPPCState
*env
, target_ulong new_EPN
, int is_code
)
173 target_ulong RPN
, CMP
, EPN
;
176 RPN
= env
->spr
[SPR_PTELO
];
177 CMP
= env
->spr
[SPR_PTEHI
];
178 EPN
= env
->spr
[SPR_TLBMISS
] & ~0x3;
179 way
= env
->spr
[SPR_TLBMISS
] & 0x3;
180 (void)EPN
; /* avoid a compiler warning */
181 LOG_SWTLB("%s: EPN " TARGET_FMT_lx
" " TARGET_FMT_lx
" PTE0 " TARGET_FMT_lx
182 " PTE1 " TARGET_FMT_lx
" way %d\n", __func__
, new_EPN
, EPN
, CMP
,
185 ppc6xx_tlb_store(env
, (uint32_t)(new_EPN
& TARGET_PAGE_MASK
),
186 way
, is_code
, CMP
, RPN
);
189 void helper_74xx_tlbd(CPUPPCState
*env
, target_ulong EPN
)
191 do_74xx_tlb(env
, EPN
, 0);
194 void helper_74xx_tlbi(CPUPPCState
*env
, target_ulong EPN
)
196 do_74xx_tlb(env
, EPN
, 1);
199 /*****************************************************************************/
200 /* PowerPC 601 specific instructions (POWER bridge) */
202 target_ulong
helper_rac(CPUPPCState
*env
, target_ulong addr
)
206 target_ulong ret
= 0;
208 /* We don't have to generate many instances of this instruction,
209 * as rac is supervisor only.
211 /* XXX: FIX THIS: Pretend we have no BAT */
212 nb_BATs
= env
->nb_BATs
;
214 if (get_physical_address(env
, &ctx
, addr
, 0, ACCESS_INT
) == 0) {
217 env
->nb_BATs
= nb_BATs
;
221 static inline target_ulong
booke_tlb_to_page_size(int size
)
223 return 1024 << (2 * size
);
226 static inline int booke_page_size_to_tlb(target_ulong page_size
)
264 #if defined(TARGET_PPC64)
265 case 0x000100000000ULL
:
268 case 0x000400000000ULL
:
271 case 0x001000000000ULL
:
274 case 0x004000000000ULL
:
277 case 0x010000000000ULL
:
289 /* Helpers for 4xx TLB management */
290 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
292 #define PPC4XX_TLBHI_V 0x00000040
293 #define PPC4XX_TLBHI_E 0x00000020
294 #define PPC4XX_TLBHI_SIZE_MIN 0
295 #define PPC4XX_TLBHI_SIZE_MAX 7
296 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
297 #define PPC4XX_TLBHI_SIZE_SHIFT 7
298 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
300 #define PPC4XX_TLBLO_EX 0x00000200
301 #define PPC4XX_TLBLO_WR 0x00000100
302 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
303 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
305 target_ulong
helper_4xx_tlbre_hi(CPUPPCState
*env
, target_ulong entry
)
311 entry
&= PPC4XX_TLB_ENTRY_MASK
;
312 tlb
= &env
->tlb
.tlbe
[entry
];
314 if (tlb
->prot
& PAGE_VALID
) {
315 ret
|= PPC4XX_TLBHI_V
;
317 size
= booke_page_size_to_tlb(tlb
->size
);
318 if (size
< PPC4XX_TLBHI_SIZE_MIN
|| size
> PPC4XX_TLBHI_SIZE_MAX
) {
319 size
= PPC4XX_TLBHI_SIZE_DEFAULT
;
321 ret
|= size
<< PPC4XX_TLBHI_SIZE_SHIFT
;
322 env
->spr
[SPR_40x_PID
] = tlb
->PID
;
326 target_ulong
helper_4xx_tlbre_lo(CPUPPCState
*env
, target_ulong entry
)
331 entry
&= PPC4XX_TLB_ENTRY_MASK
;
332 tlb
= &env
->tlb
.tlbe
[entry
];
334 if (tlb
->prot
& PAGE_EXEC
) {
335 ret
|= PPC4XX_TLBLO_EX
;
337 if (tlb
->prot
& PAGE_WRITE
) {
338 ret
|= PPC4XX_TLBLO_WR
;
343 void helper_4xx_tlbwe_hi(CPUPPCState
*env
, target_ulong entry
,
347 target_ulong page
, end
;
349 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx
"\n", __func__
, (int)entry
,
351 entry
&= PPC4XX_TLB_ENTRY_MASK
;
352 tlb
= &env
->tlb
.tlbe
[entry
];
353 /* Invalidate previous TLB (if it's valid) */
354 if (tlb
->prot
& PAGE_VALID
) {
355 end
= tlb
->EPN
+ tlb
->size
;
356 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx
" end "
357 TARGET_FMT_lx
"\n", __func__
, (int)entry
, tlb
->EPN
, end
);
358 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
359 tlb_flush_page(env
, page
);
362 tlb
->size
= booke_tlb_to_page_size((val
>> PPC4XX_TLBHI_SIZE_SHIFT
)
363 & PPC4XX_TLBHI_SIZE_MASK
);
364 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
365 * If this ever occurs, one should use the ppcemb target instead
366 * of the ppc or ppc64 one
368 if ((val
& PPC4XX_TLBHI_V
) && tlb
->size
< TARGET_PAGE_SIZE
) {
369 cpu_abort(env
, "TLB size " TARGET_FMT_lu
" < %u "
370 "are not supported (%d)\n",
371 tlb
->size
, TARGET_PAGE_SIZE
, (int)((val
>> 7) & 0x7));
373 tlb
->EPN
= val
& ~(tlb
->size
- 1);
374 if (val
& PPC4XX_TLBHI_V
) {
375 tlb
->prot
|= PAGE_VALID
;
376 if (val
& PPC4XX_TLBHI_E
) {
377 /* XXX: TO BE FIXED */
379 "Little-endian TLB entries are not supported by now\n");
382 tlb
->prot
&= ~PAGE_VALID
;
384 tlb
->PID
= env
->spr
[SPR_40x_PID
]; /* PID */
385 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx
" EPN " TARGET_FMT_lx
386 " size " TARGET_FMT_lx
" prot %c%c%c%c PID %d\n", __func__
,
387 (int)entry
, tlb
->RPN
, tlb
->EPN
, tlb
->size
,
388 tlb
->prot
& PAGE_READ
? 'r' : '-',
389 tlb
->prot
& PAGE_WRITE
? 'w' : '-',
390 tlb
->prot
& PAGE_EXEC
? 'x' : '-',
391 tlb
->prot
& PAGE_VALID
? 'v' : '-', (int)tlb
->PID
);
392 /* Invalidate new TLB (if valid) */
393 if (tlb
->prot
& PAGE_VALID
) {
394 end
= tlb
->EPN
+ tlb
->size
;
395 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx
" end "
396 TARGET_FMT_lx
"\n", __func__
, (int)entry
, tlb
->EPN
, end
);
397 for (page
= tlb
->EPN
; page
< end
; page
+= TARGET_PAGE_SIZE
) {
398 tlb_flush_page(env
, page
);
403 void helper_4xx_tlbwe_lo(CPUPPCState
*env
, target_ulong entry
,
408 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx
"\n", __func__
, (int)entry
,
410 entry
&= PPC4XX_TLB_ENTRY_MASK
;
411 tlb
= &env
->tlb
.tlbe
[entry
];
412 tlb
->attr
= val
& PPC4XX_TLBLO_ATTR_MASK
;
413 tlb
->RPN
= val
& PPC4XX_TLBLO_RPN_MASK
;
414 tlb
->prot
= PAGE_READ
;
415 if (val
& PPC4XX_TLBLO_EX
) {
416 tlb
->prot
|= PAGE_EXEC
;
418 if (val
& PPC4XX_TLBLO_WR
) {
419 tlb
->prot
|= PAGE_WRITE
;
421 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx
" EPN " TARGET_FMT_lx
422 " size " TARGET_FMT_lx
" prot %c%c%c%c PID %d\n", __func__
,
423 (int)entry
, tlb
->RPN
, tlb
->EPN
, tlb
->size
,
424 tlb
->prot
& PAGE_READ
? 'r' : '-',
425 tlb
->prot
& PAGE_WRITE
? 'w' : '-',
426 tlb
->prot
& PAGE_EXEC
? 'x' : '-',
427 tlb
->prot
& PAGE_VALID
? 'v' : '-', (int)tlb
->PID
);
430 target_ulong
helper_4xx_tlbsx(CPUPPCState
*env
, target_ulong address
)
432 return ppcemb_tlb_search(env
, address
, env
->spr
[SPR_40x_PID
]);
435 /* PowerPC 440 TLB management */
436 void helper_440_tlbwe(CPUPPCState
*env
, uint32_t word
, target_ulong entry
,
440 target_ulong EPN
, RPN
, size
;
443 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx
"\n",
444 __func__
, word
, (int)entry
, value
);
447 tlb
= &env
->tlb
.tlbe
[entry
];
450 /* Just here to please gcc */
452 EPN
= value
& 0xFFFFFC00;
453 if ((tlb
->prot
& PAGE_VALID
) && EPN
!= tlb
->EPN
) {
457 size
= booke_tlb_to_page_size((value
>> 4) & 0xF);
458 if ((tlb
->prot
& PAGE_VALID
) && tlb
->size
< size
) {
463 tlb
->attr
|= (value
>> 8) & 1;
465 tlb
->prot
|= PAGE_VALID
;
467 if (tlb
->prot
& PAGE_VALID
) {
468 tlb
->prot
&= ~PAGE_VALID
;
472 tlb
->PID
= env
->spr
[SPR_440_MMUCR
] & 0x000000FF;
478 RPN
= value
& 0xFFFFFC0F;
479 if ((tlb
->prot
& PAGE_VALID
) && tlb
->RPN
!= RPN
) {
485 tlb
->attr
= (tlb
->attr
& 0x1) | (value
& 0x0000FF00);
486 tlb
->prot
= tlb
->prot
& PAGE_VALID
;
488 tlb
->prot
|= PAGE_READ
<< 4;
491 tlb
->prot
|= PAGE_WRITE
<< 4;
494 tlb
->prot
|= PAGE_EXEC
<< 4;
497 tlb
->prot
|= PAGE_READ
;
500 tlb
->prot
|= PAGE_WRITE
;
503 tlb
->prot
|= PAGE_EXEC
;
509 target_ulong
helper_440_tlbre(CPUPPCState
*env
, uint32_t word
,
517 tlb
= &env
->tlb
.tlbe
[entry
];
520 /* Just here to please gcc */
523 size
= booke_page_size_to_tlb(tlb
->size
);
524 if (size
< 0 || size
> 0xF) {
528 if (tlb
->attr
& 0x1) {
531 if (tlb
->prot
& PAGE_VALID
) {
534 env
->spr
[SPR_440_MMUCR
] &= ~0x000000FF;
535 env
->spr
[SPR_440_MMUCR
] |= tlb
->PID
;
541 ret
= tlb
->attr
& ~0x1;
542 if (tlb
->prot
& (PAGE_READ
<< 4)) {
545 if (tlb
->prot
& (PAGE_WRITE
<< 4)) {
548 if (tlb
->prot
& (PAGE_EXEC
<< 4)) {
551 if (tlb
->prot
& PAGE_READ
) {
554 if (tlb
->prot
& PAGE_WRITE
) {
557 if (tlb
->prot
& PAGE_EXEC
) {
565 target_ulong
helper_440_tlbsx(CPUPPCState
*env
, target_ulong address
)
567 return ppcemb_tlb_search(env
, address
, env
->spr
[SPR_440_MMUCR
] & 0xFF);
570 /* PowerPC BookE 2.06 TLB management */
572 static ppcmas_tlb_t
*booke206_cur_tlb(CPUPPCState
*env
)
574 uint32_t tlbncfg
= 0;
575 int esel
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_ESEL_MASK
) >> MAS0_ESEL_SHIFT
;
576 int ea
= (env
->spr
[SPR_BOOKE_MAS2
] & MAS2_EPN_MASK
);
579 tlb
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_TLBSEL_MASK
) >> MAS0_TLBSEL_SHIFT
;
580 tlbncfg
= env
->spr
[SPR_BOOKE_TLB0CFG
+ tlb
];
582 if ((tlbncfg
& TLBnCFG_HES
) && (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_HES
)) {
583 cpu_abort(env
, "we don't support HES yet\n");
586 return booke206_get_tlbm(env
, tlb
, ea
, esel
);
589 void helper_booke_setpid(CPUPPCState
*env
, uint32_t pidn
, target_ulong pid
)
591 env
->spr
[pidn
] = pid
;
592 /* changing PIDs mean we're in a different address space now */
596 void helper_booke206_tlbwe(CPUPPCState
*env
)
598 uint32_t tlbncfg
, tlbn
;
600 uint32_t size_tlb
, size_ps
;
602 switch (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_WQ_MASK
) {
604 /* good to go, write that entry */
607 /* XXX check if reserved */
612 case MAS0_WQ_CLR_RSRV
:
613 /* XXX clear entry */
616 /* no idea what to do */
620 if (((env
->spr
[SPR_BOOKE_MAS0
] & MAS0_ATSEL
) == MAS0_ATSEL_LRAT
) &&
622 /* XXX we don't support direct LRAT setting yet */
623 fprintf(stderr
, "cpu: don't support LRAT setting yet\n");
627 tlbn
= (env
->spr
[SPR_BOOKE_MAS0
] & MAS0_TLBSEL_MASK
) >> MAS0_TLBSEL_SHIFT
;
628 tlbncfg
= env
->spr
[SPR_BOOKE_TLB0CFG
+ tlbn
];
630 tlb
= booke206_cur_tlb(env
);
633 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
635 POWERPC_EXCP_INVAL_INVAL
);
638 /* check that we support the targeted size */
639 size_tlb
= (env
->spr
[SPR_BOOKE_MAS1
] & MAS1_TSIZE_MASK
) >> MAS1_TSIZE_SHIFT
;
640 size_ps
= booke206_tlbnps(env
, tlbn
);
641 if ((env
->spr
[SPR_BOOKE_MAS1
] & MAS1_VALID
) && (tlbncfg
& TLBnCFG_AVAIL
) &&
642 !(size_ps
& (1 << size_tlb
))) {
643 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
645 POWERPC_EXCP_INVAL_INVAL
);
649 cpu_abort(env
, "missing HV implementation\n");
651 tlb
->mas7_3
= ((uint64_t)env
->spr
[SPR_BOOKE_MAS7
] << 32) |
652 env
->spr
[SPR_BOOKE_MAS3
];
653 tlb
->mas1
= env
->spr
[SPR_BOOKE_MAS1
];
656 if (!(tlbncfg
& TLBnCFG_AVAIL
)) {
657 /* force !AVAIL TLB entries to correct page size */
658 tlb
->mas1
&= ~MAS1_TSIZE_MASK
;
659 /* XXX can be configured in MMUCSR0 */
660 tlb
->mas1
|= (tlbncfg
& TLBnCFG_MINSIZE
) >> 12;
663 /* XXX needs to change when supporting 64-bit e500 */
664 tlb
->mas2
= env
->spr
[SPR_BOOKE_MAS2
] & 0xffffffff;
666 if (!(tlbncfg
& TLBnCFG_IPROT
)) {
667 /* no IPROT supported by TLB */
668 tlb
->mas1
&= ~MAS1_IPROT
;
671 if (booke206_tlb_to_page_size(env
, tlb
) == TARGET_PAGE_SIZE
) {
672 tlb_flush_page(env
, tlb
->mas2
& MAS2_EPN_MASK
);
678 static inline void booke206_tlb_to_mas(CPUPPCState
*env
, ppcmas_tlb_t
*tlb
)
680 int tlbn
= booke206_tlbm_to_tlbn(env
, tlb
);
681 int way
= booke206_tlbm_to_way(env
, tlb
);
683 env
->spr
[SPR_BOOKE_MAS0
] = tlbn
<< MAS0_TLBSEL_SHIFT
;
684 env
->spr
[SPR_BOOKE_MAS0
] |= way
<< MAS0_ESEL_SHIFT
;
685 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
687 env
->spr
[SPR_BOOKE_MAS1
] = tlb
->mas1
;
688 env
->spr
[SPR_BOOKE_MAS2
] = tlb
->mas2
;
689 env
->spr
[SPR_BOOKE_MAS3
] = tlb
->mas7_3
;
690 env
->spr
[SPR_BOOKE_MAS7
] = tlb
->mas7_3
>> 32;
693 void helper_booke206_tlbre(CPUPPCState
*env
)
695 ppcmas_tlb_t
*tlb
= NULL
;
697 tlb
= booke206_cur_tlb(env
);
699 env
->spr
[SPR_BOOKE_MAS1
] = 0;
701 booke206_tlb_to_mas(env
, tlb
);
705 void helper_booke206_tlbsx(CPUPPCState
*env
, target_ulong address
)
707 ppcmas_tlb_t
*tlb
= NULL
;
709 target_phys_addr_t raddr
;
712 spid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID_MASK
) >> MAS6_SPID_SHIFT
;
713 sas
= env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SAS
;
715 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
716 int ways
= booke206_tlb_ways(env
, i
);
718 for (j
= 0; j
< ways
; j
++) {
719 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
725 if (ppcmas_tlb_check(env
, tlb
, &raddr
, address
, spid
)) {
729 if (sas
!= ((tlb
->mas1
& MAS1_TS
) >> MAS1_TS_SHIFT
)) {
733 booke206_tlb_to_mas(env
, tlb
);
738 /* no entry found, fill with defaults */
739 env
->spr
[SPR_BOOKE_MAS0
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TLBSELD_MASK
;
740 env
->spr
[SPR_BOOKE_MAS1
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_TSIZED_MASK
;
741 env
->spr
[SPR_BOOKE_MAS2
] = env
->spr
[SPR_BOOKE_MAS4
] & MAS4_WIMGED_MASK
;
742 env
->spr
[SPR_BOOKE_MAS3
] = 0;
743 env
->spr
[SPR_BOOKE_MAS7
] = 0;
745 if (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SAS
) {
746 env
->spr
[SPR_BOOKE_MAS1
] |= MAS1_TS
;
749 env
->spr
[SPR_BOOKE_MAS1
] |= (env
->spr
[SPR_BOOKE_MAS6
] >> 16)
752 /* next victim logic */
753 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_ESEL_SHIFT
;
755 env
->last_way
&= booke206_tlb_ways(env
, 0) - 1;
756 env
->spr
[SPR_BOOKE_MAS0
] |= env
->last_way
<< MAS0_NV_SHIFT
;
759 static inline void booke206_invalidate_ea_tlb(CPUPPCState
*env
, int tlbn
,
763 int ways
= booke206_tlb_ways(env
, tlbn
);
766 for (i
= 0; i
< ways
; i
++) {
767 ppcmas_tlb_t
*tlb
= booke206_get_tlbm(env
, tlbn
, ea
, i
);
771 mask
= ~(booke206_tlb_to_page_size(env
, tlb
) - 1);
772 if (((tlb
->mas2
& MAS2_EPN_MASK
) == (ea
& mask
)) &&
773 !(tlb
->mas1
& MAS1_IPROT
)) {
774 tlb
->mas1
&= ~MAS1_VALID
;
779 void helper_booke206_tlbivax(CPUPPCState
*env
, target_ulong address
)
782 /* flush all entries */
784 /* flush all of TLB1 */
785 booke206_flush_tlb(env
, BOOKE206_FLUSH_TLB1
, 1);
787 /* flush all of TLB0 */
788 booke206_flush_tlb(env
, BOOKE206_FLUSH_TLB0
, 0);
794 /* flush TLB1 entries */
795 booke206_invalidate_ea_tlb(env
, 1, address
);
798 /* flush TLB0 entries */
799 booke206_invalidate_ea_tlb(env
, 0, address
);
800 tlb_flush_page(env
, address
& MAS2_EPN_MASK
);
804 void helper_booke206_tlbilx0(CPUPPCState
*env
, target_ulong address
)
806 /* XXX missing LPID handling */
807 booke206_flush_tlb(env
, -1, 1);
810 void helper_booke206_tlbilx1(CPUPPCState
*env
, target_ulong address
)
813 int tid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID
);
814 ppcmas_tlb_t
*tlb
= env
->tlb
.tlbm
;
817 /* XXX missing LPID handling */
818 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
819 tlb_size
= booke206_tlb_size(env
, i
);
820 for (j
= 0; j
< tlb_size
; j
++) {
821 if (!(tlb
[j
].mas1
& MAS1_IPROT
) &&
822 ((tlb
[j
].mas1
& MAS1_TID_MASK
) == tid
)) {
823 tlb
[j
].mas1
&= ~MAS1_VALID
;
826 tlb
+= booke206_tlb_size(env
, i
);
831 void helper_booke206_tlbilx3(CPUPPCState
*env
, target_ulong address
)
835 int tid
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SPID
);
836 int pid
= tid
>> MAS6_SPID_SHIFT
;
837 int sgs
= env
->spr
[SPR_BOOKE_MAS5
] & MAS5_SGS
;
838 int ind
= (env
->spr
[SPR_BOOKE_MAS6
] & MAS6_SIND
) ? MAS1_IND
: 0;
839 /* XXX check for unsupported isize and raise an invalid opcode then */
840 int size
= env
->spr
[SPR_BOOKE_MAS6
] & MAS6_ISIZE_MASK
;
841 /* XXX implement MAV2 handling */
844 /* XXX missing LPID handling */
845 /* flush by pid and ea */
846 for (i
= 0; i
< BOOKE206_MAX_TLBN
; i
++) {
847 int ways
= booke206_tlb_ways(env
, i
);
849 for (j
= 0; j
< ways
; j
++) {
850 tlb
= booke206_get_tlbm(env
, i
, address
, j
);
854 if ((ppcmas_tlb_check(env
, tlb
, NULL
, address
, pid
) != 0) ||
855 (tlb
->mas1
& MAS1_IPROT
) ||
856 ((tlb
->mas1
& MAS1_IND
) != ind
) ||
857 ((tlb
->mas8
& MAS8_TGS
) != sgs
)) {
860 if (mav2
&& ((tlb
->mas1
& MAS1_TSIZE_MASK
) != size
)) {
861 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
864 /* XXX e500mc doesn't match SAS, but other cores might */
865 tlb
->mas1
&= ~MAS1_VALID
;
871 void helper_booke206_tlbflush(CPUPPCState
*env
, uint32_t type
)
876 flags
|= BOOKE206_FLUSH_TLB1
;
880 flags
|= BOOKE206_FLUSH_TLB0
;
883 booke206_flush_tlb(env
, flags
, 1);