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