|
|
1.1 root 1: /*
2: * sparc 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, write to the Free Software
18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19: */
20: #include <stdarg.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24: #include <inttypes.h>
25: #include <signal.h>
26: #include <assert.h>
27:
28: #include "cpu.h"
29: #include "exec-all.h"
30:
31: //#define DEBUG_MMU
32:
33: /* Sparc MMU emulation */
34:
35: /* thread support */
36:
37: spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
38:
39: void cpu_lock(void)
40: {
41: spin_lock(&global_cpu_lock);
42: }
43:
44: void cpu_unlock(void)
45: {
46: spin_unlock(&global_cpu_lock);
47: }
48:
49: #if defined(CONFIG_USER_ONLY)
50:
51: int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
52: int is_user, int is_softmmu)
53: {
54: if (rw & 2)
55: env->exception_index = TT_TFAULT;
56: else
57: env->exception_index = TT_DFAULT;
58: return 1;
59: }
60:
61: #else
62:
63: #ifndef TARGET_SPARC64
64: /*
65: * Sparc V8 Reference MMU (SRMMU)
66: */
67: static const int access_table[8][8] = {
68: { 0, 0, 0, 0, 2, 0, 3, 3 },
69: { 0, 0, 0, 0, 2, 0, 0, 0 },
70: { 2, 2, 0, 0, 0, 2, 3, 3 },
71: { 2, 2, 0, 0, 0, 2, 0, 0 },
72: { 2, 0, 2, 0, 2, 2, 3, 3 },
73: { 2, 0, 2, 0, 2, 0, 2, 0 },
74: { 2, 2, 2, 0, 2, 2, 3, 3 },
75: { 2, 2, 2, 0, 2, 2, 2, 0 }
76: };
77:
1.1.1.2 ! root 78: static const int perm_table[2][8] = {
! 79: {
! 80: PAGE_READ,
! 81: PAGE_READ | PAGE_WRITE,
! 82: PAGE_READ | PAGE_EXEC,
! 83: PAGE_READ | PAGE_WRITE | PAGE_EXEC,
! 84: PAGE_EXEC,
! 85: PAGE_READ | PAGE_WRITE,
! 86: PAGE_READ | PAGE_EXEC,
! 87: PAGE_READ | PAGE_WRITE | PAGE_EXEC
! 88: },
! 89: {
! 90: PAGE_READ,
! 91: PAGE_READ | PAGE_WRITE,
! 92: PAGE_READ | PAGE_EXEC,
! 93: PAGE_READ | PAGE_WRITE | PAGE_EXEC,
! 94: PAGE_EXEC,
! 95: PAGE_READ,
! 96: 0,
! 97: 0,
! 98: }
1.1 root 99: };
100:
101: int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot,
102: int *access_index, target_ulong address, int rw,
103: int is_user)
104: {
105: int access_perms = 0;
106: target_phys_addr_t pde_ptr;
107: uint32_t pde;
108: target_ulong virt_addr;
109: int error_code = 0, is_dirty;
110: unsigned long page_offset;
111:
112: virt_addr = address & TARGET_PAGE_MASK;
113: if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
114: *physical = address;
1.1.1.2 ! root 115: *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1 root 116: return 0;
117: }
118:
119: *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
120: *physical = 0xfffff000;
121:
122: /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
123: /* Context base + context number */
124: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
125: pde = ldl_phys(pde_ptr);
126:
127: /* Ctx pde */
128: switch (pde & PTE_ENTRYTYPE_MASK) {
129: default:
130: case 0: /* Invalid */
131: return 1 << 2;
132: case 2: /* L0 PTE, maybe should not happen? */
133: case 3: /* Reserved */
134: return 4 << 2;
135: case 1: /* L0 PDE */
136: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
137: pde = ldl_phys(pde_ptr);
138:
139: switch (pde & PTE_ENTRYTYPE_MASK) {
140: default:
141: case 0: /* Invalid */
142: return (1 << 8) | (1 << 2);
143: case 3: /* Reserved */
144: return (1 << 8) | (4 << 2);
145: case 1: /* L1 PDE */
146: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
147: pde = ldl_phys(pde_ptr);
148:
149: switch (pde & PTE_ENTRYTYPE_MASK) {
150: default:
151: case 0: /* Invalid */
152: return (2 << 8) | (1 << 2);
153: case 3: /* Reserved */
154: return (2 << 8) | (4 << 2);
155: case 1: /* L2 PDE */
156: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
157: pde = ldl_phys(pde_ptr);
158:
159: switch (pde & PTE_ENTRYTYPE_MASK) {
160: default:
161: case 0: /* Invalid */
162: return (3 << 8) | (1 << 2);
163: case 1: /* PDE, should not happen */
164: case 3: /* Reserved */
165: return (3 << 8) | (4 << 2);
166: case 2: /* L3 PTE */
167: virt_addr = address & TARGET_PAGE_MASK;
168: page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
169: }
170: break;
171: case 2: /* L2 PTE */
172: virt_addr = address & ~0x3ffff;
173: page_offset = address & 0x3ffff;
174: }
175: break;
176: case 2: /* L1 PTE */
177: virt_addr = address & ~0xffffff;
178: page_offset = address & 0xffffff;
179: }
180: }
181:
182: /* update page modified and dirty bits */
183: is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
184: if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
185: pde |= PG_ACCESSED_MASK;
186: if (is_dirty)
187: pde |= PG_MODIFIED_MASK;
188: stl_phys_notdirty(pde_ptr, pde);
189: }
190: /* check access */
191: access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
192: error_code = access_table[*access_index][access_perms];
193: if (error_code && !(env->mmuregs[0] & MMU_NF))
194: return error_code;
195:
196: /* the page can be put in the TLB */
1.1.1.2 ! root 197: *prot = perm_table[is_user][access_perms];
! 198: if (!(pde & PG_MODIFIED_MASK)) {
1.1 root 199: /* only set write access if already dirty... otherwise wait
200: for dirty access */
1.1.1.2 ! root 201: *prot &= ~PAGE_WRITE;
1.1 root 202: }
203:
204: /* Even if large ptes, we map only one 4KB page in the cache to
205: avoid filling it too fast */
206: *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
207: return error_code;
208: }
209:
210: /* Perform address translation */
211: int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
212: int is_user, int is_softmmu)
213: {
214: target_phys_addr_t paddr;
215: unsigned long vaddr;
216: int error_code = 0, prot, ret = 0, access_index;
217:
218: error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
219: if (error_code == 0) {
1.1.1.2 ! root 220: vaddr = address & TARGET_PAGE_MASK;
! 221: paddr &= TARGET_PAGE_MASK;
! 222: #ifdef DEBUG_MMU
! 223: printf("Translate at 0x%lx -> 0x%lx, vaddr 0x%lx\n", (long)address, (long)paddr, (long)vaddr);
! 224: #endif
! 225: ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
1.1 root 226: return ret;
227: }
228:
229: if (env->mmuregs[3]) /* Fault status register */
230: env->mmuregs[3] = 1; /* overflow (not read before another fault) */
231: env->mmuregs[3] |= (access_index << 5) | error_code | 2;
232: env->mmuregs[4] = address; /* Fault address register */
233:
234: if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
235: // No fault mode: if a mapping is available, just override
236: // permissions. If no mapping is available, redirect accesses to
237: // neverland. Fake/overridden mappings will be flushed when
238: // switching to normal mode.
239: vaddr = address & TARGET_PAGE_MASK;
1.1.1.2 ! root 240: prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
! 241: ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
1.1 root 242: return ret;
243: } else {
244: if (rw & 2)
245: env->exception_index = TT_TFAULT;
246: else
247: env->exception_index = TT_DFAULT;
248: return 1;
249: }
250: }
1.1.1.2 ! root 251:
! 252: target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
! 253: {
! 254: target_phys_addr_t pde_ptr;
! 255: uint32_t pde;
! 256:
! 257: /* Context base + context number */
! 258: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
! 259: pde = ldl_phys(pde_ptr);
! 260:
! 261: switch (pde & PTE_ENTRYTYPE_MASK) {
! 262: default:
! 263: case 0: /* Invalid */
! 264: case 2: /* PTE, maybe should not happen? */
! 265: case 3: /* Reserved */
! 266: return 0;
! 267: case 1: /* L1 PDE */
! 268: if (mmulev == 3)
! 269: return pde;
! 270: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
! 271: pde = ldl_phys(pde_ptr);
! 272:
! 273: switch (pde & PTE_ENTRYTYPE_MASK) {
! 274: default:
! 275: case 0: /* Invalid */
! 276: case 3: /* Reserved */
! 277: return 0;
! 278: case 2: /* L1 PTE */
! 279: return pde;
! 280: case 1: /* L2 PDE */
! 281: if (mmulev == 2)
! 282: return pde;
! 283: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
! 284: pde = ldl_phys(pde_ptr);
! 285:
! 286: switch (pde & PTE_ENTRYTYPE_MASK) {
! 287: default:
! 288: case 0: /* Invalid */
! 289: case 3: /* Reserved */
! 290: return 0;
! 291: case 2: /* L2 PTE */
! 292: return pde;
! 293: case 1: /* L3 PDE */
! 294: if (mmulev == 1)
! 295: return pde;
! 296: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
! 297: pde = ldl_phys(pde_ptr);
! 298:
! 299: switch (pde & PTE_ENTRYTYPE_MASK) {
! 300: default:
! 301: case 0: /* Invalid */
! 302: case 1: /* PDE, should not happen */
! 303: case 3: /* Reserved */
! 304: return 0;
! 305: case 2: /* L3 PTE */
! 306: return pde;
! 307: }
! 308: }
! 309: }
! 310: }
! 311: return 0;
! 312: }
! 313:
! 314: #ifdef DEBUG_MMU
! 315: void dump_mmu(CPUState *env)
! 316: {
! 317: target_ulong va, va1, va2;
! 318: unsigned int n, m, o;
! 319: target_phys_addr_t pde_ptr, pa;
! 320: uint32_t pde;
! 321:
! 322: printf("MMU dump:\n");
! 323: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
! 324: pde = ldl_phys(pde_ptr);
! 325: printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
! 326: for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
! 327: pde_ptr = mmu_probe(env, va, 2);
! 328: if (pde_ptr) {
! 329: pa = cpu_get_phys_page_debug(env, va);
! 330: printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr);
! 331: for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
! 332: pde_ptr = mmu_probe(env, va1, 1);
! 333: if (pde_ptr) {
! 334: pa = cpu_get_phys_page_debug(env, va1);
! 335: printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr);
! 336: for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
! 337: pde_ptr = mmu_probe(env, va2, 0);
! 338: if (pde_ptr) {
! 339: pa = cpu_get_phys_page_debug(env, va2);
! 340: printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr);
! 341: }
! 342: }
! 343: }
! 344: }
! 345: }
! 346: }
! 347: printf("MMU dump ends\n");
! 348: }
! 349: #endif /* DEBUG_MMU */
! 350:
! 351: #else /* !TARGET_SPARC64 */
1.1 root 352: /*
353: * UltraSparc IIi I/DMMUs
354: */
355: static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
356: int *access_index, target_ulong address, int rw,
357: int is_user)
358: {
359: target_ulong mask;
360: unsigned int i;
361:
362: if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
363: *physical = address;
364: *prot = PAGE_READ | PAGE_WRITE;
365: return 0;
366: }
367:
368: for (i = 0; i < 64; i++) {
369: switch ((env->dtlb_tte[i] >> 61) & 3) {
370: default:
371: case 0x0: // 8k
372: mask = 0xffffffffffffe000ULL;
373: break;
374: case 0x1: // 64k
375: mask = 0xffffffffffff0000ULL;
376: break;
377: case 0x2: // 512k
378: mask = 0xfffffffffff80000ULL;
379: break;
380: case 0x3: // 4M
381: mask = 0xffffffffffc00000ULL;
382: break;
383: }
384: // ctx match, vaddr match?
385: if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
386: (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
387: // valid, access ok?
388: if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
389: ((env->dtlb_tte[i] & 0x4) && is_user) ||
390: (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
391: if (env->dmmuregs[3]) /* Fault status register */
392: env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
393: env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
394: env->dmmuregs[4] = address; /* Fault address register */
395: env->exception_index = TT_DFAULT;
396: #ifdef DEBUG_MMU
397: printf("DFAULT at 0x%llx\n", address);
398: #endif
399: return 1;
400: }
401: *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
402: *prot = PAGE_READ;
403: if (env->dtlb_tte[i] & 0x2)
404: *prot |= PAGE_WRITE;
405: return 0;
406: }
407: }
408: #ifdef DEBUG_MMU
409: printf("DMISS at 0x%llx\n", address);
410: #endif
411: env->exception_index = TT_DMISS;
412: return 1;
413: }
414:
415: static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
416: int *access_index, target_ulong address, int rw,
417: int is_user)
418: {
419: target_ulong mask;
420: unsigned int i;
421:
422: if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
423: *physical = address;
1.1.1.2 ! root 424: *prot = PAGE_EXEC;
1.1 root 425: return 0;
426: }
427:
428: for (i = 0; i < 64; i++) {
429: switch ((env->itlb_tte[i] >> 61) & 3) {
430: default:
431: case 0x0: // 8k
432: mask = 0xffffffffffffe000ULL;
433: break;
434: case 0x1: // 64k
435: mask = 0xffffffffffff0000ULL;
436: break;
437: case 0x2: // 512k
438: mask = 0xfffffffffff80000ULL;
439: break;
440: case 0x3: // 4M
441: mask = 0xffffffffffc00000ULL;
442: break;
443: }
444: // ctx match, vaddr match?
445: if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
446: (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
447: // valid, access ok?
448: if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
449: ((env->itlb_tte[i] & 0x4) && is_user)) {
450: if (env->immuregs[3]) /* Fault status register */
451: env->immuregs[3] = 2; /* overflow (not read before another fault) */
452: env->immuregs[3] |= (is_user << 3) | 1;
453: env->exception_index = TT_TFAULT;
454: #ifdef DEBUG_MMU
455: printf("TFAULT at 0x%llx\n", address);
456: #endif
457: return 1;
458: }
459: *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
1.1.1.2 ! root 460: *prot = PAGE_EXEC;
1.1 root 461: return 0;
462: }
463: }
464: #ifdef DEBUG_MMU
465: printf("TMISS at 0x%llx\n", address);
466: #endif
467: env->exception_index = TT_TMISS;
468: return 1;
469: }
470:
471: int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
472: int *access_index, target_ulong address, int rw,
473: int is_user)
474: {
475: if (rw == 2)
476: return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
477: else
478: return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
479: }
480:
481: /* Perform address translation */
482: int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
483: int is_user, int is_softmmu)
484: {
485: target_ulong virt_addr, vaddr;
486: target_phys_addr_t paddr;
487: int error_code = 0, prot, ret = 0, access_index;
488:
489: error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
490: if (error_code == 0) {
491: virt_addr = address & TARGET_PAGE_MASK;
492: vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
493: #ifdef DEBUG_MMU
494: printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr);
495: #endif
1.1.1.2 ! root 496: ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
1.1 root 497: return ret;
498: }
499: // XXX
500: return 1;
501: }
502:
503: #ifdef DEBUG_MMU
504: void dump_mmu(CPUState *env)
505: {
506: unsigned int i;
507: const char *mask;
508:
509: printf("MMU contexts: Primary: %lld, Secondary: %lld\n", env->dmmuregs[1], env->dmmuregs[2]);
510: if ((env->lsu & DMMU_E) == 0) {
511: printf("DMMU disabled\n");
512: } else {
513: printf("DMMU dump:\n");
514: for (i = 0; i < 64; i++) {
515: switch ((env->dtlb_tte[i] >> 61) & 3) {
516: default:
517: case 0x0:
518: mask = " 8k";
519: break;
520: case 0x1:
521: mask = " 64k";
522: break;
523: case 0x2:
524: mask = "512k";
525: break;
526: case 0x3:
527: mask = " 4M";
528: break;
529: }
530: if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
531: printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %lld\n",
532: env->dtlb_tag[i] & ~0x1fffULL,
533: env->dtlb_tte[i] & 0x1ffffffe000ULL,
534: mask,
535: env->dtlb_tte[i] & 0x4? "priv": "user",
536: env->dtlb_tte[i] & 0x2? "RW": "RO",
537: env->dtlb_tte[i] & 0x40? "locked": "unlocked",
538: env->dtlb_tag[i] & 0x1fffULL);
539: }
540: }
541: }
542: if ((env->lsu & IMMU_E) == 0) {
543: printf("IMMU disabled\n");
544: } else {
545: printf("IMMU dump:\n");
546: for (i = 0; i < 64; i++) {
547: switch ((env->itlb_tte[i] >> 61) & 3) {
548: default:
549: case 0x0:
550: mask = " 8k";
551: break;
552: case 0x1:
553: mask = " 64k";
554: break;
555: case 0x2:
556: mask = "512k";
557: break;
558: case 0x3:
559: mask = " 4M";
560: break;
561: }
562: if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
563: printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %lld\n",
564: env->itlb_tag[i] & ~0x1fffULL,
565: env->itlb_tte[i] & 0x1ffffffe000ULL,
566: mask,
567: env->itlb_tte[i] & 0x4? "priv": "user",
568: env->itlb_tte[i] & 0x40? "locked": "unlocked",
569: env->itlb_tag[i] & 0x1fffULL);
570: }
571: }
572: }
573: }
1.1.1.2 ! root 574: #endif /* DEBUG_MMU */
! 575:
! 576: #endif /* TARGET_SPARC64 */
! 577: #endif /* !CONFIG_USER_ONLY */
! 578:
! 579: void memcpy32(target_ulong *dst, const target_ulong *src)
! 580: {
! 581: dst[0] = src[0];
! 582: dst[1] = src[1];
! 583: dst[2] = src[2];
! 584: dst[3] = src[3];
! 585: dst[4] = src[4];
! 586: dst[5] = src[5];
! 587: dst[6] = src[6];
! 588: dst[7] = src[7];
! 589: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.