Code provision for PowerPC BookE MMU model support.

Better MSR flags initialisation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3189 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
j_mayer 2007-09-19 05:44:04 +00:00
parent 1527c87eee
commit 5eb7995e34
5 changed files with 365 additions and 14 deletions

View File

@ -1013,6 +1013,52 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
env->spr[SPR_405_SLER] = val;
}
int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
target_ulong address, int rw,
int access_type)
{
ppcemb_tlb_t *tlb;
target_phys_addr_t raddr;
int i, prot, ret;
ret = -1;
raddr = -1;
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb[i].tlbe;
if (ppcemb_tlb_check(env, tlb, &raddr, address,
env->spr[SPR_BOOKE_PID], 1, i) < 0)
continue;
if (msr_pr)
prot = tlb->prot & 0xF;
else
prot = (tlb->prot >> 4) & 0xF;
/* Check the address space */
if (access_type == ACCESS_CODE) {
if (msr_is != (tlb->attr & 1))
continue;
ctx->prot = prot;
if (prot & PAGE_EXEC) {
ret = 0;
break;
}
ret = -3;
} else {
if (msr_ds != (tlb->attr & 1))
continue;
ctx->prot = prot;
if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
ret = 0;
break;
}
ret = -2;
}
}
if (ret >= 0)
ctx->raddr = raddr;
return ret;
}
static int check_physical (CPUState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw)
{
@ -1115,9 +1161,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
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;
ret = mmubooke_get_physical_address(env, ctx, eaddr,
rw, access_type);
break;
case PPC_FLAGS_MMU_BOOKE_FSL:
/* XXX: TODO */
cpu_abort(env, "BookE FSL MMU model not implemented\n");
@ -1950,7 +1996,7 @@ void do_interrupt (CPUState *env)
cpu_abort(env, "Floating point assist exception "
"is not implemented yet !\n");
goto store_next;
/* 64 bits PowerPC exceptions */
/* 64 bits PowerPC exceptions */
case EXCP_DSEG: /* 0x0380 */
/* XXX: TODO */
cpu_abort(env, "Data segment exception is not implemented yet !\n");
@ -2446,28 +2492,39 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr)
void cpu_ppc_reset (void *opaque)
{
CPUPPCState *env;
int i;
env = opaque;
/* XXX: some of those flags initialisation values could depend
* on the actual PowerPC implementation
*/
for (i = 0; i < 63; i++)
env->msr[i] = 0;
#if defined(TARGET_PPC64)
msr_hv = 0; /* Should be 1... */
#endif
msr_ap = 0; /* TO BE CHECKED */
msr_sa = 0; /* TO BE CHECKED */
msr_ip = 0; /* TO BE CHECKED */
#if defined (DO_SINGLE_STEP) && 0
/* Single step trace mode */
msr_se = 1;
msr_be = 1;
#endif
msr_fp = 1; /* Allow floating point exceptions */
msr_me = 1; /* Allow machine check exceptions */
#if defined(TARGET_PPC64)
msr_sf = 0; /* Boot in 32 bits mode */
msr_cm = 0;
#endif
#if defined(CONFIG_USER_ONLY)
msr_fp = 1; /* Allow floating point exceptions */
msr_pr = 1;
tlb_flush(env, 1);
#else
env->nip = 0xFFFFFFFC;
ppc_tlb_invalidate_all(env);
#endif
do_compute_hflags(env);
env->reserve = -1;
/* Be sure no exception or interrupt is pending */
env->pending_interrupts = 0;
env->exception_index = EXCP_NONE;
/* Flush all TLBs */
tlb_flush(env, 1);
}
CPUPPCState *cpu_ppc_init (void)

View File

@ -2365,6 +2365,54 @@ void OPPROTO op_wrte (void)
RETURN();
}
void OPPROTO op_booke_tlbre0 (void)
{
do_booke_tlbre0();
RETURN();
}
void OPPROTO op_booke_tlbre1 (void)
{
do_booke_tlbre1();
RETURN();
}
void OPPROTO op_booke_tlbre2 (void)
{
do_booke_tlbre2();
RETURN();
}
void OPPROTO op_booke_tlbsx (void)
{
do_booke_tlbsx();
RETURN();
}
void OPPROTO op_booke_tlbsx_ (void)
{
do_booke_tlbsx_();
RETURN();
}
void OPPROTO op_booke_tlbwe0 (void)
{
do_booke_tlbwe0();
RETURN();
}
void OPPROTO op_booke_tlbwe1 (void)
{
do_booke_tlbwe1();
RETURN();
}
void OPPROTO op_booke_tlbwe2 (void)
{
do_booke_tlbwe2();
RETURN();
}
void OPPROTO op_4xx_tlbre_lo (void)
{
do_4xx_tlbre_lo();

View File

@ -2605,4 +2605,151 @@ void do_4xx_tlbwe_lo (void)
}
#endif
}
/* BookE TLB management */
void do_booke_tlbwe0 (void)
{
ppcemb_tlb_t *tlb;
target_ulong EPN, size;
int do_flush_tlbs;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
}
#endif
do_flush_tlbs = 0;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
EPN = T1 & 0xFFFFFC00;
if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
do_flush_tlbs = 1;
tlb->EPN = EPN;
size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
if ((tlb->prot & PAGE_VALID) && tlb->size < size)
do_flush_tlbs = 1;
tlb->size = size;
tlb->attr &= ~0x1;
tlb->attr |= (T1 >> 8) & 1;
if (T1 & 0x200) {
tlb->prot |= PAGE_VALID;
} else {
if (tlb->prot & PAGE_VALID) {
tlb->prot &= ~PAGE_VALID;
do_flush_tlbs = 1;
}
}
tlb->PID = env->spr[SPR_BOOKE_PID];
if (do_flush_tlbs)
tlb_flush(env, 1);
}
void do_booke_tlbwe1 (void)
{
ppcemb_tlb_t *tlb;
target_phys_addr_t RPN;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
}
#endif
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
RPN = T1 & 0xFFFFFC0F;
if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
tlb_flush(env, 1);
tlb->RPN = RPN;
}
void do_booke_tlbwe2 (void)
{
ppcemb_tlb_t *tlb;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
}
#endif
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
tlb->prot = tlb->prot & PAGE_VALID;
if (T1 & 0x1)
tlb->prot |= PAGE_READ << 4;
if (T1 & 0x2)
tlb->prot |= PAGE_WRITE << 4;
if (T1 & 0x4)
tlb->prot |= PAGE_EXEC << 4;
if (T1 & 0x8)
tlb->prot |= PAGE_READ;
if (T1 & 0x10)
tlb->prot |= PAGE_WRITE;
if (T1 & 0x20)
tlb->prot |= PAGE_EXEC;
}
void do_booke_tlbsx (void)
{
T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]);
}
void do_booke_tlbsx_ (void)
{
int tmp = xer_so;
T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]);
if (T0 != -1)
tmp |= 0x02;
env->crf[0] = tmp;
}
void do_booke_tlbre0 (void)
{
ppcemb_tlb_t *tlb;
int size;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
T0 = tlb->EPN;
size = booke_page_size_to_tlb(tlb->size);
if (size < 0 || size > 0xF)
size = 1;
T0 |= size << 4;
if (tlb->attr & 0x1)
T0 |= 0x100;
if (tlb->prot & PAGE_VALID)
T0 |= 0x200;
env->spr[SPR_BOOKE_PID] = tlb->PID;
}
void do_booke_tlbre1 (void)
{
ppcemb_tlb_t *tlb;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
T0 = tlb->RPN;
}
void do_booke_tlbre2 (void)
{
ppcemb_tlb_t *tlb;
T0 &= 0x3F;
tlb = &env->tlb[T0].tlbe;
T0 = tlb->attr & ~0x1;
if (tlb->prot & (PAGE_READ << 4))
T0 |= 0x1;
if (tlb->prot & (PAGE_WRITE << 4))
T0 |= 0x2;
if (tlb->prot & (PAGE_EXEC << 4))
T0 |= 0x4;
if (tlb->prot & PAGE_READ)
T0 |= 0x8;
if (tlb->prot & PAGE_WRITE)
T0 |= 0x10;
if (tlb->prot & PAGE_EXEC)
T0 |= 0x20;
}
#endif /* !CONFIG_USER_ONLY */

View File

@ -156,6 +156,18 @@ void do_POWER_rfsvc (void);
void do_op_602_mfrom (void);
#endif
/* PowerPC BookE specific helpers */
#if !defined(CONFIG_USER_ONLY)
void do_booke_tlbre0 (void);
void do_booke_tlbre1 (void);
void do_booke_tlbre2 (void);
void do_booke_tlbsx (void);
void do_booke_tlbsx_ (void);
void do_booke_tlbwe0 (void);
void do_booke_tlbwe1 (void);
void do_booke_tlbwe2 (void);
#endif
/* PowerPC 4xx specific helpers */
void do_405_check_ov (void);
void do_405_check_sat (void);

View File

@ -4618,9 +4618,10 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE)
RET_CHG_FLOW(ctx);
#endif
}
/* TLB management - PowerPC 405 implementation */
/* tlbre */
GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
@ -4648,7 +4649,7 @@ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
}
/* tlbsx - tlbsx. */
GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
@ -4667,7 +4668,7 @@ GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
}
/* tlbwe */
GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
@ -4694,6 +4695,92 @@ GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
#endif
}
/* TLB management - PowerPC BookE implementation */
/* tlbre */
GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
switch (rB(ctx->opcode)) {
case 0:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_booke_tlbre0();
gen_op_store_T0_gpr(rD(ctx->opcode));
break;
case 1:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_booke_tlbre1();
gen_op_store_T0_gpr(rD(ctx->opcode));
break;
case 2:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_booke_tlbre2();
gen_op_store_T0_gpr(rD(ctx->opcode));
break;
default:
RET_INVAL(ctx);
break;
}
#endif
}
/* tlbsx - tlbsx. */
GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
gen_addr_reg_index(ctx);
if (Rc(ctx->opcode))
gen_op_booke_tlbsx_();
else
gen_op_booke_tlbsx();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}
/* tlbwe */
GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
switch (rB(ctx->opcode)) {
case 0:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rS(ctx->opcode));
gen_op_booke_tlbwe0();
break;
case 1:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rS(ctx->opcode));
gen_op_booke_tlbwe1();
break;
case 2:
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rS(ctx->opcode));
gen_op_booke_tlbwe2();
break;
default:
RET_INVAL(ctx);
break;
}
#endif
}
/* wrtee */
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
{