ppc: Avoid a warning with the next patch
[qemu/qmp-unstable.git] / target-ppc / mmu_helper.c
blobe79b8f284f73aeb681fb60baf7b7f3e71c0aaf81
1 /*
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 "cpu.h"
20 #include "helper.h"
22 //#define DEBUG_SOFTWARE_TLB
24 #ifdef DEBUG_SOFTWARE_TLB
25 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
26 #else
27 # define LOG_SWTLB(...) do { } while (0)
28 #endif
30 /*****************************************************************************/
31 /* SPR accesses */
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);
71 #endif
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);
80 /* SLB management */
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,
86 POWERPC_EXCP_INVAL);
90 target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
92 target_ulong rt = 0;
94 if (ppc_load_slb_esid(env, rb, &rt) < 0) {
95 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
96 POWERPC_EXCP_INVAL);
98 return rt;
101 target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
103 target_ulong rt = 0;
105 if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
106 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
107 POWERPC_EXCP_INVAL);
109 return rt;
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) */
124 /* TLB management */
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;
140 int way;
142 RPN = env->spr[SPR_RPA];
143 if (is_code) {
144 CMP = env->spr[SPR_ICMP];
145 EPN = env->spr[SPR_IMISS];
146 } else {
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,
154 RPN, way);
155 /* Store this TLB */
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;
174 int way;
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,
183 RPN, way);
184 /* Store this TLB */
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)
204 mmu_ctx_t ctx;
205 int nb_BATs;
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;
213 env->nb_BATs = 0;
214 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
215 ret = ctx.raddr;
217 env->nb_BATs = nb_BATs;
218 return ret;
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)
228 int size;
230 switch (page_size) {
231 case 0x00000400UL:
232 size = 0x0;
233 break;
234 case 0x00001000UL:
235 size = 0x1;
236 break;
237 case 0x00004000UL:
238 size = 0x2;
239 break;
240 case 0x00010000UL:
241 size = 0x3;
242 break;
243 case 0x00040000UL:
244 size = 0x4;
245 break;
246 case 0x00100000UL:
247 size = 0x5;
248 break;
249 case 0x00400000UL:
250 size = 0x6;
251 break;
252 case 0x01000000UL:
253 size = 0x7;
254 break;
255 case 0x04000000UL:
256 size = 0x8;
257 break;
258 case 0x10000000UL:
259 size = 0x9;
260 break;
261 case 0x40000000UL:
262 size = 0xA;
263 break;
264 #if defined(TARGET_PPC64)
265 case 0x000100000000ULL:
266 size = 0xB;
267 break;
268 case 0x000400000000ULL:
269 size = 0xC;
270 break;
271 case 0x001000000000ULL:
272 size = 0xD;
273 break;
274 case 0x004000000000ULL:
275 size = 0xE;
276 break;
277 case 0x010000000000ULL:
278 size = 0xF;
279 break;
280 #endif
281 default:
282 size = -1;
283 break;
286 return size;
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)
307 ppcemb_tlb_t *tlb;
308 target_ulong ret;
309 int size;
311 entry &= PPC4XX_TLB_ENTRY_MASK;
312 tlb = &env->tlb.tlbe[entry];
313 ret = tlb->EPN;
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;
323 return ret;
326 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
328 ppcemb_tlb_t *tlb;
329 target_ulong ret;
331 entry &= PPC4XX_TLB_ENTRY_MASK;
332 tlb = &env->tlb.tlbe[entry];
333 ret = tlb->RPN;
334 if (tlb->prot & PAGE_EXEC) {
335 ret |= PPC4XX_TLBLO_EX;
337 if (tlb->prot & PAGE_WRITE) {
338 ret |= PPC4XX_TLBLO_WR;
340 return ret;
343 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
344 target_ulong val)
346 ppcemb_tlb_t *tlb;
347 target_ulong page, end;
349 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
350 val);
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 */
378 cpu_abort(env,
379 "Little-endian TLB entries are not supported by now\n");
381 } else {
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,
404 target_ulong val)
406 ppcemb_tlb_t *tlb;
408 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
409 val);
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,
437 target_ulong value)
439 ppcemb_tlb_t *tlb;
440 target_ulong EPN, RPN, size;
441 int do_flush_tlbs;
443 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
444 __func__, word, (int)entry, value);
445 do_flush_tlbs = 0;
446 entry &= 0x3F;
447 tlb = &env->tlb.tlbe[entry];
448 switch (word) {
449 default:
450 /* Just here to please gcc */
451 case 0:
452 EPN = value & 0xFFFFFC00;
453 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
454 do_flush_tlbs = 1;
456 tlb->EPN = EPN;
457 size = booke_tlb_to_page_size((value >> 4) & 0xF);
458 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
459 do_flush_tlbs = 1;
461 tlb->size = size;
462 tlb->attr &= ~0x1;
463 tlb->attr |= (value >> 8) & 1;
464 if (value & 0x200) {
465 tlb->prot |= PAGE_VALID;
466 } else {
467 if (tlb->prot & PAGE_VALID) {
468 tlb->prot &= ~PAGE_VALID;
469 do_flush_tlbs = 1;
472 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
473 if (do_flush_tlbs) {
474 tlb_flush(env, 1);
476 break;
477 case 1:
478 RPN = value & 0xFFFFFC0F;
479 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
480 tlb_flush(env, 1);
482 tlb->RPN = RPN;
483 break;
484 case 2:
485 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
486 tlb->prot = tlb->prot & PAGE_VALID;
487 if (value & 0x1) {
488 tlb->prot |= PAGE_READ << 4;
490 if (value & 0x2) {
491 tlb->prot |= PAGE_WRITE << 4;
493 if (value & 0x4) {
494 tlb->prot |= PAGE_EXEC << 4;
496 if (value & 0x8) {
497 tlb->prot |= PAGE_READ;
499 if (value & 0x10) {
500 tlb->prot |= PAGE_WRITE;
502 if (value & 0x20) {
503 tlb->prot |= PAGE_EXEC;
505 break;
509 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
510 target_ulong entry)
512 ppcemb_tlb_t *tlb;
513 target_ulong ret;
514 int size;
516 entry &= 0x3F;
517 tlb = &env->tlb.tlbe[entry];
518 switch (word) {
519 default:
520 /* Just here to please gcc */
521 case 0:
522 ret = tlb->EPN;
523 size = booke_page_size_to_tlb(tlb->size);
524 if (size < 0 || size > 0xF) {
525 size = 1;
527 ret |= size << 4;
528 if (tlb->attr & 0x1) {
529 ret |= 0x100;
531 if (tlb->prot & PAGE_VALID) {
532 ret |= 0x200;
534 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
535 env->spr[SPR_440_MMUCR] |= tlb->PID;
536 break;
537 case 1:
538 ret = tlb->RPN;
539 break;
540 case 2:
541 ret = tlb->attr & ~0x1;
542 if (tlb->prot & (PAGE_READ << 4)) {
543 ret |= 0x1;
545 if (tlb->prot & (PAGE_WRITE << 4)) {
546 ret |= 0x2;
548 if (tlb->prot & (PAGE_EXEC << 4)) {
549 ret |= 0x4;
551 if (tlb->prot & PAGE_READ) {
552 ret |= 0x8;
554 if (tlb->prot & PAGE_WRITE) {
555 ret |= 0x10;
557 if (tlb->prot & PAGE_EXEC) {
558 ret |= 0x20;
560 break;
562 return ret;
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);
577 int tlb;
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 */
593 tlb_flush(env, 1);
596 void helper_booke206_tlbwe(CPUPPCState *env)
598 uint32_t tlbncfg, tlbn;
599 ppcmas_tlb_t *tlb;
600 uint32_t size_tlb, size_ps;
602 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
603 case MAS0_WQ_ALWAYS:
604 /* good to go, write that entry */
605 break;
606 case MAS0_WQ_COND:
607 /* XXX check if reserved */
608 if (0) {
609 return;
611 break;
612 case MAS0_WQ_CLR_RSRV:
613 /* XXX clear entry */
614 return;
615 default:
616 /* no idea what to do */
617 return;
620 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
621 !msr_gs) {
622 /* XXX we don't support direct LRAT setting yet */
623 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
624 return;
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);
632 if (!tlb) {
633 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
634 POWERPC_EXCP_INVAL |
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,
644 POWERPC_EXCP_INVAL |
645 POWERPC_EXCP_INVAL_INVAL);
648 if (msr_gs) {
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];
655 /* MAV 1.0 only */
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);
673 } else {
674 tlb_flush(env, 1);
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);
698 if (!tlb) {
699 env->spr[SPR_BOOKE_MAS1] = 0;
700 } else {
701 booke206_tlb_to_mas(env, tlb);
705 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
707 ppcmas_tlb_t *tlb = NULL;
708 int i, j;
709 target_phys_addr_t raddr;
710 uint32_t spid, sas;
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);
721 if (!tlb) {
722 continue;
725 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
726 continue;
729 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
730 continue;
733 booke206_tlb_to_mas(env, tlb);
734 return;
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)
750 << MAS1_TID_SHIFT;
752 /* next victim logic */
753 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
754 env->last_way++;
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,
760 uint32_t ea)
762 int i;
763 int ways = booke206_tlb_ways(env, tlbn);
764 target_ulong mask;
766 for (i = 0; i < ways; i++) {
767 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
768 if (!tlb) {
769 continue;
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)
781 if (address & 0x4) {
782 /* flush all entries */
783 if (address & 0x8) {
784 /* flush all of TLB1 */
785 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
786 } else {
787 /* flush all of TLB0 */
788 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
790 return;
793 if (address & 0x8) {
794 /* flush TLB1 entries */
795 booke206_invalidate_ea_tlb(env, 1, address);
796 tlb_flush(env, 1);
797 } else {
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)
812 int i, j;
813 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
814 ppcmas_tlb_t *tlb = env->tlb.tlbm;
815 int tlb_size;
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);
828 tlb_flush(env, 1);
831 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
833 int i, j;
834 ppcmas_tlb_t *tlb;
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 */
842 bool mav2 = false;
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);
851 if (!tlb) {
852 continue;
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)) {
858 continue;
860 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
861 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
862 continue;
864 /* XXX e500mc doesn't match SAS, but other cores might */
865 tlb->mas1 &= ~MAS1_VALID;
868 tlb_flush(env, 1);
871 void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
873 int flags = 0;
875 if (type & 2) {
876 flags |= BOOKE206_FLUSH_TLB1;
879 if (type & 4) {
880 flags |= BOOKE206_FLUSH_TLB0;
883 booke206_flush_tlb(env, flags, 1);
885 #endif