aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/mmu-hash64.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-hash64.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-hash64.c')
-rw-r--r--target-ppc/mmu-hash64.c92
1 files changed, 89 insertions, 3 deletions
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index a525bd552f..23eb4801cc 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -44,7 +44,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;
@@ -276,8 +276,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;
@@ -349,3 +349,89 @@ 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 nx %d vsid " TARGET_FMT_lx "\n",
+ ctx->key, 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 */
+ 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;
+ }
+ }
+ } else {
+ LOG_MMU("No access allowed\n");
+ ret = -3;
+ }
+
+ return ret;
+}