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