Blame SOURCES/kvm-target-ppc-Implement-ISA-V3.00-radix-page-fault-hand.patch

76daa3
From 5eb7572177f7cd58bbd8556707fe6546ec46c1d2 Mon Sep 17 00:00:00 2001
76daa3
From: Laurent Vivier <lvivier@redhat.com>
76daa3
Date: Thu, 13 Jul 2017 16:36:27 +0200
76daa3
Subject: [PATCH 3/6] target/ppc: Implement ISA V3.00 radix page fault handler
76daa3
76daa3
RH-Author: Laurent Vivier <lvivier@redhat.com>
76daa3
Message-id: <20170713163630.24848-2-lvivier@redhat.com>
76daa3
Patchwork-id: 75768
76daa3
O-Subject: [RHEL-ALT-7.4 qemu-kvm PATCH 1/4] target/ppc: Implement ISA V3.00 radix page fault handler
76daa3
Bugzilla: 1470558
76daa3
RH-Acked-by: David Gibson <dgibson@redhat.com>
76daa3
RH-Acked-by: Thomas Huth <thuth@redhat.com>
76daa3
RH-Acked-by: Suraj Jitindar Singh <sursingh@redhat.com>
76daa3
76daa3
From: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
76daa3
76daa3
ISA V3.00 introduced a new radix mmu model. Implement the page fault
76daa3
handler for this so we can run a tcg guest in radix mode and perform
76daa3
address translation correctly.
76daa3
76daa3
In real mode (mmu turned off) addresses are masked to remove the top
76daa3
4 bits and then are subject to partition scoped translation, since we only
76daa3
support pseries at this stage it is only necessary to perform the masking
76daa3
and then we're done.
76daa3
76daa3
In virtual mode (mmu turned on) address translation if performed as
76daa3
follows:
76daa3
76daa3
1. Use the quadrant to determine the fully qualified address.
76daa3
76daa3
The fully qualified address is defined as the combination of the effective
76daa3
address, the effective logical partition id (LPID) and the effective
76daa3
process id (PID). Based on the quadrant (EA63:62) we set the pid and lpid
76daa3
like so:
76daa3
76daa3
quadrant 0: lpid = LPIDR, pid = PIDR
76daa3
quadrant 1: HV only (not allowed in pseries)
76daa3
quadrant 2: HV only (not allowed in pseries)
76daa3
quadrant 3: lpid = LPIDR, pid = 0
76daa3
76daa3
If we can't get the fully qualified address we raise a segment interrupt.
76daa3
76daa3
2. Find the guest radix tree
76daa3
76daa3
We ask the virtual hypervisor for the partition table which was registered
76daa3
with H_REGISTER_PROC_TBL which points us to the process table in guest
76daa3
memory. We then index this table by pid to get the process table entry
76daa3
which points us to the appropriate radix tree to translate the address.
76daa3
76daa3
If the process table isn't big enough to contain an entry for the current
76daa3
pid then we raise a storage interrupt.
76daa3
76daa3
3. Walk the radix tree
76daa3
76daa3
Next we walk the radix tree where each level is a table of page directory
76daa3
entries indexed by some number of bits from the effective address, where
76daa3
the number of bits is determined by the table size. We continue to walk
76daa3
the tree (while entries are valid and the table is of minimum size) until
76daa3
we reach a table of page table entries, indicated by having the leaf bit
76daa3
set. The appropriate pte is then checked for sufficient access permissions,
76daa3
the reference and change bits are updated and the real address is
76daa3
calculated from the real page number bits of the pte and the low bits of
76daa3
the effective address.
76daa3
76daa3
If we can't find an entry or can't access the entry bacause of permissions
76daa3
then we raise a storage interrupt.
76daa3
76daa3
Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
76daa3
[dwg: Add missing parentheses to macro]
76daa3
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
76daa3
76daa3
(cherry picked from commit d5fee0bbe68d5e61e2d2beb5ff6de0b9c1cfd182)
76daa3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
76daa3
76daa3
BZ:   https://bugzilla.redhat.com/show_bug.cgi?id=1470558
76daa3
BREW: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=13654102
76daa3
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
76daa3
---
76daa3
 target/ppc/Makefile.objs   |   1 +
76daa3
 target/ppc/cpu.h           |   2 +
76daa3
 target/ppc/mmu-book3s-v3.c |   6 +-
76daa3
 target/ppc/mmu-book3s-v3.h |   5 +
76daa3
 target/ppc/mmu-radix64.c   | 259 +++++++++++++++++++++++++++++++++++++++++++++
76daa3
 target/ppc/mmu-radix64.h   |  72 +++++++++++++
76daa3
 6 files changed, 341 insertions(+), 4 deletions(-)
76daa3
 create mode 100644 target/ppc/mmu-radix64.c
76daa3
 create mode 100644 target/ppc/mmu-radix64.h
76daa3
76daa3
diff --git a/target/ppc/Makefile.objs b/target/ppc/Makefile.objs
76daa3
index f963777..f92ba67 100644
76daa3
--- a/target/ppc/Makefile.objs
76daa3
+++ b/target/ppc/Makefile.objs
76daa3
@@ -4,6 +4,7 @@ obj-y += translate.o
76daa3
 ifeq ($(CONFIG_SOFTMMU),y)
76daa3
 obj-y += machine.o mmu_helper.o mmu-hash32.o monitor.o arch_dump.o
76daa3
 obj-$(TARGET_PPC64) += mmu-hash64.o mmu-book3s-v3.o compat.o
76daa3
+obj-$(TARGET_PPC64) += mmu-radix64.o
76daa3
 endif
76daa3
 obj-$(CONFIG_KVM) += kvm.o
76daa3
 obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
76daa3
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
76daa3
index cacdd0a..43bd257 100644
76daa3
--- a/target/ppc/cpu.h
76daa3
+++ b/target/ppc/cpu.h
76daa3
@@ -480,6 +480,8 @@ struct ppc_slb_t {
76daa3
 #define DSISR_ISSTORE            0x02000000
76daa3
 /* Not permitted by virtual page class key protection */
76daa3
 #define DSISR_AMR                0x00200000
76daa3
+/* Unsupported Radix Tree Configuration */
76daa3
+#define DSISR_R_BADCONFIG        0x00080000
76daa3
 
76daa3
 /* SRR1 error code fields */
76daa3
 
76daa3
diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c
76daa3
index 005c963..e7798b3 100644
76daa3
--- a/target/ppc/mmu-book3s-v3.c
76daa3
+++ b/target/ppc/mmu-book3s-v3.c
76daa3
@@ -22,15 +22,13 @@
76daa3
 #include "cpu.h"
76daa3
 #include "mmu-hash64.h"
76daa3
 #include "mmu-book3s-v3.h"
76daa3
-#include "qemu/error-report.h"
76daa3
+#include "mmu-radix64.h"
76daa3
 
76daa3
 int ppc64_v3_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
76daa3
                               int mmu_idx)
76daa3
 {
76daa3
     if (ppc64_radix_guest(cpu)) { /* Guest uses radix */
76daa3
-        /* TODO - Unsupported */
76daa3
-        error_report("Guest Radix Support Unimplemented");
76daa3
-        exit(1);
76daa3
+        return ppc_radix64_handle_mmu_fault(cpu, eaddr, rwx, mmu_idx);
76daa3
     } else { /* Guest uses hash */
76daa3
         return ppc_hash64_handle_mmu_fault(cpu, eaddr, rwx, mmu_idx);
76daa3
     }
76daa3
diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h
76daa3
index 636f6ab..56095da 100644
76daa3
--- a/target/ppc/mmu-book3s-v3.h
76daa3
+++ b/target/ppc/mmu-book3s-v3.h
76daa3
@@ -25,6 +25,11 @@
76daa3
 /* Partition Table Entry Fields */
76daa3
 #define PATBE1_GR 0x8000000000000000
76daa3
 
76daa3
+/* Process Table Entry */
76daa3
+struct prtb_entry {
76daa3
+    uint64_t prtbe0, prtbe1;
76daa3
+};
76daa3
+
76daa3
 #ifdef TARGET_PPC64
76daa3
 
76daa3
 static inline bool ppc64_use_proc_tbl(PowerPCCPU *cpu)
76daa3
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
76daa3
new file mode 100644
76daa3
index 0000000..de18c0b
76daa3
--- /dev/null
76daa3
+++ b/target/ppc/mmu-radix64.c
76daa3
@@ -0,0 +1,259 @@
76daa3
+/*
76daa3
+ *  PowerPC Radix MMU mulation helpers for QEMU.
76daa3
+ *
76daa3
+ *  Copyright (c) 2016 Suraj Jitindar Singh, IBM Corporation
76daa3
+ *
76daa3
+ * This library is free software; you can redistribute it and/or
76daa3
+ * modify it under the terms of the GNU Lesser General Public
76daa3
+ * License as published by the Free Software Foundation; either
76daa3
+ * version 2 of the License, or (at your option) any later version.
76daa3
+ *
76daa3
+ * This library is distributed in the hope that it will be useful,
76daa3
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
76daa3
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
76daa3
+ * Lesser General Public License for more details.
76daa3
+ *
76daa3
+ * You should have received a copy of the GNU Lesser General Public
76daa3
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
76daa3
+ */
76daa3
+
76daa3
+#include "qemu/osdep.h"
76daa3
+#include "qapi/error.h"
76daa3
+#include "cpu.h"
76daa3
+#include "exec/exec-all.h"
76daa3
+#include "exec/helper-proto.h"
76daa3
+#include "qemu/error-report.h"
76daa3
+#include "sysemu/kvm.h"
76daa3
+#include "kvm_ppc.h"
76daa3
+#include "exec/log.h"
76daa3
+#include "mmu-radix64.h"
76daa3
+#include "mmu-book3s-v3.h"
76daa3
+
76daa3
+static bool ppc_radix64_get_fully_qualified_addr(CPUPPCState *env, vaddr eaddr,
76daa3
+                                                 uint64_t *lpid, uint64_t *pid)
76daa3
+{
76daa3
+    /* We don't have HV support yet and shouldn't get here with it set anyway */
76daa3
+    assert(!msr_hv);
76daa3
+
76daa3
+    if (!msr_hv) { /* !MSR[HV] -> Guest */
76daa3
+        switch (eaddr & R_EADDR_QUADRANT) {
76daa3
+        case R_EADDR_QUADRANT0: /* Guest application */
76daa3
+            *lpid = env->spr[SPR_LPIDR];
76daa3
+            *pid = env->spr[SPR_BOOKS_PID];
76daa3
+            break;
76daa3
+        case R_EADDR_QUADRANT1: /* Illegal */
76daa3
+        case R_EADDR_QUADRANT2:
76daa3
+            return false;
76daa3
+        case R_EADDR_QUADRANT3: /* Guest OS */
76daa3
+            *lpid = env->spr[SPR_LPIDR];
76daa3
+            *pid = 0; /* pid set to 0 -> addresses guest operating system */
76daa3
+            break;
76daa3
+        }
76daa3
+    }
76daa3
+
76daa3
+    return true;
76daa3
+}
76daa3
+
76daa3
+static void ppc_radix64_raise_segi(PowerPCCPU *cpu, int rwx, vaddr eaddr)
76daa3
+{
76daa3
+    CPUState *cs = CPU(cpu);
76daa3
+    CPUPPCState *env = &cpu->env;
76daa3
+
76daa3
+    if (rwx == 2) { /* Instruction Segment Interrupt */
76daa3
+        cs->exception_index = POWERPC_EXCP_ISEG;
76daa3
+    } else { /* Data Segment Interrupt */
76daa3
+        cs->exception_index = POWERPC_EXCP_DSEG;
76daa3
+        env->spr[SPR_DAR] = eaddr;
76daa3
+    }
76daa3
+    env->error_code = 0;
76daa3
+}
76daa3
+
76daa3
+static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr,
76daa3
+                                uint32_t cause)
76daa3
+{
76daa3
+    CPUState *cs = CPU(cpu);
76daa3
+    CPUPPCState *env = &cpu->env;
76daa3
+
76daa3
+    if (rwx == 2) { /* Instruction Storage Interrupt */
76daa3
+        cs->exception_index = POWERPC_EXCP_ISI;
76daa3
+        env->error_code = cause;
76daa3
+    } else { /* Data Storage Interrupt */
76daa3
+        cs->exception_index = POWERPC_EXCP_DSI;
76daa3
+        if (rwx == 1) { /* Write -> Store */
76daa3
+            cause |= DSISR_ISSTORE;
76daa3
+        }
76daa3
+        env->spr[SPR_DSISR] = cause;
76daa3
+        env->spr[SPR_DAR] = eaddr;
76daa3
+        env->error_code = 0;
76daa3
+    }
76daa3
+}
76daa3
+
76daa3
+
76daa3
+static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
76daa3
+                                   int *fault_cause, int *prot)
76daa3
+{
76daa3
+    CPUPPCState *env = &cpu->env;
76daa3
+    const int need_prot[] = { PAGE_READ, PAGE_WRITE, PAGE_EXEC };
76daa3
+
76daa3
+    /* Check Page Attributes (pte58:59) */
76daa3
+    if (((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO) && (rwx == 2)) {
76daa3
+        /*
76daa3
+         * Radix PTE entries with the non-idempotent I/O attribute are treated
76daa3
+         * as guarded storage
76daa3
+         */
76daa3
+        *fault_cause |= SRR1_NOEXEC_GUARD;
76daa3
+        return true;
76daa3
+    }
76daa3
+
76daa3
+    /* Determine permissions allowed by Encoded Access Authority */
76daa3
+    if ((pte & R_PTE_EAA_PRIV) && msr_pr) { /* Insufficient Privilege */
76daa3
+        *prot = 0;
76daa3
+    } else if (msr_pr || (pte & R_PTE_EAA_PRIV)) {
76daa3
+        *prot = ppc_radix64_get_prot_eaa(pte);
76daa3
+    } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) */
76daa3
+        *prot = ppc_radix64_get_prot_eaa(pte);
76daa3
+        *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */
76daa3
+    }
76daa3
+
76daa3
+    /* Check if requested access type is allowed */
76daa3
+    if (need_prot[rwx] & ~(*prot)) { /* Page Protected for that Access */
76daa3
+        *fault_cause |= DSISR_PROTFAULT;
76daa3
+        return true;
76daa3
+    }
76daa3
+
76daa3
+    return false;
76daa3
+}
76daa3
+
76daa3
+static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte,
76daa3
+                               hwaddr pte_addr, int *prot)
76daa3
+{
76daa3
+    CPUState *cs = CPU(cpu);
76daa3
+    uint64_t npte;
76daa3
+
76daa3
+    npte = pte | R_PTE_R; /* Always set reference bit */
76daa3
+
76daa3
+    if (rwx == 1) { /* Store/Write */
76daa3
+        npte |= R_PTE_C; /* Set change bit */
76daa3
+    } else {
76daa3
+        /*
76daa3
+         * Treat the page as read-only for now, so that a later write
76daa3
+         * will pass through this function again to set the C bit.
76daa3
+         */
76daa3
+        *prot &= ~PAGE_WRITE;
76daa3
+    }
76daa3
+
76daa3
+    if (pte ^ npte) { /* If pte has changed then write it back */
76daa3
+        stq_phys(cs->as, pte_addr, npte);
76daa3
+    }
76daa3
+}
76daa3
+
76daa3
+static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, int rwx, vaddr eaddr,
76daa3
+                                      uint64_t base_addr, uint64_t nls,
76daa3
+                                      hwaddr *raddr, int *psize,
76daa3
+                                      int *fault_cause, int *prot,
76daa3
+                                      hwaddr *pte_addr)
76daa3
+{
76daa3
+    CPUState *cs = CPU(cpu);
76daa3
+    uint64_t index, pde;
76daa3
+
76daa3
+    if (nls < 5) { /* Directory maps less than 2**5 entries */
76daa3
+        *fault_cause |= DSISR_R_BADCONFIG;
76daa3
+        return 0;
76daa3
+    }
76daa3
+
76daa3
+    /* Read page <directory/table> entry from guest address space */
76daa3
+    index = eaddr >> (*psize - nls); /* Shift */
76daa3
+    index &= ((1UL << nls) - 1); /* Mask */
76daa3
+    pde = ldq_phys(cs->as, base_addr + (index * sizeof(pde)));
76daa3
+    if (!(pde & R_PTE_VALID)) { /* Invalid Entry */
76daa3
+        *fault_cause |= DSISR_NOPTE;
76daa3
+        return 0;
76daa3
+    }
76daa3
+
76daa3
+    *psize -= nls;
76daa3
+
76daa3
+    /* Check if Leaf Entry -> Page Table Entry -> Stop the Search */
76daa3
+    if (pde & R_PTE_LEAF) {
76daa3
+        uint64_t rpn = pde & R_PTE_RPN;
76daa3
+        uint64_t mask = (1UL << *psize) - 1;
76daa3
+
76daa3
+        if (ppc_radix64_check_prot(cpu, rwx, pde, fault_cause, prot)) {
76daa3
+            return 0; /* Protection Denied Access */
76daa3
+        }
76daa3
+
76daa3
+        /* Or high bits of rpn and low bits to ea to form whole real addr */
76daa3
+        *raddr = (rpn & ~mask) | (eaddr & mask);
76daa3
+        *pte_addr = base_addr + (index * sizeof(pde));
76daa3
+        return pde;
76daa3
+    }
76daa3
+
76daa3
+    /* Next Level of Radix Tree */
76daa3
+    return ppc_radix64_walk_tree(cpu, rwx, eaddr, pde & R_PDE_NLB,
76daa3
+                                 pde & R_PDE_NLS, raddr, psize,
76daa3
+                                 fault_cause, prot, pte_addr);
76daa3
+}
76daa3
+
76daa3
+int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
76daa3
+                                 int mmu_idx)
76daa3
+{
76daa3
+    CPUState *cs = CPU(cpu);
76daa3
+    CPUPPCState *env = &cpu->env;
76daa3
+    PPCVirtualHypervisorClass *vhc =
76daa3
+        PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
76daa3
+    hwaddr raddr, pte_addr;
76daa3
+    uint64_t lpid = 0, pid = 0, offset, size, patbe, prtbe0, pte;
76daa3
+    int page_size, prot, fault_cause = 0;
76daa3
+
76daa3
+    assert((rwx == 0) || (rwx == 1) || (rwx == 2));
76daa3
+    assert(!msr_hv); /* For now there is no Radix PowerNV Support */
76daa3
+    assert(cpu->vhyp);
76daa3
+    assert(ppc64_use_proc_tbl(cpu));
76daa3
+
76daa3
+    /* Real Mode Access */
76daa3
+    if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
76daa3
+        /* In real mode top 4 effective addr bits (mostly) ignored */
76daa3
+        raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
76daa3
+
76daa3
+        tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
76daa3
+                     PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
76daa3
+                     TARGET_PAGE_SIZE);
76daa3
+        return 0;
76daa3
+    }
76daa3
+
76daa3
+    /* Virtual Mode Access - get the fully qualified address */
76daa3
+    if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) {
76daa3
+        ppc_radix64_raise_segi(cpu, rwx, eaddr);
76daa3
+        return 1;
76daa3
+    }
76daa3
+
76daa3
+    /* Get Process Table */
76daa3
+    patbe = vhc->get_patbe(cpu->vhyp);
76daa3
+
76daa3
+    /* Index Process Table by PID to Find Corresponding Process Table Entry */
76daa3
+    offset = pid * sizeof(struct prtb_entry);
76daa3
+    size = 1ULL << ((patbe & PATBE1_R_PRTS) + 12);
76daa3
+    if (offset >= size) {
76daa3
+        /* offset exceeds size of the process table */
76daa3
+        ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
76daa3
+        return 1;
76daa3
+    }
76daa3
+    prtbe0 = ldq_phys(cs->as, (patbe & PATBE1_R_PRTB) + offset);
76daa3
+
76daa3
+    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
76daa3
+    page_size = PRTBE_R_GET_RTS(prtbe0);
76daa3
+    pte = ppc_radix64_walk_tree(cpu, rwx, eaddr & R_EADDR_MASK,
76daa3
+                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
76daa3
+                                &raddr, &page_size, &fault_cause, &prot,
76daa3
+                                &pte_addr);
76daa3
+    if (!pte) {
76daa3
+        ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
76daa3
+        return 1;
76daa3
+    }
76daa3
+
76daa3
+    /* Update Reference and Change Bits */
76daa3
+    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, &prot;;
76daa3
+
76daa3
+    tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
76daa3
+                 prot, mmu_idx, 1UL << page_size);
76daa3
+    return 1;
76daa3
+}
76daa3
diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h
76daa3
new file mode 100644
76daa3
index 0000000..1d5c7cf
76daa3
--- /dev/null
76daa3
+++ b/target/ppc/mmu-radix64.h
76daa3
@@ -0,0 +1,72 @@
76daa3
+#ifndef MMU_RADIX64_H
76daa3
+#define MMU_RADIX64_H
76daa3
+
76daa3
+#ifndef CONFIG_USER_ONLY
76daa3
+
76daa3
+/* Radix Quadrants */
76daa3
+#define R_EADDR_MASK            0x3FFFFFFFFFFFFFFF
76daa3
+#define R_EADDR_QUADRANT        0xC000000000000000
76daa3
+#define R_EADDR_QUADRANT0       0x0000000000000000
76daa3
+#define R_EADDR_QUADRANT1       0x4000000000000000
76daa3
+#define R_EADDR_QUADRANT2       0x8000000000000000
76daa3
+#define R_EADDR_QUADRANT3       0xC000000000000000
76daa3
+
76daa3
+/* Radix Partition Table Entry Fields */
76daa3
+#define PATBE1_R_PRTB           0x0FFFFFFFFFFFF000
76daa3
+#define PATBE1_R_PRTS           0x000000000000001F
76daa3
+
76daa3
+/* Radix Process Table Entry Fields */
76daa3
+#define PRTBE_R_GET_RTS(rts) \
76daa3
+    ((((rts >> 58) & 0x18) | ((rts >> 5) & 0x7)) + 31)
76daa3
+#define PRTBE_R_RPDB            0x0FFFFFFFFFFFFF00
76daa3
+#define PRTBE_R_RPDS            0x000000000000001F
76daa3
+
76daa3
+/* Radix Page Directory/Table Entry Fields */
76daa3
+#define R_PTE_VALID             0x8000000000000000
76daa3
+#define R_PTE_LEAF              0x4000000000000000
76daa3
+#define R_PTE_SW0               0x2000000000000000
76daa3
+#define R_PTE_RPN               0x01FFFFFFFFFFF000
76daa3
+#define R_PTE_SW1               0x0000000000000E00
76daa3
+#define R_GET_SW(sw)            (((sw >> 58) & 0x8) | ((sw >> 9) & 0x7))
76daa3
+#define R_PTE_R                 0x0000000000000100
76daa3
+#define R_PTE_C                 0x0000000000000080
76daa3
+#define R_PTE_ATT               0x0000000000000030
76daa3
+#define R_PTE_ATT_NORMAL        0x0000000000000000
76daa3
+#define R_PTE_ATT_SAO           0x0000000000000010
76daa3
+#define R_PTE_ATT_NI_IO         0x0000000000000020
76daa3
+#define R_PTE_ATT_TOLERANT_IO   0x0000000000000030
76daa3
+#define R_PTE_EAA_PRIV          0x0000000000000008
76daa3
+#define R_PTE_EAA_R             0x0000000000000004
76daa3
+#define R_PTE_EAA_RW            0x0000000000000002
76daa3
+#define R_PTE_EAA_X             0x0000000000000001
76daa3
+#define R_PDE_NLB               PRTBE_R_RPDB
76daa3
+#define R_PDE_NLS               PRTBE_R_RPDS
76daa3
+
76daa3
+#ifdef TARGET_PPC64
76daa3
+
76daa3
+int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
76daa3
+                                 int mmu_idx);
76daa3
+
76daa3
+static inline int ppc_radix64_get_prot_eaa(uint64_t pte)
76daa3
+{
76daa3
+    return (pte & R_PTE_EAA_R ? PAGE_READ : 0) |
76daa3
+           (pte & R_PTE_EAA_RW ? PAGE_READ | PAGE_WRITE : 0) |
76daa3
+           (pte & R_PTE_EAA_X ? PAGE_EXEC : 0);
76daa3
+}
76daa3
+
76daa3
+static inline int ppc_radix64_get_prot_amr(PowerPCCPU *cpu)
76daa3
+{
76daa3
+    CPUPPCState *env = &cpu->env;
76daa3
+    int amr = env->spr[SPR_AMR] >> 62; /* We only care about key0 AMR63:62 */
76daa3
+    int iamr = env->spr[SPR_IAMR] >> 62; /* We only care about key0 IAMR63:62 */
76daa3
+
76daa3
+    return (amr & 0x2 ? 0 : PAGE_WRITE) | /* Access denied if bit is set */
76daa3
+           (amr & 0x1 ? 0 : PAGE_READ) |
76daa3
+           (iamr & 0x1 ? 0 : PAGE_EXEC);
76daa3
+}
76daa3
+
76daa3
+#endif /* TARGET_PPC64 */
76daa3
+
76daa3
+#endif /* CONFIG_USER_ONLY */
76daa3
+
76daa3
+#endif /* MMU_RADIX64_H */
76daa3
-- 
76daa3
1.8.3.1
76daa3