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