|
|
1.1 root 1: /*
2: * Sparc MMU helpers
3: *
4: * Copyright (c) 2003-2005 Fabrice Bellard
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:
20: #include "cpu.h"
21: #include "trace.h"
1.1.1.2 ! root 22: #include "exec-memory.h"
1.1 root 23:
24: /* Sparc MMU emulation */
25:
26: #if defined(CONFIG_USER_ONLY)
27:
1.1.1.2 ! root 28: int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
1.1 root 29: int mmu_idx)
30: {
31: if (rw & 2) {
32: env1->exception_index = TT_TFAULT;
33: } else {
34: env1->exception_index = TT_DFAULT;
35: }
36: return 1;
37: }
38:
39: #else
40:
41: #ifndef TARGET_SPARC64
42: /*
43: * Sparc V8 Reference MMU (SRMMU)
44: */
45: static const int access_table[8][8] = {
46: { 0, 0, 0, 0, 8, 0, 12, 12 },
47: { 0, 0, 0, 0, 8, 0, 0, 0 },
48: { 8, 8, 0, 0, 0, 8, 12, 12 },
49: { 8, 8, 0, 0, 0, 8, 0, 0 },
50: { 8, 0, 8, 0, 8, 8, 12, 12 },
51: { 8, 0, 8, 0, 8, 0, 8, 0 },
52: { 8, 8, 8, 0, 8, 8, 12, 12 },
53: { 8, 8, 8, 0, 8, 8, 8, 0 }
54: };
55:
56: static const int perm_table[2][8] = {
57: {
58: PAGE_READ,
59: PAGE_READ | PAGE_WRITE,
60: PAGE_READ | PAGE_EXEC,
61: PAGE_READ | PAGE_WRITE | PAGE_EXEC,
62: PAGE_EXEC,
63: PAGE_READ | PAGE_WRITE,
64: PAGE_READ | PAGE_EXEC,
65: PAGE_READ | PAGE_WRITE | PAGE_EXEC
66: },
67: {
68: PAGE_READ,
69: PAGE_READ | PAGE_WRITE,
70: PAGE_READ | PAGE_EXEC,
71: PAGE_READ | PAGE_WRITE | PAGE_EXEC,
72: PAGE_EXEC,
73: PAGE_READ,
74: 0,
75: 0,
76: }
77: };
78:
1.1.1.2 ! root 79: static int get_physical_address(CPUSPARCState *env, target_phys_addr_t *physical,
1.1 root 80: int *prot, int *access_index,
81: target_ulong address, int rw, int mmu_idx,
82: target_ulong *page_size)
83: {
84: int access_perms = 0;
85: target_phys_addr_t pde_ptr;
86: uint32_t pde;
87: int error_code = 0, is_dirty, is_user;
88: unsigned long page_offset;
89:
90: is_user = mmu_idx == MMU_USER_IDX;
91:
92: if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
93: *page_size = TARGET_PAGE_SIZE;
94: /* Boot mode: instruction fetches are taken from PROM */
95: if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
96: *physical = env->prom_addr | (address & 0x7ffffULL);
97: *prot = PAGE_READ | PAGE_EXEC;
98: return 0;
99: }
100: *physical = address;
101: *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
102: return 0;
103: }
104:
105: *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1);
106: *physical = 0xffffffffffff0000ULL;
107:
108: /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
109: /* Context base + context number */
110: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
111: pde = ldl_phys(pde_ptr);
112:
113: /* Ctx pde */
114: switch (pde & PTE_ENTRYTYPE_MASK) {
115: default:
116: case 0: /* Invalid */
117: return 1 << 2;
118: case 2: /* L0 PTE, maybe should not happen? */
119: case 3: /* Reserved */
120: return 4 << 2;
121: case 1: /* L0 PDE */
122: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
123: pde = ldl_phys(pde_ptr);
124:
125: switch (pde & PTE_ENTRYTYPE_MASK) {
126: default:
127: case 0: /* Invalid */
128: return (1 << 8) | (1 << 2);
129: case 3: /* Reserved */
130: return (1 << 8) | (4 << 2);
131: case 1: /* L1 PDE */
132: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
133: pde = ldl_phys(pde_ptr);
134:
135: switch (pde & PTE_ENTRYTYPE_MASK) {
136: default:
137: case 0: /* Invalid */
138: return (2 << 8) | (1 << 2);
139: case 3: /* Reserved */
140: return (2 << 8) | (4 << 2);
141: case 1: /* L2 PDE */
142: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
143: pde = ldl_phys(pde_ptr);
144:
145: switch (pde & PTE_ENTRYTYPE_MASK) {
146: default:
147: case 0: /* Invalid */
148: return (3 << 8) | (1 << 2);
149: case 1: /* PDE, should not happen */
150: case 3: /* Reserved */
151: return (3 << 8) | (4 << 2);
152: case 2: /* L3 PTE */
1.1.1.2 ! root 153: page_offset = 0;
1.1 root 154: }
155: *page_size = TARGET_PAGE_SIZE;
156: break;
157: case 2: /* L2 PTE */
1.1.1.2 ! root 158: page_offset = address & 0x3f000;
1.1 root 159: *page_size = 0x40000;
160: }
161: break;
162: case 2: /* L1 PTE */
1.1.1.2 ! root 163: page_offset = address & 0xfff000;
1.1 root 164: *page_size = 0x1000000;
165: }
166: }
167:
168: /* check access */
169: access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
170: error_code = access_table[*access_index][access_perms];
171: if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) {
172: return error_code;
173: }
174:
175: /* update page modified and dirty bits */
176: is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
177: if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
178: pde |= PG_ACCESSED_MASK;
179: if (is_dirty) {
180: pde |= PG_MODIFIED_MASK;
181: }
182: stl_phys_notdirty(pde_ptr, pde);
183: }
184:
185: /* the page can be put in the TLB */
186: *prot = perm_table[is_user][access_perms];
187: if (!(pde & PG_MODIFIED_MASK)) {
188: /* only set write access if already dirty... otherwise wait
189: for dirty access */
190: *prot &= ~PAGE_WRITE;
191: }
192:
193: /* Even if large ptes, we map only one 4KB page in the cache to
194: avoid filling it too fast */
195: *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
196: return error_code;
197: }
198:
199: /* Perform address translation */
1.1.1.2 ! root 200: int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
1.1 root 201: int mmu_idx)
202: {
203: target_phys_addr_t paddr;
204: target_ulong vaddr;
205: target_ulong page_size;
206: int error_code = 0, prot, access_index;
207:
1.1.1.2 ! root 208: address &= TARGET_PAGE_MASK;
1.1 root 209: error_code = get_physical_address(env, &paddr, &prot, &access_index,
210: address, rw, mmu_idx, &page_size);
1.1.1.2 ! root 211: vaddr = address;
1.1 root 212: if (error_code == 0) {
213: #ifdef DEBUG_MMU
214: printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
215: TARGET_FMT_lx "\n", address, paddr, vaddr);
216: #endif
217: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
218: return 0;
219: }
220:
221: if (env->mmuregs[3]) { /* Fault status register */
222: env->mmuregs[3] = 1; /* overflow (not read before another fault) */
223: }
224: env->mmuregs[3] |= (access_index << 5) | error_code | 2;
225: env->mmuregs[4] = address; /* Fault address register */
226:
227: if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
228: /* No fault mode: if a mapping is available, just override
229: permissions. If no mapping is available, redirect accesses to
230: neverland. Fake/overridden mappings will be flushed when
231: switching to normal mode. */
232: prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
233: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
234: return 0;
235: } else {
236: if (rw & 2) {
237: env->exception_index = TT_TFAULT;
238: } else {
239: env->exception_index = TT_DFAULT;
240: }
241: return 1;
242: }
243: }
244:
1.1.1.2 ! root 245: target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
1.1 root 246: {
247: target_phys_addr_t pde_ptr;
248: uint32_t pde;
249:
250: /* Context base + context number */
251: pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
252: (env->mmuregs[2] << 2);
253: pde = ldl_phys(pde_ptr);
254:
255: switch (pde & PTE_ENTRYTYPE_MASK) {
256: default:
257: case 0: /* Invalid */
258: case 2: /* PTE, maybe should not happen? */
259: case 3: /* Reserved */
260: return 0;
261: case 1: /* L1 PDE */
262: if (mmulev == 3) {
263: return pde;
264: }
265: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
266: pde = ldl_phys(pde_ptr);
267:
268: switch (pde & PTE_ENTRYTYPE_MASK) {
269: default:
270: case 0: /* Invalid */
271: case 3: /* Reserved */
272: return 0;
273: case 2: /* L1 PTE */
274: return pde;
275: case 1: /* L2 PDE */
276: if (mmulev == 2) {
277: return pde;
278: }
279: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
280: pde = ldl_phys(pde_ptr);
281:
282: switch (pde & PTE_ENTRYTYPE_MASK) {
283: default:
284: case 0: /* Invalid */
285: case 3: /* Reserved */
286: return 0;
287: case 2: /* L2 PTE */
288: return pde;
289: case 1: /* L3 PDE */
290: if (mmulev == 1) {
291: return pde;
292: }
293: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
294: pde = ldl_phys(pde_ptr);
295:
296: switch (pde & PTE_ENTRYTYPE_MASK) {
297: default:
298: case 0: /* Invalid */
299: case 1: /* PDE, should not happen */
300: case 3: /* Reserved */
301: return 0;
302: case 2: /* L3 PTE */
303: return pde;
304: }
305: }
306: }
307: }
308: return 0;
309: }
310:
1.1.1.2 ! root 311: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
1.1 root 312: {
313: target_ulong va, va1, va2;
314: unsigned int n, m, o;
315: target_phys_addr_t pde_ptr, pa;
316: uint32_t pde;
317:
318: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
319: pde = ldl_phys(pde_ptr);
320: (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
321: (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
322: for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
323: pde = mmu_probe(env, va, 2);
324: if (pde) {
325: pa = cpu_get_phys_page_debug(env, va);
326: (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
327: " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
328: for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
329: pde = mmu_probe(env, va1, 1);
330: if (pde) {
331: pa = cpu_get_phys_page_debug(env, va1);
332: (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
333: TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
334: va1, pa, pde);
335: for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
336: pde = mmu_probe(env, va2, 0);
337: if (pde) {
338: pa = cpu_get_phys_page_debug(env, va2);
339: (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
340: TARGET_FMT_plx " PTE: "
341: TARGET_FMT_lx "\n",
342: va2, pa, pde);
343: }
344: }
345: }
346: }
347: }
348: }
349: }
350:
351: /* Gdb expects all registers windows to be flushed in ram. This function handles
352: * reads (and only reads) in stack frames as if windows were flushed. We assume
353: * that the sparc ABI is followed.
354: */
1.1.1.2 ! root 355: int target_memory_rw_debug(CPUSPARCState *env, target_ulong addr,
1.1 root 356: uint8_t *buf, int len, int is_write)
357: {
358: int i;
359: int len1;
360: int cwp = env->cwp;
361:
362: if (!is_write) {
363: for (i = 0; i < env->nwindows; i++) {
364: int off;
365: target_ulong fp = env->regbase[cwp * 16 + 22];
366:
367: /* Assume fp == 0 means end of frame. */
368: if (fp == 0) {
369: break;
370: }
371:
372: cwp = cpu_cwp_inc(env, cwp + 1);
373:
374: /* Invalid window ? */
375: if (env->wim & (1 << cwp)) {
376: break;
377: }
378:
379: /* According to the ABI, the stack is growing downward. */
380: if (addr + len < fp) {
381: break;
382: }
383:
384: /* Not in this frame. */
385: if (addr > fp + 64) {
386: continue;
387: }
388:
389: /* Handle access before this window. */
390: if (addr < fp) {
391: len1 = fp - addr;
392: if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
393: return -1;
394: }
395: addr += len1;
396: len -= len1;
397: buf += len1;
398: }
399:
400: /* Access byte per byte to registers. Not very efficient but speed
401: * is not critical.
402: */
403: off = addr - fp;
404: len1 = 64 - off;
405:
406: if (len1 > len) {
407: len1 = len;
408: }
409:
410: for (; len1; len1--) {
411: int reg = cwp * 16 + 8 + (off >> 2);
412: union {
413: uint32_t v;
414: uint8_t c[4];
415: } u;
416: u.v = cpu_to_be32(env->regbase[reg]);
417: *buf++ = u.c[off & 3];
418: addr++;
419: len--;
420: off++;
421: }
422:
423: if (len == 0) {
424: return 0;
425: }
426: }
427: }
428: return cpu_memory_rw_debug(env, addr, buf, len, is_write);
429: }
430:
431: #else /* !TARGET_SPARC64 */
432:
433: /* 41 bit physical address space */
434: static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
435: {
436: return x & 0x1ffffffffffULL;
437: }
438:
439: /*
440: * UltraSparc IIi I/DMMUs
441: */
442:
443: /* Returns true if TTE tag is valid and matches virtual address value
444: in context requires virtual address mask value calculated from TTE
445: entry size */
446: static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
447: uint64_t address, uint64_t context,
448: target_phys_addr_t *physical)
449: {
450: uint64_t mask;
451:
452: switch (TTE_PGSIZE(tlb->tte)) {
453: default:
454: case 0x0: /* 8k */
455: mask = 0xffffffffffffe000ULL;
456: break;
457: case 0x1: /* 64k */
458: mask = 0xffffffffffff0000ULL;
459: break;
460: case 0x2: /* 512k */
461: mask = 0xfffffffffff80000ULL;
462: break;
463: case 0x3: /* 4M */
464: mask = 0xffffffffffc00000ULL;
465: break;
466: }
467:
468: /* valid, context match, virtual address match? */
469: if (TTE_IS_VALID(tlb->tte) &&
470: (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
471: && compare_masked(address, tlb->tag, mask)) {
472: /* decode physical address */
473: *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
474: return 1;
475: }
476:
477: return 0;
478: }
479:
1.1.1.2 ! root 480: static int get_physical_address_data(CPUSPARCState *env,
1.1 root 481: target_phys_addr_t *physical, int *prot,
482: target_ulong address, int rw, int mmu_idx)
483: {
484: unsigned int i;
485: uint64_t context;
486: uint64_t sfsr = 0;
487:
488: int is_user = (mmu_idx == MMU_USER_IDX ||
489: mmu_idx == MMU_USER_SECONDARY_IDX);
490:
491: if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
492: *physical = ultrasparc_truncate_physical(address);
493: *prot = PAGE_READ | PAGE_WRITE;
494: return 0;
495: }
496:
497: switch (mmu_idx) {
498: case MMU_USER_IDX:
499: case MMU_KERNEL_IDX:
500: context = env->dmmu.mmu_primary_context & 0x1fff;
501: sfsr |= SFSR_CT_PRIMARY;
502: break;
503: case MMU_USER_SECONDARY_IDX:
504: case MMU_KERNEL_SECONDARY_IDX:
505: context = env->dmmu.mmu_secondary_context & 0x1fff;
506: sfsr |= SFSR_CT_SECONDARY;
507: break;
508: case MMU_NUCLEUS_IDX:
509: sfsr |= SFSR_CT_NUCLEUS;
510: /* FALLTHRU */
511: default:
512: context = 0;
513: break;
514: }
515:
516: if (rw == 1) {
517: sfsr |= SFSR_WRITE_BIT;
518: } else if (rw == 4) {
519: sfsr |= SFSR_NF_BIT;
520: }
521:
522: for (i = 0; i < 64; i++) {
523: /* ctx match, vaddr match, valid? */
524: if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
525: int do_fault = 0;
526:
527: /* access ok? */
528: /* multiple bits in SFSR.FT may be set on TT_DFAULT */
529: if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
530: do_fault = 1;
531: sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
532: trace_mmu_helper_dfault(address, context, mmu_idx, env->tl);
533: }
534: if (rw == 4) {
535: if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
536: do_fault = 1;
537: sfsr |= SFSR_FT_NF_E_BIT;
538: }
539: } else {
540: if (TTE_IS_NFO(env->dtlb[i].tte)) {
541: do_fault = 1;
542: sfsr |= SFSR_FT_NFO_BIT;
543: }
544: }
545:
546: if (do_fault) {
547: /* faults above are reported with TT_DFAULT. */
548: env->exception_index = TT_DFAULT;
549: } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
550: do_fault = 1;
551: env->exception_index = TT_DPROT;
552:
553: trace_mmu_helper_dprot(address, context, mmu_idx, env->tl);
554: }
555:
556: if (!do_fault) {
557: *prot = PAGE_READ;
558: if (TTE_IS_W_OK(env->dtlb[i].tte)) {
559: *prot |= PAGE_WRITE;
560: }
561:
562: TTE_SET_USED(env->dtlb[i].tte);
563:
564: return 0;
565: }
566:
567: if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
568: sfsr |= SFSR_OW_BIT; /* overflow (not read before
569: another fault) */
570: }
571:
572: if (env->pstate & PS_PRIV) {
573: sfsr |= SFSR_PR_BIT;
574: }
575:
576: /* FIXME: ASI field in SFSR must be set */
577: env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
578:
579: env->dmmu.sfar = address; /* Fault address register */
580:
581: env->dmmu.tag_access = (address & ~0x1fffULL) | context;
582:
583: return 1;
584: }
585: }
586:
587: trace_mmu_helper_dmiss(address, context);
588:
589: /*
590: * On MMU misses:
591: * - UltraSPARC IIi: SFSR and SFAR unmodified
592: * - JPS1: SFAR updated and some fields of SFSR updated
593: */
594: env->dmmu.tag_access = (address & ~0x1fffULL) | context;
595: env->exception_index = TT_DMISS;
596: return 1;
597: }
598:
1.1.1.2 ! root 599: static int get_physical_address_code(CPUSPARCState *env,
1.1 root 600: target_phys_addr_t *physical, int *prot,
601: target_ulong address, int mmu_idx)
602: {
603: unsigned int i;
604: uint64_t context;
605:
606: int is_user = (mmu_idx == MMU_USER_IDX ||
607: mmu_idx == MMU_USER_SECONDARY_IDX);
608:
609: if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
610: /* IMMU disabled */
611: *physical = ultrasparc_truncate_physical(address);
612: *prot = PAGE_EXEC;
613: return 0;
614: }
615:
616: if (env->tl == 0) {
617: /* PRIMARY context */
618: context = env->dmmu.mmu_primary_context & 0x1fff;
619: } else {
620: /* NUCLEUS context */
621: context = 0;
622: }
623:
624: for (i = 0; i < 64; i++) {
625: /* ctx match, vaddr match, valid? */
626: if (ultrasparc_tag_match(&env->itlb[i],
627: address, context, physical)) {
628: /* access ok? */
629: if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
630: /* Fault status register */
631: if (env->immu.sfsr & SFSR_VALID_BIT) {
632: env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
633: another fault) */
634: } else {
635: env->immu.sfsr = 0;
636: }
637: if (env->pstate & PS_PRIV) {
638: env->immu.sfsr |= SFSR_PR_BIT;
639: }
640: if (env->tl > 0) {
641: env->immu.sfsr |= SFSR_CT_NUCLEUS;
642: }
643:
644: /* FIXME: ASI field in SFSR must be set */
645: env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
646: env->exception_index = TT_TFAULT;
647:
648: env->immu.tag_access = (address & ~0x1fffULL) | context;
649:
650: trace_mmu_helper_tfault(address, context);
651:
652: return 1;
653: }
654: *prot = PAGE_EXEC;
655: TTE_SET_USED(env->itlb[i].tte);
656: return 0;
657: }
658: }
659:
660: trace_mmu_helper_tmiss(address, context);
661:
662: /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
663: env->immu.tag_access = (address & ~0x1fffULL) | context;
664: env->exception_index = TT_TMISS;
665: return 1;
666: }
667:
1.1.1.2 ! root 668: static int get_physical_address(CPUSPARCState *env, target_phys_addr_t *physical,
1.1 root 669: int *prot, int *access_index,
670: target_ulong address, int rw, int mmu_idx,
671: target_ulong *page_size)
672: {
673: /* ??? We treat everything as a small page, then explicitly flush
674: everything when an entry is evicted. */
675: *page_size = TARGET_PAGE_SIZE;
676:
677: /* safety net to catch wrong softmmu index use from dynamic code */
678: if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
679: if (rw == 2) {
680: trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx,
681: env->dmmu.mmu_primary_context,
682: env->dmmu.mmu_secondary_context,
683: address);
684: } else {
685: trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx,
686: env->dmmu.mmu_primary_context,
687: env->dmmu.mmu_secondary_context,
688: address);
689: }
690: }
691:
692: if (rw == 2) {
693: return get_physical_address_code(env, physical, prot, address,
694: mmu_idx);
695: } else {
696: return get_physical_address_data(env, physical, prot, address, rw,
697: mmu_idx);
698: }
699: }
700:
701: /* Perform address translation */
1.1.1.2 ! root 702: int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
1.1 root 703: int mmu_idx)
704: {
1.1.1.2 ! root 705: target_ulong vaddr;
1.1 root 706: target_phys_addr_t paddr;
707: target_ulong page_size;
708: int error_code = 0, prot, access_index;
709:
1.1.1.2 ! root 710: address &= TARGET_PAGE_MASK;
1.1 root 711: error_code = get_physical_address(env, &paddr, &prot, &access_index,
712: address, rw, mmu_idx, &page_size);
713: if (error_code == 0) {
1.1.1.2 ! root 714: vaddr = address;
1.1 root 715:
716: trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl,
717: env->dmmu.mmu_primary_context,
718: env->dmmu.mmu_secondary_context);
719:
720: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
721: return 0;
722: }
723: /* XXX */
724: return 1;
725: }
726:
1.1.1.2 ! root 727: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
1.1 root 728: {
729: unsigned int i;
730: const char *mask;
731:
732: (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
733: PRId64 "\n",
734: env->dmmu.mmu_primary_context,
735: env->dmmu.mmu_secondary_context);
736: if ((env->lsu & DMMU_E) == 0) {
737: (*cpu_fprintf)(f, "DMMU disabled\n");
738: } else {
739: (*cpu_fprintf)(f, "DMMU dump\n");
740: for (i = 0; i < 64; i++) {
741: switch (TTE_PGSIZE(env->dtlb[i].tte)) {
742: default:
743: case 0x0:
744: mask = " 8k";
745: break;
746: case 0x1:
747: mask = " 64k";
748: break;
749: case 0x2:
750: mask = "512k";
751: break;
752: case 0x3:
753: mask = " 4M";
754: break;
755: }
756: if (TTE_IS_VALID(env->dtlb[i].tte)) {
757: (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
758: ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
759: i,
760: env->dtlb[i].tag & (uint64_t)~0x1fffULL,
761: TTE_PA(env->dtlb[i].tte),
762: mask,
763: TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
764: TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
765: TTE_IS_LOCKED(env->dtlb[i].tte) ?
766: "locked" : "unlocked",
767: env->dtlb[i].tag & (uint64_t)0x1fffULL,
768: TTE_IS_GLOBAL(env->dtlb[i].tte) ?
769: "global" : "local");
770: }
771: }
772: }
773: if ((env->lsu & IMMU_E) == 0) {
774: (*cpu_fprintf)(f, "IMMU disabled\n");
775: } else {
776: (*cpu_fprintf)(f, "IMMU dump\n");
777: for (i = 0; i < 64; i++) {
778: switch (TTE_PGSIZE(env->itlb[i].tte)) {
779: default:
780: case 0x0:
781: mask = " 8k";
782: break;
783: case 0x1:
784: mask = " 64k";
785: break;
786: case 0x2:
787: mask = "512k";
788: break;
789: case 0x3:
790: mask = " 4M";
791: break;
792: }
793: if (TTE_IS_VALID(env->itlb[i].tte)) {
794: (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
795: ", %s, %s, %s, ctx %" PRId64 " %s\n",
796: i,
797: env->itlb[i].tag & (uint64_t)~0x1fffULL,
798: TTE_PA(env->itlb[i].tte),
799: mask,
800: TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
801: TTE_IS_LOCKED(env->itlb[i].tte) ?
802: "locked" : "unlocked",
803: env->itlb[i].tag & (uint64_t)0x1fffULL,
804: TTE_IS_GLOBAL(env->itlb[i].tte) ?
805: "global" : "local");
806: }
807: }
808: }
809: }
810:
811: #endif /* TARGET_SPARC64 */
812:
1.1.1.2 ! root 813: static int cpu_sparc_get_phys_page(CPUSPARCState *env, target_phys_addr_t *phys,
1.1 root 814: target_ulong addr, int rw, int mmu_idx)
815: {
816: target_ulong page_size;
817: int prot, access_index;
818:
819: return get_physical_address(env, phys, &prot, &access_index, addr, rw,
820: mmu_idx, &page_size);
821: }
822:
823: #if defined(TARGET_SPARC64)
1.1.1.2 ! root 824: target_phys_addr_t cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
1.1 root 825: int mmu_idx)
826: {
827: target_phys_addr_t phys_addr;
828:
829: if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
830: return -1;
831: }
832: return phys_addr;
833: }
834: #endif
835:
1.1.1.2 ! root 836: target_phys_addr_t cpu_get_phys_page_debug(CPUSPARCState *env, target_ulong addr)
1.1 root 837: {
838: target_phys_addr_t phys_addr;
839: int mmu_idx = cpu_mmu_index(env);
1.1.1.2 ! root 840: MemoryRegionSection section;
1.1 root 841:
842: if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
843: if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
844: return -1;
845: }
846: }
1.1.1.2 ! root 847: section = memory_region_find(get_system_memory(), phys_addr, 1);
! 848: if (!section.size) {
1.1 root 849: return -1;
850: }
851: return phys_addr;
852: }
853: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.