Handle all MMU models in switches, even if it's just to abort because of lack
of supporting code. Implement 74xx software TLB model. Keep 74xx with software TLB disabled, as Linux is not able to handle TLB miss on those processors. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3307 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
578bb25230
commit
7dbe11acd8
@ -664,7 +664,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||
int ret, ret2;
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
if (env->mmu_model == POWERPC_MMU_64B) {
|
||||
if (env->mmu_model == POWERPC_MMU_64B ||
|
||||
env->mmu_model == POWERPC_MMU_64BRIDGE) {
|
||||
ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -730,7 +731,8 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||
}
|
||||
/* Initialize real address with an invalid value */
|
||||
ctx->raddr = (target_ulong)-1;
|
||||
if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) {
|
||||
if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
|
||||
env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
|
||||
/* Software TLB search */
|
||||
ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
|
||||
} else {
|
||||
@ -1092,9 +1094,11 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_SOFT_6xx:
|
||||
case POWERPC_MMU_SOFT_74xx:
|
||||
case POWERPC_MMU_601:
|
||||
case POWERPC_MMU_SOFT_4xx:
|
||||
case POWERPC_MMU_REAL_4xx:
|
||||
case POWERPC_MMU_BOOKE:
|
||||
ctx->prot |= PAGE_WRITE;
|
||||
break;
|
||||
#if defined(TARGET_PPC64)
|
||||
@ -1129,9 +1133,6 @@ static int check_physical (CPUState *env, mmu_ctx_t *ctx,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE:
|
||||
ctx->prot |= PAGE_WRITE;
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookE FSL MMU model not implemented\n");
|
||||
@ -1162,6 +1163,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_SOFT_6xx:
|
||||
case POWERPC_MMU_SOFT_74xx:
|
||||
/* Try to find a BAT */
|
||||
if (check_BATs)
|
||||
ret = get_bat(env, ctx, eaddr, rw, access_type);
|
||||
@ -1262,6 +1264,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
|
||||
error_code = 1 << 18;
|
||||
goto tlb_miss;
|
||||
case POWERPC_MMU_SOFT_74xx:
|
||||
exception = POWERPC_EXCP_IFTLB;
|
||||
goto tlb_miss_74xx;
|
||||
case POWERPC_MMU_SOFT_4xx:
|
||||
case POWERPC_MMU_SOFT_4xx_Z:
|
||||
exception = POWERPC_EXCP_ITLB;
|
||||
@ -1346,6 +1351,19 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
env->spr[SPR_HASH2] = ctx.pg_addr[1];
|
||||
/* Do not alter DAR nor DSISR */
|
||||
goto out;
|
||||
case POWERPC_MMU_SOFT_74xx:
|
||||
if (rw == 1) {
|
||||
exception = POWERPC_EXCP_DSTLB;
|
||||
} else {
|
||||
exception = POWERPC_EXCP_DLTLB;
|
||||
}
|
||||
tlb_miss_74xx:
|
||||
/* Implement LRU algorithm */
|
||||
env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
|
||||
((env->last_way + 1) & (env->nb_ways - 1));
|
||||
env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
|
||||
error_code = ctx.key << 19;
|
||||
break;
|
||||
case POWERPC_MMU_SOFT_4xx:
|
||||
case POWERPC_MMU_SOFT_4xx_Z:
|
||||
exception = POWERPC_EXCP_DTLB;
|
||||
@ -1571,13 +1589,31 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
|
||||
{
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_SOFT_6xx:
|
||||
case POWERPC_MMU_SOFT_74xx:
|
||||
ppc6xx_tlb_invalidate_all(env);
|
||||
break;
|
||||
case POWERPC_MMU_SOFT_4xx:
|
||||
case POWERPC_MMU_SOFT_4xx_Z:
|
||||
ppc4xx_tlb_invalidate_all(env);
|
||||
break;
|
||||
default:
|
||||
case POWERPC_MMU_REAL_4xx:
|
||||
cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_601:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_32B:
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_64BRIDGE:
|
||||
tlb_flush(env, 1);
|
||||
break;
|
||||
}
|
||||
@ -1589,6 +1625,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_SOFT_6xx:
|
||||
case POWERPC_MMU_SOFT_74xx:
|
||||
ppc6xx_tlb_invalidate_virt(env, addr, 0);
|
||||
if (env->id_tlbs == 1)
|
||||
ppc6xx_tlb_invalidate_virt(env, addr, 1);
|
||||
@ -1597,7 +1634,22 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
|
||||
case POWERPC_MMU_SOFT_4xx_Z:
|
||||
ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
|
||||
break;
|
||||
default:
|
||||
case POWERPC_MMU_REAL_4xx:
|
||||
cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_601:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
break;
|
||||
case POWERPC_MMU_32B:
|
||||
/* tlbie invalidate TLBs for all segments */
|
||||
addr &= ~((target_ulong)-1 << 28);
|
||||
/* XXX: this case should be optimized,
|
||||
@ -1619,6 +1671,15 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
|
||||
tlb_flush_page(env, addr | (0xD << 28));
|
||||
tlb_flush_page(env, addr | (0xE << 28));
|
||||
tlb_flush_page(env, addr | (0xF << 28));
|
||||
break;
|
||||
case POWERPC_MMU_64B:
|
||||
case POWERPC_MMU_64BRIDGE:
|
||||
/* tlbie invalidate TLBs for all segments */
|
||||
/* XXX: given the fact that there are too many segments to invalidate,
|
||||
* we just invalidate all TLBs
|
||||
*/
|
||||
tlb_flush(env, 1);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
ppc_tlb_invalidate_all(env);
|
||||
@ -2317,6 +2378,8 @@ static always_inline void powerpc_excp (CPUState *env,
|
||||
goto tlb_miss_tgpr;
|
||||
case POWERPC_EXCP_7x5:
|
||||
goto tlb_miss;
|
||||
case POWERPC_EXCP_74xx:
|
||||
goto tlb_miss_74xx;
|
||||
default:
|
||||
cpu_abort(env, "Invalid instruction TLB miss exception\n");
|
||||
break;
|
||||
@ -2336,6 +2399,8 @@ static always_inline void powerpc_excp (CPUState *env,
|
||||
goto tlb_miss_tgpr;
|
||||
case POWERPC_EXCP_7x5:
|
||||
goto tlb_miss;
|
||||
case POWERPC_EXCP_74xx:
|
||||
goto tlb_miss_74xx;
|
||||
default:
|
||||
cpu_abort(env, "Invalid data load TLB miss exception\n");
|
||||
break;
|
||||
@ -2390,6 +2455,34 @@ static always_inline void powerpc_excp (CPUState *env,
|
||||
/* Set way using a LRU mechanism */
|
||||
msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
|
||||
break;
|
||||
case POWERPC_EXCP_74xx:
|
||||
tlb_miss_74xx:
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
if (loglevel != 0) {
|
||||
const unsigned char *es;
|
||||
target_ulong *miss, *cmp;
|
||||
int en;
|
||||
if (excp == POWERPC_EXCP_IFTLB) {
|
||||
es = "I";
|
||||
en = 'I';
|
||||
miss = &env->spr[SPR_IMISS];
|
||||
cmp = &env->spr[SPR_ICMP];
|
||||
} else {
|
||||
if (excp == POWERPC_EXCP_DLTLB)
|
||||
es = "DL";
|
||||
else
|
||||
es = "DS";
|
||||
en = 'D';
|
||||
miss = &env->spr[SPR_TLBMISS];
|
||||
cmp = &env->spr[SPR_PTEHI];
|
||||
}
|
||||
fprintf(logfile, "74xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
|
||||
" %08x\n",
|
||||
es, en, *miss, en, *cmp, env->error_code);
|
||||
}
|
||||
#endif
|
||||
msr |= env->error_code; /* key bit */
|
||||
break;
|
||||
default:
|
||||
cpu_abort(env, "Invalid data store TLB miss exception\n");
|
||||
break;
|
||||
|
@ -2025,8 +2025,8 @@ void OPPROTO op_slbie_64 (void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* PowerPC 602/603/755 software TLB load instructions */
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* PowerPC 602/603/755 software TLB load instructions */
|
||||
void OPPROTO op_6xx_tlbld (void)
|
||||
{
|
||||
do_load_6xx_tlb(0);
|
||||
@ -2038,6 +2038,19 @@ void OPPROTO op_6xx_tlbli (void)
|
||||
do_load_6xx_tlb(1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
/* PowerPC 74xx software TLB load instructions */
|
||||
void OPPROTO op_74xx_tlbld (void)
|
||||
{
|
||||
do_load_74xx_tlb(0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_74xx_tlbli (void)
|
||||
{
|
||||
do_load_74xx_tlb(1);
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 601 specific */
|
||||
|
@ -2363,6 +2363,27 @@ void do_load_6xx_tlb (int is_code)
|
||||
way, is_code, CMP, RPN);
|
||||
}
|
||||
|
||||
void do_load_74xx_tlb (int is_code)
|
||||
{
|
||||
target_ulong RPN, CMP, EPN;
|
||||
int way;
|
||||
|
||||
RPN = env->spr[SPR_PTELO];
|
||||
CMP = env->spr[SPR_PTEHI];
|
||||
EPN = env->spr[SPR_TLBMISS] & ~0x3;
|
||||
way = env->spr[SPR_TLBMISS] & 0x3;
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
if (loglevel != 0) {
|
||||
fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
|
||||
__func__, (unsigned long)T0, (unsigned long)EPN,
|
||||
(unsigned long)CMP, (unsigned long)RPN, way);
|
||||
}
|
||||
#endif
|
||||
/* Store this TLB */
|
||||
ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
|
||||
way, is_code, CMP, RPN);
|
||||
}
|
||||
|
||||
static target_ulong booke_tlb_to_page_size (int size)
|
||||
{
|
||||
return 1024 << (2 * size);
|
||||
|
@ -135,6 +135,7 @@ void do_rfid (void);
|
||||
void do_hrfid (void);
|
||||
#endif
|
||||
void do_load_6xx_tlb (int is_code);
|
||||
void do_load_74xx_tlb (int is_code);
|
||||
#endif
|
||||
|
||||
/* POWER / PowerPC 601 specific helpers */
|
||||
|
@ -4299,7 +4299,7 @@ GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
|
||||
|
||||
/* 602 - 603 - G2 TLB management */
|
||||
/* tlbld */
|
||||
GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
|
||||
GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
GEN_EXCP_PRIVOPC(ctx);
|
||||
@ -4314,7 +4314,7 @@ GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
|
||||
}
|
||||
|
||||
/* tlbli */
|
||||
GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
|
||||
GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
GEN_EXCP_PRIVOPC(ctx);
|
||||
@ -4328,6 +4328,37 @@ GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 74xx TLB management */
|
||||
/* tlbld */
|
||||
GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
GEN_EXCP_PRIVOPC(ctx);
|
||||
#else
|
||||
if (unlikely(!ctx->supervisor)) {
|
||||
GEN_EXCP_PRIVOPC(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_load_gpr_T0(rB(ctx->opcode));
|
||||
gen_op_74xx_tlbld();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* tlbli */
|
||||
GEN_HANDLER(tlbli_74xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
GEN_EXCP_PRIVOPC(ctx);
|
||||
#else
|
||||
if (unlikely(!ctx->supervisor)) {
|
||||
GEN_EXCP_PRIVOPC(ctx);
|
||||
return;
|
||||
}
|
||||
gen_op_load_gpr_T0(rB(ctx->opcode));
|
||||
gen_op_74xx_tlbli();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* POWER instructions not in PowerPC 601 */
|
||||
/* clf */
|
||||
GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)
|
||||
|
Loading…
Reference in New Issue
Block a user