target-sparc: Add MMU_PHYS_IDX

It's handy to have a mmu idx for physical addresses, so
that mmu disabled and physical access asis can use the
same path as normal accesses.

Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2016-07-12 21:01:29 -07:00
parent 2f9d35fc40
commit af7a06bac7
3 changed files with 53 additions and 46 deletions

View File

@ -225,9 +225,9 @@ enum {
#define MAX_NWINDOWS 32 #define MAX_NWINDOWS 32
#if !defined(TARGET_SPARC64) #if !defined(TARGET_SPARC64)
#define NB_MMU_MODES 2 #define NB_MMU_MODES 3
#else #else
#define NB_MMU_MODES 6 #define NB_MMU_MODES 7
typedef struct trap_state { typedef struct trap_state {
uint64_t tpc; uint64_t tpc;
uint64_t tnpc; uint64_t tnpc;
@ -649,11 +649,13 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
#define MMU_MODE4_SUFFIX _nucleus #define MMU_MODE4_SUFFIX _nucleus
#define MMU_HYPV_IDX 5 #define MMU_HYPV_IDX 5
#define MMU_MODE5_SUFFIX _hypv #define MMU_MODE5_SUFFIX _hypv
#define MMU_PHYS_IDX 6
#else #else
#define MMU_USER_IDX 0 #define MMU_USER_IDX 0
#define MMU_MODE0_SUFFIX _user #define MMU_MODE0_SUFFIX _user
#define MMU_KERNEL_IDX 1 #define MMU_KERNEL_IDX 1
#define MMU_MODE1_SUFFIX _kernel #define MMU_MODE1_SUFFIX _kernel
#define MMU_PHYS_IDX 2
#endif #endif
#if defined (TARGET_SPARC64) #if defined (TARGET_SPARC64)
@ -673,18 +675,27 @@ static inline int cpu_supervisor_mode(CPUSPARCState *env1)
} }
#endif #endif
static inline int cpu_mmu_index(CPUSPARCState *env1, bool ifetch) static inline int cpu_mmu_index(CPUSPARCState *env, bool ifetch)
{ {
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
return MMU_USER_IDX; return MMU_USER_IDX;
#elif !defined(TARGET_SPARC64) #elif !defined(TARGET_SPARC64)
return env1->psrs; if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
return MMU_PHYS_IDX;
} else {
return env->psrs;
}
#else #else
if (env1->tl > 0) { /* IMMU or DMMU disabled. */
if (ifetch
? (env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0
: (env->lsu & DMMU_E) == 0) {
return MMU_PHYS_IDX;
} else if (env->tl > 0) {
return MMU_NUCLEUS_IDX; return MMU_NUCLEUS_IDX;
} else if (cpu_hypervisor_mode(env1)) { } else if (cpu_hypervisor_mode(env)) {
return MMU_HYPV_IDX; return MMU_HYPV_IDX;
} else if (cpu_supervisor_mode(env1)) { } else if (cpu_supervisor_mode(env)) {
return MMU_KERNEL_IDX; return MMU_KERNEL_IDX;
} else { } else {
return MMU_USER_IDX; return MMU_USER_IDX;

View File

@ -887,10 +887,10 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val,
case 0: /* Control Register */ case 0: /* Control Register */
env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
(val & 0x00ffffff); (val & 0x00ffffff);
/* Mappings generated during no-fault mode or MMU /* Mappings generated during no-fault mode
disabled mode are invalid in normal mode */ are invalid in normal mode. */
if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) != if ((oldreg ^ env->mmuregs[reg])
(env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) { & (MMU_NF | env->def->mmu_bm)) {
tlb_flush(CPU(cpu), 1); tlb_flush(CPU(cpu), 1);
} }
break; break;
@ -1866,23 +1866,8 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
/* XXX */ /* XXX */
return; return;
case ASI_LSU_CONTROL: /* LSU */ case ASI_LSU_CONTROL: /* LSU */
{ env->lsu = val & (DMMU_E | IMMU_E);
uint64_t oldreg; return;
oldreg = env->lsu;
env->lsu = val & (DMMU_E | IMMU_E);
/* Mappings generated during D/I MMU disabled mode are
invalid in normal mode */
if (oldreg != env->lsu) {
DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
oldreg, env->lsu);
#ifdef DEBUG_MMU
dump_mmu(stdout, fprintf, env);
#endif
tlb_flush(CPU(cpu), 1);
}
return;
}
case ASI_IMMU: /* I-MMU regs */ case ASI_IMMU: /* I-MMU regs */
{ {
int reg = (addr >> 3) & 0xf; int reg = (addr >> 3) & 0xf;

View File

@ -92,7 +92,7 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
is_user = mmu_idx == MMU_USER_IDX; is_user = mmu_idx == MMU_USER_IDX;
if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ if (mmu_idx == MMU_PHYS_IDX) {
*page_size = TARGET_PAGE_SIZE; *page_size = TARGET_PAGE_SIZE;
/* Boot mode: instruction fetches are taken from PROM */ /* Boot mode: instruction fetches are taken from PROM */
if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) { if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
@ -494,23 +494,21 @@ static int get_physical_address_data(CPUSPARCState *env,
unsigned int i; unsigned int i;
uint64_t context; uint64_t context;
uint64_t sfsr = 0; uint64_t sfsr = 0;
bool is_user = false;
int is_user = (mmu_idx == MMU_USER_IDX ||
mmu_idx == MMU_USER_SECONDARY_IDX);
if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
*physical = ultrasparc_truncate_physical(address);
*prot = PAGE_READ | PAGE_WRITE;
return 0;
}
switch (mmu_idx) { switch (mmu_idx) {
case MMU_PHYS_IDX:
g_assert_not_reached();
case MMU_USER_IDX: case MMU_USER_IDX:
is_user = true;
/* fallthru */
case MMU_KERNEL_IDX: case MMU_KERNEL_IDX:
context = env->dmmu.mmu_primary_context & 0x1fff; context = env->dmmu.mmu_primary_context & 0x1fff;
sfsr |= SFSR_CT_PRIMARY; sfsr |= SFSR_CT_PRIMARY;
break; break;
case MMU_USER_SECONDARY_IDX: case MMU_USER_SECONDARY_IDX:
is_user = true;
/* fallthru */
case MMU_KERNEL_SECONDARY_IDX: case MMU_KERNEL_SECONDARY_IDX:
context = env->dmmu.mmu_secondary_context & 0x1fff; context = env->dmmu.mmu_secondary_context & 0x1fff;
sfsr |= SFSR_CT_SECONDARY; sfsr |= SFSR_CT_SECONDARY;
@ -613,15 +611,22 @@ static int get_physical_address_code(CPUSPARCState *env,
CPUState *cs = CPU(sparc_env_get_cpu(env)); CPUState *cs = CPU(sparc_env_get_cpu(env));
unsigned int i; unsigned int i;
uint64_t context; uint64_t context;
bool is_user = false;
int is_user = (mmu_idx == MMU_USER_IDX || switch (mmu_idx) {
mmu_idx == MMU_USER_SECONDARY_IDX); case MMU_PHYS_IDX:
case MMU_USER_SECONDARY_IDX:
if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) { case MMU_KERNEL_SECONDARY_IDX:
/* IMMU disabled */ g_assert_not_reached();
*physical = ultrasparc_truncate_physical(address); case MMU_USER_IDX:
*prot = PAGE_EXEC; is_user = true;
return 0; /* fallthru */
case MMU_KERNEL_IDX:
context = env->dmmu.mmu_primary_context & 0x1fff;
break;
default:
context = 0;
break;
} }
if (env->tl == 0) { if (env->tl == 0) {
@ -700,6 +705,12 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
} }
} }
if (mmu_idx == MMU_PHYS_IDX) {
*physical = ultrasparc_truncate_physical(address);
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
return 0;
}
if (rw == 2) { if (rw == 2) {
return get_physical_address_code(env, physical, prot, address, return get_physical_address_code(env, physical, prot, address,
mmu_idx); mmu_idx);