aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/helper_regs.h
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2016-05-03 18:03:24 +0200
committerDavid Gibson <david@gibson.dropbear.id.au>2016-05-30 13:20:04 +1000
commit9fb044911444fdd09f5f072ad0ca269d7f8b841d (patch)
treece608f84663764e368d651a5713933bb2c2127fd /target-ppc/helper_regs.h
parent5fd1111b20a8f1955e3156a80e0576007548e871 (diff)
ppc: Use split I/D mmu modes to avoid flushes on interrupts
We rework the way the MMU indices are calculated, providing separate indices for I and D side based on MSR:IR and MSR:DR respectively, and thus no longer need to flush the TLB on context changes. This also adds correct support for HV as a separate address space. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'target-ppc/helper_regs.h')
-rw-r--r--target-ppc/helper_regs.h54
1 files changed, 47 insertions, 7 deletions
diff --git a/target-ppc/helper_regs.h b/target-ppc/helper_regs.h
index 271fddf17f..f7edd5bc59 100644
--- a/target-ppc/helper_regs.h
+++ b/target-ppc/helper_regs.h
@@ -41,11 +41,50 @@ static inline void hreg_swap_gpr_tgpr(CPUPPCState *env)
static inline void hreg_compute_mem_idx(CPUPPCState *env)
{
- /* Precompute MMU index */
- if (msr_pr == 0 && msr_hv != 0) {
- env->mmu_idx = 2;
+ /* This is our encoding for server processors
+ *
+ * 0 = Guest User space virtual mode
+ * 1 = Guest Kernel space virtual mode
+ * 2 = Guest Kernel space real mode
+ * 3 = HV User space virtual mode
+ * 4 = HV Kernel space virtual mode
+ * 5 = HV Kernel space real mode
+ *
+ * The combination PR=1 IR&DR=0 is invalid, we will treat
+ * it as IR=DR=1
+ *
+ * For BookE, we need 8 MMU modes as follow:
+ *
+ * 0 = AS 0 HV User space
+ * 1 = AS 0 HV Kernel space
+ * 2 = AS 1 HV User space
+ * 3 = AS 1 HV Kernel space
+ * 4 = AS 0 Guest User space
+ * 5 = AS 0 Guest Kernel space
+ * 6 = AS 1 Guest User space
+ * 7 = AS 1 Guest Kernel space
+ */
+ if (env->mmu_model & POWERPC_MMU_BOOKE) {
+ env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1;
+ env->immu_idx += msr_is ? 2 : 0;
+ env->dmmu_idx += msr_ds ? 2 : 0;
+ env->immu_idx += msr_gs ? 4 : 0;
+ env->dmmu_idx += msr_gs ? 4 : 0;
} else {
- env->mmu_idx = 1 - msr_pr;
+ /* First calucalte a base value independent of HV */
+ if (msr_pr != 0) {
+ /* User space, ignore IR and DR */
+ env->immu_idx = env->dmmu_idx = 0;
+ } else {
+ /* Kernel, setup a base I/D value */
+ env->immu_idx = msr_ir ? 1 : 2;
+ env->dmmu_idx = msr_dr ? 1 : 2;
+ }
+ /* Then offset it for HV */
+ if (msr_hv) {
+ env->immu_idx += 3;
+ env->dmmu_idx += 3;
+ }
}
}
@@ -82,9 +121,10 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value,
}
if (((value >> MSR_IR) & 1) != msr_ir ||
((value >> MSR_DR) & 1) != msr_dr) {
- /* Flush all tlb when changing translation mode */
- tlb_flush(cs, 1);
- excp = POWERPC_EXCP_NONE;
+ cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+ }
+ if ((env->mmu_model & POWERPC_MMU_BOOKE) &&
+ ((value >> MSR_GS) & 1) != msr_gs) {
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
if (unlikely((env->flags & POWERPC_FLAG_TGPR) &&