aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/mmu_helper.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2013-03-12 00:31:09 +0000
committerAlexander Graf <agraf@suse.de>2013-03-22 15:28:47 +0100
commit0480884f1404295ba0d242791e036b05c4957bab (patch)
treeab601cf1a02c895765e552bf370a9b5a8ce15f2c /target-ppc/mmu_helper.c
parentc69b6151e7f242b02f261f321c392e5ef933176f (diff)
target-ppc: Disentangle get_segment()
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> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc/mmu_helper.c')
-rw-r--r--target-ppc/mmu_helper.c141
1 files changed, 40 insertions, 101 deletions
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 130139180..db5c15a92 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,