?? helper.c
字號:
target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr){ target_phys_addr_t sr_base; target_ulong rt; uint64_t tmp64; uint32_t tmp; sr_base = env->spr[SPR_ASR]; sr_base += 12 * slb_nr; tmp64 = ldq_phys(sr_base); tmp = ldl_phys(sr_base + 8); if (tmp64 & 0x0000000008000000ULL) { /* SLB entry is valid */ /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */ rt = tmp >> 8; /* 65:88 => 40:63 */ rt |= (tmp64 & 0x7) << 24; /* 62:64 => 37:39 */ /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */ rt |= ((tmp >> 4) & 0xF) << 27; } else { rt = 0; }#if defined(DEBUG_SLB) if (loglevel != 0) { fprintf(logfile, "%s: " PADDRX " %016" PRIx64 " %08" PRIx32 " => %d " ADDRX "\n", __func__, sr_base, tmp64, tmp, slb_nr, rt); }#endif return rt;}void ppc_store_slb (CPUPPCState *env, int slb_nr, target_ulong rs){ target_phys_addr_t sr_base; uint64_t tmp64; uint32_t tmp; sr_base = env->spr[SPR_ASR]; sr_base += 12 * slb_nr; /* Copy Rs bits 37:63 to SLB 62:88 */ tmp = rs << 8; tmp64 = (rs >> 24) & 0x7; /* Copy Rs bits 33:36 to SLB 89:92 */ tmp |= ((rs >> 27) & 0xF) << 4; /* Set the valid bit */ tmp64 |= 1 << 27; /* Set ESID */ tmp64 |= (uint32_t)slb_nr << 28;#if defined(DEBUG_SLB) if (loglevel != 0) { fprintf(logfile, "%s: %d " ADDRX " => " PADDRX " %016" PRIx64 " %08" PRIx32 "\n", __func__, slb_nr, rs, sr_base, tmp64, tmp); }#endif /* Write SLB entry to memory */ stq_phys(sr_base, tmp64); stl_phys(sr_base + 8, tmp);}#endif /* defined(TARGET_PPC64) *//* Perform segment based translation */static always_inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1, int sdr_sh, target_phys_addr_t hash, target_phys_addr_t mask){ return (sdr1 & ((target_phys_addr_t)(-1ULL) << sdr_sh)) | (hash & mask);}static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, int rw, int type){ target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask; target_ulong sr, vsid, vsid_mask, pgidx, page_mask;#if defined(TARGET_PPC64) int attr;#endif int ds, vsid_sh, sdr_sh, pr; int ret, ret2; pr = msr_pr;#if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) {#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "Check SLBs\n"); }#endif ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr); if (ret < 0) return ret; ctx->key = ((attr & 0x40) && (pr != 0)) || ((attr & 0x80) && (pr == 0)) ? 1 : 0; ds = 0; ctx->nx = attr & 0x20 ? 1 : 0; vsid_mask = 0x00003FFFFFFFFF80ULL; vsid_sh = 7; sdr_sh = 18; sdr_mask = 0x3FF80; } else#endif /* defined(TARGET_PPC64) */ { sr = env->sr[eaddr >> 28]; page_mask = 0x0FFFFFFF; 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; vsid_mask = 0x01FFFFC0; vsid_sh = 6; sdr_sh = 16; sdr_mask = 0xFFC0;#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "Check segment v=" ADDRX " %d " ADDRX " nip=" ADDRX " lr=" ADDRX " 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); }#endif }#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "pte segment: key=%d ds %d nx %d vsid " ADDRX "\n", ctx->key, ds, ctx->nx, vsid); }#endif ret = -1; if (!ds) { /* Check if instruction fetch is allowed, if needed */ if (type != ACCESS_CODE || ctx->nx == 0) { /* Page address translation */ /* Primary table address */ sdr = env->sdr1; pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS;#if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F)); /* XXX: this is false for 1 TB segments */ hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; } else#endif { htab_mask = sdr & 0x000001FF; hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask; } mask = (htab_mask << sdr_sh) | sdr_mask;#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX " mask " PADDRX " " ADDRX "\n", sdr, sdr_sh, hash, mask, page_mask); }#endif ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask); /* Secondary table address */ hash = (~hash) & vsid_mask;#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "sdr " PADDRX " sh %d hash " PADDRX " mask " PADDRX "\n", sdr, sdr_sh, hash, mask); }#endif ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask);#if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) { /* Only 5 bits of the page index are used in the AVPN */ ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80); } else#endif { ctx->ptem = (vsid << 7) | (pgidx >> 10); } /* Initialize real address with an invalid value */ ctx->raddr = (target_phys_addr_t)-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 {#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "0 sdr1=" PADDRX " vsid=" ADDRX " " "api=" ADDRX " hash=" PADDRX " pg_addr=" PADDRX "\n", sdr, vsid, pgidx, hash, ctx->pg_addr[0]); }#endif /* Primary table lookup */ ret = find_pte(env, ctx, 0, rw, type); if (ret < 0) { /* Secondary table lookup */#if defined (DEBUG_MMU) if (eaddr != 0xEFFFFFFF && loglevel != 0) { fprintf(logfile, "1 sdr1=" PADDRX " vsid=" ADDRX " " "api=" ADDRX " hash=" PADDRX " pg_addr=" PADDRX "\n", sdr, vsid, pgidx, hash, ctx->pg_addr[1]); }#endif ret2 = find_pte(env, ctx, 1, rw, type); if (ret2 != -1) ret = ret2; } }#if defined (DUMP_PAGE_TABLES) if (loglevel != 0) { target_phys_addr_t curaddr; uint32_t a0, a1, a2, a3; fprintf(logfile, "Page table: " PADDRX " len " PADDRX "\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) { fprintf(logfile, PADDRX ": %08x %08x %08x %08x\n", curaddr, a0, a1, a2, a3); } } }#endif } else {#if defined (DEBUG_MMU) if (loglevel != 0) fprintf(logfile, "No access allowed\n");#endif ret = -3; } } else {#if defined (DEBUG_MMU) if (loglevel != 0) fprintf(logfile, "direct store...\n");#endif /* Direct-store segment : absolutely *BUGGY* for now */ 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: if (logfile) { fprintf(logfile, "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;}/* Generic TLB check function for embedded PowerPC implementations */static always_inline int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb, target_phys_addr_t *raddrp, target_ulong address, uint32_t pid, int ext, int i){ target_ulong mask; /* Check valid flag */ if (!(tlb->prot & PAGE_VALID)) { if (loglevel != 0) fprintf(logfile, "%s: TLB %d not valid\n", __func__, i); return -1; } mask = ~(tlb->size - 1);#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: TLB %d address " ADDRX " PID %u <=> " ADDRX " " ADDRX " %u\n", __func__, i, address, pid, tlb->EPN, mask, (uint32_t)tlb->PID); }#endif /* Check PID */ if (tlb->PID != 0 && tlb->PID != pid) return -1; /* Check effective address */ if ((address & mask) != tlb->EPN) return -1; *raddrp = (tlb->RPN & mask) | (address & ~mask);#if (TARGET_PHYS_ADDR_BITS >= 36) if (ext) { /* Extend the physical address to 36 bits */ *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32; }#endif return 0;}/* Generic TLB search function for PowerPC embedded implementations */int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid){ ppcemb_tlb_t *tlb; target_phys_addr_t raddr; int i, ret; /* Default return value is no match */ ret = -1; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) { ret = i; break; } } return ret;}/* Helpers specific to PowerPC 40x implementations */static always_inline void ppc4xx_tlb_invalidate_all (CPUState *env){ ppcemb_tlb_t *tlb; int i; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; tlb->prot &= ~PAGE_VALID; } tlb_flush(env, 1);}static always_inline void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr, uint32_t pid){#if !defined(FLUSH_ALL_TLBS) ppcemb_tlb_t *tlb; target_phys_addr_t raddr; target_ulong page, end; int i; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) { end = tlb->EPN + tlb->size; for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) tlb_flush_page(env, page); tlb->prot &= ~PAGE_VALID; break; } }#else ppc4xx_tlb_invalidate_all(env);#endif}int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong address, int rw, int access_type){ ppcemb_tlb_t *tlb; target_phys_addr_t raddr; int i, ret, zsel, zpr, pr; ret = -1; raddr = (target_phys_addr_t)-1ULL; pr = msr_pr; for (i = 0; i < env->nb_tlb; i++) { tlb = &env->tlb[i].tlbe; if (ppcemb_tlb_check(env, tlb, &raddr, address, env->spr[SPR_40x_PID], 0, i) < 0) continue; zsel = (tlb->attr >> 4) & 0xF; zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n", __func__, i, zsel, zpr, rw, tlb->attr); }#endif /* Check execute enable bit */ switch (zpr) { case 0x2: if (pr != 0) goto check_perms; /* No break here */ case 0x3: /* All accesses granted */ ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ret = 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -