* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <signal.h>
-#include <assert.h>
#include "cpu.h"
#include "exec-all.h"
/* thread support */
-static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+static a_spinlock global_cpu_lock = SPIN_LOCK_UNLOCKED;
void cpu_lock(void)
{
}
};
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+static int get_physical_address(CPUState *env, a_target_phys_addr *physical,
int *prot, int *access_index,
target_ulong address, int rw, int mmu_idx)
{
int access_perms = 0;
- target_phys_addr_t pde_ptr;
+ a_target_phys_addr pde_ptr;
uint32_t pde;
target_ulong virt_addr;
int error_code = 0, is_dirty, is_user;
/* Even if large ptes, we map only one 4KB page in the cache to
avoid filling it too fast */
- *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
+ *physical = ((a_target_phys_addr)(pde & PTE_ADDR_MASK) << 4) + page_offset;
return error_code;
}
int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
- target_phys_addr_t paddr;
+ a_target_phys_addr paddr;
target_ulong vaddr;
int error_code = 0, prot, ret = 0, access_index;
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
{
- target_phys_addr_t pde_ptr;
+ a_target_phys_addr pde_ptr;
uint32_t pde;
/* Context base + context number */
- pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
+ pde_ptr = (a_target_phys_addr)(env->mmuregs[1] << 4) +
(env->mmuregs[2] << 2);
pde = ldl_phys(pde_ptr);
{
target_ulong va, va1, va2;
unsigned int n, m, o;
- target_phys_addr_t pde_ptr, pa;
+ a_target_phys_addr pde_ptr, pa;
uint32_t pde;
printf("MMU dump:\n");
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
pde = ldl_phys(pde_ptr);
printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
- (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
+ (a_target_phys_addr)env->mmuregs[1] << 4, env->mmuregs[2]);
for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
pde = mmu_probe(env, va, 2);
if (pde) {
#endif /* DEBUG_MMU */
#else /* !TARGET_SPARC64 */
+
+// 41 bit physical address space
+static inline a_target_phys_addr ultrasparc_truncate_physical(uint64_t x)
+{
+ return x & 0x1ffffffffffULL;
+}
+
/*
* UltraSparc IIi I/DMMUs
*/
+
+static inline int compare_masked(uint64_t x, uint64_t y, uint64_t mask)
+{
+ return (x & mask) == (y & mask);
+}
+
+// Returns true if TTE tag is valid and matches virtual address value in context
+// requires virtual address mask value calculated from TTE entry size
+static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
+ uint64_t address, uint64_t context,
+ a_target_phys_addr *physical)
+{
+ uint64_t mask;
+
+ switch ((tlb->tte >> 61) & 3) {
+ default:
+ case 0x0: // 8k
+ mask = 0xffffffffffffe000ULL;
+ break;
+ case 0x1: // 64k
+ mask = 0xffffffffffff0000ULL;
+ break;
+ case 0x2: // 512k
+ mask = 0xfffffffffff80000ULL;
+ break;
+ case 0x3: // 4M
+ mask = 0xffffffffffc00000ULL;
+ break;
+ }
+
+ // valid, context match, virtual address match?
+ if (TTE_IS_VALID(tlb->tte) &&
+ compare_masked(context, tlb->tag, 0x1fff) &&
+ compare_masked(address, tlb->tag, mask))
+ {
+ // decode physical address
+ *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
+ return 1;
+ }
+
+ return 0;
+}
+
static int get_physical_address_data(CPUState *env,
- target_phys_addr_t *physical, int *prot,
+ a_target_phys_addr *physical, int *prot,
target_ulong address, int rw, int is_user)
{
- target_ulong mask;
unsigned int i;
+ uint64_t context;
if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
- *physical = address;
+ *physical = ultrasparc_truncate_physical(address);
*prot = PAGE_READ | PAGE_WRITE;
return 0;
}
+ context = env->dmmu.mmu_primary_context & 0x1fff;
+
for (i = 0; i < 64; i++) {
- switch ((env->dtlb_tte[i] >> 61) & 3) {
- default:
- case 0x0: // 8k
- mask = 0xffffffffffffe000ULL;
- break;
- case 0x1: // 64k
- mask = 0xffffffffffff0000ULL;
- break;
- case 0x2: // 512k
- mask = 0xfffffffffff80000ULL;
- break;
- case 0x3: // 4M
- mask = 0xffffffffffc00000ULL;
- break;
- }
// ctx match, vaddr match, valid?
- if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
- (address & mask) == (env->dtlb_tag[i] & mask) &&
- (env->dtlb_tte[i] & 0x8000000000000000ULL)) {
+ if (ultrasparc_tag_match(&env->dtlb[i],
+ address, context, physical)
+ ) {
// access ok?
- if (((env->dtlb_tte[i] & 0x4) && is_user) ||
- (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
- if (env->dmmuregs[3]) /* Fault status register */
- env->dmmuregs[3] = 2; /* overflow (not read before
+ if (((env->dtlb[i].tte & 0x4) && is_user) ||
+ (!(env->dtlb[i].tte & 0x2) && (rw == 1))) {
+ uint8_t fault_type = 0;
+
+ if ((env->dtlb[i].tte & 0x4) && is_user) {
+ fault_type |= 1; /* privilege violation */
+ }
+
+ if (env->dmmu.sfsr & 1) /* Fault status register */
+ env->dmmu.sfsr = 2; /* overflow (not read before
another fault) */
- env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
- env->dmmuregs[4] = address; /* Fault address register */
+
+ env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;
+
+ env->dmmu.sfsr |= (fault_type << 7);
+
+ env->dmmu.sfar = address; /* Fault address register */
env->exception_index = TT_DFAULT;
#ifdef DEBUG_MMU
printf("DFAULT at 0x%" PRIx64 "\n", address);
#endif
return 1;
}
- *physical = ((env->dtlb_tte[i] & mask) | (address & ~mask)) &
- 0x1ffffffe000ULL;
*prot = PAGE_READ;
- if (env->dtlb_tte[i] & 0x2)
+ if (env->dtlb[i].tte & 0x2)
*prot |= PAGE_WRITE;
+ TTE_SET_USED(env->dtlb[i].tte);
return 0;
}
}
#ifdef DEBUG_MMU
printf("DMISS at 0x%" PRIx64 "\n", address);
#endif
- env->dmmuregs[6] = (address & ~0x1fffULL) | (env->dmmuregs[1] & 0x1fff);
+ env->dmmu.tag_access = (address & ~0x1fffULL) | context;
env->exception_index = TT_DMISS;
return 1;
}
static int get_physical_address_code(CPUState *env,
- target_phys_addr_t *physical, int *prot,
+ a_target_phys_addr *physical, int *prot,
target_ulong address, int is_user)
{
- target_ulong mask;
unsigned int i;
+ uint64_t context;
- if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
- *physical = address;
+ if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
+ /* IMMU disabled */
+ *physical = ultrasparc_truncate_physical(address);
*prot = PAGE_EXEC;
return 0;
}
+ context = env->dmmu.mmu_primary_context & 0x1fff;
+
for (i = 0; i < 64; i++) {
- switch ((env->itlb_tte[i] >> 61) & 3) {
- default:
- case 0x0: // 8k
- mask = 0xffffffffffffe000ULL;
- break;
- case 0x1: // 64k
- mask = 0xffffffffffff0000ULL;
- break;
- case 0x2: // 512k
- mask = 0xfffffffffff80000ULL;
- break;
- case 0x3: // 4M
- mask = 0xffffffffffc00000ULL;
- break;
- }
// ctx match, vaddr match, valid?
- if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
- (address & mask) == (env->itlb_tag[i] & mask) &&
- (env->itlb_tte[i] & 0x8000000000000000ULL)) {
+ if (ultrasparc_tag_match(&env->itlb[i],
+ address, context, physical)
+ ) {
// access ok?
- if ((env->itlb_tte[i] & 0x4) && is_user) {
- if (env->immuregs[3]) /* Fault status register */
- env->immuregs[3] = 2; /* overflow (not read before
+ if ((env->itlb[i].tte & 0x4) && is_user) {
+ if (env->immu.sfsr) /* Fault status register */
+ env->immu.sfsr = 2; /* overflow (not read before
another fault) */
- env->immuregs[3] |= (is_user << 3) | 1;
+ env->immu.sfsr |= (is_user << 3) | 1;
env->exception_index = TT_TFAULT;
#ifdef DEBUG_MMU
printf("TFAULT at 0x%" PRIx64 "\n", address);
#endif
return 1;
}
- *physical = ((env->itlb_tte[i] & mask) | (address & ~mask)) &
- 0x1ffffffe000ULL;
*prot = PAGE_EXEC;
+ TTE_SET_USED(env->itlb[i].tte);
return 0;
}
}
#ifdef DEBUG_MMU
printf("TMISS at 0x%" PRIx64 "\n", address);
#endif
- env->immuregs[6] = (address & ~0x1fffULL) | (env->dmmuregs[1] & 0x1fff);
+ /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
+ env->immu.tag_access = (address & ~0x1fffULL) | context;
env->exception_index = TT_TMISS;
return 1;
}
-static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
+static int get_physical_address(CPUState *env, a_target_phys_addr *physical,
int *prot, int *access_index,
target_ulong address, int rw, int mmu_idx)
{
int mmu_idx, int is_softmmu)
{
target_ulong virt_addr, vaddr;
- target_phys_addr_t paddr;
+ a_target_phys_addr paddr;
int error_code = 0, prot, ret = 0, access_index;
error_code = get_physical_address(env, &paddr, &prot, &access_index,
const char *mask;
printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n",
- env->dmmuregs[1], env->dmmuregs[2]);
+ env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context);
if ((env->lsu & DMMU_E) == 0) {
printf("DMMU disabled\n");
} else {
break;
}
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
- printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx
+ printf("[%02u] VA: " PRIx64 ", PA: " PRIx64
", %s, %s, %s, %s, ctx %" PRId64 "\n",
- env->dtlb_tag[i] & ~0x1fffULL,
- env->dtlb_tte[i] & 0x1ffffffe000ULL,
+ i,
+ env->dtlb_tag[i] & (uint64_t)~0x1fffULL,
+ env->dtlb_tte[i] & (uint64_t)0x1ffffffe000ULL,
mask,
env->dtlb_tte[i] & 0x4? "priv": "user",
env->dtlb_tte[i] & 0x2? "RW": "RO",
env->dtlb_tte[i] & 0x40? "locked": "unlocked",
- env->dtlb_tag[i] & 0x1fffULL);
+ env->dtlb_tag[i] & (uint64_t)0x1fffULL);
}
}
}
break;
}
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
- printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx
+ printf("[%02u] VA: " PRIx64 ", PA: " PRIx64
", %s, %s, %s, ctx %" PRId64 "\n",
- env->itlb_tag[i] & ~0x1fffULL,
- env->itlb_tte[i] & 0x1ffffffe000ULL,
+ i,
+ env->itlb[i].tag & (uint64_t)~0x1fffULL,
+ env->itlb_tte[i] & (uint64_t)0x1ffffffe000ULL,
mask,
env->itlb_tte[i] & 0x4? "priv": "user",
env->itlb_tte[i] & 0x40? "locked": "unlocked",
- env->itlb_tag[i] & 0x1fffULL);
+ env->itlb[i].tag & (uint64_t)0x1fffULL);
}
}
}
#if defined(CONFIG_USER_ONLY)
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+a_target_phys_addr cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
#else
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+a_target_phys_addr cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
- target_phys_addr_t phys_addr;
+ a_target_phys_addr phys_addr;
int prot, access_index;
if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
tlb_flush(env, 1);
env->cwp = 0;
+#ifndef TARGET_SPARC64
env->wim = 1;
+#endif
env->regwptr = env->regbase + (env->cwp * 16);
+ CC_OP = CC_OP_FLAGS;
#if defined(CONFIG_USER_ONLY)
#ifdef TARGET_SPARC64
env->cleanwin = env->nwindows - 2;
env->asi = 0x82; // Primary no-fault
#endif
#else
+#if !defined(TARGET_SPARC64)
env->psret = 0;
+#endif
env->psrs = 1;
env->psrps = 1;
#ifdef TARGET_SPARC64
- env->pstate = PS_PRIV;
+ env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
env->hpstate = HS_PRIV;
- env->tsptr = &env->ts[env->tl & MAXTL_MASK];
+ env->tl = env->maxtl;
+ cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
env->lsu = 0;
#else
env->mmuregs[0] &= ~(MMU_E | MMU_NF);
}
cpu_def->fpu_version = fpu_version;
#ifdef DEBUG_FEATURES
- fprintf(stderr, "fpu_version %llx\n", fpu_version);
+ fprintf(stderr, "fpu_version %x\n", fpu_version);
#endif
} else if (!strcmp(featurestr, "mmu_version")) {
char *err;
}
cpu_def->mmu_version = mmu_version;
#ifdef DEBUG_FEATURES
- fprintf(stderr, "mmu_version %llx\n", mmu_version);
+ fprintf(stderr, "mmu_version %x\n", mmu_version);
#endif
} else if (!strcmp(featurestr, "nwindows")) {
char *err;