]> git.proxmox.com Git - qemu.git/blob - target-ppc/mmu_helper.c
target-ppc: Trivial cleanups in mmu_helper.c
[qemu.git] / target-ppc / mmu_helper.c
1 /*
2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 *
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.
10 *
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.
15 *
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/>.
18 */
19 #include "cpu.h"
20 #include "helper.h"
21 #include "sysemu/kvm.h"
22 #include "kvm_ppc.h"
23
24 //#define DEBUG_MMU
25 //#define DEBUG_BATS
26 //#define DEBUG_SLB
27 //#define DEBUG_SOFTWARE_TLB
28 //#define DUMP_PAGE_TABLES
29 //#define DEBUG_SOFTWARE_TLB
30 //#define FLUSH_ALL_TLBS
31
32 #ifdef DEBUG_MMU
33 # define LOG_MMU(...) qemu_log(__VA_ARGS__)
34 # define LOG_MMU_STATE(env) log_cpu_state((env), 0)
35 #else
36 # define LOG_MMU(...) do { } while (0)
37 # define LOG_MMU_STATE(...) do { } while (0)
38 #endif
39
40 #ifdef DEBUG_SOFTWARE_TLB
41 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
42 #else
43 # define LOG_SWTLB(...) do { } while (0)
44 #endif
45
46 #ifdef DEBUG_BATS
47 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
48 #else
49 # define LOG_BATS(...) do { } while (0)
50 #endif
51
52 #ifdef DEBUG_SLB
53 # define LOG_SLB(...) qemu_log(__VA_ARGS__)
54 #else
55 # define LOG_SLB(...) do { } while (0)
56 #endif
57
58 /*****************************************************************************/
59 /* PowerPC MMU emulation */
60 #if defined(CONFIG_USER_ONLY)
61 int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
62 int mmu_idx)
63 {
64 int exception, error_code;
65
66 if (rw == 2) {
67 exception = POWERPC_EXCP_ISI;
68 error_code = 0x40000000;
69 } else {
70 exception = POWERPC_EXCP_DSI;
71 error_code = 0x40000000;
72 if (rw) {
73 error_code |= 0x02000000;
74 }
75 env->spr[SPR_DAR] = address;
76 env->spr[SPR_DSISR] = error_code;
77 }
78 env->exception_index = exception;
79 env->error_code = error_code;
80
81 return 1;
82 }
83
84 #else
85 /* Common routines used by software and hardware TLBs emulation */
86 static inline int pte_is_valid(target_ulong pte0)
87 {
88 return pte0 & 0x80000000 ? 1 : 0;
89 }
90
91 static inline void pte_invalidate(target_ulong *pte0)
92 {
93 *pte0 &= ~0x80000000;
94 }
95
96 #if defined(TARGET_PPC64)
97 static inline int pte64_is_valid(target_ulong pte0)
98 {
99 return pte0 & 0x0000000000000001ULL ? 1 : 0;
100 }
101 #endif
102
103 #define PTE_PTEM_MASK 0x7FFFFFBF
104 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
105 #if defined(TARGET_PPC64)
106 #define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
107 #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
108 #endif
109
110 static inline int pp_check(int key, int pp, int nx)
111 {
112 int access;
113
114 /* Compute access rights */
115 /* When pp is 3/7, the result is undefined. Set it to noaccess */
116 access = 0;
117 if (key == 0) {
118 switch (pp) {
119 case 0x0:
120 case 0x1:
121 case 0x2:
122 access |= PAGE_WRITE;
123 /* No break here */
124 case 0x3:
125 case 0x6:
126 access |= PAGE_READ;
127 break;
128 }
129 } else {
130 switch (pp) {
131 case 0x0:
132 case 0x6:
133 access = 0;
134 break;
135 case 0x1:
136 case 0x3:
137 access = PAGE_READ;
138 break;
139 case 0x2:
140 access = PAGE_READ | PAGE_WRITE;
141 break;
142 }
143 }
144 if (nx == 0) {
145 access |= PAGE_EXEC;
146 }
147
148 return access;
149 }
150
151 static inline int check_prot(int prot, int rw, int access_type)
152 {
153 int ret;
154
155 if (access_type == ACCESS_CODE) {
156 if (prot & PAGE_EXEC) {
157 ret = 0;
158 } else {
159 ret = -2;
160 }
161 } else if (rw) {
162 if (prot & PAGE_WRITE) {
163 ret = 0;
164 } else {
165 ret = -2;
166 }
167 } else {
168 if (prot & PAGE_READ) {
169 ret = 0;
170 } else {
171 ret = -2;
172 }
173 }
174
175 return ret;
176 }
177
178 static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
179 target_ulong pte1, int h, int rw, int type)
180 {
181 target_ulong ptem, mmask;
182 int access, ret, pteh, ptev, pp;
183
184 ret = -1;
185 /* Check validity and table match */
186 #if defined(TARGET_PPC64)
187 if (is_64b) {
188 ptev = pte64_is_valid(pte0);
189 pteh = (pte0 >> 1) & 1;
190 } else
191 #endif
192 {
193 ptev = pte_is_valid(pte0);
194 pteh = (pte0 >> 6) & 1;
195 }
196 if (ptev && h == pteh) {
197 /* Check vsid & api */
198 #if defined(TARGET_PPC64)
199 if (is_64b) {
200 ptem = pte0 & PTE64_PTEM_MASK;
201 mmask = PTE64_CHECK_MASK;
202 pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
203 ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
204 ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
205 } else
206 #endif
207 {
208 ptem = pte0 & PTE_PTEM_MASK;
209 mmask = PTE_CHECK_MASK;
210 pp = pte1 & 0x00000003;
211 }
212 if (ptem == ctx->ptem) {
213 if (ctx->raddr != (hwaddr)-1ULL) {
214 /* all matches should have equal RPN, WIMG & PP */
215 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
216 qemu_log("Bad RPN/WIMG/PP\n");
217 return -3;
218 }
219 }
220 /* Compute access rights */
221 access = pp_check(ctx->key, pp, ctx->nx);
222 /* Keep the matching PTE informations */
223 ctx->raddr = pte1;
224 ctx->prot = access;
225 ret = check_prot(ctx->prot, rw, type);
226 if (ret == 0) {
227 /* Access granted */
228 LOG_MMU("PTE access granted !\n");
229 } else {
230 /* Access right violation */
231 LOG_MMU("PTE access rejected\n");
232 }
233 }
234 }
235
236 return ret;
237 }
238
239 static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
240 target_ulong pte1, int h, int rw, int type)
241 {
242 return pte_check(ctx, 0, pte0, pte1, h, rw, type);
243 }
244
245 #if defined(TARGET_PPC64)
246 static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
247 target_ulong pte1, int h, int rw, int type)
248 {
249 return pte_check(ctx, 1, pte0, pte1, h, rw, type);
250 }
251 #endif
252
253 static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
254 int ret, int rw)
255 {
256 int store = 0;
257
258 /* Update page flags */
259 if (!(*pte1p & 0x00000100)) {
260 /* Update accessed flag */
261 *pte1p |= 0x00000100;
262 store = 1;
263 }
264 if (!(*pte1p & 0x00000080)) {
265 if (rw == 1 && ret == 0) {
266 /* Update changed flag */
267 *pte1p |= 0x00000080;
268 store = 1;
269 } else {
270 /* Force page fault for first write access */
271 ctx->prot &= ~PAGE_WRITE;
272 }
273 }
274
275 return store;
276 }
277
278 /* Software driven TLB helpers */
279 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
280 int way, int is_code)
281 {
282 int nr;
283
284 /* Select TLB num in a way from address */
285 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
286 /* Select TLB way */
287 nr += env->tlb_per_way * way;
288 /* 6xx have separate TLBs for instructions and data */
289 if (is_code && env->id_tlbs == 1) {
290 nr += env->nb_tlb;
291 }
292
293 return nr;
294 }
295
296 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
297 {
298 ppc6xx_tlb_t *tlb;
299 int nr, max;
300
301 /* LOG_SWTLB("Invalidate all TLBs\n"); */
302 /* Invalidate all defined software TLB */
303 max = env->nb_tlb;
304 if (env->id_tlbs == 1) {
305 max *= 2;
306 }
307 for (nr = 0; nr < max; nr++) {
308 tlb = &env->tlb.tlb6[nr];
309 pte_invalidate(&tlb->pte0);
310 }
311 tlb_flush(env, 1);
312 }
313
314 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
315 target_ulong eaddr,
316 int is_code, int match_epn)
317 {
318 #if !defined(FLUSH_ALL_TLBS)
319 ppc6xx_tlb_t *tlb;
320 int way, nr;
321
322 /* Invalidate ITLB + DTLB, all ways */
323 for (way = 0; way < env->nb_ways; way++) {
324 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
325 tlb = &env->tlb.tlb6[nr];
326 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
327 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
328 env->nb_tlb, eaddr);
329 pte_invalidate(&tlb->pte0);
330 tlb_flush_page(env, tlb->EPN);
331 }
332 }
333 #else
334 /* XXX: PowerPC specification say this is valid as well */
335 ppc6xx_tlb_invalidate_all(env);
336 #endif
337 }
338
339 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
340 target_ulong eaddr, int is_code)
341 {
342 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
343 }
344
345 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
346 int is_code, target_ulong pte0, target_ulong pte1)
347 {
348 ppc6xx_tlb_t *tlb;
349 int nr;
350
351 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
352 tlb = &env->tlb.tlb6[nr];
353 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
354 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
355 /* Invalidate any pending reference in QEMU for this virtual address */
356 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
357 tlb->pte0 = pte0;
358 tlb->pte1 = pte1;
359 tlb->EPN = EPN;
360 /* Store last way for LRU mechanism */
361 env->last_way = way;
362 }
363
364 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
365 target_ulong eaddr, int rw, int access_type)
366 {
367 ppc6xx_tlb_t *tlb;
368 int nr, best, way;
369 int ret;
370
371 best = -1;
372 ret = -1; /* No TLB found */
373 for (way = 0; way < env->nb_ways; way++) {
374 nr = ppc6xx_tlb_getnum(env, eaddr, way,
375 access_type == ACCESS_CODE ? 1 : 0);
376 tlb = &env->tlb.tlb6[nr];
377 /* This test "emulates" the PTE index match for hardware TLBs */
378 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
379 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
380 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
381 pte_is_valid(tlb->pte0) ? "valid" : "inval",
382 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
383 continue;
384 }
385 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
386 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
387 pte_is_valid(tlb->pte0) ? "valid" : "inval",
388 tlb->EPN, eaddr, tlb->pte1,
389 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
390 switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
391 case -3:
392 /* TLB inconsistency */
393 return -1;
394 case -2:
395 /* Access violation */
396 ret = -2;
397 best = nr;
398 break;
399 case -1:
400 default:
401 /* No match */
402 break;
403 case 0:
404 /* access granted */
405 /* XXX: we should go on looping to check all TLBs consistency
406 * but we can speed-up the whole thing as the
407 * result would be undefined if TLBs are not consistent.
408 */
409 ret = 0;
410 best = nr;
411 goto done;
412 }
413 }
414 if (best != -1) {
415 done:
416 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
417 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
418 /* Update page flags */
419 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
420 }
421
422 return ret;
423 }
424
425 /* Perform BAT hit & translation */
426 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
427 int *validp, int *protp, target_ulong *BATu,
428 target_ulong *BATl)
429 {
430 target_ulong bl;
431 int pp, valid, prot;
432
433 bl = (*BATu & 0x00001FFC) << 15;
434 valid = 0;
435 prot = 0;
436 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
437 ((msr_pr != 0) && (*BATu & 0x00000001))) {
438 valid = 1;
439 pp = *BATl & 0x00000003;
440 if (pp != 0) {
441 prot = PAGE_READ | PAGE_EXEC;
442 if (pp == 0x2) {
443 prot |= PAGE_WRITE;
444 }
445 }
446 }
447 *blp = bl;
448 *validp = valid;
449 *protp = prot;
450 }
451
452 static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
453 int *validp, int *protp,
454 target_ulong *BATu, target_ulong *BATl)
455 {
456 target_ulong bl;
457 int key, pp, valid, prot;
458
459 bl = (*BATl & 0x0000003F) << 17;
460 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
461 (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
462 prot = 0;
463 valid = (*BATl >> 6) & 1;
464 if (valid) {
465 pp = *BATu & 0x00000003;
466 if (msr_pr == 0) {
467 key = (*BATu >> 3) & 1;
468 } else {
469 key = (*BATu >> 2) & 1;
470 }
471 prot = pp_check(key, pp, 0);
472 }
473 *blp = bl;
474 *validp = valid;
475 *protp = prot;
476 }
477
478 static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
479 target_ulong virtual, int rw, int type)
480 {
481 target_ulong *BATlt, *BATut, *BATu, *BATl;
482 target_ulong BEPIl, BEPIu, bl;
483 int i, valid, prot;
484 int ret = -1;
485
486 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
487 type == ACCESS_CODE ? 'I' : 'D', virtual);
488 switch (type) {
489 case ACCESS_CODE:
490 BATlt = env->IBAT[1];
491 BATut = env->IBAT[0];
492 break;
493 default:
494 BATlt = env->DBAT[1];
495 BATut = env->DBAT[0];
496 break;
497 }
498 for (i = 0; i < env->nb_BATs; i++) {
499 BATu = &BATut[i];
500 BATl = &BATlt[i];
501 BEPIu = *BATu & 0xF0000000;
502 BEPIl = *BATu & 0x0FFE0000;
503 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
504 bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
505 } else {
506 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
507 }
508 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
509 " BATl " TARGET_FMT_lx "\n", __func__,
510 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
511 if ((virtual & 0xF0000000) == BEPIu &&
512 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
513 /* BAT matches */
514 if (valid != 0) {
515 /* Get physical address */
516 ctx->raddr = (*BATl & 0xF0000000) |
517 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
518 (virtual & 0x0001F000);
519 /* Compute access rights */
520 ctx->prot = prot;
521 ret = check_prot(ctx->prot, rw, type);
522 if (ret == 0) {
523 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
524 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
525 ctx->prot & PAGE_WRITE ? 'W' : '-');
526 }
527 break;
528 }
529 }
530 }
531 if (ret < 0) {
532 #if defined(DEBUG_BATS)
533 if (qemu_log_enabled()) {
534 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
535 for (i = 0; i < 4; i++) {
536 BATu = &BATut[i];
537 BATl = &BATlt[i];
538 BEPIu = *BATu & 0xF0000000;
539 BEPIl = *BATu & 0x0FFE0000;
540 bl = (*BATu & 0x00001FFC) << 15;
541 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
542 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
543 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
544 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
545 *BATu, *BATl, BEPIu, BEPIl, bl);
546 }
547 }
548 #endif
549 }
550 /* No hit */
551 return ret;
552 }
553
554 static inline hwaddr get_pteg_offset(CPUPPCState *env,
555 hwaddr hash,
556 int pte_size)
557 {
558 return (hash * pte_size * 8) & env->htab_mask;
559 }
560
561 /* PTE table lookup */
562 static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
563 int rw, int type, int target_page_bits)
564 {
565 hwaddr pteg_off;
566 target_ulong pte0, pte1;
567 int i, good = -1;
568 int ret, r;
569
570 ret = -1; /* No entry found */
571 pteg_off = get_pteg_offset(env, ctx->hash[h],
572 is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
573 for (i = 0; i < 8; i++) {
574 #if defined(TARGET_PPC64)
575 if (is_64b) {
576 if (env->external_htab) {
577 pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
578 pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
579 } else {
580 pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
581 pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
582 }
583
584 r = pte64_check(ctx, pte0, pte1, h, rw, type);
585 LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " "
586 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
587 pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
588 (int)((pte0 >> 1) & 1), ctx->ptem);
589 } else
590 #endif
591 {
592 if (env->external_htab) {
593 pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
594 pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
595 } else {
596 pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
597 pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
598 }
599 r = pte32_check(ctx, pte0, pte1, h, rw, type);
600 LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
601 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
602 pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
603 (int)((pte0 >> 6) & 1), ctx->ptem);
604 }
605 switch (r) {
606 case -3:
607 /* PTE inconsistency */
608 return -1;
609 case -2:
610 /* Access violation */
611 ret = -2;
612 good = i;
613 break;
614 case -1:
615 default:
616 /* No PTE match */
617 break;
618 case 0:
619 /* access granted */
620 /* XXX: we should go on looping to check all PTEs consistency
621 * but if we can speed-up the whole thing as the
622 * result would be undefined if PTEs are not consistent.
623 */
624 ret = 0;
625 good = i;
626 goto done;
627 }
628 }
629 if (good != -1) {
630 done:
631 LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
632 ctx->raddr, ctx->prot, ret);
633 /* Update page flags */
634 pte1 = ctx->raddr;
635 if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
636 #if defined(TARGET_PPC64)
637 if (is_64b) {
638 if (env->external_htab) {
639 stq_p(env->external_htab + pteg_off + (good * 16) + 8,
640 pte1);
641 } else {
642 stq_phys_notdirty(env->htab_base + pteg_off +
643 (good * 16) + 8, pte1);
644 }
645 } else
646 #endif
647 {
648 if (env->external_htab) {
649 stl_p(env->external_htab + pteg_off + (good * 8) + 4,
650 pte1);
651 } else {
652 stl_phys_notdirty(env->htab_base + pteg_off +
653 (good * 8) + 4, pte1);
654 }
655 }
656 }
657 }
658
659 /* We have a TLB that saves 4K pages, so let's
660 * split a huge page to 4k chunks */
661 if (target_page_bits != TARGET_PAGE_BITS) {
662 ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
663 & TARGET_PAGE_MASK;
664 }
665 return ret;
666 }
667
668 static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
669 int type, int target_page_bits)
670 {
671 #if defined(TARGET_PPC64)
672 if (env->mmu_model & POWERPC_MMU_64) {
673 return find_pte2(env, ctx, 1, h, rw, type, target_page_bits);
674 }
675 #endif
676
677 return find_pte2(env, ctx, 0, h, rw, type, target_page_bits);
678 }
679
680 #if defined(TARGET_PPC64)
681 static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
682 {
683 uint64_t esid_256M, esid_1T;
684 int n;
685
686 LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
687
688 esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
689 esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
690
691 for (n = 0; n < env->slb_nr; n++) {
692 ppc_slb_t *slb = &env->slb[n];
693
694 LOG_SLB("%s: slot %d %016" PRIx64 " %016"
695 PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
696 /* We check for 1T matches on all MMUs here - if the MMU
697 * doesn't have 1T segment support, we will have prevented 1T
698 * entries from being inserted in the slbmte code. */
699 if (((slb->esid == esid_256M) &&
700 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
701 || ((slb->esid == esid_1T) &&
702 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
703 return slb;
704 }
705 }
706
707 return NULL;
708 }
709
710 /*****************************************************************************/
711 /* SPR accesses */
712
713 void helper_slbia(CPUPPCState *env)
714 {
715 int n, do_invalidate;
716
717 do_invalidate = 0;
718 /* XXX: Warning: slbia never invalidates the first segment */
719 for (n = 1; n < env->slb_nr; n++) {
720 ppc_slb_t *slb = &env->slb[n];
721
722 if (slb->esid & SLB_ESID_V) {
723 slb->esid &= ~SLB_ESID_V;
724 /* XXX: given the fact that segment size is 256 MB or 1TB,
725 * and we still don't have a tlb_flush_mask(env, n, mask)
726 * in QEMU, we just invalidate all TLBs
727 */
728 do_invalidate = 1;
729 }
730 }
731 if (do_invalidate) {
732 tlb_flush(env, 1);
733 }
734 }
735
736 void helper_slbie(CPUPPCState *env, target_ulong addr)
737 {
738 ppc_slb_t *slb;
739
740 slb = slb_lookup(env, addr);
741 if (!slb) {
742 return;
743 }
744
745 if (slb->esid & SLB_ESID_V) {
746 slb->esid &= ~SLB_ESID_V;
747
748 /* XXX: given the fact that segment size is 256 MB or 1TB,
749 * and we still don't have a tlb_flush_mask(env, n, mask)
750 * in QEMU, we just invalidate all TLBs
751 */
752 tlb_flush(env, 1);
753 }
754 }
755
756 int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
757 {
758 int slot = rb & 0xfff;
759 ppc_slb_t *slb = &env->slb[slot];
760
761 if (rb & (0x1000 - env->slb_nr)) {
762 return -1; /* Reserved bits set or slot too high */
763 }
764 if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
765 return -1; /* Bad segment size */
766 }
767 if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
768 return -1; /* 1T segment on MMU that doesn't support it */
769 }
770
771 /* Mask out the slot number as we store the entry */
772 slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
773 slb->vsid = rs;
774
775 LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
776 " %016" PRIx64 "\n", __func__, slot, rb, rs,
777 slb->esid, slb->vsid);
778
779 return 0;
780 }
781
782 static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb,
783 target_ulong *rt)
784 {
785 int slot = rb & 0xfff;
786 ppc_slb_t *slb = &env->slb[slot];
787
788 if (slot >= env->slb_nr) {
789 return -1;
790 }
791
792 *rt = slb->esid;
793 return 0;
794 }
795
796 static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,
797 target_ulong *rt)
798 {
799 int slot = rb & 0xfff;
800 ppc_slb_t *slb = &env->slb[slot];
801
802 if (slot >= env->slb_nr) {
803 return -1;
804 }
805
806 *rt = slb->vsid;
807 return 0;
808 }
809 #endif /* defined(TARGET_PPC64) */
810
811 /* Perform segment based translation */
812 static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
813 target_ulong eaddr, int rw, int type)
814 {
815 hwaddr hash;
816 target_ulong vsid;
817 int ds, pr, target_page_bits;
818 int ret, ret2;
819
820 pr = msr_pr;
821 ctx->eaddr = eaddr;
822 #if defined(TARGET_PPC64)
823 if (env->mmu_model & POWERPC_MMU_64) {
824 ppc_slb_t *slb;
825 target_ulong pageaddr;
826 int segment_bits;
827
828 LOG_MMU("Check SLBs\n");
829 slb = slb_lookup(env, eaddr);
830 if (!slb) {
831 return -5;
832 }
833
834 if (slb->vsid & SLB_VSID_B) {
835 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
836 segment_bits = 40;
837 } else {
838 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
839 segment_bits = 28;
840 }
841
842 target_page_bits = (slb->vsid & SLB_VSID_L)
843 ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
844 ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
845 : (slb->vsid & SLB_VSID_KS));
846 ds = 0;
847 ctx->nx = !!(slb->vsid & SLB_VSID_N);
848
849 pageaddr = eaddr & ((1ULL << segment_bits)
850 - (1ULL << target_page_bits));
851 if (slb->vsid & SLB_VSID_B) {
852 hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
853 } else {
854 hash = vsid ^ (pageaddr >> target_page_bits);
855 }
856 /* Only 5 bits of the page index are used in the AVPN */
857 ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
858 ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
859 } else
860 #endif /* defined(TARGET_PPC64) */
861 {
862 target_ulong sr, pgidx;
863
864 sr = env->sr[eaddr >> 28];
865 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
866 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
867 ds = sr & 0x80000000 ? 1 : 0;
868 ctx->nx = sr & 0x10000000 ? 1 : 0;
869 vsid = sr & 0x00FFFFFF;
870 target_page_bits = TARGET_PAGE_BITS;
871 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
872 TARGET_FMT_lx " lr=" TARGET_FMT_lx
873 " ir=%d dr=%d pr=%d %d t=%d\n",
874 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
875 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
876 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
877 hash = vsid ^ pgidx;
878 ctx->ptem = (vsid << 7) | (pgidx >> 10);
879 }
880 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
881 ctx->key, ds, ctx->nx, vsid);
882 ret = -1;
883 if (!ds) {
884 /* Check if instruction fetch is allowed, if needed */
885 if (type != ACCESS_CODE || ctx->nx == 0) {
886 /* Page address translation */
887 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
888 " hash " TARGET_FMT_plx "\n",
889 env->htab_base, env->htab_mask, hash);
890 ctx->hash[0] = hash;
891 ctx->hash[1] = ~hash;
892
893 /* Initialize real address with an invalid value */
894 ctx->raddr = (hwaddr)-1ULL;
895 if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
896 env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
897 /* Software TLB search */
898 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
899 } else {
900 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
901 " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
902 " hash=" TARGET_FMT_plx "\n",
903 env->htab_base, env->htab_mask, vsid, ctx->ptem,
904 ctx->hash[0]);
905 /* Primary table lookup */
906 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
907 if (ret < 0) {
908 /* Secondary table lookup */
909 if (eaddr != 0xEFFFFFFF) {
910 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
911 " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
912 " hash=" TARGET_FMT_plx "\n", env->htab_base,
913 env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
914 }
915 ret2 = find_pte(env, ctx, 1, rw, type,
916 target_page_bits);
917 if (ret2 != -1) {
918 ret = ret2;
919 }
920 }
921 }
922 #if defined(DUMP_PAGE_TABLES)
923 if (qemu_log_enabled()) {
924 hwaddr curaddr;
925 uint32_t a0, a1, a2, a3;
926
927 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
928 "\n", sdr, mask + 0x80);
929 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
930 curaddr += 16) {
931 a0 = ldl_phys(curaddr);
932 a1 = ldl_phys(curaddr + 4);
933 a2 = ldl_phys(curaddr + 8);
934 a3 = ldl_phys(curaddr + 12);
935 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
936 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
937 curaddr, a0, a1, a2, a3);
938 }
939 }
940 }
941 #endif
942 } else {
943 LOG_MMU("No access allowed\n");
944 ret = -3;
945 }
946 } else {
947 target_ulong sr;
948
949 LOG_MMU("direct store...\n");
950 /* Direct-store segment : absolutely *BUGGY* for now */
951
952 /* Direct-store implies a 32-bit MMU.
953 * Check the Segment Register's bus unit ID (BUID).
954 */
955 sr = env->sr[eaddr >> 28];
956 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
957 /* Memory-forced I/O controller interface access */
958 /* If T=1 and BUID=x'07F', the 601 performs a memory access
959 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
960 */
961 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
962 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
963 return 0;
964 }
965
966 switch (type) {
967 case ACCESS_INT:
968 /* Integer load/store : only access allowed */
969 break;
970 case ACCESS_CODE:
971 /* No code fetch is allowed in direct-store areas */
972 return -4;
973 case ACCESS_FLOAT:
974 /* Floating point load/store */
975 return -4;
976 case ACCESS_RES:
977 /* lwarx, ldarx or srwcx. */
978 return -4;
979 case ACCESS_CACHE:
980 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
981 /* Should make the instruction do no-op.
982 * As it already do no-op, it's quite easy :-)
983 */
984 ctx->raddr = eaddr;
985 return 0;
986 case ACCESS_EXT:
987 /* eciwx or ecowx */
988 return -4;
989 default:
990 qemu_log("ERROR: instruction should not need "
991 "address translation\n");
992 return -4;
993 }
994 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
995 ctx->raddr = eaddr;
996 ret = 2;
997 } else {
998 ret = -2;
999 }
1000 }
1001
1002 return ret;
1003 }
1004
1005 /* Generic TLB check function for embedded PowerPC implementations */
1006 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
1007 hwaddr *raddrp,
1008 target_ulong address, uint32_t pid, int ext,
1009 int i)
1010 {
1011 target_ulong mask;
1012
1013 /* Check valid flag */
1014 if (!(tlb->prot & PAGE_VALID)) {
1015 return -1;
1016 }
1017 mask = ~(tlb->size - 1);
1018 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
1019 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
1020 mask, (uint32_t)tlb->PID, tlb->prot);
1021 /* Check PID */
1022 if (tlb->PID != 0 && tlb->PID != pid) {
1023 return -1;
1024 }
1025 /* Check effective address */
1026 if ((address & mask) != tlb->EPN) {
1027 return -1;
1028 }
1029 *raddrp = (tlb->RPN & mask) | (address & ~mask);
1030 if (ext) {
1031 /* Extend the physical address to 36 bits */
1032 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
1033 }
1034
1035 return 0;
1036 }
1037
1038 /* Generic TLB search function for PowerPC embedded implementations */
1039 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
1040 uint32_t pid)
1041 {
1042 ppcemb_tlb_t *tlb;
1043 hwaddr raddr;
1044 int i, ret;
1045
1046 /* Default return value is no match */
1047 ret = -1;
1048 for (i = 0; i < env->nb_tlb; i++) {
1049 tlb = &env->tlb.tlbe[i];
1050 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
1051 ret = i;
1052 break;
1053 }
1054 }
1055
1056 return ret;
1057 }
1058
1059 /* Helpers specific to PowerPC 40x implementations */
1060 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
1061 {
1062 ppcemb_tlb_t *tlb;
1063 int i;
1064
1065 for (i = 0; i < env->nb_tlb; i++) {
1066 tlb = &env->tlb.tlbe[i];
1067 tlb->prot &= ~PAGE_VALID;
1068 }
1069 tlb_flush(env, 1);
1070 }
1071
1072 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
1073 target_ulong eaddr, uint32_t pid)
1074 {
1075 #if !defined(FLUSH_ALL_TLBS)
1076 ppcemb_tlb_t *tlb;
1077 hwaddr raddr;
1078 target_ulong page, end;
1079 int i;
1080
1081 for (i = 0; i < env->nb_tlb; i++) {
1082 tlb = &env->tlb.tlbe[i];
1083 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
1084 end = tlb->EPN + tlb->size;
1085 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
1086 tlb_flush_page(env, page);
1087 }
1088 tlb->prot &= ~PAGE_VALID;
1089 break;
1090 }
1091 }
1092 #else
1093 ppc4xx_tlb_invalidate_all(env);
1094 #endif
1095 }
1096
1097 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1098 target_ulong address, int rw,
1099 int access_type)
1100 {
1101 ppcemb_tlb_t *tlb;
1102 hwaddr raddr;
1103 int i, ret, zsel, zpr, pr;
1104
1105 ret = -1;
1106 raddr = (hwaddr)-1ULL;
1107 pr = msr_pr;
1108 for (i = 0; i < env->nb_tlb; i++) {
1109 tlb = &env->tlb.tlbe[i];
1110 if (ppcemb_tlb_check(env, tlb, &raddr, address,
1111 env->spr[SPR_40x_PID], 0, i) < 0) {
1112 continue;
1113 }
1114 zsel = (tlb->attr >> 4) & 0xF;
1115 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
1116 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
1117 __func__, i, zsel, zpr, rw, tlb->attr);
1118 /* Check execute enable bit */
1119 switch (zpr) {
1120 case 0x2:
1121 if (pr != 0) {
1122 goto check_perms;
1123 }
1124 /* No break here */
1125 case 0x3:
1126 /* All accesses granted */
1127 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1128 ret = 0;
1129 break;
1130 case 0x0:
1131 if (pr != 0) {
1132 /* Raise Zone protection fault. */
1133 env->spr[SPR_40x_ESR] = 1 << 22;
1134 ctx->prot = 0;
1135 ret = -2;
1136 break;
1137 }
1138 /* No break here */
1139 case 0x1:
1140 check_perms:
1141 /* Check from TLB entry */
1142 ctx->prot = tlb->prot;
1143 ret = check_prot(ctx->prot, rw, access_type);
1144 if (ret == -2) {
1145 env->spr[SPR_40x_ESR] = 0;
1146 }
1147 break;
1148 }
1149 if (ret >= 0) {
1150 ctx->raddr = raddr;
1151 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1152 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1153 ret);
1154 return 0;
1155 }
1156 }
1157 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1158 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1159
1160 return ret;
1161 }
1162
1163 void store_40x_sler(CPUPPCState *env, uint32_t val)
1164 {
1165 /* XXX: TO BE FIXED */
1166 if (val != 0x00000000) {
1167 cpu_abort(env, "Little-endian regions are not supported by now\n");
1168 }
1169 env->spr[SPR_405_SLER] = val;
1170 }
1171
1172 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
1173 hwaddr *raddr, int *prot,
1174 target_ulong address, int rw,
1175 int access_type, int i)
1176 {
1177 int ret, prot2;
1178
1179 if (ppcemb_tlb_check(env, tlb, raddr, address,
1180 env->spr[SPR_BOOKE_PID],
1181 !env->nb_pids, i) >= 0) {
1182 goto found_tlb;
1183 }
1184
1185 if (env->spr[SPR_BOOKE_PID1] &&
1186 ppcemb_tlb_check(env, tlb, raddr, address,
1187 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
1188 goto found_tlb;
1189 }
1190
1191 if (env->spr[SPR_BOOKE_PID2] &&
1192 ppcemb_tlb_check(env, tlb, raddr, address,
1193 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
1194 goto found_tlb;
1195 }
1196
1197 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1198 return -1;
1199
1200 found_tlb:
1201
1202 if (msr_pr != 0) {
1203 prot2 = tlb->prot & 0xF;
1204 } else {
1205 prot2 = (tlb->prot >> 4) & 0xF;
1206 }
1207
1208 /* Check the address space */
1209 if (access_type == ACCESS_CODE) {
1210 if (msr_ir != (tlb->attr & 1)) {
1211 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1212 return -1;
1213 }
1214
1215 *prot = prot2;
1216 if (prot2 & PAGE_EXEC) {
1217 LOG_SWTLB("%s: good TLB!\n", __func__);
1218 return 0;
1219 }
1220
1221 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1222 ret = -3;
1223 } else {
1224 if (msr_dr != (tlb->attr & 1)) {
1225 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1226 return -1;
1227 }
1228
1229 *prot = prot2;
1230 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1231 LOG_SWTLB("%s: found TLB!\n", __func__);
1232 return 0;
1233 }
1234
1235 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1236 ret = -2;
1237 }
1238
1239 return ret;
1240 }
1241
1242 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1243 target_ulong address, int rw,
1244 int access_type)
1245 {
1246 ppcemb_tlb_t *tlb;
1247 hwaddr raddr;
1248 int i, ret;
1249
1250 ret = -1;
1251 raddr = (hwaddr)-1ULL;
1252 for (i = 0; i < env->nb_tlb; i++) {
1253 tlb = &env->tlb.tlbe[i];
1254 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
1255 access_type, i);
1256 if (!ret) {
1257 break;
1258 }
1259 }
1260
1261 if (ret >= 0) {
1262 ctx->raddr = raddr;
1263 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1264 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1265 ret);
1266 } else {
1267 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1268 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1269 }
1270
1271 return ret;
1272 }
1273
1274 static void booke206_flush_tlb(CPUPPCState *env, int flags,
1275 const int check_iprot)
1276 {
1277 int tlb_size;
1278 int i, j;
1279 ppcmas_tlb_t *tlb = env->tlb.tlbm;
1280
1281 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1282 if (flags & (1 << i)) {
1283 tlb_size = booke206_tlb_size(env, i);
1284 for (j = 0; j < tlb_size; j++) {
1285 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
1286 tlb[j].mas1 &= ~MAS1_VALID;
1287 }
1288 }
1289 }
1290 tlb += booke206_tlb_size(env, i);
1291 }
1292
1293 tlb_flush(env, 1);
1294 }
1295
1296 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
1297 ppcmas_tlb_t *tlb)
1298 {
1299 int tlbm_size;
1300
1301 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1302
1303 return 1024ULL << tlbm_size;
1304 }
1305
1306 /* TLB check function for MAS based SoftTLBs */
1307 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
1308 hwaddr *raddrp,
1309 target_ulong address, uint32_t pid)
1310 {
1311 target_ulong mask;
1312 uint32_t tlb_pid;
1313
1314 /* Check valid flag */
1315 if (!(tlb->mas1 & MAS1_VALID)) {
1316 return -1;
1317 }
1318
1319 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
1320 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
1321 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
1322 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
1323 tlb->mas8);
1324
1325 /* Check PID */
1326 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
1327 if (tlb_pid != 0 && tlb_pid != pid) {
1328 return -1;
1329 }
1330
1331 /* Check effective address */
1332 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
1333 return -1;
1334 }
1335
1336 if (raddrp) {
1337 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
1338 }
1339
1340 return 0;
1341 }
1342
1343 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
1344 hwaddr *raddr, int *prot,
1345 target_ulong address, int rw,
1346 int access_type)
1347 {
1348 int ret;
1349 int prot2 = 0;
1350
1351 if (ppcmas_tlb_check(env, tlb, raddr, address,
1352 env->spr[SPR_BOOKE_PID]) >= 0) {
1353 goto found_tlb;
1354 }
1355
1356 if (env->spr[SPR_BOOKE_PID1] &&
1357 ppcmas_tlb_check(env, tlb, raddr, address,
1358 env->spr[SPR_BOOKE_PID1]) >= 0) {
1359 goto found_tlb;
1360 }
1361
1362 if (env->spr[SPR_BOOKE_PID2] &&
1363 ppcmas_tlb_check(env, tlb, raddr, address,
1364 env->spr[SPR_BOOKE_PID2]) >= 0) {
1365 goto found_tlb;
1366 }
1367
1368 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1369 return -1;
1370
1371 found_tlb:
1372
1373 if (msr_pr != 0) {
1374 if (tlb->mas7_3 & MAS3_UR) {
1375 prot2 |= PAGE_READ;
1376 }
1377 if (tlb->mas7_3 & MAS3_UW) {
1378 prot2 |= PAGE_WRITE;
1379 }
1380 if (tlb->mas7_3 & MAS3_UX) {
1381 prot2 |= PAGE_EXEC;
1382 }
1383 } else {
1384 if (tlb->mas7_3 & MAS3_SR) {
1385 prot2 |= PAGE_READ;
1386 }
1387 if (tlb->mas7_3 & MAS3_SW) {
1388 prot2 |= PAGE_WRITE;
1389 }
1390 if (tlb->mas7_3 & MAS3_SX) {
1391 prot2 |= PAGE_EXEC;
1392 }
1393 }
1394
1395 /* Check the address space and permissions */
1396 if (access_type == ACCESS_CODE) {
1397 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1398 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1399 return -1;
1400 }
1401
1402 *prot = prot2;
1403 if (prot2 & PAGE_EXEC) {
1404 LOG_SWTLB("%s: good TLB!\n", __func__);
1405 return 0;
1406 }
1407
1408 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1409 ret = -3;
1410 } else {
1411 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1412 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1413 return -1;
1414 }
1415
1416 *prot = prot2;
1417 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1418 LOG_SWTLB("%s: found TLB!\n", __func__);
1419 return 0;
1420 }
1421
1422 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1423 ret = -2;
1424 }
1425
1426 return ret;
1427 }
1428
1429 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1430 target_ulong address, int rw,
1431 int access_type)
1432 {
1433 ppcmas_tlb_t *tlb;
1434 hwaddr raddr;
1435 int i, j, ret;
1436
1437 ret = -1;
1438 raddr = (hwaddr)-1ULL;
1439
1440 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1441 int ways = booke206_tlb_ways(env, i);
1442
1443 for (j = 0; j < ways; j++) {
1444 tlb = booke206_get_tlbm(env, i, address, j);
1445 if (!tlb) {
1446 continue;
1447 }
1448 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1449 rw, access_type);
1450 if (ret != -1) {
1451 goto found_tlb;
1452 }
1453 }
1454 }
1455
1456 found_tlb:
1457
1458 if (ret >= 0) {
1459 ctx->raddr = raddr;
1460 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1461 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1462 ret);
1463 } else {
1464 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1465 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1466 }
1467
1468 return ret;
1469 }
1470
1471 static const char *book3e_tsize_to_str[32] = {
1472 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1473 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1474 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1475 "1T", "2T"
1476 };
1477
1478 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1479 CPUPPCState *env)
1480 {
1481 ppcemb_tlb_t *entry;
1482 int i;
1483
1484 if (kvm_enabled() && !env->kvm_sw_tlb) {
1485 cpu_fprintf(f, "Cannot access KVM TLB\n");
1486 return;
1487 }
1488
1489 cpu_fprintf(f, "\nTLB:\n");
1490 cpu_fprintf(f, "Effective Physical Size PID Prot "
1491 "Attr\n");
1492
1493 entry = &env->tlb.tlbe[0];
1494 for (i = 0; i < env->nb_tlb; i++, entry++) {
1495 hwaddr ea, pa;
1496 target_ulong mask;
1497 uint64_t size = (uint64_t)entry->size;
1498 char size_buf[20];
1499
1500 /* Check valid flag */
1501 if (!(entry->prot & PAGE_VALID)) {
1502 continue;
1503 }
1504
1505 mask = ~(entry->size - 1);
1506 ea = entry->EPN & mask;
1507 pa = entry->RPN & mask;
1508 /* Extend the physical address to 36 bits */
1509 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1510 size /= 1024;
1511 if (size >= 1024) {
1512 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1513 } else {
1514 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1515 }
1516 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1517 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1518 entry->prot, entry->attr);
1519 }
1520
1521 }
1522
1523 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1524 CPUPPCState *env, int tlbn, int offset,
1525 int tlbsize)
1526 {
1527 ppcmas_tlb_t *entry;
1528 int i;
1529
1530 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1531 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1532 " URWX WIMGE U0123\n");
1533
1534 entry = &env->tlb.tlbm[offset];
1535 for (i = 0; i < tlbsize; i++, entry++) {
1536 hwaddr ea, pa, size;
1537 int tsize;
1538
1539 if (!(entry->mas1 & MAS1_VALID)) {
1540 continue;
1541 }
1542
1543 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1544 size = 1024ULL << tsize;
1545 ea = entry->mas2 & ~(size - 1);
1546 pa = entry->mas7_3 & ~(size - 1);
1547
1548 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1549 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1550 (uint64_t)ea, (uint64_t)pa,
1551 book3e_tsize_to_str[tsize],
1552 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1553 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1554 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1555 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1556 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1557 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1558 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1559 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1560 entry->mas2 & MAS2_W ? 'W' : '-',
1561 entry->mas2 & MAS2_I ? 'I' : '-',
1562 entry->mas2 & MAS2_M ? 'M' : '-',
1563 entry->mas2 & MAS2_G ? 'G' : '-',
1564 entry->mas2 & MAS2_E ? 'E' : '-',
1565 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1566 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1567 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1568 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1569 }
1570 }
1571
1572 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1573 CPUPPCState *env)
1574 {
1575 int offset = 0;
1576 int i;
1577
1578 if (kvm_enabled() && !env->kvm_sw_tlb) {
1579 cpu_fprintf(f, "Cannot access KVM TLB\n");
1580 return;
1581 }
1582
1583 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1584 int size = booke206_tlb_size(env, i);
1585
1586 if (size == 0) {
1587 continue;
1588 }
1589
1590 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1591 offset += size;
1592 }
1593 }
1594
1595 #if defined(TARGET_PPC64)
1596 static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1597 CPUPPCState *env)
1598 {
1599 int i;
1600 uint64_t slbe, slbv;
1601
1602 cpu_synchronize_state(env);
1603
1604 cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
1605 for (i = 0; i < env->slb_nr; i++) {
1606 slbe = env->slb[i].esid;
1607 slbv = env->slb[i].vsid;
1608 if (slbe == 0 && slbv == 0) {
1609 continue;
1610 }
1611 cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
1612 i, slbe, slbv);
1613 }
1614 }
1615 #endif
1616
1617 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1618 {
1619 switch (env->mmu_model) {
1620 case POWERPC_MMU_BOOKE:
1621 mmubooke_dump_mmu(f, cpu_fprintf, env);
1622 break;
1623 case POWERPC_MMU_BOOKE206:
1624 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1625 break;
1626 #if defined(TARGET_PPC64)
1627 case POWERPC_MMU_64B:
1628 case POWERPC_MMU_2_06:
1629 case POWERPC_MMU_2_06d:
1630 mmubooks_dump_mmu(f, cpu_fprintf, env);
1631 break;
1632 #endif
1633 default:
1634 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1635 }
1636 }
1637
1638 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1639 target_ulong eaddr, int rw)
1640 {
1641 int in_plb, ret;
1642
1643 ctx->raddr = eaddr;
1644 ctx->prot = PAGE_READ | PAGE_EXEC;
1645 ret = 0;
1646 switch (env->mmu_model) {
1647 case POWERPC_MMU_32B:
1648 case POWERPC_MMU_601:
1649 case POWERPC_MMU_SOFT_6xx:
1650 case POWERPC_MMU_SOFT_74xx:
1651 case POWERPC_MMU_SOFT_4xx:
1652 case POWERPC_MMU_REAL:
1653 case POWERPC_MMU_BOOKE:
1654 ctx->prot |= PAGE_WRITE;
1655 break;
1656 #if defined(TARGET_PPC64)
1657 case POWERPC_MMU_64B:
1658 case POWERPC_MMU_2_06:
1659 case POWERPC_MMU_2_06d:
1660 /* Real address are 60 bits long */
1661 ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
1662 ctx->prot |= PAGE_WRITE;
1663 break;
1664 #endif
1665 case POWERPC_MMU_SOFT_4xx_Z:
1666 if (unlikely(msr_pe != 0)) {
1667 /* 403 family add some particular protections,
1668 * using PBL/PBU registers for accesses with no translation.
1669 */
1670 in_plb =
1671 /* Check PLB validity */
1672 (env->pb[0] < env->pb[1] &&
1673 /* and address in plb area */
1674 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1675 (env->pb[2] < env->pb[3] &&
1676 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1677 if (in_plb ^ msr_px) {
1678 /* Access in protected area */
1679 if (rw == 1) {
1680 /* Access is not allowed */
1681 ret = -2;
1682 }
1683 } else {
1684 /* Read-write access is allowed */
1685 ctx->prot |= PAGE_WRITE;
1686 }
1687 }
1688 break;
1689 case POWERPC_MMU_MPC8xx:
1690 /* XXX: TODO */
1691 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1692 break;
1693 case POWERPC_MMU_BOOKE206:
1694 cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
1695 break;
1696 default:
1697 cpu_abort(env, "Unknown or invalid MMU model\n");
1698 return -1;
1699 }
1700
1701 return ret;
1702 }
1703
1704 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1705 target_ulong eaddr, int rw, int access_type)
1706 {
1707 int ret;
1708
1709 #if 0
1710 qemu_log("%s\n", __func__);
1711 #endif
1712 if ((access_type == ACCESS_CODE && msr_ir == 0) ||
1713 (access_type != ACCESS_CODE && msr_dr == 0)) {
1714 if (env->mmu_model == POWERPC_MMU_BOOKE) {
1715 /* The BookE MMU always performs address translation. The
1716 IS and DS bits only affect the address space. */
1717 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1718 rw, access_type);
1719 } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
1720 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1721 access_type);
1722 } else {
1723 /* No address translation. */
1724 ret = check_physical(env, ctx, eaddr, rw);
1725 }
1726 } else {
1727 ret = -1;
1728 switch (env->mmu_model) {
1729 case POWERPC_MMU_32B:
1730 case POWERPC_MMU_601:
1731 case POWERPC_MMU_SOFT_6xx:
1732 case POWERPC_MMU_SOFT_74xx:
1733 /* Try to find a BAT */
1734 if (env->nb_BATs != 0) {
1735 ret = get_bat(env, ctx, eaddr, rw, access_type);
1736 }
1737 #if defined(TARGET_PPC64)
1738 case POWERPC_MMU_64B:
1739 case POWERPC_MMU_2_06:
1740 case POWERPC_MMU_2_06d:
1741 #endif
1742 if (ret < 0) {
1743 /* We didn't match any BAT entry or don't have BATs */
1744 ret = get_segment(env, ctx, eaddr, rw, access_type);
1745 }
1746 break;
1747 case POWERPC_MMU_SOFT_4xx:
1748 case POWERPC_MMU_SOFT_4xx_Z:
1749 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1750 rw, access_type);
1751 break;
1752 case POWERPC_MMU_BOOKE:
1753 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1754 rw, access_type);
1755 break;
1756 case POWERPC_MMU_BOOKE206:
1757 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1758 access_type);
1759 break;
1760 case POWERPC_MMU_MPC8xx:
1761 /* XXX: TODO */
1762 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1763 break;
1764 case POWERPC_MMU_REAL:
1765 cpu_abort(env, "PowerPC in real mode do not do any translation\n");
1766 return -1;
1767 default:
1768 cpu_abort(env, "Unknown or invalid MMU model\n");
1769 return -1;
1770 }
1771 }
1772 #if 0
1773 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1774 __func__, eaddr, ret, ctx->raddr);
1775 #endif
1776
1777 return ret;
1778 }
1779
1780 hwaddr cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
1781 {
1782 mmu_ctx_t ctx;
1783
1784 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1785 return -1;
1786 }
1787
1788 return ctx.raddr & TARGET_PAGE_MASK;
1789 }
1790
1791 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1792 int rw)
1793 {
1794 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1795 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1796 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1797 env->spr[SPR_BOOKE_MAS3] = 0;
1798 env->spr[SPR_BOOKE_MAS6] = 0;
1799 env->spr[SPR_BOOKE_MAS7] = 0;
1800
1801 /* AS */
1802 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1803 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1804 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1805 }
1806
1807 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1808 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1809
1810 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1811 case MAS4_TIDSELD_PID0:
1812 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1813 break;
1814 case MAS4_TIDSELD_PID1:
1815 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1816 break;
1817 case MAS4_TIDSELD_PID2:
1818 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1819 break;
1820 }
1821
1822 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1823
1824 /* next victim logic */
1825 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1826 env->last_way++;
1827 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1828 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1829 }
1830
1831 /* Perform address translation */
1832 int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
1833 int mmu_idx)
1834 {
1835 mmu_ctx_t ctx;
1836 int access_type;
1837 int ret = 0;
1838
1839 if (rw == 2) {
1840 /* code access */
1841 rw = 0;
1842 access_type = ACCESS_CODE;
1843 } else {
1844 /* data access */
1845 access_type = env->access_type;
1846 }
1847 ret = get_physical_address(env, &ctx, address, rw, access_type);
1848 if (ret == 0) {
1849 tlb_set_page(env, address & TARGET_PAGE_MASK,
1850 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1851 mmu_idx, TARGET_PAGE_SIZE);
1852 ret = 0;
1853 } else if (ret < 0) {
1854 LOG_MMU_STATE(env);
1855 if (access_type == ACCESS_CODE) {
1856 switch (ret) {
1857 case -1:
1858 /* No matches in page tables or TLB */
1859 switch (env->mmu_model) {
1860 case POWERPC_MMU_SOFT_6xx:
1861 env->exception_index = POWERPC_EXCP_IFTLB;
1862 env->error_code = 1 << 18;
1863 env->spr[SPR_IMISS] = address;
1864 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1865 goto tlb_miss;
1866 case POWERPC_MMU_SOFT_74xx:
1867 env->exception_index = POWERPC_EXCP_IFTLB;
1868 goto tlb_miss_74xx;
1869 case POWERPC_MMU_SOFT_4xx:
1870 case POWERPC_MMU_SOFT_4xx_Z:
1871 env->exception_index = POWERPC_EXCP_ITLB;
1872 env->error_code = 0;
1873 env->spr[SPR_40x_DEAR] = address;
1874 env->spr[SPR_40x_ESR] = 0x00000000;
1875 break;
1876 case POWERPC_MMU_32B:
1877 case POWERPC_MMU_601:
1878 #if defined(TARGET_PPC64)
1879 case POWERPC_MMU_64B:
1880 case POWERPC_MMU_2_06:
1881 case POWERPC_MMU_2_06d:
1882 #endif
1883 env->exception_index = POWERPC_EXCP_ISI;
1884 env->error_code = 0x40000000;
1885 break;
1886 case POWERPC_MMU_BOOKE206:
1887 booke206_update_mas_tlb_miss(env, address, rw);
1888 /* fall through */
1889 case POWERPC_MMU_BOOKE:
1890 env->exception_index = POWERPC_EXCP_ITLB;
1891 env->error_code = 0;
1892 env->spr[SPR_BOOKE_DEAR] = address;
1893 return -1;
1894 case POWERPC_MMU_MPC8xx:
1895 /* XXX: TODO */
1896 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1897 break;
1898 case POWERPC_MMU_REAL:
1899 cpu_abort(env, "PowerPC in real mode should never raise "
1900 "any MMU exceptions\n");
1901 return -1;
1902 default:
1903 cpu_abort(env, "Unknown or invalid MMU model\n");
1904 return -1;
1905 }
1906 break;
1907 case -2:
1908 /* Access rights violation */
1909 env->exception_index = POWERPC_EXCP_ISI;
1910 env->error_code = 0x08000000;
1911 break;
1912 case -3:
1913 /* No execute protection violation */
1914 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1915 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1916 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1917 }
1918 env->exception_index = POWERPC_EXCP_ISI;
1919 env->error_code = 0x10000000;
1920 break;
1921 case -4:
1922 /* Direct store exception */
1923 /* No code fetch is allowed in direct-store areas */
1924 env->exception_index = POWERPC_EXCP_ISI;
1925 env->error_code = 0x10000000;
1926 break;
1927 #if defined(TARGET_PPC64)
1928 case -5:
1929 /* No match in segment table */
1930 env->exception_index = POWERPC_EXCP_ISEG;
1931 env->error_code = 0;
1932 break;
1933 #endif
1934 }
1935 } else {
1936 switch (ret) {
1937 case -1:
1938 /* No matches in page tables or TLB */
1939 switch (env->mmu_model) {
1940 case POWERPC_MMU_SOFT_6xx:
1941 if (rw == 1) {
1942 env->exception_index = POWERPC_EXCP_DSTLB;
1943 env->error_code = 1 << 16;
1944 } else {
1945 env->exception_index = POWERPC_EXCP_DLTLB;
1946 env->error_code = 0;
1947 }
1948 env->spr[SPR_DMISS] = address;
1949 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1950 tlb_miss:
1951 env->error_code |= ctx.key << 19;
1952 env->spr[SPR_HASH1] = env->htab_base +
1953 get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
1954 env->spr[SPR_HASH2] = env->htab_base +
1955 get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
1956 break;
1957 case POWERPC_MMU_SOFT_74xx:
1958 if (rw == 1) {
1959 env->exception_index = POWERPC_EXCP_DSTLB;
1960 } else {
1961 env->exception_index = POWERPC_EXCP_DLTLB;
1962 }
1963 tlb_miss_74xx:
1964 /* Implement LRU algorithm */
1965 env->error_code = ctx.key << 19;
1966 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1967 ((env->last_way + 1) & (env->nb_ways - 1));
1968 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1969 break;
1970 case POWERPC_MMU_SOFT_4xx:
1971 case POWERPC_MMU_SOFT_4xx_Z:
1972 env->exception_index = POWERPC_EXCP_DTLB;
1973 env->error_code = 0;
1974 env->spr[SPR_40x_DEAR] = address;
1975 if (rw) {
1976 env->spr[SPR_40x_ESR] = 0x00800000;
1977 } else {
1978 env->spr[SPR_40x_ESR] = 0x00000000;
1979 }
1980 break;
1981 case POWERPC_MMU_32B:
1982 case POWERPC_MMU_601:
1983 #if defined(TARGET_PPC64)
1984 case POWERPC_MMU_64B:
1985 case POWERPC_MMU_2_06:
1986 case POWERPC_MMU_2_06d:
1987 #endif
1988 env->exception_index = POWERPC_EXCP_DSI;
1989 env->error_code = 0;
1990 env->spr[SPR_DAR] = address;
1991 if (rw == 1) {
1992 env->spr[SPR_DSISR] = 0x42000000;
1993 } else {
1994 env->spr[SPR_DSISR] = 0x40000000;
1995 }
1996 break;
1997 case POWERPC_MMU_MPC8xx:
1998 /* XXX: TODO */
1999 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2000 break;
2001 case POWERPC_MMU_BOOKE206:
2002 booke206_update_mas_tlb_miss(env, address, rw);
2003 /* fall through */
2004 case POWERPC_MMU_BOOKE:
2005 env->exception_index = POWERPC_EXCP_DTLB;
2006 env->error_code = 0;
2007 env->spr[SPR_BOOKE_DEAR] = address;
2008 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
2009 return -1;
2010 case POWERPC_MMU_REAL:
2011 cpu_abort(env, "PowerPC in real mode should never raise "
2012 "any MMU exceptions\n");
2013 return -1;
2014 default:
2015 cpu_abort(env, "Unknown or invalid MMU model\n");
2016 return -1;
2017 }
2018 break;
2019 case -2:
2020 /* Access rights violation */
2021 env->exception_index = POWERPC_EXCP_DSI;
2022 env->error_code = 0;
2023 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
2024 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
2025 env->spr[SPR_40x_DEAR] = address;
2026 if (rw) {
2027 env->spr[SPR_40x_ESR] |= 0x00800000;
2028 }
2029 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
2030 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
2031 env->spr[SPR_BOOKE_DEAR] = address;
2032 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
2033 } else {
2034 env->spr[SPR_DAR] = address;
2035 if (rw == 1) {
2036 env->spr[SPR_DSISR] = 0x0A000000;
2037 } else {
2038 env->spr[SPR_DSISR] = 0x08000000;
2039 }
2040 }
2041 break;
2042 case -4:
2043 /* Direct store exception */
2044 switch (access_type) {
2045 case ACCESS_FLOAT:
2046 /* Floating point load/store */
2047 env->exception_index = POWERPC_EXCP_ALIGN;
2048 env->error_code = POWERPC_EXCP_ALIGN_FP;
2049 env->spr[SPR_DAR] = address;
2050 break;
2051 case ACCESS_RES:
2052 /* lwarx, ldarx or stwcx. */
2053 env->exception_index = POWERPC_EXCP_DSI;
2054 env->error_code = 0;
2055 env->spr[SPR_DAR] = address;
2056 if (rw == 1) {
2057 env->spr[SPR_DSISR] = 0x06000000;
2058 } else {
2059 env->spr[SPR_DSISR] = 0x04000000;
2060 }
2061 break;
2062 case ACCESS_EXT:
2063 /* eciwx or ecowx */
2064 env->exception_index = POWERPC_EXCP_DSI;
2065 env->error_code = 0;
2066 env->spr[SPR_DAR] = address;
2067 if (rw == 1) {
2068 env->spr[SPR_DSISR] = 0x06100000;
2069 } else {
2070 env->spr[SPR_DSISR] = 0x04100000;
2071 }
2072 break;
2073 default:
2074 printf("DSI: invalid exception (%d)\n", ret);
2075 env->exception_index = POWERPC_EXCP_PROGRAM;
2076 env->error_code =
2077 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
2078 env->spr[SPR_DAR] = address;
2079 break;
2080 }
2081 break;
2082 #if defined(TARGET_PPC64)
2083 case -5:
2084 /* No match in segment table */
2085 env->exception_index = POWERPC_EXCP_DSEG;
2086 env->error_code = 0;
2087 env->spr[SPR_DAR] = address;
2088 break;
2089 #endif
2090 }
2091 }
2092 #if 0
2093 printf("%s: set exception to %d %02x\n", __func__,
2094 env->exception, env->error_code);
2095 #endif
2096 ret = 1;
2097 }
2098
2099 return ret;
2100 }
2101
2102 /*****************************************************************************/
2103 /* BATs management */
2104 #if !defined(FLUSH_ALL_TLBS)
2105 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
2106 target_ulong mask)
2107 {
2108 target_ulong base, end, page;
2109
2110 base = BATu & ~0x0001FFFF;
2111 end = base + mask + 0x00020000;
2112 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
2113 TARGET_FMT_lx ")\n", base, end, mask);
2114 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
2115 tlb_flush_page(env, page);
2116 }
2117 LOG_BATS("Flush done\n");
2118 }
2119 #endif
2120
2121 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
2122 target_ulong value)
2123 {
2124 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
2125 nr, ul == 0 ? 'u' : 'l', value, env->nip);
2126 }
2127
2128 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
2129 {
2130 target_ulong mask;
2131
2132 dump_store_bat(env, 'I', 0, nr, value);
2133 if (env->IBAT[0][nr] != value) {
2134 mask = (value << 15) & 0x0FFE0000UL;
2135 #if !defined(FLUSH_ALL_TLBS)
2136 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2137 #endif
2138 /* When storing valid upper BAT, mask BEPI and BRPN
2139 * and invalidate all TLBs covered by this BAT
2140 */
2141 mask = (value << 15) & 0x0FFE0000UL;
2142 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
2143 (value & ~0x0001FFFFUL & ~mask);
2144 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
2145 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
2146 #if !defined(FLUSH_ALL_TLBS)
2147 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2148 #else
2149 tlb_flush(env, 1);
2150 #endif
2151 }
2152 }
2153
2154 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
2155 {
2156 dump_store_bat(env, 'I', 1, nr, value);
2157 env->IBAT[1][nr] = value;
2158 }
2159
2160 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
2161 {
2162 target_ulong mask;
2163
2164 dump_store_bat(env, 'D', 0, nr, value);
2165 if (env->DBAT[0][nr] != value) {
2166 /* When storing valid upper BAT, mask BEPI and BRPN
2167 * and invalidate all TLBs covered by this BAT
2168 */
2169 mask = (value << 15) & 0x0FFE0000UL;
2170 #if !defined(FLUSH_ALL_TLBS)
2171 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
2172 #endif
2173 mask = (value << 15) & 0x0FFE0000UL;
2174 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
2175 (value & ~0x0001FFFFUL & ~mask);
2176 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
2177 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
2178 #if !defined(FLUSH_ALL_TLBS)
2179 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
2180 #else
2181 tlb_flush(env, 1);
2182 #endif
2183 }
2184 }
2185
2186 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
2187 {
2188 dump_store_bat(env, 'D', 1, nr, value);
2189 env->DBAT[1][nr] = value;
2190 }
2191
2192 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
2193 {
2194 target_ulong mask;
2195 #if defined(FLUSH_ALL_TLBS)
2196 int do_inval;
2197 #endif
2198
2199 dump_store_bat(env, 'I', 0, nr, value);
2200 if (env->IBAT[0][nr] != value) {
2201 #if defined(FLUSH_ALL_TLBS)
2202 do_inval = 0;
2203 #endif
2204 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
2205 if (env->IBAT[1][nr] & 0x40) {
2206 /* Invalidate BAT only if it is valid */
2207 #if !defined(FLUSH_ALL_TLBS)
2208 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2209 #else
2210 do_inval = 1;
2211 #endif
2212 }
2213 /* When storing valid upper BAT, mask BEPI and BRPN
2214 * and invalidate all TLBs covered by this BAT
2215 */
2216 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
2217 (value & ~0x0001FFFFUL & ~mask);
2218 env->DBAT[0][nr] = env->IBAT[0][nr];
2219 if (env->IBAT[1][nr] & 0x40) {
2220 #if !defined(FLUSH_ALL_TLBS)
2221 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2222 #else
2223 do_inval = 1;
2224 #endif
2225 }
2226 #if defined(FLUSH_ALL_TLBS)
2227 if (do_inval) {
2228 tlb_flush(env, 1);
2229 }
2230 #endif
2231 }
2232 }
2233
2234 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
2235 {
2236 #if !defined(FLUSH_ALL_TLBS)
2237 target_ulong mask;
2238 #else
2239 int do_inval;
2240 #endif
2241
2242 dump_store_bat(env, 'I', 1, nr, value);
2243 if (env->IBAT[1][nr] != value) {
2244 #if defined(FLUSH_ALL_TLBS)
2245 do_inval = 0;
2246 #endif
2247 if (env->IBAT[1][nr] & 0x40) {
2248 #if !defined(FLUSH_ALL_TLBS)
2249 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
2250 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2251 #else
2252 do_inval = 1;
2253 #endif
2254 }
2255 if (value & 0x40) {
2256 #if !defined(FLUSH_ALL_TLBS)
2257 mask = (value << 17) & 0x0FFE0000UL;
2258 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2259 #else
2260 do_inval = 1;
2261 #endif
2262 }
2263 env->IBAT[1][nr] = value;
2264 env->DBAT[1][nr] = value;
2265 #if defined(FLUSH_ALL_TLBS)
2266 if (do_inval) {
2267 tlb_flush(env, 1);
2268 }
2269 #endif
2270 }
2271 }
2272
2273 /*****************************************************************************/
2274 /* TLB management */
2275 void ppc_tlb_invalidate_all(CPUPPCState *env)
2276 {
2277 switch (env->mmu_model) {
2278 case POWERPC_MMU_SOFT_6xx:
2279 case POWERPC_MMU_SOFT_74xx:
2280 ppc6xx_tlb_invalidate_all(env);
2281 break;
2282 case POWERPC_MMU_SOFT_4xx:
2283 case POWERPC_MMU_SOFT_4xx_Z:
2284 ppc4xx_tlb_invalidate_all(env);
2285 break;
2286 case POWERPC_MMU_REAL:
2287 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
2288 break;
2289 case POWERPC_MMU_MPC8xx:
2290 /* XXX: TODO */
2291 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2292 break;
2293 case POWERPC_MMU_BOOKE:
2294 tlb_flush(env, 1);
2295 break;
2296 case POWERPC_MMU_BOOKE206:
2297 booke206_flush_tlb(env, -1, 0);
2298 break;
2299 case POWERPC_MMU_32B:
2300 case POWERPC_MMU_601:
2301 #if defined(TARGET_PPC64)
2302 case POWERPC_MMU_64B:
2303 case POWERPC_MMU_2_06:
2304 case POWERPC_MMU_2_06d:
2305 #endif /* defined(TARGET_PPC64) */
2306 tlb_flush(env, 1);
2307 break;
2308 default:
2309 /* XXX: TODO */
2310 cpu_abort(env, "Unknown MMU model\n");
2311 break;
2312 }
2313 }
2314
2315 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
2316 {
2317 #if !defined(FLUSH_ALL_TLBS)
2318 addr &= TARGET_PAGE_MASK;
2319 switch (env->mmu_model) {
2320 case POWERPC_MMU_SOFT_6xx:
2321 case POWERPC_MMU_SOFT_74xx:
2322 ppc6xx_tlb_invalidate_virt(env, addr, 0);
2323 if (env->id_tlbs == 1) {
2324 ppc6xx_tlb_invalidate_virt(env, addr, 1);
2325 }
2326 break;
2327 case POWERPC_MMU_SOFT_4xx:
2328 case POWERPC_MMU_SOFT_4xx_Z:
2329 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
2330 break;
2331 case POWERPC_MMU_REAL:
2332 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
2333 break;
2334 case POWERPC_MMU_MPC8xx:
2335 /* XXX: TODO */
2336 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2337 break;
2338 case POWERPC_MMU_BOOKE:
2339 /* XXX: TODO */
2340 cpu_abort(env, "BookE MMU model is not implemented\n");
2341 break;
2342 case POWERPC_MMU_BOOKE206:
2343 /* XXX: TODO */
2344 cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
2345 break;
2346 case POWERPC_MMU_32B:
2347 case POWERPC_MMU_601:
2348 /* tlbie invalidate TLBs for all segments */
2349 addr &= ~((target_ulong)-1ULL << 28);
2350 /* XXX: this case should be optimized,
2351 * giving a mask to tlb_flush_page
2352 */
2353 tlb_flush_page(env, addr | (0x0 << 28));
2354 tlb_flush_page(env, addr | (0x1 << 28));
2355 tlb_flush_page(env, addr | (0x2 << 28));
2356 tlb_flush_page(env, addr | (0x3 << 28));
2357 tlb_flush_page(env, addr | (0x4 << 28));
2358 tlb_flush_page(env, addr | (0x5 << 28));
2359 tlb_flush_page(env, addr | (0x6 << 28));
2360 tlb_flush_page(env, addr | (0x7 << 28));
2361 tlb_flush_page(env, addr | (0x8 << 28));
2362 tlb_flush_page(env, addr | (0x9 << 28));
2363 tlb_flush_page(env, addr | (0xA << 28));
2364 tlb_flush_page(env, addr | (0xB << 28));
2365 tlb_flush_page(env, addr | (0xC << 28));
2366 tlb_flush_page(env, addr | (0xD << 28));
2367 tlb_flush_page(env, addr | (0xE << 28));
2368 tlb_flush_page(env, addr | (0xF << 28));
2369 break;
2370 #if defined(TARGET_PPC64)
2371 case POWERPC_MMU_64B:
2372 case POWERPC_MMU_2_06:
2373 case POWERPC_MMU_2_06d:
2374 /* tlbie invalidate TLBs for all segments */
2375 /* XXX: given the fact that there are too many segments to invalidate,
2376 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2377 * we just invalidate all TLBs
2378 */
2379 tlb_flush(env, 1);
2380 break;
2381 #endif /* defined(TARGET_PPC64) */
2382 default:
2383 /* XXX: TODO */
2384 cpu_abort(env, "Unknown MMU model\n");
2385 break;
2386 }
2387 #else
2388 ppc_tlb_invalidate_all(env);
2389 #endif
2390 }
2391
2392 /*****************************************************************************/
2393 /* Special registers manipulation */
2394 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2395 {
2396 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
2397 if (env->spr[SPR_SDR1] != value) {
2398 env->spr[SPR_SDR1] = value;
2399 #if defined(TARGET_PPC64)
2400 if (env->mmu_model & POWERPC_MMU_64) {
2401 target_ulong htabsize = value & SDR_64_HTABSIZE;
2402
2403 if (htabsize > 28) {
2404 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2405 " stored in SDR1\n", htabsize);
2406 htabsize = 28;
2407 }
2408 env->htab_mask = (1ULL << (htabsize + 18)) - 1;
2409 env->htab_base = value & SDR_64_HTABORG;
2410 } else
2411 #endif /* defined(TARGET_PPC64) */
2412 {
2413 /* FIXME: Should check for valid HTABMASK values */
2414 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2415 env->htab_base = value & SDR_32_HTABORG;
2416 }
2417 tlb_flush(env, 1);
2418 }
2419 }
2420
2421 /* Segment registers load and store */
2422 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2423 {
2424 #if defined(TARGET_PPC64)
2425 if (env->mmu_model & POWERPC_MMU_64) {
2426 /* XXX */
2427 return 0;
2428 }
2429 #endif
2430 return env->sr[sr_num];
2431 }
2432
2433 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2434 {
2435 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2436 (int)srnum, value, env->sr[srnum]);
2437 #if defined(TARGET_PPC64)
2438 if (env->mmu_model & POWERPC_MMU_64) {
2439 uint64_t rb = 0, rs = 0;
2440
2441 /* ESID = srnum */
2442 rb |= ((uint32_t)srnum & 0xf) << 28;
2443 /* Set the valid bit */
2444 rb |= 1 << 27;
2445 /* Index = ESID */
2446 rb |= (uint32_t)srnum;
2447
2448 /* VSID = VSID */
2449 rs |= (value & 0xfffffff) << 12;
2450 /* flags = flags */
2451 rs |= ((value >> 27) & 0xf) << 8;
2452
2453 ppc_store_slb(env, rb, rs);
2454 } else
2455 #endif
2456 if (env->sr[srnum] != value) {
2457 env->sr[srnum] = value;
2458 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2459 flusing the whole TLB. */
2460 #if !defined(FLUSH_ALL_TLBS) && 0
2461 {
2462 target_ulong page, end;
2463 /* Invalidate 256 MB of virtual memory */
2464 page = (16 << 20) * srnum;
2465 end = page + (16 << 20);
2466 for (; page != end; page += TARGET_PAGE_SIZE) {
2467 tlb_flush_page(env, page);
2468 }
2469 }
2470 #else
2471 tlb_flush(env, 1);
2472 #endif
2473 }
2474 }
2475 #endif /* !defined(CONFIG_USER_ONLY) */
2476
2477 #if !defined(CONFIG_USER_ONLY)
2478 /* SLB management */
2479 #if defined(TARGET_PPC64)
2480 void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
2481 {
2482 if (ppc_store_slb(env, rb, rs) < 0) {
2483 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2484 POWERPC_EXCP_INVAL);
2485 }
2486 }
2487
2488 target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
2489 {
2490 target_ulong rt = 0;
2491
2492 if (ppc_load_slb_esid(env, rb, &rt) < 0) {
2493 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2494 POWERPC_EXCP_INVAL);
2495 }
2496 return rt;
2497 }
2498
2499 target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
2500 {
2501 target_ulong rt = 0;
2502
2503 if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
2504 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2505 POWERPC_EXCP_INVAL);
2506 }
2507 return rt;
2508 }
2509 #endif /* defined(TARGET_PPC64) */
2510
2511 /* TLB management */
2512 void helper_tlbia(CPUPPCState *env)
2513 {
2514 ppc_tlb_invalidate_all(env);
2515 }
2516
2517 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2518 {
2519 ppc_tlb_invalidate_one(env, addr);
2520 }
2521
2522 /* Software driven TLBs management */
2523 /* PowerPC 602/603 software TLB load instructions helpers */
2524 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2525 {
2526 target_ulong RPN, CMP, EPN;
2527 int way;
2528
2529 RPN = env->spr[SPR_RPA];
2530 if (is_code) {
2531 CMP = env->spr[SPR_ICMP];
2532 EPN = env->spr[SPR_IMISS];
2533 } else {
2534 CMP = env->spr[SPR_DCMP];
2535 EPN = env->spr[SPR_DMISS];
2536 }
2537 way = (env->spr[SPR_SRR1] >> 17) & 1;
2538 (void)EPN; /* avoid a compiler warning */
2539 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2540 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2541 RPN, way);
2542 /* Store this TLB */
2543 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2544 way, is_code, CMP, RPN);
2545 }
2546
2547 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2548 {
2549 do_6xx_tlb(env, EPN, 0);
2550 }
2551
2552 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2553 {
2554 do_6xx_tlb(env, EPN, 1);
2555 }
2556
2557 /* PowerPC 74xx software TLB load instructions helpers */
2558 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2559 {
2560 target_ulong RPN, CMP, EPN;
2561 int way;
2562
2563 RPN = env->spr[SPR_PTELO];
2564 CMP = env->spr[SPR_PTEHI];
2565 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2566 way = env->spr[SPR_TLBMISS] & 0x3;
2567 (void)EPN; /* avoid a compiler warning */
2568 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2569 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2570 RPN, way);
2571 /* Store this TLB */
2572 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2573 way, is_code, CMP, RPN);
2574 }
2575
2576 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2577 {
2578 do_74xx_tlb(env, EPN, 0);
2579 }
2580
2581 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2582 {
2583 do_74xx_tlb(env, EPN, 1);
2584 }
2585
2586 /*****************************************************************************/
2587 /* PowerPC 601 specific instructions (POWER bridge) */
2588
2589 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2590 {
2591 mmu_ctx_t ctx;
2592 int nb_BATs;
2593 target_ulong ret = 0;
2594
2595 /* We don't have to generate many instances of this instruction,
2596 * as rac is supervisor only.
2597 */
2598 /* XXX: FIX THIS: Pretend we have no BAT */
2599 nb_BATs = env->nb_BATs;
2600 env->nb_BATs = 0;
2601 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2602 ret = ctx.raddr;
2603 }
2604 env->nb_BATs = nb_BATs;
2605 return ret;
2606 }
2607
2608 static inline target_ulong booke_tlb_to_page_size(int size)
2609 {
2610 return 1024 << (2 * size);
2611 }
2612
2613 static inline int booke_page_size_to_tlb(target_ulong page_size)
2614 {
2615 int size;
2616
2617 switch (page_size) {
2618 case 0x00000400UL:
2619 size = 0x0;
2620 break;
2621 case 0x00001000UL:
2622 size = 0x1;
2623 break;
2624 case 0x00004000UL:
2625 size = 0x2;
2626 break;
2627 case 0x00010000UL:
2628 size = 0x3;
2629 break;
2630 case 0x00040000UL:
2631 size = 0x4;
2632 break;
2633 case 0x00100000UL:
2634 size = 0x5;
2635 break;
2636 case 0x00400000UL:
2637 size = 0x6;
2638 break;
2639 case 0x01000000UL:
2640 size = 0x7;
2641 break;
2642 case 0x04000000UL:
2643 size = 0x8;
2644 break;
2645 case 0x10000000UL:
2646 size = 0x9;
2647 break;
2648 case 0x40000000UL:
2649 size = 0xA;
2650 break;
2651 #if defined(TARGET_PPC64)
2652 case 0x000100000000ULL:
2653 size = 0xB;
2654 break;
2655 case 0x000400000000ULL:
2656 size = 0xC;
2657 break;
2658 case 0x001000000000ULL:
2659 size = 0xD;
2660 break;
2661 case 0x004000000000ULL:
2662 size = 0xE;
2663 break;
2664 case 0x010000000000ULL:
2665 size = 0xF;
2666 break;
2667 #endif
2668 default:
2669 size = -1;
2670 break;
2671 }
2672
2673 return size;
2674 }
2675
2676 /* Helpers for 4xx TLB management */
2677 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2678
2679 #define PPC4XX_TLBHI_V 0x00000040
2680 #define PPC4XX_TLBHI_E 0x00000020
2681 #define PPC4XX_TLBHI_SIZE_MIN 0
2682 #define PPC4XX_TLBHI_SIZE_MAX 7
2683 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2684 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2685 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2686
2687 #define PPC4XX_TLBLO_EX 0x00000200
2688 #define PPC4XX_TLBLO_WR 0x00000100
2689 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2690 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2691
2692 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2693 {
2694 ppcemb_tlb_t *tlb;
2695 target_ulong ret;
2696 int size;
2697
2698 entry &= PPC4XX_TLB_ENTRY_MASK;
2699 tlb = &env->tlb.tlbe[entry];
2700 ret = tlb->EPN;
2701 if (tlb->prot & PAGE_VALID) {
2702 ret |= PPC4XX_TLBHI_V;
2703 }
2704 size = booke_page_size_to_tlb(tlb->size);
2705 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2706 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2707 }
2708 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2709 env->spr[SPR_40x_PID] = tlb->PID;
2710 return ret;
2711 }
2712
2713 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2714 {
2715 ppcemb_tlb_t *tlb;
2716 target_ulong ret;
2717
2718 entry &= PPC4XX_TLB_ENTRY_MASK;
2719 tlb = &env->tlb.tlbe[entry];
2720 ret = tlb->RPN;
2721 if (tlb->prot & PAGE_EXEC) {
2722 ret |= PPC4XX_TLBLO_EX;
2723 }
2724 if (tlb->prot & PAGE_WRITE) {
2725 ret |= PPC4XX_TLBLO_WR;
2726 }
2727 return ret;
2728 }
2729
2730 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2731 target_ulong val)
2732 {
2733 ppcemb_tlb_t *tlb;
2734 target_ulong page, end;
2735
2736 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2737 val);
2738 entry &= PPC4XX_TLB_ENTRY_MASK;
2739 tlb = &env->tlb.tlbe[entry];
2740 /* Invalidate previous TLB (if it's valid) */
2741 if (tlb->prot & PAGE_VALID) {
2742 end = tlb->EPN + tlb->size;
2743 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2744 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2745 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2746 tlb_flush_page(env, page);
2747 }
2748 }
2749 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2750 & PPC4XX_TLBHI_SIZE_MASK);
2751 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2752 * If this ever occurs, one should use the ppcemb target instead
2753 * of the ppc or ppc64 one
2754 */
2755 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2756 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2757 "are not supported (%d)\n",
2758 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2759 }
2760 tlb->EPN = val & ~(tlb->size - 1);
2761 if (val & PPC4XX_TLBHI_V) {
2762 tlb->prot |= PAGE_VALID;
2763 if (val & PPC4XX_TLBHI_E) {
2764 /* XXX: TO BE FIXED */
2765 cpu_abort(env,
2766 "Little-endian TLB entries are not supported by now\n");
2767 }
2768 } else {
2769 tlb->prot &= ~PAGE_VALID;
2770 }
2771 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2772 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2773 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2774 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2775 tlb->prot & PAGE_READ ? 'r' : '-',
2776 tlb->prot & PAGE_WRITE ? 'w' : '-',
2777 tlb->prot & PAGE_EXEC ? 'x' : '-',
2778 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2779 /* Invalidate new TLB (if valid) */
2780 if (tlb->prot & PAGE_VALID) {
2781 end = tlb->EPN + tlb->size;
2782 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2783 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2784 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2785 tlb_flush_page(env, page);
2786 }
2787 }
2788 }
2789
2790 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2791 target_ulong val)
2792 {
2793 ppcemb_tlb_t *tlb;
2794
2795 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2796 val);
2797 entry &= PPC4XX_TLB_ENTRY_MASK;
2798 tlb = &env->tlb.tlbe[entry];
2799 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2800 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2801 tlb->prot = PAGE_READ;
2802 if (val & PPC4XX_TLBLO_EX) {
2803 tlb->prot |= PAGE_EXEC;
2804 }
2805 if (val & PPC4XX_TLBLO_WR) {
2806 tlb->prot |= PAGE_WRITE;
2807 }
2808 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2809 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2810 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2811 tlb->prot & PAGE_READ ? 'r' : '-',
2812 tlb->prot & PAGE_WRITE ? 'w' : '-',
2813 tlb->prot & PAGE_EXEC ? 'x' : '-',
2814 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2815 }
2816
2817 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2818 {
2819 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2820 }
2821
2822 /* PowerPC 440 TLB management */
2823 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2824 target_ulong value)
2825 {
2826 ppcemb_tlb_t *tlb;
2827 target_ulong EPN, RPN, size;
2828 int do_flush_tlbs;
2829
2830 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2831 __func__, word, (int)entry, value);
2832 do_flush_tlbs = 0;
2833 entry &= 0x3F;
2834 tlb = &env->tlb.tlbe[entry];
2835 switch (word) {
2836 default:
2837 /* Just here to please gcc */
2838 case 0:
2839 EPN = value & 0xFFFFFC00;
2840 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2841 do_flush_tlbs = 1;
2842 }
2843 tlb->EPN = EPN;
2844 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2845 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2846 do_flush_tlbs = 1;
2847 }
2848 tlb->size = size;
2849 tlb->attr &= ~0x1;
2850 tlb->attr |= (value >> 8) & 1;
2851 if (value & 0x200) {
2852 tlb->prot |= PAGE_VALID;
2853 } else {
2854 if (tlb->prot & PAGE_VALID) {
2855 tlb->prot &= ~PAGE_VALID;
2856 do_flush_tlbs = 1;
2857 }
2858 }
2859 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2860 if (do_flush_tlbs) {
2861 tlb_flush(env, 1);
2862 }
2863 break;
2864 case 1:
2865 RPN = value & 0xFFFFFC0F;
2866 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2867 tlb_flush(env, 1);
2868 }
2869 tlb->RPN = RPN;
2870 break;
2871 case 2:
2872 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2873 tlb->prot = tlb->prot & PAGE_VALID;
2874 if (value & 0x1) {
2875 tlb->prot |= PAGE_READ << 4;
2876 }
2877 if (value & 0x2) {
2878 tlb->prot |= PAGE_WRITE << 4;
2879 }
2880 if (value & 0x4) {
2881 tlb->prot |= PAGE_EXEC << 4;
2882 }
2883 if (value & 0x8) {
2884 tlb->prot |= PAGE_READ;
2885 }
2886 if (value & 0x10) {
2887 tlb->prot |= PAGE_WRITE;
2888 }
2889 if (value & 0x20) {
2890 tlb->prot |= PAGE_EXEC;
2891 }
2892 break;
2893 }
2894 }
2895
2896 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2897 target_ulong entry)
2898 {
2899 ppcemb_tlb_t *tlb;
2900 target_ulong ret;
2901 int size;
2902
2903 entry &= 0x3F;
2904 tlb = &env->tlb.tlbe[entry];
2905 switch (word) {
2906 default:
2907 /* Just here to please gcc */
2908 case 0:
2909 ret = tlb->EPN;
2910 size = booke_page_size_to_tlb(tlb->size);
2911 if (size < 0 || size > 0xF) {
2912 size = 1;
2913 }
2914 ret |= size << 4;
2915 if (tlb->attr & 0x1) {
2916 ret |= 0x100;
2917 }
2918 if (tlb->prot & PAGE_VALID) {
2919 ret |= 0x200;
2920 }
2921 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2922 env->spr[SPR_440_MMUCR] |= tlb->PID;
2923 break;
2924 case 1:
2925 ret = tlb->RPN;
2926 break;
2927 case 2:
2928 ret = tlb->attr & ~0x1;
2929 if (tlb->prot & (PAGE_READ << 4)) {
2930 ret |= 0x1;
2931 }
2932 if (tlb->prot & (PAGE_WRITE << 4)) {
2933 ret |= 0x2;
2934 }
2935 if (tlb->prot & (PAGE_EXEC << 4)) {
2936 ret |= 0x4;
2937 }
2938 if (tlb->prot & PAGE_READ) {
2939 ret |= 0x8;
2940 }
2941 if (tlb->prot & PAGE_WRITE) {
2942 ret |= 0x10;
2943 }
2944 if (tlb->prot & PAGE_EXEC) {
2945 ret |= 0x20;
2946 }
2947 break;
2948 }
2949 return ret;
2950 }
2951
2952 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2953 {
2954 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2955 }
2956
2957 /* PowerPC BookE 2.06 TLB management */
2958
2959 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2960 {
2961 uint32_t tlbncfg = 0;
2962 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2963 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2964 int tlb;
2965
2966 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2967 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2968
2969 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2970 cpu_abort(env, "we don't support HES yet\n");
2971 }
2972
2973 return booke206_get_tlbm(env, tlb, ea, esel);
2974 }
2975
2976 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2977 {
2978 env->spr[pidn] = pid;
2979 /* changing PIDs mean we're in a different address space now */
2980 tlb_flush(env, 1);
2981 }
2982
2983 void helper_booke206_tlbwe(CPUPPCState *env)
2984 {
2985 uint32_t tlbncfg, tlbn;
2986 ppcmas_tlb_t *tlb;
2987 uint32_t size_tlb, size_ps;
2988 target_ulong mask;
2989
2990
2991 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2992 case MAS0_WQ_ALWAYS:
2993 /* good to go, write that entry */
2994 break;
2995 case MAS0_WQ_COND:
2996 /* XXX check if reserved */
2997 if (0) {
2998 return;
2999 }
3000 break;
3001 case MAS0_WQ_CLR_RSRV:
3002 /* XXX clear entry */
3003 return;
3004 default:
3005 /* no idea what to do */
3006 return;
3007 }
3008
3009 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
3010 !msr_gs) {
3011 /* XXX we don't support direct LRAT setting yet */
3012 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
3013 return;
3014 }
3015
3016 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
3017 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
3018
3019 tlb = booke206_cur_tlb(env);
3020
3021 if (!tlb) {
3022 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
3023 POWERPC_EXCP_INVAL |
3024 POWERPC_EXCP_INVAL_INVAL);
3025 }
3026
3027 /* check that we support the targeted size */
3028 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
3029 size_ps = booke206_tlbnps(env, tlbn);
3030 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
3031 !(size_ps & (1 << size_tlb))) {
3032 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
3033 POWERPC_EXCP_INVAL |
3034 POWERPC_EXCP_INVAL_INVAL);
3035 }
3036
3037 if (msr_gs) {
3038 cpu_abort(env, "missing HV implementation\n");
3039 }
3040 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
3041 env->spr[SPR_BOOKE_MAS3];
3042 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
3043
3044 /* MAV 1.0 only */
3045 if (!(tlbncfg & TLBnCFG_AVAIL)) {
3046 /* force !AVAIL TLB entries to correct page size */
3047 tlb->mas1 &= ~MAS1_TSIZE_MASK;
3048 /* XXX can be configured in MMUCSR0 */
3049 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
3050 }
3051
3052 /* Make a mask from TLB size to discard invalid bits in EPN field */
3053 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
3054 /* Add a mask for page attributes */
3055 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
3056
3057 if (!msr_cm) {
3058 /* Executing a tlbwe instruction in 32-bit mode will set
3059 * bits 0:31 of the TLB EPN field to zero.
3060 */
3061 mask &= 0xffffffff;
3062 }
3063
3064 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
3065
3066 if (!(tlbncfg & TLBnCFG_IPROT)) {
3067 /* no IPROT supported by TLB */
3068 tlb->mas1 &= ~MAS1_IPROT;
3069 }
3070
3071 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
3072 tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
3073 } else {
3074 tlb_flush(env, 1);
3075 }
3076 }
3077
3078 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
3079 {
3080 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
3081 int way = booke206_tlbm_to_way(env, tlb);
3082
3083 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
3084 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
3085 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
3086
3087 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
3088 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
3089 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
3090 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
3091 }
3092
3093 void helper_booke206_tlbre(CPUPPCState *env)
3094 {
3095 ppcmas_tlb_t *tlb = NULL;
3096
3097 tlb = booke206_cur_tlb(env);
3098 if (!tlb) {
3099 env->spr[SPR_BOOKE_MAS1] = 0;
3100 } else {
3101 booke206_tlb_to_mas(env, tlb);
3102 }
3103 }
3104
3105 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
3106 {
3107 ppcmas_tlb_t *tlb = NULL;
3108 int i, j;
3109 hwaddr raddr;
3110 uint32_t spid, sas;
3111
3112 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
3113 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
3114
3115 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
3116 int ways = booke206_tlb_ways(env, i);
3117
3118 for (j = 0; j < ways; j++) {
3119 tlb = booke206_get_tlbm(env, i, address, j);
3120
3121 if (!tlb) {
3122 continue;
3123 }
3124
3125 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
3126 continue;
3127 }
3128
3129 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
3130 continue;
3131 }
3132
3133 booke206_tlb_to_mas(env, tlb);
3134 return;
3135 }
3136 }
3137
3138 /* no entry found, fill with defaults */
3139 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
3140 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
3141 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
3142 env->spr[SPR_BOOKE_MAS3] = 0;
3143 env->spr[SPR_BOOKE_MAS7] = 0;
3144
3145 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
3146 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
3147 }
3148
3149 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
3150 << MAS1_TID_SHIFT;
3151
3152 /* next victim logic */
3153 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
3154 env->last_way++;
3155 env->last_way &= booke206_tlb_ways(env, 0) - 1;
3156 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
3157 }
3158
3159 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
3160 uint32_t ea)
3161 {
3162 int i;
3163 int ways = booke206_tlb_ways(env, tlbn);
3164 target_ulong mask;
3165
3166 for (i = 0; i < ways; i++) {
3167 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
3168 if (!tlb) {
3169 continue;
3170 }
3171 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
3172 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
3173 !(tlb->mas1 & MAS1_IPROT)) {
3174 tlb->mas1 &= ~MAS1_VALID;
3175 }
3176 }
3177 }
3178
3179 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
3180 {
3181 if (address & 0x4) {
3182 /* flush all entries */
3183 if (address & 0x8) {
3184 /* flush all of TLB1 */
3185 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
3186 } else {
3187 /* flush all of TLB0 */
3188 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
3189 }
3190 return;
3191 }
3192
3193 if (address & 0x8) {
3194 /* flush TLB1 entries */
3195 booke206_invalidate_ea_tlb(env, 1, address);
3196 tlb_flush(env, 1);
3197 } else {
3198 /* flush TLB0 entries */
3199 booke206_invalidate_ea_tlb(env, 0, address);
3200 tlb_flush_page(env, address & MAS2_EPN_MASK);
3201 }
3202 }
3203
3204 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
3205 {
3206 /* XXX missing LPID handling */
3207 booke206_flush_tlb(env, -1, 1);
3208 }
3209
3210 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
3211 {
3212 int i, j;
3213 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
3214 ppcmas_tlb_t *tlb = env->tlb.tlbm;
3215 int tlb_size;
3216
3217 /* XXX missing LPID handling */
3218 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
3219 tlb_size = booke206_tlb_size(env, i);
3220 for (j = 0; j < tlb_size; j++) {
3221 if (!(tlb[j].mas1 & MAS1_IPROT) &&
3222 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
3223 tlb[j].mas1 &= ~MAS1_VALID;
3224 }
3225 }
3226 tlb += booke206_tlb_size(env, i);
3227 }
3228 tlb_flush(env, 1);
3229 }
3230
3231 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
3232 {
3233 int i, j;
3234 ppcmas_tlb_t *tlb;
3235 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
3236 int pid = tid >> MAS6_SPID_SHIFT;
3237 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
3238 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
3239 /* XXX check for unsupported isize and raise an invalid opcode then */
3240 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
3241 /* XXX implement MAV2 handling */
3242 bool mav2 = false;
3243
3244 /* XXX missing LPID handling */
3245 /* flush by pid and ea */
3246 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
3247 int ways = booke206_tlb_ways(env, i);
3248
3249 for (j = 0; j < ways; j++) {
3250 tlb = booke206_get_tlbm(env, i, address, j);
3251 if (!tlb) {
3252 continue;
3253 }
3254 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
3255 (tlb->mas1 & MAS1_IPROT) ||
3256 ((tlb->mas1 & MAS1_IND) != ind) ||
3257 ((tlb->mas8 & MAS8_TGS) != sgs)) {
3258 continue;
3259 }
3260 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
3261 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
3262 continue;
3263 }
3264 /* XXX e500mc doesn't match SAS, but other cores might */
3265 tlb->mas1 &= ~MAS1_VALID;
3266 }
3267 }
3268 tlb_flush(env, 1);
3269 }
3270
3271 void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
3272 {
3273 int flags = 0;
3274
3275 if (type & 2) {
3276 flags |= BOOKE206_FLUSH_TLB1;
3277 }
3278
3279 if (type & 4) {
3280 flags |= BOOKE206_FLUSH_TLB0;
3281 }
3282
3283 booke206_flush_tlb(env, flags, 1);
3284 }
3285 #endif