?? helper.c
字號:
/* TLB inconsistency */ return -1; case -2: /* Access violation */ ret = -2; best = nr; break; case -1: default: /* No match */ break; case 0: /* access granted */ /* XXX: we should go on looping to check all TLBs consistency * but we can speed-up the whole thing as the * result would be undefined if TLBs are not consistent. */ ret = 0; best = nr; goto done; } } if (best != -1) { done:#if defined (DEBUG_SOFTWARE_TLB) if (loglevel != 0) { fprintf(logfile, "found TLB at addr " PADDRX " prot=%01x ret=%d\n", ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); }#endif /* Update page flags */ pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw); } return ret;}/* Perform BAT hit & translation */static always_inline void bat_size_prot (CPUState *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 always_inline void bat_601_size_prot (CPUState *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;#if defined (DEBUG_BATS) if (loglevel != 0) { fprintf(logfile, "b %02x ==> bl " ADDRX " msk " ADDRX "\n", (uint8_t)(*BATl & 0x0000003F), bl, ~bl); }#endif 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;}static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx, target_ulong virtual, int rw, int type){ target_ulong *BATlt, *BATut, *BATu, *BATl; target_ulong base, BEPIl, BEPIu, bl; int i, valid, prot; int ret = -1;#if defined (DEBUG_BATS) if (loglevel != 0) { fprintf(logfile, "%s: %cBAT v " ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', virtual); }#endif switch (type) { case ACCESS_CODE: BATlt = env->IBAT[1]; BATut = env->IBAT[0]; break; default: BATlt = env->DBAT[1]; BATut = env->DBAT[0]; break; } base = virtual & 0xFFFC0000; 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)) { bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl); } else { bat_size_prot(env, &bl, &valid, &prot, BATu, BATl); }#if defined (DEBUG_BATS) if (loglevel != 0) { fprintf(logfile, "%s: %cBAT%d v " ADDRX " BATu " ADDRX " BATl " ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl); }#endif 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 = check_prot(ctx->prot, rw, type);#if defined (DEBUG_BATS) if (ret == 0 && loglevel != 0) { fprintf(logfile, "BAT %d match: r " PADDRX " prot=%c%c\n", i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-', ctx->prot & PAGE_WRITE ? 'W' : '-'); }#endif break; } } } if (ret < 0) {#if defined (DEBUG_BATS) if (loglevel != 0) { fprintf(logfile, "no BAT match for " ADDRX ":\n", virtual); for (i = 0; i < 4; i++) { BATu = &BATut[i]; BATl = &BATlt[i]; BEPIu = *BATu & 0xF0000000; BEPIl = *BATu & 0x0FFE0000; bl = (*BATu & 0x00001FFC) << 15; fprintf(logfile, "%s: %cBAT%d v " ADDRX " BATu " ADDRX " BATl " ADDRX " \n\t" ADDRX " " ADDRX " " ADDRX "\n", __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl); } }#endif } /* No hit */ return ret;}/* PTE table lookup */static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw, int type){ target_ulong base, pte0, pte1; int i, good = -1; int ret, r; ret = -1; /* No entry found */ base = ctx->pg_addr[h]; for (i = 0; i < 8; i++) {#if defined(TARGET_PPC64) if (is_64b) { pte0 = ldq_phys(base + (i * 16)); pte1 = ldq_phys(base + (i * 16) + 8); r = pte64_check(ctx, pte0, pte1, h, rw, type);#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "Load pte from " ADDRX " => " ADDRX " " ADDRX " %d %d %d " ADDRX "\n", base + (i * 16), pte0, pte1, (int)(pte0 & 1), h, (int)((pte0 >> 1) & 1), ctx->ptem); }#endif } else#endif { pte0 = ldl_phys(base + (i * 8)); pte1 = ldl_phys(base + (i * 8) + 4); r = pte32_check(ctx, pte0, pte1, h, rw, type);#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "Load pte from " ADDRX " => " ADDRX " " ADDRX " %d %d %d " ADDRX "\n", base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem); }#endif } 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:#if defined (DEBUG_MMU) if (loglevel != 0) { fprintf(logfile, "found PTE at addr " PADDRX " prot=%01x ret=%d\n", ctx->raddr, ctx->prot, ret); }#endif /* Update page flags */ pte1 = ctx->raddr; if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {#if defined(TARGET_PPC64) if (is_64b) { stq_phys_notdirty(base + (good * 16) + 8, pte1); } else#endif { stl_phys_notdirty(base + (good * 8) + 4, pte1); } } } return ret;}static always_inline int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type){ return _find_pte(ctx, 0, h, rw, type);}#if defined(TARGET_PPC64)static always_inline int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type){ return _find_pte(ctx, 1, h, rw, type);}#endifstatic always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw, int type){#if defined(TARGET_PPC64) if (env->mmu_model & POWERPC_MMU_64) return find_pte64(ctx, h, rw, type);#endif return find_pte32(ctx, h, rw, type);}#if defined(TARGET_PPC64)static always_inline int slb_is_valid (uint64_t slb64){ return slb64 & 0x0000000008000000ULL ? 1 : 0;}static always_inline void slb_invalidate (uint64_t *slb64){ *slb64 &= ~0x0000000008000000ULL;}static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr, target_ulong *vsid, target_ulong *page_mask, int *attr){ target_phys_addr_t sr_base; target_ulong mask; uint64_t tmp64; uint32_t tmp; int n, ret; ret = -5; sr_base = env->spr[SPR_ASR];#if defined(DEBUG_SLB) if (loglevel != 0) { fprintf(logfile, "%s: eaddr " ADDRX " base " PADDRX "\n", __func__, eaddr, sr_base); }#endif mask = 0x0000000000000000ULL; /* Avoid gcc warning */ for (n = 0; n < env->slb_nr; n++) { tmp64 = ldq_phys(sr_base); tmp = ldl_phys(sr_base + 8);#if defined(DEBUG_SLB) if (loglevel != 0) { fprintf(logfile, "%s: seg %d " PADDRX " %016" PRIx64 " %08" PRIx32 "\n", __func__, n, sr_base, tmp64, tmp); }#endif if (slb_is_valid(tmp64)) { /* SLB entry is valid */ switch (tmp64 & 0x0000000006000000ULL) { case 0x0000000000000000ULL: /* 256 MB segment */ mask = 0xFFFFFFFFF0000000ULL; break; case 0x0000000002000000ULL: /* 1 TB segment */ mask = 0xFFFF000000000000ULL; break; case 0x0000000004000000ULL: case 0x0000000006000000ULL: /* Reserved => segment is invalid */ continue; } if ((eaddr & mask) == (tmp64 & mask)) { /* SLB match */ *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL; *page_mask = ~mask; *attr = tmp & 0xFF; ret = n; break; } } sr_base += 12; } return ret;}void ppc_slb_invalidate_all (CPUPPCState *env){ target_phys_addr_t sr_base; uint64_t tmp64; int n, do_invalidate; do_invalidate = 0; sr_base = env->spr[SPR_ASR]; /* XXX: Warning: slbia never invalidates the first segment */ for (n = 1; n < env->slb_nr; n++) { tmp64 = ldq_phys(sr_base); if (slb_is_valid(tmp64)) { slb_invalidate(&tmp64); stq_phys(sr_base, tmp64); /* 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; } sr_base += 12; } if (do_invalidate) tlb_flush(env, 1);}void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0){ target_phys_addr_t sr_base; target_ulong vsid, page_mask; uint64_t tmp64; int attr; int n; n = slb_lookup(env, T0, &vsid, &page_mask, &attr); if (n >= 0) { sr_base = env->spr[SPR_ASR]; sr_base += 12 * n; tmp64 = ldq_phys(sr_base); if (slb_is_valid(tmp64)) { slb_invalidate(&tmp64); stq_phys(sr_base, tmp64); /* 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); } }}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -