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