Improve PowerPC 405 MMU model / share more code for other embedded targets
support. Fix PowerPC 405 MSR mask. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2717 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
9c02f1a2e6
commit
c294fc587a
@ -881,9 +881,11 @@ void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value);
|
||||
target_ulong load_40x_pit (CPUPPCState *env);
|
||||
void store_40x_pit (CPUPPCState *env, target_ulong val);
|
||||
void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
|
||||
void store_40x_sler (CPUPPCState *env, uint32_t val);
|
||||
void store_booke_tcr (CPUPPCState *env, target_ulong val);
|
||||
void store_booke_tsr (CPUPPCState *env, target_ulong val);
|
||||
void ppc_tlb_invalidate_all (CPUPPCState *env);
|
||||
int ppcemb_tlb_search (CPUPPCState *env, target_ulong address);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -632,6 +632,58 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Generic TLB check function for embedded PowerPC implementations */
|
||||
static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb,
|
||||
target_phys_addr_t *raddrp,
|
||||
target_ulong address, int i)
|
||||
{
|
||||
target_ulong mask;
|
||||
|
||||
/* Check valid flag */
|
||||
if (!(tlb->prot & PAGE_VALID)) {
|
||||
if (loglevel != 0)
|
||||
fprintf(logfile, "%s: TLB %d not valid\n", __func__, i);
|
||||
return -1;
|
||||
}
|
||||
mask = ~(tlb->size - 1);
|
||||
if (loglevel != 0) {
|
||||
fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> "
|
||||
ADDRX " " ADDRX " %d\n",
|
||||
__func__, i, address, (int)env->spr[SPR_40x_PID],
|
||||
tlb->EPN, mask, (int)tlb->PID);
|
||||
}
|
||||
/* Check PID */
|
||||
if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
|
||||
return -1;
|
||||
/* Check effective address */
|
||||
if ((address & mask) != tlb->EPN)
|
||||
return -1;
|
||||
*raddrp = (tlb->RPN & mask) | (address & ~mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generic TLB search function for PowerPC embedded implementations */
|
||||
int ppcemb_tlb_search (CPUState *env, target_ulong address)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_phys_addr_t raddr;
|
||||
int i, ret;
|
||||
|
||||
/* Default return value is no match */
|
||||
ret = -1;
|
||||
for (i = 0; i < 64; i++) {
|
||||
tlb = &env->tlb[i].tlbe;
|
||||
if (ppcemb_tlb_check(env, tlb, &raddr, address, i) == 0) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Helpers specific to PowerPC 40x implementations */
|
||||
void ppc4xx_tlb_invalidate_all (CPUState *env)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
@ -656,33 +708,14 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_phys_addr_t raddr;
|
||||
target_ulong mask;
|
||||
int i, ret, zsel, zpr;
|
||||
|
||||
ret = -1;
|
||||
raddr = -1;
|
||||
for (i = 0; i < env->nb_tlb; i++) {
|
||||
tlb = &env->tlb[i].tlbe;
|
||||
/* Check valid flag */
|
||||
if (!(tlb->prot & PAGE_VALID)) {
|
||||
if (loglevel != 0)
|
||||
fprintf(logfile, "%s: TLB %d not valid\n", __func__, i);
|
||||
if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0)
|
||||
continue;
|
||||
}
|
||||
mask = ~(tlb->size - 1);
|
||||
if (loglevel != 0) {
|
||||
fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> "
|
||||
ADDRX " " ADDRX " %d\n",
|
||||
__func__, i, address, (int)env->spr[SPR_40x_PID],
|
||||
tlb->EPN, mask, (int)tlb->PID);
|
||||
}
|
||||
/* Check PID */
|
||||
if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
|
||||
continue;
|
||||
/* Check effective address */
|
||||
if ((address & mask) != tlb->EPN)
|
||||
continue;
|
||||
raddr = (tlb->RPN & mask) | (address & ~mask);
|
||||
zsel = (tlb->attr >> 4) & 0xF;
|
||||
zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
|
||||
if (loglevel != 0) {
|
||||
@ -692,6 +725,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
if (access_type == ACCESS_CODE) {
|
||||
/* Check execute enable bit */
|
||||
switch (zpr) {
|
||||
case 0x2:
|
||||
if (msr_pr)
|
||||
goto check_exec_perm;
|
||||
goto exec_granted;
|
||||
case 0x0:
|
||||
if (msr_pr) {
|
||||
ctx->prot = 0;
|
||||
@ -700,7 +737,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
}
|
||||
/* No break here */
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
check_exec_perm:
|
||||
/* Check from TLB entry */
|
||||
if (!(tlb->prot & PAGE_EXEC)) {
|
||||
ret = -3;
|
||||
@ -714,6 +751,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
exec_granted:
|
||||
/* All accesses granted */
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
ret = 0;
|
||||
@ -721,6 +759,10 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
}
|
||||
} else {
|
||||
switch (zpr) {
|
||||
case 0x2:
|
||||
if (msr_pr)
|
||||
goto check_rw_perm;
|
||||
goto rw_granted;
|
||||
case 0x0:
|
||||
if (msr_pr) {
|
||||
ctx->prot = 0;
|
||||
@ -729,7 +771,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
}
|
||||
/* No break here */
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
check_rw_perm:
|
||||
/* Check from TLB entry */
|
||||
/* Check write protection bit */
|
||||
if (tlb->prot & PAGE_WRITE) {
|
||||
@ -744,6 +786,7 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
rw_granted:
|
||||
/* All accesses granted */
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
ret = 0;
|
||||
@ -769,6 +812,15 @@ int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
void store_40x_sler (CPUPPCState *env, uint32_t val)
|
||||
{
|
||||
/* XXX: TO BE FIXED */
|
||||
if (val != 0x00000000) {
|
||||
cpu_abort(env, "Little-endian regions are not supported by now\n");
|
||||
}
|
||||
env->spr[SPR_405_SLER] = val;
|
||||
}
|
||||
|
||||
static int check_physical (CPUState *env, mmu_ctx_t *ctx,
|
||||
target_ulong eaddr, int rw)
|
||||
{
|
||||
|
@ -2459,6 +2459,12 @@ void OPPROTO op_store_40x_dbcr0 (void)
|
||||
store_40x_dbcr0(env, T0);
|
||||
}
|
||||
|
||||
void OPPROTO op_store_40x_sler (void)
|
||||
{
|
||||
store_40x_sler(env, T0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_store_booke_tcr (void)
|
||||
{
|
||||
store_booke_tcr(env, T0);
|
||||
|
@ -2494,44 +2494,16 @@ void do_4xx_tlbre_hi (void)
|
||||
T0 |= 0x100;
|
||||
}
|
||||
|
||||
static int tlb_4xx_search (target_ulong virtual)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_ulong base, mask;
|
||||
int i, ret;
|
||||
|
||||
/* Default return value is no match */
|
||||
ret = -1;
|
||||
for (i = 0; i < 64; i++) {
|
||||
tlb = &env->tlb[i].tlbe;
|
||||
/* Check TLB validity */
|
||||
if (!(tlb->prot & PAGE_VALID))
|
||||
continue;
|
||||
/* Check TLB PID vs current PID */
|
||||
if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
|
||||
continue;
|
||||
/* Check TLB address vs virtual address */
|
||||
base = tlb->EPN;
|
||||
mask = ~(tlb->size - 1);
|
||||
if ((base & mask) != (virtual & mask))
|
||||
continue;
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void do_4xx_tlbsx (void)
|
||||
{
|
||||
T0 = tlb_4xx_search(T0);
|
||||
T0 = ppcemb_tlb_search(env, T0);
|
||||
}
|
||||
|
||||
void do_4xx_tlbsx_ (void)
|
||||
{
|
||||
int tmp = xer_ov;
|
||||
|
||||
T0 = tlb_4xx_search(T0);
|
||||
T0 = ppcemb_tlb_search(env, T0);
|
||||
if (T0 != -1)
|
||||
tmp |= 0x02;
|
||||
env->crf[0] = tmp;
|
||||
@ -2562,16 +2534,28 @@ void do_4xx_tlbwe_hi (void)
|
||||
tlb_flush_page(env, page);
|
||||
}
|
||||
tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
|
||||
/* We cannot handle TLB size < TARGET_PAGE_SIZE.
|
||||
* If this ever occurs, one should use the ppcemb target instead
|
||||
* of the ppc or ppc64 one
|
||||
*/
|
||||
if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
|
||||
cpu_abort(env, "TLB size %u < %u are not supported (%d)\n",
|
||||
tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
|
||||
}
|
||||
tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
|
||||
if (T1 & 0x40)
|
||||
tlb->prot |= PAGE_VALID;
|
||||
else
|
||||
tlb->prot &= ~PAGE_VALID;
|
||||
if (T1 & 0x20) {
|
||||
/* XXX: TO BE FIXED */
|
||||
cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
|
||||
}
|
||||
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
|
||||
if (loglevel != 0) {
|
||||
fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " 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' : '-',
|
||||
|
@ -355,6 +355,17 @@ static void spr_write_40x_dbcr0 (void *opaque, int sprn)
|
||||
RET_STOP(ctx);
|
||||
}
|
||||
|
||||
static void spr_write_40x_sler (void *opaque, int sprn)
|
||||
{
|
||||
DisasContext *ctx = opaque;
|
||||
|
||||
gen_op_store_40x_sler();
|
||||
/* We must stop the translation as we may have changed
|
||||
* some regions endianness
|
||||
*/
|
||||
RET_STOP(ctx);
|
||||
}
|
||||
|
||||
static void spr_write_booke_tcr (void *opaque, int sprn)
|
||||
{
|
||||
gen_op_store_booke_tcr();
|
||||
@ -1711,10 +1722,9 @@ static void gen_spr_405 (CPUPPCState *env)
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
/* Storage control */
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_405_SLER, "SLER",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
&spr_read_generic, &spr_write_40x_sler,
|
||||
0x00000000);
|
||||
/* XXX : not implemented */
|
||||
spr_register(env, SPR_405_SU0R, "SU0R",
|
||||
@ -2837,7 +2847,7 @@ static ppc_def_t ppc_defs[] = {
|
||||
.pvr_mask = 0xFFFFFFFF,
|
||||
.insns_flags = PPC_INSNS_405,
|
||||
.flags = PPC_FLAGS_405,
|
||||
.msr_mask = 0x00000000020EFF30ULL,
|
||||
.msr_mask = 0x00000000000ED630ULL,
|
||||
},
|
||||
#if defined (TODO)
|
||||
/* PowerPC 405 EZ */
|
||||
|
Loading…
Reference in New Issue
Block a user