summaryrefslogtreecommitdiff
path: root/target-ppc/mmu-hash64.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc/mmu-hash64.c')
-rw-r--r--target-ppc/mmu-hash64.c123
1 files changed, 57 insertions, 66 deletions
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 66b2d2444b..36e2c84556 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;
}