summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-ppc/cpu.h5
-rw-r--r--target-ppc/exec.h6
-rw-r--r--target-ppc/helper.c118
-rw-r--r--target-ppc/op.c35
-rw-r--r--target-ppc/op_helper.c143
-rw-r--r--target-ppc/translate.c10
6 files changed, 119 insertions, 198 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 5d0a86be2c..c4ae414413 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -656,6 +656,11 @@ 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);
+void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
+#if defined(TARGET_PPC64)
+void ppc_slb_invalidate_all (CPUPPCState *env);
+void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0);
+#endif
int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid);
#endif
#endif
diff --git a/target-ppc/exec.h b/target-ppc/exec.h
index 10a51e93cb..8a54258271 100644
--- a/target-ppc/exec.h
+++ b/target-ppc/exec.h
@@ -100,14 +100,8 @@ void do_raise_exception (uint32_t exception);
int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr,
int rw, int access_type, int check_BATs);
-void ppc6xx_tlb_invalidate_all (CPUState *env);
-void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
- int is_code);
void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
target_ulong pte0, target_ulong pte1);
-void ppc4xx_tlb_invalidate_all (CPUState *env);
-void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
- uint32_t pid);
static inline void env_to_regs (void)
{
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 3e6fb48cd6..66dc7b22a8 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -237,7 +237,7 @@ static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
return nr;
}
-void ppc6xx_tlb_invalidate_all (CPUState *env)
+static void ppc6xx_tlb_invalidate_all (CPUState *env)
{
ppc6xx_tlb_t *tlb;
int nr, max;
@@ -253,14 +253,9 @@ void ppc6xx_tlb_invalidate_all (CPUState *env)
max *= 2;
for (nr = 0; nr < max; nr++) {
tlb = &env->tlb[nr].tlb6;
-#if !defined(FLUSH_ALL_TLBS)
- tlb_flush_page(env, tlb->EPN);
-#endif
pte_invalidate(&tlb->pte0);
}
-#if defined(FLUSH_ALL_TLBS)
tlb_flush(env, 1);
-#endif
}
static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
@@ -292,8 +287,8 @@ static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
#endif
}
-void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
- int is_code)
+static void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+ int is_code)
{
__ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
}
@@ -834,11 +829,13 @@ static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb,
return -1;
}
mask = ~(tlb->size - 1);
+#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> "
ADDRX " " ADDRX " %d\n",
__func__, i, address, pid, tlb->EPN, mask, (int)tlb->PID);
}
+#endif
/* Check PID */
if (tlb->PID != 0 && tlb->PID != pid)
return -1;
@@ -876,44 +873,41 @@ int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
return ret;
}
-void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
- uint32_t pid)
+/* Helpers specific to PowerPC 40x implementations */
+static void ppc4xx_tlb_invalidate_all (CPUState *env)
{
ppcemb_tlb_t *tlb;
- target_phys_addr_t raddr;
- target_ulong page, end;
int i;
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb[i].tlbe;
- if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
- end = tlb->EPN + tlb->size;
- for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
- tlb_flush_page(env, page);
- tlb->prot &= ~PAGE_VALID;
- break;
- }
+ tlb->prot &= ~PAGE_VALID;
}
+ tlb_flush(env, 1);
}
-/* Helpers specific to PowerPC 40x implementations */
-void ppc4xx_tlb_invalidate_all (CPUState *env)
+static void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+ uint32_t pid)
{
+#if !defined(FLUSH_ALL_TLBS)
ppcemb_tlb_t *tlb;
+ target_phys_addr_t raddr;
+ target_ulong page, end;
int i;
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb[i].tlbe;
- if (tlb->prot & PAGE_VALID) {
-#if 0 // XXX: TLB have variable sizes then we flush all Qemu TLB.
+ if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 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;
+ break;
}
}
- tlb_flush(env, 1);
+#else
+ ppc4xx_tlb_invalidate_all(env);
+#endif
}
int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
@@ -932,10 +926,12 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
continue;
zsel = (tlb->attr >> 4) & 0xF;
zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
+#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
__func__, i, zsel, zpr, rw, tlb->attr);
}
+#endif
if (access_type == ACCESS_CODE) {
/* Check execute enable bit */
switch (zpr) {
@@ -1009,19 +1005,23 @@ int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
}
if (ret >= 0) {
ctx->raddr = raddr;
+#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s: access granted " ADDRX " => " REGX
" %d %d\n", __func__, address, ctx->raddr, ctx->prot,
ret);
}
+#endif
return 0;
}
}
+#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
fprintf(logfile, "%s: access refused " ADDRX " => " REGX
" %d %d\n", __func__, address, raddr, ctx->prot,
ret);
}
+#endif
return ret;
}
@@ -1569,15 +1569,77 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
/* TLB management */
void ppc_tlb_invalidate_all (CPUPPCState *env)
{
- if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) {
+ switch (env->mmu_model) {
+ case POWERPC_MMU_SOFT_6xx:
ppc6xx_tlb_invalidate_all(env);
- } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) {
+ break;
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_SOFT_4xx_Z:
ppc4xx_tlb_invalidate_all(env);
- } else {
+ break;
+ default:
tlb_flush(env, 1);
+ break;
+ }
+}
+
+void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
+{
+#if !defined(FLUSH_ALL_TLBS)
+ addr &= TARGET_PAGE_MASK;
+ switch (env->mmu_model) {
+ case POWERPC_MMU_SOFT_6xx:
+ ppc6xx_tlb_invalidate_virt(env, addr, 0);
+ if (env->id_tlbs == 1)
+ ppc6xx_tlb_invalidate_virt(env, addr, 1);
+ break;
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_SOFT_4xx_Z:
+ ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
+ break;
+ default:
+ /* tlbie invalidate TLBs for all segments */
+ addr &= ~((target_ulong)-1 << 28);
+ /* XXX: this case should be optimized,
+ * giving a mask to tlb_flush_page
+ */
+ tlb_flush_page(env, addr | (0x0 << 28));
+ tlb_flush_page(env, addr | (0x1 << 28));
+ tlb_flush_page(env, addr | (0x2 << 28));
+ tlb_flush_page(env, addr | (0x3 << 28));
+ tlb_flush_page(env, addr | (0x4 << 28));
+ tlb_flush_page(env, addr | (0x5 << 28));
+ tlb_flush_page(env, addr | (0x6 << 28));
+ tlb_flush_page(env, addr | (0x7 << 28));
+ tlb_flush_page(env, addr | (0x8 << 28));
+ tlb_flush_page(env, addr | (0x9 << 28));
+ tlb_flush_page(env, addr | (0xA << 28));
+ tlb_flush_page(env, addr | (0xB << 28));
+ tlb_flush_page(env, addr | (0xC << 28));
+ tlb_flush_page(env, addr | (0xD << 28));
+ tlb_flush_page(env, addr | (0xE << 28));
+ tlb_flush_page(env, addr | (0xF << 28));
}
+#else
+ ppc_tlb_invalidate_all(env);
+#endif
}
+#if defined(TARGET_PPC64)
+void ppc_slb_invalidate_all (CPUPPCState *env)
+{
+ /* XXX: TODO */
+ tlb_flush(env, 1);
+}
+
+void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
+{
+ /* XXX: TODO */
+ tlb_flush(env, 1);
+}
+#endif
+
+
/*****************************************************************************/
/* Special registers manipulation */
#if defined(TARGET_PPC64)
diff --git a/target-ppc/op.c b/target-ppc/op.c
index 8f0f11a66f..6ad68eabaa 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -1985,21 +1985,21 @@ void OPPROTO op_td (void)
/* tlbia */
void OPPROTO op_tlbia (void)
{
- do_tlbia();
+ ppc_tlb_invalidate_all(env);
RETURN();
}
/* tlbie */
void OPPROTO op_tlbie (void)
{
- do_tlbie();
+ ppc_tlb_invalidate_one(env, (uint32_t)T0);
RETURN();
}
#if defined(TARGET_PPC64)
void OPPROTO op_tlbie_64 (void)
{
- do_tlbie_64();
+ ppc_tlb_invalidate_one(env, T0);
RETURN();
}
#endif
@@ -2007,13 +2007,19 @@ void OPPROTO op_tlbie_64 (void)
#if defined(TARGET_PPC64)
void OPPROTO op_slbia (void)
{
- do_slbia();
+ ppc_slb_invalidate_all(env);
RETURN();
}
void OPPROTO op_slbie (void)
{
- do_slbie();
+ ppc_slb_invalidate_one(env, (uint32_t)T0);
+ RETURN();
+}
+
+void OPPROTO op_slbie_64 (void)
+{
+ ppc_slb_invalidate_one(env, T0);
RETURN();
}
#endif
@@ -2487,13 +2493,18 @@ void OPPROTO op_440_tlbre (void)
void OPPROTO op_440_tlbsx (void)
{
- do_440_tlbsx();
+ T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF);
RETURN();
}
-void OPPROTO op_440_tlbsx_ (void)
+void OPPROTO op_4xx_tlbsx_check (void)
{
- do_440_tlbsx_();
+ int tmp;
+
+ tmp = xer_so;
+ if (T0 != -1)
+ tmp |= 0x02;
+ env->crf[0] = tmp;
RETURN();
}
@@ -2517,13 +2528,7 @@ void OPPROTO op_4xx_tlbre_hi (void)
void OPPROTO op_4xx_tlbsx (void)
{
- do_4xx_tlbsx();
- RETURN();
-}
-
-void OPPROTO op_4xx_tlbsx_ (void)
-{
- do_4xx_tlbsx_();
+ T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]);
RETURN();
}
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 5223b1543f..a7c81776fd 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -36,7 +36,6 @@
//#define DEBUG_OP
//#define DEBUG_EXCEPTIONS
//#define DEBUG_SOFTWARE_TLB
-//#define FLUSH_ALL_TLBS
/*****************************************************************************/
/* Exceptions processing helpers */
@@ -2336,118 +2335,6 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
env = saved_env;
}
-/* TLB invalidation helpers */
-void do_tlbia (void)
-{
- ppc_tlb_invalidate_all(env);
-}
-
-void do_tlbie (void)
-{
- T0 = (uint32_t)T0;
-#if !defined(FLUSH_ALL_TLBS)
- /* XXX: Remove thoses tests */
- if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) {
- ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0);
- if (env->id_tlbs == 1)
- ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1);
- } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) {
- ppc4xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK,
- env->spr[SPR_40x_PID]);
- } else {
- /* tlbie invalidate TLBs for all segments */
- T0 &= TARGET_PAGE_MASK;
- T0 &= ~((target_ulong)-1 << 28);
- /* XXX: this case should be optimized,
- * giving a mask to tlb_flush_page
- */
- tlb_flush_page(env, T0 | (0x0 << 28));
- tlb_flush_page(env, T0 | (0x1 << 28));
- tlb_flush_page(env, T0 | (0x2 << 28));
- tlb_flush_page(env, T0 | (0x3 << 28));
- tlb_flush_page(env, T0 | (0x4 << 28));
- tlb_flush_page(env, T0 | (0x5 << 28));
- tlb_flush_page(env, T0 | (0x6 << 28));
- tlb_flush_page(env, T0 | (0x7 << 28));
- tlb_flush_page(env, T0 | (0x8 << 28));
- tlb_flush_page(env, T0 | (0x9 << 28));
- tlb_flush_page(env, T0 | (0xA << 28));
- tlb_flush_page(env, T0 | (0xB << 28));
- tlb_flush_page(env, T0 | (0xC << 28));
- tlb_flush_page(env, T0 | (0xD << 28));
- tlb_flush_page(env, T0 | (0xE << 28));
- tlb_flush_page(env, T0 | (0xF << 28));
- }
-#else
- do_tlbia();
-#endif
-}
-
-#if defined(TARGET_PPC64)
-void do_tlbie_64 (void)
-{
- T0 = (uint64_t)T0;
-#if !defined(FLUSH_ALL_TLBS)
- if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx)) {
- ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0);
- if (env->id_tlbs == 1)
- ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1);
- } else if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_4xx)) {
- /* XXX: TODO */
-#if 0
- ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK,
- env->spr[SPR_BOOKE_PID]);
-#endif
- } else {
- /* tlbie invalidate TLBs for all segments
- * As we have 2^36 segments, invalidate all qemu TLBs
- */
-#if 0
- T0 &= TARGET_PAGE_MASK;
- T0 &= ~((target_ulong)-1 << 28);
- /* XXX: this case should be optimized,
- * giving a mask to tlb_flush_page
- */
- tlb_flush_page(env, T0 | (0x0 << 28));
- tlb_flush_page(env, T0 | (0x1 << 28));
- tlb_flush_page(env, T0 | (0x2 << 28));
- tlb_flush_page(env, T0 | (0x3 << 28));
- tlb_flush_page(env, T0 | (0x4 << 28));
- tlb_flush_page(env, T0 | (0x5 << 28));
- tlb_flush_page(env, T0 | (0x6 << 28));
- tlb_flush_page(env, T0 | (0x7 << 28));
- tlb_flush_page(env, T0 | (0x8 << 28));
- tlb_flush_page(env, T0 | (0x9 << 28));
- tlb_flush_page(env, T0 | (0xA << 28));
- tlb_flush_page(env, T0 | (0xB << 28));
- tlb_flush_page(env, T0 | (0xC << 28));
- tlb_flush_page(env, T0 | (0xD << 28));
- tlb_flush_page(env, T0 | (0xE << 28));
- tlb_flush_page(env, T0 | (0xF << 28));
-#else
- tlb_flush(env, 1);
-#endif
- }
-#else
- do_tlbia();
-#endif
-}
-#endif
-
-#if defined(TARGET_PPC64)
-void do_slbia (void)
-{
- /* XXX: TODO */
- tlb_flush(env, 1);
-}
-
-void do_slbie (void)
-{
- /* XXX: TODO */
- tlb_flush(env, 1);
-}
-#endif
-
/* Software driven TLBs management */
/* PowerPC 602/603 software TLB load instructions helpers */
void do_load_6xx_tlb (int is_code)
@@ -2575,21 +2462,6 @@ void do_4xx_tlbre_hi (void)
T0 |= 0x100;
}
-void do_4xx_tlbsx (void)
-{
- T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]);
-}
-
-void do_4xx_tlbsx_ (void)
-{
- int tmp = xer_so;
-
- T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]);
- if (T0 != -1)
- tmp |= 0x02;
- env->crf[0] = tmp;
-}
-
void do_4xx_tlbwe_hi (void)
{
ppcemb_tlb_t *tlb;
@@ -2757,21 +2629,6 @@ void do_440_tlbwe (int word)
}
}
-void do_440_tlbsx (void)
-{
- T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF);
-}
-
-void do_440_tlbsx_ (void)
-{
- int tmp = xer_so;
-
- T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF);
- if (T0 != -1)
- tmp |= 0x02;
- env->crf[0] = tmp;
-}
-
void do_440_tlbre (int word)
{
ppcemb_tlb_t *tlb;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 6faf0b6717..d76a92a65d 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -4991,10 +4991,9 @@ GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
return;
}
gen_addr_reg_index(ctx);
+ gen_op_4xx_tlbsx();
if (Rc(ctx->opcode))
- gen_op_4xx_tlbsx_();
- else
- gen_op_4xx_tlbsx();
+ gen_op_4xx_tlbsx_check();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}
@@ -5064,10 +5063,9 @@ GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
return;
}
gen_addr_reg_index(ctx);
+ gen_op_440_tlbsx();
if (Rc(ctx->opcode))
- gen_op_440_tlbsx_();
- else
- gen_op_440_tlbsx();
+ gen_op_4xx_tlbsx_check();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}