PowerPC 4xx software driven TLB fixes + debug traces.
Add code provision for more MMU models support. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2683 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
0a032cbec6
commit
c55e9aefa7
@ -581,12 +581,12 @@ struct ppc6xx_tlb_t {
|
||||
|
||||
typedef struct ppcemb_tlb_t ppcemb_tlb_t;
|
||||
struct ppcemb_tlb_t {
|
||||
target_ulong RPN;
|
||||
target_phys_addr_t RPN;
|
||||
target_ulong EPN;
|
||||
target_ulong PID;
|
||||
int size;
|
||||
int prot;
|
||||
int attr; /* Storage attributes */
|
||||
target_ulong size;
|
||||
uint32_t prot;
|
||||
uint32_t attr; /* Storage attributes */
|
||||
};
|
||||
|
||||
union ppc_tlb_t {
|
||||
@ -765,10 +765,6 @@ struct CPUPPCState {
|
||||
int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */
|
||||
int nb_pids; /* Number of available PID registers */
|
||||
ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */
|
||||
/* Callbacks for specific checks on some implementations */
|
||||
int (*tlb_check_more)(CPUPPCState *env, ppc_tlb_t *tlb, int *prot,
|
||||
target_ulong vaddr, int rw, int acc_type,
|
||||
int is_user);
|
||||
/* 403 dedicated access protection registers */
|
||||
target_ulong pb[4];
|
||||
|
||||
|
@ -657,7 +657,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
target_ulong mask;
|
||||
int i, ret, zsel, zpr;
|
||||
|
||||
ret = -6;
|
||||
ret = -1;
|
||||
raddr = -1;
|
||||
for (i = 0; i < env->nb_tlb; i++) {
|
||||
tlb = &env->tlb[i].tlbe;
|
||||
/* Check valid flag */
|
||||
@ -691,8 +692,8 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
switch (zpr) {
|
||||
case 0x0:
|
||||
if (msr_pr) {
|
||||
ret = -3;
|
||||
ctx->prot = 0;
|
||||
ret = -3;
|
||||
break;
|
||||
}
|
||||
/* No break here */
|
||||
@ -702,25 +703,26 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
if (!(tlb->prot & PAGE_EXEC)) {
|
||||
ret = -3;
|
||||
} else {
|
||||
if (tlb->prot & PAGE_WRITE)
|
||||
if (tlb->prot & PAGE_WRITE) {
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
else
|
||||
} else {
|
||||
ctx->prot = PAGE_READ;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
/* All accesses granted */
|
||||
ret = 0;
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (zpr) {
|
||||
case 0x0:
|
||||
if (msr_pr) {
|
||||
ret = -2;
|
||||
ctx->prot = 0;
|
||||
ret = -2;
|
||||
break;
|
||||
}
|
||||
/* No break here */
|
||||
@ -728,20 +730,21 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
case 0x2:
|
||||
/* Check from TLB entry */
|
||||
/* Check write protection bit */
|
||||
if (rw && !(tlb->prot & PAGE_WRITE)) {
|
||||
ret = -2;
|
||||
if (tlb->prot & PAGE_WRITE) {
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = 2;
|
||||
if (tlb->prot & PAGE_WRITE)
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
ctx->prot = PAGE_READ;
|
||||
if (rw)
|
||||
ret = -2;
|
||||
else
|
||||
ctx->prot = PAGE_READ;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
/* All accesses granted */
|
||||
ret = 2;
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -749,11 +752,17 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
ctx->raddr = raddr;
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s: access granted " ADDRX " => " REGX
|
||||
" %d\n", __func__, address, ctx->raddr, ctx->prot);
|
||||
" %d %d\n", __func__, address, ctx->raddr, ctx->prot,
|
||||
ret);
|
||||
}
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s: access refused " ADDRX " => " REGX
|
||||
" %d %d\n", __func__, address, raddr, ctx->prot,
|
||||
ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -808,32 +817,49 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
|
||||
/* No address translation */
|
||||
ret = check_physical(env, ctx, eaddr, rw);
|
||||
} else {
|
||||
ret = -1;
|
||||
switch (PPC_MMU(env)) {
|
||||
case PPC_FLAGS_MMU_32B:
|
||||
case PPC_FLAGS_MMU_SOFT_6xx:
|
||||
/* Try to find a BAT */
|
||||
ret = -1;
|
||||
if (check_BATs)
|
||||
ret = get_bat(env, ctx, eaddr, rw, access_type);
|
||||
/* No break here */
|
||||
#if defined(TARGET_PPC64)
|
||||
case PPC_FLAGS_MMU_64B:
|
||||
case PPC_FLAGS_MMU_64BRIDGE:
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
/* We didn't match any BAT entry */
|
||||
/* We didn't match any BAT entry or don't have BATs */
|
||||
ret = get_segment(env, ctx, eaddr, rw, access_type);
|
||||
}
|
||||
break;
|
||||
case PPC_FLAGS_MMU_SOFT_4xx:
|
||||
case PPC_FLAGS_MMU_403:
|
||||
ret = mmu4xx_get_physical_address(env, ctx, eaddr,
|
||||
rw, access_type);
|
||||
break;
|
||||
default:
|
||||
case PPC_FLAGS_MMU_601:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
cpu_abort(env, "601 MMU model not implemented\n");
|
||||
return -1;
|
||||
case PPC_FLAGS_MMU_BOOKE:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookeE MMU model not implemented\n");
|
||||
return -1;
|
||||
case PPC_FLAGS_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "BookE FSL MMU model not implemented\n");
|
||||
return -1;
|
||||
default:
|
||||
cpu_abort(env, "Unknown or invalid MMU model\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (loglevel > 0) {
|
||||
fprintf(logfile, "%s address " ADDRX " => " ADDRX "\n",
|
||||
__func__, eaddr, ctx->raddr);
|
||||
fprintf(logfile, "%s address " ADDRX " => %d " ADDRX "\n",
|
||||
__func__, eaddr, ret, ctx->raddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -885,19 +911,48 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
switch (ret) {
|
||||
case -1:
|
||||
/* No matches in page tables or TLB */
|
||||
if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
|
||||
switch (PPC_MMU(env)) {
|
||||
case PPC_FLAGS_MMU_SOFT_6xx:
|
||||
exception = EXCP_I_TLBMISS;
|
||||
env->spr[SPR_IMISS] = address;
|
||||
env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
|
||||
error_code = 1 << 18;
|
||||
goto tlb_miss;
|
||||
} else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
|
||||
case PPC_FLAGS_MMU_SOFT_4xx:
|
||||
case PPC_FLAGS_MMU_403:
|
||||
exception = EXCP_40x_ITLBMISS;
|
||||
error_code = 0;
|
||||
env->spr[SPR_40x_DEAR] = address;
|
||||
env->spr[SPR_40x_ESR] = 0x00000000;
|
||||
} else {
|
||||
break;
|
||||
case PPC_FLAGS_MMU_32B:
|
||||
error_code = 0x40000000;
|
||||
break;
|
||||
#if defined(TARGET_PPC64)
|
||||
case PPC_FLAGS_MMU_64B:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
case PPC_FLAGS_MMU_64BRIDGE:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
#endif
|
||||
case PPC_FLAGS_MMU_601:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
case PPC_FLAGS_MMU_BOOKE:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
case PPC_FLAGS_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
default:
|
||||
cpu_abort(env, "Unknown or invalid MMU model\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case -2:
|
||||
@ -924,7 +979,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
switch (ret) {
|
||||
case -1:
|
||||
/* No matches in page tables or TLB */
|
||||
if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
|
||||
switch (PPC_MMU(env)) {
|
||||
case PPC_FLAGS_MMU_SOFT_6xx:
|
||||
if (rw == 1) {
|
||||
exception = EXCP_DS_TLBMISS;
|
||||
error_code = 1 << 16;
|
||||
@ -940,7 +996,8 @@ 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;
|
||||
} else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
|
||||
case PPC_FLAGS_MMU_SOFT_4xx:
|
||||
case PPC_FLAGS_MMU_403:
|
||||
exception = EXCP_40x_DTLBMISS;
|
||||
error_code = 0;
|
||||
env->spr[SPR_40x_DEAR] = address;
|
||||
@ -948,8 +1005,35 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
|
||||
env->spr[SPR_40x_ESR] = 0x00800000;
|
||||
else
|
||||
env->spr[SPR_40x_ESR] = 0x00000000;
|
||||
} else {
|
||||
break;
|
||||
case PPC_FLAGS_MMU_32B:
|
||||
error_code = 0x40000000;
|
||||
break;
|
||||
#if defined(TARGET_PPC64)
|
||||
case PPC_FLAGS_MMU_64B:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
case PPC_FLAGS_MMU_64BRIDGE:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
#endif
|
||||
case PPC_FLAGS_MMU_601:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
case PPC_FLAGS_MMU_BOOKE:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
case PPC_FLAGS_MMU_BOOKE_FSL:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
default:
|
||||
cpu_abort(env, "Unknown or invalid MMU model\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case -2:
|
||||
|
@ -2537,39 +2537,72 @@ void do_4xx_tlbsx_ (void)
|
||||
env->crf[0] = tmp;
|
||||
}
|
||||
|
||||
void do_4xx_tlbwe_lo (void)
|
||||
void do_4xx_tlbwe_hi (void)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_ulong page, end;
|
||||
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
|
||||
}
|
||||
#endif
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
/* Invalidate previous TLB (if it's valid) */
|
||||
if (tlb->prot & PAGE_VALID) {
|
||||
end = tlb->EPN + tlb->size;
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
|
||||
" end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
|
||||
}
|
||||
#endif
|
||||
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
|
||||
tlb_flush_page(env, page);
|
||||
}
|
||||
tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
|
||||
tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
|
||||
if (T1 & 0x400)
|
||||
if (T1 & 0x40)
|
||||
tlb->prot |= PAGE_VALID;
|
||||
else
|
||||
tlb->prot &= ~PAGE_VALID;
|
||||
tlb->PID = env->spr[SPR_BOOKE_PID]; /* PID */
|
||||
tlb->PID = env->spr[SPR_40x_PID]; /* PID */
|
||||
tlb->attr = T1 & 0xFF;
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX
|
||||
" size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
|
||||
(int)T0, tlb->RPN, tlb->EPN, tlb->size,
|
||||
tlb->prot & PAGE_READ ? 'r' : '-',
|
||||
tlb->prot & PAGE_WRITE ? 'w' : '-',
|
||||
tlb->prot & PAGE_EXEC ? 'x' : '-',
|
||||
tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
|
||||
}
|
||||
#endif
|
||||
/* Invalidate new TLB (if valid) */
|
||||
if (tlb->prot & PAGE_VALID) {
|
||||
end = tlb->EPN + tlb->size;
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
|
||||
" end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
|
||||
}
|
||||
#endif
|
||||
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
|
||||
tlb_flush_page(env, page);
|
||||
}
|
||||
}
|
||||
|
||||
void do_4xx_tlbwe_hi (void)
|
||||
void do_4xx_tlbwe_lo (void)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
|
||||
}
|
||||
#endif
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
tlb->RPN = T1 & 0xFFFFFC00;
|
||||
@ -2578,5 +2611,16 @@ void do_4xx_tlbwe_hi (void)
|
||||
tlb->prot |= PAGE_EXEC;
|
||||
if (T1 & 0x100)
|
||||
tlb->prot |= PAGE_WRITE;
|
||||
#if defined (DEBUG_SOFTWARE_TLB)
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s: set up TLB %d RPN " ADDRX " EPN " ADDRX
|
||||
" size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
|
||||
(int)T0, tlb->RPN, tlb->EPN, tlb->size,
|
||||
tlb->prot & PAGE_READ ? 'r' : '-',
|
||||
tlb->prot & PAGE_WRITE ? 'w' : '-',
|
||||
tlb->prot & PAGE_EXEC ? 'x' : '-',
|
||||
tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
Loading…
Reference in New Issue
Block a user