diff options
Diffstat (limited to 'target/sparc')
-rw-r--r-- | target/sparc/cpu.h | 3 | ||||
-rw-r--r-- | target/sparc/ldst_helper.c | 52 |
2 files changed, 47 insertions, 8 deletions
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 9e9b22a054..95a36a4bdc 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -384,6 +384,9 @@ enum { #define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */ #define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */ +#define CONVERT_BIT(X, SRC, DST) \ + (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC)) + typedef struct SparcTLBEntry { uint64_t tag; uint64_t tte; diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index c69167e78d..2c05d6af75 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -204,12 +204,34 @@ static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, } } +static uint64_t sun4v_tte_to_sun4u(CPUSPARCState *env, uint64_t tag, + uint64_t sun4v_tte) +{ + uint64_t sun4u_tte; + if (!(cpu_has_hypervisor(env) && (tag & TLB_UST1_IS_SUN4V_BIT))) { + /* is already in the sun4u format */ + return sun4v_tte; + } + sun4u_tte = TTE_PA(sun4v_tte) | (sun4v_tte & TTE_VALID_BIT); + sun4u_tte |= (sun4v_tte & 3ULL) << 61; /* TTE_PGSIZE */ + sun4u_tte |= CONVERT_BIT(sun4v_tte, TTE_NFO_BIT_UA2005, TTE_NFO_BIT); + sun4u_tte |= CONVERT_BIT(sun4v_tte, TTE_USED_BIT_UA2005, TTE_USED_BIT); + sun4u_tte |= CONVERT_BIT(sun4v_tte, TTE_W_OK_BIT_UA2005, TTE_W_OK_BIT); + sun4u_tte |= CONVERT_BIT(sun4v_tte, TTE_SIDEEFFECT_BIT_UA2005, + TTE_SIDEEFFECT_BIT); + sun4u_tte |= CONVERT_BIT(sun4v_tte, TTE_PRIV_BIT_UA2005, TTE_PRIV_BIT); + sun4u_tte |= CONVERT_BIT(sun4v_tte, TTE_LOCKED_BIT_UA2005, TTE_LOCKED_BIT); + return sun4u_tte; +} + static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, uint64_t tlb_tag, uint64_t tlb_tte, - const char *strmmu, CPUSPARCState *env1) + const char *strmmu, CPUSPARCState *env1, + uint64_t addr) { unsigned int i, replace_used; + tlb_tte = sun4v_tte_to_sun4u(env1, addr, tlb_tte); if (cpu_has_hypervisor(env1)) { uint64_t new_vaddr = tlb_tag & ~0x1fffULL; uint64_t new_size = 8192ULL << 3 * TTE_PGSIZE(tlb_tte); @@ -1617,7 +1639,11 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, return; } case ASI_ITLB_DATA_IN: /* I-MMU data in */ - replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env); + /* ignore real translation entries */ + if (!(addr & TLB_UST1_IS_REAL_BIT)) { + replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, + val, "immu", env, addr); + } return; case ASI_ITLB_DATA_ACCESS: /* I-MMU data access */ { @@ -1625,8 +1651,11 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, unsigned int i = (addr >> 3) & 0x3f; - replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env); - + /* ignore real translation entries */ + if (!(addr & TLB_UST1_IS_REAL_BIT)) { + replace_tlb_entry(&env->itlb[i], env->immu.tag_access, + sun4v_tte_to_sun4u(env, addr, val), env); + } #ifdef DEBUG_MMU DPRINTF_MMU("immu data access replaced entry [%i]\n", i); dump_mmu(stdout, fprintf, env); @@ -1694,14 +1723,21 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val, return; } case ASI_DTLB_DATA_IN: /* D-MMU data in */ - replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env); - return; + /* ignore real translation entries */ + if (!(addr & TLB_UST1_IS_REAL_BIT)) { + replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, + val, "dmmu", env, addr); + } + return; case ASI_DTLB_DATA_ACCESS: /* D-MMU data access */ { unsigned int i = (addr >> 3) & 0x3f; - replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env); - + /* ignore real translation entries */ + if (!(addr & TLB_UST1_IS_REAL_BIT)) { + replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, + sun4v_tte_to_sun4u(env, addr, val), env); + } #ifdef DEBUG_MMU DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); dump_mmu(stdout, fprintf, env); |