[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-ppc] [PATCH 5/8] target-ppc: Disentangle 64-bit version of get_seg
From: |
David Gibson |
Subject: |
[Qemu-ppc] [PATCH 5/8] target-ppc: Disentangle 64-bit version of get_segment() |
Date: |
Tue, 12 Feb 2013 13:00:08 +1100 |
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.
Signed-off-by: David Gibson <address@hidden>
---
target-ppc/cpu.h | 5 +--
target-ppc/mmu-hash64.c | 114 +++++++++++++++++++++++++++++++++++++++++++++--
target-ppc/mmu_helper.c | 108 +++++++++++++-------------------------------
3 files changed, 143 insertions(+), 84 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index da4bc17..cf12632 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1152,10 +1152,9 @@ hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash,
int pte_size);
#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);
-ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr);
void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
-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 /* 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
index 465592a..1d6425c 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -43,7 +43,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;
@@ -275,8 +275,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;
@@ -348,3 +348,111 @@ 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 ds %d nx %d vsid " TARGET_FMT_lx "\n",
+ ctx->key, ds, 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 */
+ 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]);
+ }
+ ret2 = find_pte64(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;
+ }
+
+ return ret;
+}
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 48dc658..e9f8949 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -578,87 +578,35 @@ static inline int find_pte32(CPUPPCState *env, mmu_ctx_t
*ctx, int h,
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_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_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;
-#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);
+ 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);
- 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);
- }
LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
ctx->key, ds, ctx->nx, vsid);
ret = -1;
@@ -685,7 +633,7 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t
*ctx,
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);
+ ret = find_pte32(env, ctx, 0, rw, type, target_page_bits);
if (ret < 0) {
/* Secondary table lookup */
if (eaddr != 0xEFFFFFFF) {
@@ -694,8 +642,8 @@ static inline int get_segment(CPUPPCState *env, mmu_ctx_t
*ctx,
" 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);
+ ret2 = find_pte32(env, ctx, 1, rw, type,
+ target_page_bits);
if (ret2 != -1) {
ret = ret2;
}
@@ -1494,16 +1442,20 @@ static int get_physical_address(CPUPPCState *env,
mmu_ctx_t *ctx,
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;
+
#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
[Qemu-ppc] [PATCH 2/8] target-ppc: Move SLB handling into a mmu-hash64.c, David Gibson, 2013/02/11
[Qemu-ppc] [PATCH 4/8] target-ppc: Disentangle 64-bit version of find_pte(), David Gibson, 2013/02/11
Re: [Qemu-ppc] [Qemu-devel] [0/8] RFC: target-ppc: Start disentangling different MMU types, Andreas Färber, 2013/02/12