* [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs
@ 2013-03-12 10:31 David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 01/48] target-ppc: Remove vestigial PowerPC 620 support David Gibson
` (48 more replies)
0 siblings, 49 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: qemu-ppc, afaerber, qemu-devel
This large patch series makes a serious overhaul of the MMU
implementation for target-ppc. Previously all the quite dissimilar
PowerPC MMU variants attempted to use a more-or-less common code path,
with dependencies on env->mmu_model scattered throughout. The
resulting confused code was not worth the handful of saved lines.
This series starts the transition to a new model, where the different
MMU types are represented by appropriate QOM methods on the CPU
object. For now, only the main translation path - previously
cpu_ppc_handle_mmu_fault() is made such a method, but more could be
added in future. For now, 32-bit and 64-bit hash page table based
MMUs (the "classic" PPC MMUs) are given their own handle_mmu_fault
functions - the remaining MMU types retain the old code for now, I'm
hoping those more familiar with them will perform a similar conversion
in future though.
There's plenty more cleanup that could be done. As well as the
obvious work to convert other MMU types, there's room for improvement
in: handling of SDR1 and other SPRs, handling of segment registers,
switching MMU code to user PowerPCCPU instead of CPUPPCState, remove
the duplicate mmu_model in PowerpCCPUClass and CPUPPCState, removing
remaining uses of mmu_model. But if I tackled all those now, I might
never get this series ready.
Please apply.
^ permalink raw reply [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 01/48] target-ppc: Remove vestigial PowerPC 620 support
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 02/48] target-ppc: Trivial cleanups in mmu_helper.c David Gibson
` (47 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
The PowerPC 620 was the very first 64-bit PowerPC implementation, but
hardly anyone ever actually used the chips. qemu notionally supports the
620, but since we don't actually have code to implement the segment table,
the support is broken (quite likely in other ways too).
This patch, therefore, removes all remaining pieces of 620 support, to
stop it cluttering up the platforms we actually care about. This includes
removing support for the ASR register, used only on segment table based
machines.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
v2: Don't remove the POWERPC_DEF()s from the table, just move them under
#ifdef(TODO) to document the CPU's existence and aliases..
---
monitor.c | 4 -
target-ppc/cpu-models.c | 2 +-
target-ppc/cpu.h | 30 -----
target-ppc/helper.h | 1 -
target-ppc/machine.c | 4 +-
target-ppc/misc_helper.c | 6 -
target-ppc/mmu_helper.c | 44 +-------
target-ppc/translate.c | 1 -
target-ppc/translate_init.c | 255 -------------------------------------------
9 files changed, 8 insertions(+), 339 deletions(-)
diff --git a/monitor.c b/monitor.c
index c48530b..8edf25a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2936,10 +2936,6 @@ static const MonitorDef monitor_defs[] = {
{ "xer", 0, &monitor_get_xer, },
{ "tbu", 0, &monitor_get_tbu, },
{ "tbl", 0, &monitor_get_tbl, },
-#if defined(TARGET_PPC64)
- /* Address space register */
- { "asr", offsetof(CPUPPCState, asr) },
-#endif
/* Segment registers */
{ "sdr1", offsetof(CPUPPCState, spr[SPR_SDR1]) },
{ "sr0", offsetof(CPUPPCState, sr[0]) },
diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
index 20ca84e..17f56b7 100644
--- a/target-ppc/cpu-models.c
+++ b/target-ppc/cpu-models.c
@@ -1101,9 +1101,9 @@
"PowerPC 7457A v1.2 (G4)")
/* 64 bits PowerPC */
#if defined (TARGET_PPC64)
+#if defined(TODO)
POWERPC_DEF("620", CPU_POWERPC_620, 620,
"PowerPC 620")
-#if defined(TODO)
POWERPC_DEF("630", CPU_POWERPC_630, 630,
"PowerPC 630 (POWER3)")
#endif
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 417abb0..68e6967 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -115,8 +115,6 @@ enum powerpc_mmu_t {
#define POWERPC_MMU_1TSEG 0x00020000
/* 64 bits PowerPC MMU */
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
- /* 620 variant (no segment exceptions) */
- POWERPC_MMU_620 = POWERPC_MMU_64 | 0x00000002,
/* Architecture 2.06 variant */
POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
/* Architecture 2.06 "degraded" (no 1T segments) */
@@ -965,8 +963,6 @@ struct CPUPPCState {
/* MMU context - only relevant for full system emulation */
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
- /* Address space register */
- target_ulong asr;
/* PowerPC 64 SLB area */
ppc_slb_t slb[64];
int slb_nr;
@@ -1139,7 +1135,6 @@ void ppc_hw_interrupt (CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
#if defined(TARGET_PPC64)
-void ppc_store_asr (CPUPPCState *env, target_ulong value);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
#endif /* defined(TARGET_PPC64) */
#endif /* !defined(CONFIG_USER_ONLY) */
@@ -1490,11 +1485,9 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_RCPU_MI_RBA2 (0x302)
#define SPR_MPC_MI_AP (0x302)
#define SPR_PERF3 (0x303)
-#define SPR_620_PMC1R (0x303)
#define SPR_RCPU_MI_RBA3 (0x303)
#define SPR_MPC_MI_EPN (0x303)
#define SPR_PERF4 (0x304)
-#define SPR_620_PMC2R (0x304)
#define SPR_PERF5 (0x305)
#define SPR_MPC_MI_TWC (0x305)
#define SPR_PERF6 (0x306)
@@ -1510,7 +1503,6 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_RCPU_L2U_RBA2 (0x30A)
#define SPR_MPC_MD_AP (0x30A)
#define SPR_PERFB (0x30B)
-#define SPR_620_MMCR0R (0x30B)
#define SPR_RCPU_L2U_RBA3 (0x30B)
#define SPR_MPC_MD_EPN (0x30B)
#define SPR_PERFC (0x30C)
@@ -1525,9 +1517,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_UPERF1 (0x311)
#define SPR_UPERF2 (0x312)
#define SPR_UPERF3 (0x313)
-#define SPR_620_PMC1W (0x313)
#define SPR_UPERF4 (0x314)
-#define SPR_620_PMC2W (0x314)
#define SPR_UPERF5 (0x315)
#define SPR_UPERF6 (0x316)
#define SPR_UPERF7 (0x317)
@@ -1535,7 +1525,6 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_UPERF9 (0x319)
#define SPR_UPERFA (0x31A)
#define SPR_UPERFB (0x31B)
-#define SPR_620_MMCR0W (0x31B)
#define SPR_UPERFC (0x31C)
#define SPR_UPERFD (0x31D)
#define SPR_UPERFE (0x31E)
@@ -1607,49 +1596,33 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_USDA (0x3AF)
#define SPR_40x_ZPR (0x3B0)
#define SPR_BOOKE_MAS7 (0x3B0)
-#define SPR_620_PMR0 (0x3B0)
#define SPR_MMCR2 (0x3B0)
#define SPR_PMC5 (0x3B1)
#define SPR_40x_PID (0x3B1)
-#define SPR_620_PMR1 (0x3B1)
#define SPR_PMC6 (0x3B2)
#define SPR_440_MMUCR (0x3B2)
-#define SPR_620_PMR2 (0x3B2)
#define SPR_4xx_CCR0 (0x3B3)
#define SPR_BOOKE_EPLC (0x3B3)
-#define SPR_620_PMR3 (0x3B3)
#define SPR_405_IAC3 (0x3B4)
#define SPR_BOOKE_EPSC (0x3B4)
-#define SPR_620_PMR4 (0x3B4)
#define SPR_405_IAC4 (0x3B5)
-#define SPR_620_PMR5 (0x3B5)
#define SPR_405_DVC1 (0x3B6)
-#define SPR_620_PMR6 (0x3B6)
#define SPR_405_DVC2 (0x3B7)
-#define SPR_620_PMR7 (0x3B7)
#define SPR_BAMR (0x3B7)
#define SPR_MMCR0 (0x3B8)
-#define SPR_620_PMR8 (0x3B8)
#define SPR_PMC1 (0x3B9)
#define SPR_40x_SGR (0x3B9)
-#define SPR_620_PMR9 (0x3B9)
#define SPR_PMC2 (0x3BA)
#define SPR_40x_DCWR (0x3BA)
-#define SPR_620_PMRA (0x3BA)
#define SPR_SIAR (0x3BB)
#define SPR_405_SLER (0x3BB)
-#define SPR_620_PMRB (0x3BB)
#define SPR_MMCR1 (0x3BC)
#define SPR_405_SU0R (0x3BC)
-#define SPR_620_PMRC (0x3BC)
#define SPR_401_SKR (0x3BC)
#define SPR_PMC3 (0x3BD)
#define SPR_405_DBCR1 (0x3BD)
-#define SPR_620_PMRD (0x3BD)
#define SPR_PMC4 (0x3BE)
-#define SPR_620_PMRE (0x3BE)
#define SPR_SDA (0x3BF)
-#define SPR_620_PMRF (0x3BF)
#define SPR_403_VTBL (0x3CC)
#define SPR_403_VTBU (0x3CD)
#define SPR_DMISS (0x3D0)
@@ -1717,15 +1690,12 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_LDSTCR (0x3F8)
#define SPR_L2PMCR (0x3F8)
#define SPR_750FX_HID2 (0x3F8)
-#define SPR_620_BUSCSR (0x3F8)
#define SPR_Exxx_L1FINV0 (0x3F8)
#define SPR_L2CR (0x3F9)
-#define SPR_620_L2CR (0x3F9)
#define SPR_L3CR (0x3FA)
#define SPR_750_TDCH (0x3FA)
#define SPR_IABR2 (0x3FA)
#define SPR_40x_DCCR (0x3FA)
-#define SPR_620_L2SR (0x3FA)
#define SPR_ICTC (0x3FB)
#define SPR_40x_ICCR (0x3FB)
#define SPR_THRM1 (0x3FC)
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index fcf372a..d33ee66 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -382,7 +382,6 @@ DEF_HELPER_1(load_601_rtcl, tl, env)
DEF_HELPER_1(load_601_rtcu, tl, env)
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
-DEF_HELPER_2(store_asr, void, env, tl)
DEF_HELPER_1(load_purr, tl, env)
#endif
DEF_HELPER_2(store_sdr1, void, env, tl)
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 708a840..235b0d5 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -37,7 +37,7 @@ void cpu_save(QEMUFile *f, void *opaque)
qemu_put_be32s(f, &fpscr);
qemu_put_sbe32s(f, &env->access_type);
#if defined(TARGET_PPC64)
- qemu_put_betls(f, &env->asr);
+ qemu_put_betls(f, &env->spr[SPR_ASR]);
qemu_put_sbe32s(f, &env->slb_nr);
#endif
qemu_put_betls(f, &env->spr[SPR_SDR1]);
@@ -125,7 +125,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
env->fpscr = fpscr;
qemu_get_sbe32s(f, &env->access_type);
#if defined(TARGET_PPC64)
- qemu_get_betls(f, &env->asr);
+ qemu_get_betls(f, &env->spr[SPR_ASR]);
qemu_get_sbe32s(f, &env->slb_nr);
#endif
qemu_get_betls(f, &sdr1);
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index 26edcca..616aab6 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -35,12 +35,6 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
env->spr[sprn]);
}
#if !defined(CONFIG_USER_ONLY)
-#if defined(TARGET_PPC64)
-void helper_store_asr(CPUPPCState *env, target_ulong val)
-{
- ppc_store_asr(env, val);
-}
-#endif
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
{
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 1cc1c16..2f01b31 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1659,7 +1659,6 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
ctx->prot |= PAGE_WRITE;
break;
#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
@@ -1741,7 +1740,6 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
ret = get_bat(env, ctx, eaddr, rw, access_type);
}
#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
@@ -1883,7 +1881,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
@@ -1935,14 +1932,8 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
#if defined(TARGET_PPC64)
case -5:
/* No match in segment table */
- if (env->mmu_model == POWERPC_MMU_620) {
- env->exception_index = POWERPC_EXCP_ISI;
- /* XXX: this might be incorrect */
- env->error_code = 0x40000000;
- } else {
- env->exception_index = POWERPC_EXCP_ISEG;
- env->error_code = 0;
- }
+ env->exception_index = POWERPC_EXCP_ISEG;
+ env->error_code = 0;
break;
#endif
}
@@ -1995,7 +1986,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
@@ -2097,21 +2087,9 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
#if defined(TARGET_PPC64)
case -5:
/* No match in segment table */
- if (env->mmu_model == POWERPC_MMU_620) {
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- /* XXX: this might be incorrect */
- if (rw == 1) {
- env->spr[SPR_DSISR] = 0x42000000;
- } else {
- env->spr[SPR_DSISR] = 0x40000000;
- }
- } else {
- env->exception_index = POWERPC_EXCP_DSEG;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- }
+ env->exception_index = POWERPC_EXCP_DSEG;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
break;
#endif
}
@@ -2326,7 +2304,6 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
@@ -2396,7 +2373,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
tlb_flush_page(env, addr | (0xF << 28));
break;
#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
@@ -2420,16 +2396,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
/*****************************************************************************/
/* Special registers manipulation */
-#if defined(TARGET_PPC64)
-void ppc_store_asr(CPUPPCState *env, target_ulong value)
-{
- if (env->asr != value) {
- env->asr = value;
- tlb_flush(env, 1);
- }
-}
-#endif
-
void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index fa9e9e3..cb4b414 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -9427,7 +9427,6 @@ void cpu_dump_state (CPUPPCState *env, FILE *f, fprintf_function cpu_fprintf,
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
#if defined(TARGET_PPC64)
- case POWERPC_MMU_620:
case POWERPC_MMU_64B:
#endif
cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 09ad4ba..c580d62 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -365,7 +365,6 @@ static void spr_write_sdr1 (void *opaque, int sprn, int gprn)
}
/* 64 bits PowerPC specific SPRs */
-/* ASR */
#if defined(TARGET_PPC64)
static void spr_read_hior (void *opaque, int gprn, int sprn)
{
@@ -379,16 +378,6 @@ static void spr_write_hior (void *opaque, int sprn, int gprn)
tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
tcg_temp_free(t0);
}
-
-static void spr_read_asr (void *opaque, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, asr));
-}
-
-static void spr_write_asr (void *opaque, int sprn, int gprn)
-{
- gen_helper_store_asr(cpu_env, cpu_gpr[gprn]);
-}
#endif
#endif
@@ -2151,173 +2140,6 @@ static void gen_spr_compress (CPUPPCState *env)
0x00000000);
}
-#if defined (TARGET_PPC64)
-/* SPR specific to PowerPC 620 */
-static void gen_spr_620 (CPUPPCState *env)
-{
- /* Processor identification */
- spr_register(env, SPR_PIR, "PIR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_pir,
- 0x00000000);
- spr_register(env, SPR_ASR, "ASR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_asr, &spr_write_asr,
- 0x00000000);
- /* Breakpoints */
- /* XXX : not implemented */
- spr_register(env, SPR_IABR, "IABR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_DABR, "DABR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_SIAR, "SIAR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_SDA, "SDA",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMC1R, "PMC1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_620_PMC1W, "PMC1",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMC2R, "PMC2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_620_PMC2W, "PMC2",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_MMCR0R, "MMCR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_620_MMCR0W, "MMCR0",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, &spr_write_generic,
- 0x00000000);
- /* External access control */
- /* XXX : not implemented */
- spr_register(env, SPR_EAR, "EAR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
-#if 0 // XXX: check this
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR0, "PMR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR1, "PMR1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR2, "PMR2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR3, "PMR3",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR4, "PMR4",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR5, "PMR5",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR6, "PMR6",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR7, "PMR7",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR8, "PMR8",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMR9, "PMR9",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMRA, "PMR10",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMRB, "PMR11",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMRC, "PMR12",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMRD, "PMR13",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMRE, "PMR14",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_PMRF, "PMR15",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
-#endif
- /* XXX : not implemented */
- spr_register(env, SPR_620_BUSCSR, "BUSCSR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_L2CR, "L2CR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_620_L2SR, "L2SR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
-}
-#endif /* defined (TARGET_PPC64) */
-
static void gen_spr_5xx_8xx (CPUPPCState *env)
{
/* Exception processing */
@@ -2993,31 +2815,6 @@ static void init_excp_604 (CPUPPCState *env)
#endif
}
-#if defined(TARGET_PPC64)
-static void init_excp_620 (CPUPPCState *env)
-{
-#if !defined(CONFIG_USER_ONLY)
- env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100;
- env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200;
- env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300;
- env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400;
- env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
- env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600;
- env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700;
- env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800;
- env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900;
- env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
- env->excp_vectors[POWERPC_EXCP_TRACE] = 0x00000D00;
- env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
- env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
- env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->hreset_excp_prefix = 0xFFF00000UL;
- /* Hardware reset vector */
- env->hreset_vector = 0x0000000000000100ULL;
-#endif
-}
-#endif /* defined(TARGET_PPC64) */
-
static void init_excp_7x0 (CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
@@ -7129,55 +6926,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR;
}
-
-static void init_proc_620 (CPUPPCState *env)
-{
- gen_spr_ne_601(env);
- gen_spr_620(env);
- /* Time base */
- gen_tbl(env);
- /* Hardware implementation registers */
- /* XXX : not implemented */
- spr_register(env, SPR_HID0, "HID0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Memory management */
- gen_low_BATs(env);
- init_excp_620(env);
- env->dcache_line_size = 64;
- env->icache_line_size = 64;
- /* Allocate hardware IRQ controller */
- ppc6xx_irq_init(env);
-}
-
-POWERPC_FAMILY(620)(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-
- dc->desc = "PowerPC 620";
- pcc->init_proc = init_proc_620;
- pcc->check_pow = check_pow_nocheck; /* Check this */
- pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
- PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
- PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
- PPC_FLOAT_STFIWX |
- PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
- PPC_MEM_SYNC | PPC_MEM_EIEIO |
- PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
- PPC_SEGMENT | PPC_EXTERN |
- PPC_64B | PPC_SLBI;
- pcc->insns_flags2 = PPC_NONE;
- pcc->msr_mask = 0x800000000005FF77ULL;
- pcc->mmu_model = POWERPC_MMU_620;
- pcc->excp_model = POWERPC_EXCP_970;
- pcc->bus_model = PPC_FLAGS_INPUT_6xx;
- pcc->bfd_mach = bfd_mach_ppc64;
- pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
- POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK;
-}
-
#endif /* defined (TARGET_PPC64) */
@@ -7915,9 +7663,6 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
case POWERPC_MMU_64B:
mmu_model = "PowerPC 64";
break;
- case POWERPC_MMU_620:
- mmu_model = "PowerPC 620";
- break;
#endif
default:
mmu_model = "Unknown or invalid";
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 02/48] target-ppc: Trivial cleanups in mmu_helper.c
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 01/48] target-ppc: Remove vestigial PowerPC 620 support David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 03/48] target-ppc: Remove address check for logging David Gibson
` (46 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
This removes the never-used pte64_invalidate() function, and makes
ppcmas_tlb_check() static, since it's only used within that file.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 3 ---
target-ppc/mmu_helper.c | 11 +++--------
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 68e6967..2210ce5 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1168,9 +1168,6 @@ void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
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);
-int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
- hwaddr *raddrp, target_ulong address,
- uint32_t pid);
void ppc_tlb_invalidate_all (CPUPPCState *env);
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
#endif
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 2f01b31..3570e91 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -98,11 +98,6 @@ static inline int pte64_is_valid(target_ulong pte0)
{
return pte0 & 0x0000000000000001ULL ? 1 : 0;
}
-
-static inline void pte64_invalidate(target_ulong *pte0)
-{
- *pte0 &= ~0x0000000000000001ULL;
-}
#endif
#define PTE_PTEM_MASK 0x7FFFFFBF
@@ -1309,9 +1304,9 @@ static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
}
/* TLB check function for MAS based SoftTLBs */
-int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
- hwaddr *raddrp,
- target_ulong address, uint32_t pid)
+static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
+ hwaddr *raddrp,
+ target_ulong address, uint32_t pid)
{
target_ulong mask;
uint32_t tlb_pid;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 03/48] target-ppc: Remove address check for logging
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 01/48] target-ppc: Remove vestigial PowerPC 620 support David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 02/48] target-ppc: Trivial cleanups in mmu_helper.c David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 04/48] target-ppc: Move SLB handling into a mmu-hash64.c David Gibson
` (45 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
One LOG_MMU statement in mmu_helper.c has an odd check on the effective
address being translated. I can see no reason for this; I suspect it was
a debugging hack from long ago. This patch removes it.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu_helper.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 3570e91..f1de84c 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -906,12 +906,10 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
if (ret < 0) {
/* Secondary table lookup */
- if (eaddr != 0xEFFFFFFF) {
- LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- }
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
ret2 = find_pte(env, ctx, 1, rw, type,
target_page_bits);
if (ret2 != -1) {
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 04/48] target-ppc: Move SLB handling into a mmu-hash64.c
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (2 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 03/48] target-ppc: Remove address check for logging David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 05/48] target-ppc: Disentangle pte_check() David Gibson
` (44 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
As a first step to disentangling the handling for 64-bit hash MMUs from
the rest, we move the code handling the Segment Lookaside Buffer (SLB)
(which only exists on 64-bit hash MMUs) into a new mmu-hash64.c file.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/Makefile.objs | 5 +-
target-ppc/cpu.h | 3 -
target-ppc/mmu-hash64.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/mmu-hash64.h | 14 +++
target-ppc/mmu_helper.c | 198 +------------------------------------------
5 files changed, 232 insertions(+), 199 deletions(-)
create mode 100644 target-ppc/mmu-hash64.c
create mode 100644 target-ppc/mmu-hash64.h
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 00ac4ad..4ef9fc0 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -1,6 +1,9 @@
obj-y += cpu-models.o
obj-y += translate.o
-obj-$(CONFIG_SOFTMMU) += machine.o
+ifeq ($(CONFIG_SOFTMMU),y)
+obj-y += machine.o
+obj-$(TARGET_PPC64) += mmu-hash64.o
+endif
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += excp_helper.o
obj-y += fpu_helper.o
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2210ce5..74b6e0e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1134,9 +1134,6 @@ void ppc_hw_interrupt (CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
-#if defined(TARGET_PPC64)
-int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
-#endif /* defined(TARGET_PPC64) */
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
new file mode 100644
index 0000000..a72e7c1
--- /dev/null
+++ b/target-ppc/mmu-hash64.c
@@ -0,0 +1,211 @@
+/*
+ * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ * Copyright (c) 2013 David Gibson, IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "cpu.h"
+#include "helper.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "mmu-hash64.h"
+
+//#define DEBUG_SLB
+
+#ifdef DEBUG_SLB
+# define LOG_SLB(...) qemu_log(__VA_ARGS__)
+#else
+# define LOG_SLB(...) do { } while (0)
+#endif
+
+/*
+ * SLB handling
+ */
+
+ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
+{
+ uint64_t esid_256M, esid_1T;
+ int n;
+
+ LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
+
+ esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+ esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
+
+ for (n = 0; n < env->slb_nr; n++) {
+ ppc_slb_t *slb = &env->slb[n];
+
+ LOG_SLB("%s: slot %d %016" PRIx64 " %016"
+ PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
+ /* We check for 1T matches on all MMUs here - if the MMU
+ * doesn't have 1T segment support, we will have prevented 1T
+ * entries from being inserted in the slbmte code. */
+ if (((slb->esid == esid_256M) &&
+ ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
+ || ((slb->esid == esid_1T) &&
+ ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
+ return slb;
+ }
+ }
+
+ return NULL;
+}
+
+void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
+{
+ int i;
+ uint64_t slbe, slbv;
+
+ cpu_synchronize_state(env);
+
+ cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
+ for (i = 0; i < env->slb_nr; i++) {
+ slbe = env->slb[i].esid;
+ slbv = env->slb[i].vsid;
+ if (slbe == 0 && slbv == 0) {
+ continue;
+ }
+ cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
+ i, slbe, slbv);
+ }
+}
+
+void helper_slbia(CPUPPCState *env)
+{
+ int n, do_invalidate;
+
+ 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];
+
+ if (slb->esid & SLB_ESID_V) {
+ slb->esid &= ~SLB_ESID_V;
+ /* XXX: given the fact that segment size is 256 MB or 1TB,
+ * and we still don't have a tlb_flush_mask(env, n, mask)
+ * in QEMU, we just invalidate all TLBs
+ */
+ do_invalidate = 1;
+ }
+ }
+ if (do_invalidate) {
+ tlb_flush(env, 1);
+ }
+}
+
+void helper_slbie(CPUPPCState *env, target_ulong addr)
+{
+ ppc_slb_t *slb;
+
+ slb = slb_lookup(env, addr);
+ if (!slb) {
+ return;
+ }
+
+ if (slb->esid & SLB_ESID_V) {
+ slb->esid &= ~SLB_ESID_V;
+
+ /* XXX: given the fact that segment size is 256 MB or 1TB,
+ * and we still don't have a tlb_flush_mask(env, n, mask)
+ * in QEMU, we just invalidate all TLBs
+ */
+ tlb_flush(env, 1);
+ }
+}
+
+int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
+{
+ int slot = rb & 0xfff;
+ ppc_slb_t *slb = &env->slb[slot];
+
+ if (rb & (0x1000 - env->slb_nr)) {
+ return -1; /* Reserved bits set or slot too high */
+ }
+ if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
+ return -1; /* Bad segment size */
+ }
+ if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
+ return -1; /* 1T segment on MMU that doesn't support it */
+ }
+
+ /* Mask out the slot number as we store the entry */
+ slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
+ slb->vsid = rs;
+
+ LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
+ " %016" PRIx64 "\n", __func__, slot, rb, rs,
+ slb->esid, slb->vsid);
+
+ return 0;
+}
+
+static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb,
+ target_ulong *rt)
+{
+ int slot = rb & 0xfff;
+ ppc_slb_t *slb = &env->slb[slot];
+
+ if (slot >= env->slb_nr) {
+ return -1;
+ }
+
+ *rt = slb->esid;
+ return 0;
+}
+
+static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,
+ target_ulong *rt)
+{
+ int slot = rb & 0xfff;
+ ppc_slb_t *slb = &env->slb[slot];
+
+ if (slot >= env->slb_nr) {
+ return -1;
+ }
+
+ *rt = slb->vsid;
+ return 0;
+}
+
+void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
+{
+ if (ppc_store_slb(env, rb, rs) < 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
+ }
+}
+
+target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
+{
+ target_ulong rt = 0;
+
+ if (ppc_load_slb_esid(env, rb, &rt) < 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
+ }
+ return rt;
+}
+
+target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
+{
+ target_ulong rt = 0;
+
+ if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
+ helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL);
+ }
+ return rt;
+}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
new file mode 100644
index 0000000..894b1f2
--- /dev/null
+++ b/target-ppc/mmu-hash64.h
@@ -0,0 +1,14 @@
+#if !defined (__MMU_HASH64_H__)
+#define __MMU_HASH64_H__
+
+#ifndef CONFIG_USER_ONLY
+
+#ifdef TARGET_PPC64
+ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr);
+void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
+int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
+#endif
+
+#endif /* CONFIG_USER_ONLY */
+
+#endif /* !defined (__MMU_HASH64_H__) */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index f1de84c..671ca5e 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -20,10 +20,10 @@
#include "helper.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
+#include "mmu-hash64.h"
//#define DEBUG_MMU
//#define DEBUG_BATS
-//#define DEBUG_SLB
//#define DEBUG_SOFTWARE_TLB
//#define DUMP_PAGE_TABLES
//#define DEBUG_SOFTWARE_TLB
@@ -49,12 +49,6 @@
# define LOG_BATS(...) do { } while (0)
#endif
-#ifdef DEBUG_SLB
-# define LOG_SLB(...) qemu_log(__VA_ARGS__)
-#else
-# define LOG_SLB(...) do { } while (0)
-#endif
-
/*****************************************************************************/
/* PowerPC MMU emulation */
#if defined(CONFIG_USER_ONLY)
@@ -677,137 +671,6 @@ static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
return find_pte2(env, ctx, 0, h, rw, type, target_page_bits);
}
-#if defined(TARGET_PPC64)
-static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
-{
- uint64_t esid_256M, esid_1T;
- int n;
-
- LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
-
- esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
- esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
-
- for (n = 0; n < env->slb_nr; n++) {
- ppc_slb_t *slb = &env->slb[n];
-
- LOG_SLB("%s: slot %d %016" PRIx64 " %016"
- PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
- /* We check for 1T matches on all MMUs here - if the MMU
- * doesn't have 1T segment support, we will have prevented 1T
- * entries from being inserted in the slbmte code. */
- if (((slb->esid == esid_256M) &&
- ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
- || ((slb->esid == esid_1T) &&
- ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
- return slb;
- }
- }
-
- return NULL;
-}
-
-/*****************************************************************************/
-/* SPR accesses */
-
-void helper_slbia(CPUPPCState *env)
-{
- int n, do_invalidate;
-
- 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];
-
- if (slb->esid & SLB_ESID_V) {
- slb->esid &= ~SLB_ESID_V;
- /* XXX: given the fact that segment size is 256 MB or 1TB,
- * and we still don't have a tlb_flush_mask(env, n, mask)
- * in QEMU, we just invalidate all TLBs
- */
- do_invalidate = 1;
- }
- }
- if (do_invalidate) {
- tlb_flush(env, 1);
- }
-}
-
-void helper_slbie(CPUPPCState *env, target_ulong addr)
-{
- ppc_slb_t *slb;
-
- slb = slb_lookup(env, addr);
- if (!slb) {
- return;
- }
-
- if (slb->esid & SLB_ESID_V) {
- slb->esid &= ~SLB_ESID_V;
-
- /* XXX: given the fact that segment size is 256 MB or 1TB,
- * and we still don't have a tlb_flush_mask(env, n, mask)
- * in QEMU, we just invalidate all TLBs
- */
- tlb_flush(env, 1);
- }
-}
-
-int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
-{
- int slot = rb & 0xfff;
- ppc_slb_t *slb = &env->slb[slot];
-
- if (rb & (0x1000 - env->slb_nr)) {
- return -1; /* Reserved bits set or slot too high */
- }
- if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
- return -1; /* Bad segment size */
- }
- if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
- return -1; /* 1T segment on MMU that doesn't support it */
- }
-
- /* Mask out the slot number as we store the entry */
- slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
- slb->vsid = rs;
-
- LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
- " %016" PRIx64 "\n", __func__, slot, rb, rs,
- slb->esid, slb->vsid);
-
- return 0;
-}
-
-static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb,
- target_ulong *rt)
-{
- int slot = rb & 0xfff;
- ppc_slb_t *slb = &env->slb[slot];
-
- if (slot >= env->slb_nr) {
- return -1;
- }
-
- *rt = slb->esid;
- return 0;
-}
-
-static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,
- target_ulong *rt)
-{
- int slot = rb & 0xfff;
- ppc_slb_t *slb = &env->slb[slot];
-
- if (slot >= env->slb_nr) {
- return -1;
- }
-
- *rt = slb->vsid;
- return 0;
-}
-#endif /* defined(TARGET_PPC64) */
-
/* Perform segment based translation */
static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int type)
@@ -1304,7 +1167,7 @@ static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
/* TLB check function for MAS based SoftTLBs */
static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
hwaddr *raddrp,
- target_ulong address, uint32_t pid)
+ target_ulong address, uint32_t pid)
{
target_ulong mask;
uint32_t tlb_pid;
@@ -1590,28 +1453,6 @@ static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
}
}
-#if defined(TARGET_PPC64)
-static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
- CPUPPCState *env)
-{
- int i;
- uint64_t slbe, slbv;
-
- cpu_synchronize_state(env);
-
- cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
- for (i = 0; i < env->slb_nr; i++) {
- slbe = env->slb[i].esid;
- slbv = env->slb[i].vsid;
- if (slbe == 0 && slbv == 0) {
- continue;
- }
- cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
- i, slbe, slbv);
- }
-}
-#endif
-
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
{
switch (env->mmu_model) {
@@ -1625,7 +1466,7 @@ void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
- mmubooks_dump_mmu(f, cpu_fprintf, env);
+ dump_slb(f, cpu_fprintf, env);
break;
#endif
default:
@@ -2473,39 +2314,6 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
#endif /* !defined(CONFIG_USER_ONLY) */
#if !defined(CONFIG_USER_ONLY)
-/* SLB management */
-#if defined(TARGET_PPC64)
-void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
-{
- if (ppc_store_slb(env, rb, rs) < 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL);
- }
-}
-
-target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
-{
- target_ulong rt = 0;
-
- if (ppc_load_slb_esid(env, rb, &rt) < 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL);
- }
- return rt;
-}
-
-target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
-{
- target_ulong rt = 0;
-
- if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
- helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
- POWERPC_EXCP_INVAL);
- }
- return rt;
-}
-#endif /* defined(TARGET_PPC64) */
-
/* TLB management */
void helper_tlbia(CPUPPCState *env)
{
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 05/48] target-ppc: Disentangle pte_check()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (3 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 04/48] target-ppc: Move SLB handling into a mmu-hash64.c David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 06/48] target-ppc: Disentangle find_pte() David Gibson
` (43 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Currently support for both 32-bit and 64-bit hash MMUs share an
implementation of pte_check. But there are enough differences that this
means the shared function has several very ugly conditionals on "is_64b".
This patch cleans things up by separating out the 64-bit version
(putting it into mmu-hash64.c) and the 32-bit hash version (putting it
in mmu-hash32.c). Another copy remains in mmu_helper.c, which is used
for the 6xx software loaded TLB paths.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/Makefile.objs | 2 +-
target-ppc/cpu.h | 2 ++
target-ppc/mmu-hash32.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/mmu-hash32.h | 12 +++++++
target-ppc/mmu-hash64.c | 65 +++++++++++++++++++++++++++++++++++
target-ppc/mmu-hash64.h | 2 ++
target-ppc/mmu_helper.c | 67 +++++++-----------------------------
7 files changed, 179 insertions(+), 56 deletions(-)
create mode 100644 target-ppc/mmu-hash32.c
create mode 100644 target-ppc/mmu-hash32.h
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index 4ef9fc0..c80911f 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -1,7 +1,7 @@
obj-y += cpu-models.o
obj-y += translate.o
ifeq ($(CONFIG_SOFTMMU),y)
-obj-y += machine.o
+obj-y += machine.o mmu-hash32.o
obj-$(TARGET_PPC64) += mmu-hash64.o
endif
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 74b6e0e..15d3174 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1134,6 +1134,8 @@ void ppc_hw_interrupt (CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
+int pp_check(int key, int pp, int nx);
+int check_prot(int prot, int rw, int access_type);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
new file mode 100644
index 0000000..ce5389d
--- /dev/null
+++ b/target-ppc/mmu-hash32.c
@@ -0,0 +1,85 @@
+/*
+ * PowerPC MMU, TLB and BAT emulation helpers for QEMU.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ * Copyright (c) 2013 David Gibson, IBM Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "helper.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "mmu-hash32.h"
+
+//#define DEBUG_MMU
+
+#ifdef DEBUG_MMU
+# define LOG_MMU(...) qemu_log(__VA_ARGS__)
+# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
+#else
+# define LOG_MMU(...) do { } while (0)
+# define LOG_MMU_STATE(...) do { } while (0)
+#endif
+
+#define PTE_PTEM_MASK 0x7FFFFFBF
+#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+
+static inline int pte_is_valid_hash32(target_ulong pte0)
+{
+ return pte0 & 0x80000000 ? 1 : 0;
+}
+
+int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
+{
+ target_ulong ptem, mmask;
+ int access, ret, pteh, ptev, pp;
+
+ ret = -1;
+ /* Check validity and table match */
+ ptev = pte_is_valid_hash32(pte0);
+ pteh = (pte0 >> 6) & 1;
+ if (ptev && h == pteh) {
+ /* Check vsid & api */
+ ptem = pte0 & PTE_PTEM_MASK;
+ mmask = PTE_CHECK_MASK;
+ pp = pte1 & 0x00000003;
+ if (ptem == ctx->ptem) {
+ if (ctx->raddr != (hwaddr)-1ULL) {
+ /* all matches should have equal RPN, WIMG & PP */
+ if ((ctx->raddr & mmask) != (pte1 & mmask)) {
+ qemu_log("Bad RPN/WIMG/PP\n");
+ return -3;
+ }
+ }
+ /* Compute access rights */
+ access = pp_check(ctx->key, pp, ctx->nx);
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte1;
+ ctx->prot = access;
+ ret = check_prot(ctx->prot, rw, type);
+ if (ret == 0) {
+ /* Access granted */
+ LOG_MMU("PTE access granted !\n");
+ } else {
+ /* Access right violation */
+ LOG_MMU("PTE access rejected\n");
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
new file mode 100644
index 0000000..2411085
--- /dev/null
+++ b/target-ppc/mmu-hash32.h
@@ -0,0 +1,12 @@
+#if !defined (__MMU_HASH32_H__)
+#define __MMU_HASH32_H__
+
+#ifndef CONFIG_USER_ONLY
+
+int pte32_is_valid(target_ulong pte0);
+int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type);
+
+#endif /* CONFIG_USER_ONLY */
+
+#endif /* __MMU_HASH32_H__ */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index a72e7c1..9c0de1b 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -23,8 +23,17 @@
#include "kvm_ppc.h"
#include "mmu-hash64.h"
+//#define DEBUG_MMU
//#define DEBUG_SLB
+#ifdef DEBUG_MMU
+# define LOG_MMU(...) qemu_log(__VA_ARGS__)
+# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
+#else
+# define LOG_MMU(...) do { } while (0)
+# define LOG_MMU_STATE(...) do { } while (0)
+#endif
+
#ifdef DEBUG_SLB
# define LOG_SLB(...) qemu_log(__VA_ARGS__)
#else
@@ -209,3 +218,59 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
}
return rt;
}
+
+/*
+ * 64-bit hash table MMU handling
+ */
+
+#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
+#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
+
+static inline int pte64_is_valid(target_ulong pte0)
+{
+ return pte0 & 0x0000000000000001ULL ? 1 : 0;
+}
+
+int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
+{
+ target_ulong ptem, mmask;
+ int access, ret, pteh, ptev, pp;
+
+ ret = -1;
+ /* Check validity and table match */
+ ptev = pte64_is_valid(pte0);
+ pteh = (pte0 >> 1) & 1;
+ if (ptev && h == pteh) {
+ /* Check vsid & api */
+ ptem = pte0 & PTE64_PTEM_MASK;
+ mmask = PTE64_CHECK_MASK;
+ pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
+ ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
+ ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
+ if (ptem == ctx->ptem) {
+ if (ctx->raddr != (hwaddr)-1ULL) {
+ /* all matches should have equal RPN, WIMG & PP */
+ if ((ctx->raddr & mmask) != (pte1 & mmask)) {
+ qemu_log("Bad RPN/WIMG/PP\n");
+ return -3;
+ }
+ }
+ /* Compute access rights */
+ access = pp_check(ctx->key, pp, ctx->nx);
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte1;
+ ctx->prot = access;
+ ret = check_prot(ctx->prot, rw, type);
+ if (ret == 0) {
+ /* Access granted */
+ LOG_MMU("PTE access granted !\n");
+ } else {
+ /* Access right violation */
+ LOG_MMU("PTE access rejected\n");
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 894b1f2..1a2e3e7 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -7,6 +7,8 @@
ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr);
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
+int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type);
#endif
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 671ca5e..c7620c0 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -21,6 +21,7 @@
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "mmu-hash64.h"
+#include "mmu-hash32.h"
//#define DEBUG_MMU
//#define DEBUG_BATS
@@ -87,21 +88,10 @@ static inline void pte_invalidate(target_ulong *pte0)
*pte0 &= ~0x80000000;
}
-#if defined(TARGET_PPC64)
-static inline int pte64_is_valid(target_ulong pte0)
-{
- return pte0 & 0x0000000000000001ULL ? 1 : 0;
-}
-#endif
-
#define PTE_PTEM_MASK 0x7FFFFFBF
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
-#if defined(TARGET_PPC64)
-#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
-#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
-#endif
-static inline int pp_check(int key, int pp, int nx)
+int pp_check(int key, int pp, int nx)
{
int access;
@@ -142,7 +132,7 @@ static inline int pp_check(int key, int pp, int nx)
return access;
}
-static inline int check_prot(int prot, int rw, int access_type)
+int check_prot(int prot, int rw, int access_type)
{
int ret;
@@ -169,40 +159,21 @@ static inline int check_prot(int prot, int rw, int access_type)
return ret;
}
-static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
+static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
{
target_ulong ptem, mmask;
int access, ret, pteh, ptev, pp;
ret = -1;
/* Check validity and table match */
-#if defined(TARGET_PPC64)
- if (is_64b) {
- ptev = pte64_is_valid(pte0);
- pteh = (pte0 >> 1) & 1;
- } else
-#endif
- {
- ptev = pte_is_valid(pte0);
- pteh = (pte0 >> 6) & 1;
- }
+ ptev = pte_is_valid(pte0);
+ pteh = (pte0 >> 6) & 1;
if (ptev && h == pteh) {
/* Check vsid & api */
-#if defined(TARGET_PPC64)
- if (is_64b) {
- ptem = pte0 & PTE64_PTEM_MASK;
- mmask = PTE64_CHECK_MASK;
- pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
- ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
- ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
- } else
-#endif
- {
- ptem = pte0 & PTE_PTEM_MASK;
- mmask = PTE_CHECK_MASK;
- pp = pte1 & 0x00000003;
- }
+ ptem = pte0 & PTE_PTEM_MASK;
+ mmask = PTE_CHECK_MASK;
+ pp = pte1 & 0x00000003;
if (ptem == ctx->ptem) {
if (ctx->raddr != (hwaddr)-1ULL) {
/* all matches should have equal RPN, WIMG & PP */
@@ -230,20 +201,6 @@ static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
return ret;
}
-static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
-{
- return pte_check(ctx, 0, pte0, pte1, h, rw, type);
-}
-
-#if defined(TARGET_PPC64)
-static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
-{
- return pte_check(ctx, 1, pte0, pte1, h, rw, type);
-}
-#endif
-
static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
int ret, int rw)
{
@@ -381,7 +338,7 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
pte_is_valid(tlb->pte0) ? "valid" : "inval",
tlb->EPN, eaddr, tlb->pte1,
rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
- switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
+ switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
case -3:
/* TLB inconsistency */
return -1;
@@ -590,7 +547,7 @@ static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
}
- r = pte32_check(ctx, pte0, pte1, h, rw, type);
+ r = pte_check_hash32(ctx, pte0, pte1, h, rw, type);
LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 06/48] target-ppc: Disentangle find_pte()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (4 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 05/48] target-ppc: Disentangle pte_check() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 07/48] target-ppc: Disentangle get_segment() David Gibson
` (42 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
32-bit and 64-bit hash MMU implementations currently share a find_pte
function. This results in a whole bunch of ugly conditionals in the shared
function, and not all that much actually shared code.
This patch separates out the 32-bit and 64-bit versions, putting then
in mmu-hash64.c and mmu-has32.c, and removes the conditionals from
both versions.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 2 +
target-ppc/mmu-hash32.c | 78 ++++++++++++++++++++++++++++++-
target-ppc/mmu-hash32.h | 4 +-
target-ppc/mmu-hash64.c | 79 ++++++++++++++++++++++++++++++-
target-ppc/mmu-hash64.h | 4 +-
target-ppc/mmu_helper.c | 119 ++---------------------------------------------
6 files changed, 164 insertions(+), 122 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 15d3174..a9994cb 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1136,6 +1136,8 @@ void ppc_hw_interrupt (CPUPPCState *env);
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
int pp_check(int key, int pp, int nx);
int check_prot(int prot, int rw, int access_type);
+int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, int ret, int rw);
+hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index ce5389d..f852e5c 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -42,8 +42,8 @@ static inline int pte_is_valid_hash32(target_ulong pte0)
return pte0 & 0x80000000 ? 1 : 0;
}
-int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
+static int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
{
target_ulong ptem, mmask;
int access, ret, pteh, ptev, pp;
@@ -83,3 +83,77 @@ int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
return ret;
}
+
+/* PTE table lookup */
+int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+ int rw, int type, int target_page_bits)
+{
+ hwaddr pteg_off;
+ target_ulong pte0, pte1;
+ int i, good = -1;
+ int ret, r;
+
+ ret = -1; /* No entry found */
+ pteg_off = get_pteg_offset(env, ctx->hash[h], HASH_PTE_SIZE_32);
+ for (i = 0; i < 8; i++) {
+ if (env->external_htab) {
+ pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
+ pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
+ } else {
+ pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
+ pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
+ }
+ r = pte_check_hash32(ctx, pte0, pte1, h, rw, type);
+ LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
+ TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
+ pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
+ (int)((pte0 >> 6) & 1), ctx->ptem);
+ switch (r) {
+ case -3:
+ /* PTE inconsistency */
+ return -1;
+ case -2:
+ /* Access violation */
+ ret = -2;
+ good = i;
+ break;
+ case -1:
+ default:
+ /* No PTE match */
+ break;
+ case 0:
+ /* access granted */
+ /* XXX: we should go on looping to check all PTEs consistency
+ * but if we can speed-up the whole thing as the
+ * result would be undefined if PTEs are not consistent.
+ */
+ ret = 0;
+ good = i;
+ goto done;
+ }
+ }
+ if (good != -1) {
+ done:
+ LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
+ ctx->raddr, ctx->prot, ret);
+ /* Update page flags */
+ pte1 = ctx->raddr;
+ if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+ if (env->external_htab) {
+ stl_p(env->external_htab + pteg_off + (good * 8) + 4,
+ pte1);
+ } else {
+ stl_phys_notdirty(env->htab_base + pteg_off +
+ (good * 8) + 4, pte1);
+ }
+ }
+ }
+
+ /* We have a TLB that saves 4K pages, so let's
+ * split a huge page to 4k chunks */
+ if (target_page_bits != TARGET_PAGE_BITS) {
+ ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
+ & TARGET_PAGE_MASK;
+ }
+ return ret;
+}
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 2411085..6bf8f92 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -4,8 +4,8 @@
#ifndef CONFIG_USER_ONLY
int pte32_is_valid(target_ulong pte0);
-int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type);
+int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+ int rw, int type, int target_page_bits);
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 9c0de1b..a525bd5 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -231,8 +231,8 @@ static inline int pte64_is_valid(target_ulong pte0)
return pte0 & 0x0000000000000001ULL ? 1 : 0;
}
-int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
+static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h, int rw, int type)
{
target_ulong ptem, mmask;
int access, ret, pteh, ptev, pp;
@@ -274,3 +274,78 @@ int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
return ret;
}
+
+/* PTE table lookup */
+int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+ int rw, int type, int target_page_bits)
+{
+ hwaddr pteg_off;
+ target_ulong pte0, pte1;
+ int i, good = -1;
+ int ret, r;
+
+ ret = -1; /* No entry found */
+ pteg_off = get_pteg_offset(env, ctx->hash[h], HASH_PTE_SIZE_64);
+ for (i = 0; i < 8; i++) {
+ if (env->external_htab) {
+ pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
+ pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
+ } else {
+ pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
+ pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
+ }
+
+ r = pte64_check(ctx, pte0, pte1, h, rw, type);
+ LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " "
+ TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
+ pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
+ (int)((pte0 >> 1) & 1), ctx->ptem);
+ switch (r) {
+ case -3:
+ /* PTE inconsistency */
+ return -1;
+ case -2:
+ /* Access violation */
+ ret = -2;
+ good = i;
+ break;
+ case -1:
+ default:
+ /* No PTE match */
+ break;
+ case 0:
+ /* access granted */
+ /* XXX: we should go on looping to check all PTEs consistency
+ * but if we can speed-up the whole thing as the
+ * result would be undefined if PTEs are not consistent.
+ */
+ ret = 0;
+ good = i;
+ goto done;
+ }
+ }
+ if (good != -1) {
+ done:
+ LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
+ ctx->raddr, ctx->prot, ret);
+ /* Update page flags */
+ pte1 = ctx->raddr;
+ if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+ if (env->external_htab) {
+ stq_p(env->external_htab + pteg_off + (good * 16) + 8,
+ pte1);
+ } else {
+ stq_phys_notdirty(env->htab_base + pteg_off +
+ (good * 16) + 8, pte1);
+ }
+ }
+ }
+
+ /* We have a TLB that saves 4K pages, so let's
+ * split a huge page to 4k chunks */
+ if (target_page_bits != TARGET_PAGE_BITS) {
+ ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
+ & TARGET_PAGE_MASK;
+ }
+ return ret;
+}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 1a2e3e7..7b9713d 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -7,8 +7,8 @@
ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr);
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
-int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type);
+int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+ int rw, int type, int target_page_bits);
#endif
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index c7620c0..1301391 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -201,8 +201,8 @@ static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
return ret;
}
-static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
- int ret, int rw)
+int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
+ int ret, int rw)
{
int store = 0;
@@ -502,130 +502,21 @@ static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-static inline hwaddr get_pteg_offset(CPUPPCState *env,
- hwaddr hash,
- int pte_size)
+hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size)
{
return (hash * pte_size * 8) & env->htab_mask;
}
-/* PTE table lookup */
-static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
- int rw, int type, int target_page_bits)
-{
- hwaddr pteg_off;
- target_ulong pte0, pte1;
- int i, good = -1;
- int ret, r;
-
- ret = -1; /* No entry found */
- pteg_off = get_pteg_offset(env, ctx->hash[h],
- is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
- for (i = 0; i < 8; i++) {
-#if defined(TARGET_PPC64)
- if (is_64b) {
- if (env->external_htab) {
- pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
- pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
- } else {
- pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
- pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
- }
-
- r = pte64_check(ctx, pte0, pte1, h, rw, type);
- LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " "
- TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
- pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
- (int)((pte0 >> 1) & 1), ctx->ptem);
- } else
-#endif
- {
- if (env->external_htab) {
- pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
- pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
- } else {
- pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
- pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
- }
- r = pte_check_hash32(ctx, pte0, pte1, h, rw, type);
- LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
- TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
- pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
- (int)((pte0 >> 6) & 1), ctx->ptem);
- }
- switch (r) {
- case -3:
- /* PTE inconsistency */
- return -1;
- case -2:
- /* Access violation */
- ret = -2;
- good = i;
- break;
- case -1:
- default:
- /* No PTE match */
- break;
- case 0:
- /* access granted */
- /* XXX: we should go on looping to check all PTEs consistency
- * but if we can speed-up the whole thing as the
- * result would be undefined if PTEs are not consistent.
- */
- ret = 0;
- good = i;
- goto done;
- }
- }
- if (good != -1) {
- done:
- LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
- ctx->raddr, ctx->prot, ret);
- /* Update page flags */
- pte1 = ctx->raddr;
- if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
-#if defined(TARGET_PPC64)
- if (is_64b) {
- if (env->external_htab) {
- stq_p(env->external_htab + pteg_off + (good * 16) + 8,
- pte1);
- } else {
- stq_phys_notdirty(env->htab_base + pteg_off +
- (good * 16) + 8, pte1);
- }
- } else
-#endif
- {
- if (env->external_htab) {
- stl_p(env->external_htab + pteg_off + (good * 8) + 4,
- pte1);
- } else {
- stl_phys_notdirty(env->htab_base + pteg_off +
- (good * 8) + 4, pte1);
- }
- }
- }
- }
-
- /* We have a TLB that saves 4K pages, so let's
- * split a huge page to 4k chunks */
- if (target_page_bits != TARGET_PAGE_BITS) {
- ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
- & TARGET_PAGE_MASK;
- }
- return ret;
-}
-
static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
int type, int target_page_bits)
{
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
- return find_pte2(env, ctx, 1, h, rw, type, target_page_bits);
+ return find_pte64(env, ctx, h, rw, type, target_page_bits);
}
#endif
- return find_pte2(env, ctx, 0, h, rw, type, target_page_bits);
+ return find_pte32(env, ctx, h, rw, type, target_page_bits);
}
/* Perform segment based translation */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 07/48] target-ppc: Disentangle get_segment()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (5 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 06/48] target-ppc: Disentangle find_pte() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 08/48] target-ppc: Rework get_physical_address() David Gibson
` (41 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
The poorly named get_segment() function handles most of the address
translation logic for hash-based MMUs. It has many ugly conditionals on
whether the MMU is 32-bit or 64-bit.
This patch splits the function into 32 and 64-bit versions, using the
switch on mmu_type that's already in the caller
(get_physical_address()) to select the right one. Most of the
original function remains in mmu_helper.c to support the 6xx software
loaded TLB implementations (cleaning those up is a project for another
day).
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++-
target-ppc/mmu-hash32.h | 4 +-
target-ppc/mmu-hash64.c | 92 ++++++++++++++++++++++++++++-
target-ppc/mmu-hash64.h | 5 +-
target-ppc/mmu_helper.c | 141 +++++++++++++-------------------------------
5 files changed, 280 insertions(+), 111 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index f852e5c..4bae72a 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -85,8 +85,8 @@ static int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
}
/* PTE table lookup */
-int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
- int rw, int type, int target_page_bits)
+static int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+ int rw, int type, int target_page_bits)
{
hwaddr pteg_off;
target_ulong pte0, pte1;
@@ -157,3 +157,148 @@ int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
}
return ret;
}
+
+int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
+{
+ hwaddr hash;
+ target_ulong vsid;
+ int ds, pr, target_page_bits;
+ int ret, ret2;
+ target_ulong sr, pgidx;
+
+ pr = msr_pr;
+ ctx->eaddr = eaddr;
+
+ sr = env->sr[eaddr >> 28];
+ ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
+ ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
+ ds = sr & 0x80000000 ? 1 : 0;
+ ctx->nx = sr & 0x10000000 ? 1 : 0;
+ vsid = sr & 0x00FFFFFF;
+ target_page_bits = TARGET_PAGE_BITS;
+ LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
+ TARGET_FMT_lx " lr=" TARGET_FMT_lx
+ " ir=%d dr=%d pr=%d %d t=%d\n",
+ eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
+ (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+ pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+ hash = vsid ^ pgidx;
+ ctx->ptem = (vsid << 7) | (pgidx >> 10);
+
+ LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
+ ctx->key, ds, ctx->nx, vsid);
+ ret = -1;
+ if (!ds) {
+ /* Check if instruction fetch is allowed, if needed */
+ if (type != ACCESS_CODE || ctx->nx == 0) {
+ /* Page address translation */
+ LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+ " hash " TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, hash);
+ ctx->hash[0] = hash;
+ ctx->hash[1] = ~hash;
+
+ /* Initialize real address with an invalid value */
+ ctx->raddr = (hwaddr)-1ULL;
+ LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, vsid, ctx->ptem,
+ ctx->hash[0]);
+ /* Primary table lookup */
+ ret = find_pte32(env, ctx, 0, rw, type, target_page_bits);
+ if (ret < 0) {
+ /* Secondary table lookup */
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+ ret2 = find_pte32(env, ctx, 1, rw, type,
+ target_page_bits);
+ if (ret2 != -1) {
+ ret = ret2;
+ }
+ }
+#if defined(DUMP_PAGE_TABLES)
+ if (qemu_log_enabled()) {
+ hwaddr curaddr;
+ uint32_t a0, a1, a2, a3;
+
+ qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
+ "\n", sdr, mask + 0x80);
+ for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
+ curaddr += 16) {
+ a0 = ldl_phys(curaddr);
+ a1 = ldl_phys(curaddr + 4);
+ a2 = ldl_phys(curaddr + 8);
+ a3 = ldl_phys(curaddr + 12);
+ if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
+ qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
+ curaddr, a0, a1, a2, a3);
+ }
+ }
+ }
+#endif
+ } else {
+ LOG_MMU("No access allowed\n");
+ ret = -3;
+ }
+ } else {
+ target_ulong sr;
+
+ LOG_MMU("direct store...\n");
+ /* Direct-store segment : absolutely *BUGGY* for now */
+
+ /* Direct-store implies a 32-bit MMU.
+ * Check the Segment Register's bus unit ID (BUID).
+ */
+ sr = env->sr[eaddr >> 28];
+ if ((sr & 0x1FF00000) >> 20 == 0x07f) {
+ /* Memory-forced I/O controller interface access */
+ /* If T=1 and BUID=x'07F', the 601 performs a memory access
+ * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
+ */
+ ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
+ ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return 0;
+ }
+
+ switch (type) {
+ case ACCESS_INT:
+ /* Integer load/store : only access allowed */
+ break;
+ case ACCESS_CODE:
+ /* No code fetch is allowed in direct-store areas */
+ return -4;
+ case ACCESS_FLOAT:
+ /* Floating point load/store */
+ return -4;
+ case ACCESS_RES:
+ /* lwarx, ldarx or srwcx. */
+ return -4;
+ case ACCESS_CACHE:
+ /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
+ /* Should make the instruction do no-op.
+ * As it already do no-op, it's quite easy :-)
+ */
+ ctx->raddr = eaddr;
+ return 0;
+ case ACCESS_EXT:
+ /* eciwx or ecowx */
+ return -4;
+ default:
+ qemu_log("ERROR: instruction should not need "
+ "address translation\n");
+ return -4;
+ }
+ if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+ ctx->raddr = eaddr;
+ ret = 2;
+ } else {
+ ret = -2;
+ }
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 6bf8f92..6f9a0c2 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -4,8 +4,8 @@
#ifndef CONFIG_USER_ONLY
int pte32_is_valid(target_ulong pte0);
-int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
- int rw, int type, int target_page_bits);
+int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type);
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index a525bd5..23eb480 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -44,7 +44,7 @@
* SLB handling
*/
-ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
+static ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
{
uint64_t esid_256M, esid_1T;
int n;
@@ -276,8 +276,8 @@ static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
}
/* PTE table lookup */
-int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
- int rw, int type, int target_page_bits)
+static int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+ int rw, int type, int target_page_bits)
{
hwaddr pteg_off;
target_ulong pte0, pte1;
@@ -349,3 +349,89 @@ int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
}
return ret;
}
+
+int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
+{
+ hwaddr hash;
+ target_ulong vsid;
+ int pr, target_page_bits;
+ int ret, ret2;
+
+ pr = msr_pr;
+ ctx->eaddr = eaddr;
+ ppc_slb_t *slb;
+ target_ulong pageaddr;
+ int segment_bits;
+
+ LOG_MMU("Check SLBs\n");
+ slb = slb_lookup(env, eaddr);
+ if (!slb) {
+ return -5;
+ }
+
+ if (slb->vsid & SLB_VSID_B) {
+ vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
+ segment_bits = 40;
+ } else {
+ vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+ segment_bits = 28;
+ }
+
+ target_page_bits = (slb->vsid & SLB_VSID_L)
+ ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+ ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
+ : (slb->vsid & SLB_VSID_KS));
+ ctx->nx = !!(slb->vsid & SLB_VSID_N);
+
+ pageaddr = eaddr & ((1ULL << segment_bits)
+ - (1ULL << target_page_bits));
+ if (slb->vsid & SLB_VSID_B) {
+ hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
+ } else {
+ hash = vsid ^ (pageaddr >> target_page_bits);
+ }
+ /* Only 5 bits of the page index are used in the AVPN */
+ ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
+ ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
+
+ LOG_MMU("pte segment: key=%d nx %d vsid " TARGET_FMT_lx "\n",
+ ctx->key, ctx->nx, vsid);
+ ret = -1;
+
+ /* Check if instruction fetch is allowed, if needed */
+ if (type != ACCESS_CODE || ctx->nx == 0) {
+ /* Page address translation */
+ LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+ " hash " TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, hash);
+ ctx->hash[0] = hash;
+ ctx->hash[1] = ~hash;
+
+ /* Initialize real address with an invalid value */
+ ctx->raddr = (hwaddr)-1ULL;
+ LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, vsid, ctx->ptem,
+ ctx->hash[0]);
+ /* Primary table lookup */
+ ret = find_pte64(env, ctx, 0, rw, type, target_page_bits);
+ if (ret < 0) {
+ /* Secondary table lookup */
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+ ret2 = find_pte64(env, ctx, 1, rw, type, target_page_bits);
+ if (ret2 != -1) {
+ ret = ret2;
+ }
+ }
+ } else {
+ LOG_MMU("No access allowed\n");
+ ret = -3;
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 7b9713d..690c1d8 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -4,11 +4,10 @@
#ifndef CONFIG_USER_ONLY
#ifdef TARGET_PPC64
-ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr);
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
-int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
- int rw, int type, int target_page_bits);
+int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type);
#endif
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 1301391..db5c15a 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -507,87 +507,35 @@ hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size)
return (hash * pte_size * 8) & env->htab_mask;
}
-static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
- int type, int target_page_bits)
-{
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
- return find_pte64(env, ctx, h, rw, type, target_page_bits);
- }
-#endif
-
- return find_pte32(env, ctx, h, rw, type, target_page_bits);
-}
-
/* Perform segment based translation */
-static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int type)
+static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
{
hwaddr hash;
target_ulong vsid;
int ds, pr, target_page_bits;
- int ret, ret2;
+ int ret;
+ target_ulong sr, pgidx;
pr = msr_pr;
ctx->eaddr = eaddr;
-#if defined(TARGET_PPC64)
- if (env->mmu_model & POWERPC_MMU_64) {
- ppc_slb_t *slb;
- target_ulong pageaddr;
- int segment_bits;
-
- LOG_MMU("Check SLBs\n");
- slb = slb_lookup(env, eaddr);
- if (!slb) {
- return -5;
- }
-
- if (slb->vsid & SLB_VSID_B) {
- vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
- segment_bits = 40;
- } else {
- vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
- segment_bits = 28;
- }
-
- target_page_bits = (slb->vsid & SLB_VSID_L)
- ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
- ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
- : (slb->vsid & SLB_VSID_KS));
- ds = 0;
- ctx->nx = !!(slb->vsid & SLB_VSID_N);
- pageaddr = eaddr & ((1ULL << segment_bits)
- - (1ULL << target_page_bits));
- if (slb->vsid & SLB_VSID_B) {
- hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
- } else {
- hash = vsid ^ (pageaddr >> target_page_bits);
- }
- /* Only 5 bits of the page index are used in the AVPN */
- ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
- ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
- } else
-#endif /* defined(TARGET_PPC64) */
- {
- target_ulong sr, pgidx;
+ sr = env->sr[eaddr >> 28];
+ ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
+ ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
+ ds = sr & 0x80000000 ? 1 : 0;
+ ctx->nx = sr & 0x10000000 ? 1 : 0;
+ vsid = sr & 0x00FFFFFF;
+ target_page_bits = TARGET_PAGE_BITS;
+ LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
+ TARGET_FMT_lx " lr=" TARGET_FMT_lx
+ " ir=%d dr=%d pr=%d %d t=%d\n",
+ eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
+ (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+ pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+ hash = vsid ^ pgidx;
+ ctx->ptem = (vsid << 7) | (pgidx >> 10);
- sr = env->sr[eaddr >> 28];
- ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
- ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
- ds = sr & 0x80000000 ? 1 : 0;
- ctx->nx = sr & 0x10000000 ? 1 : 0;
- vsid = sr & 0x00FFFFFF;
- target_page_bits = TARGET_PAGE_BITS;
- LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
- TARGET_FMT_lx " lr=" TARGET_FMT_lx
- " ir=%d dr=%d pr=%d %d t=%d\n",
- eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
- (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
- pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
- hash = vsid ^ pgidx;
- ctx->ptem = (vsid << 7) | (pgidx >> 10);
- }
LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
ctx->key, ds, ctx->nx, vsid);
ret = -1;
@@ -603,31 +551,8 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
/* Initialize real address with an invalid value */
ctx->raddr = (hwaddr)-1ULL;
- if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
- env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
- /* Software TLB search */
- ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
- } else {
- LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ctx->ptem,
- ctx->hash[0]);
- /* Primary table lookup */
- ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
- if (ret < 0) {
- /* Secondary table lookup */
- LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte(env, ctx, 1, rw, type,
- target_page_bits);
- if (ret2 != -1) {
- ret = ret2;
- }
- }
- }
+ /* Software TLB search */
+ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
#if defined(DUMP_PAGE_TABLES)
if (qemu_log_enabled()) {
hwaddr curaddr;
@@ -1415,22 +1340,36 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
switch (env->mmu_model) {
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
+ /* Try to find a BAT */
+ if (env->nb_BATs != 0) {
+ ret = get_bat(env, ctx, eaddr, rw, access_type);
+ }
+ if (ret < 0) {
+ /* We didn't match any BAT entry or don't have BATs */
+ ret = get_segment32(env, ctx, eaddr, rw, access_type);
+ }
+ break;
+
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
/* Try to find a BAT */
if (env->nb_BATs != 0) {
ret = get_bat(env, ctx, eaddr, rw, access_type);
}
+ if (ret < 0) {
+ /* We didn't match any BAT entry or don't have BATs */
+ ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
+ }
+ break;
+
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
-#endif
- if (ret < 0) {
- /* We didn't match any BAT entry or don't have BATs */
- ret = get_segment(env, ctx, eaddr, rw, access_type);
- }
+ ret = get_segment64(env, ctx, eaddr, rw, access_type);
break;
+#endif
+
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
ret = mmu40x_get_physical_address(env, ctx, eaddr,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 08/48] target-ppc: Rework get_physical_address()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (6 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 07/48] target-ppc: Disentangle get_segment() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 09/48] target-ppc: Disentangle get_physical_address() paths David Gibson
` (40 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Currently get_physical_address() first checks to see if translation is
enabled in the MSR, then in the translation on case switches on the mmu
type. Except that for BookE MMUs, translation is always on, and so it
has to switch in the "translation off" case as well and do the same thing
as the translation on path for those MMUs. Plus, even translation off
doesn't behave exactly the same on the various MMU types so there are
further mmu type checks in the "translation off" path.
As a first step to cleaning this up, this patch moves the switch on mmu
type to the top level, then makes the translation on/off check just for
those mmu types where it is meaningful.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu_helper.c | 98 +++++++++++++++++++++++++----------------------
1 file changed, 52 insertions(+), 46 deletions(-)
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index db5c15a..5b82731 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1316,30 +1316,20 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int access_type)
{
- int ret;
+ int ret = -1;
+ bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
+ || (access_type != ACCESS_CODE && msr_dr == 0);
#if 0
qemu_log("%s\n", __func__);
#endif
- if ((access_type == ACCESS_CODE && msr_ir == 0) ||
- (access_type != ACCESS_CODE && msr_dr == 0)) {
- if (env->mmu_model == POWERPC_MMU_BOOKE) {
- /* The BookE MMU always performs address translation. The
- IS and DS bits only affect the address space. */
- ret = mmubooke_get_physical_address(env, ctx, eaddr,
- rw, access_type);
- } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
- ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
- access_type);
- } else {
- /* No address translation. */
+
+ switch (env->mmu_model) {
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+ if (real_mode) {
ret = check_physical(env, ctx, eaddr, rw);
- }
- } else {
- ret = -1;
- switch (env->mmu_model) {
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
+ } else {
/* Try to find a BAT */
if (env->nb_BATs != 0) {
ret = get_bat(env, ctx, eaddr, rw, access_type);
@@ -1348,10 +1338,14 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
/* We didn't match any BAT entry or don't have BATs */
ret = get_segment32(env, ctx, eaddr, rw, access_type);
}
- break;
+ }
+ break;
- case POWERPC_MMU_SOFT_6xx:
- case POWERPC_MMU_SOFT_74xx:
+ case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
+ if (real_mode) {
+ ret = check_physical(env, ctx, eaddr, rw);
+ } else {
/* Try to find a BAT */
if (env->nb_BATs != 0) {
ret = get_bat(env, ctx, eaddr, rw, access_type);
@@ -1360,40 +1354,52 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
/* We didn't match any BAT entry or don't have BATs */
ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
}
- break;
+ }
+ break;
#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
+ if (real_mode) {
+ ret = check_physical(env, ctx, eaddr, rw);
+ } else {
ret = get_segment64(env, ctx, eaddr, rw, access_type);
- break;
+ }
+ break;
#endif
- case POWERPC_MMU_SOFT_4xx:
- case POWERPC_MMU_SOFT_4xx_Z:
+ case POWERPC_MMU_SOFT_4xx:
+ case POWERPC_MMU_SOFT_4xx_Z:
+ if (real_mode) {
+ ret = check_physical(env, ctx, eaddr, rw);
+ } else {
ret = mmu40x_get_physical_address(env, ctx, eaddr,
rw, access_type);
- break;
- case POWERPC_MMU_BOOKE:
- ret = mmubooke_get_physical_address(env, ctx, eaddr,
- rw, access_type);
- break;
- case POWERPC_MMU_BOOKE206:
- ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
+ }
+ break;
+ case POWERPC_MMU_BOOKE:
+ ret = mmubooke_get_physical_address(env, ctx, eaddr,
+ rw, access_type);
+ break;
+ case POWERPC_MMU_BOOKE206:
+ ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
access_type);
- break;
- case POWERPC_MMU_MPC8xx:
- /* XXX: TODO */
- cpu_abort(env, "MPC8xx MMU model is not implemented\n");
- break;
- case POWERPC_MMU_REAL:
+ break;
+ case POWERPC_MMU_MPC8xx:
+ /* XXX: TODO */
+ cpu_abort(env, "MPC8xx MMU model is not implemented\n");
+ break;
+ case POWERPC_MMU_REAL:
+ if (real_mode) {
+ ret = check_physical(env, ctx, eaddr, rw);
+ } else {
cpu_abort(env, "PowerPC in real mode do not do any translation\n");
- return -1;
- default:
- cpu_abort(env, "Unknown or invalid MMU model\n");
- return -1;
}
+ return -1;
+ default:
+ cpu_abort(env, "Unknown or invalid MMU model\n");
+ return -1;
}
#if 0
qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 09/48] target-ppc: Disentangle get_physical_address() paths
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (7 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 08/48] target-ppc: Rework get_physical_address() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 10/48] target-ppc: Disentangle hash mmu paths for cpu_ppc_handle_mmu_fault David Gibson
` (39 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Depending on the MSR state, for 64-bit hash MMUs, get_physical_address
can either call check_physical (which has further tests for mmu type)
or get_segment64. Similarly for 32-bit hash MMUs we can either call
check_physucal or get_bat() and get_segment32().
This patch splits off the whole get_physical_addresss() path for hash
MMUs into 32-bit and 64-bit versions, handling real mode correctly for
such MMUs without going to check_physical and rechecking the mmu type.
Correspondingly, the hash MMU specific paths in check_physical() are
removed.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 2 ++
target-ppc/mmu-hash32.c | 29 +++++++++++++++++++++++++++--
target-ppc/mmu-hash32.h | 4 ++--
target-ppc/mmu-hash64.c | 19 +++++++++++++++++--
target-ppc/mmu-hash64.h | 4 ++--
target-ppc/mmu_helper.c | 46 ++++++++--------------------------------------
6 files changed, 58 insertions(+), 46 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index a9994cb..b76b09a 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1138,6 +1138,8 @@ int pp_check(int key, int pp, int nx);
int check_prot(int prot, int rw, int access_type);
int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, int ret, int rw);
hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size);
+int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 4bae72a..3998d63 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -158,8 +158,8 @@ static int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
return ret;
}
-int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int type)
+static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
{
hwaddr hash;
target_ulong vsid;
@@ -302,3 +302,28 @@ int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
+
+int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int access_type)
+{
+ bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
+ || (access_type != ACCESS_CODE && msr_dr == 0);
+
+ if (real_mode) {
+ ctx->raddr = eaddr;
+ ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
+ return 0;
+ } else {
+ int ret = -1;
+
+ /* Try to find a BAT */
+ if (env->nb_BATs != 0) {
+ ret = get_bat(env, ctx, eaddr, rw, access_type);
+ }
+ if (ret < 0) {
+ /* We didn't match any BAT entry or don't have BATs */
+ ret = get_segment32(env, ctx, eaddr, rw, access_type);
+ }
+ return ret;
+ }
+}
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 6f9a0c2..1318562 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -4,8 +4,8 @@
#ifndef CONFIG_USER_ONLY
int pte32_is_valid(target_ulong pte0);
-int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int type);
+int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int access_type);
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 23eb480..c727298 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -350,8 +350,8 @@ static int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
return ret;
}
-int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int type)
+static int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
{
hwaddr hash;
target_ulong vsid;
@@ -435,3 +435,18 @@ int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
+
+int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int access_type)
+{
+ bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
+ || (access_type != ACCESS_CODE && msr_dr == 0);
+
+ if (real_mode) {
+ ctx->raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
+ ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
+ return 0;
+ } else {
+ return get_segment64(env, ctx, eaddr, rw, access_type);
+ }
+}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 690c1d8..d8eb8de 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -6,8 +6,8 @@
#ifdef TARGET_PPC64
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
-int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int type);
+int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int access_type);
#endif
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 5b82731..ce39f49 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -426,8 +426,8 @@ static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
*protp = prot;
}
-static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong virtual, int rw, int type)
+int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong BEPIl, BEPIu, bl;
@@ -1256,8 +1256,6 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
ctx->prot = PAGE_READ | PAGE_EXEC;
ret = 0;
switch (env->mmu_model) {
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
case POWERPC_MMU_SOFT_4xx:
@@ -1265,15 +1263,7 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
case POWERPC_MMU_BOOKE:
ctx->prot |= PAGE_WRITE;
break;
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
- /* Real address are 60 bits long */
- ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
- ctx->prot |= PAGE_WRITE;
- break;
-#endif
+
case POWERPC_MMU_SOFT_4xx_Z:
if (unlikely(msr_pe != 0)) {
/* 403 family add some particular protections,
@@ -1298,15 +1288,10 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
}
}
break;
- case POWERPC_MMU_MPC8xx:
- /* XXX: TODO */
- cpu_abort(env, "MPC8xx MMU model is not implemented\n");
- break;
- case POWERPC_MMU_BOOKE206:
- cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
- break;
+
default:
- cpu_abort(env, "Unknown or invalid MMU model\n");
+ /* Caller's checks mean we should never get here for other models */
+ abort();
return -1;
}
@@ -1327,18 +1312,7 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
switch (env->mmu_model) {
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
- if (real_mode) {
- ret = check_physical(env, ctx, eaddr, rw);
- } else {
- /* Try to find a BAT */
- if (env->nb_BATs != 0) {
- ret = get_bat(env, ctx, eaddr, rw, access_type);
- }
- if (ret < 0) {
- /* We didn't match any BAT entry or don't have BATs */
- ret = get_segment32(env, ctx, eaddr, rw, access_type);
- }
- }
+ ret = ppc_hash32_get_physical_address(env, ctx, eaddr, rw, access_type);
break;
case POWERPC_MMU_SOFT_6xx:
@@ -1361,11 +1335,7 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
case POWERPC_MMU_2_06d:
- if (real_mode) {
- ret = check_physical(env, ctx, eaddr, rw);
- } else {
- ret = get_segment64(env, ctx, eaddr, rw, access_type);
- }
+ ret = ppc_hash64_get_physical_address(env, ctx, eaddr, rw, access_type);
break;
#endif
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 10/48] target-ppc: Disentangle hash mmu paths for cpu_ppc_handle_mmu_fault
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (8 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 09/48] target-ppc: Disentangle get_physical_address() paths David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 11/48] target-ppc: Disentangle hash mmu versions of cpu_get_phys_page_debug() David Gibson
` (38 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
cpu_ppc_handle_mmu_fault() calls get_physical_address() (whose behaviour
depends on MMU type) then, if that fails, issues an appropriate exception
- which again has a number of dependencies on MMU type.
This patch starts converting cpu_ppc_handle_mmu_fault() to have a
single switch on MMU type, calling MMU specific fault handler
functions which deal with both translation and exception delivery
appropriately for the MMU type. We convert 32-bit and 64-bit hash
MMUs to this new model, but the existing code is left in place for
other MMU types for now.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++
target-ppc/mmu-hash32.h | 2 +
target-ppc/mmu-hash64.c | 87 +++++++++++++++++++++++++++++++++
target-ppc/mmu-hash64.h | 2 +
target-ppc/mmu_helper.c | 57 ++++++----------------
5 files changed, 231 insertions(+), 41 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 3998d63..50f8c54 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -303,6 +303,7 @@ static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
+
int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int access_type)
{
@@ -327,3 +328,126 @@ int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
}
+
+int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ mmu_ctx_t ctx;
+ int access_type;
+ int ret = 0;
+
+ if (rw == 2) {
+ /* code access */
+ rw = 0;
+ access_type = ACCESS_CODE;
+ } else {
+ /* data access */
+ access_type = env->access_type;
+ }
+ ret = ppc_hash32_get_physical_address(env, &ctx, address, rw, access_type);
+ if (ret == 0) {
+ tlb_set_page(env, address & TARGET_PAGE_MASK,
+ ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+ mmu_idx, TARGET_PAGE_SIZE);
+ ret = 0;
+ } else if (ret < 0) {
+ LOG_MMU_STATE(env);
+ if (access_type == ACCESS_CODE) {
+ switch (ret) {
+ case -1:
+ /* No matches in page tables or TLB */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x40000000;
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x08000000;
+ break;
+ case -3:
+ /* No execute protection violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ break;
+ case -4:
+ /* Direct store exception */
+ /* No code fetch is allowed in direct-store areas */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case -1:
+ /* No matches in page tables or TLB */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x42000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x40000000;
+ }
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x0A000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ break;
+ case -4:
+ /* Direct store exception */
+ switch (access_type) {
+ case ACCESS_FLOAT:
+ /* Floating point load/store */
+ env->exception_index = POWERPC_EXCP_ALIGN;
+ env->error_code = POWERPC_EXCP_ALIGN_FP;
+ env->spr[SPR_DAR] = address;
+ break;
+ case ACCESS_RES:
+ /* lwarx, ldarx or stwcx. */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x06000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x04000000;
+ }
+ break;
+ case ACCESS_EXT:
+ /* eciwx or ecowx */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x06100000;
+ } else {
+ env->spr[SPR_DSISR] = 0x04100000;
+ }
+ break;
+ default:
+ printf("DSI: invalid exception (%d)\n", ret);
+ env->exception_index = POWERPC_EXCP_PROGRAM;
+ env->error_code =
+ POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
+ env->spr[SPR_DAR] = address;
+ break;
+ }
+ break;
+ }
+ }
+#if 0
+ printf("%s: set exception to %d %02x\n", __func__,
+ env->exception, env->error_code);
+#endif
+ ret = 1;
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 1318562..8f1f2a9 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -6,6 +6,8 @@
int pte32_is_valid(target_ulong pte0);
int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int access_type);
+int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx);
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index c727298..32825ff 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -450,3 +450,90 @@ int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
return get_segment64(env, ctx, eaddr, rw, access_type);
}
}
+
+int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ mmu_ctx_t ctx;
+ int access_type;
+ int ret = 0;
+
+ if (rw == 2) {
+ /* code access */
+ rw = 0;
+ access_type = ACCESS_CODE;
+ } else {
+ /* data access */
+ access_type = env->access_type;
+ }
+ ret = ppc_hash64_get_physical_address(env, &ctx, address, rw, access_type);
+ if (ret == 0) {
+ tlb_set_page(env, address & TARGET_PAGE_MASK,
+ ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+ mmu_idx, TARGET_PAGE_SIZE);
+ ret = 0;
+ } else if (ret < 0) {
+ LOG_MMU_STATE(env);
+ if (access_type == ACCESS_CODE) {
+ switch (ret) {
+ case -1:
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x40000000;
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x08000000;
+ break;
+ case -3:
+ /* No execute protection violation */
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ break;
+ case -5:
+ /* No match in segment table */
+ env->exception_index = POWERPC_EXCP_ISEG;
+ env->error_code = 0;
+ break;
+ }
+ } else {
+ switch (ret) {
+ case -1:
+ /* No matches in page tables or TLB */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x42000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x40000000;
+ }
+ break;
+ case -2:
+ /* Access rights violation */
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ if (rw == 1) {
+ env->spr[SPR_DSISR] = 0x0A000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ break;
+ case -5:
+ /* No match in segment table */
+ env->exception_index = POWERPC_EXCP_DSEG;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = address;
+ break;
+ }
+ }
+#if 0
+ printf("%s: set exception to %d %02x\n", __func__,
+ env->exception, env->error_code);
+#endif
+ ret = 1;
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index d8eb8de..3a53e61 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -8,6 +8,8 @@ void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int access_type);
+int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx);
#endif
#endif /* CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index ce39f49..287334f 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1438,6 +1438,22 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int access_type;
int ret = 0;
+ switch (env->mmu_model) {
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
+ return ppc_hash64_handle_mmu_fault(env, address, rw, mmu_idx);
+#endif
+
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+ return ppc_hash32_handle_mmu_fault(env, address, rw, mmu_idx);
+
+ default:
+ ; /* Otherwise fall through to the general code below */
+ }
+
if (rw == 2) {
/* code access */
rw = 0;
@@ -1475,16 +1491,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->spr[SPR_40x_DEAR] = address;
env->spr[SPR_40x_ESR] = 0x00000000;
break;
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
-#endif
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x40000000;
- break;
case POWERPC_MMU_BOOKE206:
booke206_update_mas_tlb_miss(env, address, rw);
/* fall through */
@@ -1526,13 +1532,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000;
break;
-#if defined(TARGET_PPC64)
- case -5:
- /* No match in segment table */
- env->exception_index = POWERPC_EXCP_ISEG;
- env->error_code = 0;
- break;
-#endif
}
} else {
switch (ret) {
@@ -1580,22 +1579,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->spr[SPR_40x_ESR] = 0x00000000;
}
break;
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
-#endif
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rw == 1) {
- env->spr[SPR_DSISR] = 0x42000000;
- } else {
- env->spr[SPR_DSISR] = 0x40000000;
- }
- break;
case POWERPC_MMU_MPC8xx:
/* XXX: TODO */
cpu_abort(env, "MPC8xx MMU model is not implemented\n");
@@ -1681,14 +1664,6 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
break;
}
break;
-#if defined(TARGET_PPC64)
- case -5:
- /* No match in segment table */
- env->exception_index = POWERPC_EXCP_DSEG;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- break;
-#endif
}
}
#if 0
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 11/48] target-ppc: Disentangle hash mmu versions of cpu_get_phys_page_debug()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (9 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 10/48] target-ppc: Disentangle hash mmu paths for cpu_ppc_handle_mmu_fault David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 12/48] target-ppc: Disentangle hash mmu helper functions David Gibson
` (37 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
cpu_get_phys_page_debug() is a trivial wrapper around
get_physical_address(). But even the signature of
get_physical_address() has some things we'd like to clean up on a
per-mmu basis, so this patch moves the test on mmu model out to
cpu_get_phys_page_debug(), moving the version for 64-bit hash MMUs out
to mmu-hash64.c and the version for 32-bit hash MMUs to mmu-hash32.c
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 17 +++++++++++++++--
target-ppc/mmu-hash32.h | 3 +--
target-ppc/mmu-hash64.c | 17 +++++++++++++++--
target-ppc/mmu-hash64.h | 3 +--
target-ppc/mmu_helper.c | 29 ++++++++++++++++-------------
5 files changed, 48 insertions(+), 21 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 50f8c54..c0e5742 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -304,8 +304,9 @@ static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
}
-int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type)
+static int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw,
+ int access_type)
{
bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
|| (access_type != ACCESS_CODE && msr_dr == 0);
@@ -329,6 +330,18 @@ int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
}
}
+hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
+{
+ mmu_ctx_t ctx;
+
+ if (unlikely(ppc_hash32_get_physical_address(env, &ctx, addr, 0, ACCESS_INT)
+ != 0)) {
+ return -1;
+ }
+
+ return ctx.raddr & TARGET_PAGE_MASK;
+}
+
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx)
{
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 8f1f2a9..8f10e0d 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -4,8 +4,7 @@
#ifndef CONFIG_USER_ONLY
int pte32_is_valid(target_ulong pte0);
-int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type);
+hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 32825ff..427b095 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -436,8 +436,9 @@ static int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type)
+static int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw,
+ int access_type)
{
bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
|| (access_type != ACCESS_CODE && msr_dr == 0);
@@ -451,6 +452,18 @@ int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
}
}
+hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
+{
+ mmu_ctx_t ctx;
+
+ if (unlikely(ppc_hash64_get_physical_address(env, &ctx, addr, 0, ACCESS_INT)
+ != 0)) {
+ return -1;
+ }
+
+ return ctx.raddr & TARGET_PAGE_MASK;
+}
+
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx)
{
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 3a53e61..665d3b0 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -6,8 +6,7 @@
#ifdef TARGET_PPC64
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
-int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type);
+hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
#endif
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 287334f..818f1b5 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1310,11 +1310,6 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
#endif
switch (env->mmu_model) {
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
- ret = ppc_hash32_get_physical_address(env, ctx, eaddr, rw, access_type);
- break;
-
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
if (real_mode) {
@@ -1331,14 +1326,6 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
}
break;
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
- ret = ppc_hash64_get_physical_address(env, ctx, eaddr, rw, access_type);
- break;
-#endif
-
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
if (real_mode) {
@@ -1383,6 +1370,22 @@ hwaddr cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
mmu_ctx_t ctx;
+ switch (env->mmu_model) {
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06d:
+ return ppc_hash64_get_phys_page_debug(env, addr);
+#endif
+
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+ return ppc_hash32_get_phys_page_debug(env, addr);
+
+ default:
+ ;
+ }
+
if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
return -1;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 12/48] target-ppc: Disentangle hash mmu helper functions
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (10 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 11/48] target-ppc: Disentangle hash mmu versions of cpu_get_phys_page_debug() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 13/48] target-ppc: Don't share get_pteg_offset() between 32 and 64-bit David Gibson
` (36 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
The newly separated paths for hash mmus rely on several helper functions
which are still shared with 32-bit hash mmus: pp_check(), check_prot() and
pte_update_flags(). While these don't have ugly ifdefs on the mmu type,
they're not very well thought out, so sharing them impedes cleaning up the
hash mmu paths. For now, put near-duplicate versions into mmu-hash64.c and
mmu-hash32.c, leaving the old version in mmu_helper.c for 6xx software
loaded tlb implementations. The hash 32 and software loaded
implementations are simplfied slightly, using the fact that no 32-bit CPUs
implement the 3rd page protection bit.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 3 --
target-ppc/mmu-hash32.c | 96 +++++++++++++++++++++++++++++++++++++++++++--
target-ppc/mmu-hash64.c | 99 +++++++++++++++++++++++++++++++++++++++++++++--
target-ppc/mmu_helper.c | 11 ++----
4 files changed, 193 insertions(+), 16 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index b76b09a..c9ea3a4 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1134,9 +1134,6 @@ void ppc_hw_interrupt (CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
-int pp_check(int key, int pp, int nx);
-int check_prot(int prot, int rw, int access_type);
-int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p, int ret, int rw);
hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size);
int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong virtual, int rw, int type);
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index c0e5742..4b7598b 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -37,6 +37,71 @@
#define PTE_PTEM_MASK 0x7FFFFFBF
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+static int ppc_hash32_pp_check(int key, int pp, int nx)
+{
+ int access;
+
+ /* Compute access rights */
+ access = 0;
+ if (key == 0) {
+ switch (pp) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ access |= PAGE_WRITE;
+ /* No break here */
+ case 0x3:
+ access |= PAGE_READ;
+ break;
+ }
+ } else {
+ switch (pp) {
+ case 0x0:
+ access = 0;
+ break;
+ case 0x1:
+ case 0x3:
+ access = PAGE_READ;
+ break;
+ case 0x2:
+ access = PAGE_READ | PAGE_WRITE;
+ break;
+ }
+ }
+ if (nx == 0) {
+ access |= PAGE_EXEC;
+ }
+
+ return access;
+}
+
+static int ppc_hash32_check_prot(int prot, int rw, int access_type)
+{
+ int ret;
+
+ if (access_type == ACCESS_CODE) {
+ if (prot & PAGE_EXEC) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ } else if (rw) {
+ if (prot & PAGE_WRITE) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ } else {
+ if (prot & PAGE_READ) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ }
+
+ return ret;
+}
+
static inline int pte_is_valid_hash32(target_ulong pte0)
{
return pte0 & 0x80000000 ? 1 : 0;
@@ -66,11 +131,11 @@ static int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
}
}
/* Compute access rights */
- access = pp_check(ctx->key, pp, ctx->nx);
+ access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
/* Keep the matching PTE informations */
ctx->raddr = pte1;
ctx->prot = access;
- ret = check_prot(ctx->prot, rw, type);
+ ret = ppc_hash32_check_prot(ctx->prot, rw, type);
if (ret == 0) {
/* Access granted */
LOG_MMU("PTE access granted !\n");
@@ -84,6 +149,31 @@ static int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
return ret;
}
+static int ppc_hash32_pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
+ int ret, int rw)
+{
+ int store = 0;
+
+ /* Update page flags */
+ if (!(*pte1p & 0x00000100)) {
+ /* Update accessed flag */
+ *pte1p |= 0x00000100;
+ store = 1;
+ }
+ if (!(*pte1p & 0x00000080)) {
+ if (rw == 1 && ret == 0) {
+ /* Update changed flag */
+ *pte1p |= 0x00000080;
+ store = 1;
+ } else {
+ /* Force page fault for first write access */
+ ctx->prot &= ~PAGE_WRITE;
+ }
+ }
+
+ return store;
+}
+
/* PTE table lookup */
static int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
int rw, int type, int target_page_bits)
@@ -138,7 +228,7 @@ static int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
ctx->raddr, ctx->prot, ret);
/* Update page flags */
pte1 = ctx->raddr;
- if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+ if (ppc_hash32_pte_update_flags(ctx, &pte1, ret, rw) == 1) {
if (env->external_htab) {
stl_p(env->external_htab + pteg_off + (good * 8) + 4,
pte1);
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 427b095..f9c5b09 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -226,6 +226,74 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
+static int ppc_hash64_pp_check(int key, int pp, int nx)
+{
+ int access;
+
+ /* Compute access rights */
+ /* When pp is 4, 5 or 7, the result is undefined. Set it to noaccess */
+ access = 0;
+ if (key == 0) {
+ switch (pp) {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ access |= PAGE_WRITE;
+ /* No break here */
+ case 0x3:
+ case 0x6:
+ access |= PAGE_READ;
+ break;
+ }
+ } else {
+ switch (pp) {
+ case 0x0:
+ case 0x6:
+ access = 0;
+ break;
+ case 0x1:
+ case 0x3:
+ access = PAGE_READ;
+ break;
+ case 0x2:
+ access = PAGE_READ | PAGE_WRITE;
+ break;
+ }
+ }
+ if (nx == 0) {
+ access |= PAGE_EXEC;
+ }
+
+ return access;
+}
+
+static int ppc_hash64_check_prot(int prot, int rw, int access_type)
+{
+ int ret;
+
+ if (access_type == ACCESS_CODE) {
+ if (prot & PAGE_EXEC) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ } else if (rw) {
+ if (prot & PAGE_WRITE) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ } else {
+ if (prot & PAGE_READ) {
+ ret = 0;
+ } else {
+ ret = -2;
+ }
+ }
+
+ return ret;
+}
+
static inline int pte64_is_valid(target_ulong pte0)
{
return pte0 & 0x0000000000000001ULL ? 1 : 0;
@@ -257,11 +325,11 @@ static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
}
}
/* Compute access rights */
- access = pp_check(ctx->key, pp, ctx->nx);
+ access = ppc_hash64_pp_check(ctx->key, pp, ctx->nx);
/* Keep the matching PTE informations */
ctx->raddr = pte1;
ctx->prot = access;
- ret = check_prot(ctx->prot, rw, type);
+ ret = ppc_hash64_check_prot(ctx->prot, rw, type);
if (ret == 0) {
/* Access granted */
LOG_MMU("PTE access granted !\n");
@@ -275,6 +343,31 @@ static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
return ret;
}
+static int ppc_hash64_pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
+ int ret, int rw)
+{
+ int store = 0;
+
+ /* Update page flags */
+ if (!(*pte1p & 0x00000100)) {
+ /* Update accessed flag */
+ *pte1p |= 0x00000100;
+ store = 1;
+ }
+ if (!(*pte1p & 0x00000080)) {
+ if (rw == 1 && ret == 0) {
+ /* Update changed flag */
+ *pte1p |= 0x00000080;
+ store = 1;
+ } else {
+ /* Force page fault for first write access */
+ ctx->prot &= ~PAGE_WRITE;
+ }
+ }
+
+ return store;
+}
+
/* PTE table lookup */
static int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
int rw, int type, int target_page_bits)
@@ -330,7 +423,7 @@ static int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
ctx->raddr, ctx->prot, ret);
/* Update page flags */
pte1 = ctx->raddr;
- if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+ if (ppc_hash64_pte_update_flags(ctx, &pte1, ret, rw) == 1) {
if (env->external_htab) {
stq_p(env->external_htab + pteg_off + (good * 16) + 8,
pte1);
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 818f1b5..2deb635 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -91,12 +91,11 @@ static inline void pte_invalidate(target_ulong *pte0)
#define PTE_PTEM_MASK 0x7FFFFFBF
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
-int pp_check(int key, int pp, int nx)
+static int pp_check(int key, int pp, int nx)
{
int access;
/* Compute access rights */
- /* When pp is 3/7, the result is undefined. Set it to noaccess */
access = 0;
if (key == 0) {
switch (pp) {
@@ -106,14 +105,12 @@ int pp_check(int key, int pp, int nx)
access |= PAGE_WRITE;
/* No break here */
case 0x3:
- case 0x6:
access |= PAGE_READ;
break;
}
} else {
switch (pp) {
case 0x0:
- case 0x6:
access = 0;
break;
case 0x1:
@@ -132,7 +129,7 @@ int pp_check(int key, int pp, int nx)
return access;
}
-int check_prot(int prot, int rw, int access_type)
+static int check_prot(int prot, int rw, int access_type)
{
int ret;
@@ -201,8 +198,8 @@ static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
return ret;
}
-int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
- int ret, int rw)
+static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
+ int ret, int rw)
{
int store = 0;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 13/48] target-ppc: Don't share get_pteg_offset() between 32 and 64-bit
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (11 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 12/48] target-ppc: Disentangle hash mmu helper functions David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 14/48] target-ppc: Disentangle BAT code for 32-bit hash MMUs David Gibson
` (35 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
The get_pteg_offset() helper function is currently shared between 32-bit
and 64-bit hash mmus, taking a parameter for the hash pte size. In the
64-bit paths, it's only called in one place, and it's a trivial
calculation. This patch, therefore, open codes it for 64-bit. The
remaining version, which is used in two places is made 32-bit only and
moved to mmu-hash32.c.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 1 -
target-ppc/mmu-hash32.c | 7 ++++++-
target-ppc/mmu-hash32.h | 2 +-
target-ppc/mmu-hash64.c | 2 +-
target-ppc/mmu_helper.c | 9 ++-------
5 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index c9ea3a4..54e1dbc 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1134,7 +1134,6 @@ void ppc_hw_interrupt (CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
-hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size);
int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong virtual, int rw, int type);
#endif /* !defined(CONFIG_USER_ONLY) */
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 4b7598b..0ccaf7c 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -174,6 +174,11 @@ static int ppc_hash32_pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
return store;
}
+hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
+{
+ return (hash * HASH_PTE_SIZE_32 * 8) & env->htab_mask;
+}
+
/* PTE table lookup */
static int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
int rw, int type, int target_page_bits)
@@ -184,7 +189,7 @@ static int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
int ret, r;
ret = -1; /* No entry found */
- pteg_off = get_pteg_offset(env, ctx->hash[h], HASH_PTE_SIZE_32);
+ pteg_off = get_pteg_offset32(env, ctx->hash[h]);
for (i = 0; i < 8; i++) {
if (env->external_htab) {
pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 8f10e0d..3435aa5 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -3,7 +3,7 @@
#ifndef CONFIG_USER_ONLY
-int pte32_is_valid(target_ulong pte0);
+hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash);
hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index f9c5b09..7134616 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -378,7 +378,7 @@ static int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
int ret, r;
ret = -1; /* No entry found */
- pteg_off = get_pteg_offset(env, ctx->hash[h], HASH_PTE_SIZE_64);
+ pteg_off = (ctx->hash[h] * HASH_PTE_SIZE_64 * 8) & env->htab_mask;
for (i = 0; i < 8; i++) {
if (env->external_htab) {
pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 2deb635..50ec0ac 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -499,11 +499,6 @@ int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size)
-{
- return (hash * pte_size * 8) & env->htab_mask;
-}
-
/* Perform segment based translation */
static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw, int type)
@@ -1551,9 +1546,9 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
tlb_miss:
env->error_code |= ctx.key << 19;
env->spr[SPR_HASH1] = env->htab_base +
- get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
+ get_pteg_offset32(env, ctx.hash[0]);
env->spr[SPR_HASH2] = env->htab_base +
- get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
+ get_pteg_offset32(env, ctx.hash[1]);
break;
case POWERPC_MMU_SOFT_74xx:
if (rw == 1) {
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 14/48] target-ppc: Disentangle BAT code for 32-bit hash MMUs
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (12 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 13/48] target-ppc: Don't share get_pteg_offset() between 32 and 64-bit David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 15/48] target-ppc: mmu_ctx_t should not be a global type David Gibson
` (34 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
The functions for looking up BATs (Block Address Translation - essentially
a level 0 TLB) are shared between the classic 32-bit hash MMUs and the
6xx style software loaded TLB implementations.
This patch splits out a copy for the 32-bit hash MMUs, to facilitate
cleaning it up. The remaining version is left, but cleaned up slightly
to no longer deal with PowerPC 601 peculiarities (601 has a hash MMU).
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 2 -
target-ppc/mmu-hash32.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++-
target-ppc/mmu_helper.c | 38 ++-----------
3 files changed, 142 insertions(+), 38 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 54e1dbc..74b6e0e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1134,8 +1134,6 @@ void ppc_hw_interrupt (CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
-int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong virtual, int rw, int type);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr (CPUPPCState *env, target_ulong value);
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 0ccaf7c..f94b65d 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -25,6 +25,7 @@
#include "mmu-hash32.h"
//#define DEBUG_MMU
+//#define DEBUG_BAT
#ifdef DEBUG_MMU
# define LOG_MMU(...) qemu_log(__VA_ARGS__)
@@ -34,6 +35,12 @@
# define LOG_MMU_STATE(...) do { } while (0)
#endif
+#ifdef DEBUG_BATS
+# define LOG_BATS(...) qemu_log(__VA_ARGS__)
+#else
+# define LOG_BATS(...) do { } while (0)
+#endif
+
#define PTE_PTEM_MASK 0x7FFFFFBF
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
@@ -102,6 +109,136 @@ static int ppc_hash32_check_prot(int prot, int rw, int access_type)
return ret;
}
+/* Perform BAT hit & translation */
+static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp,
+ int *validp, int *protp, target_ulong *BATu,
+ target_ulong *BATl)
+{
+ target_ulong bl;
+ int pp, valid, prot;
+
+ bl = (*BATu & 0x00001FFC) << 15;
+ valid = 0;
+ prot = 0;
+ if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
+ ((msr_pr != 0) && (*BATu & 0x00000001))) {
+ valid = 1;
+ pp = *BATl & 0x00000003;
+ if (pp != 0) {
+ prot = PAGE_READ | PAGE_EXEC;
+ if (pp == 0x2) {
+ prot |= PAGE_WRITE;
+ }
+ }
+ }
+ *blp = bl;
+ *validp = valid;
+ *protp = prot;
+}
+
+static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
+ int *validp, int *protp,
+ target_ulong *BATu, target_ulong *BATl)
+{
+ target_ulong bl;
+ int key, pp, valid, prot;
+
+ bl = (*BATl & 0x0000003F) << 17;
+ LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
+ (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
+ prot = 0;
+ valid = (*BATl >> 6) & 1;
+ if (valid) {
+ pp = *BATu & 0x00000003;
+ if (msr_pr == 0) {
+ key = (*BATu >> 3) & 1;
+ } else {
+ key = (*BATu >> 2) & 1;
+ }
+ prot = ppc_hash32_pp_check(key, pp, 0);
+ }
+ *blp = bl;
+ *validp = valid;
+ *protp = prot;
+}
+
+static int ppc_hash32_get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type)
+{
+ target_ulong *BATlt, *BATut, *BATu, *BATl;
+ target_ulong BEPIl, BEPIu, bl;
+ int i, valid, prot;
+ int ret = -1;
+
+ LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
+ type == ACCESS_CODE ? 'I' : 'D', virtual);
+ switch (type) {
+ case ACCESS_CODE:
+ BATlt = env->IBAT[1];
+ BATut = env->IBAT[0];
+ break;
+ default:
+ BATlt = env->DBAT[1];
+ BATut = env->DBAT[0];
+ break;
+ }
+ for (i = 0; i < env->nb_BATs; i++) {
+ BATu = &BATut[i];
+ BATl = &BATlt[i];
+ BEPIu = *BATu & 0xF0000000;
+ BEPIl = *BATu & 0x0FFE0000;
+ if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
+ hash32_bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ } else {
+ hash32_bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ }
+ LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
+ " BATl " TARGET_FMT_lx "\n", __func__,
+ type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
+ if ((virtual & 0xF0000000) == BEPIu &&
+ ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
+ /* BAT matches */
+ if (valid != 0) {
+ /* Get physical address */
+ ctx->raddr = (*BATl & 0xF0000000) |
+ ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
+ (virtual & 0x0001F000);
+ /* Compute access rights */
+ ctx->prot = prot;
+ ret = ppc_hash32_check_prot(ctx->prot, rw, type);
+ if (ret == 0) {
+ LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
+ i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
+ ctx->prot & PAGE_WRITE ? 'W' : '-');
+ }
+ break;
+ }
+ }
+ }
+ if (ret < 0) {
+#if defined(DEBUG_BATS)
+ if (qemu_log_enabled()) {
+ LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
+ for (i = 0; i < 4; i++) {
+ BATu = &BATut[i];
+ BATl = &BATlt[i];
+ BEPIu = *BATu & 0xF0000000;
+ BEPIl = *BATu & 0x0FFE0000;
+ bl = (*BATu & 0x00001FFC) << 15;
+ LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
+ " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
+ TARGET_FMT_lx " " TARGET_FMT_lx "\n",
+ __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
+ *BATu, *BATl, BEPIu, BEPIl, bl);
+ }
+ }
+#endif
+ }
+ /* No hit */
+ return ret;
+}
+
+
static inline int pte_is_valid_hash32(target_ulong pte0)
{
return pte0 & 0x80000000 ? 1 : 0;
@@ -398,7 +535,6 @@ static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-
static int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
target_ulong eaddr, int rw,
int access_type)
@@ -415,7 +551,7 @@ static int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
/* Try to find a BAT */
if (env->nb_BATs != 0) {
- ret = get_bat(env, ctx, eaddr, rw, access_type);
+ ret = ppc_hash32_get_bat(env, ctx, eaddr, rw, access_type);
}
if (ret < 0) {
/* We didn't match any BAT entry or don't have BATs */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 50ec0ac..9471d59 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -397,34 +397,8 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
*protp = prot;
}
-static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
- int *validp, int *protp,
- target_ulong *BATu, target_ulong *BATl)
-{
- target_ulong bl;
- int key, pp, valid, prot;
-
- bl = (*BATl & 0x0000003F) << 17;
- LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
- (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
- prot = 0;
- valid = (*BATl >> 6) & 1;
- if (valid) {
- pp = *BATu & 0x00000003;
- if (msr_pr == 0) {
- key = (*BATu >> 3) & 1;
- } else {
- key = (*BATu >> 2) & 1;
- }
- prot = pp_check(key, pp, 0);
- }
- *blp = bl;
- *validp = valid;
- *protp = prot;
-}
-
-int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong virtual, int rw, int type)
+static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong BEPIl, BEPIu, bl;
@@ -448,11 +422,7 @@ int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
BATl = &BATlt[i];
BEPIu = *BATu & 0xF0000000;
BEPIl = *BATu & 0x0FFE0000;
- if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
- bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
- } else {
- bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
- }
+ bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
@@ -1309,7 +1279,7 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
} else {
/* Try to find a BAT */
if (env->nb_BATs != 0) {
- ret = get_bat(env, ctx, eaddr, rw, access_type);
+ ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
}
if (ret < 0) {
/* We didn't match any BAT entry or don't have BATs */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 15/48] target-ppc: mmu_ctx_t should not be a global type
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (13 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 14/48] target-ppc: Disentangle BAT code for 32-bit hash MMUs David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 16/48] mmu-hash*: Add header file for definitions David Gibson
` (33 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
mmu_ctx_t is currently defined in cpu.h. However it is used for temporary
information relating to mmu translation, and is only used in mmu_helper.c
and (now) mmu-hash{32,64}.c. Furthermore it contains information which
should be specific to particular MMU types. Therefore, move its definition
to mmu_helper.c. mmu-hash{32,64}.c are converted to use new data types
private to the relevant MMUs (identical to mmu_ctx_t for now, but that will
change in future patches).
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 14 --------------
target-ppc/mmu-hash32.c | 26 ++++++++++++++++++--------
target-ppc/mmu-hash64.c | 26 +++++++++++++++++++-------
target-ppc/mmu_helper.c | 13 +++++++++++++
4 files changed, 50 insertions(+), 29 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 74b6e0e..035d939 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1101,20 +1101,6 @@ do { \
env->wdt_period[3] = (d_); \
} while (0)
-#if !defined(CONFIG_USER_ONLY)
-/* Context used internally during MMU translations */
-typedef struct mmu_ctx_t mmu_ctx_t;
-struct mmu_ctx_t {
- hwaddr raddr; /* Real address */
- hwaddr eaddr; /* Effective address */
- int prot; /* Protection bits */
- hwaddr hash[2]; /* Pagetable hash values */
- target_ulong ptem; /* Virtual segment ID | API */
- int key; /* Access key */
- int nx; /* Non-execute area */
-};
-#endif
-
#include "cpu-qom.h"
/*****************************************************************************/
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index f94b65d..5b48aa8 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -41,6 +41,16 @@
# define LOG_BATS(...) do { } while (0)
#endif
+struct mmu_ctx_hash32 {
+ hwaddr raddr; /* Real address */
+ hwaddr eaddr; /* Effective address */
+ int prot; /* Protection bits */
+ hwaddr hash[2]; /* Pagetable hash values */
+ target_ulong ptem; /* Virtual segment ID | API */
+ int key; /* Access key */
+ int nx; /* Non-execute area */
+};
+
#define PTE_PTEM_MASK 0x7FFFFFBF
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
@@ -162,7 +172,7 @@ static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
*protp = prot;
}
-static int ppc_hash32_get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
+static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong virtual, int rw, int type)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
@@ -244,7 +254,7 @@ static inline int pte_is_valid_hash32(target_ulong pte0)
return pte0 & 0x80000000 ? 1 : 0;
}
-static int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
+static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
target_ulong pte1, int h, int rw, int type)
{
target_ulong ptem, mmask;
@@ -286,7 +296,7 @@ static int pte_check_hash32(mmu_ctx_t *ctx, target_ulong pte0,
return ret;
}
-static int ppc_hash32_pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
+static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong *pte1p,
int ret, int rw)
{
int store = 0;
@@ -317,7 +327,7 @@ hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
}
/* PTE table lookup */
-static int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
int rw, int type, int target_page_bits)
{
hwaddr pteg_off;
@@ -390,7 +400,7 @@ static int find_pte32(CPUPPCState *env, mmu_ctx_t *ctx, int h,
return ret;
}
-static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
+static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong eaddr, int rw, int type)
{
hwaddr hash;
@@ -535,7 +545,7 @@ static int get_segment32(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-static int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+static int ppc_hash32_get_physical_address(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong eaddr, int rw,
int access_type)
{
@@ -563,7 +573,7 @@ static int ppc_hash32_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
- mmu_ctx_t ctx;
+ struct mmu_ctx_hash32 ctx;
if (unlikely(ppc_hash32_get_physical_address(env, &ctx, addr, 0, ACCESS_INT)
!= 0)) {
@@ -576,7 +586,7 @@ hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx)
{
- mmu_ctx_t ctx;
+ struct mmu_ctx_hash32 ctx;
int access_type;
int ret = 0;
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 7134616..3008be8 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -40,6 +40,16 @@
# define LOG_SLB(...) do { } while (0)
#endif
+struct mmu_ctx_hash64 {
+ hwaddr raddr; /* Real address */
+ hwaddr eaddr; /* Effective address */
+ int prot; /* Protection bits */
+ hwaddr hash[2]; /* Pagetable hash values */
+ target_ulong ptem; /* Virtual segment ID | API */
+ int key; /* Access key */
+ int nx; /* Non-execute area */
+};
+
/*
* SLB handling
*/
@@ -299,7 +309,7 @@ static inline int pte64_is_valid(target_ulong pte0)
return pte0 & 0x0000000000000001ULL ? 1 : 0;
}
-static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
+static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
target_ulong pte1, int h, int rw, int type)
{
target_ulong ptem, mmask;
@@ -343,7 +353,8 @@ static int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
return ret;
}
-static int ppc_hash64_pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
+static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
+ target_ulong *pte1p,
int ret, int rw)
{
int store = 0;
@@ -369,7 +380,7 @@ static int ppc_hash64_pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
}
/* PTE table lookup */
-static int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
+static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
int rw, int type, int target_page_bits)
{
hwaddr pteg_off;
@@ -443,7 +454,7 @@ static int find_pte64(CPUPPCState *env, mmu_ctx_t *ctx, int h,
return ret;
}
-static int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
+static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
target_ulong eaddr, int rw, int type)
{
hwaddr hash;
@@ -529,7 +540,8 @@ static int get_segment64(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-static int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+static int ppc_hash64_get_physical_address(CPUPPCState *env,
+ struct mmu_ctx_hash64 *ctx,
target_ulong eaddr, int rw,
int access_type)
{
@@ -547,7 +559,7 @@ static int ppc_hash64_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
- mmu_ctx_t ctx;
+ struct mmu_ctx_hash64 ctx;
if (unlikely(ppc_hash64_get_physical_address(env, &ctx, addr, 0, ACCESS_INT)
!= 0)) {
@@ -560,7 +572,7 @@ hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx)
{
- mmu_ctx_t ctx;
+ struct mmu_ctx_hash64 ctx;
int access_type;
int ret = 0;
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 9471d59..c780ce1 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -77,6 +77,19 @@ int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
}
#else
+
+/* Context used internally during MMU translations */
+typedef struct mmu_ctx_t mmu_ctx_t;
+struct mmu_ctx_t {
+ hwaddr raddr; /* Real address */
+ hwaddr eaddr; /* Effective address */
+ int prot; /* Protection bits */
+ hwaddr hash[2]; /* Pagetable hash values */
+ target_ulong ptem; /* Virtual segment ID | API */
+ int key; /* Access key */
+ int nx; /* Non-execute area */
+};
+
/* Common routines used by software and hardware TLBs emulation */
static inline int pte_is_valid(target_ulong pte0)
{
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 16/48] mmu-hash*: Add header file for definitions
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (14 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 15/48] target-ppc: mmu_ctx_t should not be a global type David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 17/48] mmu-hash*: Add hash pte load/store helpers David Gibson
` (32 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Currently cpu.h contains a number of definitions relating to the 64-bit
hash MMU. Some are used in the MMU emulation code, but some are only used
in the spapr MMU management hcall implementations.
This patch moves these definitions (except for a few that are needed
more widely) into mmu-hash64.h header, shared between the MMU emulation
code and the spapr hcall code. The MMU emulation code is also updated to
actually use a number of those definitions in place of hard coded
constants.
Similarly, we add new analogous definitions to mmu-hash32.h and use those
in place of many hard-coded constants in mmu-hash32.c
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/ppc/spapr_hcall.c | 70 ++++++++++++------------------------------
target-ppc/cpu.h | 24 ---------------
target-ppc/kvm.c | 1 +
target-ppc/mmu-hash32.c | 78 +++++++++++++++++++++--------------------------
target-ppc/mmu-hash32.h | 61 ++++++++++++++++++++++++++++++++++++
target-ppc/mmu-hash64.c | 35 ++++++++-------------
target-ppc/mmu-hash64.h | 62 +++++++++++++++++++++++++++++++++++++
7 files changed, 190 insertions(+), 141 deletions(-)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 77c052f..d706227 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -3,39 +3,7 @@
#include "sysemu/sysemu.h"
#include "helper_regs.h"
#include "hw/spapr.h"
-
-#define HPTES_PER_GROUP 8
-
-#define HPTE_V_SSIZE_SHIFT 62
-#define HPTE_V_AVPN_SHIFT 7
-#define HPTE_V_AVPN 0x3fffffffffffff80ULL
-#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
-#define HPTE_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL))
-#define HPTE_V_BOLTED 0x0000000000000010ULL
-#define HPTE_V_LOCK 0x0000000000000008ULL
-#define HPTE_V_LARGE 0x0000000000000004ULL
-#define HPTE_V_SECONDARY 0x0000000000000002ULL
-#define HPTE_V_VALID 0x0000000000000001ULL
-
-#define HPTE_R_PP0 0x8000000000000000ULL
-#define HPTE_R_TS 0x4000000000000000ULL
-#define HPTE_R_KEY_HI 0x3000000000000000ULL
-#define HPTE_R_RPN_SHIFT 12
-#define HPTE_R_RPN 0x3ffffffffffff000ULL
-#define HPTE_R_FLAGS 0x00000000000003ffULL
-#define HPTE_R_PP 0x0000000000000003ULL
-#define HPTE_R_N 0x0000000000000004ULL
-#define HPTE_R_G 0x0000000000000008ULL
-#define HPTE_R_M 0x0000000000000010ULL
-#define HPTE_R_I 0x0000000000000020ULL
-#define HPTE_R_W 0x0000000000000040ULL
-#define HPTE_R_WIMG 0x0000000000000078ULL
-#define HPTE_R_C 0x0000000000000080ULL
-#define HPTE_R_R 0x0000000000000100ULL
-#define HPTE_R_KEY_LO 0x0000000000000e00ULL
-
-#define HPTE_V_1TB_SEG 0x4000000000000000ULL
-#define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL
+#include "mmu-hash64.h"
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
target_ulong pte_index)
@@ -44,17 +12,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
rb = (v & ~0x7fULL) << 16; /* AVA field */
va_low = pte_index >> 3;
- if (v & HPTE_V_SECONDARY) {
+ if (v & HPTE64_V_SECONDARY) {
va_low = ~va_low;
}
/* xor vsid from AVA */
- if (!(v & HPTE_V_1TB_SEG)) {
+ if (!(v & HPTE64_V_1TB_SEG)) {
va_low ^= v >> 12;
} else {
va_low ^= v >> 24;
}
va_low &= 0x7ff;
- if (v & HPTE_V_LARGE) {
+ if (v & HPTE64_V_LARGE) {
rb |= 1; /* L field */
#if 0 /* Disable that P7 specific bit for now */
if (r & 0xff000) {
@@ -87,7 +55,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint8_t *hpte;
/* only handle 4k and 16M pages for now */
- if (pteh & HPTE_V_LARGE) {
+ if (pteh & HPTE64_V_LARGE) {
#if 0 /* We don't support 64k pages yet */
if ((ptel & 0xf000) == 0x1000) {
/* 64k page */
@@ -105,11 +73,11 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
}
- raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1);
+ raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << page_shift) - 1);
if (raddr < spapr->ram_limit) {
/* Regular RAM - should have WIMG=0010 */
- if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
+ if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
return H_PARAMETER;
}
} else {
@@ -117,7 +85,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* FIXME: What WIMG combinations could be sensible for IO?
* For now we allow WIMG=010x, but are there others? */
/* FIXME: Should we check against registered IO addresses? */
- if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) {
+ if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) {
return H_PARAMETER;
}
}
@@ -134,7 +102,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
if (i == 8) {
return H_PTEG_FULL;
}
- if ((ldq_p(hpte) & HPTE_V_VALID) == 0) {
+ if ((ldq_p(hpte) & HPTE64_V_VALID) == 0) {
break;
}
hpte += HASH_PTE_SIZE_64;
@@ -142,7 +110,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
} else {
i = 0;
hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
- if (ldq_p(hpte) & HPTE_V_VALID) {
+ if (ldq_p(hpte) & HPTE64_V_VALID) {
return H_PTEG_FULL;
}
}
@@ -178,7 +146,7 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
v = ldq_p(hpte);
r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
- if ((v & HPTE_V_VALID) == 0 ||
+ if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
((flags & H_ANDCOND) && (v & avpn) != 0)) {
return REMOVE_NOT_FOUND;
@@ -271,7 +239,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
switch (ret) {
case REMOVE_SUCCESS:
- *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43;
+ *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
break;
case REMOVE_PARM:
@@ -304,18 +272,18 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
v = ldq_p(hpte);
r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
- if ((v & HPTE_V_VALID) == 0 ||
+ if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
return H_NOT_FOUND;
}
- r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
- HPTE_R_KEY_HI | HPTE_R_KEY_LO);
- r |= (flags << 55) & HPTE_R_PP0;
- r |= (flags << 48) & HPTE_R_KEY_HI;
- r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
+ r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
+ HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
+ r |= (flags << 55) & HPTE64_R_PP0;
+ r |= (flags << 48) & HPTE64_R_KEY_HI;
+ r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
rb = compute_tlbie_rb(v, r, pte_index);
- stq_p(hpte, v & ~HPTE_V_VALID);
+ stq_p(hpte, v & ~HPTE64_V_VALID);
ppc_tlb_invalidate_one(env, rb);
stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
/* Don't need a memory barrier, due to qemu's global lock */
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 035d939..696551a 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -394,36 +394,12 @@ union ppc_tlb_t {
#define SDR_64_HTABSIZE 0x000000000000001FULL
#endif /* defined(TARGET_PPC64 */
-#define HASH_PTE_SIZE_32 8
-#define HASH_PTE_SIZE_64 16
-
typedef struct ppc_slb_t ppc_slb_t;
struct ppc_slb_t {
uint64_t esid;
uint64_t vsid;
};
-/* Bits in the SLB ESID word */
-#define SLB_ESID_ESID 0xFFFFFFFFF0000000ULL
-#define SLB_ESID_V 0x0000000008000000ULL /* valid */
-
-/* Bits in the SLB VSID word */
-#define SLB_VSID_SHIFT 12
-#define SLB_VSID_SHIFT_1T 24
-#define SLB_VSID_SSIZE_SHIFT 62
-#define SLB_VSID_B 0xc000000000000000ULL
-#define SLB_VSID_B_256M 0x0000000000000000ULL
-#define SLB_VSID_B_1T 0x4000000000000000ULL
-#define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL
-#define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID)
-#define SLB_VSID_KS 0x0000000000000800ULL
-#define SLB_VSID_KP 0x0000000000000400ULL
-#define SLB_VSID_N 0x0000000000000200ULL /* no-execute */
-#define SLB_VSID_L 0x0000000000000100ULL
-#define SLB_VSID_C 0x0000000000000080ULL /* class */
-#define SLB_VSID_LP 0x0000000000000030ULL
-#define SLB_VSID_ATTR 0x0000000000000FFFULL
-
#define SEGMENT_SHIFT_256M 28
#define SEGMENT_MASK_256M (~((1ULL << SEGMENT_SHIFT_256M) - 1))
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 9dff760..67f3f42 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -32,6 +32,7 @@
#include "sysemu/device_tree.h"
#include "hw/sysbus.h"
#include "hw/spapr.h"
+#include "mmu-hash64.h"
#include "hw/sysbus.h"
#include "hw/spapr.h"
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 5b48aa8..a1bbd50 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -51,7 +51,6 @@ struct mmu_ctx_hash32 {
int nx; /* Non-execute area */
};
-#define PTE_PTEM_MASK 0x7FFFFFBF
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
static int ppc_hash32_pp_check(int key, int pp, int nx)
@@ -127,13 +126,13 @@ static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp,
target_ulong bl;
int pp, valid, prot;
- bl = (*BATu & 0x00001FFC) << 15;
+ bl = (*BATu & BATU32_BL) << 15;
valid = 0;
prot = 0;
- if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
- ((msr_pr != 0) && (*BATu & 0x00000001))) {
+ if (((msr_pr == 0) && (*BATu & BATU32_VS)) ||
+ ((msr_pr != 0) && (*BATu & BATU32_VP))) {
valid = 1;
- pp = *BATl & 0x00000003;
+ pp = *BATl & BATL32_PP;
if (pp != 0) {
prot = PAGE_READ | PAGE_EXEC;
if (pp == 0x2) {
@@ -153,17 +152,17 @@ static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
target_ulong bl;
int key, pp, valid, prot;
- bl = (*BATl & 0x0000003F) << 17;
+ bl = (*BATl & BATL32_601_BL) << 17;
LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
- (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
+ (uint8_t)(*BATl & BATL32_601_BL), bl, ~bl);
prot = 0;
- valid = (*BATl >> 6) & 1;
+ valid = !!(*BATl & BATL32_601_V);
if (valid) {
- pp = *BATu & 0x00000003;
+ pp = *BATu & BATU32_601_PP;
if (msr_pr == 0) {
- key = (*BATu >> 3) & 1;
+ key = !!(*BATu & BATU32_601_KS);
} else {
- key = (*BATu >> 2) & 1;
+ key = !!(*BATu & BATU32_601_KP);
}
prot = ppc_hash32_pp_check(key, pp, 0);
}
@@ -195,8 +194,8 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
hash32_bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
} else {
@@ -205,13 +204,13 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
- if ((virtual & 0xF0000000) == BEPIu &&
- ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
+ if ((virtual & BATU32_BEPIU) == BEPIu &&
+ ((virtual & BATU32_BEPIL) & ~bl) == BEPIl) {
/* BAT matches */
if (valid != 0) {
/* Get physical address */
- ctx->raddr = (*BATl & 0xF0000000) |
- ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
+ ctx->raddr = (*BATl & BATL32_BRPNU) |
+ ((virtual & BATU32_BEPIL & bl) | (*BATl & BATL32_BRPNL)) |
(virtual & 0x0001F000);
/* Compute access rights */
ctx->prot = prot;
@@ -232,8 +231,8 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
for (i = 0; i < 4; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
bl = (*BATu & 0x00001FFC) << 15;
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
@@ -248,28 +247,19 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
return ret;
}
-
-static inline int pte_is_valid_hash32(target_ulong pte0)
-{
- return pte0 & 0x80000000 ? 1 : 0;
-}
-
static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
target_ulong pte1, int h, int rw, int type)
{
- target_ulong ptem, mmask;
- int access, ret, pteh, ptev, pp;
+ target_ulong mmask;
+ int access, ret, pp;
ret = -1;
/* Check validity and table match */
- ptev = pte_is_valid_hash32(pte0);
- pteh = (pte0 >> 6) & 1;
- if (ptev && h == pteh) {
+ if ((pte0 & HPTE32_V_VALID) && (h == !!(pte0 & HPTE32_V_SECONDARY))) {
/* Check vsid & api */
- ptem = pte0 & PTE_PTEM_MASK;
mmask = PTE_CHECK_MASK;
- pp = pte1 & 0x00000003;
- if (ptem == ctx->ptem) {
+ pp = pte1 & HPTE32_R_PP;
+ if (HPTE32_V_COMPARE(pte0, ctx->ptem)) {
if (ctx->raddr != (hwaddr)-1ULL) {
/* all matches should have equal RPN, WIMG & PP */
if ((ctx->raddr & mmask) != (pte1 & mmask)) {
@@ -302,15 +292,15 @@ static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong
int store = 0;
/* Update page flags */
- if (!(*pte1p & 0x00000100)) {
+ if (!(*pte1p & HPTE32_R_R)) {
/* Update accessed flag */
- *pte1p |= 0x00000100;
+ *pte1p |= HPTE32_R_R;
store = 1;
}
- if (!(*pte1p & 0x00000080)) {
+ if (!(*pte1p & HPTE32_R_C)) {
if (rw == 1 && ret == 0) {
/* Update changed flag */
- *pte1p |= 0x00000080;
+ *pte1p |= HPTE32_R_C;
store = 1;
} else {
/* Force page fault for first write access */
@@ -323,7 +313,7 @@ static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong
hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
{
- return (hash * HASH_PTE_SIZE_32 * 8) & env->htab_mask;
+ return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
}
/* PTE table lookup */
@@ -337,7 +327,7 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
ret = -1; /* No entry found */
pteg_off = get_pteg_offset32(env, ctx->hash[h]);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < HPTES_PER_GROUP; i++) {
if (env->external_htab) {
pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
@@ -413,11 +403,11 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
ctx->eaddr = eaddr;
sr = env->sr[eaddr >> 28];
- ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
- ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
- ds = sr & 0x80000000 ? 1 : 0;
- ctx->nx = sr & 0x10000000 ? 1 : 0;
- vsid = sr & 0x00FFFFFF;
+ ctx->key = (((sr & SR32_KP) && (pr != 0)) ||
+ ((sr & SR32_KS) && (pr == 0))) ? 1 : 0;
+ ds = !!(sr & SR32_T);
+ ctx->nx = !!(sr & SR32_NX);
+ vsid = sr & SR32_VSID;
target_page_bits = TARGET_PAGE_BITS;
LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
TARGET_FMT_lx " lr=" TARGET_FMT_lx
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 3435aa5..a09ccb3 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -8,6 +8,67 @@ hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
+/*
+ * Segment register definitions
+ */
+
+#define SR32_T 0x80000000
+#define SR32_KS 0x40000000
+#define SR32_KP 0x20000000
+#define SR32_NX 0x10000000
+#define SR32_VSID 0x00ffffff
+
+/*
+ * Block Address Translation (BAT) definitions
+ */
+
+#define BATU32_BEPIU 0xf0000000
+#define BATU32_BEPIL 0x0ffe0000
+#define BATU32_BEPI 0xfffe0000
+#define BATU32_BL 0x00001ffc
+#define BATU32_VS 0x00000002
+#define BATU32_VP 0x00000001
+
+
+#define BATL32_BRPNU 0xf0000000
+#define BATL32_BRPNL 0x0ffe0000
+#define BATL32_BRPN 0xfffe0000
+#define BATL32_WIMG 0x00000078
+#define BATL32_PP 0x00000003
+
+/* PowerPC 601 has slightly different BAT registers */
+
+#define BATU32_601_KS 0x00000008
+#define BATU32_601_KP 0x00000004
+#define BATU32_601_PP 0x00000003
+
+#define BATL32_601_V 0x00000040
+#define BATL32_601_BL 0x0000003f
+
+/*
+ * Hash page table definitions
+ */
+
+#define HPTES_PER_GROUP 8
+#define HASH_PTE_SIZE_32 8
+#define HASH_PTEG_SIZE_32 (HASH_PTE_SIZE_32 * HPTES_PER_GROUP)
+
+#define HPTE32_V_VALID 0x80000000
+#define HPTE32_V_VSID 0x7fffff80
+#define HPTE32_V_SECONDARY 0x00000040
+#define HPTE32_V_API 0x0000003f
+#define HPTE32_V_COMPARE(x, y) (!(((x) ^ (y)) & 0x7fffffbf))
+
+#define HPTE32_R_RPN 0xfffff000
+#define HPTE32_R_R 0x00000100
+#define HPTE32_R_C 0x00000080
+#define HPTE32_R_W 0x00000040
+#define HPTE32_R_I 0x00000020
+#define HPTE32_R_M 0x00000010
+#define HPTE32_R_G 0x00000008
+#define HPTE32_R_WIMG 0x00000078
+#define HPTE32_R_PP 0x00000003
+
#endif /* CONFIG_USER_ONLY */
#endif /* __MMU_HASH32_H__ */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 3008be8..f3223dd 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -233,7 +233,6 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
* 64-bit hash table MMU handling
*/
-#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
static int ppc_hash64_pp_check(int key, int pp, int nx)
@@ -304,29 +303,21 @@ static int ppc_hash64_check_prot(int prot, int rw, int access_type)
return ret;
}
-static inline int pte64_is_valid(target_ulong pte0)
-{
- return pte0 & 0x0000000000000001ULL ? 1 : 0;
-}
-
static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
target_ulong pte1, int h, int rw, int type)
{
- target_ulong ptem, mmask;
- int access, ret, pteh, ptev, pp;
+ target_ulong mmask;
+ int access, ret, pp;
ret = -1;
/* Check validity and table match */
- ptev = pte64_is_valid(pte0);
- pteh = (pte0 >> 1) & 1;
- if (ptev && h == pteh) {
+ if ((pte0 & HPTE64_V_VALID) && (h == !!(pte0 & HPTE64_V_SECONDARY))) {
/* Check vsid & api */
- ptem = pte0 & PTE64_PTEM_MASK;
mmask = PTE64_CHECK_MASK;
- pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
- ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
- ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
- if (ptem == ctx->ptem) {
+ pp = (pte1 & HPTE64_R_PP) | ((pte1 & HPTE64_R_PP0) >> 61);
+ /* No execute if either noexec or guarded bits set */
+ ctx->nx = (pte1 & HPTE64_R_N) || (pte1 & HPTE64_R_G);
+ if (HPTE64_V_COMPARE(pte0, ctx->ptem)) {
if (ctx->raddr != (hwaddr)-1ULL) {
/* all matches should have equal RPN, WIMG & PP */
if ((ctx->raddr & mmask) != (pte1 & mmask)) {
@@ -360,15 +351,15 @@ static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
int store = 0;
/* Update page flags */
- if (!(*pte1p & 0x00000100)) {
+ if (!(*pte1p & HPTE64_R_R)) {
/* Update accessed flag */
- *pte1p |= 0x00000100;
+ *pte1p |= HPTE64_R_R;
store = 1;
}
- if (!(*pte1p & 0x00000080)) {
+ if (!(*pte1p & HPTE64_R_C)) {
if (rw == 1 && ret == 0) {
/* Update changed flag */
- *pte1p |= 0x00000080;
+ *pte1p |= HPTE64_R_C;
store = 1;
} else {
/* Force page fault for first write access */
@@ -389,8 +380,8 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
int ret, r;
ret = -1; /* No entry found */
- pteg_off = (ctx->hash[h] * HASH_PTE_SIZE_64 * 8) & env->htab_mask;
- for (i = 0; i < 8; i++) {
+ pteg_off = (ctx->hash[h] * HASH_PTEG_SIZE_64) & env->htab_mask;
+ for (i = 0; i < HPTES_PER_GROUP; i++) {
if (env->external_htab) {
pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 665d3b0..bc0cd68 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -11,6 +11,68 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
#endif
+/*
+ * SLB definitions
+ */
+
+/* Bits in the SLB ESID word */
+#define SLB_ESID_ESID 0xFFFFFFFFF0000000ULL
+#define SLB_ESID_V 0x0000000008000000ULL /* valid */
+
+/* Bits in the SLB VSID word */
+#define SLB_VSID_SHIFT 12
+#define SLB_VSID_SHIFT_1T 24
+#define SLB_VSID_SSIZE_SHIFT 62
+#define SLB_VSID_B 0xc000000000000000ULL
+#define SLB_VSID_B_256M 0x0000000000000000ULL
+#define SLB_VSID_B_1T 0x4000000000000000ULL
+#define SLB_VSID_VSID 0x3FFFFFFFFFFFF000ULL
+#define SLB_VSID_PTEM (SLB_VSID_B | SLB_VSID_VSID)
+#define SLB_VSID_KS 0x0000000000000800ULL
+#define SLB_VSID_KP 0x0000000000000400ULL
+#define SLB_VSID_N 0x0000000000000200ULL /* no-execute */
+#define SLB_VSID_L 0x0000000000000100ULL
+#define SLB_VSID_C 0x0000000000000080ULL /* class */
+#define SLB_VSID_LP 0x0000000000000030ULL
+#define SLB_VSID_ATTR 0x0000000000000FFFULL
+
+/*
+ * Hash page table definitions
+ */
+
+#define HPTES_PER_GROUP 8
+#define HASH_PTE_SIZE_64 16
+#define HASH_PTEG_SIZE_64 (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
+
+#define HPTE64_V_SSIZE_SHIFT 62
+#define HPTE64_V_AVPN_SHIFT 7
+#define HPTE64_V_AVPN 0x3fffffffffffff80ULL
+#define HPTE64_V_AVPN_VAL(x) (((x) & HPTE64_V_AVPN) >> HPTE64_V_AVPN_SHIFT)
+#define HPTE64_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL))
+#define HPTE64_V_LARGE 0x0000000000000004ULL
+#define HPTE64_V_SECONDARY 0x0000000000000002ULL
+#define HPTE64_V_VALID 0x0000000000000001ULL
+
+#define HPTE64_R_PP0 0x8000000000000000ULL
+#define HPTE64_R_TS 0x4000000000000000ULL
+#define HPTE64_R_KEY_HI 0x3000000000000000ULL
+#define HPTE64_R_RPN_SHIFT 12
+#define HPTE64_R_RPN 0x0ffffffffffff000ULL
+#define HPTE64_R_FLAGS 0x00000000000003ffULL
+#define HPTE64_R_PP 0x0000000000000003ULL
+#define HPTE64_R_N 0x0000000000000004ULL
+#define HPTE64_R_G 0x0000000000000008ULL
+#define HPTE64_R_M 0x0000000000000010ULL
+#define HPTE64_R_I 0x0000000000000020ULL
+#define HPTE64_R_W 0x0000000000000040ULL
+#define HPTE64_R_WIMG 0x0000000000000078ULL
+#define HPTE64_R_C 0x0000000000000080ULL
+#define HPTE64_R_R 0x0000000000000100ULL
+#define HPTE64_R_KEY_LO 0x0000000000000e00ULL
+
+#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
+#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL
+
#endif /* CONFIG_USER_ONLY */
#endif /* !defined (__MMU_HASH64_H__) */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 17/48] mmu-hash*: Add hash pte load/store helpers
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (15 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 16/48] mmu-hash*: Add header file for definitions David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 18/48] mmu-hash*: Reduce use of access_type David Gibson
` (31 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
On real hardware the ppc hash page table is stored in memory; accordingly
our mmu emulation code can read a hash page table in guest memory. But,
when paravirtualized under PAPR, the real hash page table is in host
memory, accessible to the guest only via hypercalls. We model this by
also allowing the MMU emulation code to access a specially allocated hash
page table outside the guest's memory image. At present these two options
are implemented with some ugly conditionals at each access point in the mmu
emulation code. In the implementation of the PAPR hypercalls, we assume
the external hash table.
This patch cleans things up by adding helpers to load and store from the
hash table for both 32-bit and 64-bit hash mmus. The 64-bit versions
handle both the in-guest-memory and outside guest memory cases. The 32-bit
versions only handle the in-guest-memory case since no 32-bit systems can
have an external hash table at present.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/ppc/spapr_hcall.c | 38 +++++++++++++++++++-------------------
target-ppc/mmu-hash32.c | 18 ++++--------------
target-ppc/mmu-hash32.h | 28 ++++++++++++++++++++++++++++
target-ppc/mmu-hash64.c | 17 +++--------------
target-ppc/mmu-hash64.h | 40 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 94 insertions(+), 47 deletions(-)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index d706227..96ebf5e 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -52,7 +52,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong page_shift = 12;
target_ulong raddr;
target_ulong i;
- uint8_t *hpte;
+ hwaddr hpte;
/* only handle 4k and 16M pages for now */
if (pteh & HPTE64_V_LARGE) {
@@ -97,26 +97,26 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
if (likely((flags & H_EXACT) == 0)) {
pte_index &= ~7ULL;
- hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+ hpte = pte_index * HASH_PTE_SIZE_64;
for (i = 0; ; ++i) {
if (i == 8) {
return H_PTEG_FULL;
}
- if ((ldq_p(hpte) & HPTE64_V_VALID) == 0) {
+ if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
break;
}
hpte += HASH_PTE_SIZE_64;
}
} else {
i = 0;
- hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
- if (ldq_p(hpte) & HPTE64_V_VALID) {
+ hpte = pte_index * HASH_PTE_SIZE_64;
+ if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
return H_PTEG_FULL;
}
}
- stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
+ ppc_hash64_store_hpte1(env, hpte, ptel);
/* eieio(); FIXME: need some sort of barrier for smp? */
- stq_p(hpte, pteh);
+ ppc_hash64_store_hpte0(env, hpte, pteh);
args[0] = pte_index + i;
return H_SUCCESS;
@@ -134,17 +134,17 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
target_ulong flags,
target_ulong *vp, target_ulong *rp)
{
- uint8_t *hpte;
+ hwaddr hpte;
target_ulong v, r, rb;
if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
return REMOVE_PARM;
}
- hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
+ hpte = ptex * HASH_PTE_SIZE_64;
- v = ldq_p(hpte);
- r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+ v = ppc_hash64_load_hpte0(env, hpte);
+ r = ppc_hash64_load_hpte1(env, hpte);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
@@ -153,7 +153,7 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
}
*vp = v;
*rp = r;
- stq_p(hpte, 0);
+ ppc_hash64_store_hpte0(env, hpte, 0);
rb = compute_tlbie_rb(v, r, ptex);
ppc_tlb_invalidate_one(env, rb);
return REMOVE_SUCCESS;
@@ -260,17 +260,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong flags = args[0];
target_ulong pte_index = args[1];
target_ulong avpn = args[2];
- uint8_t *hpte;
+ hwaddr hpte;
target_ulong v, r, rb;
if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
return H_PARAMETER;
}
- hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+ hpte = pte_index * HASH_PTE_SIZE_64;
- v = ldq_p(hpte);
- r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+ v = ppc_hash64_load_hpte0(env, hpte);
+ r = ppc_hash64_load_hpte1(env, hpte);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
@@ -283,11 +283,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
r |= (flags << 48) & HPTE64_R_KEY_HI;
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
rb = compute_tlbie_rb(v, r, pte_index);
- stq_p(hpte, v & ~HPTE64_V_VALID);
+ ppc_hash64_store_hpte0(env, hpte, v & ~HPTE64_V_VALID);
ppc_tlb_invalidate_one(env, rb);
- stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
+ ppc_hash64_store_hpte1(env, hpte, r);
/* Don't need a memory barrier, due to qemu's global lock */
- stq_p(hpte, v);
+ ppc_hash64_store_hpte0(env, hpte, v);
return H_SUCCESS;
}
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index a1bbd50..a7c2e35 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -328,13 +328,8 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
ret = -1; /* No entry found */
pteg_off = get_pteg_offset32(env, ctx->hash[h]);
for (i = 0; i < HPTES_PER_GROUP; i++) {
- if (env->external_htab) {
- pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
- pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
- } else {
- pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
- pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
- }
+ pte0 = ppc_hash32_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_32);
+ pte1 = ppc_hash32_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_32);
r = pte_check_hash32(ctx, pte0, pte1, h, rw, type);
LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
@@ -371,13 +366,8 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
/* Update page flags */
pte1 = ctx->raddr;
if (ppc_hash32_pte_update_flags(ctx, &pte1, ret, rw) == 1) {
- if (env->external_htab) {
- stl_p(env->external_htab + pteg_off + (good * 8) + 4,
- pte1);
- } else {
- stl_phys_notdirty(env->htab_base + pteg_off +
- (good * 8) + 4, pte1);
- }
+ ppc_hash32_store_hpte1(env, pteg_off + good * HASH_PTE_SIZE_32,
+ pte1);
}
}
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index a09ccb3..2344184 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -69,6 +69,34 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
#define HPTE32_R_WIMG 0x00000078
#define HPTE32_R_PP 0x00000003
+static inline target_ulong ppc_hash32_load_hpte0(CPUPPCState *env,
+ hwaddr pte_offset)
+{
+ assert(!env->external_htab); /* Not supported on 32-bit for now */
+ return ldl_phys(env->htab_base + pte_offset);
+}
+
+static inline target_ulong ppc_hash32_load_hpte1(CPUPPCState *env,
+ hwaddr pte_offset)
+{
+ assert(!env->external_htab); /* Not supported on 32-bit for now */
+ return ldl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2);
+}
+
+static inline void ppc_hash32_store_hpte0(CPUPPCState *env,
+ hwaddr pte_offset, target_ulong pte0)
+{
+ assert(!env->external_htab); /* Not supported on 32-bit for now */
+ stl_phys(env->htab_base + pte_offset, pte0);
+}
+
+static inline void ppc_hash32_store_hpte1(CPUPPCState *env,
+ hwaddr pte_offset, target_ulong pte1)
+{
+ assert(!env->external_htab); /* Not supported on 32-bit for now */
+ stl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2, pte1);
+}
+
#endif /* CONFIG_USER_ONLY */
#endif /* __MMU_HASH32_H__ */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index f3223dd..30c25dd 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -382,13 +382,8 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
ret = -1; /* No entry found */
pteg_off = (ctx->hash[h] * HASH_PTEG_SIZE_64) & env->htab_mask;
for (i = 0; i < HPTES_PER_GROUP; i++) {
- if (env->external_htab) {
- pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
- pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
- } else {
- pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
- pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
- }
+ pte0 = ppc_hash64_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_64);
+ pte1 = ppc_hash64_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_64);
r = pte64_check(ctx, pte0, pte1, h, rw, type);
LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " "
@@ -426,13 +421,7 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
/* Update page flags */
pte1 = ctx->raddr;
if (ppc_hash64_pte_update_flags(ctx, &pte1, ret, rw) == 1) {
- if (env->external_htab) {
- stq_p(env->external_htab + pteg_off + (good * 16) + 8,
- pte1);
- } else {
- stq_phys_notdirty(env->htab_base + pteg_off +
- (good * 16) + 8, pte1);
- }
+ ppc_hash64_store_hpte1(env, pteg_off + good * HASH_PTE_SIZE_64, pte1);
}
}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index bc0cd68..a9c73d4 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -73,6 +73,46 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL
+static inline target_ulong ppc_hash64_load_hpte0(CPUPPCState *env,
+ hwaddr pte_offset)
+{
+ if (env->external_htab) {
+ return ldq_p(env->external_htab + pte_offset);
+ } else {
+ return ldq_phys(env->htab_base + pte_offset);
+ }
+}
+
+static inline target_ulong ppc_hash64_load_hpte1(CPUPPCState *env,
+ hwaddr pte_offset)
+{
+ if (env->external_htab) {
+ return ldq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2);
+ } else {
+ return ldq_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_64/2);
+ }
+}
+
+static inline void ppc_hash64_store_hpte0(CPUPPCState *env,
+ hwaddr pte_offset, target_ulong pte0)
+{
+ if (env->external_htab) {
+ stq_p(env->external_htab + pte_offset, pte0);
+ } else {
+ stq_phys(env->htab_base + pte_offset, pte0);
+ }
+}
+
+static inline void ppc_hash64_store_hpte1(CPUPPCState *env,
+ hwaddr pte_offset, target_ulong pte1)
+{
+ if (env->external_htab) {
+ stq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2, pte1);
+ } else {
+ stq_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_64/2, pte1);
+ }
+}
+
#endif /* CONFIG_USER_ONLY */
#endif /* !defined (__MMU_HASH64_H__) */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 18/48] mmu-hash*: Reduce use of access_type
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (16 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 17/48] mmu-hash*: Add hash pte load/store helpers David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 19/48] mmu-hash64: Remove nx from mmu_ctx_hash64 David Gibson
` (30 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
In ppc env->access_type is updated by e.g. integer load/stores with
ACCESS_INT floating point load/stores with ACCESS_FLOAT and so forth. In
hash mmu fault paths it can also b set to ACCESS_CODE for instruction
fetch accesses.
But the only place which uses anything more of the access_type than
whether it is instruction fetch or data access is the direct store segment
handling. Instruction versus data access can be more simply determined
from the rw value passed down from the top.
This changes the code to use rw in preference to checking access_type.
For the 32-bit case there is a small amount of code (for direct store
segments) that still needs the full access type. Instead of passing it
all the way down the stack, we retrieve it from the env structure, which
is where it came anyway, before this patch.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 98 +++++++++++++++++++++--------------------------
target-ppc/mmu-hash64.c | 55 +++++++++++---------------
2 files changed, 66 insertions(+), 87 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index a7c2e35..ad5ef44 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -91,17 +91,17 @@ static int ppc_hash32_pp_check(int key, int pp, int nx)
return access;
}
-static int ppc_hash32_check_prot(int prot, int rw, int access_type)
+static int ppc_hash32_check_prot(int prot, int rwx)
{
int ret;
- if (access_type == ACCESS_CODE) {
+ if (rwx == 2) {
if (prot & PAGE_EXEC) {
ret = 0;
} else {
ret = -2;
}
- } else if (rw) {
+ } else if (rwx) {
if (prot & PAGE_WRITE) {
ret = 0;
} else {
@@ -172,7 +172,7 @@ static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
}
static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong virtual, int rw, int type)
+ target_ulong virtual, int rwx)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong BEPIl, BEPIu, bl;
@@ -180,16 +180,13 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
int ret = -1;
LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', virtual);
- switch (type) {
- case ACCESS_CODE:
+ rwx == 2 ? 'I' : 'D', virtual);
+ if (rwx == 2) {
BATlt = env->IBAT[1];
BATut = env->IBAT[0];
- break;
- default:
+ } else {
BATlt = env->DBAT[1];
BATut = env->DBAT[0];
- break;
}
for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
@@ -214,7 +211,7 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
(virtual & 0x0001F000);
/* Compute access rights */
ctx->prot = prot;
- ret = ppc_hash32_check_prot(ctx->prot, rw, type);
+ ret = ppc_hash32_check_prot(ctx->prot, rwx);
if (ret == 0) {
LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
@@ -248,7 +245,7 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
}
static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
+ target_ulong pte1, int h, int rwx)
{
target_ulong mmask;
int access, ret, pp;
@@ -272,7 +269,7 @@ static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
/* Keep the matching PTE informations */
ctx->raddr = pte1;
ctx->prot = access;
- ret = ppc_hash32_check_prot(ctx->prot, rw, type);
+ ret = ppc_hash32_check_prot(ctx->prot, rwx);
if (ret == 0) {
/* Access granted */
LOG_MMU("PTE access granted !\n");
@@ -287,7 +284,7 @@ static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
}
static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong *pte1p,
- int ret, int rw)
+ int ret, int rwx)
{
int store = 0;
@@ -298,7 +295,7 @@ static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong
store = 1;
}
if (!(*pte1p & HPTE32_R_C)) {
- if (rw == 1 && ret == 0) {
+ if (rwx == 1 && ret == 0) {
/* Update changed flag */
*pte1p |= HPTE32_R_C;
store = 1;
@@ -318,7 +315,7 @@ hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
/* PTE table lookup */
static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
- int rw, int type, int target_page_bits)
+ int rwx, int target_page_bits)
{
hwaddr pteg_off;
target_ulong pte0, pte1;
@@ -330,7 +327,7 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
for (i = 0; i < HPTES_PER_GROUP; i++) {
pte0 = ppc_hash32_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_32);
pte1 = ppc_hash32_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_32);
- r = pte_check_hash32(ctx, pte0, pte1, h, rw, type);
+ r = pte_check_hash32(ctx, pte0, pte1, h, rwx);
LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
@@ -365,7 +362,7 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
ctx->raddr, ctx->prot, ret);
/* Update page flags */
pte1 = ctx->raddr;
- if (ppc_hash32_pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+ if (ppc_hash32_pte_update_flags(ctx, &pte1, ret, rwx) == 1) {
ppc_hash32_store_hpte1(env, pteg_off + good * HASH_PTE_SIZE_32,
pte1);
}
@@ -381,7 +378,7 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
}
static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong eaddr, int rw, int type)
+ target_ulong eaddr, int rwx)
{
hwaddr hash;
target_ulong vsid;
@@ -401,9 +398,9 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_page_bits = TARGET_PAGE_BITS;
LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
TARGET_FMT_lx " lr=" TARGET_FMT_lx
- " ir=%d dr=%d pr=%d %d t=%d\n",
+ " ir=%d dr=%d pr=%d %d\n",
eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
- (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+ (int)msr_dr, pr != 0 ? 1 : 0, rwx);
pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
hash = vsid ^ pgidx;
ctx->ptem = (vsid << 7) | (pgidx >> 10);
@@ -413,7 +410,7 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
ret = -1;
if (!ds) {
/* Check if instruction fetch is allowed, if needed */
- if (type != ACCESS_CODE || ctx->nx == 0) {
+ if (rwx != 2 || ctx->nx == 0) {
/* Page address translation */
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
@@ -429,15 +426,14 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
env->htab_base, env->htab_mask, vsid, ctx->ptem,
ctx->hash[0]);
/* Primary table lookup */
- ret = find_pte32(env, ctx, 0, rw, type, target_page_bits);
+ ret = find_pte32(env, ctx, 0, rwx, target_page_bits);
if (ret < 0) {
/* Secondary table lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte32(env, ctx, 1, rw, type,
- target_page_bits);
+ ret2 = find_pte32(env, ctx, 1, rwx, target_page_bits);
if (ret2 != -1) {
ret = ret2;
}
@@ -486,13 +482,15 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
return 0;
}
- switch (type) {
+ if (rwx == 2) {
+ /* No code fetch is allowed in direct-store areas */
+ return -4;
+ }
+
+ switch (env->access_type) {
case ACCESS_INT:
/* Integer load/store : only access allowed */
break;
- case ACCESS_CODE:
- /* No code fetch is allowed in direct-store areas */
- return -4;
case ACCESS_FLOAT:
/* Floating point load/store */
return -4;
@@ -514,7 +512,7 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
"address translation\n");
return -4;
}
- if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+ if ((rwx == 1 || ctx->key != 1) && (rwx == 0 || ctx->key != 0)) {
ctx->raddr = eaddr;
ret = 2;
} else {
@@ -526,11 +524,10 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
}
static int ppc_hash32_get_physical_address(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong eaddr, int rw,
- int access_type)
+ target_ulong eaddr, int rwx)
{
- bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
- || (access_type != ACCESS_CODE && msr_dr == 0);
+ bool real_mode = (rwx == 2 && msr_ir == 0)
+ || (rwx != 2 && msr_dr == 0);
if (real_mode) {
ctx->raddr = eaddr;
@@ -541,11 +538,11 @@ static int ppc_hash32_get_physical_address(CPUPPCState *env, struct mmu_ctx_hash
/* Try to find a BAT */
if (env->nb_BATs != 0) {
- ret = ppc_hash32_get_bat(env, ctx, eaddr, rw, access_type);
+ ret = ppc_hash32_get_bat(env, ctx, eaddr, rwx);
}
if (ret < 0) {
/* We didn't match any BAT entry or don't have BATs */
- ret = get_segment32(env, ctx, eaddr, rw, access_type);
+ ret = get_segment32(env, ctx, eaddr, rwx);
}
return ret;
}
@@ -555,7 +552,9 @@ hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
struct mmu_ctx_hash32 ctx;
- if (unlikely(ppc_hash32_get_physical_address(env, &ctx, addr, 0, ACCESS_INT)
+ /* FIXME: Will not behave sanely for direct store segments, but
+ * they're almost never used */
+ if (unlikely(ppc_hash32_get_physical_address(env, &ctx, addr, 0)
!= 0)) {
return -1;
}
@@ -563,22 +562,13 @@ hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
return ctx.raddr & TARGET_PAGE_MASK;
}
-int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
int mmu_idx)
{
struct mmu_ctx_hash32 ctx;
- int access_type;
int ret = 0;
- if (rw == 2) {
- /* code access */
- rw = 0;
- access_type = ACCESS_CODE;
- } else {
- /* data access */
- access_type = env->access_type;
- }
- ret = ppc_hash32_get_physical_address(env, &ctx, address, rw, access_type);
+ ret = ppc_hash32_get_physical_address(env, &ctx, address, rwx);
if (ret == 0) {
tlb_set_page(env, address & TARGET_PAGE_MASK,
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
@@ -586,7 +576,7 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
ret = 0;
} else if (ret < 0) {
LOG_MMU_STATE(env);
- if (access_type == ACCESS_CODE) {
+ if (rwx == 2) {
switch (ret) {
case -1:
/* No matches in page tables or TLB */
@@ -617,7 +607,7 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (rwx == 1) {
env->spr[SPR_DSISR] = 0x42000000;
} else {
env->spr[SPR_DSISR] = 0x40000000;
@@ -628,7 +618,7 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (rwx == 1) {
env->spr[SPR_DSISR] = 0x0A000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
@@ -636,7 +626,7 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
break;
case -4:
/* Direct store exception */
- switch (access_type) {
+ switch (env->access_type) {
case ACCESS_FLOAT:
/* Floating point load/store */
env->exception_index = POWERPC_EXCP_ALIGN;
@@ -648,7 +638,7 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (rwx == 1) {
env->spr[SPR_DSISR] = 0x06000000;
} else {
env->spr[SPR_DSISR] = 0x04000000;
@@ -659,7 +649,7 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (rwx == 1) {
env->spr[SPR_DSISR] = 0x06100000;
} else {
env->spr[SPR_DSISR] = 0x04100000;
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 30c25dd..654ef06 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -276,17 +276,17 @@ static int ppc_hash64_pp_check(int key, int pp, int nx)
return access;
}
-static int ppc_hash64_check_prot(int prot, int rw, int access_type)
+static int ppc_hash64_check_prot(int prot, int rwx)
{
int ret;
- if (access_type == ACCESS_CODE) {
+ if (rwx == 2) {
if (prot & PAGE_EXEC) {
ret = 0;
} else {
ret = -2;
}
- } else if (rw) {
+ } else if (rwx == 1) {
if (prot & PAGE_WRITE) {
ret = 0;
} else {
@@ -304,7 +304,7 @@ static int ppc_hash64_check_prot(int prot, int rw, int access_type)
}
static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rw, int type)
+ target_ulong pte1, int h, int rwx)
{
target_ulong mmask;
int access, ret, pp;
@@ -330,7 +330,7 @@ static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
/* Keep the matching PTE informations */
ctx->raddr = pte1;
ctx->prot = access;
- ret = ppc_hash64_check_prot(ctx->prot, rw, type);
+ ret = ppc_hash64_check_prot(ctx->prot, rwx);
if (ret == 0) {
/* Access granted */
LOG_MMU("PTE access granted !\n");
@@ -372,7 +372,7 @@ static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
/* PTE table lookup */
static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
- int rw, int type, int target_page_bits)
+ int rwx, int target_page_bits)
{
hwaddr pteg_off;
target_ulong pte0, pte1;
@@ -385,7 +385,7 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
pte0 = ppc_hash64_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_64);
pte1 = ppc_hash64_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_64);
- r = pte64_check(ctx, pte0, pte1, h, rw, type);
+ r = pte64_check(ctx, pte0, pte1, h, rwx);
LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " "
TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
@@ -420,7 +420,7 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
ctx->raddr, ctx->prot, ret);
/* Update page flags */
pte1 = ctx->raddr;
- if (ppc_hash64_pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+ if (ppc_hash64_pte_update_flags(ctx, &pte1, ret, rwx) == 1) {
ppc_hash64_store_hpte1(env, pteg_off + good * HASH_PTE_SIZE_64, pte1);
}
}
@@ -435,7 +435,7 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
}
static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
- target_ulong eaddr, int rw, int type)
+ target_ulong eaddr, int rwx)
{
hwaddr hash;
target_ulong vsid;
@@ -484,7 +484,7 @@ static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ret = -1;
/* Check if instruction fetch is allowed, if needed */
- if (type != ACCESS_CODE || ctx->nx == 0) {
+ if (rwx != 2 || ctx->nx == 0) {
/* Page address translation */
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
@@ -500,14 +500,14 @@ static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
env->htab_base, env->htab_mask, vsid, ctx->ptem,
ctx->hash[0]);
/* Primary table lookup */
- ret = find_pte64(env, ctx, 0, rw, type, target_page_bits);
+ ret = find_pte64(env, ctx, 0, rwx, target_page_bits);
if (ret < 0) {
/* Secondary table lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte64(env, ctx, 1, rw, type, target_page_bits);
+ ret2 = find_pte64(env, ctx, 1, rwx, target_page_bits);
if (ret2 != -1) {
ret = ret2;
}
@@ -522,18 +522,17 @@ static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
static int ppc_hash64_get_physical_address(CPUPPCState *env,
struct mmu_ctx_hash64 *ctx,
- target_ulong eaddr, int rw,
- int access_type)
+ target_ulong eaddr, int rwx)
{
- bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
- || (access_type != ACCESS_CODE && msr_dr == 0);
+ bool real_mode = (rwx == 2 && msr_ir == 0)
+ || (rwx != 2 && msr_dr == 0);
if (real_mode) {
ctx->raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
return 0;
} else {
- return get_segment64(env, ctx, eaddr, rw, access_type);
+ return get_segment64(env, ctx, eaddr, rwx);
}
}
@@ -541,30 +540,20 @@ hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
struct mmu_ctx_hash64 ctx;
- if (unlikely(ppc_hash64_get_physical_address(env, &ctx, addr, 0, ACCESS_INT)
- != 0)) {
+ if (unlikely(ppc_hash64_get_physical_address(env, &ctx, addr, 0) != 0)) {
return -1;
}
return ctx.raddr & TARGET_PAGE_MASK;
}
-int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
int mmu_idx)
{
struct mmu_ctx_hash64 ctx;
- int access_type;
int ret = 0;
- if (rw == 2) {
- /* code access */
- rw = 0;
- access_type = ACCESS_CODE;
- } else {
- /* data access */
- access_type = env->access_type;
- }
- ret = ppc_hash64_get_physical_address(env, &ctx, address, rw, access_type);
+ ret = ppc_hash64_get_physical_address(env, &ctx, address, rwx);
if (ret == 0) {
tlb_set_page(env, address & TARGET_PAGE_MASK,
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
@@ -572,7 +561,7 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
ret = 0;
} else if (ret < 0) {
LOG_MMU_STATE(env);
- if (access_type == ACCESS_CODE) {
+ if (rwx == 2) {
switch (ret) {
case -1:
env->exception_index = POWERPC_EXCP_ISI;
@@ -601,7 +590,7 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (rwx == 1) {
env->spr[SPR_DSISR] = 0x42000000;
} else {
env->spr[SPR_DSISR] = 0x40000000;
@@ -612,7 +601,7 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (rwx == 1) {
env->spr[SPR_DSISR] = 0x0A000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 19/48] mmu-hash64: Remove nx from mmu_ctx_hash64
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (17 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 18/48] mmu-hash*: Reduce use of access_type David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 20/48] mmu-hash*: Remove eaddr field from mmu_ctx_hash{32, 64} David Gibson
` (29 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
The nx field in mmu_ctx_hash64 is used in two different functions. But its
used for slightly different things in each place, and the value is never
propagated between them. In other words, it might as well be two local
variables. This patch makes it so.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash64.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 654ef06..f89d005 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -47,7 +47,6 @@ struct mmu_ctx_hash64 {
hwaddr hash[2]; /* Pagetable hash values */
target_ulong ptem; /* Virtual segment ID | API */
int key; /* Access key */
- int nx; /* Non-execute area */
};
/*
@@ -235,7 +234,7 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
-static int ppc_hash64_pp_check(int key, int pp, int nx)
+static int ppc_hash64_pp_check(int key, int pp, bool nx)
{
int access;
@@ -269,7 +268,7 @@ static int ppc_hash64_pp_check(int key, int pp, int nx)
break;
}
}
- if (nx == 0) {
+ if (!nx) {
access |= PAGE_EXEC;
}
@@ -312,11 +311,13 @@ static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
ret = -1;
/* Check validity and table match */
if ((pte0 & HPTE64_V_VALID) && (h == !!(pte0 & HPTE64_V_SECONDARY))) {
+ bool nx;
+
/* Check vsid & api */
mmask = PTE64_CHECK_MASK;
pp = (pte1 & HPTE64_R_PP) | ((pte1 & HPTE64_R_PP0) >> 61);
/* No execute if either noexec or guarded bits set */
- ctx->nx = (pte1 & HPTE64_R_N) || (pte1 & HPTE64_R_G);
+ nx = (pte1 & HPTE64_R_N) || (pte1 & HPTE64_R_G);
if (HPTE64_V_COMPARE(pte0, ctx->ptem)) {
if (ctx->raddr != (hwaddr)-1ULL) {
/* all matches should have equal RPN, WIMG & PP */
@@ -326,7 +327,7 @@ static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
}
}
/* Compute access rights */
- access = ppc_hash64_pp_check(ctx->key, pp, ctx->nx);
+ access = ppc_hash64_pp_check(ctx->key, pp, nx);
/* Keep the matching PTE informations */
ctx->raddr = pte1;
ctx->prot = access;
@@ -466,7 +467,6 @@ static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
: (slb->vsid & SLB_VSID_KS));
- ctx->nx = !!(slb->vsid & SLB_VSID_N);
pageaddr = eaddr & ((1ULL << segment_bits)
- (1ULL << target_page_bits));
@@ -480,11 +480,11 @@ static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
LOG_MMU("pte segment: key=%d nx %d vsid " TARGET_FMT_lx "\n",
- ctx->key, ctx->nx, vsid);
+ ctx->key, !!(slb->vsid & SLB_VSID_N), vsid);
ret = -1;
/* Check if instruction fetch is allowed, if needed */
- if (rwx != 2 || ctx->nx == 0) {
+ if (rwx != 2 || !(slb->vsid & SLB_VSID_N)) {
/* Page address translation */
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 20/48] mmu-hash*: Remove eaddr field from mmu_ctx_hash{32, 64}
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (18 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 19/48] mmu-hash64: Remove nx from mmu_ctx_hash64 David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 21/48] mmu-hash*: Combine ppc_hash{32, 64}_get_physical_address and get_segment{32, 64}() David Gibson
` (28 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
The eaddr field of mmu_ctx_hash{32,64} is effectively just used to pass the
effective address from get_segment{32,64}() to find_pte{32,64}(). Just
pass it as a normal parameter instead.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 12 +++++-------
target-ppc/mmu-hash64.c | 12 +++++-------
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index ad5ef44..8001563 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -43,7 +43,6 @@
struct mmu_ctx_hash32 {
hwaddr raddr; /* Real address */
- hwaddr eaddr; /* Effective address */
int prot; /* Protection bits */
hwaddr hash[2]; /* Pagetable hash values */
target_ulong ptem; /* Virtual segment ID | API */
@@ -314,8 +313,8 @@ hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
}
/* PTE table lookup */
-static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
- int rwx, int target_page_bits)
+static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
+ target_ulong eaddr, int h, int rwx, int target_page_bits)
{
hwaddr pteg_off;
target_ulong pte0, pte1;
@@ -371,7 +370,7 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
/* We have a TLB that saves 4K pages, so let's
* split a huge page to 4k chunks */
if (target_page_bits != TARGET_PAGE_BITS) {
- ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
+ ctx->raddr |= (eaddr & ((1 << target_page_bits) - 1))
& TARGET_PAGE_MASK;
}
return ret;
@@ -387,7 +386,6 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong sr, pgidx;
pr = msr_pr;
- ctx->eaddr = eaddr;
sr = env->sr[eaddr >> 28];
ctx->key = (((sr & SR32_KP) && (pr != 0)) ||
@@ -426,14 +424,14 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
env->htab_base, env->htab_mask, vsid, ctx->ptem,
ctx->hash[0]);
/* Primary table lookup */
- ret = find_pte32(env, ctx, 0, rwx, target_page_bits);
+ ret = find_pte32(env, ctx, eaddr, 0, rwx, target_page_bits);
if (ret < 0) {
/* Secondary table lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte32(env, ctx, 1, rwx, target_page_bits);
+ ret2 = find_pte32(env, ctx, eaddr, 1, rwx, target_page_bits);
if (ret2 != -1) {
ret = ret2;
}
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index f89d005..407c6e6 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -42,7 +42,6 @@
struct mmu_ctx_hash64 {
hwaddr raddr; /* Real address */
- hwaddr eaddr; /* Effective address */
int prot; /* Protection bits */
hwaddr hash[2]; /* Pagetable hash values */
target_ulong ptem; /* Virtual segment ID | API */
@@ -372,8 +371,8 @@ static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
}
/* PTE table lookup */
-static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
- int rwx, int target_page_bits)
+static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
+ target_ulong eaddr, int h, int rwx, int target_page_bits)
{
hwaddr pteg_off;
target_ulong pte0, pte1;
@@ -429,7 +428,7 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx, int h,
/* We have a TLB that saves 4K pages, so let's
* split a huge page to 4k chunks */
if (target_page_bits != TARGET_PAGE_BITS) {
- ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
+ ctx->raddr |= (eaddr & ((1 << target_page_bits) - 1))
& TARGET_PAGE_MASK;
}
return ret;
@@ -444,7 +443,6 @@ static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
int ret, ret2;
pr = msr_pr;
- ctx->eaddr = eaddr;
ppc_slb_t *slb;
target_ulong pageaddr;
int segment_bits;
@@ -500,14 +498,14 @@ static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
env->htab_base, env->htab_mask, vsid, ctx->ptem,
ctx->hash[0]);
/* Primary table lookup */
- ret = find_pte64(env, ctx, 0, rwx, target_page_bits);
+ ret = find_pte64(env, ctx, eaddr, 0, rwx, target_page_bits);
if (ret < 0) {
/* Secondary table lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte64(env, ctx, 1, rwx, target_page_bits);
+ ret2 = find_pte64(env, ctx, eaddr, 1, rwx, target_page_bits);
if (ret2 != -1) {
ret = ret2;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 21/48] mmu-hash*: Combine ppc_hash{32, 64}_get_physical_address and get_segment{32, 64}()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (19 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 20/48] mmu-hash*: Remove eaddr field from mmu_ctx_hash{32, 64} David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 22/48] mmu-hash32: Split out handling of direct store segments David Gibson
` (27 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
After previous work, ppc_hash{32,64}_get_physical_address() are almost
trivial wrappers around get_segment{32,64}() which does nearly all the work of
translating an address according to the hash mmu model. Therefore combine the
two functions into one, under the better name of
ppc_hash{32,64}_translate().
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 49 +++++++++++++++++++----------------------------
target-ppc/mmu-hash64.c | 37 +++++++++++++++--------------------
2 files changed, 35 insertions(+), 51 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 8001563..bc97834 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -376,8 +376,8 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
return ret;
}
-static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong eaddr, int rwx)
+static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
+ target_ulong eaddr, int rwx)
{
hwaddr hash;
target_ulong vsid;
@@ -385,6 +385,22 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
int ret, ret2;
target_ulong sr, pgidx;
+ /* 1. Handle real mode accesses */
+ if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
+ /* Translation is off */
+ ctx->raddr = eaddr;
+ ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
+ return 0;
+ }
+
+ /* 2. Check Block Address Translation entries (BATs) */
+ if (env->nb_BATs != 0) {
+ ret = ppc_hash32_get_bat(env, ctx, eaddr, rwx);
+ if (ret == 0) {
+ return 0;
+ }
+ }
+
pr = msr_pr;
sr = env->sr[eaddr >> 28];
@@ -521,38 +537,13 @@ static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
return ret;
}
-static int ppc_hash32_get_physical_address(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong eaddr, int rwx)
-{
- bool real_mode = (rwx == 2 && msr_ir == 0)
- || (rwx != 2 && msr_dr == 0);
-
- if (real_mode) {
- ctx->raddr = eaddr;
- ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
- return 0;
- } else {
- int ret = -1;
-
- /* Try to find a BAT */
- if (env->nb_BATs != 0) {
- ret = ppc_hash32_get_bat(env, ctx, eaddr, rwx);
- }
- if (ret < 0) {
- /* We didn't match any BAT entry or don't have BATs */
- ret = get_segment32(env, ctx, eaddr, rwx);
- }
- return ret;
- }
-}
-
hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
struct mmu_ctx_hash32 ctx;
/* FIXME: Will not behave sanely for direct store segments, but
* they're almost never used */
- if (unlikely(ppc_hash32_get_physical_address(env, &ctx, addr, 0)
+ if (unlikely(ppc_hash32_translate(env, &ctx, addr, 0)
!= 0)) {
return -1;
}
@@ -566,7 +557,7 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
struct mmu_ctx_hash32 ctx;
int ret = 0;
- ret = ppc_hash32_get_physical_address(env, &ctx, address, rwx);
+ ret = ppc_hash32_translate(env, &ctx, address, rwx);
if (ret == 0) {
tlb_set_page(env, address & TARGET_PAGE_MASK,
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 407c6e6..9afc418 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -434,19 +434,28 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
return ret;
}
-static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
- target_ulong eaddr, int rwx)
+static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
+ target_ulong eaddr, int rwx)
{
hwaddr hash;
target_ulong vsid;
int pr, target_page_bits;
int ret, ret2;
-
- pr = msr_pr;
ppc_slb_t *slb;
target_ulong pageaddr;
int segment_bits;
+ /* 1. Handle real mode accesses */
+ if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
+ /* Translation is off */
+ /* In real mode the top 4 effective address bits are ignored */
+ ctx->raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
+ ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
+ return 0;
+ }
+
+ pr = msr_pr;
+
LOG_MMU("Check SLBs\n");
slb = slb_lookup(env, eaddr);
if (!slb) {
@@ -518,27 +527,11 @@ static int get_segment64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
return ret;
}
-static int ppc_hash64_get_physical_address(CPUPPCState *env,
- struct mmu_ctx_hash64 *ctx,
- target_ulong eaddr, int rwx)
-{
- bool real_mode = (rwx == 2 && msr_ir == 0)
- || (rwx != 2 && msr_dr == 0);
-
- if (real_mode) {
- ctx->raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
- ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
- return 0;
- } else {
- return get_segment64(env, ctx, eaddr, rwx);
- }
-}
-
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
struct mmu_ctx_hash64 ctx;
- if (unlikely(ppc_hash64_get_physical_address(env, &ctx, addr, 0) != 0)) {
+ if (unlikely(ppc_hash64_translate(env, &ctx, addr, 0) != 0)) {
return -1;
}
@@ -551,7 +544,7 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
struct mmu_ctx_hash64 ctx;
int ret = 0;
- ret = ppc_hash64_get_physical_address(env, &ctx, address, rwx);
+ ret = ppc_hash64_translate(env, &ctx, address, rwx);
if (ret == 0) {
tlb_set_page(env, address & TARGET_PAGE_MASK,
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 22/48] mmu-hash32: Split out handling of direct store segments
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (20 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 21/48] mmu-hash*: Combine ppc_hash{32, 64}_get_physical_address and get_segment{32, 64}() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 23/48] mmu-hash32: Split direct store segment handling into a helper David Gibson
` (26 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
At present a large chunk of ppc_hash32_translate() is taken up with an
ugly if selecting between direct store segments (hardly ever used) and
normal paged segments. This patch clarifies the flow of code by
handling direct store segments immediately then returning, leaving the
straight line code to describe the normal MMU path.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 156 +++++++++++++++++++++++------------------------
1 file changed, 78 insertions(+), 78 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index bc97834..04ddf1d 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -381,7 +381,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
{
hwaddr hash;
target_ulong vsid;
- int ds, pr, target_page_bits;
+ int pr, target_page_bits;
int ret, ret2;
target_ulong sr, pgidx;
@@ -401,91 +401,21 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
}
}
- pr = msr_pr;
-
+ /* 3. Look up the Segment Register */
sr = env->sr[eaddr >> 28];
+
+ pr = msr_pr;
ctx->key = (((sr & SR32_KP) && (pr != 0)) ||
((sr & SR32_KS) && (pr == 0))) ? 1 : 0;
- ds = !!(sr & SR32_T);
- ctx->nx = !!(sr & SR32_NX);
- vsid = sr & SR32_VSID;
- target_page_bits = TARGET_PAGE_BITS;
- LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
- TARGET_FMT_lx " lr=" TARGET_FMT_lx
- " ir=%d dr=%d pr=%d %d\n",
- eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
- (int)msr_dr, pr != 0 ? 1 : 0, rwx);
- pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
- hash = vsid ^ pgidx;
- ctx->ptem = (vsid << 7) | (pgidx >> 10);
-
- LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
- ctx->key, ds, ctx->nx, vsid);
- ret = -1;
- if (!ds) {
- /* Check if instruction fetch is allowed, if needed */
- if (rwx != 2 || ctx->nx == 0) {
- /* Page address translation */
- LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
- " hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
- ctx->hash[0] = hash;
- ctx->hash[1] = ~hash;
-
- /* Initialize real address with an invalid value */
- ctx->raddr = (hwaddr)-1ULL;
- LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ctx->ptem,
- ctx->hash[0]);
- /* Primary table lookup */
- ret = find_pte32(env, ctx, eaddr, 0, rwx, target_page_bits);
- if (ret < 0) {
- /* Secondary table lookup */
- LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte32(env, ctx, eaddr, 1, rwx, target_page_bits);
- if (ret2 != -1) {
- ret = ret2;
- }
- }
-#if defined(DUMP_PAGE_TABLES)
- if (qemu_log_enabled()) {
- hwaddr curaddr;
- uint32_t a0, a1, a2, a3;
-
- qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
- "\n", sdr, mask + 0x80);
- for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
- curaddr += 16) {
- a0 = ldl_phys(curaddr);
- a1 = ldl_phys(curaddr + 4);
- a2 = ldl_phys(curaddr + 8);
- a3 = ldl_phys(curaddr + 12);
- if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
- qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
- curaddr, a0, a1, a2, a3);
- }
- }
- }
-#endif
- } else {
- LOG_MMU("No access allowed\n");
- ret = -3;
- }
- } else {
- target_ulong sr;
+ /* 4. Handle direct store segments */
+ if (sr & SR32_T) {
LOG_MMU("direct store...\n");
/* Direct-store segment : absolutely *BUGGY* for now */
/* Direct-store implies a 32-bit MMU.
* Check the Segment Register's bus unit ID (BUID).
*/
- sr = env->sr[eaddr >> 28];
if ((sr & 0x1FF00000) >> 20 == 0x07f) {
/* Memory-forced I/O controller interface access */
/* If T=1 and BUID=x'07F', the 601 performs a memory access
@@ -528,10 +458,80 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
}
if ((rwx == 1 || ctx->key != 1) && (rwx == 0 || ctx->key != 0)) {
ctx->raddr = eaddr;
- ret = 2;
+ return 2;
} else {
- ret = -2;
+ return -2;
+ }
+ }
+
+ ctx->nx = !!(sr & SR32_NX);
+ vsid = sr & SR32_VSID;
+ target_page_bits = TARGET_PAGE_BITS;
+ LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
+ TARGET_FMT_lx " lr=" TARGET_FMT_lx
+ " ir=%d dr=%d pr=%d %d\n",
+ eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
+ (int)msr_dr, pr != 0 ? 1 : 0, rwx);
+ pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+ hash = vsid ^ pgidx;
+ ctx->ptem = (vsid << 7) | (pgidx >> 10);
+
+ LOG_MMU("pte segment: key=%d nx %d vsid " TARGET_FMT_lx "\n",
+ ctx->key, ctx->nx, vsid);
+ ret = -1;
+
+ /* Check if instruction fetch is allowed, if needed */
+ if (rwx != 2 || ctx->nx == 0) {
+ /* Page address translation */
+ LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+ " hash " TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, hash);
+ ctx->hash[0] = hash;
+ ctx->hash[1] = ~hash;
+
+ /* Initialize real address with an invalid value */
+ ctx->raddr = (hwaddr)-1ULL;
+ LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, vsid, ctx->ptem,
+ ctx->hash[0]);
+ /* Primary table lookup */
+ ret = find_pte32(env, ctx, eaddr, 0, rwx, target_page_bits);
+ if (ret < 0) {
+ /* Secondary table lookup */
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+ ret2 = find_pte32(env, ctx, eaddr, 1, rwx, target_page_bits);
+ if (ret2 != -1) {
+ ret = ret2;
+ }
}
+#if defined(DUMP_PAGE_TABLES)
+ if (qemu_log_enabled()) {
+ hwaddr curaddr;
+ uint32_t a0, a1, a2, a3;
+
+ qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
+ "\n", sdr, mask + 0x80);
+ for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
+ curaddr += 16) {
+ a0 = ldl_phys(curaddr);
+ a1 = ldl_phys(curaddr + 4);
+ a2 = ldl_phys(curaddr + 8);
+ a3 = ldl_phys(curaddr + 12);
+ if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
+ qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
+ curaddr, a0, a1, a2, a3);
+ }
+ }
+ }
+#endif
+ } else {
+ LOG_MMU("No access allowed\n");
+ ret = -3;
}
return ret;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 23/48] mmu-hash32: Split direct store segment handling into a helper
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (21 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 22/48] mmu-hash32: Split out handling of direct store segments David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 24/48] mmu-hash*: Cleanup segment-level NX check David Gibson
` (25 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
This further separates the unusual case handling of direct store segments
from the main translation path by moving its logic into a helper function,
with some tiny cleanups along the way.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 117 ++++++++++++++++++++++++-----------------------
1 file changed, 61 insertions(+), 56 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 04ddf1d..dbde264 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -243,6 +243,62 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
return ret;
}
+static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
+ target_ulong eaddr, int rwx,
+ hwaddr *raddr, int *prot)
+{
+ int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
+
+ LOG_MMU("direct store...\n");
+
+ if ((sr & 0x1FF00000) >> 20 == 0x07f) {
+ /* Memory-forced I/O controller interface access */
+ /* If T=1 and BUID=x'07F', the 601 performs a memory access
+ * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
+ */
+ *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return 0;
+ }
+
+ if (rwx == 2) {
+ /* No code fetch is allowed in direct-store areas */
+ return -4;
+ }
+
+ switch (env->access_type) {
+ case ACCESS_INT:
+ /* Integer load/store : only access allowed */
+ break;
+ case ACCESS_FLOAT:
+ /* Floating point load/store */
+ return -4;
+ case ACCESS_RES:
+ /* lwarx, ldarx or srwcx. */
+ return -4;
+ case ACCESS_CACHE:
+ /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
+ /* Should make the instruction do no-op.
+ * As it already do no-op, it's quite easy :-)
+ */
+ *raddr = eaddr;
+ return 0;
+ case ACCESS_EXT:
+ /* eciwx or ecowx */
+ return -4;
+ default:
+ qemu_log("ERROR: instruction should not need "
+ "address translation\n");
+ return -4;
+ }
+ if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
+ *raddr = eaddr;
+ return 2;
+ } else {
+ return -2;
+ }
+}
+
static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
target_ulong pte1, int h, int rwx)
{
@@ -404,66 +460,15 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
/* 3. Look up the Segment Register */
sr = env->sr[eaddr >> 28];
- pr = msr_pr;
- ctx->key = (((sr & SR32_KP) && (pr != 0)) ||
- ((sr & SR32_KS) && (pr == 0))) ? 1 : 0;
-
/* 4. Handle direct store segments */
if (sr & SR32_T) {
- LOG_MMU("direct store...\n");
- /* Direct-store segment : absolutely *BUGGY* for now */
-
- /* Direct-store implies a 32-bit MMU.
- * Check the Segment Register's bus unit ID (BUID).
- */
- if ((sr & 0x1FF00000) >> 20 == 0x07f) {
- /* Memory-forced I/O controller interface access */
- /* If T=1 and BUID=x'07F', the 601 performs a memory access
- * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
- */
- ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
- ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return 0;
- }
-
- if (rwx == 2) {
- /* No code fetch is allowed in direct-store areas */
- return -4;
- }
-
- switch (env->access_type) {
- case ACCESS_INT:
- /* Integer load/store : only access allowed */
- break;
- case ACCESS_FLOAT:
- /* Floating point load/store */
- return -4;
- case ACCESS_RES:
- /* lwarx, ldarx or srwcx. */
- return -4;
- case ACCESS_CACHE:
- /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
- /* Should make the instruction do no-op.
- * As it already do no-op, it's quite easy :-)
- */
- ctx->raddr = eaddr;
- return 0;
- case ACCESS_EXT:
- /* eciwx or ecowx */
- return -4;
- default:
- qemu_log("ERROR: instruction should not need "
- "address translation\n");
- return -4;
- }
- if ((rwx == 1 || ctx->key != 1) && (rwx == 0 || ctx->key != 0)) {
- ctx->raddr = eaddr;
- return 2;
- } else {
- return -2;
- }
+ return ppc_hash32_direct_store(env, sr, eaddr, rwx,
+ &ctx->raddr, &ctx->prot);
}
+ pr = msr_pr;
+ ctx->key = (((sr & SR32_KP) && (pr != 0)) ||
+ ((sr & SR32_KS) && (pr == 0))) ? 1 : 0;
ctx->nx = !!(sr & SR32_NX);
vsid = sr & SR32_VSID;
target_page_bits = TARGET_PAGE_BITS;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 24/48] mmu-hash*: Cleanup segment-level NX check
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (22 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 23/48] mmu-hash32: Split direct store segment handling into a helper David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 25/48] mmu-hash*: Don't keep looking for PTEs after we find a match David Gibson
` (24 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
On the ppc hash mmus, no-execute can be set at the segment level (on more
recent 64-bit hash mmus it can also be set at the page level). This patch
separates out this check to make it clearer what is going on, and avoiding
excessive indentation of the remaining translation code.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 98 +++++++++++++++++++++++------------------------
target-ppc/mmu-hash64.c | 68 ++++++++++++++++----------------
2 files changed, 83 insertions(+), 83 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index dbde264..d812adb 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -466,10 +466,16 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
&ctx->raddr, &ctx->prot);
}
+ /* 5. Check for segment level no-execute violation */
+ ctx->nx = !!(sr & SR32_NX);
+ if ((rwx == 2) && ctx->nx) {
+ return -3;
+ }
+
pr = msr_pr;
ctx->key = (((sr & SR32_KP) && (pr != 0)) ||
((sr & SR32_KS) && (pr == 0))) ? 1 : 0;
- ctx->nx = !!(sr & SR32_NX);
+
vsid = sr & SR32_VSID;
target_page_bits = TARGET_PAGE_BITS;
LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
@@ -485,59 +491,53 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
ctx->key, ctx->nx, vsid);
ret = -1;
- /* Check if instruction fetch is allowed, if needed */
- if (rwx != 2 || ctx->nx == 0) {
- /* Page address translation */
- LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
- " hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
- ctx->hash[0] = hash;
- ctx->hash[1] = ~hash;
-
- /* Initialize real address with an invalid value */
- ctx->raddr = (hwaddr)-1ULL;
- LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ctx->ptem,
- ctx->hash[0]);
- /* Primary table lookup */
- ret = find_pte32(env, ctx, eaddr, 0, rwx, target_page_bits);
- if (ret < 0) {
- /* Secondary table lookup */
- LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte32(env, ctx, eaddr, 1, rwx, target_page_bits);
- if (ret2 != -1) {
- ret = ret2;
- }
+ /* Page address translation */
+ LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+ " hash " TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, hash);
+ ctx->hash[0] = hash;
+ ctx->hash[1] = ~hash;
+
+ /* Initialize real address with an invalid value */
+ ctx->raddr = (hwaddr)-1ULL;
+ LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, vsid, ctx->ptem,
+ ctx->hash[0]);
+ /* Primary table lookup */
+ ret = find_pte32(env, ctx, eaddr, 0, rwx, target_page_bits);
+ if (ret < 0) {
+ /* Secondary table lookup */
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+ ret2 = find_pte32(env, ctx, eaddr, 1, rwx, target_page_bits);
+ if (ret2 != -1) {
+ ret = ret2;
}
+ }
#if defined(DUMP_PAGE_TABLES)
- if (qemu_log_enabled()) {
- hwaddr curaddr;
- uint32_t a0, a1, a2, a3;
-
- qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
- "\n", sdr, mask + 0x80);
- for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
- curaddr += 16) {
- a0 = ldl_phys(curaddr);
- a1 = ldl_phys(curaddr + 4);
- a2 = ldl_phys(curaddr + 8);
- a3 = ldl_phys(curaddr + 12);
- if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
- qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
- curaddr, a0, a1, a2, a3);
- }
+ if (qemu_log_enabled()) {
+ hwaddr curaddr;
+ uint32_t a0, a1, a2, a3;
+
+ qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
+ "\n", sdr, mask + 0x80);
+ for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
+ curaddr += 16) {
+ a0 = ldl_phys(curaddr);
+ a1 = ldl_phys(curaddr + 4);
+ a2 = ldl_phys(curaddr + 8);
+ a3 = ldl_phys(curaddr + 12);
+ if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
+ qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
+ curaddr, a0, a1, a2, a3);
}
}
-#endif
- } else {
- LOG_MMU("No access allowed\n");
- ret = -3;
}
+#endif
return ret;
}
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 9afc418..4fb7ecd 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -454,14 +454,20 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
return 0;
}
- pr = msr_pr;
-
- LOG_MMU("Check SLBs\n");
+ /* 2. Translation is on, so look up the SLB */
slb = slb_lookup(env, eaddr);
+
if (!slb) {
return -5;
}
+ /* 3. Check for segment level no-execute violation */
+ if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
+ return -3;
+ }
+
+ pr = msr_pr;
+
if (slb->vsid & SLB_VSID_B) {
vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
segment_bits = 40;
@@ -490,38 +496,32 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ctx->key, !!(slb->vsid & SLB_VSID_N), vsid);
ret = -1;
- /* Check if instruction fetch is allowed, if needed */
- if (rwx != 2 || !(slb->vsid & SLB_VSID_N)) {
- /* Page address translation */
- LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
- " hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
- ctx->hash[0] = hash;
- ctx->hash[1] = ~hash;
-
- /* Initialize real address with an invalid value */
- ctx->raddr = (hwaddr)-1ULL;
- LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ctx->ptem,
- ctx->hash[0]);
- /* Primary table lookup */
- ret = find_pte64(env, ctx, eaddr, 0, rwx, target_page_bits);
- if (ret < 0) {
- /* Secondary table lookup */
- LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte64(env, ctx, eaddr, 1, rwx, target_page_bits);
- if (ret2 != -1) {
- ret = ret2;
- }
+ /* Page address translation */
+ LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+ " hash " TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, hash);
+ ctx->hash[0] = hash;
+ ctx->hash[1] = ~hash;
+
+ /* Initialize real address with an invalid value */
+ ctx->raddr = (hwaddr)-1ULL;
+ LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, vsid, ctx->ptem,
+ ctx->hash[0]);
+ /* Primary table lookup */
+ ret = find_pte64(env, ctx, eaddr, 0, rwx, target_page_bits);
+ if (ret < 0) {
+ /* Secondary table lookup */
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
+ ret2 = find_pte64(env, ctx, eaddr, 1, rwx, target_page_bits);
+ if (ret2 != -1) {
+ ret = ret2;
}
- } else {
- LOG_MMU("No access allowed\n");
- ret = -3;
}
return ret;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 25/48] mmu-hash*: Don't keep looking for PTEs after we find a match
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (23 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 24/48] mmu-hash*: Cleanup segment-level NX check David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 26/48] mmu-hash*: Separate PTEG searching from permissions checking David Gibson
` (23 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
BEHAVIOUR CHANGE
The ppc hash mmu hashes each virtual address to a primary and secondary
possible hash bucket (aka PTE group or PTEG) each with 8 PTEs. Then we
need a linear search through the PTEs to find the correct one for the
virtual address we're translating.
It is a programming error for the guest to insert multiple PTEs mapping the
same virtual address into a PTEG - in this case the ppc architecture says
the MMU can either act as if just one was present, or give a machine check.
Currently our code takes the first matching PTE in a PTEG if it finds a
successful translation. But if a matching PTE is found, but permission
bits don't allow the access, we keep looking through the PTEG, checking
that any other matching PTEs contain an identical translation.
That behaviour is perhaps not exactly wrong, but it's certainly not useful.
This patch changes it to always just find the first matching PTE in a PTEG.
In addition, if we get a permissions problem on the primary PTEG, we then
search the secondary PTEG. This is incorrect - a permission denying PTE
in the primary PTEG should not be overwritten by an access granting PTE in
the secondary (although again, it would be a programming error for the
guest to set up such a situation anyway). So additionally we update the
code to only search the secondary PTEG if no matching PTE is found in the
primary at all.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 86 ++++++++++++++----------------------------
target-ppc/mmu-hash64.c | 96 ++++++++++++++++-------------------------------
2 files changed, 60 insertions(+), 122 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index d812adb..3be1002 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -50,8 +50,6 @@ struct mmu_ctx_hash32 {
int nx; /* Non-execute area */
};
-#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
-
static int ppc_hash32_pp_check(int key, int pp, int nx)
{
int access;
@@ -299,40 +297,32 @@ static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
}
}
+static bool pte32_match(target_ulong pte0, target_ulong pte1,
+ bool secondary, target_ulong ptem)
+{
+ return (pte0 & HPTE32_V_VALID)
+ && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
+ && HPTE32_V_COMPARE(pte0, ptem);
+}
+
static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rwx)
+ target_ulong pte1, int rwx)
{
- target_ulong mmask;
int access, ret, pp;
- ret = -1;
- /* Check validity and table match */
- if ((pte0 & HPTE32_V_VALID) && (h == !!(pte0 & HPTE32_V_SECONDARY))) {
- /* Check vsid & api */
- mmask = PTE_CHECK_MASK;
- pp = pte1 & HPTE32_R_PP;
- if (HPTE32_V_COMPARE(pte0, ctx->ptem)) {
- if (ctx->raddr != (hwaddr)-1ULL) {
- /* all matches should have equal RPN, WIMG & PP */
- if ((ctx->raddr & mmask) != (pte1 & mmask)) {
- qemu_log("Bad RPN/WIMG/PP\n");
- return -3;
- }
- }
- /* Compute access rights */
- access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
- /* Keep the matching PTE informations */
- ctx->raddr = pte1;
- ctx->prot = access;
- ret = ppc_hash32_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- /* Access granted */
- LOG_MMU("PTE access granted !\n");
- } else {
- /* Access right violation */
- LOG_MMU("PTE access rejected\n");
- }
- }
+ pp = pte1 & HPTE32_R_PP;
+ /* Compute access rights */
+ access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte1;
+ ctx->prot = access;
+ ret = ppc_hash32_check_prot(ctx->prot, rwx);
+ if (ret == 0) {
+ /* Access granted */
+ LOG_MMU("PTE access granted !\n");
+ } else {
+ /* Access right violation */
+ LOG_MMU("PTE access rejected\n");
}
return ret;
@@ -375,44 +365,26 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
hwaddr pteg_off;
target_ulong pte0, pte1;
int i, good = -1;
- int ret, r;
+ int ret;
ret = -1; /* No entry found */
pteg_off = get_pteg_offset32(env, ctx->hash[h]);
for (i = 0; i < HPTES_PER_GROUP; i++) {
pte0 = ppc_hash32_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_32);
pte1 = ppc_hash32_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_32);
- r = pte_check_hash32(ctx, pte0, pte1, h, rwx);
+
LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
(int)((pte0 >> 6) & 1), ctx->ptem);
- switch (r) {
- case -3:
- /* PTE inconsistency */
- return -1;
- case -2:
- /* Access violation */
- ret = -2;
+
+ if (pte32_match(pte0, pte1, h, ctx->ptem)) {
good = i;
break;
- case -1:
- default:
- /* No PTE match */
- break;
- case 0:
- /* access granted */
- /* XXX: we should go on looping to check all PTEs consistency
- * but if we can speed-up the whole thing as the
- * result would be undefined if PTEs are not consistent.
- */
- ret = 0;
- good = i;
- goto done;
}
}
if (good != -1) {
- done:
+ ret = pte_check_hash32(ctx, pte0, pte1, rwx);
LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
ctx->raddr, ctx->prot, ret);
/* Update page flags */
@@ -498,8 +470,6 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
ctx->hash[0] = hash;
ctx->hash[1] = ~hash;
- /* Initialize real address with an invalid value */
- ctx->raddr = (hwaddr)-1ULL;
LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n",
@@ -507,7 +477,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
ctx->hash[0]);
/* Primary table lookup */
ret = find_pte32(env, ctx, eaddr, 0, rwx, target_page_bits);
- if (ret < 0) {
+ if (ret == -1) {
/* Secondary table lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 4fb7ecd..8664116 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -231,8 +231,6 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
* 64-bit hash table MMU handling
*/
-#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
-
static int ppc_hash64_pp_check(int key, int pp, bool nx)
{
int access;
@@ -301,44 +299,35 @@ static int ppc_hash64_check_prot(int prot, int rwx)
return ret;
}
+static bool pte64_match(target_ulong pte0, target_ulong pte1,
+ bool secondary, target_ulong ptem)
+{
+ return (pte0 & HPTE64_V_VALID)
+ && (secondary == !!(pte0 & HPTE64_V_SECONDARY))
+ && HPTE64_V_COMPARE(pte0, ptem);
+}
+
static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
- target_ulong pte1, int h, int rwx)
+ target_ulong pte1, int rwx)
{
- target_ulong mmask;
int access, ret, pp;
+ bool nx;
- ret = -1;
- /* Check validity and table match */
- if ((pte0 & HPTE64_V_VALID) && (h == !!(pte0 & HPTE64_V_SECONDARY))) {
- bool nx;
-
- /* Check vsid & api */
- mmask = PTE64_CHECK_MASK;
- pp = (pte1 & HPTE64_R_PP) | ((pte1 & HPTE64_R_PP0) >> 61);
- /* No execute if either noexec or guarded bits set */
- nx = (pte1 & HPTE64_R_N) || (pte1 & HPTE64_R_G);
- if (HPTE64_V_COMPARE(pte0, ctx->ptem)) {
- if (ctx->raddr != (hwaddr)-1ULL) {
- /* all matches should have equal RPN, WIMG & PP */
- if ((ctx->raddr & mmask) != (pte1 & mmask)) {
- qemu_log("Bad RPN/WIMG/PP\n");
- return -3;
- }
- }
- /* Compute access rights */
- access = ppc_hash64_pp_check(ctx->key, pp, nx);
- /* Keep the matching PTE informations */
- ctx->raddr = pte1;
- ctx->prot = access;
- ret = ppc_hash64_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- /* Access granted */
- LOG_MMU("PTE access granted !\n");
- } else {
- /* Access right violation */
- LOG_MMU("PTE access rejected\n");
- }
- }
+ pp = (pte1 & HPTE64_R_PP) | ((pte1 & HPTE64_R_PP0) >> 61);
+ /* No execute if either noexec or guarded bits set */
+ nx = (pte1 & HPTE64_R_N) || (pte1 & HPTE64_R_G);
+ /* Compute access rights */
+ access = ppc_hash64_pp_check(ctx->key, pp, nx);
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte1;
+ ctx->prot = access;
+ ret = ppc_hash64_check_prot(ctx->prot, rwx);
+ if (ret == 0) {
+ /* Access granted */
+ LOG_MMU("PTE access granted !\n");
+ } else {
+ /* Access right violation */
+ LOG_MMU("PTE access rejected\n");
}
return ret;
@@ -377,7 +366,7 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
hwaddr pteg_off;
target_ulong pte0, pte1;
int i, good = -1;
- int ret, r;
+ int ret;
ret = -1; /* No entry found */
pteg_off = (ctx->hash[h] * HASH_PTEG_SIZE_64) & env->htab_mask;
@@ -385,37 +374,18 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
pte0 = ppc_hash64_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_64);
pte1 = ppc_hash64_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_64);
- r = pte64_check(ctx, pte0, pte1, h, rwx);
LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " "
TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
- pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
- (int)((pte0 >> 1) & 1), ctx->ptem);
- switch (r) {
- case -3:
- /* PTE inconsistency */
- return -1;
- case -2:
- /* Access violation */
- ret = -2;
+ pteg_off + (i * 16), pte0, pte1, !!(pte0 & HPTE64_V_VALID),
+ h, !!(pte0 & HPTE64_V_SECONDARY), ctx->ptem);
+
+ if (pte64_match(pte0, pte1, h, ctx->ptem)) {
good = i;
break;
- case -1:
- default:
- /* No PTE match */
- break;
- case 0:
- /* access granted */
- /* XXX: we should go on looping to check all PTEs consistency
- * but if we can speed-up the whole thing as the
- * result would be undefined if PTEs are not consistent.
- */
- ret = 0;
- good = i;
- goto done;
}
}
if (good != -1) {
- done:
+ ret = pte64_check(ctx, pte0, pte1, rwx);
LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
ctx->raddr, ctx->prot, ret);
/* Update page flags */
@@ -503,8 +473,6 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ctx->hash[0] = hash;
ctx->hash[1] = ~hash;
- /* Initialize real address with an invalid value */
- ctx->raddr = (hwaddr)-1ULL;
LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n",
@@ -512,7 +480,7 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ctx->hash[0]);
/* Primary table lookup */
ret = find_pte64(env, ctx, eaddr, 0, rwx, target_page_bits);
- if (ret < 0) {
+ if (ret == -1) {
/* Secondary table lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 26/48] mmu-hash*: Separate PTEG searching from permissions checking
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (24 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 25/48] mmu-hash*: Don't keep looking for PTEs after we find a match David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 27/48] mmu-hash*: Make find_pte{32, 64} do more of the job of finding ptes David Gibson
` (22 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
find_pte{32,64{() do several things. First they search through a PTEG
ooking for a PTE matching our virtual address. Then they do permissions
checking and other processing on that PTE.
This patch separates the search by VA out from the rest. The search is
combined with the pte{32,64}_match() functions into new
ppc_has{32,64}_pteg_search() functions.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 69 ++++++++++++++++++++++++-----------------------
target-ppc/mmu-hash32.h | 4 +++
target-ppc/mmu-hash64.c | 67 ++++++++++++++++++++++-----------------------
target-ppc/mmu-hash64.h | 4 +++
4 files changed, 77 insertions(+), 67 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 3be1002..7c13a49 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -297,14 +297,6 @@ static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
}
}
-static bool pte32_match(target_ulong pte0, target_ulong pte1,
- bool secondary, target_ulong ptem)
-{
- return (pte0 & HPTE32_V_VALID)
- && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
- && HPTE32_V_COMPARE(pte0, ptem);
-}
-
static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
target_ulong pte1, int rwx)
{
@@ -328,8 +320,8 @@ static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
return ret;
}
-static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong *pte1p,
- int ret, int rwx)
+static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx,
+ uint32_t *pte1p, int ret, int rwx)
{
int store = 0;
@@ -358,40 +350,49 @@ hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
}
-/* PTE table lookup */
+static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
+ bool secondary, target_ulong ptem,
+ ppc_hash_pte32_t *pte)
+{
+ hwaddr pte_offset = pteg_off;
+ target_ulong pte0, pte1;
+ int i;
+
+ for (i = 0; i < HPTES_PER_GROUP; i++) {
+ pte0 = ppc_hash32_load_hpte0(env, pte_offset);
+ pte1 = ppc_hash32_load_hpte1(env, pte_offset);
+
+ if ((pte0 & HPTE32_V_VALID)
+ && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
+ && HPTE32_V_COMPARE(pte0, ptem)) {
+ pte->pte0 = pte0;
+ pte->pte1 = pte1;
+ return pte_offset;
+ }
+
+ pte_offset += HASH_PTE_SIZE_32;
+ }
+
+ return -1;
+}
+
static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong eaddr, int h, int rwx, int target_page_bits)
{
- hwaddr pteg_off;
- target_ulong pte0, pte1;
- int i, good = -1;
+ hwaddr pteg_off, pte_offset;
+ ppc_hash_pte32_t pte;
int ret;
ret = -1; /* No entry found */
pteg_off = get_pteg_offset32(env, ctx->hash[h]);
- for (i = 0; i < HPTES_PER_GROUP; i++) {
- pte0 = ppc_hash32_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_32);
- pte1 = ppc_hash32_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_32);
-
- LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
- TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
- pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
- (int)((pte0 >> 6) & 1), ctx->ptem);
-
- if (pte32_match(pte0, pte1, h, ctx->ptem)) {
- good = i;
- break;
- }
- }
- if (good != -1) {
- ret = pte_check_hash32(ctx, pte0, pte1, rwx);
+ pte_offset = ppc_hash32_pteg_search(env, pteg_off, h, ctx->ptem, &pte);
+ if (pte_offset != -1) {
+ ret = pte_check_hash32(ctx, pte.pte0, pte.pte1, rwx);
LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
ctx->raddr, ctx->prot, ret);
/* Update page flags */
- pte1 = ctx->raddr;
- if (ppc_hash32_pte_update_flags(ctx, &pte1, ret, rwx) == 1) {
- ppc_hash32_store_hpte1(env, pteg_off + good * HASH_PTE_SIZE_32,
- pte1);
+ if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
+ ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
}
}
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index 2344184..f990edc 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -97,6 +97,10 @@ static inline void ppc_hash32_store_hpte1(CPUPPCState *env,
stl_phys(env->htab_base + pte_offset + HASH_PTE_SIZE_32/2, pte1);
}
+typedef struct {
+ uint32_t pte0, pte1;
+} ppc_hash_pte32_t;
+
#endif /* CONFIG_USER_ONLY */
#endif /* __MMU_HASH32_H__ */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 8664116..66b2d24 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -299,14 +299,6 @@ static int ppc_hash64_check_prot(int prot, int rwx)
return ret;
}
-static bool pte64_match(target_ulong pte0, target_ulong pte1,
- bool secondary, target_ulong ptem)
-{
- return (pte0 & HPTE64_V_VALID)
- && (secondary == !!(pte0 & HPTE64_V_SECONDARY))
- && HPTE64_V_COMPARE(pte0, ptem);
-}
-
static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
target_ulong pte1, int rwx)
{
@@ -334,8 +326,7 @@ static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
}
static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
- target_ulong *pte1p,
- int ret, int rw)
+ uint64_t *pte1p, int ret, int rw)
{
int store = 0;
@@ -359,39 +350,49 @@ static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
return store;
}
-/* PTE table lookup */
+static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
+ bool secondary, target_ulong ptem,
+ ppc_hash_pte64_t *pte)
+{
+ hwaddr pte_offset = pteg_off;
+ target_ulong pte0, pte1;
+ int i;
+
+ for (i = 0; i < HPTES_PER_GROUP; i++) {
+ pte0 = ppc_hash64_load_hpte0(env, pte_offset);
+ pte1 = ppc_hash64_load_hpte1(env, pte_offset);
+
+ if ((pte0 & HPTE64_V_VALID)
+ && (secondary == !!(pte0 & HPTE64_V_SECONDARY))
+ && HPTE64_V_COMPARE(pte0, ptem)) {
+ pte->pte0 = pte0;
+ pte->pte1 = pte1;
+ return pte_offset;
+ }
+
+ pte_offset += HASH_PTE_SIZE_64;
+ }
+
+ return -1;
+}
+
static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
target_ulong eaddr, int h, int rwx, int target_page_bits)
{
- hwaddr pteg_off;
- target_ulong pte0, pte1;
- int i, good = -1;
+ hwaddr pteg_off, pte_offset;
+ ppc_hash_pte64_t pte;
int ret;
ret = -1; /* No entry found */
pteg_off = (ctx->hash[h] * HASH_PTEG_SIZE_64) & env->htab_mask;
- for (i = 0; i < HPTES_PER_GROUP; i++) {
- pte0 = ppc_hash64_load_hpte0(env, pteg_off + i*HASH_PTE_SIZE_64);
- pte1 = ppc_hash64_load_hpte1(env, pteg_off + i*HASH_PTE_SIZE_64);
-
- LOG_MMU("Load pte from %016" HWADDR_PRIx " => " TARGET_FMT_lx " "
- TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
- pteg_off + (i * 16), pte0, pte1, !!(pte0 & HPTE64_V_VALID),
- h, !!(pte0 & HPTE64_V_SECONDARY), ctx->ptem);
-
- if (pte64_match(pte0, pte1, h, ctx->ptem)) {
- good = i;
- break;
- }
- }
- if (good != -1) {
- ret = pte64_check(ctx, pte0, pte1, rwx);
+ pte_offset = ppc_hash64_pteg_search(env, pteg_off, h, ctx->ptem, &pte);
+ if (pte_offset != -1) {
+ ret = pte64_check(ctx, pte.pte0, pte.pte1, rwx);
LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
ctx->raddr, ctx->prot, ret);
/* Update page flags */
- pte1 = ctx->raddr;
- if (ppc_hash64_pte_update_flags(ctx, &pte1, ret, rwx) == 1) {
- ppc_hash64_store_hpte1(env, pteg_off + good * HASH_PTE_SIZE_64, pte1);
+ if (ppc_hash64_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
+ ppc_hash64_store_hpte1(env, pte_offset, pte.pte1);
}
}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index a9c73d4..1ce6e5b 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -113,6 +113,10 @@ static inline void ppc_hash64_store_hpte1(CPUPPCState *env,
}
}
+typedef struct {
+ uint64_t pte0, pte1;
+} ppc_hash_pte64_t;
+
#endif /* CONFIG_USER_ONLY */
#endif /* !defined (__MMU_HASH64_H__) */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 27/48] mmu-hash*: Make find_pte{32, 64} do more of the job of finding ptes
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (25 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 26/48] mmu-hash*: Separate PTEG searching from permissions checking David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 28/48] mmu-hash*: Remove permission checking from find_pte{32, 64}() David Gibson
` (21 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
find_pte{32,64}() are not particularly well named. They only "find" a PTE
within a given PTE group, and they also do permissions checking and other
things.
This patch makes it somewhat close to matching the name, by folding the
search of both primary and secondary hash bucket into it, along with the
various address bit shuffling to determine the right hash buckets.
In the 32-bit case we also remove the code for splitting large pages into
4k pieces for the qemu tlb, since no 32-bit hash MMUs support multiple page
sizes.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 116 ++++++++++++++------------------------------
target-ppc/mmu-hash64.c | 123 ++++++++++++++++++++++-------------------------
2 files changed, 92 insertions(+), 147 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 7c13a49..b7a26a2 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -44,8 +44,6 @@
struct mmu_ctx_hash32 {
hwaddr raddr; /* Real address */
int prot; /* Protection bits */
- hwaddr hash[2]; /* Pagetable hash values */
- target_ulong ptem; /* Virtual segment ID | API */
int key; /* Access key */
int nx; /* Non-execute area */
};
@@ -377,15 +375,44 @@ static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
}
static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong eaddr, int h, int rwx, int target_page_bits)
+ target_ulong sr, target_ulong eaddr, int rwx)
{
hwaddr pteg_off, pte_offset;
ppc_hash_pte32_t pte;
+ hwaddr hash;
+ uint32_t vsid, pgidx, ptem;
int ret;
ret = -1; /* No entry found */
- pteg_off = get_pteg_offset32(env, ctx->hash[h]);
- pte_offset = ppc_hash32_pteg_search(env, pteg_off, h, ctx->ptem, &pte);
+ vsid = sr & SR32_VSID;
+ ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
+ ((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
+ pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
+ hash = vsid ^ pgidx;
+ ptem = (vsid << 7) | (pgidx >> 10);
+
+ /* Page address translation */
+ LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+ " hash " TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, hash);
+
+ /* Primary PTEG lookup */
+ LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=%" PRIx32 " ptem=%" PRIx32
+ " hash=" TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, vsid, ptem, hash);
+ pteg_off = get_pteg_offset32(env, hash);
+ pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, &pte);
+ if (pte_offset == -1) {
+ /* Secondary PTEG lookup */
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=%" PRIx32 " api=%" PRIx32
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ptem, ~hash);
+ pteg_off = get_pteg_offset32(env, ~hash);
+ pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, &pte);
+ }
+
if (pte_offset != -1) {
ret = pte_check_hash32(ctx, pte.pte0, pte.pte1, rwx);
LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
@@ -396,23 +423,14 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
}
}
- /* We have a TLB that saves 4K pages, so let's
- * split a huge page to 4k chunks */
- if (target_page_bits != TARGET_PAGE_BITS) {
- ctx->raddr |= (eaddr & ((1 << target_page_bits) - 1))
- & TARGET_PAGE_MASK;
- }
return ret;
}
static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong eaddr, int rwx)
{
- hwaddr hash;
- target_ulong vsid;
- int pr, target_page_bits;
- int ret, ret2;
- target_ulong sr, pgidx;
+ int ret;
+ target_ulong sr;
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
@@ -444,71 +462,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
if ((rwx == 2) && ctx->nx) {
return -3;
}
-
- pr = msr_pr;
- ctx->key = (((sr & SR32_KP) && (pr != 0)) ||
- ((sr & SR32_KS) && (pr == 0))) ? 1 : 0;
-
- vsid = sr & SR32_VSID;
- target_page_bits = TARGET_PAGE_BITS;
- LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
- TARGET_FMT_lx " lr=" TARGET_FMT_lx
- " ir=%d dr=%d pr=%d %d\n",
- eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
- (int)msr_dr, pr != 0 ? 1 : 0, rwx);
- pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
- hash = vsid ^ pgidx;
- ctx->ptem = (vsid << 7) | (pgidx >> 10);
-
- LOG_MMU("pte segment: key=%d nx %d vsid " TARGET_FMT_lx "\n",
- ctx->key, ctx->nx, vsid);
- ret = -1;
-
- /* Page address translation */
- LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
- " hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
- ctx->hash[0] = hash;
- ctx->hash[1] = ~hash;
-
- LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ctx->ptem,
- ctx->hash[0]);
- /* Primary table lookup */
- ret = find_pte32(env, ctx, eaddr, 0, rwx, target_page_bits);
- if (ret == -1) {
- /* Secondary table lookup */
- LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte32(env, ctx, eaddr, 1, rwx, target_page_bits);
- if (ret2 != -1) {
- ret = ret2;
- }
- }
-#if defined(DUMP_PAGE_TABLES)
- if (qemu_log_enabled()) {
- hwaddr curaddr;
- uint32_t a0, a1, a2, a3;
-
- qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
- "\n", sdr, mask + 0x80);
- for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
- curaddr += 16) {
- a0 = ldl_phys(curaddr);
- a1 = ldl_phys(curaddr + 4);
- a2 = ldl_phys(curaddr + 8);
- a3 = ldl_phys(curaddr + 12);
- if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
- qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
- curaddr, a0, a1, a2, a3);
- }
- }
- }
-#endif
+ ret = find_pte32(env, ctx, sr, eaddr, rwx);
return ret;
}
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 66b2d24..36e2c84 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -43,8 +43,6 @@
struct mmu_ctx_hash64 {
hwaddr raddr; /* Real address */
int prot; /* Protection bits */
- hwaddr hash[2]; /* Pagetable hash values */
- target_ulong ptem; /* Virtual segment ID | API */
int key; /* Access key */
};
@@ -377,15 +375,67 @@ static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
}
static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
- target_ulong eaddr, int h, int rwx, int target_page_bits)
+ ppc_slb_t *slb, target_ulong eaddr, int rwx)
{
hwaddr pteg_off, pte_offset;
ppc_hash_pte64_t pte;
+ uint64_t vsid, pageaddr, ptem;
+ hwaddr hash;
+ int segment_bits, target_page_bits;
int ret;
ret = -1; /* No entry found */
- pteg_off = (ctx->hash[h] * HASH_PTEG_SIZE_64) & env->htab_mask;
- pte_offset = ppc_hash64_pteg_search(env, pteg_off, h, ctx->ptem, &pte);
+
+ if (slb->vsid & SLB_VSID_B) {
+ vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
+ segment_bits = 40;
+ } else {
+ vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+ segment_bits = 28;
+ }
+
+ target_page_bits = (slb->vsid & SLB_VSID_L)
+ ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+ ctx->key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP)
+ : (slb->vsid & SLB_VSID_KS));
+
+ pageaddr = eaddr & ((1ULL << segment_bits)
+ - (1ULL << target_page_bits));
+ if (slb->vsid & SLB_VSID_B) {
+ hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
+ } else {
+ hash = vsid ^ (pageaddr >> target_page_bits);
+ }
+ /* Only 5 bits of the page index are used in the AVPN */
+ ptem = (slb->vsid & SLB_VSID_PTEM) |
+ ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
+
+ ret = -1;
+
+ /* Page address translation */
+ LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+ " hash " TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, hash);
+
+
+ /* Primary PTEG lookup */
+ LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n",
+ env->htab_base, env->htab_mask, vsid, ptem, hash);
+ pteg_off = (hash * HASH_PTEG_SIZE_64) & env->htab_mask;
+ pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, &pte);
+ if (pte_offset == -1) {
+ /* Secondary PTEG lookup */
+ LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+ " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+ " hash=" TARGET_FMT_plx "\n", env->htab_base,
+ env->htab_mask, vsid, ptem, ~hash);
+
+ pteg_off = (~hash * HASH_PTEG_SIZE_64) & env->htab_mask;
+ pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, &pte);
+ }
+
if (pte_offset != -1) {
ret = pte64_check(ctx, pte.pte0, pte.pte1, rwx);
LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
@@ -408,13 +458,8 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
target_ulong eaddr, int rwx)
{
- hwaddr hash;
- target_ulong vsid;
- int pr, target_page_bits;
- int ret, ret2;
+ int ret;
ppc_slb_t *slb;
- target_ulong pageaddr;
- int segment_bits;
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
@@ -437,61 +482,7 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
return -3;
}
- pr = msr_pr;
-
- if (slb->vsid & SLB_VSID_B) {
- vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
- segment_bits = 40;
- } else {
- vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
- segment_bits = 28;
- }
-
- target_page_bits = (slb->vsid & SLB_VSID_L)
- ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
- ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
- : (slb->vsid & SLB_VSID_KS));
-
- pageaddr = eaddr & ((1ULL << segment_bits)
- - (1ULL << target_page_bits));
- if (slb->vsid & SLB_VSID_B) {
- hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
- } else {
- hash = vsid ^ (pageaddr >> target_page_bits);
- }
- /* Only 5 bits of the page index are used in the AVPN */
- ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
- ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
-
- LOG_MMU("pte segment: key=%d nx %d vsid " TARGET_FMT_lx "\n",
- ctx->key, !!(slb->vsid & SLB_VSID_N), vsid);
- ret = -1;
-
- /* Page address translation */
- LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
- " hash " TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, hash);
- ctx->hash[0] = hash;
- ctx->hash[1] = ~hash;
-
- LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n",
- env->htab_base, env->htab_mask, vsid, ctx->ptem,
- ctx->hash[0]);
- /* Primary table lookup */
- ret = find_pte64(env, ctx, eaddr, 0, rwx, target_page_bits);
- if (ret == -1) {
- /* Secondary table lookup */
- LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
- " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
- " hash=" TARGET_FMT_plx "\n", env->htab_base,
- env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
- ret2 = find_pte64(env, ctx, eaddr, 1, rwx, target_page_bits);
- if (ret2 != -1) {
- ret = ret2;
- }
- }
+ ret = find_pte64(env, ctx, slb, eaddr, rwx);
return ret;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 28/48] mmu-hash*: Remove permission checking from find_pte{32, 64}()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (26 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 27/48] mmu-hash*: Make find_pte{32, 64} do more of the job of finding ptes David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 29/48] mmu-hash64: Clean up ppc_hash64_htab_lookup() David Gibson
` (20 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
find_pte{32,64}() are poorly named, since they both find a PTE and do
permissions checking of it. This patch makes them only locate a matching
PTE, moving the permission checking and other logic to the caller. We
rename the resulting search functions ppc_hash{32,64}_htab_lookup().
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 45 +++++++++++++++++---------------
target-ppc/mmu-hash64.c | 65 +++++++++++++++++++++++++----------------------
2 files changed, 58 insertions(+), 52 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index b7a26a2..8b403fe 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -374,19 +374,15 @@ static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
return -1;
}
-static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong sr, target_ulong eaddr, int rwx)
+static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
+ target_ulong sr, target_ulong eaddr,
+ ppc_hash_pte32_t *pte)
{
hwaddr pteg_off, pte_offset;
- ppc_hash_pte32_t pte;
hwaddr hash;
uint32_t vsid, pgidx, ptem;
- int ret;
- ret = -1; /* No entry found */
vsid = sr & SR32_VSID;
- ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
- ((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
hash = vsid ^ pgidx;
ptem = (vsid << 7) | (pgidx >> 10);
@@ -402,7 +398,7 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
" hash=" TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, vsid, ptem, hash);
pteg_off = get_pteg_offset32(env, hash);
- pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, &pte);
+ pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte);
if (pte_offset == -1) {
/* Secondary PTEG lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
@@ -410,20 +406,10 @@ static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ptem, ~hash);
pteg_off = get_pteg_offset32(env, ~hash);
- pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, &pte);
+ pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte);
}
- if (pte_offset != -1) {
- ret = pte_check_hash32(ctx, pte.pte0, pte.pte1, rwx);
- LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
- ctx->raddr, ctx->prot, ret);
- /* Update page flags */
- if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
- ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
- }
- }
-
- return ret;
+ return pte_offset;
}
static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
@@ -431,6 +417,8 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
{
int ret;
target_ulong sr;
+ hwaddr pte_offset;
+ ppc_hash_pte32_t pte;
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
@@ -462,7 +450,22 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
if ((rwx == 2) && ctx->nx) {
return -3;
}
- ret = find_pte32(env, ctx, sr, eaddr, rwx);
+
+ /* 6. Locate the PTE in the hash table */
+ pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
+ if (pte_offset == -1) {
+ return -1;
+ }
+ LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
+
+ /* 7. Check access permissions */
+ ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
+ ((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
+ ret = pte_check_hash32(ctx, pte.pte0, pte.pte1, rwx);
+ /* Update page flags */
+ if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
+ ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
+ }
return ret;
}
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 36e2c84..a98e008 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -374,17 +374,14 @@ static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
return -1;
}
-static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
- ppc_slb_t *slb, target_ulong eaddr, int rwx)
+static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
+ ppc_slb_t *slb, target_ulong eaddr,
+ ppc_hash_pte64_t *pte)
{
hwaddr pteg_off, pte_offset;
- ppc_hash_pte64_t pte;
uint64_t vsid, pageaddr, ptem;
hwaddr hash;
int segment_bits, target_page_bits;
- int ret;
-
- ret = -1; /* No entry found */
if (slb->vsid & SLB_VSID_B) {
vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
@@ -396,8 +393,6 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
target_page_bits = (slb->vsid & SLB_VSID_L)
? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
- ctx->key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP)
- : (slb->vsid & SLB_VSID_KS));
pageaddr = eaddr & ((1ULL << segment_bits)
- (1ULL << target_page_bits));
@@ -410,21 +405,19 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ptem = (slb->vsid & SLB_VSID_PTEM) |
((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
- ret = -1;
-
/* Page address translation */
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
" hash " TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, hash);
-
/* Primary PTEG lookup */
LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
" vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, vsid, ptem, hash);
pteg_off = (hash * HASH_PTEG_SIZE_64) & env->htab_mask;
- pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, &pte);
+ pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, pte);
+
if (pte_offset == -1) {
/* Secondary PTEG lookup */
LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
@@ -433,26 +426,10 @@ static int find_pte64(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
env->htab_mask, vsid, ptem, ~hash);
pteg_off = (~hash * HASH_PTEG_SIZE_64) & env->htab_mask;
- pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, &pte);
+ pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, pte);
}
- if (pte_offset != -1) {
- ret = pte64_check(ctx, pte.pte0, pte.pte1, rwx);
- LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
- ctx->raddr, ctx->prot, ret);
- /* Update page flags */
- if (ppc_hash64_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
- ppc_hash64_store_hpte1(env, pte_offset, pte.pte1);
- }
- }
-
- /* We have a TLB that saves 4K pages, so let's
- * split a huge page to 4k chunks */
- if (target_page_bits != TARGET_PAGE_BITS) {
- ctx->raddr |= (eaddr & ((1 << target_page_bits) - 1))
- & TARGET_PAGE_MASK;
- }
- return ret;
+ return pte_offset;
}
static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
@@ -460,6 +437,9 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
{
int ret;
ppc_slb_t *slb;
+ hwaddr pte_offset;
+ ppc_hash_pte64_t pte;
+ int target_page_bits;
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
@@ -482,8 +462,31 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
return -3;
}
- ret = find_pte64(env, ctx, slb, eaddr, rwx);
+ /* 4. Locate the PTE in the hash table */
+ pte_offset = ppc_hash64_htab_lookup(env, slb, eaddr, &pte);
+ if (pte_offset == -1) {
+ return -1;
+ }
+ LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
+
+ /* 5. Check access permissions */
+ ctx->key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP)
+ : (slb->vsid & SLB_VSID_KS));
+
+ ret = pte64_check(ctx, pte.pte0, pte.pte1, rwx);
+ /* Update page flags */
+ if (ppc_hash64_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
+ ppc_hash64_store_hpte1(env, pte_offset, pte.pte1);
+ }
+ /* We have a TLB that saves 4K pages, so let's
+ * split a huge page to 4k chunks */
+ target_page_bits = (slb->vsid & SLB_VSID_L)
+ ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+ if (target_page_bits != TARGET_PAGE_BITS) {
+ ctx->raddr |= (eaddr & ((1 << target_page_bits) - 1))
+ & TARGET_PAGE_MASK;
+ }
return ret;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 29/48] mmu-hash64: Clean up ppc_hash64_htab_lookup()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (27 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 28/48] mmu-hash*: Remove permission checking from find_pte{32, 64}() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 30/48] mmu-hash*: Fold pte_check*() logic into caller David Gibson
` (19 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
This patch makes a general cleanup of the address mangling logic in
ppc_hash64_htab_lookup(). In particular it now avoids repeatedly switching
on the segment size. The lack of SLB and multiple segment sizes on 32-bit
means an analogous cleanup is not needed there.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash64.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index a98e008..10372f0 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -379,31 +379,29 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
ppc_hash_pte64_t *pte)
{
hwaddr pteg_off, pte_offset;
- uint64_t vsid, pageaddr, ptem;
hwaddr hash;
- int segment_bits, target_page_bits;
+ uint64_t vsid, epnshift, epnmask, epn, ptem;
- if (slb->vsid & SLB_VSID_B) {
- vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
- segment_bits = 40;
- } else {
- vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
- segment_bits = 28;
- }
-
- target_page_bits = (slb->vsid & SLB_VSID_L)
+ /* Page size according to the SLB, which we use to generate the
+ * EPN for hash table lookup.. When we implement more recent MMU
+ * extensions this might be different from the actual page size
+ * encoded in the PTE */
+ epnshift = (slb->vsid & SLB_VSID_L)
? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+ epnmask = ~((1ULL << epnshift) - 1);
- pageaddr = eaddr & ((1ULL << segment_bits)
- - (1ULL << target_page_bits));
if (slb->vsid & SLB_VSID_B) {
- hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
+ /* 1TB segment */
+ vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
+ epn = (eaddr & ~SEGMENT_MASK_1T) & epnmask;
+ hash = vsid ^ (vsid << 25) ^ (epn >> epnshift);
} else {
- hash = vsid ^ (pageaddr >> target_page_bits);
+ /* 256M segment */
+ vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+ epn = (eaddr & ~SEGMENT_MASK_256M) & epnmask;
+ hash = vsid ^ (epn >> epnshift);
}
- /* Only 5 bits of the page index are used in the AVPN */
- ptem = (slb->vsid & SLB_VSID_PTEM) |
- ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
+ ptem = (slb->vsid & SLB_VSID_PTEM) | ((epn >> 16) & HPTE64_V_AVPN);
/* Page address translation */
LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 30/48] mmu-hash*: Fold pte_check*() logic into caller
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (28 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 29/48] mmu-hash64: Clean up ppc_hash64_htab_lookup() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 31/48] mmu-hash32: Remove odd pointer usage from BAT code David Gibson
` (18 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
With previous cleanups made, the 32-bit and 64-bit pte_check*() functions
are pretty trivial and only have one call site. This patch therefore
clarifies the overall code flow by folding those functions into their
call site.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 48 +++++++++++++++++++++------------------------
target-ppc/mmu-hash64.c | 50 ++++++++++++++++++++++-------------------------
2 files changed, 45 insertions(+), 53 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 8b403fe..53e86de 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -295,31 +295,8 @@ static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
}
}
-static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
- target_ulong pte1, int rwx)
-{
- int access, ret, pp;
-
- pp = pte1 & HPTE32_R_PP;
- /* Compute access rights */
- access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
- /* Keep the matching PTE informations */
- ctx->raddr = pte1;
- ctx->prot = access;
- ret = ppc_hash32_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- /* Access granted */
- LOG_MMU("PTE access granted !\n");
- } else {
- /* Access right violation */
- LOG_MMU("PTE access rejected\n");
- }
-
- return ret;
-}
-
-static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx,
- uint32_t *pte1p, int ret, int rwx)
+static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, uint32_t *pte1p,
+ int ret, int rwx)
{
int store = 0;
@@ -420,6 +397,8 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
hwaddr pte_offset;
ppc_hash_pte32_t pte;
+ assert((rwx == 0) || (rwx == 1) || (rwx == 2));
+
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
/* Translation is off */
@@ -461,7 +440,24 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
/* 7. Check access permissions */
ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
- ret = pte_check_hash32(ctx, pte.pte0, pte.pte1, rwx);
+
+ int access, pp;
+
+ pp = pte.pte1 & HPTE32_R_PP;
+ /* Compute access rights */
+ access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte.pte1;
+ ctx->prot = access;
+ ret = ppc_hash32_check_prot(ctx->prot, rwx);
+ if (ret == 0) {
+ /* Access granted */
+ LOG_MMU("PTE access granted !\n");
+ } else {
+ /* Access right violation */
+ LOG_MMU("PTE access rejected\n");
+ }
+
/* Update page flags */
if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 10372f0..2e109f4 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -297,32 +297,6 @@ static int ppc_hash64_check_prot(int prot, int rwx)
return ret;
}
-static int pte64_check(struct mmu_ctx_hash64 *ctx, target_ulong pte0,
- target_ulong pte1, int rwx)
-{
- int access, ret, pp;
- bool nx;
-
- pp = (pte1 & HPTE64_R_PP) | ((pte1 & HPTE64_R_PP0) >> 61);
- /* No execute if either noexec or guarded bits set */
- nx = (pte1 & HPTE64_R_N) || (pte1 & HPTE64_R_G);
- /* Compute access rights */
- access = ppc_hash64_pp_check(ctx->key, pp, nx);
- /* Keep the matching PTE informations */
- ctx->raddr = pte1;
- ctx->prot = access;
- ret = ppc_hash64_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- /* Access granted */
- LOG_MMU("PTE access granted !\n");
- } else {
- /* Access right violation */
- LOG_MMU("PTE access rejected\n");
- }
-
- return ret;
-}
-
static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
uint64_t *pte1p, int ret, int rw)
{
@@ -439,6 +413,8 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ppc_hash_pte64_t pte;
int target_page_bits;
+ assert((rwx == 0) || (rwx == 1) || (rwx == 2));
+
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
/* Translation is off */
@@ -471,7 +447,27 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ctx->key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP)
: (slb->vsid & SLB_VSID_KS));
- ret = pte64_check(ctx, pte.pte0, pte.pte1, rwx);
+
+ int access, pp;
+ bool nx;
+
+ pp = (pte.pte1 & HPTE64_R_PP) | ((pte.pte1 & HPTE64_R_PP0) >> 61);
+ /* No execute if either noexec or guarded bits set */
+ nx = (pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G);
+ /* Compute access rights */
+ access = ppc_hash64_pp_check(ctx->key, pp, nx);
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte.pte1;
+ ctx->prot = access;
+ ret = ppc_hash64_check_prot(ctx->prot, rwx);
+ if (ret == 0) {
+ /* Access granted */
+ LOG_MMU("PTE access granted !\n");
+ } else {
+ /* Access right violation */
+ LOG_MMU("PTE access rejected\n");
+ }
+
/* Update page flags */
if (ppc_hash64_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
ppc_hash64_store_hpte1(env, pte_offset, pte.pte1);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 31/48] mmu-hash32: Remove odd pointer usage from BAT code
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (29 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 30/48] mmu-hash*: Fold pte_check*() logic into caller David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 32/48] mmu-hash32: Split BAT size logic from permissions logic David Gibson
` (17 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
In the code for handling BATs, the hash32_bat_size_prot() and
hash32_bat_601_size_prot() functions are passed the BAT contents by
reference (pointer) for no clear reason, since they only need the values
within.
This patch removes this odd usage, and uses the resulting change to clean
up the caller slightly.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 47 ++++++++++++++++++++++++-----------------------
1 file changed, 24 insertions(+), 23 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 53e86de..b7f6e8f 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -115,19 +115,19 @@ static int ppc_hash32_check_prot(int prot, int rwx)
/* Perform BAT hit & translation */
static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp,
- int *validp, int *protp, target_ulong *BATu,
- target_ulong *BATl)
+ int *validp, int *protp,
+ target_ulong batu, target_ulong batl)
{
target_ulong bl;
int pp, valid, prot;
- bl = (*BATu & BATU32_BL) << 15;
+ bl = (batu & BATU32_BL) << 15;
valid = 0;
prot = 0;
- if (((msr_pr == 0) && (*BATu & BATU32_VS)) ||
- ((msr_pr != 0) && (*BATu & BATU32_VP))) {
+ if (((msr_pr == 0) && (batu & BATU32_VS)) ||
+ ((msr_pr != 0) && (batu & BATU32_VP))) {
valid = 1;
- pp = *BATl & BATL32_PP;
+ pp = batl & BATL32_PP;
if (pp != 0) {
prot = PAGE_READ | PAGE_EXEC;
if (pp == 0x2) {
@@ -142,22 +142,22 @@ static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp,
static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
int *validp, int *protp,
- target_ulong *BATu, target_ulong *BATl)
+ target_ulong batu, target_ulong batl)
{
target_ulong bl;
int key, pp, valid, prot;
- bl = (*BATl & BATL32_601_BL) << 17;
+ bl = (batl & BATL32_601_BL) << 17;
LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
- (uint8_t)(*BATl & BATL32_601_BL), bl, ~bl);
+ (uint8_t)(batl & BATL32_601_BL), bl, ~bl);
prot = 0;
- valid = !!(*BATl & BATL32_601_V);
+ valid = !!(batl & BATL32_601_V);
if (valid) {
- pp = *BATu & BATU32_601_PP;
+ pp = batu & BATU32_601_PP;
if (msr_pr == 0) {
- key = !!(*BATu & BATU32_601_KS);
+ key = !!(batu & BATU32_601_KS);
} else {
- key = !!(*BATu & BATU32_601_KP);
+ key = !!(batu & BATU32_601_KP);
}
prot = ppc_hash32_pp_check(key, pp, 0);
}
@@ -169,7 +169,7 @@ static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong virtual, int rwx)
{
- target_ulong *BATlt, *BATut, *BATu, *BATl;
+ target_ulong *BATlt, *BATut;
target_ulong BEPIl, BEPIu, bl;
int i, valid, prot;
int ret = -1;
@@ -184,25 +184,26 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
BATut = env->DBAT[0];
}
for (i = 0; i < env->nb_BATs; i++) {
- BATu = &BATut[i];
- BATl = &BATlt[i];
- BEPIu = *BATu & BATU32_BEPIU;
- BEPIl = *BATu & BATU32_BEPIL;
+ target_ulong batu = BATut[i];
+ target_ulong batl = BATlt[i];
+
+ BEPIu = batu & BATU32_BEPIU;
+ BEPIl = batu & BATU32_BEPIL;
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
- hash32_bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ hash32_bat_601_size_prot(env, &bl, &valid, &prot, batu, batl);
} else {
- hash32_bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ hash32_bat_size_prot(env, &bl, &valid, &prot, batu, batl);
}
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
+ type == ACCESS_CODE ? 'I' : 'D', i, virtual, batu, batl);
if ((virtual & BATU32_BEPIU) == BEPIu &&
((virtual & BATU32_BEPIL) & ~bl) == BEPIl) {
/* BAT matches */
if (valid != 0) {
/* Get physical address */
- ctx->raddr = (*BATl & BATL32_BRPNU) |
- ((virtual & BATU32_BEPIL & bl) | (*BATl & BATL32_BRPNL)) |
+ ctx->raddr = (batl & BATL32_BRPNU) |
+ ((virtual & BATU32_BEPIL & bl) | (batl & BATL32_BRPNL)) |
(virtual & 0x0001F000);
/* Compute access rights */
ctx->prot = prot;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 32/48] mmu-hash32: Split BAT size logic from permissions logic
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (30 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 31/48] mmu-hash32: Remove odd pointer usage from BAT code David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 33/48] mmu-hash32: Clean up BAT matching logic David Gibson
` (16 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
hash32_bat_size_prot() and its 601 variant, as the name suggests, returns
both a BAT's size - needed to search for a matching BAT - and its
permissions, only relevant once a matching BAT has been located.
There's no particular advantage to combining these, so we split these roles
into seperate functions for clarity.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 71 ++++++++++++++++++++++++++---------------------
1 file changed, 40 insertions(+), 31 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index b7f6e8f..6c71ebd 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -113,57 +113,64 @@ static int ppc_hash32_check_prot(int prot, int rwx)
return ret;
}
-/* Perform BAT hit & translation */
-static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp,
- int *validp, int *protp,
- target_ulong batu, target_ulong batl)
+static void hash32_bat_size(CPUPPCState *env, target_ulong *blp, int *validp,
+ target_ulong batu, target_ulong batl)
{
target_ulong bl;
- int pp, valid, prot;
+ int valid;
bl = (batu & BATU32_BL) << 15;
valid = 0;
- prot = 0;
if (((msr_pr == 0) && (batu & BATU32_VS)) ||
((msr_pr != 0) && (batu & BATU32_VP))) {
valid = 1;
- pp = batl & BATL32_PP;
- if (pp != 0) {
- prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2) {
- prot |= PAGE_WRITE;
- }
- }
}
*blp = bl;
*validp = valid;
- *protp = prot;
}
-static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
- int *validp, int *protp,
- target_ulong batu, target_ulong batl)
+static int hash32_bat_prot(CPUPPCState *env,
+ target_ulong batu, target_ulong batl)
+{
+ int pp, prot;
+
+ prot = 0;
+ pp = batl & BATL32_PP;
+ if (pp != 0) {
+ prot = PAGE_READ | PAGE_EXEC;
+ if (pp == 0x2) {
+ prot |= PAGE_WRITE;
+ }
+ }
+ return prot;
+}
+
+static void hash32_bat_601_size(CPUPPCState *env, target_ulong *blp, int *validp,
+ target_ulong batu, target_ulong batl)
{
target_ulong bl;
- int key, pp, valid, prot;
+ int valid;
bl = (batl & BATL32_601_BL) << 17;
LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
(uint8_t)(batl & BATL32_601_BL), bl, ~bl);
- prot = 0;
valid = !!(batl & BATL32_601_V);
- if (valid) {
- pp = batu & BATU32_601_PP;
- if (msr_pr == 0) {
- key = !!(batu & BATU32_601_KS);
- } else {
- key = !!(batu & BATU32_601_KP);
- }
- prot = ppc_hash32_pp_check(key, pp, 0);
- }
*blp = bl;
*validp = valid;
- *protp = prot;
+}
+
+static int hash32_bat_601_prot(CPUPPCState *env,
+ target_ulong batu, target_ulong batl)
+{
+ int key, pp;
+
+ pp = batu & BATU32_601_PP;
+ if (msr_pr == 0) {
+ key = !!(batu & BATU32_601_KS);
+ } else {
+ key = !!(batu & BATU32_601_KP);
+ }
+ return ppc_hash32_pp_check(key, pp, 0);
}
static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
@@ -190,9 +197,11 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
BEPIu = batu & BATU32_BEPIU;
BEPIl = batu & BATU32_BEPIL;
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
- hash32_bat_601_size_prot(env, &bl, &valid, &prot, batu, batl);
+ hash32_bat_601_size(env, &bl, &valid, batu, batl);
+ prot = hash32_bat_601_prot(env, batu, batl);
} else {
- hash32_bat_size_prot(env, &bl, &valid, &prot, batu, batl);
+ hash32_bat_size(env, &bl, &valid, batu, batl);
+ prot = hash32_bat_prot(env, batu, batl);
}
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 33/48] mmu-hash32: Clean up BAT matching logic
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (31 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 32/48] mmu-hash32: Split BAT size logic from permissions logic David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 34/48] mmu-hash32: Cleanup BAT lookup David Gibson
` (15 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
The code to search for a matching BAT for a virtual address is somewhat
longwinded and awkward. In particular, it relies on seperate size and
validity information being returned from the hash32_bat_size() function
(and 601 specific variant).
We simplify this by having hash32_bat_size() return instead a mask of the
virtual address bits to match, and 0 for invalid (since a BAT can never
match the entire address space).
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 74 +++++++++++++++++++----------------------------
target-ppc/mmu-hash32.h | 4 ---
2 files changed, 30 insertions(+), 48 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 6c71ebd..40d3564 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -113,20 +113,15 @@ static int ppc_hash32_check_prot(int prot, int rwx)
return ret;
}
-static void hash32_bat_size(CPUPPCState *env, target_ulong *blp, int *validp,
- target_ulong batu, target_ulong batl)
+static target_ulong hash32_bat_size(CPUPPCState *env,
+ target_ulong batu, target_ulong batl)
{
- target_ulong bl;
- int valid;
-
- bl = (batu & BATU32_BL) << 15;
- valid = 0;
- if (((msr_pr == 0) && (batu & BATU32_VS)) ||
- ((msr_pr != 0) && (batu & BATU32_VP))) {
- valid = 1;
+ if ((msr_pr && !(batu & BATU32_VP))
+ || (!msr_pr && !(batu & BATU32_VS))) {
+ return 0;
}
- *blp = bl;
- *validp = valid;
+
+ return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
}
static int hash32_bat_prot(CPUPPCState *env,
@@ -145,18 +140,14 @@ static int hash32_bat_prot(CPUPPCState *env,
return prot;
}
-static void hash32_bat_601_size(CPUPPCState *env, target_ulong *blp, int *validp,
+static target_ulong hash32_bat_601_size(CPUPPCState *env,
target_ulong batu, target_ulong batl)
{
- target_ulong bl;
- int valid;
-
- bl = (batl & BATL32_601_BL) << 17;
- LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
- (uint8_t)(batl & BATL32_601_BL), bl, ~bl);
- valid = !!(batl & BATL32_601_V);
- *blp = bl;
- *validp = valid;
+ if (!(batl & BATL32_601_V)) {
+ return 0;
+ }
+
+ return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
}
static int hash32_bat_601_prot(CPUPPCState *env,
@@ -177,8 +168,7 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong virtual, int rwx)
{
target_ulong *BATlt, *BATut;
- target_ulong BEPIl, BEPIu, bl;
- int i, valid, prot;
+ int i, prot;
int ret = -1;
LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
@@ -193,37 +183,33 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
for (i = 0; i < env->nb_BATs; i++) {
target_ulong batu = BATut[i];
target_ulong batl = BATlt[i];
+ target_ulong mask;
- BEPIu = batu & BATU32_BEPIU;
- BEPIl = batu & BATU32_BEPIL;
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
- hash32_bat_601_size(env, &bl, &valid, batu, batl);
+ mask = hash32_bat_601_size(env, batu, batl);
prot = hash32_bat_601_prot(env, batu, batl);
} else {
- hash32_bat_size(env, &bl, &valid, batu, batl);
+ mask = hash32_bat_size(env, batu, batl);
prot = hash32_bat_prot(env, batu, batl);
}
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
type == ACCESS_CODE ? 'I' : 'D', i, virtual, batu, batl);
- if ((virtual & BATU32_BEPIU) == BEPIu &&
- ((virtual & BATU32_BEPIL) & ~bl) == BEPIl) {
+
+ if (mask && ((virtual & mask) == (batu & BATU32_BEPI))) {
/* BAT matches */
- if (valid != 0) {
- /* Get physical address */
- ctx->raddr = (batl & BATL32_BRPNU) |
- ((virtual & BATU32_BEPIL & bl) | (batl & BATL32_BRPNL)) |
- (virtual & 0x0001F000);
- /* Compute access rights */
- ctx->prot = prot;
- ret = ppc_hash32_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
- i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
- ctx->prot & PAGE_WRITE ? 'W' : '-');
- }
- break;
+ /* Get physical address */
+ ctx->raddr = (batl & mask) | (virtual & ~mask);
+ ctx->raddr &= TARGET_PAGE_MASK;
+ /* Compute access rights */
+ ctx->prot = prot;
+ ret = ppc_hash32_check_prot(ctx->prot, rwx);
+ if (ret == 0) {
+ LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
+ i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
+ ctx->prot & PAGE_WRITE ? 'W' : '-');
}
+ break;
}
}
if (ret < 0) {
diff --git a/target-ppc/mmu-hash32.h b/target-ppc/mmu-hash32.h
index f990edc..884786b 100644
--- a/target-ppc/mmu-hash32.h
+++ b/target-ppc/mmu-hash32.h
@@ -22,16 +22,12 @@ int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
* Block Address Translation (BAT) definitions
*/
-#define BATU32_BEPIU 0xf0000000
-#define BATU32_BEPIL 0x0ffe0000
#define BATU32_BEPI 0xfffe0000
#define BATU32_BL 0x00001ffc
#define BATU32_VS 0x00000002
#define BATU32_VP 0x00000001
-#define BATL32_BRPNU 0xf0000000
-#define BATL32_BRPNL 0x0ffe0000
#define BATL32_BRPN 0xfffe0000
#define BATL32_WIMG 0x00000078
#define BATL32_PP 0x00000003
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 34/48] mmu-hash32: Cleanup BAT lookup
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (32 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 33/48] mmu-hash32: Clean up BAT matching logic David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 35/48] mmu-hash32: Don't look up page tables on BAT permission error David Gibson
` (14 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
This patch makes a general cleanup of the ppc_hash32_get_bat() function,
renaming it to ppc_hash32_bat_lookup(). In particular, the new function
only looks for a matching BAT, with the permissions check from the old
function moved to the caller.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 82 ++++++++++++++++++++++-------------------------
1 file changed, 39 insertions(+), 43 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 40d3564..d4d91dd 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -164,15 +164,14 @@ static int hash32_bat_601_prot(CPUPPCState *env,
return ppc_hash32_pp_check(key, pp, 0);
}
-static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong virtual, int rwx)
+static hwaddr ppc_hash32_bat_lookup(CPUPPCState *env, target_ulong ea, int rwx,
+ int *prot)
{
target_ulong *BATlt, *BATut;
- int i, prot;
- int ret = -1;
+ int i;
LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
- rwx == 2 ? 'I' : 'D', virtual);
+ rwx == 2 ? 'I' : 'D', ea);
if (rwx == 2) {
BATlt = env->IBAT[1];
BATut = env->IBAT[0];
@@ -187,52 +186,46 @@ static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
mask = hash32_bat_601_size(env, batu, batl);
- prot = hash32_bat_601_prot(env, batu, batl);
} else {
mask = hash32_bat_size(env, batu, batl);
- prot = hash32_bat_prot(env, batu, batl);
}
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', i, virtual, batu, batl);
-
- if (mask && ((virtual & mask) == (batu & BATU32_BEPI))) {
- /* BAT matches */
- /* Get physical address */
- ctx->raddr = (batl & mask) | (virtual & ~mask);
- ctx->raddr &= TARGET_PAGE_MASK;
- /* Compute access rights */
- ctx->prot = prot;
- ret = ppc_hash32_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
- i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
- ctx->prot & PAGE_WRITE ? 'W' : '-');
+ type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl);
+
+ if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
+ hwaddr raddr = (batl & mask) | (ea & ~mask);
+
+ if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
+ *prot = hash32_bat_601_prot(env, batu, batl);
+ } else {
+ *prot = hash32_bat_prot(env, batu, batl);
}
- break;
+
+ return raddr & TARGET_PAGE_MASK;
}
}
- if (ret < 0) {
+
+ /* No hit */
#if defined(DEBUG_BATS)
- if (qemu_log_enabled()) {
- LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
- for (i = 0; i < 4; i++) {
- BATu = &BATut[i];
- BATl = &BATlt[i];
- BEPIu = *BATu & BATU32_BEPIU;
- BEPIl = *BATu & BATU32_BEPIL;
- bl = (*BATu & 0x00001FFC) << 15;
- LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
- " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
- TARGET_FMT_lx " " TARGET_FMT_lx "\n",
- __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
- *BATu, *BATl, BEPIu, BEPIl, bl);
- }
+ if (qemu_log_enabled()) {
+ LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
+ for (i = 0; i < 4; i++) {
+ BATu = &BATut[i];
+ BATl = &BATlt[i];
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
+ bl = (*BATu & 0x00001FFC) << 15;
+ LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
+ " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
+ TARGET_FMT_lx " " TARGET_FMT_lx "\n",
+ __func__, type == ACCESS_CODE ? 'I' : 'D', i, ea,
+ *BATu, *BATl, BEPIu, BEPIl, bl);
}
-#endif
}
- /* No hit */
- return ret;
+#endif
+
+ return -1;
}
static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
@@ -405,9 +398,12 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
/* 2. Check Block Address Translation entries (BATs) */
if (env->nb_BATs != 0) {
- ret = ppc_hash32_get_bat(env, ctx, eaddr, rwx);
- if (ret == 0) {
- return 0;
+ ctx->raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &ctx->prot);
+ if (ctx->raddr != -1) {
+ ret = ppc_hash32_check_prot(ctx->prot, rwx);
+ if (ret == 0) {
+ return 0;
+ }
}
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 35/48] mmu-hash32: Don't look up page tables on BAT permission error
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (33 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 34/48] mmu-hash32: Cleanup BAT lookup David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 36/48] mmu-hash*: Don't update PTE flags when permission is denied David Gibson
` (13 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
BEHAVIOUR CHANGE
Currently, on any failure translating an address with BATs, we proceed to
normal segment and page table translation. That's incorrect if the
BAT error was due to permissions, rather than not finding a matching BAT.
We've gotten away with it because a guest would not usually put
translations for the same address in both BATs and page table. Nonetheless
this patch corrects the logic, only doing page table lookup if no BAT
is found. A matching BAT with bad permissions will now correctly trigger
an exception.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index d4d91dd..3488092 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -400,10 +400,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
if (env->nb_BATs != 0) {
ctx->raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &ctx->prot);
if (ctx->raddr != -1) {
- ret = ppc_hash32_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- return 0;
- }
+ return ppc_hash32_check_prot(ctx->prot, rwx);
}
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 36/48] mmu-hash*: Don't update PTE flags when permission is denied
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (34 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 35/48] mmu-hash32: Don't look up page tables on BAT permission error David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 37/48] mmu-hash32: Remove nx from context structure David Gibson
` (12 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
BEHAVIOUR CHANGE
Currently if ppc_hash{32,64}_translate() finds a PTE matching the given
virtual address, it will always update the PTE's R & C (Referenced and
Changed) bits. This happens even if the PTE's permissions mean we are
about to deny the translation.
This is clearly a bug, although we get away with it because:
a) It will only incorrectly set, never reset the bits, which should not
cause guest correctness problems.
b) Linux guests never use the R & C bits anyway.
This patch fixes the behaviour, only updating R & C when access is granted
by the PTE.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 12 +++++++-----
target-ppc/mmu-hash64.c | 12 +++++++-----
2 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 3488092..ae606fd 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -439,15 +439,17 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
ctx->raddr = pte.pte1;
ctx->prot = access;
ret = ppc_hash32_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- /* Access granted */
- LOG_MMU("PTE access granted !\n");
- } else {
+
+ if (ret) {
/* Access right violation */
LOG_MMU("PTE access rejected\n");
+ return ret;
}
- /* Update page flags */
+ LOG_MMU("PTE access granted !\n");
+
+ /* 8. Update PTE referenced and changed bits if necessary */
+
if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
}
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 2e109f4..f7aa352 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -460,15 +460,17 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ctx->raddr = pte.pte1;
ctx->prot = access;
ret = ppc_hash64_check_prot(ctx->prot, rwx);
- if (ret == 0) {
- /* Access granted */
- LOG_MMU("PTE access granted !\n");
- } else {
+
+ if (ret) {
/* Access right violation */
LOG_MMU("PTE access rejected\n");
+ return ret;
}
- /* Update page flags */
+ LOG_MMU("PTE access granted !\n");
+
+ /* 6. Update PTE referenced and changed bits if necessary */
+
if (ppc_hash64_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
ppc_hash64_store_hpte1(env, pte_offset, pte.pte1);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 37/48] mmu-hash32: Remove nx from context structure
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (35 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 36/48] mmu-hash*: Don't update PTE flags when permission is denied David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 38/48] mmu-hash*: Clean up permission checking David Gibson
` (11 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Previous cleanups have meant the nx field of the mmu_ctx_hash32 structure
is now only used within ppc_hash32_translate(), and so it can be replaced
by a local variable.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index ae606fd..2b88b9f 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -45,7 +45,6 @@ struct mmu_ctx_hash32 {
hwaddr raddr; /* Real address */
int prot; /* Protection bits */
int key; /* Access key */
- int nx; /* Non-execute area */
};
static int ppc_hash32_pp_check(int key, int pp, int nx)
@@ -383,6 +382,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
{
int ret;
target_ulong sr;
+ bool nx;
hwaddr pte_offset;
ppc_hash_pte32_t pte;
@@ -414,8 +414,8 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
}
/* 5. Check for segment level no-execute violation */
- ctx->nx = !!(sr & SR32_NX);
- if ((rwx == 2) && ctx->nx) {
+ nx = !!(sr & SR32_NX);
+ if ((rwx == 2) && nx) {
return -3;
}
@@ -434,7 +434,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
pp = pte.pte1 & HPTE32_R_PP;
/* Compute access rights */
- access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
+ access = ppc_hash32_pp_check(ctx->key, pp, nx);
/* Keep the matching PTE informations */
ctx->raddr = pte.pte1;
ctx->prot = access;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 38/48] mmu-hash*: Clean up permission checking
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (36 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 37/48] mmu-hash32: Remove nx from context structure David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 39/48] mmu-hash64: Factor SLB N bit into permissions bits David Gibson
` (10 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Currently checking of PTE permission bits is split messily amongst
ppc_hash{32,64}_pp_check(), ppc_hash{32,64}_check_prot() and their callers.
This patch cleans this up to have the new function
ppc_hash{32,64}_pte_prot() compute the page permissions from the SLBE (for
64-bit) or segment register (32-bit) and the pte. A greatly simplified
version of the actual permissions check is then open coded in the callers.
The 32-bit version of ppc_hash32_pte_prot() is implemented in terms of
ppc_hash32_pp_prot(), a renamed and slightly cleaned up version of the old
ppc_hash32_pp_check(), which is also used for checking BAT permissions on
the 601.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 95 ++++++++++++++++++++---------------------------
target-ppc/mmu-hash64.c | 93 ++++++++++++++++------------------------------
2 files changed, 72 insertions(+), 116 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 2b88b9f..6581d0f 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -47,69 +47,60 @@ struct mmu_ctx_hash32 {
int key; /* Access key */
};
-static int ppc_hash32_pp_check(int key, int pp, int nx)
+static int ppc_hash32_pp_prot(int key, int pp, int nx)
{
- int access;
+ int prot;
- /* Compute access rights */
- access = 0;
if (key == 0) {
switch (pp) {
case 0x0:
case 0x1:
case 0x2:
- access |= PAGE_WRITE;
- /* No break here */
+ prot = PAGE_READ | PAGE_WRITE;
+ break;
+
case 0x3:
- access |= PAGE_READ;
+ prot = PAGE_READ;
break;
+
+ default:
+ abort();
}
} else {
switch (pp) {
case 0x0:
- access = 0;
+ prot = 0;
break;
+
case 0x1:
case 0x3:
- access = PAGE_READ;
+ prot = PAGE_READ;
break;
+
case 0x2:
- access = PAGE_READ | PAGE_WRITE;
+ prot = PAGE_READ | PAGE_WRITE;
break;
+
+ default:
+ abort();
}
}
if (nx == 0) {
- access |= PAGE_EXEC;
+ prot |= PAGE_EXEC;
}
- return access;
+ return prot;
}
-static int ppc_hash32_check_prot(int prot, int rwx)
+static int ppc_hash32_pte_prot(CPUPPCState *env,
+ target_ulong sr, ppc_hash_pte32_t pte)
{
- int ret;
+ unsigned pp, key;
- if (rwx == 2) {
- if (prot & PAGE_EXEC) {
- ret = 0;
- } else {
- ret = -2;
- }
- } else if (rwx) {
- if (prot & PAGE_WRITE) {
- ret = 0;
- } else {
- ret = -2;
- }
- } else {
- if (prot & PAGE_READ) {
- ret = 0;
- } else {
- ret = -2;
- }
- }
+ key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
+ pp = pte.pte1 & HPTE32_R_PP;
- return ret;
+ return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
}
static target_ulong hash32_bat_size(CPUPPCState *env,
@@ -160,7 +151,7 @@ static int hash32_bat_601_prot(CPUPPCState *env,
} else {
key = !!(batu & BATU32_601_KP);
}
- return ppc_hash32_pp_check(key, pp, 0);
+ return ppc_hash32_pp_prot(key, pp, 0);
}
static hwaddr ppc_hash32_bat_lookup(CPUPPCState *env, target_ulong ea, int rwx,
@@ -380,11 +371,10 @@ static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong eaddr, int rwx)
{
- int ret;
target_ulong sr;
- bool nx;
hwaddr pte_offset;
ppc_hash_pte32_t pte;
+ const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
@@ -400,7 +390,10 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
if (env->nb_BATs != 0) {
ctx->raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &ctx->prot);
if (ctx->raddr != -1) {
- return ppc_hash32_check_prot(ctx->prot, rwx);
+ if (need_prot[rwx] & ~ctx->prot) {
+ return -2;
+ }
+ return 0;
}
}
@@ -414,8 +407,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
}
/* 5. Check for segment level no-execute violation */
- nx = !!(sr & SR32_NX);
- if ((rwx == 2) && nx) {
+ if ((rwx == 2) && (sr & SR32_NX)) {
return -3;
}
@@ -427,34 +419,27 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
/* 7. Check access permissions */
- ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
- ((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
-
- int access, pp;
- pp = pte.pte1 & HPTE32_R_PP;
- /* Compute access rights */
- access = ppc_hash32_pp_check(ctx->key, pp, nx);
- /* Keep the matching PTE informations */
- ctx->raddr = pte.pte1;
- ctx->prot = access;
- ret = ppc_hash32_check_prot(ctx->prot, rwx);
+ ctx->prot = ppc_hash32_pte_prot(env, sr, pte);
- if (ret) {
+ if (need_prot[rwx] & ~ctx->prot) {
/* Access right violation */
LOG_MMU("PTE access rejected\n");
- return ret;
+ return -2;
}
LOG_MMU("PTE access granted !\n");
/* 8. Update PTE referenced and changed bits if necessary */
- if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
+ if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, 0, rwx) == 1) {
ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
}
- return ret;
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte.pte1;
+
+ return 0;
}
hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index f7aa352..1458f15 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -43,7 +43,6 @@
struct mmu_ctx_hash64 {
hwaddr raddr; /* Real address */
int prot; /* Protection bits */
- int key; /* Access key */
};
/*
@@ -229,72 +228,55 @@ target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
* 64-bit hash table MMU handling
*/
-static int ppc_hash64_pp_check(int key, int pp, bool nx)
+static int ppc_hash64_pte_prot(CPUPPCState *env,
+ ppc_slb_t *slb, ppc_hash_pte64_t pte)
{
- int access;
+ unsigned pp, key;
+ /* Some pp bit combinations have undefined behaviour, so default
+ * to no access in those cases */
+ int prot = 0;
+
+ key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP)
+ : (slb->vsid & SLB_VSID_KS));
+ pp = (pte.pte1 & HPTE64_R_PP) | ((pte.pte1 & HPTE64_R_PP0) >> 61);
- /* Compute access rights */
- /* When pp is 4, 5 or 7, the result is undefined. Set it to noaccess */
- access = 0;
if (key == 0) {
switch (pp) {
case 0x0:
case 0x1:
case 0x2:
- access |= PAGE_WRITE;
- /* No break here */
+ prot = PAGE_READ | PAGE_WRITE;
+ break;
+
case 0x3:
case 0x6:
- access |= PAGE_READ;
+ prot = PAGE_READ;
break;
}
} else {
switch (pp) {
case 0x0:
case 0x6:
- access = 0;
+ prot = 0;
break;
+
case 0x1:
case 0x3:
- access = PAGE_READ;
+ prot = PAGE_READ;
break;
+
case 0x2:
- access = PAGE_READ | PAGE_WRITE;
+ prot = PAGE_READ | PAGE_WRITE;
break;
}
}
- if (!nx) {
- access |= PAGE_EXEC;
- }
-
- return access;
-}
-
-static int ppc_hash64_check_prot(int prot, int rwx)
-{
- int ret;
- if (rwx == 2) {
- if (prot & PAGE_EXEC) {
- ret = 0;
- } else {
- ret = -2;
- }
- } else if (rwx == 1) {
- if (prot & PAGE_WRITE) {
- ret = 0;
- } else {
- ret = -2;
- }
- } else {
- if (prot & PAGE_READ) {
- ret = 0;
- } else {
- ret = -2;
- }
+ /* No execute if either noexec or guarded bits set */
+ if (!(pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G)) {
+ prot |= PAGE_EXEC;
}
- return ret;
+ return prot;
}
static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
@@ -407,11 +389,11 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
target_ulong eaddr, int rwx)
{
- int ret;
ppc_slb_t *slb;
hwaddr pte_offset;
ppc_hash_pte64_t pte;
int target_page_bits;
+ const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
@@ -444,37 +426,26 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
/* 5. Check access permissions */
- ctx->key = !!(msr_pr ? (slb->vsid & SLB_VSID_KP)
- : (slb->vsid & SLB_VSID_KS));
+ ctx->prot = ppc_hash64_pte_prot(env, slb, pte);
- int access, pp;
- bool nx;
-
- pp = (pte.pte1 & HPTE64_R_PP) | ((pte.pte1 & HPTE64_R_PP0) >> 61);
- /* No execute if either noexec or guarded bits set */
- nx = (pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G);
- /* Compute access rights */
- access = ppc_hash64_pp_check(ctx->key, pp, nx);
- /* Keep the matching PTE informations */
- ctx->raddr = pte.pte1;
- ctx->prot = access;
- ret = ppc_hash64_check_prot(ctx->prot, rwx);
-
- if (ret) {
+ if ((need_prot[rwx] & ~ctx->prot) != 0) {
/* Access right violation */
LOG_MMU("PTE access rejected\n");
- return ret;
+ return -2;
}
LOG_MMU("PTE access granted !\n");
/* 6. Update PTE referenced and changed bits if necessary */
- if (ppc_hash64_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
+ if (ppc_hash64_pte_update_flags(ctx, &pte.pte1, 0, rwx) == 1) {
ppc_hash64_store_hpte1(env, pte_offset, pte.pte1);
}
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte.pte1;
+
/* We have a TLB that saves 4K pages, so let's
* split a huge page to 4k chunks */
target_page_bits = (slb->vsid & SLB_VSID_L)
@@ -483,7 +454,7 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ctx->raddr |= (eaddr & ((1 << target_page_bits) - 1))
& TARGET_PAGE_MASK;
}
- return ret;
+ return 0;
}
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 39/48] mmu-hash64: Factor SLB N bit into permissions bits
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (37 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 38/48] mmu-hash*: Clean up permission checking David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 40/48] mmu-hash*: Clean up PTE flags update David Gibson
` (9 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
BEHAVIOUR CHANGE
Currently, for 64-bit hash mmu, the execute protection bit placed into the
qemu tlb is based only on the N (No execute) bit from the PTE. However,
No Execute can also be set at the segment level. We do check this on
execute faults, but this still means we could incorrectly allow execution
of code from a No Execute segment, if a prior read or write fault caused
the page to be loaded into the qemu tlb with PROT_EXEC set.
To correct this, we (re-)check the segment level no execute permission when
generating the protection bits for the qemu tlb.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash64.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 1458f15..5607ce8 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -272,7 +272,8 @@ static int ppc_hash64_pte_prot(CPUPPCState *env,
}
/* No execute if either noexec or guarded bits set */
- if (!(pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G)) {
+ if (!(pte.pte1 & HPTE64_R_N) || (pte.pte1 & HPTE64_R_G)
+ || (slb->vsid & SLB_VSID_N)) {
prot |= PAGE_EXEC;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 40/48] mmu-hash*: Clean up PTE flags update
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (38 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 39/48] mmu-hash64: Factor SLB N bit into permissions bits David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 41/48] mmu-hash*: Clean up real address calculation David Gibson
` (8 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Currently the ppc_hash{32,64}_pte_update_flags() helper functions update a
PTE's referenced and changed bits as necessary to reflect the access. It
is somewhat long winded, though. This patch open codes them in their
(single) callers, in a simpler way.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 39 ++++++++++++---------------------------
target-ppc/mmu-hash64.c | 39 ++++++++++++---------------------------
2 files changed, 24 insertions(+), 54 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 6581d0f..314b7d1 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -274,31 +274,6 @@ static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
}
}
-static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, uint32_t *pte1p,
- int ret, int rwx)
-{
- int store = 0;
-
- /* Update page flags */
- if (!(*pte1p & HPTE32_R_R)) {
- /* Update accessed flag */
- *pte1p |= HPTE32_R_R;
- store = 1;
- }
- if (!(*pte1p & HPTE32_R_C)) {
- if (rwx == 1 && ret == 0) {
- /* Update changed flag */
- *pte1p |= HPTE32_R_C;
- store = 1;
- } else {
- /* Force page fault for first write access */
- ctx->prot &= ~PAGE_WRITE;
- }
- }
-
- return store;
-}
-
hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
{
return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
@@ -374,6 +349,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong sr;
hwaddr pte_offset;
ppc_hash_pte32_t pte;
+ uint32_t new_pte1;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
@@ -432,8 +408,17 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
/* 8. Update PTE referenced and changed bits if necessary */
- if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, 0, rwx) == 1) {
- ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
+ new_pte1 = pte.pte1 | HPTE32_R_R; /* set referenced bit */
+ if (rwx == 1) {
+ new_pte1 |= HPTE32_R_C; /* set changed (dirty) bit */
+ } else {
+ /* Treat the page as read-only for now, so that a later write
+ * will pass through this function again to set the C bit */
+ ctx->prot &= ~PAGE_WRITE;
+ }
+
+ if (new_pte1 != pte.pte1) {
+ ppc_hash32_store_hpte1(env, pte_offset, new_pte1);
}
/* Keep the matching PTE informations */
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 5607ce8..c76abb7 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -280,31 +280,6 @@ static int ppc_hash64_pte_prot(CPUPPCState *env,
return prot;
}
-static int ppc_hash64_pte_update_flags(struct mmu_ctx_hash64 *ctx,
- uint64_t *pte1p, int ret, int rw)
-{
- int store = 0;
-
- /* Update page flags */
- if (!(*pte1p & HPTE64_R_R)) {
- /* Update accessed flag */
- *pte1p |= HPTE64_R_R;
- store = 1;
- }
- if (!(*pte1p & HPTE64_R_C)) {
- if (rw == 1 && ret == 0) {
- /* Update changed flag */
- *pte1p |= HPTE64_R_C;
- store = 1;
- } else {
- /* Force page fault for first write access */
- ctx->prot &= ~PAGE_WRITE;
- }
- }
-
- return store;
-}
-
static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
bool secondary, target_ulong ptem,
ppc_hash_pte64_t *pte)
@@ -393,6 +368,7 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ppc_slb_t *slb;
hwaddr pte_offset;
ppc_hash_pte64_t pte;
+ uint64_t new_pte1;
int target_page_bits;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
@@ -440,8 +416,17 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
/* 6. Update PTE referenced and changed bits if necessary */
- if (ppc_hash64_pte_update_flags(ctx, &pte.pte1, 0, rwx) == 1) {
- ppc_hash64_store_hpte1(env, pte_offset, pte.pte1);
+ new_pte1 = pte.pte1 | HPTE64_R_R; /* set referenced bit */
+ if (rwx == 1) {
+ new_pte1 |= HPTE64_R_C; /* set changed (dirty) bit */
+ } else {
+ /* Treat the page as read-only for now, so that a later write
+ * will pass through this function again to set the C bit */
+ ctx->prot &= ~PAGE_WRITE;
+ }
+
+ if (new_pte1 != pte.pte1) {
+ ppc_hash64_store_hpte1(env, pte_offset, new_pte1);
}
/* Keep the matching PTE informations */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 41/48] mmu-hash*: Clean up real address calculation
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (39 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 40/48] mmu-hash*: Clean up PTE flags update David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 42/48] mmu-hash*: Correctly mask RPN from hash PTE David Gibson
` (7 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
More recent 64-bit hash MMUs support multiple page sizes, and PTEs for
large pages only include the offset of the whole large page. But the qemu
tlb only handles pages of the base size (4k) so we need to break up the
large pages into 4k pieces for the qemu tlb. To do that we have a somewhat
awkward piece of code that adds the folds address bits 4k and the page size
from the virtual address into the real address from the pte.
This patch simplifies this redefining the raddr output of
ppc_hash64_translate() to be the full real address of the faulting address,
rather than just the (4k) page offset. Computing that turns out to be
simpler, and is fine for the caller, since it already masks with
TARGET_PAGE_MASK before inserting into the qemu tlb.
The multiple page size complication doesn't exist for 32-bit hash mmus, but
we make an analogous cleanup there for consistency.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 14 ++++++++++++--
target-ppc/mmu-hash64.c | 26 +++++++++++++++-----------
2 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 314b7d1..e5ee29b 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -343,6 +343,15 @@ static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
return pte_offset;
}
+static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
+ target_ulong eaddr)
+{
+ hwaddr rpn = pte.pte1;
+ hwaddr mask = ~TARGET_PAGE_MASK;
+
+ return (rpn & ~mask) | (eaddr & mask);
+}
+
static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
target_ulong eaddr, int rwx)
{
@@ -421,8 +430,9 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
ppc_hash32_store_hpte1(env, pte_offset, new_pte1);
}
- /* Keep the matching PTE informations */
- ctx->raddr = pte.pte1;
+ /* 9. Determine the real address from the PTE */
+
+ ctx->raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
return 0;
}
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index c76abb7..5e168d5 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -362,6 +362,18 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
return pte_offset;
}
+static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,
+ target_ulong eaddr)
+{
+ hwaddr rpn = pte.pte1;
+ /* FIXME: Add support for SLLP extended page sizes */
+ int target_page_bits = (slb->vsid & SLB_VSID_L)
+ ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+ hwaddr mask = (1ULL << target_page_bits) - 1;
+
+ return (rpn & ~mask) | (eaddr & mask);
+}
+
static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
target_ulong eaddr, int rwx)
{
@@ -369,7 +381,6 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
hwaddr pte_offset;
ppc_hash_pte64_t pte;
uint64_t new_pte1;
- int target_page_bits;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
@@ -429,17 +440,10 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
ppc_hash64_store_hpte1(env, pte_offset, new_pte1);
}
- /* Keep the matching PTE informations */
- ctx->raddr = pte.pte1;
+ /* 7. Determine the real address from the PTE */
+
+ ctx->raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
- /* We have a TLB that saves 4K pages, so let's
- * split a huge page to 4k chunks */
- target_page_bits = (slb->vsid & SLB_VSID_L)
- ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
- if (target_page_bits != TARGET_PAGE_BITS) {
- ctx->raddr |= (eaddr & ((1 << target_page_bits) - 1))
- & TARGET_PAGE_MASK;
- }
return 0;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 42/48] mmu-hash*: Correctly mask RPN from hash PTE
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (40 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 41/48] mmu-hash*: Clean up real address calculation David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 43/48] mmu-hash*: Don't use full ppc_hash{32, 64}_translate() path for get_phys_page_debug() David Gibson
` (6 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
BEHAVIOUR CHANGE
At present we take the whole of word 1 of the hash PTE as the real page
number used to calculate the translated address. This is incorrect,
because it leaves the flags from the low bits of PTE word 1 in place in the
rpm. We mostly get away with that because the value is later masked by
TARGET_PAGE_MASK.
More recent 64-bit CPUs also have a small number of flag bits (PP0 and
KEY) in the top bits of PTE word 1. Any guest which used those bits would
fail with the current code.
This patch fixes the problem by correctly masking out the RPN field of
PTE word 1. This is safe, even for older CPUs which didn't have PP0 and
KEY, because although the RPN notionally extended to the very top of PTE
word 1, none of those CPUs actually implemented that many real address
bits.
We add analogous masking to the 32-bit code, even though it also doesn't
have the high flag bits, for consistency and clarity.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 2 +-
target-ppc/mmu-hash64.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index e5ee29b..07e9b8c 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -346,7 +346,7 @@ static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
target_ulong eaddr)
{
- hwaddr rpn = pte.pte1;
+ hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
hwaddr mask = ~TARGET_PAGE_MASK;
return (rpn & ~mask) | (eaddr & mask);
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 5e168d5..d986c0f 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -365,7 +365,7 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,
target_ulong eaddr)
{
- hwaddr rpn = pte.pte1;
+ hwaddr rpn = pte.pte1 & HPTE64_R_RPN;
/* FIXME: Add support for SLLP extended page sizes */
int target_page_bits = (slb->vsid & SLB_VSID_L)
? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 43/48] mmu-hash*: Don't use full ppc_hash{32, 64}_translate() path for get_phys_page_debug()
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (41 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 42/48] mmu-hash*: Correctly mask RPN from hash PTE David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 44/48] mmu-hash*: Merge translate and fault handling functions David Gibson
` (5 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Currently the hash mmu versionsof get_phys_page_debug() use the same
ppc64_hash64_translate() function to do the translation logic as the normal
mm fault handler code.
That sounds like a good idea, but has some complications. The debug path
doesn't need, or even want some parts of the full translation path, like
permissions checking. Furthermore, the pte flags update included in the
normal path means that the debug call is not quite side effect free.
This patch, therefore, reimplements get_phys_page_debug as the minimal
required subset of the full translation path.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>`z
---
target-ppc/mmu-hash32.c | 34 +++++++++++++++++++++++++++-------
target-ppc/mmu-hash64.c | 19 ++++++++++++++++---
2 files changed, 43 insertions(+), 10 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 07e9b8c..5ec1a09 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -437,18 +437,38 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
return 0;
}
-hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
+hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong eaddr)
{
- struct mmu_ctx_hash32 ctx;
+ target_ulong sr;
+ hwaddr pte_offset;
+ ppc_hash_pte32_t pte;
+ int prot;
+
+ if (msr_dr == 0) {
+ /* Translation is off */
+ return eaddr;
+ }
+
+ if (env->nb_BATs != 0) {
+ hwaddr raddr = ppc_hash32_bat_lookup(env, eaddr, 0, &prot);
+ if (raddr != -1) {
+ return raddr;
+ }
+ }
+
+ sr = env->sr[eaddr >> 28];
+
+ if (sr & SR32_T) {
+ /* FIXME: Add suitable debug support for Direct Store segments */
+ return -1;
+ }
- /* FIXME: Will not behave sanely for direct store segments, but
- * they're almost never used */
- if (unlikely(ppc_hash32_translate(env, &ctx, addr, 0)
- != 0)) {
+ pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
+ if (pte_offset == -1) {
return -1;
}
- return ctx.raddr & TARGET_PAGE_MASK;
+ return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK;
}
int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index d986c0f..4a7dbbb 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -449,13 +449,26 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
{
- struct mmu_ctx_hash64 ctx;
+ ppc_slb_t *slb;
+ hwaddr pte_offset;
+ ppc_hash_pte64_t pte;
+
+ if (msr_dr == 0) {
+ /* In real mode the top 4 effective address bits are ignored */
+ return addr & 0x0FFFFFFFFFFFFFFFULL;
+ }
- if (unlikely(ppc_hash64_translate(env, &ctx, addr, 0) != 0)) {
+ slb = slb_lookup(env, addr);
+ if (!slb) {
+ return -1;
+ }
+
+ pte_offset = ppc_hash64_htab_lookup(env, slb, addr, &pte);
+ if (pte_offset == -1) {
return -1;
}
- return ctx.raddr & TARGET_PAGE_MASK;
+ return ppc_hash64_pte_raddr(slb, pte, addr) & TARGET_PAGE_MASK;
}
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 44/48] mmu-hash*: Merge translate and fault handling functions
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (42 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 43/48] mmu-hash*: Don't use full ppc_hash{32, 64}_translate() path for get_phys_page_debug() David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 45/48] mmu-hash64: Implement Virtual Page Class Key Protection David Gibson
` (4 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
ppc_hash{32,64}_handle_mmu_fault() is now the only caller of
ppc_hash{32,64{_translate(), so this patch combines them together. This
means that instead of one returning a variety of non-obvious error codes
which then get translated into the various mmu exception conditions, we can
just generate the exceptions as we discover problems in the translation
path. This also removes the last usage of mmu_ctx_hash{32,64}.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/mmu-hash32.c | 250 +++++++++++++++++++++--------------------------
target-ppc/mmu-hash64.c | 150 +++++++++++-----------------
2 files changed, 167 insertions(+), 233 deletions(-)
diff --git a/target-ppc/mmu-hash32.c b/target-ppc/mmu-hash32.c
index 5ec1a09..0946d76 100644
--- a/target-ppc/mmu-hash32.c
+++ b/target-ppc/mmu-hash32.c
@@ -238,7 +238,9 @@ static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
if (rwx == 2) {
/* No code fetch is allowed in direct-store areas */
- return -4;
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ return 1;
}
switch (env->access_type) {
@@ -247,10 +249,20 @@ static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
break;
case ACCESS_FLOAT:
/* Floating point load/store */
- return -4;
+ env->exception_index = POWERPC_EXCP_ALIGN;
+ env->error_code = POWERPC_EXCP_ALIGN_FP;
+ env->spr[SPR_DAR] = eaddr;
+ return 1;
case ACCESS_RES:
/* lwarx, ldarx or srwcx. */
- return -4;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ if (rwx == 1) {
+ env->spr[SPR_DSISR] = 0x06000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x04000000;
+ }
+ return 1;
case ACCESS_CACHE:
/* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
/* Should make the instruction do no-op.
@@ -260,17 +272,33 @@ static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
return 0;
case ACCESS_EXT:
/* eciwx or ecowx */
- return -4;
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ if (rwx == 1) {
+ env->spr[SPR_DSISR] = 0x06100000;
+ } else {
+ env->spr[SPR_DSISR] = 0x04100000;
+ }
+ return 1;
default:
qemu_log("ERROR: instruction should not need "
"address translation\n");
- return -4;
+ abort();
}
if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
*raddr = eaddr;
- return 2;
+ return 0;
} else {
- return -2;
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ if (rwx == 1) {
+ env->spr[SPR_DSISR] = 0x0a000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ return 1;
}
}
@@ -352,32 +380,53 @@ static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
return (rpn & ~mask) | (eaddr & mask);
}
-static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
- target_ulong eaddr, int rwx)
+int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr, int rwx,
+ int mmu_idx)
{
target_ulong sr;
hwaddr pte_offset;
ppc_hash_pte32_t pte;
+ int prot;
uint32_t new_pte1;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
+ hwaddr raddr;
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
/* 1. Handle real mode accesses */
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
/* Translation is off */
- ctx->raddr = eaddr;
- ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
+ raddr = eaddr;
+ tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
+ TARGET_PAGE_SIZE);
return 0;
}
/* 2. Check Block Address Translation entries (BATs) */
if (env->nb_BATs != 0) {
- ctx->raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &ctx->prot);
- if (ctx->raddr != -1) {
- if (need_prot[rwx] & ~ctx->prot) {
- return -2;
+ raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &prot);
+ if (raddr != -1) {
+ if (need_prot[rwx] & ~prot) {
+ if (rwx == 2) {
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x08000000;
+ } else {
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ if (rwx == 1) {
+ env->spr[SPR_DSISR] = 0x0a000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ }
+ return 1;
}
+
+ tlb_set_page(env, eaddr & TARGET_PAGE_MASK,
+ raddr & TARGET_PAGE_MASK, prot, mmu_idx,
+ TARGET_PAGE_SIZE);
return 0;
}
}
@@ -387,30 +436,66 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
/* 4. Handle direct store segments */
if (sr & SR32_T) {
- return ppc_hash32_direct_store(env, sr, eaddr, rwx,
- &ctx->raddr, &ctx->prot);
+ if (ppc_hash32_direct_store(env, sr, eaddr, rwx,
+ &raddr, &prot) == 0) {
+ tlb_set_page(env, eaddr & TARGET_PAGE_MASK,
+ raddr & TARGET_PAGE_MASK, prot, mmu_idx,
+ TARGET_PAGE_SIZE);
+ return 0;
+ } else {
+ return 1;
+ }
}
/* 5. Check for segment level no-execute violation */
if ((rwx == 2) && (sr & SR32_NX)) {
- return -3;
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ return 1;
}
/* 6. Locate the PTE in the hash table */
pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
if (pte_offset == -1) {
- return -1;
+ if (rwx == 2) {
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x40000000;
+ } else {
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ if (rwx == 1) {
+ env->spr[SPR_DSISR] = 0x42000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x40000000;
+ }
+ }
+
+ return 1;
}
LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
/* 7. Check access permissions */
- ctx->prot = ppc_hash32_pte_prot(env, sr, pte);
+ prot = ppc_hash32_pte_prot(env, sr, pte);
- if (need_prot[rwx] & ~ctx->prot) {
+ if (need_prot[rwx] & ~prot) {
/* Access right violation */
LOG_MMU("PTE access rejected\n");
- return -2;
+ if (rwx == 2) {
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x08000000;
+ } else {
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ if (rwx == 1) {
+ env->spr[SPR_DSISR] = 0x0a000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ }
+ return 1;
}
LOG_MMU("PTE access granted !\n");
@@ -423,7 +508,7 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
} else {
/* Treat the page as read-only for now, so that a later write
* will pass through this function again to set the C bit */
- ctx->prot &= ~PAGE_WRITE;
+ prot &= ~PAGE_WRITE;
}
if (new_pte1 != pte.pte1) {
@@ -432,7 +517,10 @@ static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
/* 9. Determine the real address from the PTE */
- ctx->raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
+ raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
+
+ tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+ prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
}
@@ -470,117 +558,3 @@ hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong eaddr)
return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK;
}
-
-int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
- int mmu_idx)
-{
- struct mmu_ctx_hash32 ctx;
- int ret = 0;
-
- ret = ppc_hash32_translate(env, &ctx, address, rwx);
- if (ret == 0) {
- tlb_set_page(env, address & TARGET_PAGE_MASK,
- ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
- mmu_idx, TARGET_PAGE_SIZE);
- ret = 0;
- } else if (ret < 0) {
- LOG_MMU_STATE(env);
- if (rwx == 2) {
- switch (ret) {
- case -1:
- /* No matches in page tables or TLB */
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x40000000;
- break;
- case -2:
- /* Access rights violation */
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x08000000;
- break;
- case -3:
- /* No execute protection violation */
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x10000000;
- break;
- case -4:
- /* Direct store exception */
- /* No code fetch is allowed in direct-store areas */
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x10000000;
- break;
- }
- } else {
- switch (ret) {
- case -1:
- /* No matches in page tables or TLB */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rwx == 1) {
- env->spr[SPR_DSISR] = 0x42000000;
- } else {
- env->spr[SPR_DSISR] = 0x40000000;
- }
- break;
- case -2:
- /* Access rights violation */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rwx == 1) {
- env->spr[SPR_DSISR] = 0x0A000000;
- } else {
- env->spr[SPR_DSISR] = 0x08000000;
- }
- break;
- case -4:
- /* Direct store exception */
- switch (env->access_type) {
- case ACCESS_FLOAT:
- /* Floating point load/store */
- env->exception_index = POWERPC_EXCP_ALIGN;
- env->error_code = POWERPC_EXCP_ALIGN_FP;
- env->spr[SPR_DAR] = address;
- break;
- case ACCESS_RES:
- /* lwarx, ldarx or stwcx. */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rwx == 1) {
- env->spr[SPR_DSISR] = 0x06000000;
- } else {
- env->spr[SPR_DSISR] = 0x04000000;
- }
- break;
- case ACCESS_EXT:
- /* eciwx or ecowx */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rwx == 1) {
- env->spr[SPR_DSISR] = 0x06100000;
- } else {
- env->spr[SPR_DSISR] = 0x04100000;
- }
- break;
- default:
- printf("DSI: invalid exception (%d)\n", ret);
- env->exception_index = POWERPC_EXCP_PROGRAM;
- env->error_code =
- POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
- env->spr[SPR_DAR] = address;
- break;
- }
- break;
- }
- }
-#if 0
- printf("%s: set exception to %d %02x\n", __func__,
- env->exception, env->error_code);
-#endif
- ret = 1;
- }
-
- return ret;
-}
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 4a7dbbb..f18c98f 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -40,11 +40,6 @@
# define LOG_SLB(...) do { } while (0)
#endif
-struct mmu_ctx_hash64 {
- hwaddr raddr; /* Real address */
- int prot; /* Protection bits */
-};
-
/*
* SLB handling
*/
@@ -374,14 +369,16 @@ static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,
return (rpn & ~mask) | (eaddr & mask);
}
-static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
- target_ulong eaddr, int rwx)
+int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
+ int rwx, int mmu_idx)
{
ppc_slb_t *slb;
hwaddr pte_offset;
ppc_hash_pte64_t pte;
+ int prot;
uint64_t new_pte1;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
+ hwaddr raddr;
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
@@ -389,8 +386,10 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
/* Translation is off */
/* In real mode the top 4 effective address bits are ignored */
- ctx->raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
- ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
+ raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
+ tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+ PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
+ TARGET_PAGE_SIZE);
return 0;
}
@@ -398,29 +397,65 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
slb = slb_lookup(env, eaddr);
if (!slb) {
- return -5;
+ if (rwx == 2) {
+ env->exception_index = POWERPC_EXCP_ISEG;
+ env->error_code = 0;
+ } else {
+ env->exception_index = POWERPC_EXCP_DSEG;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ }
+ return 1;
}
/* 3. Check for segment level no-execute violation */
if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
- return -3;
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x10000000;
+ return 1;
}
/* 4. Locate the PTE in the hash table */
pte_offset = ppc_hash64_htab_lookup(env, slb, eaddr, &pte);
if (pte_offset == -1) {
- return -1;
+ if (rwx == 2) {
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x40000000;
+ } else {
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ if (rwx == 1) {
+ env->spr[SPR_DSISR] = 0x42000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x40000000;
+ }
+ }
+ return 1;
}
LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
/* 5. Check access permissions */
- ctx->prot = ppc_hash64_pte_prot(env, slb, pte);
+ prot = ppc_hash64_pte_prot(env, slb, pte);
- if ((need_prot[rwx] & ~ctx->prot) != 0) {
+ if ((need_prot[rwx] & ~prot) != 0) {
/* Access right violation */
LOG_MMU("PTE access rejected\n");
- return -2;
+ if (rwx == 2) {
+ env->exception_index = POWERPC_EXCP_ISI;
+ env->error_code = 0x08000000;
+ } else {
+ env->exception_index = POWERPC_EXCP_DSI;
+ env->error_code = 0;
+ env->spr[SPR_DAR] = eaddr;
+ if (rwx == 1) {
+ env->spr[SPR_DSISR] = 0x0A000000;
+ } else {
+ env->spr[SPR_DSISR] = 0x08000000;
+ }
+ }
+ return 1;
}
LOG_MMU("PTE access granted !\n");
@@ -433,7 +468,7 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
} else {
/* Treat the page as read-only for now, so that a later write
* will pass through this function again to set the C bit */
- ctx->prot &= ~PAGE_WRITE;
+ prot &= ~PAGE_WRITE;
}
if (new_pte1 != pte.pte1) {
@@ -442,7 +477,10 @@ static int ppc_hash64_translate(CPUPPCState *env, struct mmu_ctx_hash64 *ctx,
/* 7. Determine the real address from the PTE */
- ctx->raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
+ raddr = ppc_hash64_pte_raddr(slb, pte, eaddr);
+
+ tlb_set_page(env, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
+ prot, mmu_idx, TARGET_PAGE_SIZE);
return 0;
}
@@ -470,81 +508,3 @@ hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
return ppc_hash64_pte_raddr(slb, pte, addr) & TARGET_PAGE_MASK;
}
-
-int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
- int mmu_idx)
-{
- struct mmu_ctx_hash64 ctx;
- int ret = 0;
-
- ret = ppc_hash64_translate(env, &ctx, address, rwx);
- if (ret == 0) {
- tlb_set_page(env, address & TARGET_PAGE_MASK,
- ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
- mmu_idx, TARGET_PAGE_SIZE);
- ret = 0;
- } else if (ret < 0) {
- LOG_MMU_STATE(env);
- if (rwx == 2) {
- switch (ret) {
- case -1:
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x40000000;
- break;
- case -2:
- /* Access rights violation */
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x08000000;
- break;
- case -3:
- /* No execute protection violation */
- env->exception_index = POWERPC_EXCP_ISI;
- env->error_code = 0x10000000;
- break;
- case -5:
- /* No match in segment table */
- env->exception_index = POWERPC_EXCP_ISEG;
- env->error_code = 0;
- break;
- }
- } else {
- switch (ret) {
- case -1:
- /* No matches in page tables or TLB */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rwx == 1) {
- env->spr[SPR_DSISR] = 0x42000000;
- } else {
- env->spr[SPR_DSISR] = 0x40000000;
- }
- break;
- case -2:
- /* Access rights violation */
- env->exception_index = POWERPC_EXCP_DSI;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- if (rwx == 1) {
- env->spr[SPR_DSISR] = 0x0A000000;
- } else {
- env->spr[SPR_DSISR] = 0x08000000;
- }
- break;
- case -5:
- /* No match in segment table */
- env->exception_index = POWERPC_EXCP_DSEG;
- env->error_code = 0;
- env->spr[SPR_DAR] = address;
- break;
- }
- }
-#if 0
- printf("%s: set exception to %d %02x\n", __func__,
- env->exception, env->error_code);
-#endif
- ret = 1;
- }
-
- return ret;
-}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 45/48] mmu-hash64: Implement Virtual Page Class Key Protection
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (43 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 44/48] mmu-hash*: Merge translate and fault handling functions David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 46/48] target-ppc: Split user only code out of mmu_helper.c David Gibson
` (3 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
Version 2.06 of the Power architecture describes an additional page
protection mechanism. Each virtual page has a "class" (0-31) recorded in
the PTE. The AMR register contains bits which can prohibit reads and/or
writes on a class by class basis. Interestingly, the AMR is userspace
readable and writable, however user mode writes are masked by the contents
of the UAMOR which is privileged.
This patch implements this protection mechanism, along with the AMR and
UAMOR SPRs. The architecture also specifies a hypervisor-privileged AMOR
register which masks user and supervisor writes to the AMR and UAMOR. We
leave this out for now, since we don't at present model hypervisor mode
correctly in any case.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 8 +++++--
target-ppc/mmu-hash64.c | 46 +++++++++++++++++++++++++++++++++++-----
target-ppc/mmu-hash64.h | 2 ++
target-ppc/translate_init.c | 49 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 98 insertions(+), 7 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 696551a..f42e184 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -113,11 +113,13 @@ enum powerpc_mmu_t {
#if defined(TARGET_PPC64)
#define POWERPC_MMU_64 0x00010000
#define POWERPC_MMU_1TSEG 0x00020000
+#define POWERPC_MMU_AMR 0x00040000
/* 64 bits PowerPC MMU */
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
/* Architecture 2.06 variant */
- POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
- /* Architecture 2.06 "degraded" (no 1T segments) */
+ POWERPC_MMU_2_06 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
+ | POWERPC_MMU_AMR | 0x00000003,
+ /* Architecture 2.06 "degraded" (no 1T segments or AMR) */
POWERPC_MMU_2_06d = POWERPC_MMU_64 | 0x00000003,
#endif /* defined(TARGET_PPC64) */
};
@@ -1222,6 +1224,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_601_UDECR (0x006)
#define SPR_LR (0x008)
#define SPR_CTR (0x009)
+#define SPR_UAMR (0x00C)
#define SPR_DSCR (0x011)
#define SPR_DSISR (0x012)
#define SPR_DAR (0x013) /* DAE for PowerPC 601 */
@@ -1259,6 +1262,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_MPC_CMPH (0x09B)
#define SPR_MPC_LCTRL1 (0x09C)
#define SPR_MPC_LCTRL2 (0x09D)
+#define SPR_UAMOR (0x09D)
#define SPR_MPC_ICTRL (0x09E)
#define SPR_MPC_BAR (0x09F)
#define SPR_VRSAVE (0x100)
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index f18c98f..43ccf45 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -275,6 +275,33 @@ static int ppc_hash64_pte_prot(CPUPPCState *env,
return prot;
}
+static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
+{
+ int key, amrbits;
+ int prot = PAGE_EXEC;
+
+
+ /* Only recent MMUs implement Virtual Page Class Key Protection */
+ if (!(env->mmu_model & POWERPC_MMU_AMR)) {
+ return PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ }
+
+ key = HPTE64_R_KEY(pte.pte1);
+ amrbits = (env->spr[SPR_AMR] >> 2*(31 - key)) & 0x3;
+
+ /* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */
+ /* env->spr[SPR_AMR]); */
+
+ if (amrbits & 0x2) {
+ prot |= PAGE_WRITE;
+ }
+ if (amrbits & 0x1) {
+ prot |= PAGE_READ;
+ }
+
+ return prot;
+}
+
static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
bool secondary, target_ulong ptem,
ppc_hash_pte64_t *pte)
@@ -375,7 +402,7 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
ppc_slb_t *slb;
hwaddr pte_offset;
ppc_hash_pte64_t pte;
- int prot;
+ int pp_prot, amr_prot, prot;
uint64_t new_pte1;
const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
hwaddr raddr;
@@ -437,7 +464,9 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
/* 5. Check access permissions */
- prot = ppc_hash64_pte_prot(env, slb, pte);
+ pp_prot = ppc_hash64_pte_prot(env, slb, pte);
+ amr_prot = ppc_hash64_amr_prot(env, pte);
+ prot = pp_prot & amr_prot;
if ((need_prot[rwx] & ~prot) != 0) {
/* Access right violation */
@@ -446,14 +475,21 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x08000000;
} else {
+ target_ulong dsisr = 0;
+
env->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
+ if (need_prot[rwx] & ~pp_prot) {
+ dsisr |= 0x08000000;
+ }
if (rwx == 1) {
- env->spr[SPR_DSISR] = 0x0A000000;
- } else {
- env->spr[SPR_DSISR] = 0x08000000;
+ dsisr |= 0x02000000;
+ }
+ if (need_prot[rwx] & ~amr_prot) {
+ dsisr |= 0x00200000;
}
+ env->spr[SPR_DSISR] = dsisr;
}
return 1;
}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index 1ce6e5b..5e6e506 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -69,6 +69,8 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
#define HPTE64_R_C 0x0000000000000080ULL
#define HPTE64_R_R 0x0000000000000100ULL
#define HPTE64_R_KEY_LO 0x0000000000000e00ULL
+#define HPTE64_R_KEY(x) ((((x) & HPTE64_R_KEY_HI) >> 60) | \
+ (((x) & HPTE64_R_KEY_LO) >> 9))
#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index c580d62..b2a76d0 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -1017,6 +1017,54 @@ static void gen_spr_7xx (CPUPPCState *env)
0x00000000);
}
+#ifdef TARGET_PPC64
+#ifndef CONFIG_USER_ONLY
+static void spr_read_uamr (void *opaque, int gprn, int sprn)
+{
+ gen_load_spr(cpu_gpr[gprn], SPR_AMR);
+ spr_load_dump_spr(SPR_AMR);
+}
+
+static void spr_write_uamr (void *opaque, int sprn, int gprn)
+{
+ gen_store_spr(SPR_AMR, cpu_gpr[gprn]);
+ spr_store_dump_spr(SPR_AMR);
+}
+
+static void spr_write_uamr_pr (void *opaque, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+
+ gen_load_spr(t0, SPR_UAMOR);
+ tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+ gen_store_spr(SPR_AMR, t0);
+ spr_store_dump_spr(SPR_AMR);
+}
+#endif /* CONFIG_USER_ONLY */
+
+static void gen_spr_amr (CPUPPCState *env)
+{
+#ifndef CONFIG_USER_ONLY
+ /* Virtual Page Class Key protection */
+ /* The AMR is accessible either via SPR 13 or SPR 29. 13 is
+ * userspace accessible, 29 is privileged. So we only need to set
+ * the kvm ONE_REG id on one of them, we use 29 */
+ spr_register(env, SPR_UAMR, "UAMR",
+ &spr_read_uamr, &spr_write_uamr_pr,
+ &spr_read_uamr, &spr_write_uamr,
+ 0);
+ spr_register_kvm(env, SPR_AMR, "AMR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_AMR, 0xffffffffffffffff);
+ spr_register_kvm(env, SPR_UAMOR, "UAMOR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_UAMOR, 0);
+#endif /* !CONFIG_USER_ONLY */
+}
+#endif /* TARGET_PPC64 */
+
static void gen_spr_thrm (CPUPPCState *env)
{
/* Thermal management */
@@ -6872,6 +6920,7 @@ static void init_proc_POWER7 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
0x00000000); /* TOFIX */
+ gen_spr_amr(env);
/* XXX : not implemented */
spr_register(env, SPR_CTRL, "SPR_CTRLT",
SPR_NOACCESS, SPR_NOACCESS,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 46/48] target-ppc: Split user only code out of mmu_helper.c
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (44 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 45/48] mmu-hash64: Implement Virtual Page Class Key Protection David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 47/48] target-ppc: Move ppc tlb_fill implementation into mmu_helper.c David Gibson
` (2 subsequent siblings)
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
mmu_helper.c is, for obvious reasons, almost entirely concerned with
softmmu builds of qemu. However, it does contain one stub function which
is used when CONFIG_USER_ONLY=y - the user only versoin of
cpu_ppc_handle_mmu_fault, which always triggers an exception. The entire
rest of the file is surrounded by #if !defined(CONFIG_USER_ONLY).
We clean this up by moving the user only stub into its own new file,
removing the ifdefs and building mmu_helper.c only when CONFIG_SOFTMMU
is set. This also lets us remove the #define of cpu_handle_mmu_fault to
cpu_ppc_handle_mmu_fault - that name is only used from generic code for
user only - so we just name our split user version by the generic name.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/Makefile.objs | 4 ++--
target-ppc/cpu.h | 5 ++++-
target-ppc/mmu_helper.c | 28 --------------------------
target-ppc/user_only_helper.c | 44 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 50 insertions(+), 31 deletions(-)
create mode 100644 target-ppc/user_only_helper.c
diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index c80911f..2c43c34 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -1,14 +1,14 @@
obj-y += cpu-models.o
obj-y += translate.o
ifeq ($(CONFIG_SOFTMMU),y)
-obj-y += machine.o mmu-hash32.o
+obj-y += machine.o mmu_helper.o mmu-hash32.o
obj-$(TARGET_PPC64) += mmu-hash64.o
endif
obj-$(CONFIG_KVM) += kvm.o kvm_ppc.o
obj-y += excp_helper.o
obj-y += fpu_helper.o
obj-y += int_helper.o
-obj-y += mmu_helper.o
obj-y += timebase_helper.o
obj-y += misc_helper.o
obj-y += mem_helper.o
+obj-$(CONFIG_USER_ONLY) += user_only_helper.o
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index f42e184..b616a94 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1092,9 +1092,12 @@ int cpu_ppc_signal_handler (int host_signum, void *pinfo,
void *puc);
int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
-#define cpu_handle_mmu_fault cpu_ppc_handle_mmu_fault
void do_interrupt (CPUPPCState *env);
void ppc_hw_interrupt (CPUPPCState *env);
+#if defined(CONFIG_USER_ONLY)
+int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx);
+#endif
#if !defined(CONFIG_USER_ONLY)
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index c780ce1..525eb6f 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -52,31 +52,6 @@
/*****************************************************************************/
/* PowerPC MMU emulation */
-#if defined(CONFIG_USER_ONLY)
-int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
- int mmu_idx)
-{
- int exception, error_code;
-
- if (rw == 2) {
- exception = POWERPC_EXCP_ISI;
- error_code = 0x40000000;
- } else {
- exception = POWERPC_EXCP_DSI;
- error_code = 0x40000000;
- if (rw) {
- error_code |= 0x02000000;
- }
- env->spr[SPR_DAR] = address;
- env->spr[SPR_DSISR] = error_code;
- }
- env->exception_index = exception;
- env->error_code = error_code;
-
- return 1;
-}
-
-#else
/* Context used internally during MMU translations */
typedef struct mmu_ctx_t mmu_ctx_t;
@@ -2027,9 +2002,7 @@ void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
#endif
}
}
-#endif /* !defined(CONFIG_USER_ONLY) */
-#if !defined(CONFIG_USER_ONLY)
/* TLB management */
void helper_tlbia(CPUPPCState *env)
{
@@ -2804,4 +2777,3 @@ void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
booke206_flush_tlb(env, flags, 1);
}
-#endif
diff --git a/target-ppc/user_only_helper.c b/target-ppc/user_only_helper.c
new file mode 100644
index 0000000..56e686e
--- /dev/null
+++ b/target-ppc/user_only_helper.c
@@ -0,0 +1,44 @@
+/*
+ * PowerPC MMU stub handling for user mode emulation
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ * Copyright (c) 2013 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+
+int cpu_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
+ int mmu_idx)
+{
+ int exception, error_code;
+
+ if (rw == 2) {
+ exception = POWERPC_EXCP_ISI;
+ error_code = 0x40000000;
+ } else {
+ exception = POWERPC_EXCP_DSI;
+ error_code = 0x40000000;
+ if (rw) {
+ error_code |= 0x02000000;
+ }
+ env->spr[SPR_DAR] = address;
+ env->spr[SPR_DSISR] = error_code;
+ }
+ env->exception_index = exception;
+ env->error_code = error_code;
+
+ return 1;
+}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 47/48] target-ppc: Move ppc tlb_fill implementation into mmu_helper.c
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (45 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 46/48] target-ppc: Split user only code out of mmu_helper.c David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 48/48] target-ppc: Use QOM method dispatch for MMU fault handling David Gibson
2013-03-21 13:43 ` [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs Alexander Graf
48 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
For softmmu builds the interface from the generic code to the target
specific MMU implementation is through the tlb_fill() function. For ppc
this is currently in mem_helper.c, whereas it would make more sense in
mmu_helper.c. This patch moves it, which also allows
cpu_ppc_handle_mmu_fault() to become a local function in mmu_helper.c
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 2 --
target-ppc/mem_helper.c | 38 --------------------------------------
target-ppc/mmu_helper.c | 40 ++++++++++++++++++++++++++++++++++++++--
3 files changed, 38 insertions(+), 42 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index b616a94..0b2d0b9 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1090,8 +1090,6 @@ int cpu_ppc_exec (CPUPPCState *s);
is returned if the signal was handled by the virtual CPU. */
int cpu_ppc_signal_handler (int host_signum, void *pinfo,
void *puc);
-int cpu_ppc_handle_mmu_fault (CPUPPCState *env, target_ulong address, int rw,
- int mmu_idx);
void do_interrupt (CPUPPCState *env);
void ppc_hw_interrupt (CPUPPCState *env);
#if defined(CONFIG_USER_ONLY)
diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index ba383c8..9783e52 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -252,41 +252,3 @@ STVE(stvewx, cpu_stl_data, bswap32, u32)
#undef HI_IDX
#undef LO_IDX
-
-/*****************************************************************************/
-/* Softmmu support */
-#if !defined(CONFIG_USER_ONLY)
-
-#define MMUSUFFIX _mmu
-
-#define SHIFT 0
-#include "exec/softmmu_template.h"
-
-#define SHIFT 1
-#include "exec/softmmu_template.h"
-
-#define SHIFT 2
-#include "exec/softmmu_template.h"
-
-#define SHIFT 3
-#include "exec/softmmu_template.h"
-
-/* try to fill the TLB and return an exception if error. If retaddr is
- NULL, it means that the function was called in C code (i.e. not
- from generated code or from helper.c) */
-/* XXX: fix it to restore all registers */
-void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
- uintptr_t retaddr)
-{
- int ret;
-
- ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
- if (unlikely(ret != 0)) {
- if (likely(retaddr)) {
- /* now we have a real cpu fault */
- cpu_restore_state(env, retaddr);
- }
- helper_raise_exception_err(env, env->exception_index, env->error_code);
- }
-}
-#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 525eb6f..4c41673 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1384,8 +1384,8 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
}
/* Perform address translation */
-int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
- int mmu_idx)
+static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
+ int rw, int mmu_idx)
{
mmu_ctx_t ctx;
int access_type;
@@ -2777,3 +2777,39 @@ void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
booke206_flush_tlb(env, flags, 1);
}
+
+
+/*****************************************************************************/
+
+#define MMUSUFFIX _mmu
+
+#define SHIFT 0
+#include "exec/softmmu_template.h"
+
+#define SHIFT 1
+#include "exec/softmmu_template.h"
+
+#define SHIFT 2
+#include "exec/softmmu_template.h"
+
+#define SHIFT 3
+#include "exec/softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error. If retaddr is
+ NULL, it means that the function was called in C code (i.e. not
+ from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
+ uintptr_t retaddr)
+{
+ int ret;
+
+ ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ if (unlikely(ret != 0)) {
+ if (likely(retaddr)) {
+ /* now we have a real cpu fault */
+ cpu_restore_state(env, retaddr);
+ }
+ helper_raise_exception_err(env, env->exception_index, env->error_code);
+ }
+}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* [Qemu-devel] [PATCH 48/48] target-ppc: Use QOM method dispatch for MMU fault handling
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (46 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 47/48] target-ppc: Move ppc tlb_fill implementation into mmu_helper.c David Gibson
@ 2013-03-12 10:31 ` David Gibson
2013-03-13 0:42 ` [Qemu-devel] [Qemu-ppc] " David Gibson
2013-03-21 13:43 ` [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs Alexander Graf
48 siblings, 1 reply; 51+ messages in thread
From: David Gibson @ 2013-03-12 10:31 UTC (permalink / raw)
To: agraf; +Cc: David Gibson, qemu-ppc, afaerber, qemu-devel
After previous cleanups, the many scattered checks of env->mmu_model in
the ppc MMU implementation have, at least for "classic" hash MMUs been
reduced (almost) to a single switch at the top of
cpu_ppc_handle_mmu_fault().
An explicit switch is still a pretty ugly way of handling this though. Now
that Andreas Färber's CPU QOM cleanups for ppc have gone in, it's quite
straightforward to instead make the handle_mmu_fault function a QOM method
on the CPU object.
This patch implements such a scheme, initializing the method pointer at
the same time as the mmu_model variable. We need to keep the latter around
for now, because of the MMU types (BookE, 4xx, et al) which haven't been
converted to the new scheme yet, and also for a few other uses. It would
be good to clean those up eventually.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu-qom.h | 4 ++++
target-ppc/mmu_helper.c | 24 +++++++-----------------
target-ppc/translate_init.c | 20 +++++++++++++++++++-
3 files changed, 30 insertions(+), 18 deletions(-)
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 2bf0ab6..8a08958 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -68,6 +68,10 @@ typedef struct PowerPCCPUClass {
#endif
void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env);
+#if defined(CONFIG_SOFTMMU)
+ int (*handle_mmu_fault)(CPUPPCState *env, target_ulong eaddr, int rwx,
+ int mmu_idx);
+#endif
} PowerPCCPUClass;
/**
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 4c41673..acf0133 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1391,22 +1391,6 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
int access_type;
int ret = 0;
- switch (env->mmu_model) {
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
- return ppc_hash64_handle_mmu_fault(env, address, rw, mmu_idx);
-#endif
-
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
- return ppc_hash32_handle_mmu_fault(env, address, rw, mmu_idx);
-
- default:
- ; /* Otherwise fall through to the general code below */
- }
-
if (rw == 2) {
/* code access */
rw = 0;
@@ -2802,9 +2786,15 @@ void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr)
{
+ CPUState *cpu = ENV_GET_CPU(env);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
int ret;
- ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ if (pcc->handle_mmu_fault) {
+ ret = pcc->handle_mmu_fault(env, addr, is_write, mmu_idx);
+ } else {
+ ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ }
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index b2a76d0..6803ae3 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -25,6 +25,8 @@
#include "sysemu/arch_init.h"
#include "sysemu/cpus.h"
#include "cpu-models.h"
+#include "mmu-hash32.h"
+#include "mmu-hash64.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@@ -4796,6 +4798,7 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000000FD70ULL;
pcc->mmu_model = POWERPC_MMU_601;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_601;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_601;
@@ -4830,7 +4833,7 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000000FD70ULL;
pcc->mmu_model = POWERPC_MMU_601;
- pcc->excp_model = POWERPC_EXCP_601;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_601;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK;
@@ -5037,6 +5040,7 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_604;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_604;
@@ -5103,6 +5107,7 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_604;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_604;
@@ -5156,6 +5161,7 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5217,6 +5223,7 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5401,6 +5408,7 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5466,6 +5474,7 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5536,6 +5545,7 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5606,6 +5616,7 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5798,6 +5809,7 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000205FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_74xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_7400;
@@ -5864,6 +5876,7 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000205FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_74xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_7400;
@@ -6570,6 +6583,7 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x900000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@@ -6680,6 +6694,7 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@@ -6778,6 +6793,7 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@@ -6876,6 +6892,7 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x900000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@@ -6968,6 +6985,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
pcc->excp_model = POWERPC_EXCP_POWER7;
pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
pcc->bfd_mach = bfd_mach_ppc64;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 51+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] [PATCH 48/48] target-ppc: Use QOM method dispatch for MMU fault handling
2013-03-12 10:31 ` [Qemu-devel] [PATCH 48/48] target-ppc: Use QOM method dispatch for MMU fault handling David Gibson
@ 2013-03-13 0:42 ` David Gibson
0 siblings, 0 replies; 51+ messages in thread
From: David Gibson @ 2013-03-13 0:42 UTC (permalink / raw)
To: agraf; +Cc: qemu-ppc, afaerber, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 11347 bytes --]
Oops. Screwed this one up so as to break compile for
CONFIG_USER_ONLY. Fixed version below.
From 0fd64364fcc0af95b23e17fa8ba58c28685a3a02 Mon Sep 17 00:00:00 2001
From: David Gibson <david@gibson.dropbear.id.au>
Date: Wed, 13 Mar 2013 11:40:33 +1100
Subject: [PATCH] target-ppc: Use QOM method dispatch for MMU fault handling
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
After previous cleanups, the many scattered checks of env->mmu_model in
the ppc MMU implementation have, at least for "classic" hash MMUs been
reduced (almost) to a single switch at the top of
cpu_ppc_handle_mmu_fault().
An explicit switch is still a pretty ugly way of handling this though. Now
that Andreas Färber's CPU QOM cleanups for ppc have gone in, it's quite
straightforward to instead make the handle_mmu_fault function a QOM method
on the CPU object.
This patch implements such a scheme, initializing the method pointer at
the same time as the mmu_model variable. We need to keep the latter around
for now, because of the MMU types (BookE, 4xx, et al) which haven't been
converted to the new scheme yet, and also for a few other uses. It would
be good to clean those up eventually.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu-qom.h | 4 ++++
target-ppc/mmu_helper.c | 24 ++++++-------------
target-ppc/translate_init.c | 54 ++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 64 insertions(+), 18 deletions(-)
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 2bf0ab6..8a08958 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -68,6 +68,10 @@ typedef struct PowerPCCPUClass {
#endif
void (*init_proc)(CPUPPCState *env);
int (*check_pow)(CPUPPCState *env);
+#if defined(CONFIG_SOFTMMU)
+ int (*handle_mmu_fault)(CPUPPCState *env, target_ulong eaddr, int rwx,
+ int mmu_idx);
+#endif
} PowerPCCPUClass;
/**
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 4c41673..acf0133 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -1391,22 +1391,6 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
int access_type;
int ret = 0;
- switch (env->mmu_model) {
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_06d:
- return ppc_hash64_handle_mmu_fault(env, address, rw, mmu_idx);
-#endif
-
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
- return ppc_hash32_handle_mmu_fault(env, address, rw, mmu_idx);
-
- default:
- ; /* Otherwise fall through to the general code below */
- }
-
if (rw == 2) {
/* code access */
rw = 0;
@@ -2802,9 +2786,15 @@ void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr)
{
+ CPUState *cpu = ENV_GET_CPU(env);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
int ret;
- ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ if (pcc->handle_mmu_fault) {
+ ret = pcc->handle_mmu_fault(env, addr, is_write, mmu_idx);
+ } else {
+ ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+ }
if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index b2a76d0..3cf440e 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -25,6 +25,8 @@
#include "sysemu/arch_init.h"
#include "sysemu/cpus.h"
#include "cpu-models.h"
+#include "mmu-hash32.h"
+#include "mmu-hash64.h"
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
@@ -4796,6 +4798,9 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000000FD70ULL;
pcc->mmu_model = POWERPC_MMU_601;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_601;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_601;
@@ -4830,7 +4835,9 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000000FD70ULL;
pcc->mmu_model = POWERPC_MMU_601;
- pcc->excp_model = POWERPC_EXCP_601;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_601;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK;
@@ -5037,6 +5044,9 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_604;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_604;
@@ -5103,6 +5113,9 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_604;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_604;
@@ -5156,6 +5169,9 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5217,6 +5233,9 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5401,6 +5420,9 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5466,6 +5488,9 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5536,6 +5561,9 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5606,6 +5634,9 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000005FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_7x0;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
@@ -5798,6 +5829,9 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000205FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_74xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_7400;
@@ -5864,6 +5898,9 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x000000000205FF77ULL;
pcc->mmu_model = POWERPC_MMU_32B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_74xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_7400;
@@ -6570,6 +6607,9 @@ POWERPC_FAMILY(970)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x900000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@@ -6680,6 +6720,9 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@@ -6778,6 +6821,9 @@ POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@@ -6876,6 +6922,9 @@ POWERPC_FAMILY(970MP)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC_NONE;
pcc->msr_mask = 0x900000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_64B;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_970;
pcc->bus_model = PPC_FLAGS_INPUT_970;
pcc->bfd_mach = bfd_mach_ppc64;
@@ -6968,6 +7017,9 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
+#if defined(CONFIG_SOFTMMU)
+ pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
+#endif
pcc->excp_model = POWERPC_EXCP_POWER7;
pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
pcc->bfd_mach = bfd_mach_ppc64;
--
1.7.10.4
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related [flat|nested] 51+ messages in thread
* Re: [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
` (47 preceding siblings ...)
2013-03-12 10:31 ` [Qemu-devel] [PATCH 48/48] target-ppc: Use QOM method dispatch for MMU fault handling David Gibson
@ 2013-03-21 13:43 ` Alexander Graf
48 siblings, 0 replies; 51+ messages in thread
From: Alexander Graf @ 2013-03-21 13:43 UTC (permalink / raw)
To: David Gibson; +Cc: qemu-ppc, afaerber, qemu-devel
On 12.03.2013, at 11:31, David Gibson wrote:
> This large patch series makes a serious overhaul of the MMU
> implementation for target-ppc. Previously all the quite dissimilar
> PowerPC MMU variants attempted to use a more-or-less common code path,
> with dependencies on env->mmu_model scattered throughout. The
> resulting confused code was not worth the handful of saved lines.
>
> This series starts the transition to a new model, where the different
> MMU types are represented by appropriate QOM methods on the CPU
> object. For now, only the main translation path - previously
> cpu_ppc_handle_mmu_fault() is made such a method, but more could be
> added in future. For now, 32-bit and 64-bit hash page table based
> MMUs (the "classic" PPC MMUs) are given their own handle_mmu_fault
> functions - the remaining MMU types retain the old code for now, I'm
> hoping those more familiar with them will perform a similar conversion
> in future though.
>
> There's plenty more cleanup that could be done. As well as the
> obvious work to convert other MMU types, there's room for improvement
> in: handling of SDR1 and other SPRs, handling of segment registers,
> switching MMU code to user PowerPCCPU instead of CPUPPCState, remove
> the duplicate mmu_model in PowerpCCPUClass and CPUPPCState, removing
> remaining uses of mmu_model. But if I tackled all those now, I might
> never get this series ready.
Thanks a lot, applied all to ppc-next :). With a few 32-bit host fixes. I'll only push it out once the other TCG breakage is solved, so that I can verify this actually works on 32-bit hosts (it fails there today, but very very likely not due to your patches)
Alex
^ permalink raw reply [flat|nested] 51+ messages in thread
end of thread, other threads:[~2013-03-21 13:43 UTC | newest]
Thread overview: 51+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-12 10:31 [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 01/48] target-ppc: Remove vestigial PowerPC 620 support David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 02/48] target-ppc: Trivial cleanups in mmu_helper.c David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 03/48] target-ppc: Remove address check for logging David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 04/48] target-ppc: Move SLB handling into a mmu-hash64.c David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 05/48] target-ppc: Disentangle pte_check() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 06/48] target-ppc: Disentangle find_pte() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 07/48] target-ppc: Disentangle get_segment() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 08/48] target-ppc: Rework get_physical_address() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 09/48] target-ppc: Disentangle get_physical_address() paths David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 10/48] target-ppc: Disentangle hash mmu paths for cpu_ppc_handle_mmu_fault David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 11/48] target-ppc: Disentangle hash mmu versions of cpu_get_phys_page_debug() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 12/48] target-ppc: Disentangle hash mmu helper functions David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 13/48] target-ppc: Don't share get_pteg_offset() between 32 and 64-bit David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 14/48] target-ppc: Disentangle BAT code for 32-bit hash MMUs David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 15/48] target-ppc: mmu_ctx_t should not be a global type David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 16/48] mmu-hash*: Add header file for definitions David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 17/48] mmu-hash*: Add hash pte load/store helpers David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 18/48] mmu-hash*: Reduce use of access_type David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 19/48] mmu-hash64: Remove nx from mmu_ctx_hash64 David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 20/48] mmu-hash*: Remove eaddr field from mmu_ctx_hash{32, 64} David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 21/48] mmu-hash*: Combine ppc_hash{32, 64}_get_physical_address and get_segment{32, 64}() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 22/48] mmu-hash32: Split out handling of direct store segments David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 23/48] mmu-hash32: Split direct store segment handling into a helper David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 24/48] mmu-hash*: Cleanup segment-level NX check David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 25/48] mmu-hash*: Don't keep looking for PTEs after we find a match David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 26/48] mmu-hash*: Separate PTEG searching from permissions checking David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 27/48] mmu-hash*: Make find_pte{32, 64} do more of the job of finding ptes David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 28/48] mmu-hash*: Remove permission checking from find_pte{32, 64}() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 29/48] mmu-hash64: Clean up ppc_hash64_htab_lookup() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 30/48] mmu-hash*: Fold pte_check*() logic into caller David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 31/48] mmu-hash32: Remove odd pointer usage from BAT code David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 32/48] mmu-hash32: Split BAT size logic from permissions logic David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 33/48] mmu-hash32: Clean up BAT matching logic David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 34/48] mmu-hash32: Cleanup BAT lookup David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 35/48] mmu-hash32: Don't look up page tables on BAT permission error David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 36/48] mmu-hash*: Don't update PTE flags when permission is denied David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 37/48] mmu-hash32: Remove nx from context structure David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 38/48] mmu-hash*: Clean up permission checking David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 39/48] mmu-hash64: Factor SLB N bit into permissions bits David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 40/48] mmu-hash*: Clean up PTE flags update David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 41/48] mmu-hash*: Clean up real address calculation David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 42/48] mmu-hash*: Correctly mask RPN from hash PTE David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 43/48] mmu-hash*: Don't use full ppc_hash{32, 64}_translate() path for get_phys_page_debug() David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 44/48] mmu-hash*: Merge translate and fault handling functions David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 45/48] mmu-hash64: Implement Virtual Page Class Key Protection David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 46/48] target-ppc: Split user only code out of mmu_helper.c David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 47/48] target-ppc: Move ppc tlb_fill implementation into mmu_helper.c David Gibson
2013-03-12 10:31 ` [Qemu-devel] [PATCH 48/48] target-ppc: Use QOM method dispatch for MMU fault handling David Gibson
2013-03-13 0:42 ` [Qemu-devel] [Qemu-ppc] " David Gibson
2013-03-21 13:43 ` [Qemu-devel] [0/48] target-ppc: MMU implementation cleanup for hash MMUs Alexander Graf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).