mirror of https://gitee.com/openkylin/qemu.git
Merge PowerPC 405 MMU model.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2554 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
1d0a48fb92
commit
a8dea12f45
|
@ -549,8 +549,6 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
|||
if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
|
||||
/* Software TLB search */
|
||||
ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
|
||||
} else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
|
||||
/* XXX: TODO */
|
||||
} else {
|
||||
#if defined (DEBUG_MMU)
|
||||
if (loglevel > 0) {
|
||||
|
@ -632,6 +630,115 @@ static int get_segment (CPUState *env, mmu_ctx_t *ctx,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
|
||||
uint32_t address, int rw, int access_type)
|
||||
{
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_phys_addr_t raddr;
|
||||
target_ulong mask;
|
||||
int i, ret, zsel, zpr;
|
||||
|
||||
ret = -6;
|
||||
for (i = 0; i < env->nb_tlb; i++) {
|
||||
tlb = &env->tlb[i].tlbe;
|
||||
/* Check valid flag */
|
||||
if (!(tlb->prot & PAGE_VALID)) {
|
||||
if (loglevel)
|
||||
fprintf(logfile, "%s: TLB %d not valid\n", __func__, i);
|
||||
continue;
|
||||
}
|
||||
mask = ~(tlb->size - 1);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s: TLB %d address %08x PID %04x <=> "
|
||||
"%08x %08x %04x\n",
|
||||
__func__, i, address, env->spr[SPR_40x_PID],
|
||||
tlb->EPN, mask, 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) {
|
||||
fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
|
||||
__func__, i, zsel, zpr, rw, tlb->attr);
|
||||
}
|
||||
if (access_type == ACCESS_CODE) {
|
||||
/* Check execute enable bit */
|
||||
switch (zpr) {
|
||||
case 0x0:
|
||||
if (msr_pr) {
|
||||
ret = -3;
|
||||
ctx->prot = 0;
|
||||
break;
|
||||
}
|
||||
/* No break here */
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
/* Check from TLB entry */
|
||||
if (!(tlb->prot & PAGE_EXEC)) {
|
||||
ret = -3;
|
||||
} else {
|
||||
if (tlb->prot & PAGE_WRITE)
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
else
|
||||
ctx->prot = PAGE_READ;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
/* All accesses granted */
|
||||
ret = 0;
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (zpr) {
|
||||
case 0x0:
|
||||
if (msr_pr) {
|
||||
ret = -2;
|
||||
ctx->prot = 0;
|
||||
break;
|
||||
}
|
||||
/* No break here */
|
||||
case 0x1:
|
||||
case 0x2:
|
||||
/* Check from TLB entry */
|
||||
/* Check write protection bit */
|
||||
if (rw && !(tlb->prot & PAGE_WRITE)) {
|
||||
ret = -2;
|
||||
} else {
|
||||
ret = 2;
|
||||
if (tlb->prot & PAGE_WRITE)
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
else
|
||||
ctx->prot = PAGE_READ;
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
/* All accesses granted */
|
||||
ret = 2;
|
||||
ctx->prot = PAGE_READ | PAGE_WRITE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret >= 0) {
|
||||
ctx->raddr = raddr;
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "%s: access granted " ADDRX " => " REGX
|
||||
" %d\n", __func__, address, ctx->raddr, ctx->prot);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_physical (CPUState *env, mmu_ctx_t *ctx,
|
||||
target_ulong eaddr, int rw)
|
||||
{
|
||||
|
@ -682,13 +789,26 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
|
|||
/* No address translation */
|
||||
ret = check_physical(env, ctx, eaddr, rw);
|
||||
} else {
|
||||
/* Try to find a BAT */
|
||||
ret = -1;
|
||||
if (check_BATs)
|
||||
ret = get_bat(env, ctx, eaddr, rw, access_type);
|
||||
if (ret < 0) {
|
||||
/* We didn't match any BAT entry */
|
||||
ret = get_segment(env, ctx, eaddr, rw, access_type);
|
||||
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);
|
||||
if (ret < 0) {
|
||||
/* We didn't match any BAT entry */
|
||||
ret = get_segment(env, ctx, eaddr, rw, access_type);
|
||||
}
|
||||
break;
|
||||
case PPC_FLAGS_MMU_SOFT_4xx:
|
||||
ret = mmu4xx_get_physical_address(env, ctx, eaddr,
|
||||
rw, access_type);
|
||||
break;
|
||||
default:
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env, "MMU model not implemented\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
|
@ -753,7 +873,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
|||
error_code = 1 << 18;
|
||||
goto tlb_miss;
|
||||
} else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
|
||||
/* XXX: TODO */
|
||||
exception = EXCP_40x_ITLBMISS;
|
||||
error_code = 0;
|
||||
env->spr[SPR_40x_DEAR] = address;
|
||||
env->spr[SPR_40x_ESR] = 0x00000000;
|
||||
} else {
|
||||
error_code = 0x40000000;
|
||||
}
|
||||
|
@ -799,7 +922,13 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
|
|||
/* Do not alter DAR nor DSISR */
|
||||
goto out;
|
||||
} else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
|
||||
/* XXX: TODO */
|
||||
exception = EXCP_40x_DTLBMISS;
|
||||
error_code = 0;
|
||||
env->spr[SPR_40x_DEAR] = address;
|
||||
if (rw)
|
||||
env->spr[SPR_40x_ESR] = 0x00800000;
|
||||
else
|
||||
env->spr[SPR_40x_ESR] = 0x00000000;
|
||||
} else {
|
||||
error_code = 0x40000000;
|
||||
}
|
||||
|
@ -1518,9 +1647,7 @@ void do_interrupt (CPUState *env)
|
|||
switch (PPC_EXCP(env)) {
|
||||
case PPC_FLAGS_EXCP_40x:
|
||||
/* DTLBMISS on 4xx */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env,
|
||||
"40x DTLBMISS exception is not implemented yet !\n");
|
||||
msr &= ~0xFFFF0000;
|
||||
goto store_next;
|
||||
case PPC_FLAGS_EXCP_602:
|
||||
case PPC_FLAGS_EXCP_603:
|
||||
|
@ -1538,9 +1665,7 @@ void do_interrupt (CPUState *env)
|
|||
switch (PPC_EXCP(env)) {
|
||||
case PPC_FLAGS_EXCP_40x:
|
||||
/* ITLBMISS on 4xx */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(env,
|
||||
"40x ITLBMISS exception is not implemented yet !\n");
|
||||
msr &= ~0xFFFF0000;
|
||||
goto store_next;
|
||||
case PPC_FLAGS_EXCP_602:
|
||||
case PPC_FLAGS_EXCP_603:
|
||||
|
|
|
@ -2365,65 +2365,139 @@ void do_load_6xx_tlb (int is_code)
|
|||
way, is_code, CMP, RPN);
|
||||
}
|
||||
|
||||
static target_ulong booke_tlb_to_page_size (int size)
|
||||
{
|
||||
return 1024 << (2 * size);
|
||||
}
|
||||
|
||||
static int booke_page_size_to_tlb (target_ulong page_size)
|
||||
{
|
||||
int size;
|
||||
|
||||
switch (page_size) {
|
||||
case 0x00000400UL:
|
||||
size = 0x0;
|
||||
break;
|
||||
case 0x00001000UL:
|
||||
size = 0x1;
|
||||
break;
|
||||
case 0x00004000UL:
|
||||
size = 0x2;
|
||||
break;
|
||||
case 0x00010000UL:
|
||||
size = 0x3;
|
||||
break;
|
||||
case 0x00040000UL:
|
||||
size = 0x4;
|
||||
break;
|
||||
case 0x00100000UL:
|
||||
size = 0x5;
|
||||
break;
|
||||
case 0x00400000UL:
|
||||
size = 0x6;
|
||||
break;
|
||||
case 0x01000000UL:
|
||||
size = 0x7;
|
||||
break;
|
||||
case 0x04000000UL:
|
||||
size = 0x8;
|
||||
break;
|
||||
case 0x10000000UL:
|
||||
size = 0x9;
|
||||
break;
|
||||
case 0x40000000UL:
|
||||
size = 0xA;
|
||||
break;
|
||||
#if defined (TARGET_PPC64)
|
||||
case 0x000100000000ULL:
|
||||
size = 0xB;
|
||||
break;
|
||||
case 0x000400000000ULL:
|
||||
size = 0xC;
|
||||
break;
|
||||
case 0x001000000000ULL:
|
||||
size = 0xD;
|
||||
break;
|
||||
case 0x004000000000ULL:
|
||||
size = 0xE;
|
||||
break;
|
||||
case 0x010000000000ULL:
|
||||
size = 0xF;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
size = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Helpers for 4xx TLB management */
|
||||
void do_4xx_tlbia (void)
|
||||
{
|
||||
#if 0
|
||||
ppc_tlb_t *tlb;
|
||||
target_ulong page, end;
|
||||
ppcemb_tlb_t *tlb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
tlb = &env->tlb[i];
|
||||
tlb = &env->tlb[i].tlbe;
|
||||
if (tlb->prot & PAGE_VALID) {
|
||||
#if 0
|
||||
end = tlb->EPN + tlb->size;
|
||||
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
|
||||
tlb_flush_page(env, page);
|
||||
#endif
|
||||
tlb->prot &= ~PAGE_VALID;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
tlb_flush(env, 1);
|
||||
}
|
||||
|
||||
void do_4xx_tlbre_lo (void)
|
||||
{
|
||||
#if 0
|
||||
ppc_tlb_t *tlb;
|
||||
ppcemb_tlb_t *tlb;
|
||||
int size;
|
||||
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0];
|
||||
T0 = tlb->stor[0];
|
||||
env->spr[SPR_40x_PID] = tlb->pid;
|
||||
#endif
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
T0 = tlb->EPN;
|
||||
if (tlb->prot & PAGE_VALID)
|
||||
T0 |= 0x400;
|
||||
size = booke_page_size_to_tlb(tlb->size);
|
||||
if (size < 0 || size > 0x7)
|
||||
size = 1;
|
||||
T0 |= size << 7;
|
||||
env->spr[SPR_40x_PID] = tlb->PID;
|
||||
}
|
||||
|
||||
void do_4xx_tlbre_hi (void)
|
||||
{
|
||||
#if 0
|
||||
ppc_tlb_t *tlb;
|
||||
ppcemb_tlb_t *tlb;
|
||||
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0];
|
||||
T0 = tlb->stor[1];
|
||||
#endif
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
T0 = tlb->RPN;
|
||||
if (tlb->prot & PAGE_EXEC)
|
||||
T0 |= 0x200;
|
||||
if (tlb->prot & PAGE_WRITE)
|
||||
T0 |= 0x100;
|
||||
}
|
||||
|
||||
static int tlb_4xx_search (target_ulong virtual)
|
||||
{
|
||||
#if 0
|
||||
ppc_tlb_t *tlb;
|
||||
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];
|
||||
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])
|
||||
if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
|
||||
continue;
|
||||
/* Check TLB address vs virtual address */
|
||||
base = tlb->EPN;
|
||||
|
@ -2435,9 +2509,6 @@ static int tlb_4xx_search (target_ulong virtual)
|
|||
}
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_4xx_tlbsx (void)
|
||||
|
@ -2457,47 +2528,44 @@ void do_4xx_tlbsx_ (void)
|
|||
|
||||
void do_4xx_tlbwe_lo (void)
|
||||
{
|
||||
#if 0
|
||||
ppc_tlb_t *tlb;
|
||||
ppcemb_tlb_t *tlb;
|
||||
target_ulong page, end;
|
||||
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0];
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
/* Invalidate previous TLB (if it's valid) */
|
||||
if (tlb->prot & PAGE_VALID) {
|
||||
end = tlb->EPN + tlb->size;
|
||||
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
|
||||
tlb_flush_page(env, page);
|
||||
}
|
||||
tlb->size = 1024 << (2 * ((T1 >> 7) & 0x7));
|
||||
tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
|
||||
tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
|
||||
if (T1 & 0x400)
|
||||
tlb->prot |= PAGE_VALID;
|
||||
else
|
||||
tlb->prot &= ~PAGE_VALID;
|
||||
tlb->pid = env->spr[SPR_BOOKE_PID]; /* PID */
|
||||
tlb->PID = env->spr[SPR_BOOKE_PID]; /* PID */
|
||||
tlb->attr = T1 & 0xFF;
|
||||
/* Invalidate new TLB (if valid) */
|
||||
if (tlb->prot & PAGE_VALID) {
|
||||
end = tlb->EPN + tlb->size;
|
||||
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
|
||||
tlb_flush_page(env, page);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void do_4xx_tlbwe_hi (void)
|
||||
{
|
||||
#if 0
|
||||
ppc_tlb_t *tlb;
|
||||
ppcemb_tlb_t *tlb;
|
||||
|
||||
T0 &= 0x3F;
|
||||
tlb = &env->tlb[T0];
|
||||
tlb = &env->tlb[T0].tlbe;
|
||||
tlb->RPN = T1 & 0xFFFFFC00;
|
||||
tlb->prot = PAGE_READ;
|
||||
if (T1 & 0x200)
|
||||
tlb->prot |= PAGE_EXEC;
|
||||
if (T1 & 0x100)
|
||||
tlb->prot |= PAGE_WRITE;
|
||||
#endif
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
|
Loading…
Reference in New Issue