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