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