ppc: Minor 40x MMU fixes

* Fix swapped reading of tlblo/hi.
* Fix tlb exec permissions

Signed-off-by: John Clark <clarkjc@runbox.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
This commit is contained in:
John Clark 2010-10-05 18:38:55 +02:00 committed by Edgar E. Iglesias
parent 358664cc6d
commit 999fa40e43
2 changed files with 58 additions and 36 deletions

View File

@ -1172,9 +1172,7 @@ static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
case 0x1:
check_perms:
/* Check from TLB entry */
/* XXX: there is a problem here or in the TLB fill code... */
ctx->prot = tlb->prot;
ctx->prot |= PAGE_EXEC;
ret = check_prot(ctx->prot, rw, access_type);
if (ret == -2)
env->spr[SPR_40x_ESR] = 0;

View File

@ -3929,37 +3929,56 @@ static inline int booke_page_size_to_tlb(target_ulong page_size)
}
/* Helpers for 4xx TLB management */
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
int size;
#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
entry &= 0x3F;
tlb = &env->tlb[entry].tlbe;
ret = tlb->EPN;
if (tlb->prot & PAGE_VALID)
ret |= 0x400;
size = booke_page_size_to_tlb(tlb->size);
if (size < 0 || size > 0x7)
size = 1;
ret |= size << 7;
env->spr[SPR_40x_PID] = tlb->PID;
return ret;
}
#define PPC4XX_TLBHI_V 0x00000040
#define PPC4XX_TLBHI_E 0x00000020
#define PPC4XX_TLBHI_SIZE_MIN 0
#define PPC4XX_TLBHI_SIZE_MAX 7
#define PPC4XX_TLBHI_SIZE_DEFAULT 1
#define PPC4XX_TLBHI_SIZE_SHIFT 7
#define PPC4XX_TLBHI_SIZE_MASK 0x00000007
#define PPC4XX_TLBLO_EX 0x00000200
#define PPC4XX_TLBLO_WR 0x00000100
#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
target_ulong helper_4xx_tlbre_hi (target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
int size;
entry &= 0x3F;
entry &= PPC4XX_TLB_ENTRY_MASK;
tlb = &env->tlb[entry].tlbe;
ret = tlb->EPN;
if (tlb->prot & PAGE_VALID) {
ret |= PPC4XX_TLBHI_V;
}
size = booke_page_size_to_tlb(tlb->size);
if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
size = PPC4XX_TLBHI_SIZE_DEFAULT;
}
ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
env->spr[SPR_40x_PID] = tlb->PID;
return ret;
}
target_ulong helper_4xx_tlbre_lo (target_ulong entry)
{
ppcemb_tlb_t *tlb;
target_ulong ret;
entry &= PPC4XX_TLB_ENTRY_MASK;
tlb = &env->tlb[entry].tlbe;
ret = tlb->RPN;
if (tlb->prot & PAGE_EXEC)
ret |= 0x200;
if (tlb->prot & PAGE_WRITE)
ret |= 0x100;
if (tlb->prot & PAGE_EXEC) {
ret |= PPC4XX_TLBLO_EX;
}
if (tlb->prot & PAGE_WRITE) {
ret |= PPC4XX_TLBLO_WR;
}
return ret;
}
@ -3970,30 +3989,32 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
val);
entry &= 0x3F;
entry &= PPC4XX_TLB_ENTRY_MASK;
tlb = &env->tlb[entry].tlbe;
/* Invalidate previous TLB (if it's valid) */
if (tlb->prot & PAGE_VALID) {
end = tlb->EPN + tlb->size;
LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
tlb_flush_page(env, page);
}
tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
}
tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
& PPC4XX_TLBHI_SIZE_MASK);
/* 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 ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
"are not supported (%d)\n",
tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
}
tlb->EPN = val & ~(tlb->size - 1);
if (val & 0x40) {
if (val & PPC4XX_TLBHI_V) {
tlb->prot |= PAGE_VALID;
if (val & 0x20) {
if (val & PPC4XX_TLBHI_E) {
/* XXX: TO BE FIXED */
cpu_abort(env,
"Little-endian TLB entries are not supported by now\n");
@ -4014,10 +4035,11 @@ void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
end = tlb->EPN + tlb->size;
LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
tlb_flush_page(env, page);
}
}
}
void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
{
@ -4025,15 +4047,17 @@ void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
val);
entry &= 0x3F;
entry &= PPC4XX_TLB_ENTRY_MASK;
tlb = &env->tlb[entry].tlbe;
tlb->attr = val & 0xFF;
tlb->RPN = val & 0xFFFFFC00;
tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
tlb->prot = PAGE_READ;
if (val & 0x200)
if (val & PPC4XX_TLBLO_EX) {
tlb->prot |= PAGE_EXEC;
if (val & 0x100)
}
if (val & PPC4XX_TLBLO_WR) {
tlb->prot |= PAGE_WRITE;
}
LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
" size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
(int)entry, tlb->RPN, tlb->EPN, tlb->size,