aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/ppc/spapr_hcall.c14
-rw-r--r--target-ppc/cpu.h2
-rw-r--r--target-ppc/excp_helper.c8
-rw-r--r--target-ppc/helper.h1
-rw-r--r--target-ppc/helper_regs.h13
-rw-r--r--target-ppc/mmu-hash64.c11
-rw-r--r--target-ppc/mmu_helper.c9
-rw-r--r--target-ppc/translate.c39
8 files changed, 82 insertions, 15 deletions
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index feb3629664..9a3f4ecc1e 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -186,6 +186,7 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
+ CPUPPCState *env = &cpu->env;
target_ulong flags = args[0];
target_ulong pte_index = args[1];
target_ulong avpn = args[2];
@@ -196,6 +197,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
switch (ret) {
case REMOVE_SUCCESS:
+ check_tlb_flush(env);
return H_SUCCESS;
case REMOVE_NOT_FOUND:
@@ -232,7 +234,9 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
+ CPUPPCState *env = &cpu->env;
int i;
+ target_ulong rc = H_SUCCESS;
for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
target_ulong *tsh = &args[i*2];
@@ -265,14 +269,18 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
break;
case REMOVE_PARM:
- return H_PARAMETER;
+ rc = H_PARAMETER;
+ goto exit;
case REMOVE_HW:
- return H_HARDWARE;
+ rc = H_HARDWARE;
+ goto exit;
}
}
+ exit:
+ check_tlb_flush(env);
- return H_SUCCESS;
+ return rc;
}
static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2c8c8c0c6a..98a24a50f3 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -958,6 +958,8 @@ struct CPUPPCState {
/* PowerPC 64 SLB area */
ppc_slb_t slb[MAX_SLB_ENTRIES];
int32_t slb_nr;
+ /* tcg TLB needs flush (deferred slb inval instruction typically) */
+ uint32_t tlb_need_flush;
#endif
/* segment registers */
hwaddr htab_base;
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index ba3caec699..a37009eb25 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -718,6 +718,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
/* Reset exception state */
cs->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0;
+
+ /* Any interrupt is context synchronizing, check if TCG TLB
+ * needs a delayed flush on ppc64
+ */
+ check_tlb_flush(env);
}
void ppc_cpu_do_interrupt(CPUState *cs)
@@ -943,6 +948,9 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
* as rfi is always the last insn of a TB
*/
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+
+ /* Context synchronizing: check if TCG TLB needs flush */
+ check_tlb_flush(env);
}
void helper_rfi(CPUPPCState *env)
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index e5a8f7b9b5..0526322f4d 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -16,6 +16,7 @@ DEF_HELPER_1(rfmci, void, env)
DEF_HELPER_1(rfid, void, env)
DEF_HELPER_1(hrfid, void, env)
#endif
+DEF_HELPER_1(check_tlb_flush, void, env)
#endif
DEF_HELPER_3(lmw, void, env, tl, i32)
diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h
index f7edd5bc59..57da931e3c 100644
--- a/target-ppc/helper_regs.h
+++ b/target-ppc/helper_regs.h
@@ -151,4 +151,17 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
return excp;
}
+#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
+static inline void check_tlb_flush(CPUPPCState *env)
+{
+ CPUState *cs = CPU(ppc_env_get_cpu(env));
+ if (env->tlb_need_flush) {
+ env->tlb_need_flush = 0;
+ tlb_flush(cs, 1);
+ }
+}
+#else
+static inline void check_tlb_flush(CPUPPCState *env) { }
+#endif
+
#endif /* !defined(__HELPER_REGS_H__) */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 17e24800cb..ea6e99acd1 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -99,10 +99,8 @@ void dump_slb(FILE *f, fprintf_function cpu_fprintf, PowerPCCPU *cpu)
void helper_slbia(CPUPPCState *env)
{
- PowerPCCPU *cpu = ppc_env_get_cpu(env);
- int n, do_invalidate;
+ int n;
- do_invalidate = 0;
/* XXX: Warning: slbia never invalidates the first segment */
for (n = 1; n < env->slb_nr; n++) {
ppc_slb_t *slb = &env->slb[n];
@@ -113,12 +111,9 @@ void helper_slbia(CPUPPCState *env)
* and we still don't have a tlb_flush_mask(env, n, mask)
* in QEMU, we just invalidate all TLBs
*/
- do_invalidate = 1;
+ env->tlb_need_flush = 1;
}
}
- if (do_invalidate) {
- tlb_flush(CPU(cpu), 1);
- }
}
void helper_slbie(CPUPPCState *env, target_ulong addr)
@@ -138,7 +133,7 @@ void helper_slbie(CPUPPCState *env, target_ulong addr)
* and we still don't have a tlb_flush_mask(env, n, mask)
* in QEMU, we just invalidate all TLBs
*/
- tlb_flush(CPU(cpu), 1);
+ env->tlb_need_flush = 1;
}
}
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 2e0e3ca92c..1499af72a0 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -27,6 +27,7 @@
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/log.h"
+#include "helper_regs.h"
//#define DEBUG_MMU
//#define DEBUG_BATS
@@ -1924,6 +1925,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
case POWERPC_MMU_2_06a:
case POWERPC_MMU_2_07:
case POWERPC_MMU_2_07a:
+ env->tlb_need_flush = 0;
#endif /* defined(TARGET_PPC64) */
tlb_flush(CPU(cpu), 1);
break;
@@ -1986,7 +1988,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
* and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
* we just invalidate all TLBs
*/
- tlb_flush(CPU(cpu), 1);
+ env->tlb_need_flush = 1;
break;
#endif /* defined(TARGET_PPC64) */
default:
@@ -2875,6 +2877,11 @@ void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
}
+void helper_check_tlb_flush(CPUPPCState *env)
+{
+ check_tlb_flush(env);
+}
+
/*****************************************************************************/
/* try to fill the TLB and return an exception if error. If retaddr is
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index b757634b11..dfd3010815 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -3275,9 +3275,32 @@ static void gen_eieio(DisasContext *ctx)
{
}
+#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
+static inline void gen_check_tlb_flush(DisasContext *ctx)
+{
+ TCGv_i32 t = tcg_temp_new_i32();
+ TCGLabel *l = gen_new_label();
+
+ tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, tlb_need_flush));
+ tcg_gen_brcondi_i32(TCG_COND_EQ, t, 0, l);
+ gen_helper_check_tlb_flush(cpu_env);
+ gen_set_label(l);
+ tcg_temp_free_i32(t);
+}
+#else
+static inline void gen_check_tlb_flush(DisasContext *ctx) { }
+#endif
+
/* isync */
static void gen_isync(DisasContext *ctx)
{
+ /*
+ * We need to check for a pending TLB flush. This can only happen in
+ * kernel mode however so check MSR_PR
+ */
+ if (!ctx->pr) {
+ gen_check_tlb_flush(ctx);
+ }
gen_stop_exception(ctx);
}
@@ -3434,6 +3457,15 @@ STCX(stqcx_, 16);
/* sync */
static void gen_sync(DisasContext *ctx)
{
+ uint32_t l = (ctx->opcode >> 21) & 3;
+
+ /*
+ * For l == 2, it's a ptesync, We need to check for a pending TLB flush.
+ * This can only happen in kernel mode however so check MSR_PR as well.
+ */
+ if (l == 2 && !ctx->pr) {
+ gen_check_tlb_flush(ctx);
+ }
}
/* wait */
@@ -4851,10 +4883,11 @@ static void gen_tlbsync(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- /* This has no effect: it should ensure that all previous
- * tlbie have completed
+ /* tlbsync is a nop for server, ptesync handles delayed tlb flush,
+ * embedded however needs to deal with tlbsync. We don't try to be
+ * fancy and swallow the overhead of checking for both.
*/
- gen_stop_exception(ctx);
+ gen_check_tlb_flush(ctx);
#endif
}