|
|
1.1 root 1: /*
2: * sparc helpers
1.1.1.4 root 3: *
1.1 root 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
1.1.1.6 root 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1 root 18: */
19: #include <stdarg.h>
20: #include <stdlib.h>
21: #include <stdio.h>
22: #include <string.h>
23: #include <inttypes.h>
24: #include <signal.h>
25:
26: #include "cpu.h"
27: #include "exec-all.h"
1.1.1.5 root 28: #include "qemu-common.h"
1.1 root 29:
30: //#define DEBUG_MMU
1.1.1.5 root 31: //#define DEBUG_FEATURES
32:
1.1.1.8 ! root 33: #ifdef DEBUG_MMU
! 34: #define DPRINTF_MMU(fmt, ...) \
! 35: do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
! 36: #else
! 37: #define DPRINTF_MMU(fmt, ...) do {} while (0)
! 38: #endif
! 39:
1.1.1.5 root 40: static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
1.1 root 41:
42: /* Sparc MMU emulation */
43:
44: /* thread support */
45:
1.1.1.5 root 46: static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
1.1 root 47:
48: void cpu_lock(void)
49: {
50: spin_lock(&global_cpu_lock);
51: }
52:
53: void cpu_unlock(void)
54: {
55: spin_unlock(&global_cpu_lock);
56: }
57:
1.1.1.4 root 58: #if defined(CONFIG_USER_ONLY)
1.1 root 59:
1.1.1.5 root 60: int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
1.1.1.4 root 61: int mmu_idx, int is_softmmu)
1.1 root 62: {
63: if (rw & 2)
1.1.1.5 root 64: env1->exception_index = TT_TFAULT;
1.1 root 65: else
1.1.1.5 root 66: env1->exception_index = TT_DFAULT;
1.1 root 67: return 1;
68: }
69:
70: #else
71:
72: #ifndef TARGET_SPARC64
73: /*
74: * Sparc V8 Reference MMU (SRMMU)
75: */
76: static const int access_table[8][8] = {
1.1.1.5 root 77: { 0, 0, 0, 0, 8, 0, 12, 12 },
78: { 0, 0, 0, 0, 8, 0, 0, 0 },
79: { 8, 8, 0, 0, 0, 8, 12, 12 },
80: { 8, 8, 0, 0, 0, 8, 0, 0 },
81: { 8, 0, 8, 0, 8, 8, 12, 12 },
82: { 8, 0, 8, 0, 8, 0, 8, 0 },
83: { 8, 8, 8, 0, 8, 8, 12, 12 },
84: { 8, 8, 8, 0, 8, 8, 8, 0 }
1.1 root 85: };
86:
1.1.1.2 root 87: static const int perm_table[2][8] = {
88: {
89: PAGE_READ,
90: PAGE_READ | PAGE_WRITE,
91: PAGE_READ | PAGE_EXEC,
92: PAGE_READ | PAGE_WRITE | PAGE_EXEC,
93: PAGE_EXEC,
94: PAGE_READ | PAGE_WRITE,
95: PAGE_READ | PAGE_EXEC,
96: PAGE_READ | PAGE_WRITE | PAGE_EXEC
97: },
98: {
99: PAGE_READ,
100: PAGE_READ | PAGE_WRITE,
101: PAGE_READ | PAGE_EXEC,
102: PAGE_READ | PAGE_WRITE | PAGE_EXEC,
103: PAGE_EXEC,
104: PAGE_READ,
105: 0,
106: 0,
107: }
1.1 root 108: };
109:
1.1.1.5 root 110: static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
111: int *prot, int *access_index,
1.1.1.8 ! root 112: target_ulong address, int rw, int mmu_idx,
! 113: target_ulong *page_size)
1.1 root 114: {
115: int access_perms = 0;
116: target_phys_addr_t pde_ptr;
117: uint32_t pde;
1.1.1.4 root 118: int error_code = 0, is_dirty, is_user;
1.1 root 119: unsigned long page_offset;
120:
1.1.1.4 root 121: is_user = mmu_idx == MMU_USER_IDX;
122:
1.1 root 123: if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
1.1.1.8 ! root 124: *page_size = TARGET_PAGE_SIZE;
1.1.1.4 root 125: // Boot mode: instruction fetches are taken from PROM
1.1.1.5 root 126: if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
1.1.1.4 root 127: *physical = env->prom_addr | (address & 0x7ffffULL);
128: *prot = PAGE_READ | PAGE_EXEC;
129: return 0;
130: }
131: *physical = address;
1.1.1.2 root 132: *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1 root 133: return 0;
134: }
135:
136: *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
1.1.1.4 root 137: *physical = 0xffffffffffff0000ULL;
1.1 root 138:
139: /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
140: /* Context base + context number */
1.1.1.5 root 141: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
1.1 root 142: pde = ldl_phys(pde_ptr);
143:
144: /* Ctx pde */
145: switch (pde & PTE_ENTRYTYPE_MASK) {
146: default:
147: case 0: /* Invalid */
1.1.1.4 root 148: return 1 << 2;
1.1 root 149: case 2: /* L0 PTE, maybe should not happen? */
150: case 3: /* Reserved */
151: return 4 << 2;
152: case 1: /* L0 PDE */
1.1.1.4 root 153: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
1.1 root 154: pde = ldl_phys(pde_ptr);
155:
1.1.1.4 root 156: switch (pde & PTE_ENTRYTYPE_MASK) {
157: default:
158: case 0: /* Invalid */
159: return (1 << 8) | (1 << 2);
160: case 3: /* Reserved */
161: return (1 << 8) | (4 << 2);
162: case 1: /* L1 PDE */
163: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
1.1 root 164: pde = ldl_phys(pde_ptr);
165:
1.1.1.4 root 166: switch (pde & PTE_ENTRYTYPE_MASK) {
167: default:
168: case 0: /* Invalid */
169: return (2 << 8) | (1 << 2);
170: case 3: /* Reserved */
171: return (2 << 8) | (4 << 2);
172: case 1: /* L2 PDE */
173: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
1.1 root 174: pde = ldl_phys(pde_ptr);
175:
1.1.1.4 root 176: switch (pde & PTE_ENTRYTYPE_MASK) {
177: default:
178: case 0: /* Invalid */
179: return (3 << 8) | (1 << 2);
180: case 1: /* PDE, should not happen */
181: case 3: /* Reserved */
182: return (3 << 8) | (4 << 2);
183: case 2: /* L3 PTE */
1.1.1.5 root 184: page_offset = (address & TARGET_PAGE_MASK) &
185: (TARGET_PAGE_SIZE - 1);
1.1.1.4 root 186: }
1.1.1.8 ! root 187: *page_size = TARGET_PAGE_SIZE;
1.1.1.4 root 188: break;
189: case 2: /* L2 PTE */
190: page_offset = address & 0x3ffff;
1.1.1.8 ! root 191: *page_size = 0x40000;
1.1.1.4 root 192: }
193: break;
194: case 2: /* L1 PTE */
195: page_offset = address & 0xffffff;
1.1.1.8 ! root 196: *page_size = 0x1000000;
1.1.1.4 root 197: }
1.1 root 198: }
199:
1.1.1.8 ! root 200: /* check access */
! 201: access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
! 202: error_code = access_table[*access_index][access_perms];
! 203: if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
! 204: return error_code;
! 205:
1.1 root 206: /* update page modified and dirty bits */
207: is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
208: if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
1.1.1.4 root 209: pde |= PG_ACCESSED_MASK;
210: if (is_dirty)
211: pde |= PG_MODIFIED_MASK;
1.1 root 212: stl_phys_notdirty(pde_ptr, pde);
213: }
214:
215: /* the page can be put in the TLB */
1.1.1.2 root 216: *prot = perm_table[is_user][access_perms];
217: if (!(pde & PG_MODIFIED_MASK)) {
1.1 root 218: /* only set write access if already dirty... otherwise wait
219: for dirty access */
1.1.1.2 root 220: *prot &= ~PAGE_WRITE;
1.1 root 221: }
222:
223: /* Even if large ptes, we map only one 4KB page in the cache to
224: avoid filling it too fast */
1.1.1.4 root 225: *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
1.1 root 226: return error_code;
227: }
228:
229: /* Perform address translation */
230: int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1.1.1.4 root 231: int mmu_idx, int is_softmmu)
1.1 root 232: {
233: target_phys_addr_t paddr;
1.1.1.4 root 234: target_ulong vaddr;
1.1.1.8 ! root 235: target_ulong page_size;
! 236: int error_code = 0, prot, access_index;
1.1 root 237:
1.1.1.5 root 238: error_code = get_physical_address(env, &paddr, &prot, &access_index,
1.1.1.8 ! root 239: address, rw, mmu_idx, &page_size);
1.1 root 240: if (error_code == 0) {
1.1.1.4 root 241: vaddr = address & TARGET_PAGE_MASK;
242: paddr &= TARGET_PAGE_MASK;
1.1.1.2 root 243: #ifdef DEBUG_MMU
1.1.1.4 root 244: printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
245: TARGET_FMT_lx "\n", address, paddr, vaddr);
1.1.1.2 root 246: #endif
1.1.1.8 ! root 247: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
! 248: return 0;
1.1 root 249: }
250:
251: if (env->mmuregs[3]) /* Fault status register */
1.1.1.4 root 252: env->mmuregs[3] = 1; /* overflow (not read before another fault) */
1.1 root 253: env->mmuregs[3] |= (access_index << 5) | error_code | 2;
254: env->mmuregs[4] = address; /* Fault address register */
255:
256: if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
257: // No fault mode: if a mapping is available, just override
258: // permissions. If no mapping is available, redirect accesses to
259: // neverland. Fake/overridden mappings will be flushed when
260: // switching to normal mode.
1.1.1.4 root 261: vaddr = address & TARGET_PAGE_MASK;
1.1.1.2 root 262: prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1.1.8 ! root 263: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
! 264: return 0;
1.1 root 265: } else {
266: if (rw & 2)
267: env->exception_index = TT_TFAULT;
268: else
269: env->exception_index = TT_DFAULT;
270: return 1;
271: }
272: }
1.1.1.2 root 273:
274: target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
275: {
276: target_phys_addr_t pde_ptr;
277: uint32_t pde;
278:
279: /* Context base + context number */
1.1.1.4 root 280: pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
281: (env->mmuregs[2] << 2);
1.1.1.2 root 282: pde = ldl_phys(pde_ptr);
283:
284: switch (pde & PTE_ENTRYTYPE_MASK) {
285: default:
286: case 0: /* Invalid */
287: case 2: /* PTE, maybe should not happen? */
288: case 3: /* Reserved */
1.1.1.4 root 289: return 0;
1.1.1.2 root 290: case 1: /* L1 PDE */
1.1.1.4 root 291: if (mmulev == 3)
292: return pde;
293: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
1.1.1.2 root 294: pde = ldl_phys(pde_ptr);
295:
1.1.1.4 root 296: switch (pde & PTE_ENTRYTYPE_MASK) {
297: default:
298: case 0: /* Invalid */
299: case 3: /* Reserved */
300: return 0;
301: case 2: /* L1 PTE */
302: return pde;
303: case 1: /* L2 PDE */
304: if (mmulev == 2)
305: return pde;
306: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
1.1.1.2 root 307: pde = ldl_phys(pde_ptr);
308:
1.1.1.4 root 309: switch (pde & PTE_ENTRYTYPE_MASK) {
310: default:
311: case 0: /* Invalid */
312: case 3: /* Reserved */
313: return 0;
314: case 2: /* L2 PTE */
315: return pde;
316: case 1: /* L3 PDE */
317: if (mmulev == 1)
318: return pde;
319: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
1.1.1.2 root 320: pde = ldl_phys(pde_ptr);
321:
1.1.1.4 root 322: switch (pde & PTE_ENTRYTYPE_MASK) {
323: default:
324: case 0: /* Invalid */
325: case 1: /* PDE, should not happen */
326: case 3: /* Reserved */
327: return 0;
328: case 2: /* L3 PTE */
329: return pde;
330: }
331: }
332: }
1.1.1.2 root 333: }
334: return 0;
335: }
336:
337: #ifdef DEBUG_MMU
338: void dump_mmu(CPUState *env)
339: {
1.1.1.4 root 340: target_ulong va, va1, va2;
341: unsigned int n, m, o;
342: target_phys_addr_t pde_ptr, pa;
1.1.1.2 root 343: uint32_t pde;
344:
345: printf("MMU dump:\n");
346: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
347: pde = ldl_phys(pde_ptr);
1.1.1.4 root 348: printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
349: (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
1.1.1.2 root 350: for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
1.1.1.4 root 351: pde = mmu_probe(env, va, 2);
352: if (pde) {
353: pa = cpu_get_phys_page_debug(env, va);
354: printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
355: " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
356: for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
357: pde = mmu_probe(env, va1, 1);
358: if (pde) {
359: pa = cpu_get_phys_page_debug(env, va1);
360: printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
361: " PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
362: for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
363: pde = mmu_probe(env, va2, 0);
364: if (pde) {
365: pa = cpu_get_phys_page_debug(env, va2);
366: printf(" VA: " TARGET_FMT_lx ", PA: "
367: TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
368: va2, pa, pde);
369: }
370: }
371: }
372: }
373: }
1.1.1.2 root 374: }
375: printf("MMU dump ends\n");
376: }
377: #endif /* DEBUG_MMU */
378:
379: #else /* !TARGET_SPARC64 */
1.1.1.6 root 380:
381: // 41 bit physical address space
382: static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
383: {
384: return x & 0x1ffffffffffULL;
385: }
386:
1.1 root 387: /*
388: * UltraSparc IIi I/DMMUs
389: */
1.1.1.6 root 390:
391: // Returns true if TTE tag is valid and matches virtual address value in context
392: // requires virtual address mask value calculated from TTE entry size
1.1.1.7 root 393: static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
1.1.1.6 root 394: uint64_t address, uint64_t context,
1.1.1.8 ! root 395: target_phys_addr_t *physical)
1.1.1.6 root 396: {
397: uint64_t mask;
398:
1.1.1.7 root 399: switch ((tlb->tte >> 61) & 3) {
1.1.1.6 root 400: default:
401: case 0x0: // 8k
402: mask = 0xffffffffffffe000ULL;
403: break;
404: case 0x1: // 64k
405: mask = 0xffffffffffff0000ULL;
406: break;
407: case 0x2: // 512k
408: mask = 0xfffffffffff80000ULL;
409: break;
410: case 0x3: // 4M
411: mask = 0xffffffffffc00000ULL;
412: break;
413: }
414:
415: // valid, context match, virtual address match?
1.1.1.7 root 416: if (TTE_IS_VALID(tlb->tte) &&
1.1.1.8 ! root 417: (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
1.1.1.7 root 418: && compare_masked(address, tlb->tag, mask))
1.1.1.6 root 419: {
420: // decode physical address
1.1.1.7 root 421: *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
1.1.1.6 root 422: return 1;
423: }
424:
425: return 0;
426: }
427:
1.1.1.5 root 428: static int get_physical_address_data(CPUState *env,
429: target_phys_addr_t *physical, int *prot,
1.1.1.8 ! root 430: target_ulong address, int rw, int mmu_idx)
1.1 root 431: {
432: unsigned int i;
1.1.1.6 root 433: uint64_t context;
1.1.1.8 ! root 434:
! 435: int is_user = (mmu_idx == MMU_USER_IDX ||
! 436: mmu_idx == MMU_USER_SECONDARY_IDX);
1.1 root 437:
438: if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
1.1.1.6 root 439: *physical = ultrasparc_truncate_physical(address);
1.1.1.4 root 440: *prot = PAGE_READ | PAGE_WRITE;
1.1 root 441: return 0;
442: }
443:
1.1.1.8 ! root 444: switch(mmu_idx) {
! 445: case MMU_USER_IDX:
! 446: case MMU_KERNEL_IDX:
! 447: context = env->dmmu.mmu_primary_context & 0x1fff;
! 448: break;
! 449: case MMU_USER_SECONDARY_IDX:
! 450: case MMU_KERNEL_SECONDARY_IDX:
! 451: context = env->dmmu.mmu_secondary_context & 0x1fff;
! 452: break;
! 453: case MMU_NUCLEUS_IDX:
! 454: default:
! 455: context = 0;
! 456: break;
! 457: }
1.1.1.6 root 458:
1.1 root 459: for (i = 0; i < 64; i++) {
1.1.1.5 root 460: // ctx match, vaddr match, valid?
1.1.1.8 ! root 461: if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
! 462:
! 463: uint8_t fault_type = 0;
! 464:
1.1.1.5 root 465: // access ok?
1.1.1.8 ! root 466: if ((env->dtlb[i].tte & 0x4) && is_user) {
! 467: fault_type |= 1; /* privilege violation */
! 468: env->exception_index = TT_DFAULT;
1.1.1.7 root 469:
1.1.1.8 ! root 470: DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
! 471: " mmu_idx=%d tl=%d\n",
! 472: address, context, mmu_idx, env->tl);
! 473: } else if (!(env->dtlb[i].tte & 0x2) && (rw == 1)) {
! 474: env->exception_index = TT_DPROT;
! 475:
! 476: DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
! 477: " mmu_idx=%d tl=%d\n",
! 478: address, context, mmu_idx, env->tl);
! 479: } else {
! 480: *prot = PAGE_READ;
! 481: if (env->dtlb[i].tte & 0x2)
! 482: *prot |= PAGE_WRITE;
! 483:
! 484: TTE_SET_USED(env->dtlb[i].tte);
! 485:
! 486: return 0;
! 487: }
1.1.1.7 root 488:
1.1.1.8 ! root 489: if (env->dmmu.sfsr & 1) /* Fault status register */
! 490: env->dmmu.sfsr = 2; /* overflow (not read before
1.1.1.5 root 491: another fault) */
1.1.1.7 root 492:
1.1.1.8 ! root 493: env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;
1.1.1.7 root 494:
1.1.1.8 ! root 495: env->dmmu.sfsr |= (fault_type << 7);
1.1.1.7 root 496:
1.1.1.8 ! root 497: env->dmmu.sfar = address; /* Fault address register */
! 498:
! 499: env->dmmu.tag_access = (address & ~0x1fffULL) | context;
! 500:
! 501: return 1;
1.1.1.4 root 502: }
1.1 root 503: }
1.1.1.8 ! root 504:
! 505: DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
! 506: address, context);
! 507:
1.1.1.7 root 508: env->dmmu.tag_access = (address & ~0x1fffULL) | context;
1.1 root 509: env->exception_index = TT_DMISS;
510: return 1;
511: }
512:
1.1.1.5 root 513: static int get_physical_address_code(CPUState *env,
514: target_phys_addr_t *physical, int *prot,
1.1.1.8 ! root 515: target_ulong address, int mmu_idx)
1.1 root 516: {
517: unsigned int i;
1.1.1.6 root 518: uint64_t context;
1.1.1.8 ! root 519:
! 520: int is_user = (mmu_idx == MMU_USER_IDX ||
! 521: mmu_idx == MMU_USER_SECONDARY_IDX);
1.1 root 522:
1.1.1.6 root 523: if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
524: /* IMMU disabled */
525: *physical = ultrasparc_truncate_physical(address);
1.1.1.4 root 526: *prot = PAGE_EXEC;
1.1 root 527: return 0;
528: }
529:
1.1.1.8 ! root 530: if (env->tl == 0) {
! 531: /* PRIMARY context */
! 532: context = env->dmmu.mmu_primary_context & 0x1fff;
! 533: } else {
! 534: /* NUCLEUS context */
! 535: context = 0;
! 536: }
1.1.1.6 root 537:
1.1 root 538: for (i = 0; i < 64; i++) {
1.1.1.5 root 539: // ctx match, vaddr match, valid?
1.1.1.7 root 540: if (ultrasparc_tag_match(&env->itlb[i],
1.1.1.8 ! root 541: address, context, physical)) {
1.1.1.5 root 542: // access ok?
1.1.1.7 root 543: if ((env->itlb[i].tte & 0x4) && is_user) {
544: if (env->immu.sfsr) /* Fault status register */
545: env->immu.sfsr = 2; /* overflow (not read before
1.1.1.5 root 546: another fault) */
1.1.1.7 root 547: env->immu.sfsr |= (is_user << 3) | 1;
1.1.1.4 root 548: env->exception_index = TT_TFAULT;
1.1.1.8 ! root 549:
! 550: env->immu.tag_access = (address & ~0x1fffULL) | context;
! 551:
! 552: DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
! 553: address, context);
! 554:
1.1.1.4 root 555: return 1;
556: }
557: *prot = PAGE_EXEC;
1.1.1.7 root 558: TTE_SET_USED(env->itlb[i].tte);
1.1.1.4 root 559: return 0;
560: }
1.1 root 561: }
1.1.1.8 ! root 562:
! 563: DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
! 564: address, context);
! 565:
1.1.1.6 root 566: /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
1.1.1.7 root 567: env->immu.tag_access = (address & ~0x1fffULL) | context;
1.1 root 568: env->exception_index = TT_TMISS;
569: return 1;
570: }
571:
1.1.1.5 root 572: static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
573: int *prot, int *access_index,
1.1.1.8 ! root 574: target_ulong address, int rw, int mmu_idx,
! 575: target_ulong *page_size)
1.1 root 576: {
1.1.1.8 ! root 577: /* ??? We treat everything as a small page, then explicitly flush
! 578: everything when an entry is evicted. */
! 579: *page_size = TARGET_PAGE_SIZE;
! 580:
! 581: #if defined (DEBUG_MMU)
! 582: /* safety net to catch wrong softmmu index use from dynamic code */
! 583: if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
! 584: DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
! 585: " primary context=%" PRIx64
! 586: " secondary context=%" PRIx64
! 587: " address=%" PRIx64
! 588: "\n",
! 589: (rw == 2 ? "CODE" : "DATA"),
! 590: env->tl, mmu_idx,
! 591: env->dmmu.mmu_primary_context,
! 592: env->dmmu.mmu_secondary_context,
! 593: address);
! 594: }
! 595: #endif
1.1.1.4 root 596:
1.1 root 597: if (rw == 2)
1.1.1.5 root 598: return get_physical_address_code(env, physical, prot, address,
1.1.1.8 ! root 599: mmu_idx);
1.1 root 600: else
1.1.1.5 root 601: return get_physical_address_data(env, physical, prot, address, rw,
1.1.1.8 ! root 602: mmu_idx);
1.1 root 603: }
604:
605: /* Perform address translation */
606: int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1.1.1.4 root 607: int mmu_idx, int is_softmmu)
1.1 root 608: {
609: target_ulong virt_addr, vaddr;
610: target_phys_addr_t paddr;
1.1.1.8 ! root 611: target_ulong page_size;
! 612: int error_code = 0, prot, access_index;
1.1 root 613:
1.1.1.5 root 614: error_code = get_physical_address(env, &paddr, &prot, &access_index,
1.1.1.8 ! root 615: address, rw, mmu_idx, &page_size);
1.1 root 616: if (error_code == 0) {
1.1.1.4 root 617: virt_addr = address & TARGET_PAGE_MASK;
1.1.1.5 root 618: vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
619: (TARGET_PAGE_SIZE - 1));
1.1.1.8 ! root 620:
! 621: DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
! 622: " vaddr %" PRIx64
! 623: " mmu_idx=%d"
! 624: " tl=%d"
! 625: " primary context=%" PRIx64
! 626: " secondary context=%" PRIx64
! 627: "\n",
! 628: address, paddr, vaddr, mmu_idx, env->tl,
! 629: env->dmmu.mmu_primary_context,
! 630: env->dmmu.mmu_secondary_context);
! 631:
! 632: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
! 633: return 0;
1.1 root 634: }
635: // XXX
636: return 1;
637: }
638:
639: #ifdef DEBUG_MMU
640: void dump_mmu(CPUState *env)
641: {
642: unsigned int i;
643: const char *mask;
644:
1.1.1.5 root 645: printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n",
1.1.1.7 root 646: env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context);
1.1 root 647: if ((env->lsu & DMMU_E) == 0) {
1.1.1.4 root 648: printf("DMMU disabled\n");
1.1 root 649: } else {
1.1.1.4 root 650: printf("DMMU dump:\n");
651: for (i = 0; i < 64; i++) {
1.1.1.7 root 652: switch ((env->dtlb[i].tte >> 61) & 3) {
1.1.1.4 root 653: default:
654: case 0x0:
655: mask = " 8k";
656: break;
657: case 0x1:
658: mask = " 64k";
659: break;
660: case 0x2:
661: mask = "512k";
662: break;
663: case 0x3:
664: mask = " 4M";
665: break;
666: }
1.1.1.7 root 667: if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) {
668: printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
669: ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
670: i,
671: env->dtlb[i].tag & (uint64_t)~0x1fffULL,
672: env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
1.1.1.4 root 673: mask,
1.1.1.7 root 674: env->dtlb[i].tte & 0x4? "priv": "user",
675: env->dtlb[i].tte & 0x2? "RW": "RO",
676: env->dtlb[i].tte & 0x40? "locked": "unlocked",
677: env->dtlb[i].tag & (uint64_t)0x1fffULL,
1.1.1.8 ! root 678: TTE_IS_GLOBAL(env->dtlb[i].tte)? "global" : "local");
1.1.1.4 root 679: }
680: }
1.1 root 681: }
682: if ((env->lsu & IMMU_E) == 0) {
1.1.1.4 root 683: printf("IMMU disabled\n");
1.1 root 684: } else {
1.1.1.4 root 685: printf("IMMU dump:\n");
686: for (i = 0; i < 64; i++) {
1.1.1.7 root 687: switch ((env->itlb[i].tte >> 61) & 3) {
1.1.1.4 root 688: default:
689: case 0x0:
690: mask = " 8k";
691: break;
692: case 0x1:
693: mask = " 64k";
694: break;
695: case 0x2:
696: mask = "512k";
697: break;
698: case 0x3:
699: mask = " 4M";
700: break;
701: }
1.1.1.7 root 702: if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) {
703: printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
704: ", %s, %s, %s, ctx %" PRId64 " %s\n",
705: i,
706: env->itlb[i].tag & (uint64_t)~0x1fffULL,
707: env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
1.1.1.4 root 708: mask,
1.1.1.7 root 709: env->itlb[i].tte & 0x4? "priv": "user",
710: env->itlb[i].tte & 0x40? "locked": "unlocked",
711: env->itlb[i].tag & (uint64_t)0x1fffULL,
1.1.1.8 ! root 712: TTE_IS_GLOBAL(env->itlb[i].tte)? "global" : "local");
1.1.1.4 root 713: }
714: }
1.1 root 715: }
716: }
1.1.1.2 root 717: #endif /* DEBUG_MMU */
718:
719: #endif /* TARGET_SPARC64 */
720: #endif /* !CONFIG_USER_ONLY */
721:
1.1.1.5 root 722:
1.1.1.8 ! root 723: #if !defined(CONFIG_USER_ONLY)
! 724: target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
! 725: int mmu_idx)
1.1.1.5 root 726: {
727: target_phys_addr_t phys_addr;
1.1.1.8 ! root 728: target_ulong page_size;
1.1.1.5 root 729: int prot, access_index;
730:
731: if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
1.1.1.8 ! root 732: mmu_idx, &page_size) != 0)
1.1.1.5 root 733: if (get_physical_address(env, &phys_addr, &prot, &access_index, addr,
1.1.1.8 ! root 734: 0, mmu_idx, &page_size) != 0)
1.1.1.5 root 735: return -1;
736: if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
737: return -1;
738: return phys_addr;
739: }
1.1.1.8 ! root 740:
! 741: target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
! 742: {
! 743: return cpu_get_phys_page_nofault(env, addr, cpu_mmu_index(env));
! 744: }
1.1.1.4 root 745: #endif
746:
1.1.1.5 root 747: void cpu_reset(CPUSPARCState *env)
1.1.1.4 root 748: {
1.1.1.5 root 749: if (qemu_loglevel_mask(CPU_LOG_RESET)) {
750: qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
751: log_cpu_state(env, 0);
752: }
753:
754: tlb_flush(env, 1);
755: env->cwp = 0;
1.1.1.6 root 756: #ifndef TARGET_SPARC64
1.1.1.5 root 757: env->wim = 1;
1.1.1.6 root 758: #endif
1.1.1.5 root 759: env->regwptr = env->regbase + (env->cwp * 16);
1.1.1.7 root 760: CC_OP = CC_OP_FLAGS;
1.1.1.5 root 761: #if defined(CONFIG_USER_ONLY)
762: #ifdef TARGET_SPARC64
763: env->cleanwin = env->nwindows - 2;
764: env->cansave = env->nwindows - 2;
765: env->pstate = PS_RMO | PS_PEF | PS_IE;
766: env->asi = 0x82; // Primary no-fault
767: #endif
768: #else
1.1.1.6 root 769: #if !defined(TARGET_SPARC64)
1.1.1.5 root 770: env->psret = 0;
771: env->psrs = 1;
772: env->psrps = 1;
1.1.1.8 ! root 773: #endif
1.1.1.5 root 774: #ifdef TARGET_SPARC64
1.1.1.7 root 775: env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
1.1.1.8 ! root 776: env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
1.1.1.7 root 777: env->tl = env->maxtl;
778: cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
1.1.1.5 root 779: env->lsu = 0;
780: #else
781: env->mmuregs[0] &= ~(MMU_E | MMU_NF);
782: env->mmuregs[0] |= env->def->mmu_bm;
783: #endif
784: env->pc = 0;
785: env->npc = env->pc + 4;
1.1.1.4 root 786: #endif
787: }
788:
1.1.1.5 root 789: static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
1.1.1.4 root 790: {
1.1.1.5 root 791: sparc_def_t def1, *def = &def1;
792:
793: if (cpu_sparc_find_by_name(def, cpu_model) < 0)
794: return -1;
795:
796: env->def = qemu_mallocz(sizeof(*def));
797: memcpy(env->def, def, sizeof(*def));
798: #if defined(CONFIG_USER_ONLY)
799: if ((env->def->features & CPU_FEATURE_FLOAT))
800: env->def->features |= CPU_FEATURE_FLOAT128;
801: #endif
802: env->cpu_model_str = cpu_model;
803: env->version = def->iu_version;
804: env->fsr = def->fpu_version;
805: env->nwindows = def->nwindows;
806: #if !defined(TARGET_SPARC64)
807: env->mmuregs[0] |= def->mmu_version;
808: cpu_sparc_set_id(env, 0);
809: env->mxccregs[7] |= def->mxcc_version;
1.1.1.4 root 810: #else
1.1.1.5 root 811: env->mmu_version = def->mmu_version;
812: env->maxtl = def->maxtl;
813: env->version |= def->maxtl << 8;
814: env->version |= def->nwindows - 1;
815: #endif
1.1.1.4 root 816: return 0;
1.1.1.5 root 817: }
818:
819: static void cpu_sparc_close(CPUSPARCState *env)
820: {
821: free(env->def);
822: free(env);
823: }
824:
825: CPUSPARCState *cpu_sparc_init(const char *cpu_model)
826: {
827: CPUSPARCState *env;
828:
829: env = qemu_mallocz(sizeof(CPUSPARCState));
830: cpu_exec_init(env);
831:
832: gen_intermediate_code_init(env);
833:
834: if (cpu_sparc_register(env, cpu_model) < 0) {
835: cpu_sparc_close(env);
836: return NULL;
837: }
1.1.1.6 root 838: qemu_init_vcpu(env);
1.1.1.5 root 839:
840: return env;
841: }
842:
843: void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
844: {
845: #if !defined(TARGET_SPARC64)
846: env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
847: #endif
848: }
849:
850: static const sparc_def_t sparc_defs[] = {
851: #ifdef TARGET_SPARC64
852: {
853: .name = "Fujitsu Sparc64",
854: .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
855: .fpu_version = 0x00000000,
856: .mmu_version = mmu_us_12,
857: .nwindows = 4,
858: .maxtl = 4,
859: .features = CPU_DEFAULT_FEATURES,
860: },
861: {
862: .name = "Fujitsu Sparc64 III",
863: .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
864: .fpu_version = 0x00000000,
865: .mmu_version = mmu_us_12,
866: .nwindows = 5,
867: .maxtl = 4,
868: .features = CPU_DEFAULT_FEATURES,
869: },
870: {
871: .name = "Fujitsu Sparc64 IV",
872: .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
873: .fpu_version = 0x00000000,
874: .mmu_version = mmu_us_12,
875: .nwindows = 8,
876: .maxtl = 5,
877: .features = CPU_DEFAULT_FEATURES,
878: },
879: {
880: .name = "Fujitsu Sparc64 V",
881: .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
882: .fpu_version = 0x00000000,
883: .mmu_version = mmu_us_12,
884: .nwindows = 8,
885: .maxtl = 5,
886: .features = CPU_DEFAULT_FEATURES,
887: },
888: {
889: .name = "TI UltraSparc I",
890: .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
891: .fpu_version = 0x00000000,
892: .mmu_version = mmu_us_12,
893: .nwindows = 8,
894: .maxtl = 5,
895: .features = CPU_DEFAULT_FEATURES,
896: },
897: {
898: .name = "TI UltraSparc II",
899: .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
900: .fpu_version = 0x00000000,
901: .mmu_version = mmu_us_12,
902: .nwindows = 8,
903: .maxtl = 5,
904: .features = CPU_DEFAULT_FEATURES,
905: },
906: {
907: .name = "TI UltraSparc IIi",
908: .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
909: .fpu_version = 0x00000000,
910: .mmu_version = mmu_us_12,
911: .nwindows = 8,
912: .maxtl = 5,
913: .features = CPU_DEFAULT_FEATURES,
914: },
915: {
916: .name = "TI UltraSparc IIe",
917: .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
918: .fpu_version = 0x00000000,
919: .mmu_version = mmu_us_12,
920: .nwindows = 8,
921: .maxtl = 5,
922: .features = CPU_DEFAULT_FEATURES,
923: },
924: {
925: .name = "Sun UltraSparc III",
926: .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
927: .fpu_version = 0x00000000,
928: .mmu_version = mmu_us_12,
929: .nwindows = 8,
930: .maxtl = 5,
931: .features = CPU_DEFAULT_FEATURES,
932: },
933: {
934: .name = "Sun UltraSparc III Cu",
935: .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
936: .fpu_version = 0x00000000,
937: .mmu_version = mmu_us_3,
938: .nwindows = 8,
939: .maxtl = 5,
940: .features = CPU_DEFAULT_FEATURES,
941: },
942: {
943: .name = "Sun UltraSparc IIIi",
944: .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
945: .fpu_version = 0x00000000,
946: .mmu_version = mmu_us_12,
947: .nwindows = 8,
948: .maxtl = 5,
949: .features = CPU_DEFAULT_FEATURES,
950: },
951: {
952: .name = "Sun UltraSparc IV",
953: .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
954: .fpu_version = 0x00000000,
955: .mmu_version = mmu_us_4,
956: .nwindows = 8,
957: .maxtl = 5,
958: .features = CPU_DEFAULT_FEATURES,
959: },
960: {
961: .name = "Sun UltraSparc IV+",
962: .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
963: .fpu_version = 0x00000000,
964: .mmu_version = mmu_us_12,
965: .nwindows = 8,
966: .maxtl = 5,
967: .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
968: },
969: {
970: .name = "Sun UltraSparc IIIi+",
971: .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
972: .fpu_version = 0x00000000,
973: .mmu_version = mmu_us_3,
974: .nwindows = 8,
975: .maxtl = 5,
976: .features = CPU_DEFAULT_FEATURES,
977: },
978: {
979: .name = "Sun UltraSparc T1",
980: // defined in sparc_ifu_fdp.v and ctu.h
981: .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
982: .fpu_version = 0x00000000,
983: .mmu_version = mmu_sun4v,
984: .nwindows = 8,
985: .maxtl = 6,
986: .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
987: | CPU_FEATURE_GL,
988: },
989: {
990: .name = "Sun UltraSparc T2",
991: // defined in tlu_asi_ctl.v and n2_revid_cust.v
992: .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
993: .fpu_version = 0x00000000,
994: .mmu_version = mmu_sun4v,
995: .nwindows = 8,
996: .maxtl = 6,
997: .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
998: | CPU_FEATURE_GL,
999: },
1000: {
1001: .name = "NEC UltraSparc I",
1002: .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1003: .fpu_version = 0x00000000,
1004: .mmu_version = mmu_us_12,
1005: .nwindows = 8,
1006: .maxtl = 5,
1007: .features = CPU_DEFAULT_FEATURES,
1008: },
1009: #else
1010: {
1011: .name = "Fujitsu MB86900",
1012: .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
1013: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1014: .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
1015: .mmu_bm = 0x00004000,
1016: .mmu_ctpr_mask = 0x007ffff0,
1017: .mmu_cxr_mask = 0x0000003f,
1018: .mmu_sfsr_mask = 0xffffffff,
1019: .mmu_trcr_mask = 0xffffffff,
1020: .nwindows = 7,
1021: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
1022: },
1023: {
1024: .name = "Fujitsu MB86904",
1025: .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
1026: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1027: .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
1028: .mmu_bm = 0x00004000,
1029: .mmu_ctpr_mask = 0x00ffffc0,
1030: .mmu_cxr_mask = 0x000000ff,
1031: .mmu_sfsr_mask = 0x00016fff,
1032: .mmu_trcr_mask = 0x00ffffff,
1033: .nwindows = 8,
1034: .features = CPU_DEFAULT_FEATURES,
1035: },
1036: {
1037: .name = "Fujitsu MB86907",
1038: .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
1039: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1040: .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
1041: .mmu_bm = 0x00004000,
1042: .mmu_ctpr_mask = 0xffffffc0,
1043: .mmu_cxr_mask = 0x000000ff,
1044: .mmu_sfsr_mask = 0x00016fff,
1045: .mmu_trcr_mask = 0xffffffff,
1046: .nwindows = 8,
1047: .features = CPU_DEFAULT_FEATURES,
1048: },
1049: {
1050: .name = "LSI L64811",
1051: .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
1052: .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
1053: .mmu_version = 0x10 << 24,
1054: .mmu_bm = 0x00004000,
1055: .mmu_ctpr_mask = 0x007ffff0,
1056: .mmu_cxr_mask = 0x0000003f,
1057: .mmu_sfsr_mask = 0xffffffff,
1058: .mmu_trcr_mask = 0xffffffff,
1059: .nwindows = 8,
1060: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1061: CPU_FEATURE_FSMULD,
1062: },
1063: {
1064: .name = "Cypress CY7C601",
1065: .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1066: .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1067: .mmu_version = 0x10 << 24,
1068: .mmu_bm = 0x00004000,
1069: .mmu_ctpr_mask = 0x007ffff0,
1070: .mmu_cxr_mask = 0x0000003f,
1071: .mmu_sfsr_mask = 0xffffffff,
1072: .mmu_trcr_mask = 0xffffffff,
1073: .nwindows = 8,
1074: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1075: CPU_FEATURE_FSMULD,
1076: },
1077: {
1078: .name = "Cypress CY7C611",
1079: .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1080: .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1081: .mmu_version = 0x10 << 24,
1082: .mmu_bm = 0x00004000,
1083: .mmu_ctpr_mask = 0x007ffff0,
1084: .mmu_cxr_mask = 0x0000003f,
1085: .mmu_sfsr_mask = 0xffffffff,
1086: .mmu_trcr_mask = 0xffffffff,
1087: .nwindows = 8,
1088: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1089: CPU_FEATURE_FSMULD,
1090: },
1091: {
1092: .name = "TI MicroSparc I",
1093: .iu_version = 0x41000000,
1094: .fpu_version = 4 << 17,
1095: .mmu_version = 0x41000000,
1096: .mmu_bm = 0x00004000,
1097: .mmu_ctpr_mask = 0x007ffff0,
1098: .mmu_cxr_mask = 0x0000003f,
1099: .mmu_sfsr_mask = 0x00016fff,
1100: .mmu_trcr_mask = 0x0000003f,
1101: .nwindows = 7,
1102: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1103: CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1104: CPU_FEATURE_FMUL,
1105: },
1106: {
1107: .name = "TI MicroSparc II",
1108: .iu_version = 0x42000000,
1109: .fpu_version = 4 << 17,
1110: .mmu_version = 0x02000000,
1111: .mmu_bm = 0x00004000,
1112: .mmu_ctpr_mask = 0x00ffffc0,
1113: .mmu_cxr_mask = 0x000000ff,
1114: .mmu_sfsr_mask = 0x00016fff,
1115: .mmu_trcr_mask = 0x00ffffff,
1116: .nwindows = 8,
1117: .features = CPU_DEFAULT_FEATURES,
1118: },
1119: {
1120: .name = "TI MicroSparc IIep",
1121: .iu_version = 0x42000000,
1122: .fpu_version = 4 << 17,
1123: .mmu_version = 0x04000000,
1124: .mmu_bm = 0x00004000,
1125: .mmu_ctpr_mask = 0x00ffffc0,
1126: .mmu_cxr_mask = 0x000000ff,
1127: .mmu_sfsr_mask = 0x00016bff,
1128: .mmu_trcr_mask = 0x00ffffff,
1129: .nwindows = 8,
1130: .features = CPU_DEFAULT_FEATURES,
1131: },
1132: {
1133: .name = "TI SuperSparc 40", // STP1020NPGA
1134: .iu_version = 0x41000000, // SuperSPARC 2.x
1135: .fpu_version = 0 << 17,
1136: .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
1137: .mmu_bm = 0x00002000,
1138: .mmu_ctpr_mask = 0xffffffc0,
1139: .mmu_cxr_mask = 0x0000ffff,
1140: .mmu_sfsr_mask = 0xffffffff,
1141: .mmu_trcr_mask = 0xffffffff,
1142: .nwindows = 8,
1143: .features = CPU_DEFAULT_FEATURES,
1144: },
1145: {
1146: .name = "TI SuperSparc 50", // STP1020PGA
1147: .iu_version = 0x40000000, // SuperSPARC 3.x
1148: .fpu_version = 0 << 17,
1149: .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1150: .mmu_bm = 0x00002000,
1151: .mmu_ctpr_mask = 0xffffffc0,
1152: .mmu_cxr_mask = 0x0000ffff,
1153: .mmu_sfsr_mask = 0xffffffff,
1154: .mmu_trcr_mask = 0xffffffff,
1155: .nwindows = 8,
1156: .features = CPU_DEFAULT_FEATURES,
1157: },
1158: {
1159: .name = "TI SuperSparc 51",
1160: .iu_version = 0x40000000, // SuperSPARC 3.x
1161: .fpu_version = 0 << 17,
1162: .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1163: .mmu_bm = 0x00002000,
1164: .mmu_ctpr_mask = 0xffffffc0,
1165: .mmu_cxr_mask = 0x0000ffff,
1166: .mmu_sfsr_mask = 0xffffffff,
1167: .mmu_trcr_mask = 0xffffffff,
1168: .mxcc_version = 0x00000104,
1169: .nwindows = 8,
1170: .features = CPU_DEFAULT_FEATURES,
1171: },
1172: {
1173: .name = "TI SuperSparc 60", // STP1020APGA
1174: .iu_version = 0x40000000, // SuperSPARC 3.x
1175: .fpu_version = 0 << 17,
1176: .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1177: .mmu_bm = 0x00002000,
1178: .mmu_ctpr_mask = 0xffffffc0,
1179: .mmu_cxr_mask = 0x0000ffff,
1180: .mmu_sfsr_mask = 0xffffffff,
1181: .mmu_trcr_mask = 0xffffffff,
1182: .nwindows = 8,
1183: .features = CPU_DEFAULT_FEATURES,
1184: },
1185: {
1186: .name = "TI SuperSparc 61",
1187: .iu_version = 0x44000000, // SuperSPARC 3.x
1188: .fpu_version = 0 << 17,
1189: .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1190: .mmu_bm = 0x00002000,
1191: .mmu_ctpr_mask = 0xffffffc0,
1192: .mmu_cxr_mask = 0x0000ffff,
1193: .mmu_sfsr_mask = 0xffffffff,
1194: .mmu_trcr_mask = 0xffffffff,
1195: .mxcc_version = 0x00000104,
1196: .nwindows = 8,
1197: .features = CPU_DEFAULT_FEATURES,
1198: },
1199: {
1200: .name = "TI SuperSparc II",
1201: .iu_version = 0x40000000, // SuperSPARC II 1.x
1202: .fpu_version = 0 << 17,
1203: .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
1204: .mmu_bm = 0x00002000,
1205: .mmu_ctpr_mask = 0xffffffc0,
1206: .mmu_cxr_mask = 0x0000ffff,
1207: .mmu_sfsr_mask = 0xffffffff,
1208: .mmu_trcr_mask = 0xffffffff,
1209: .mxcc_version = 0x00000104,
1210: .nwindows = 8,
1211: .features = CPU_DEFAULT_FEATURES,
1212: },
1213: {
1214: .name = "Ross RT625",
1215: .iu_version = 0x1e000000,
1216: .fpu_version = 1 << 17,
1217: .mmu_version = 0x1e000000,
1218: .mmu_bm = 0x00004000,
1219: .mmu_ctpr_mask = 0x007ffff0,
1220: .mmu_cxr_mask = 0x0000003f,
1221: .mmu_sfsr_mask = 0xffffffff,
1222: .mmu_trcr_mask = 0xffffffff,
1223: .nwindows = 8,
1224: .features = CPU_DEFAULT_FEATURES,
1225: },
1226: {
1227: .name = "Ross RT620",
1228: .iu_version = 0x1f000000,
1229: .fpu_version = 1 << 17,
1230: .mmu_version = 0x1f000000,
1231: .mmu_bm = 0x00004000,
1232: .mmu_ctpr_mask = 0x007ffff0,
1233: .mmu_cxr_mask = 0x0000003f,
1234: .mmu_sfsr_mask = 0xffffffff,
1235: .mmu_trcr_mask = 0xffffffff,
1236: .nwindows = 8,
1237: .features = CPU_DEFAULT_FEATURES,
1238: },
1239: {
1240: .name = "BIT B5010",
1241: .iu_version = 0x20000000,
1242: .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1243: .mmu_version = 0x20000000,
1244: .mmu_bm = 0x00004000,
1245: .mmu_ctpr_mask = 0x007ffff0,
1246: .mmu_cxr_mask = 0x0000003f,
1247: .mmu_sfsr_mask = 0xffffffff,
1248: .mmu_trcr_mask = 0xffffffff,
1249: .nwindows = 8,
1250: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1251: CPU_FEATURE_FSMULD,
1252: },
1253: {
1254: .name = "Matsushita MN10501",
1255: .iu_version = 0x50000000,
1256: .fpu_version = 0 << 17,
1257: .mmu_version = 0x50000000,
1258: .mmu_bm = 0x00004000,
1259: .mmu_ctpr_mask = 0x007ffff0,
1260: .mmu_cxr_mask = 0x0000003f,
1261: .mmu_sfsr_mask = 0xffffffff,
1262: .mmu_trcr_mask = 0xffffffff,
1263: .nwindows = 8,
1264: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1265: CPU_FEATURE_FSMULD,
1266: },
1267: {
1268: .name = "Weitek W8601",
1269: .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1270: .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1271: .mmu_version = 0x10 << 24,
1272: .mmu_bm = 0x00004000,
1273: .mmu_ctpr_mask = 0x007ffff0,
1274: .mmu_cxr_mask = 0x0000003f,
1275: .mmu_sfsr_mask = 0xffffffff,
1276: .mmu_trcr_mask = 0xffffffff,
1277: .nwindows = 8,
1278: .features = CPU_DEFAULT_FEATURES,
1279: },
1280: {
1281: .name = "LEON2",
1282: .iu_version = 0xf2000000,
1283: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1284: .mmu_version = 0xf2000000,
1285: .mmu_bm = 0x00004000,
1286: .mmu_ctpr_mask = 0x007ffff0,
1287: .mmu_cxr_mask = 0x0000003f,
1288: .mmu_sfsr_mask = 0xffffffff,
1289: .mmu_trcr_mask = 0xffffffff,
1290: .nwindows = 8,
1291: .features = CPU_DEFAULT_FEATURES,
1292: },
1293: {
1294: .name = "LEON3",
1295: .iu_version = 0xf3000000,
1296: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1297: .mmu_version = 0xf3000000,
1298: .mmu_bm = 0x00004000,
1299: .mmu_ctpr_mask = 0x007ffff0,
1300: .mmu_cxr_mask = 0x0000003f,
1301: .mmu_sfsr_mask = 0xffffffff,
1302: .mmu_trcr_mask = 0xffffffff,
1303: .nwindows = 8,
1304: .features = CPU_DEFAULT_FEATURES,
1305: },
1.1.1.4 root 1306: #endif
1.1.1.5 root 1307: };
1308:
1309: static const char * const feature_name[] = {
1310: "float",
1311: "float128",
1312: "swap",
1313: "mul",
1314: "div",
1315: "flush",
1316: "fsqrt",
1317: "fmul",
1318: "vis1",
1319: "vis2",
1320: "fsmuld",
1321: "hypv",
1322: "cmt",
1323: "gl",
1324: };
1325:
1326: static void print_features(FILE *f,
1327: int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1328: uint32_t features, const char *prefix)
1329: {
1330: unsigned int i;
1331:
1332: for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1333: if (feature_name[i] && (features & (1 << i))) {
1334: if (prefix)
1335: (*cpu_fprintf)(f, "%s", prefix);
1336: (*cpu_fprintf)(f, "%s ", feature_name[i]);
1337: }
1.1.1.4 root 1338: }
1339:
1.1.1.5 root 1340: static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
1.1.1.4 root 1341: {
1.1.1.5 root 1342: unsigned int i;
1343:
1344: for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1345: if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
1346: *features |= 1 << i;
1347: return;
1348: }
1349: fprintf(stderr, "CPU feature %s not found\n", flagname);
1350: }
1351:
1352: static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
1353: {
1354: unsigned int i;
1355: const sparc_def_t *def = NULL;
1356: char *s = strdup(cpu_model);
1357: char *featurestr, *name = strtok(s, ",");
1358: uint32_t plus_features = 0;
1359: uint32_t minus_features = 0;
1.1.1.8 ! root 1360: uint64_t iu_version;
1.1.1.5 root 1361: uint32_t fpu_version, mmu_version, nwindows;
1362:
1363: for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1364: if (strcasecmp(name, sparc_defs[i].name) == 0) {
1365: def = &sparc_defs[i];
1366: }
1367: }
1368: if (!def)
1369: goto error;
1370: memcpy(cpu_def, def, sizeof(*def));
1371:
1372: featurestr = strtok(NULL, ",");
1373: while (featurestr) {
1374: char *val;
1375:
1376: if (featurestr[0] == '+') {
1377: add_flagname_to_bitmaps(featurestr + 1, &plus_features);
1378: } else if (featurestr[0] == '-') {
1379: add_flagname_to_bitmaps(featurestr + 1, &minus_features);
1380: } else if ((val = strchr(featurestr, '='))) {
1381: *val = 0; val++;
1382: if (!strcmp(featurestr, "iu_version")) {
1383: char *err;
1384:
1385: iu_version = strtoll(val, &err, 0);
1386: if (!*val || *err) {
1387: fprintf(stderr, "bad numerical value %s\n", val);
1388: goto error;
1389: }
1390: cpu_def->iu_version = iu_version;
1391: #ifdef DEBUG_FEATURES
1.1.1.8 ! root 1392: fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
1.1.1.5 root 1393: #endif
1394: } else if (!strcmp(featurestr, "fpu_version")) {
1395: char *err;
1396:
1397: fpu_version = strtol(val, &err, 0);
1398: if (!*val || *err) {
1399: fprintf(stderr, "bad numerical value %s\n", val);
1400: goto error;
1401: }
1402: cpu_def->fpu_version = fpu_version;
1403: #ifdef DEBUG_FEATURES
1.1.1.6 root 1404: fprintf(stderr, "fpu_version %x\n", fpu_version);
1.1.1.5 root 1405: #endif
1406: } else if (!strcmp(featurestr, "mmu_version")) {
1407: char *err;
1408:
1409: mmu_version = strtol(val, &err, 0);
1410: if (!*val || *err) {
1411: fprintf(stderr, "bad numerical value %s\n", val);
1412: goto error;
1413: }
1414: cpu_def->mmu_version = mmu_version;
1415: #ifdef DEBUG_FEATURES
1.1.1.6 root 1416: fprintf(stderr, "mmu_version %x\n", mmu_version);
1.1.1.5 root 1417: #endif
1418: } else if (!strcmp(featurestr, "nwindows")) {
1419: char *err;
1420:
1421: nwindows = strtol(val, &err, 0);
1422: if (!*val || *err || nwindows > MAX_NWINDOWS ||
1423: nwindows < MIN_NWINDOWS) {
1424: fprintf(stderr, "bad numerical value %s\n", val);
1425: goto error;
1426: }
1427: cpu_def->nwindows = nwindows;
1428: #ifdef DEBUG_FEATURES
1429: fprintf(stderr, "nwindows %d\n", nwindows);
1.1.1.4 root 1430: #endif
1.1.1.5 root 1431: } else {
1432: fprintf(stderr, "unrecognized feature %s\n", featurestr);
1433: goto error;
1434: }
1435: } else {
1436: fprintf(stderr, "feature string `%s' not in format "
1437: "(+feature|-feature|feature=xyz)\n", featurestr);
1438: goto error;
1439: }
1440: featurestr = strtok(NULL, ",");
1441: }
1442: cpu_def->features |= plus_features;
1443: cpu_def->features &= ~minus_features;
1444: #ifdef DEBUG_FEATURES
1445: print_features(stderr, fprintf, cpu_def->features, NULL);
1446: #endif
1447: free(s);
1448: return 0;
1449:
1450: error:
1451: free(s);
1452: return -1;
1.1.1.4 root 1453: }
1.1.1.5 root 1454:
1455: void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
1456: {
1457: unsigned int i;
1458:
1459: for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1460: (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
1461: sparc_defs[i].name,
1462: sparc_defs[i].iu_version,
1463: sparc_defs[i].fpu_version,
1464: sparc_defs[i].mmu_version,
1465: sparc_defs[i].nwindows);
1466: print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
1467: ~sparc_defs[i].features, "-");
1468: print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
1469: sparc_defs[i].features, "+");
1470: (*cpu_fprintf)(f, "\n");
1471: }
1472: (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1473: print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
1474: (*cpu_fprintf)(f, "\n");
1475: (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1476: print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1477: (*cpu_fprintf)(f, "\n");
1478: (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1479: "fpu_version mmu_version nwindows\n");
1480: }
1481:
1.1.1.8 ! root 1482: static void cpu_print_cc(FILE *f,
! 1483: int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
! 1484: uint32_t cc)
! 1485: {
! 1486: cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
! 1487: cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
! 1488: cc & PSR_CARRY? 'C' : '-');
! 1489: }
! 1490:
! 1491: #ifdef TARGET_SPARC64
! 1492: #define REGS_PER_LINE 4
! 1493: #else
! 1494: #define REGS_PER_LINE 8
! 1495: #endif
! 1496:
1.1.1.5 root 1497: void cpu_dump_state(CPUState *env, FILE *f,
1498: int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1499: int flags)
1500: {
1501: int i, x;
1502:
1503: cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
1504: env->npc);
1505: cpu_fprintf(f, "General Registers:\n");
1.1.1.8 ! root 1506:
! 1507: for (i = 0; i < 8; i++) {
! 1508: if (i % REGS_PER_LINE == 0) {
! 1509: cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
! 1510: }
! 1511: cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
! 1512: if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
! 1513: cpu_fprintf(f, "\n");
! 1514: }
! 1515: }
1.1.1.5 root 1516: cpu_fprintf(f, "\nCurrent Register Window:\n");
1517: for (x = 0; x < 3; x++) {
1.1.1.8 ! root 1518: for (i = 0; i < 8; i++) {
! 1519: if (i % REGS_PER_LINE == 0) {
! 1520: cpu_fprintf(f, "%%%c%d-%d: ",
! 1521: x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
! 1522: i, i + REGS_PER_LINE - 1);
! 1523: }
! 1524: cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
! 1525: if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
! 1526: cpu_fprintf(f, "\n");
! 1527: }
! 1528: }
1.1.1.5 root 1529: }
1530: cpu_fprintf(f, "\nFloating Point Registers:\n");
1.1.1.8 ! root 1531: for (i = 0; i < TARGET_FPREGS; i++) {
1.1.1.5 root 1532: if ((i & 3) == 0)
1533: cpu_fprintf(f, "%%f%02d:", i);
1534: cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
1535: if ((i & 3) == 3)
1536: cpu_fprintf(f, "\n");
1537: }
1538: #ifdef TARGET_SPARC64
1.1.1.8 ! root 1539: cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
! 1540: (unsigned)cpu_get_ccr(env));
! 1541: cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
! 1542: cpu_fprintf(f, " xcc: ");
! 1543: cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
! 1544: cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
! 1545: env->psrpil);
! 1546: cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
! 1547: "cleanwin: %d cwp: %d\n",
1.1.1.5 root 1548: env->cansave, env->canrestore, env->otherwin, env->wstate,
1549: env->cleanwin, env->nwindows - 1 - env->cwp);
1.1.1.8 ! root 1550: cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
! 1551: TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
1.1.1.5 root 1552: #else
1.1.1.8 ! root 1553: cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
! 1554: cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
! 1555: cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
! 1556: env->psrps? 'P' : '-', env->psret? 'E' : '-',
! 1557: env->wim);
! 1558: cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
! 1559: env->fsr, env->y);
1.1.1.4 root 1560: #endif
1.1.1.5 root 1561: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.