All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/4] target/ppc: Add support for Radix partition-scoped translation
@ 2020-04-03 14:00 Cédric Le Goater
  2020-04-03 14:00 ` [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation Cédric Le Goater
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Cédric Le Goater @ 2020-04-03 14:00 UTC (permalink / raw)
  To: David Gibson; +Cc: Cédric Le Goater, qemu-ppc, Greg Kurz, qemu-devel

Hello,

The Radix tree translation model currently supports process-scoped
translation for the PowerNV machine (Hypervisor mode) and for the
pSeries machine (Guest mode). Guests running under an emulated
Hypervisor (PowerNV machine) require a new type of Radix translation,
called partition-scoped, which is missing today.

The Radix tree translation is a 2 steps process. The first step,
process-scoped translation, converts an effective Address to a guest
real address, and the second step, partition-scoped translation,
converts a guest real address to a host real address.

There are difference cases to covers : 

* Hypervisor real mode access: no Radix translation.

* Hypervisor or host application access (quadrant 0 and 3) with
  relocation on: process-scoped translation.

* Guest OS real mode access: only partition-scoped translation.

* Guest OS real or guest application access (quadrant 0 and 3) with
  relocation on: both process-scoped translation and partition-scoped
  translations.

* Hypervisor access in quadrant 1 and 2 with relocation on: both
  process-scoped translation and partition-scoped translations.

The radix tree partition-scoped translation is performed using tables
pointed to by the first double-word of the Partition Table Entries and
process-scoped translation uses tables pointed to by the Process Table
Entries (second double-word of the Partition Table Entries).

Both partition-scoped and process-scoped translations process are
identical and thus the radix tree traversing code is largely reused.
However, errors in partition-scoped translations generate hypervisor
exceptions.

Based on work from Suraj Jitindar Singh <sjitindarsingh@gmail.com>

Thanks,

C.

Changes since v3:

 - changed ppc_radix64_walk_tree() and ppc_radix64_next_level() to
   return an error code instead of a PTE. It clarifies error handling
   in the callers (Greg's contribution)
 
Changes since v2:

 - removed the changes on the routines raising the exceptions to take
   a 'cause_excp' bool.

Changes since v1:

 - removed checks (cpu->vhyp && lpid == 0)
 - changed ppc_radix64_walk_tree() and ppc_radix64_next_level() to use
   an 'AddressSpace *'
 - moved call to ppc_radix64_get_fully_qualified_addr() under
   ppc_radix64_xlate()
 - reworked the prototype of the routines raising the exceptions to
   take a 'cause_excp' bool.
 - re-introduced an extra test on nls in ppc_radix64_walk_tree()
 
Cédric Le Goater (4):
  target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation
  target/ppc: Extend ppc_radix64_check_prot() with a 'partition_scoped'
    bool
  target/ppc: Rework ppc_radix64_walk_tree() for partition-scoped
    translation
  target/ppc: Add support for Radix partition-scoped translation

 target/ppc/cpu.h         |   3 +
 target/ppc/excp_helper.c |   3 +-
 target/ppc/mmu-radix64.c | 453 ++++++++++++++++++++++++++++-----------
 3 files changed, 334 insertions(+), 125 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation
  2020-04-03 14:00 [PATCH v4 0/4] target/ppc: Add support for Radix partition-scoped translation Cédric Le Goater
@ 2020-04-03 14:00 ` Cédric Le Goater
  2020-04-03 14:56   ` Greg Kurz
  2020-04-08  2:57   ` David Gibson
  2020-04-03 14:00 ` [PATCH v4 2/4] target/ppc: Extend ppc_radix64_check_prot() with a 'partition_scoped' bool Cédric Le Goater
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 10+ messages in thread
From: Cédric Le Goater @ 2020-04-03 14:00 UTC (permalink / raw)
  To: David Gibson
  Cc: Cédric Le Goater, qemu-ppc, Greg Kurz, Suraj Jitindar Singh,
	qemu-devel

This is moving code under a new ppc_radix64_xlate() routine shared by
the MMU Radix page fault handler and the 'get_phys_page_debug' PPC
callback. The difference being that 'get_phys_page_debug' does not
generate exceptions.

The specific part of process-scoped Radix translation is moved under
ppc_radix64_process_scoped_xlate() in preparation of the future support
for partition-scoped Radix translation. Routines raising the exceptions
now take a 'cause_excp' bool to cover the 'get_phys_page_debug' case.

It should be functionally equivalent.

Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 target/ppc/mmu-radix64.c | 219 ++++++++++++++++++++++-----------------
 1 file changed, 123 insertions(+), 96 deletions(-)

diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index d2422d1c54c9..4b0d0ff50a3c 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -219,17 +219,127 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
     return true;
 }
 
+static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
+                                            vaddr eaddr, uint64_t pid,
+                                            ppc_v3_pate_t pate, hwaddr *g_raddr,
+                                            int *g_prot, int *g_page_size,
+                                            bool cause_excp)
+{
+    CPUState *cs = CPU(cpu);
+    uint64_t offset, size, prtbe_addr, prtbe0, pte;
+    int fault_cause = 0;
+    hwaddr pte_addr;
+
+    /* Index Process Table by PID to Find Corresponding Process Table Entry */
+    offset = pid * sizeof(struct prtb_entry);
+    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
+    if (offset >= size) {
+        /* offset exceeds size of the process table */
+        if (cause_excp) {
+            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
+        }
+        return 1;
+    }
+    prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
+    prtbe0 = ldq_phys(cs->as, prtbe_addr);
+
+    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
+    *g_page_size = PRTBE_R_GET_RTS(prtbe0);
+    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
+                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
+                                g_raddr, g_page_size, &fault_cause, &pte_addr);
+
+    if (!(pte & R_PTE_VALID) ||
+        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot)) {
+        /* No valid pte or access denied due to protection */
+        if (cause_excp) {
+            ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
+        }
+        return 1;
+    }
+
+    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
+
+    return 0;
+}
+
+static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
+                             bool relocation,
+                             hwaddr *raddr, int *psizep, int *protp,
+                             bool cause_excp)
+{
+    uint64_t lpid = 0, pid = 0;
+    ppc_v3_pate_t pate;
+    int psize, prot;
+    hwaddr g_raddr;
+
+    /* Virtual Mode Access - get the fully qualified address */
+    if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
+        if (cause_excp) {
+            ppc_radix64_raise_segi(cpu, rwx, eaddr);
+        }
+        return 1;
+    }
+
+    /* Get Process Table */
+    if (cpu->vhyp) {
+        PPCVirtualHypervisorClass *vhc;
+        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+        vhc->get_pate(cpu->vhyp, &pate);
+    } else {
+        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
+            if (cause_excp) {
+                ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
+            }
+            return 1;
+        }
+        if (!validate_pate(cpu, lpid, &pate)) {
+            if (cause_excp) {
+                ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
+            }
+            return 1;
+        }
+        /* We don't support guest mode yet */
+        if (lpid != 0) {
+            error_report("PowerNV guest support Unimplemented");
+            exit(1);
+        }
+    }
+
+    *psizep = INT_MAX;
+    *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+
+    /*
+     * Perform process-scoped translation if relocation enabled.
+     *
+     * - Translates an effective address to a host real address in
+     *   quadrants 0 and 3 when HV=1.
+     */
+    if (relocation) {
+        int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
+                                                   pate, &g_raddr, &prot,
+                                                   &psize, cause_excp);
+        if (ret) {
+            return ret;
+        }
+        *psizep = MIN(*psizep, psize);
+        *protp &= prot;
+    } else {
+        g_raddr = eaddr & R_EADDR_MASK;
+    }
+
+    *raddr = g_raddr;
+    return 0;
+}
+
 int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
                                  int mmu_idx)
 {
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
-    PPCVirtualHypervisorClass *vhc;
-    hwaddr raddr, pte_addr;
-    uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte;
-    int page_size, prot, fault_cause = 0;
-    ppc_v3_pate_t pate;
+    int page_size, prot;
     bool relocation;
+    hwaddr raddr;
 
     assert(!(msr_hv && cpu->vhyp));
     assert((rwx == 0) || (rwx == 1) || (rwx == 2));
@@ -262,55 +372,12 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
                       TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
     }
 
-    /* Virtual Mode Access - get the fully qualified address */
-    if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) {
-        ppc_radix64_raise_segi(cpu, rwx, eaddr);
+    /* Translate eaddr to raddr (where raddr is addr qemu needs for access) */
+    if (ppc_radix64_xlate(cpu, eaddr, rwx, relocation, &raddr,
+                          &page_size, &prot, true)) {
         return 1;
     }
 
-    /* Get Process Table */
-    if (cpu->vhyp) {
-        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
-        vhc->get_pate(cpu->vhyp, &pate);
-    } else {
-        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
-            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
-            return 1;
-        }
-        if (!validate_pate(cpu, lpid, &pate)) {
-            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
-        }
-        /* We don't support guest mode yet */
-        if (lpid != 0) {
-            error_report("PowerNV guest support Unimplemented");
-            exit(1);
-       }
-    }
-
-    /* Index Process Table by PID to Find Corresponding Process Table Entry */
-    offset = pid * sizeof(struct prtb_entry);
-    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
-    if (offset >= size) {
-        /* offset exceeds size of the process table */
-        ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
-        return 1;
-    }
-    prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset);
-
-    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
-    page_size = PRTBE_R_GET_RTS(prtbe0);
-    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
-                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
-                                &raddr, &page_size, &fault_cause, &pte_addr);
-    if (!pte || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, &prot)) {
-        /* Couldn't get pte or access denied due to protection */
-        ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
-        return 1;
-    }
-
-    /* Update Reference and Change Bits */
-    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, &prot);
-
     tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
                  prot, mmu_idx, 1UL << page_size);
     return 0;
@@ -318,58 +385,18 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
 
 hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr)
 {
-    CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
-    PPCVirtualHypervisorClass *vhc;
-    hwaddr raddr, pte_addr;
-    uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte;
-    int page_size, fault_cause = 0;
-    ppc_v3_pate_t pate;
+    int psize, prot;
+    hwaddr raddr;
 
     /* Handle Real Mode */
-    if (msr_dr == 0) {
+    if ((msr_dr == 0) && (msr_hv || cpu->vhyp)) {
         /* In real mode top 4 effective addr bits (mostly) ignored */
         return eaddr & 0x0FFFFFFFFFFFFFFFULL;
     }
 
-    /* Virtual Mode Access - get the fully qualified address */
-    if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) {
-        return -1;
-    }
-
-    /* Get Process Table */
-    if (cpu->vhyp) {
-        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
-        vhc->get_pate(cpu->vhyp, &pate);
-    } else {
-        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
-            return -1;
-        }
-        if (!validate_pate(cpu, lpid, &pate)) {
-            return -1;
-        }
-        /* We don't support guest mode yet */
-        if (lpid != 0) {
-            error_report("PowerNV guest support Unimplemented");
-            exit(1);
-       }
-    }
-
-    /* Index Process Table by PID to Find Corresponding Process Table Entry */
-    offset = pid * sizeof(struct prtb_entry);
-    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
-    if (offset >= size) {
-        /* offset exceeds size of the process table */
-        return -1;
-    }
-    prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset);
-
-    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
-    page_size = PRTBE_R_GET_RTS(prtbe0);
-    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
-                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
-                                &raddr, &page_size, &fault_cause, &pte_addr);
-    if (!pte) {
+    if (ppc_radix64_xlate(cpu, eaddr, 0, msr_dr, &raddr, &psize,
+                          &prot, false)) {
         return -1;
     }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 2/4] target/ppc: Extend ppc_radix64_check_prot() with a 'partition_scoped' bool
  2020-04-03 14:00 [PATCH v4 0/4] target/ppc: Add support for Radix partition-scoped translation Cédric Le Goater
  2020-04-03 14:00 ` [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation Cédric Le Goater
@ 2020-04-03 14:00 ` Cédric Le Goater
  2020-04-03 14:00 ` [PATCH v4 3/4] target/ppc: Rework ppc_radix64_walk_tree() for partition-scoped translation Cédric Le Goater
  2020-04-03 14:00 ` [PATCH v4 4/4] target/ppc: Add support for Radix " Cédric Le Goater
  3 siblings, 0 replies; 10+ messages in thread
From: Cédric Le Goater @ 2020-04-03 14:00 UTC (permalink / raw)
  To: David Gibson
  Cc: Cédric Le Goater, qemu-ppc, Greg Kurz, Suraj Jitindar Singh,
	qemu-devel

This prepares ground for partition-scoped Radix translation.

Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
 target/ppc/mmu-radix64.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 4b0d0ff50a3c..11b3c6d48c65 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -105,7 +105,8 @@ static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr,
 
 
 static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
-                                   int *fault_cause, int *prot)
+                                   int *fault_cause, int *prot,
+                                   bool partition_scoped)
 {
     CPUPPCState *env = &cpu->env;
     const int need_prot[] = { PAGE_READ, PAGE_WRITE, PAGE_EXEC };
@@ -121,11 +122,11 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
     }
 
     /* Determine permissions allowed by Encoded Access Authority */
-    if ((pte & R_PTE_EAA_PRIV) && msr_pr) { /* Insufficient Privilege */
+    if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) {
         *prot = 0;
-    } else if (msr_pr || (pte & R_PTE_EAA_PRIV)) {
+    } else if (msr_pr || (pte & R_PTE_EAA_PRIV) || partition_scoped) {
         *prot = ppc_radix64_get_prot_eaa(pte);
-    } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) */
+    } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */
         *prot = ppc_radix64_get_prot_eaa(pte);
         *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */
     }
@@ -250,7 +251,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
                                 g_raddr, g_page_size, &fault_cause, &pte_addr);
 
     if (!(pte & R_PTE_VALID) ||
-        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot)) {
+        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
         /* No valid pte or access denied due to protection */
         if (cause_excp) {
             ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 3/4] target/ppc: Rework ppc_radix64_walk_tree() for partition-scoped translation
  2020-04-03 14:00 [PATCH v4 0/4] target/ppc: Add support for Radix partition-scoped translation Cédric Le Goater
  2020-04-03 14:00 ` [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation Cédric Le Goater
  2020-04-03 14:00 ` [PATCH v4 2/4] target/ppc: Extend ppc_radix64_check_prot() with a 'partition_scoped' bool Cédric Le Goater
@ 2020-04-03 14:00 ` Cédric Le Goater
  2020-04-03 14:00 ` [PATCH v4 4/4] target/ppc: Add support for Radix " Cédric Le Goater
  3 siblings, 0 replies; 10+ messages in thread
From: Cédric Le Goater @ 2020-04-03 14:00 UTC (permalink / raw)
  To: David Gibson
  Cc: Cédric Le Goater, qemu-ppc, Greg Kurz, Suraj Jitindar Singh,
	qemu-devel

The ppc_radix64_walk_tree() routine walks through the nested radix
tables to look for a PTE.

Split it in two and introduce a new routine ppc_radix64_next_level()
which we will use for partition-scoped Radix translation when
translating the process tree addresses. The prototypes are slightly
change to use a 'AddressSpace *' parameter, instead of a 'PowerPCCPU *'
which is not required, and to return an error code instead of a PTE
value. It clarifies error handling in the callers.

Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 target/ppc/mmu-radix64.c | 79 ++++++++++++++++++++++++++--------------
 1 file changed, 52 insertions(+), 27 deletions(-)

diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 11b3c6d48c65..2400da41e06c 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -163,44 +163,67 @@ static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte,
     }
 }
 
-static uint64_t ppc_radix64_walk_tree(PowerPCCPU *cpu, vaddr eaddr,
-                                      uint64_t base_addr, uint64_t nls,
-                                      hwaddr *raddr, int *psize,
-                                      int *fault_cause, hwaddr *pte_addr)
+static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
+                                  uint64_t *pte_addr, uint64_t *nls,
+                                  int *psize, uint64_t *pte, int *fault_cause)
 {
-    CPUState *cs = CPU(cpu);
     uint64_t index, pde;
 
-    if (nls < 5) { /* Directory maps less than 2**5 entries */
+    if (*nls < 5) { /* Directory maps less than 2**5 entries */
         *fault_cause |= DSISR_R_BADCONFIG;
-        return 0;
+        return 1;
     }
 
     /* Read page <directory/table> entry from guest address space */
-    index = eaddr >> (*psize - nls); /* Shift */
-    index &= ((1UL << nls) - 1); /* Mask */
-    pde = ldq_phys(cs->as, base_addr + (index * sizeof(pde)));
-    if (!(pde & R_PTE_VALID)) { /* Invalid Entry */
+    pde = ldq_phys(as, *pte_addr);
+    if (!(pde & R_PTE_VALID)) {         /* Invalid Entry */
         *fault_cause |= DSISR_NOPTE;
-        return 0;
+        return 1;
     }
 
-    *psize -= nls;
+    *pte = pde;
+    *psize -= *nls;
+    if (!(pde & R_PTE_LEAF)) { /* Prepare for next iteration */
+        *nls = pde & R_PDE_NLS;
+        index = eaddr >> (*psize - *nls);       /* Shift */
+        index &= ((1UL << *nls) - 1);           /* Mask */
+        *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
+    }
+    return 0;
+}
 
-    /* Check if Leaf Entry -> Page Table Entry -> Stop the Search */
-    if (pde & R_PTE_LEAF) {
-        uint64_t rpn = pde & R_PTE_RPN;
-        uint64_t mask = (1UL << *psize) - 1;
+static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
+                                 uint64_t base_addr, uint64_t nls,
+                                 hwaddr *raddr, int *psize, uint64_t *pte,
+                                 int *fault_cause, hwaddr *pte_addr)
+{
+    uint64_t index, pde, rpn , mask;
 
-        /* Or high bits of rpn and low bits to ea to form whole real addr */
-        *raddr = (rpn & ~mask) | (eaddr & mask);
-        *pte_addr = base_addr + (index * sizeof(pde));
-        return pde;
+    if (nls < 5) { /* Directory maps less than 2**5 entries */
+        *fault_cause |= DSISR_R_BADCONFIG;
+        return 1;
     }
 
-    /* Next Level of Radix Tree */
-    return ppc_radix64_walk_tree(cpu, eaddr, pde & R_PDE_NLB, pde & R_PDE_NLS,
-                                 raddr, psize, fault_cause, pte_addr);
+    index = eaddr >> (*psize - nls);    /* Shift */
+    index &= ((1UL << nls) - 1);       /* Mask */
+    *pte_addr = base_addr + (index * sizeof(pde));
+    do {
+        int ret;
+
+        ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde,
+                                     fault_cause);
+        if (ret) {
+            return ret;
+        }
+    } while (!(pde & R_PTE_LEAF));
+
+    *pte = pde;
+    rpn = pde & R_PTE_RPN;
+    mask = (1UL << *psize) - 1;
+
+    /* Or high bits of rpn and low bits to ea to form whole real addr */
+    *raddr = (rpn & ~mask) | (eaddr & mask);
+    return 0;
 }
 
 static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
@@ -230,6 +253,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
     uint64_t offset, size, prtbe_addr, prtbe0, pte;
     int fault_cause = 0;
     hwaddr pte_addr;
+    int ret;
 
     /* Index Process Table by PID to Find Corresponding Process Table Entry */
     offset = pid * sizeof(struct prtb_entry);
@@ -246,11 +270,12 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
 
     /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
     *g_page_size = PRTBE_R_GET_RTS(prtbe0);
-    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
+    ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK,
                                 prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
-                                g_raddr, g_page_size, &fault_cause, &pte_addr);
+                                g_raddr, g_page_size, &pte, &fault_cause,
+                                &pte_addr);
 
-    if (!(pte & R_PTE_VALID) ||
+    if (ret ||
         ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
         /* No valid pte or access denied due to protection */
         if (cause_excp) {
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 4/4] target/ppc: Add support for Radix partition-scoped translation
  2020-04-03 14:00 [PATCH v4 0/4] target/ppc: Add support for Radix partition-scoped translation Cédric Le Goater
                   ` (2 preceding siblings ...)
  2020-04-03 14:00 ` [PATCH v4 3/4] target/ppc: Rework ppc_radix64_walk_tree() for partition-scoped translation Cédric Le Goater
@ 2020-04-03 14:00 ` Cédric Le Goater
  2020-04-03 15:11   ` Greg Kurz
  3 siblings, 1 reply; 10+ messages in thread
From: Cédric Le Goater @ 2020-04-03 14:00 UTC (permalink / raw)
  To: David Gibson
  Cc: Cédric Le Goater, qemu-ppc, Greg Kurz, Suraj Jitindar Singh,
	qemu-devel

The Radix tree translation model currently supports process-scoped
translation for the PowerNV machine (Hypervisor mode) and for the
pSeries machine (Guest mode). Guests running under an emulated
Hypervisor (PowerNV machine) require a new type of Radix translation,
called partition-scoped, which is missing today.

The Radix tree translation is a 2 steps process. The first step,
process-scoped translation, converts an effective Address to a guest
real address, and the second step, partition-scoped translation,
converts a guest real address to a host real address.

There are difference cases to covers :

* Hypervisor real mode access: no Radix translation.

* Hypervisor or host application access (quadrant 0 and 3) with
  relocation on: process-scoped translation.

* Guest OS real mode access: only partition-scoped translation.

* Guest OS real or guest application access (quadrant 0 and 3) with
  relocation on: both process-scoped translation and partition-scoped
  translations.

* Hypervisor access in quadrant 1 and 2 with relocation on: both
  process-scoped translation and partition-scoped translations.

The radix tree partition-scoped translation is performed using tables
pointed to by the first double-word of the Partition Table Entries and
process-scoped translation uses tables pointed to by the Process Table
Entries (second double-word of the Partition Table Entries).

Both partition-scoped and process-scoped translations process are
identical and thus the radix tree traversing code is largely reused.
However, errors in partition-scoped translations generate hypervisor
exceptions.

Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 target/ppc/cpu.h         |   3 +
 target/ppc/excp_helper.c |   3 +-
 target/ppc/mmu-radix64.c | 188 +++++++++++++++++++++++++++++++++++----
 3 files changed, 175 insertions(+), 19 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index f4a5304d4356..6b6dd7e483f1 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -463,6 +463,9 @@ typedef struct ppc_v3_pate_t {
 #define DSISR_AMR                0x00200000
 /* Unsupported Radix Tree Configuration */
 #define DSISR_R_BADCONFIG        0x00080000
+#define DSISR_ATOMIC_RC          0x00040000
+/* Unable to translate address of (guest) pde or process/page table entry */
+#define DSISR_PRTABLE_FAULT      0x00020000
 
 /* SRR1 error code fields */
 
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 1acc3786de0e..f05297966472 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -506,9 +506,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
     case POWERPC_EXCP_TRACE:     /* Trace exception                          */
         break;
+    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
+        msr |= env->error_code;
     case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
     case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
-    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
     case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
     case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
     case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 2400da41e06c..d473dc742e11 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -103,6 +103,27 @@ static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr,
     }
 }
 
+static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, int rwx, vaddr eaddr,
+                                  hwaddr g_raddr, uint32_t cause)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    if (rwx == 2) { /* H Instruction Storage Interrupt */
+        cs->exception_index = POWERPC_EXCP_HISI;
+        env->spr[SPR_ASDR] = g_raddr;
+        env->error_code = cause;
+    } else { /* H Data Storage Interrupt */
+        cs->exception_index = POWERPC_EXCP_HDSI;
+        if (rwx == 1) { /* Write -> Store */
+            cause |= DSISR_ISSTORE;
+        }
+        env->spr[SPR_HDSISR] = cause;
+        env->spr[SPR_HDAR] = eaddr;
+        env->spr[SPR_ASDR] = g_raddr;
+        env->error_code = 0;
+    }
+}
 
 static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
                                    int *fault_cause, int *prot,
@@ -243,6 +264,37 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
     return true;
 }
 
+static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
+                                              vaddr eaddr, hwaddr g_raddr,
+                                              ppc_v3_pate_t pate,
+                                              hwaddr *h_raddr, int *h_prot,
+                                              int *h_page_size, bool pde_addr,
+                                              bool cause_excp)
+{
+    int fault_cause = 0;
+    hwaddr pte_addr;
+    uint64_t pte;
+
+    *h_page_size = PRTBE_R_GET_RTS(pate.dw0);
+    /* No valid pte or access denied due to protection */
+    if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
+                              pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
+                              &pte, &fault_cause, &pte_addr) ||
+        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) {
+        if (pde_addr) /* address being translated was that of a guest pde */
+            fault_cause |= DSISR_PRTABLE_FAULT;
+        if (cause_excp) {
+            ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause);
+        }
+        return 1;
+    }
+
+    /* Update Reference and Change Bits */
+    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
+
+    return 0;
+}
+
 static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
                                             vaddr eaddr, uint64_t pid,
                                             ppc_v3_pate_t pate, hwaddr *g_raddr,
@@ -250,9 +302,10 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
                                             bool cause_excp)
 {
     CPUState *cs = CPU(cpu);
-    uint64_t offset, size, prtbe_addr, prtbe0, pte;
-    int fault_cause = 0;
-    hwaddr pte_addr;
+    CPUPPCState *env = &cpu->env;
+    uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
+    int fault_cause = 0, h_page_size, h_prot;
+    hwaddr h_raddr, pte_addr;
     int ret;
 
     /* Index Process Table by PID to Find Corresponding Process Table Entry */
@@ -266,18 +319,85 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
         return 1;
     }
     prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
-    prtbe0 = ldq_phys(cs->as, prtbe_addr);
+
+    if (cpu->vhyp) {
+        prtbe0 = ldq_phys(cs->as, prtbe_addr);
+    } else {
+        /*
+         * Process table addresses are subject to partition-scoped
+         * translation
+         *
+         * On a Radix host, the partition-scoped page table for LPID=0
+         * is only used to translate the effective addresses of the
+         * process table entries.
+         */
+        ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
+                                                 pate, &h_raddr, &h_prot,
+                                                 &h_page_size, 1, 1);
+        if (ret) {
+            return ret;
+        }
+        prtbe0 = ldq_phys(cs->as, h_raddr);
+    }
 
     /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
     *g_page_size = PRTBE_R_GET_RTS(prtbe0);
-    ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK,
-                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
-                                g_raddr, g_page_size, &pte, &fault_cause,
-                                &pte_addr);
-
-    if (ret ||
-        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
-        /* No valid pte or access denied due to protection */
+    base_addr = prtbe0 & PRTBE_R_RPDB;
+    nls = prtbe0 & PRTBE_R_RPDS;
+    if (msr_hv || cpu->vhyp) {
+        /*
+         * Can treat process table addresses as real addresses
+         */
+        ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
+                                    nls, g_raddr, g_page_size, &pte,
+                                    &fault_cause, &pte_addr);
+        if (ret) {
+            /* No valid PTE */
+            if (cause_excp) {
+                ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
+            }
+            return ret;
+        }
+    } else {
+        uint64_t rpn, mask;
+
+        index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
+        index &= ((1UL << nls) - 1);                            /* Mask */
+        pte_addr = base_addr + (index * sizeof(pte));
+
+        /*
+         * Each process table address is subject to a partition-scoped
+         * translation
+         */
+        do {
+            ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
+                                                     pate, &h_raddr, &h_prot,
+                                                     &h_page_size, 1, 1);
+            if (ret) {
+                return ret;
+            }
+
+            ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
+                                         &nls, g_page_size, &pte, &fault_cause);
+            if (ret) {
+                /* No valid pte */
+                if (cause_excp) {
+                    ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
+                }
+                return ret;
+            }
+            pte_addr = h_raddr;
+        } while (!(pte & R_PTE_LEAF));
+
+        rpn = pte & R_PTE_RPN;
+        mask = (1UL << *g_page_size) - 1;
+
+        /* Or high bits of rpn and low bits to ea to form whole real addr */
+        *g_raddr = (rpn & ~mask) | (eaddr & mask);
+    }
+
+    if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
+        /* Access denied due to protection */
         if (cause_excp) {
             ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
         }
@@ -289,11 +409,29 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
     return 0;
 }
 
+/*
+ * Radix tree translation is a 2 steps translation process:
+ *
+ * 1. Process-scoped translation:   Guest Eff Addr  -> Guest Real Addr
+ * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
+ *
+ *                                  MSR[HV]
+ *              +-------------+----------------+---------------+
+ *              |             |     HV = 0     |     HV = 1    |
+ *              +-------------+----------------+---------------+
+ *              | Relocation  |    Partition   |      No       |
+ *              | = Off       |     Scoped     |  Translation  |
+ *  Relocation  +-------------+----------------+---------------+
+ *              | Relocation  |   Partition &  |    Process    |
+ *              | = On        | Process Scoped |    Scoped     |
+ *              +-------------+----------------+---------------+
+ */
 static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
                              bool relocation,
                              hwaddr *raddr, int *psizep, int *protp,
                              bool cause_excp)
 {
+    CPUPPCState *env = &cpu->env;
     uint64_t lpid = 0, pid = 0;
     ppc_v3_pate_t pate;
     int psize, prot;
@@ -325,11 +463,6 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
             }
             return 1;
         }
-        /* We don't support guest mode yet */
-        if (lpid != 0) {
-            error_report("PowerNV guest support Unimplemented");
-            exit(1);
-        }
     }
 
     *psizep = INT_MAX;
@@ -340,6 +473,8 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
      *
      * - Translates an effective address to a host real address in
      *   quadrants 0 and 3 when HV=1.
+     *
+     * - Translates an effective address to a guest real address.
      */
     if (relocation) {
         int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
@@ -354,7 +489,24 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
         g_raddr = eaddr & R_EADDR_MASK;
     }
 
-    *raddr = g_raddr;
+    /*
+     * Perform partition-scoped translation if !HV or HV access to
+     * quadrants 1 or 2. Translates a guest real address to a host
+     * real address.
+     */
+    if ((lpid != 0) || (!cpu->vhyp && !msr_hv)) {
+        int ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
+                                                     pate, raddr, &prot, &psize,
+                                                     0, cause_excp);
+        if (ret) {
+            return ret;
+        }
+        *psizep = MIN(*psizep, psize);
+        *protp &= prot;
+    } else {
+        *raddr = g_raddr;
+    }
+
     return 0;
 }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation
  2020-04-03 14:00 ` [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation Cédric Le Goater
@ 2020-04-03 14:56   ` Greg Kurz
  2020-04-08  2:57   ` David Gibson
  1 sibling, 0 replies; 10+ messages in thread
From: Greg Kurz @ 2020-04-03 14:56 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, qemu-devel, Suraj Jitindar Singh, David Gibson

On Fri,  3 Apr 2020 16:00:53 +0200
Cédric Le Goater <clg@kaod.org> wrote:

> This is moving code under a new ppc_radix64_xlate() routine shared by
> the MMU Radix page fault handler and the 'get_phys_page_debug' PPC
> callback. The difference being that 'get_phys_page_debug' does not
> generate exceptions.
> 
> The specific part of process-scoped Radix translation is moved under
> ppc_radix64_process_scoped_xlate() in preparation of the future support
> for partition-scoped Radix translation. Routines raising the exceptions
> now take a 'cause_excp' bool to cover the 'get_phys_page_debug' case.
> 
> It should be functionally equivalent.
> 
> Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  target/ppc/mmu-radix64.c | 219 ++++++++++++++++++++++-----------------
>  1 file changed, 123 insertions(+), 96 deletions(-)
> 
> diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
> index d2422d1c54c9..4b0d0ff50a3c 100644
> --- a/target/ppc/mmu-radix64.c
> +++ b/target/ppc/mmu-radix64.c
> @@ -219,17 +219,127 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
>      return true;
>  }
>  
> +static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
> +                                            vaddr eaddr, uint64_t pid,
> +                                            ppc_v3_pate_t pate, hwaddr *g_raddr,
> +                                            int *g_prot, int *g_page_size,
> +                                            bool cause_excp)
> +{
> +    CPUState *cs = CPU(cpu);
> +    uint64_t offset, size, prtbe_addr, prtbe0, pte;
> +    int fault_cause = 0;
> +    hwaddr pte_addr;
> +
> +    /* Index Process Table by PID to Find Corresponding Process Table Entry */
> +    offset = pid * sizeof(struct prtb_entry);
> +    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
> +    if (offset >= size) {
> +        /* offset exceeds size of the process table */
> +        if (cause_excp) {
> +            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
> +        }
> +        return 1;
> +    }
> +    prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
> +    prtbe0 = ldq_phys(cs->as, prtbe_addr);
> +
> +    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
> +    *g_page_size = PRTBE_R_GET_RTS(prtbe0);
> +    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
> +                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
> +                                g_raddr, g_page_size, &fault_cause, &pte_addr);
> +
> +    if (!(pte & R_PTE_VALID) ||

As previously discussed, this could have remained "if (!pte ||" but checking
the valid bit works too and anyway this goes away in a later patch in this
series.

Reviewed-by: Greg Kurz <groug@kaod.org>


> +        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot)) {
> +        /* No valid pte or access denied due to protection */
> +        if (cause_excp) {
> +            ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> +        }
> +        return 1;
> +    }
> +
> +    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
> +
> +    return 0;
> +}
> +
> +static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
> +                             bool relocation,
> +                             hwaddr *raddr, int *psizep, int *protp,
> +                             bool cause_excp)
> +{
> +    uint64_t lpid = 0, pid = 0;
> +    ppc_v3_pate_t pate;
> +    int psize, prot;
> +    hwaddr g_raddr;
> +
> +    /* Virtual Mode Access - get the fully qualified address */
> +    if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
> +        if (cause_excp) {
> +            ppc_radix64_raise_segi(cpu, rwx, eaddr);
> +        }
> +        return 1;
> +    }
> +
> +    /* Get Process Table */
> +    if (cpu->vhyp) {
> +        PPCVirtualHypervisorClass *vhc;
> +        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> +        vhc->get_pate(cpu->vhyp, &pate);
> +    } else {
> +        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
> +            if (cause_excp) {
> +                ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
> +            }
> +            return 1;
> +        }
> +        if (!validate_pate(cpu, lpid, &pate)) {
> +            if (cause_excp) {
> +                ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
> +            }
> +            return 1;
> +        }
> +        /* We don't support guest mode yet */
> +        if (lpid != 0) {
> +            error_report("PowerNV guest support Unimplemented");
> +            exit(1);
> +        }
> +    }
> +
> +    *psizep = INT_MAX;
> +    *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> +
> +    /*
> +     * Perform process-scoped translation if relocation enabled.
> +     *
> +     * - Translates an effective address to a host real address in
> +     *   quadrants 0 and 3 when HV=1.
> +     */
> +    if (relocation) {
> +        int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
> +                                                   pate, &g_raddr, &prot,
> +                                                   &psize, cause_excp);
> +        if (ret) {
> +            return ret;
> +        }
> +        *psizep = MIN(*psizep, psize);
> +        *protp &= prot;
> +    } else {
> +        g_raddr = eaddr & R_EADDR_MASK;
> +    }
> +
> +    *raddr = g_raddr;
> +    return 0;
> +}
> +
>  int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>                                   int mmu_idx)
>  {
>      CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
> -    PPCVirtualHypervisorClass *vhc;
> -    hwaddr raddr, pte_addr;
> -    uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte;
> -    int page_size, prot, fault_cause = 0;
> -    ppc_v3_pate_t pate;
> +    int page_size, prot;
>      bool relocation;
> +    hwaddr raddr;
>  
>      assert(!(msr_hv && cpu->vhyp));
>      assert((rwx == 0) || (rwx == 1) || (rwx == 2));
> @@ -262,55 +372,12 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>                        TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
>      }
>  
> -    /* Virtual Mode Access - get the fully qualified address */
> -    if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) {
> -        ppc_radix64_raise_segi(cpu, rwx, eaddr);
> +    /* Translate eaddr to raddr (where raddr is addr qemu needs for access) */
> +    if (ppc_radix64_xlate(cpu, eaddr, rwx, relocation, &raddr,
> +                          &page_size, &prot, true)) {
>          return 1;
>      }
>  
> -    /* Get Process Table */
> -    if (cpu->vhyp) {
> -        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> -        vhc->get_pate(cpu->vhyp, &pate);
> -    } else {
> -        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
> -            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
> -            return 1;
> -        }
> -        if (!validate_pate(cpu, lpid, &pate)) {
> -            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
> -        }
> -        /* We don't support guest mode yet */
> -        if (lpid != 0) {
> -            error_report("PowerNV guest support Unimplemented");
> -            exit(1);
> -       }
> -    }
> -
> -    /* Index Process Table by PID to Find Corresponding Process Table Entry */
> -    offset = pid * sizeof(struct prtb_entry);
> -    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
> -    if (offset >= size) {
> -        /* offset exceeds size of the process table */
> -        ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
> -        return 1;
> -    }
> -    prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset);
> -
> -    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
> -    page_size = PRTBE_R_GET_RTS(prtbe0);
> -    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
> -                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
> -                                &raddr, &page_size, &fault_cause, &pte_addr);
> -    if (!pte || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, &prot)) {
> -        /* Couldn't get pte or access denied due to protection */
> -        ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> -        return 1;
> -    }
> -
> -    /* Update Reference and Change Bits */
> -    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, &prot);
> -
>      tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
>                   prot, mmu_idx, 1UL << page_size);
>      return 0;
> @@ -318,58 +385,18 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>  
>  hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr)
>  {
> -    CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
> -    PPCVirtualHypervisorClass *vhc;
> -    hwaddr raddr, pte_addr;
> -    uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte;
> -    int page_size, fault_cause = 0;
> -    ppc_v3_pate_t pate;
> +    int psize, prot;
> +    hwaddr raddr;
>  
>      /* Handle Real Mode */
> -    if (msr_dr == 0) {
> +    if ((msr_dr == 0) && (msr_hv || cpu->vhyp)) {
>          /* In real mode top 4 effective addr bits (mostly) ignored */
>          return eaddr & 0x0FFFFFFFFFFFFFFFULL;
>      }
>  
> -    /* Virtual Mode Access - get the fully qualified address */
> -    if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) {
> -        return -1;
> -    }
> -
> -    /* Get Process Table */
> -    if (cpu->vhyp) {
> -        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> -        vhc->get_pate(cpu->vhyp, &pate);
> -    } else {
> -        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
> -            return -1;
> -        }
> -        if (!validate_pate(cpu, lpid, &pate)) {
> -            return -1;
> -        }
> -        /* We don't support guest mode yet */
> -        if (lpid != 0) {
> -            error_report("PowerNV guest support Unimplemented");
> -            exit(1);
> -       }
> -    }
> -
> -    /* Index Process Table by PID to Find Corresponding Process Table Entry */
> -    offset = pid * sizeof(struct prtb_entry);
> -    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
> -    if (offset >= size) {
> -        /* offset exceeds size of the process table */
> -        return -1;
> -    }
> -    prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset);
> -
> -    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
> -    page_size = PRTBE_R_GET_RTS(prtbe0);
> -    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
> -                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
> -                                &raddr, &page_size, &fault_cause, &pte_addr);
> -    if (!pte) {
> +    if (ppc_radix64_xlate(cpu, eaddr, 0, msr_dr, &raddr, &psize,
> +                          &prot, false)) {
>          return -1;
>      }
>  



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 4/4] target/ppc: Add support for Radix partition-scoped translation
  2020-04-03 14:00 ` [PATCH v4 4/4] target/ppc: Add support for Radix " Cédric Le Goater
@ 2020-04-03 15:11   ` Greg Kurz
  2020-04-08  3:09     ` David Gibson
  0 siblings, 1 reply; 10+ messages in thread
From: Greg Kurz @ 2020-04-03 15:11 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, qemu-devel, Suraj Jitindar Singh, David Gibson

On Fri,  3 Apr 2020 16:00:56 +0200
Cédric Le Goater <clg@kaod.org> wrote:

> The Radix tree translation model currently supports process-scoped
> translation for the PowerNV machine (Hypervisor mode) and for the
> pSeries machine (Guest mode). Guests running under an emulated
> Hypervisor (PowerNV machine) require a new type of Radix translation,
> called partition-scoped, which is missing today.
> 
> The Radix tree translation is a 2 steps process. The first step,
> process-scoped translation, converts an effective Address to a guest
> real address, and the second step, partition-scoped translation,
> converts a guest real address to a host real address.
> 
> There are difference cases to covers :
> 
> * Hypervisor real mode access: no Radix translation.
> 
> * Hypervisor or host application access (quadrant 0 and 3) with
>   relocation on: process-scoped translation.
> 
> * Guest OS real mode access: only partition-scoped translation.
> 
> * Guest OS real or guest application access (quadrant 0 and 3) with
>   relocation on: both process-scoped translation and partition-scoped
>   translations.
> 
> * Hypervisor access in quadrant 1 and 2 with relocation on: both
>   process-scoped translation and partition-scoped translations.
> 
> The radix tree partition-scoped translation is performed using tables
> pointed to by the first double-word of the Partition Table Entries and
> process-scoped translation uses tables pointed to by the Process Table
> Entries (second double-word of the Partition Table Entries).
> 
> Both partition-scoped and process-scoped translations process are
> identical and thus the radix tree traversing code is largely reused.
> However, errors in partition-scoped translations generate hypervisor
> exceptions.
> 
> Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> Signed-off-by: Greg Kurz <groug@kaod.org>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>  target/ppc/cpu.h         |   3 +
>  target/ppc/excp_helper.c |   3 +-
>  target/ppc/mmu-radix64.c | 188 +++++++++++++++++++++++++++++++++++----
>  3 files changed, 175 insertions(+), 19 deletions(-)
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index f4a5304d4356..6b6dd7e483f1 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -463,6 +463,9 @@ typedef struct ppc_v3_pate_t {
>  #define DSISR_AMR                0x00200000
>  /* Unsupported Radix Tree Configuration */
>  #define DSISR_R_BADCONFIG        0x00080000
> +#define DSISR_ATOMIC_RC          0x00040000
> +/* Unable to translate address of (guest) pde or process/page table entry */
> +#define DSISR_PRTABLE_FAULT      0x00020000
>  
>  /* SRR1 error code fields */
>  
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 1acc3786de0e..f05297966472 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -506,9 +506,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
>      case POWERPC_EXCP_TRACE:     /* Trace exception                          */
>          break;
> +    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
> +        msr |= env->error_code;
>      case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
>      case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
> -    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
>      case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
>      case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
>      case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
> diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
> index 2400da41e06c..d473dc742e11 100644
> --- a/target/ppc/mmu-radix64.c
> +++ b/target/ppc/mmu-radix64.c
> @@ -103,6 +103,27 @@ static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr,
>      }
>  }
>  
> +static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, int rwx, vaddr eaddr,
> +                                  hwaddr g_raddr, uint32_t cause)
> +{
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +
> +    if (rwx == 2) { /* H Instruction Storage Interrupt */
> +        cs->exception_index = POWERPC_EXCP_HISI;
> +        env->spr[SPR_ASDR] = g_raddr;
> +        env->error_code = cause;
> +    } else { /* H Data Storage Interrupt */
> +        cs->exception_index = POWERPC_EXCP_HDSI;
> +        if (rwx == 1) { /* Write -> Store */
> +            cause |= DSISR_ISSTORE;
> +        }
> +        env->spr[SPR_HDSISR] = cause;
> +        env->spr[SPR_HDAR] = eaddr;
> +        env->spr[SPR_ASDR] = g_raddr;
> +        env->error_code = 0;
> +    }
> +}
>  
>  static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
>                                     int *fault_cause, int *prot,
> @@ -243,6 +264,37 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
>      return true;
>  }
>  
> +static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
> +                                              vaddr eaddr, hwaddr g_raddr,
> +                                              ppc_v3_pate_t pate,
> +                                              hwaddr *h_raddr, int *h_prot,
> +                                              int *h_page_size, bool pde_addr,
> +                                              bool cause_excp)
> +{
> +    int fault_cause = 0;
> +    hwaddr pte_addr;
> +    uint64_t pte;
> +
> +    *h_page_size = PRTBE_R_GET_RTS(pate.dw0);
> +    /* No valid pte or access denied due to protection */
> +    if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
> +                              pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
> +                              &pte, &fault_cause, &pte_addr) ||
> +        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) {
> +        if (pde_addr) /* address being translated was that of a guest pde */
> +            fault_cause |= DSISR_PRTABLE_FAULT;
> +        if (cause_excp) {
> +            ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause);
> +        }
> +        return 1;
> +    }
> +
> +    /* Update Reference and Change Bits */
> +    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
> +
> +    return 0;
> +}
> +
>  static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
>                                              vaddr eaddr, uint64_t pid,
>                                              ppc_v3_pate_t pate, hwaddr *g_raddr,
> @@ -250,9 +302,10 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
>                                              bool cause_excp)
>  {
>      CPUState *cs = CPU(cpu);
> -    uint64_t offset, size, prtbe_addr, prtbe0, pte;
> -    int fault_cause = 0;
> -    hwaddr pte_addr;
> +    CPUPPCState *env = &cpu->env;
> +    uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
> +    int fault_cause = 0, h_page_size, h_prot;
> +    hwaddr h_raddr, pte_addr;
>      int ret;
>  
>      /* Index Process Table by PID to Find Corresponding Process Table Entry */
> @@ -266,18 +319,85 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
>          return 1;
>      }
>      prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
> -    prtbe0 = ldq_phys(cs->as, prtbe_addr);
> +
> +    if (cpu->vhyp) {
> +        prtbe0 = ldq_phys(cs->as, prtbe_addr);
> +    } else {
> +        /*
> +         * Process table addresses are subject to partition-scoped
> +         * translation
> +         *
> +         * On a Radix host, the partition-scoped page table for LPID=0
> +         * is only used to translate the effective addresses of the
> +         * process table entries.
> +         */
> +        ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
> +                                                 pate, &h_raddr, &h_prot,
> +                                                 &h_page_size, 1, 1);
> +        if (ret) {
> +            return ret;
> +        }
> +        prtbe0 = ldq_phys(cs->as, h_raddr);
> +    }
>  
>      /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
>      *g_page_size = PRTBE_R_GET_RTS(prtbe0);
> -    ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK,
> -                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
> -                                g_raddr, g_page_size, &pte, &fault_cause,
> -                                &pte_addr);
> -
> -    if (ret ||
> -        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
> -        /* No valid pte or access denied due to protection */
> +    base_addr = prtbe0 & PRTBE_R_RPDB;
> +    nls = prtbe0 & PRTBE_R_RPDS;
> +    if (msr_hv || cpu->vhyp) {
> +        /*
> +         * Can treat process table addresses as real addresses
> +         */
> +        ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
> +                                    nls, g_raddr, g_page_size, &pte,
> +                                    &fault_cause, &pte_addr);
> +        if (ret) {
> +            /* No valid PTE */
> +            if (cause_excp) {
> +                ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> +            }
> +            return ret;
> +        }
> +    } else {
> +        uint64_t rpn, mask;
> +
> +        index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
> +        index &= ((1UL << nls) - 1);                            /* Mask */
> +        pte_addr = base_addr + (index * sizeof(pte));
> +
> +        /*
> +         * Each process table address is subject to a partition-scoped
> +         * translation
> +         */
> +        do {
> +            ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
> +                                                     pate, &h_raddr, &h_prot,
> +                                                     &h_page_size, 1, 1);
> +            if (ret) {
> +                return ret;
> +            }
> +
> +            ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
> +                                         &nls, g_page_size, &pte, &fault_cause);
> +            if (ret) {
> +                /* No valid pte */
> +                if (cause_excp) {
> +                    ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> +                }
> +                return ret;
> +            }
> +            pte_addr = h_raddr;
> +        } while (!(pte & R_PTE_LEAF));
> +
> +        rpn = pte & R_PTE_RPN;
> +        mask = (1UL << *g_page_size) - 1;
> +
> +        /* Or high bits of rpn and low bits to ea to form whole real addr */
> +        *g_raddr = (rpn & ~mask) | (eaddr & mask);
> +    }
> +
> +    if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
> +        /* Access denied due to protection */
>          if (cause_excp) {
>              ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
>          }
> @@ -289,11 +409,29 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
>      return 0;
>  }
>  
> +/*
> + * Radix tree translation is a 2 steps translation process:
> + *
> + * 1. Process-scoped translation:   Guest Eff Addr  -> Guest Real Addr
> + * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
> + *
> + *                                  MSR[HV]
> + *              +-------------+----------------+---------------+
> + *              |             |     HV = 0     |     HV = 1    |
> + *              +-------------+----------------+---------------+
> + *              | Relocation  |    Partition   |      No       |
> + *              | = Off       |     Scoped     |  Translation  |
> + *  Relocation  +-------------+----------------+---------------+
> + *              | Relocation  |   Partition &  |    Process    |
> + *              | = On        | Process Scoped |    Scoped     |
> + *              +-------------+----------------+---------------+
> + */
>  static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>                               bool relocation,
>                               hwaddr *raddr, int *psizep, int *protp,
>                               bool cause_excp)
>  {
> +    CPUPPCState *env = &cpu->env;
>      uint64_t lpid = 0, pid = 0;
>      ppc_v3_pate_t pate;
>      int psize, prot;
> @@ -325,11 +463,6 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>              }
>              return 1;
>          }
> -        /* We don't support guest mode yet */
> -        if (lpid != 0) {
> -            error_report("PowerNV guest support Unimplemented");
> -            exit(1);
> -        }
>      }
>  
>      *psizep = INT_MAX;
> @@ -340,6 +473,8 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>       *
>       * - Translates an effective address to a host real address in
>       *   quadrants 0 and 3 when HV=1.
> +     *
> +     * - Translates an effective address to a guest real address.
>       */
>      if (relocation) {
>          int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
> @@ -354,7 +489,24 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>          g_raddr = eaddr & R_EADDR_MASK;
>      }
>  
> -    *raddr = g_raddr;
> +    /*
> +     * Perform partition-scoped translation if !HV or HV access to
> +     * quadrants 1 or 2. Translates a guest real address to a host
> +     * real address.
> +     */
> +    if ((lpid != 0) || (!cpu->vhyp && !msr_hv)) {

This check is too complex for my taste. Also it doesn't seem right
to look at lpid if the machine is pseries, even if it would happen
to work because pseries cannot have lpid != 0. I think we should
have distinct paths for powernv and pseries.

A bit like with the following squashed in:

=======================================
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -489,22 +489,28 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
         g_raddr = eaddr & R_EADDR_MASK;
     }
 
-    /*
-     * Perform partition-scoped translation if !HV or HV access to
-     * quadrants 1 or 2. Translates a guest real address to a host
-     * real address.
-     */
-    if ((lpid != 0) || (!cpu->vhyp && !msr_hv)) {
-        int ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
+    if (cpu->vhyp) {
+        *raddr = g_raddr;
+    } else {
+        /*
+         * Perform partition-scoped translation if !HV or HV access to
+         * quadrants 1 or 2. Translates a guest real address to a host
+         * real address.
+         */
+        if (lpid || !msr_hv) {
+            int ret;
+
+            ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
                                                      pate, raddr, &prot, &psize,
                                                      0, cause_excp);
-        if (ret) {
-            return ret;
+            if (ret) {
+                return ret;
+            }
+            *psizep = MIN(*psizep, psize);
+            *protp &= prot;
+        } else {
+            *raddr = g_raddr;
         }
-        *psizep = MIN(*psizep, psize);
-        *protp &= prot;
-    } else {
-        *raddr = g_raddr;
     }
 
     return 0;
=======================================

David,

If my comment makes sense to you, can you squash the above fix into
Cedric's patch ?

Cheers,

--
Greg

> +        int ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
> +                                                     pate, raddr, &prot, &psize,
> +                                                     0, cause_excp);
> +        if (ret) {
> +            return ret;
> +        }
> +        *psizep = MIN(*psizep, psize);
> +        *protp &= prot;
> +    } else {
> +        *raddr = g_raddr;
> +    }
> +
>      return 0;
>  }
>  



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation
  2020-04-03 14:00 ` [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation Cédric Le Goater
  2020-04-03 14:56   ` Greg Kurz
@ 2020-04-08  2:57   ` David Gibson
  1 sibling, 0 replies; 10+ messages in thread
From: David Gibson @ 2020-04-08  2:57 UTC (permalink / raw)
  To: Cédric Le Goater
  Cc: qemu-ppc, Greg Kurz, Suraj Jitindar Singh, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 11289 bytes --]

On Fri, Apr 03, 2020 at 04:00:53PM +0200, Cédric Le Goater wrote:
> This is moving code under a new ppc_radix64_xlate() routine shared by
> the MMU Radix page fault handler and the 'get_phys_page_debug' PPC
> callback. The difference being that 'get_phys_page_debug' does not
> generate exceptions.
> 
> The specific part of process-scoped Radix translation is moved under
> ppc_radix64_process_scoped_xlate() in preparation of the future support
> for partition-scoped Radix translation. Routines raising the exceptions
> now take a 'cause_excp' bool to cover the 'get_phys_page_debug' case.
> 
> It should be functionally equivalent.
> 
> Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Applied to ppc-for-5.1.

> ---
>  target/ppc/mmu-radix64.c | 219 ++++++++++++++++++++++-----------------
>  1 file changed, 123 insertions(+), 96 deletions(-)
> 
> diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
> index d2422d1c54c9..4b0d0ff50a3c 100644
> --- a/target/ppc/mmu-radix64.c
> +++ b/target/ppc/mmu-radix64.c
> @@ -219,17 +219,127 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
>      return true;
>  }
>  
> +static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
> +                                            vaddr eaddr, uint64_t pid,
> +                                            ppc_v3_pate_t pate, hwaddr *g_raddr,
> +                                            int *g_prot, int *g_page_size,
> +                                            bool cause_excp)
> +{
> +    CPUState *cs = CPU(cpu);
> +    uint64_t offset, size, prtbe_addr, prtbe0, pte;
> +    int fault_cause = 0;
> +    hwaddr pte_addr;
> +
> +    /* Index Process Table by PID to Find Corresponding Process Table Entry */
> +    offset = pid * sizeof(struct prtb_entry);
> +    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
> +    if (offset >= size) {
> +        /* offset exceeds size of the process table */
> +        if (cause_excp) {
> +            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
> +        }
> +        return 1;
> +    }
> +    prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
> +    prtbe0 = ldq_phys(cs->as, prtbe_addr);
> +
> +    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
> +    *g_page_size = PRTBE_R_GET_RTS(prtbe0);
> +    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
> +                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
> +                                g_raddr, g_page_size, &fault_cause, &pte_addr);
> +
> +    if (!(pte & R_PTE_VALID) ||
> +        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot)) {
> +        /* No valid pte or access denied due to protection */
> +        if (cause_excp) {
> +            ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> +        }
> +        return 1;
> +    }
> +
> +    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
> +
> +    return 0;
> +}
> +
> +static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
> +                             bool relocation,
> +                             hwaddr *raddr, int *psizep, int *protp,
> +                             bool cause_excp)
> +{
> +    uint64_t lpid = 0, pid = 0;
> +    ppc_v3_pate_t pate;
> +    int psize, prot;
> +    hwaddr g_raddr;
> +
> +    /* Virtual Mode Access - get the fully qualified address */
> +    if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
> +        if (cause_excp) {
> +            ppc_radix64_raise_segi(cpu, rwx, eaddr);
> +        }
> +        return 1;
> +    }
> +
> +    /* Get Process Table */
> +    if (cpu->vhyp) {
> +        PPCVirtualHypervisorClass *vhc;
> +        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> +        vhc->get_pate(cpu->vhyp, &pate);
> +    } else {
> +        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
> +            if (cause_excp) {
> +                ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
> +            }
> +            return 1;
> +        }
> +        if (!validate_pate(cpu, lpid, &pate)) {
> +            if (cause_excp) {
> +                ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
> +            }
> +            return 1;
> +        }
> +        /* We don't support guest mode yet */
> +        if (lpid != 0) {
> +            error_report("PowerNV guest support Unimplemented");
> +            exit(1);
> +        }
> +    }
> +
> +    *psizep = INT_MAX;
> +    *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> +
> +    /*
> +     * Perform process-scoped translation if relocation enabled.
> +     *
> +     * - Translates an effective address to a host real address in
> +     *   quadrants 0 and 3 when HV=1.
> +     */
> +    if (relocation) {
> +        int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
> +                                                   pate, &g_raddr, &prot,
> +                                                   &psize, cause_excp);
> +        if (ret) {
> +            return ret;
> +        }
> +        *psizep = MIN(*psizep, psize);
> +        *protp &= prot;
> +    } else {
> +        g_raddr = eaddr & R_EADDR_MASK;
> +    }
> +
> +    *raddr = g_raddr;
> +    return 0;
> +}
> +
>  int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>                                   int mmu_idx)
>  {
>      CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
> -    PPCVirtualHypervisorClass *vhc;
> -    hwaddr raddr, pte_addr;
> -    uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte;
> -    int page_size, prot, fault_cause = 0;
> -    ppc_v3_pate_t pate;
> +    int page_size, prot;
>      bool relocation;
> +    hwaddr raddr;
>  
>      assert(!(msr_hv && cpu->vhyp));
>      assert((rwx == 0) || (rwx == 1) || (rwx == 2));
> @@ -262,55 +372,12 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>                        TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
>      }
>  
> -    /* Virtual Mode Access - get the fully qualified address */
> -    if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) {
> -        ppc_radix64_raise_segi(cpu, rwx, eaddr);
> +    /* Translate eaddr to raddr (where raddr is addr qemu needs for access) */
> +    if (ppc_radix64_xlate(cpu, eaddr, rwx, relocation, &raddr,
> +                          &page_size, &prot, true)) {
>          return 1;
>      }
>  
> -    /* Get Process Table */
> -    if (cpu->vhyp) {
> -        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> -        vhc->get_pate(cpu->vhyp, &pate);
> -    } else {
> -        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
> -            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
> -            return 1;
> -        }
> -        if (!validate_pate(cpu, lpid, &pate)) {
> -            ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
> -        }
> -        /* We don't support guest mode yet */
> -        if (lpid != 0) {
> -            error_report("PowerNV guest support Unimplemented");
> -            exit(1);
> -       }
> -    }
> -
> -    /* Index Process Table by PID to Find Corresponding Process Table Entry */
> -    offset = pid * sizeof(struct prtb_entry);
> -    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
> -    if (offset >= size) {
> -        /* offset exceeds size of the process table */
> -        ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
> -        return 1;
> -    }
> -    prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset);
> -
> -    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
> -    page_size = PRTBE_R_GET_RTS(prtbe0);
> -    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
> -                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
> -                                &raddr, &page_size, &fault_cause, &pte_addr);
> -    if (!pte || ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, &prot)) {
> -        /* Couldn't get pte or access denied due to protection */
> -        ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> -        return 1;
> -    }
> -
> -    /* Update Reference and Change Bits */
> -    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, &prot);
> -
>      tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
>                   prot, mmu_idx, 1UL << page_size);
>      return 0;
> @@ -318,58 +385,18 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>  
>  hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr)
>  {
> -    CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
> -    PPCVirtualHypervisorClass *vhc;
> -    hwaddr raddr, pte_addr;
> -    uint64_t lpid = 0, pid = 0, offset, size, prtbe0, pte;
> -    int page_size, fault_cause = 0;
> -    ppc_v3_pate_t pate;
> +    int psize, prot;
> +    hwaddr raddr;
>  
>      /* Handle Real Mode */
> -    if (msr_dr == 0) {
> +    if ((msr_dr == 0) && (msr_hv || cpu->vhyp)) {
>          /* In real mode top 4 effective addr bits (mostly) ignored */
>          return eaddr & 0x0FFFFFFFFFFFFFFFULL;
>      }
>  
> -    /* Virtual Mode Access - get the fully qualified address */
> -    if (!ppc_radix64_get_fully_qualified_addr(env, eaddr, &lpid, &pid)) {
> -        return -1;
> -    }
> -
> -    /* Get Process Table */
> -    if (cpu->vhyp) {
> -        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> -        vhc->get_pate(cpu->vhyp, &pate);
> -    } else {
> -        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
> -            return -1;
> -        }
> -        if (!validate_pate(cpu, lpid, &pate)) {
> -            return -1;
> -        }
> -        /* We don't support guest mode yet */
> -        if (lpid != 0) {
> -            error_report("PowerNV guest support Unimplemented");
> -            exit(1);
> -       }
> -    }
> -
> -    /* Index Process Table by PID to Find Corresponding Process Table Entry */
> -    offset = pid * sizeof(struct prtb_entry);
> -    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
> -    if (offset >= size) {
> -        /* offset exceeds size of the process table */
> -        return -1;
> -    }
> -    prtbe0 = ldq_phys(cs->as, (pate.dw1 & PATE1_R_PRTB) + offset);
> -
> -    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
> -    page_size = PRTBE_R_GET_RTS(prtbe0);
> -    pte = ppc_radix64_walk_tree(cpu, eaddr & R_EADDR_MASK,
> -                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
> -                                &raddr, &page_size, &fault_cause, &pte_addr);
> -    if (!pte) {
> +    if (ppc_radix64_xlate(cpu, eaddr, 0, msr_dr, &raddr, &psize,
> +                          &prot, false)) {
>          return -1;
>      }
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 4/4] target/ppc: Add support for Radix partition-scoped translation
  2020-04-03 15:11   ` Greg Kurz
@ 2020-04-08  3:09     ` David Gibson
  2020-04-08  7:22       ` Cédric Le Goater
  0 siblings, 1 reply; 10+ messages in thread
From: David Gibson @ 2020-04-08  3:09 UTC (permalink / raw)
  To: Greg Kurz
  Cc: qemu-ppc, Cédric Le Goater, Suraj Jitindar Singh, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 17209 bytes --]

On Fri, Apr 03, 2020 at 05:11:29PM +0200, Greg Kurz wrote:
> On Fri,  3 Apr 2020 16:00:56 +0200
> Cédric Le Goater <clg@kaod.org> wrote:
> 
> > The Radix tree translation model currently supports process-scoped
> > translation for the PowerNV machine (Hypervisor mode) and for the
> > pSeries machine (Guest mode). Guests running under an emulated
> > Hypervisor (PowerNV machine) require a new type of Radix translation,
> > called partition-scoped, which is missing today.
> > 
> > The Radix tree translation is a 2 steps process. The first step,
> > process-scoped translation, converts an effective Address to a guest
> > real address, and the second step, partition-scoped translation,
> > converts a guest real address to a host real address.
> > 
> > There are difference cases to covers :
> > 
> > * Hypervisor real mode access: no Radix translation.
> > 
> > * Hypervisor or host application access (quadrant 0 and 3) with
> >   relocation on: process-scoped translation.
> > 
> > * Guest OS real mode access: only partition-scoped translation.
> > 
> > * Guest OS real or guest application access (quadrant 0 and 3) with
> >   relocation on: both process-scoped translation and partition-scoped
> >   translations.
> > 
> > * Hypervisor access in quadrant 1 and 2 with relocation on: both
> >   process-scoped translation and partition-scoped translations.
> > 
> > The radix tree partition-scoped translation is performed using tables
> > pointed to by the first double-word of the Partition Table Entries and
> > process-scoped translation uses tables pointed to by the Process Table
> > Entries (second double-word of the Partition Table Entries).
> > 
> > Both partition-scoped and process-scoped translations process are
> > identical and thus the radix tree traversing code is largely reused.
> > However, errors in partition-scoped translations generate hypervisor
> > exceptions.
> > 
> > Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> > Signed-off-by: Greg Kurz <groug@kaod.org>
> > Signed-off-by: Cédric Le Goater <clg@kaod.org>
> > ---
> >  target/ppc/cpu.h         |   3 +
> >  target/ppc/excp_helper.c |   3 +-
> >  target/ppc/mmu-radix64.c | 188 +++++++++++++++++++++++++++++++++++----
> >  3 files changed, 175 insertions(+), 19 deletions(-)
> > 
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index f4a5304d4356..6b6dd7e483f1 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -463,6 +463,9 @@ typedef struct ppc_v3_pate_t {
> >  #define DSISR_AMR                0x00200000
> >  /* Unsupported Radix Tree Configuration */
> >  #define DSISR_R_BADCONFIG        0x00080000
> > +#define DSISR_ATOMIC_RC          0x00040000
> > +/* Unable to translate address of (guest) pde or process/page table entry */
> > +#define DSISR_PRTABLE_FAULT      0x00020000
> >  
> >  /* SRR1 error code fields */
> >  
> > diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> > index 1acc3786de0e..f05297966472 100644
> > --- a/target/ppc/excp_helper.c
> > +++ b/target/ppc/excp_helper.c
> > @@ -506,9 +506,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
> >      case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
> >      case POWERPC_EXCP_TRACE:     /* Trace exception                          */
> >          break;
> > +    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
> > +        msr |= env->error_code;
> >      case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
> >      case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
> > -    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
> >      case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
> >      case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
> >      case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
> > diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
> > index 2400da41e06c..d473dc742e11 100644
> > --- a/target/ppc/mmu-radix64.c
> > +++ b/target/ppc/mmu-radix64.c
> > @@ -103,6 +103,27 @@ static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr,
> >      }
> >  }
> >  
> > +static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, int rwx, vaddr eaddr,
> > +                                  hwaddr g_raddr, uint32_t cause)
> > +{
> > +    CPUState *cs = CPU(cpu);
> > +    CPUPPCState *env = &cpu->env;
> > +
> > +    if (rwx == 2) { /* H Instruction Storage Interrupt */
> > +        cs->exception_index = POWERPC_EXCP_HISI;
> > +        env->spr[SPR_ASDR] = g_raddr;
> > +        env->error_code = cause;
> > +    } else { /* H Data Storage Interrupt */
> > +        cs->exception_index = POWERPC_EXCP_HDSI;
> > +        if (rwx == 1) { /* Write -> Store */
> > +            cause |= DSISR_ISSTORE;
> > +        }
> > +        env->spr[SPR_HDSISR] = cause;
> > +        env->spr[SPR_HDAR] = eaddr;
> > +        env->spr[SPR_ASDR] = g_raddr;
> > +        env->error_code = 0;
> > +    }
> > +}
> >  
> >  static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
> >                                     int *fault_cause, int *prot,
> > @@ -243,6 +264,37 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
> >      return true;
> >  }
> >  
> > +static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
> > +                                              vaddr eaddr, hwaddr g_raddr,
> > +                                              ppc_v3_pate_t pate,
> > +                                              hwaddr *h_raddr, int *h_prot,
> > +                                              int *h_page_size, bool pde_addr,
> > +                                              bool cause_excp)
> > +{
> > +    int fault_cause = 0;
> > +    hwaddr pte_addr;
> > +    uint64_t pte;
> > +
> > +    *h_page_size = PRTBE_R_GET_RTS(pate.dw0);
> > +    /* No valid pte or access denied due to protection */
> > +    if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
> > +                              pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
> > +                              &pte, &fault_cause, &pte_addr) ||
> > +        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) {
> > +        if (pde_addr) /* address being translated was that of a guest pde */
> > +            fault_cause |= DSISR_PRTABLE_FAULT;
> > +        if (cause_excp) {
> > +            ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause);
> > +        }
> > +        return 1;
> > +    }
> > +
> > +    /* Update Reference and Change Bits */
> > +    ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
> > +
> > +    return 0;
> > +}
> > +
> >  static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
> >                                              vaddr eaddr, uint64_t pid,
> >                                              ppc_v3_pate_t pate, hwaddr *g_raddr,
> > @@ -250,9 +302,10 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
> >                                              bool cause_excp)
> >  {
> >      CPUState *cs = CPU(cpu);
> > -    uint64_t offset, size, prtbe_addr, prtbe0, pte;
> > -    int fault_cause = 0;
> > -    hwaddr pte_addr;
> > +    CPUPPCState *env = &cpu->env;
> > +    uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
> > +    int fault_cause = 0, h_page_size, h_prot;
> > +    hwaddr h_raddr, pte_addr;
> >      int ret;
> >  
> >      /* Index Process Table by PID to Find Corresponding Process Table Entry */
> > @@ -266,18 +319,85 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
> >          return 1;
> >      }
> >      prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
> > -    prtbe0 = ldq_phys(cs->as, prtbe_addr);
> > +
> > +    if (cpu->vhyp) {
> > +        prtbe0 = ldq_phys(cs->as, prtbe_addr);
> > +    } else {
> > +        /*
> > +         * Process table addresses are subject to partition-scoped
> > +         * translation
> > +         *
> > +         * On a Radix host, the partition-scoped page table for LPID=0
> > +         * is only used to translate the effective addresses of the
> > +         * process table entries.
> > +         */
> > +        ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
> > +                                                 pate, &h_raddr, &h_prot,
> > +                                                 &h_page_size, 1, 1);
> > +        if (ret) {
> > +            return ret;
> > +        }
> > +        prtbe0 = ldq_phys(cs->as, h_raddr);
> > +    }
> >  
> >      /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
> >      *g_page_size = PRTBE_R_GET_RTS(prtbe0);
> > -    ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK,
> > -                                prtbe0 & PRTBE_R_RPDB, prtbe0 & PRTBE_R_RPDS,
> > -                                g_raddr, g_page_size, &pte, &fault_cause,
> > -                                &pte_addr);
> > -
> > -    if (ret ||
> > -        ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
> > -        /* No valid pte or access denied due to protection */
> > +    base_addr = prtbe0 & PRTBE_R_RPDB;
> > +    nls = prtbe0 & PRTBE_R_RPDS;
> > +    if (msr_hv || cpu->vhyp) {
> > +        /*
> > +         * Can treat process table addresses as real addresses
> > +         */
> > +        ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
> > +                                    nls, g_raddr, g_page_size, &pte,
> > +                                    &fault_cause, &pte_addr);
> > +        if (ret) {
> > +            /* No valid PTE */
> > +            if (cause_excp) {
> > +                ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> > +            }
> > +            return ret;
> > +        }
> > +    } else {
> > +        uint64_t rpn, mask;
> > +
> > +        index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
> > +        index &= ((1UL << nls) - 1);                            /* Mask */
> > +        pte_addr = base_addr + (index * sizeof(pte));
> > +
> > +        /*
> > +         * Each process table address is subject to a partition-scoped
> > +         * translation
> > +         */
> > +        do {
> > +            ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
> > +                                                     pate, &h_raddr, &h_prot,
> > +                                                     &h_page_size, 1, 1);
> > +            if (ret) {
> > +                return ret;
> > +            }
> > +
> > +            ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
> > +                                         &nls, g_page_size, &pte, &fault_cause);
> > +            if (ret) {
> > +                /* No valid pte */
> > +                if (cause_excp) {
> > +                    ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> > +                }
> > +                return ret;
> > +            }
> > +            pte_addr = h_raddr;
> > +        } while (!(pte & R_PTE_LEAF));
> > +
> > +        rpn = pte & R_PTE_RPN;
> > +        mask = (1UL << *g_page_size) - 1;
> > +
> > +        /* Or high bits of rpn and low bits to ea to form whole real addr */
> > +        *g_raddr = (rpn & ~mask) | (eaddr & mask);
> > +    }
> > +
> > +    if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
> > +        /* Access denied due to protection */
> >          if (cause_excp) {
> >              ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
> >          }
> > @@ -289,11 +409,29 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
> >      return 0;
> >  }
> >  
> > +/*
> > + * Radix tree translation is a 2 steps translation process:
> > + *
> > + * 1. Process-scoped translation:   Guest Eff Addr  -> Guest Real Addr
> > + * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
> > + *
> > + *                                  MSR[HV]
> > + *              +-------------+----------------+---------------+
> > + *              |             |     HV = 0     |     HV = 1    |
> > + *              +-------------+----------------+---------------+
> > + *              | Relocation  |    Partition   |      No       |
> > + *              | = Off       |     Scoped     |  Translation  |
> > + *  Relocation  +-------------+----------------+---------------+
> > + *              | Relocation  |   Partition &  |    Process    |
> > + *              | = On        | Process Scoped |    Scoped     |
> > + *              +-------------+----------------+---------------+
> > + */
> >  static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
> >                               bool relocation,
> >                               hwaddr *raddr, int *psizep, int *protp,
> >                               bool cause_excp)
> >  {
> > +    CPUPPCState *env = &cpu->env;
> >      uint64_t lpid = 0, pid = 0;
> >      ppc_v3_pate_t pate;
> >      int psize, prot;
> > @@ -325,11 +463,6 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
> >              }
> >              return 1;
> >          }
> > -        /* We don't support guest mode yet */
> > -        if (lpid != 0) {
> > -            error_report("PowerNV guest support Unimplemented");
> > -            exit(1);
> > -        }
> >      }
> >  
> >      *psizep = INT_MAX;
> > @@ -340,6 +473,8 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
> >       *
> >       * - Translates an effective address to a host real address in
> >       *   quadrants 0 and 3 when HV=1.
> > +     *
> > +     * - Translates an effective address to a guest real address.
> >       */
> >      if (relocation) {
> >          int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
> > @@ -354,7 +489,24 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
> >          g_raddr = eaddr & R_EADDR_MASK;
> >      }
> >  
> > -    *raddr = g_raddr;
> > +    /*
> > +     * Perform partition-scoped translation if !HV or HV access to
> > +     * quadrants 1 or 2. Translates a guest real address to a host
> > +     * real address.
> > +     */
> > +    if ((lpid != 0) || (!cpu->vhyp && !msr_hv)) {
> 
> This check is too complex for my taste. Also it doesn't seem right
> to look at lpid if the machine is pseries, even if it would happen
> to work because pseries cannot have lpid != 0. I think we should
> have distinct paths for powernv and pseries.
> 
> A bit like with the following squashed in:
> 
> =======================================
> --- a/target/ppc/mmu-radix64.c
> +++ b/target/ppc/mmu-radix64.c
> @@ -489,22 +489,28 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>          g_raddr = eaddr & R_EADDR_MASK;
>      }
>  
> -    /*
> -     * Perform partition-scoped translation if !HV or HV access to
> -     * quadrants 1 or 2. Translates a guest real address to a host
> -     * real address.
> -     */
> -    if ((lpid != 0) || (!cpu->vhyp && !msr_hv)) {
> -        int ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
> +    if (cpu->vhyp) {
> +        *raddr = g_raddr;
> +    } else {
> +        /*
> +         * Perform partition-scoped translation if !HV or HV access to
> +         * quadrants 1 or 2. Translates a guest real address to a host
> +         * real address.
> +         */
> +        if (lpid || !msr_hv) {
> +            int ret;
> +
> +            ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
>                                                       pate, raddr, &prot, &psize,
>                                                       0, cause_excp);
> -        if (ret) {
> -            return ret;
> +            if (ret) {
> +                return ret;
> +            }
> +            *psizep = MIN(*psizep, psize);
> +            *protp &= prot;
> +        } else {
> +            *raddr = g_raddr;
>          }
> -        *psizep = MIN(*psizep, psize);
> -        *protp &= prot;
> -    } else {
> -        *raddr = g_raddr;
>      }
>  
>      return 0;
> =======================================
> 
> David,
> 
> If my comment makes sense to you, can you squash the above fix into
> Cedric's patch ?

Yes.  I also think we shouldn't be looking at lpid for the vhyp case.
I've applied the rest of the series to ppc-for-5.1, and folded in this
correction as suggested.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 4/4] target/ppc: Add support for Radix partition-scoped translation
  2020-04-08  3:09     ` David Gibson
@ 2020-04-08  7:22       ` Cédric Le Goater
  0 siblings, 0 replies; 10+ messages in thread
From: Cédric Le Goater @ 2020-04-08  7:22 UTC (permalink / raw)
  To: David Gibson, Greg Kurz; +Cc: qemu-ppc, qemu-devel, Suraj Jitindar Singh

>>> -    *raddr = g_raddr;
>>> +    /*
>>> +     * Perform partition-scoped translation if !HV or HV access to
>>> +     * quadrants 1 or 2. Translates a guest real address to a host
>>> +     * real address.
>>> +     */
>>> +    if ((lpid != 0) || (!cpu->vhyp && !msr_hv)) {
>>
>> This check is too complex for my taste. Also it doesn't seem right
>> to look at lpid if the machine is pseries, even if it would happen
>> to work because pseries cannot have lpid != 0. I think we should
>> have distinct paths for powernv and pseries.
>>
>> A bit like with the following squashed in:
>>
>> =======================================
>> --- a/target/ppc/mmu-radix64.c
>> +++ b/target/ppc/mmu-radix64.c
>> @@ -489,22 +489,28 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
>>          g_raddr = eaddr & R_EADDR_MASK;
>>      }
>>  
>> -    /*
>> -     * Perform partition-scoped translation if !HV or HV access to
>> -     * quadrants 1 or 2. Translates a guest real address to a host
>> -     * real address.
>> -     */
>> -    if ((lpid != 0) || (!cpu->vhyp && !msr_hv)) {
>> -        int ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
>> +    if (cpu->vhyp) {
>> +        *raddr = g_raddr;
>> +    } else {
>> +        /*
>> +         * Perform partition-scoped translation if !HV or HV access to
>> +         * quadrants 1 or 2. Translates a guest real address to a host
>> +         * real address.
>> +         */
>> +        if (lpid || !msr_hv) {
>> +            int ret;
>> +
>> +            ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
>>                                                       pate, raddr, &prot, &psize,
>>                                                       0, cause_excp);
>> -        if (ret) {
>> -            return ret;
>> +            if (ret) {
>> +                return ret;
>> +            }
>> +            *psizep = MIN(*psizep, psize);
>> +            *protp &= prot;
>> +        } else {
>> +            *raddr = g_raddr;
>>          }
>> -        *psizep = MIN(*psizep, psize);
>> -        *protp &= prot;
>> -    } else {
>> -        *raddr = g_raddr;
>>      }
>>  
>>      return 0;
>> =======================================
>>
>> David,
>>
>> If my comment makes sense to you, can you squash the above fix into
>> Cedric's patch ?
> 
> Yes.  I also think we shouldn't be looking at lpid for the vhyp case.
> I've applied the rest of the series to ppc-for-5.1, and folded in this
> correction as suggested.


I explored a solution with two ppc_radix64_xlate() routines, one simple 
for pseries, a second more complex for powernv but it didn't look very
good. May be it will be easier now that the first patches are merged. 

Thanks,

C. 




^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-04-08  7:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-03 14:00 [PATCH v4 0/4] target/ppc: Add support for Radix partition-scoped translation Cédric Le Goater
2020-04-03 14:00 ` [PATCH v4 1/4] target/ppc: Introduce ppc_radix64_xlate() for Radix tree translation Cédric Le Goater
2020-04-03 14:56   ` Greg Kurz
2020-04-08  2:57   ` David Gibson
2020-04-03 14:00 ` [PATCH v4 2/4] target/ppc: Extend ppc_radix64_check_prot() with a 'partition_scoped' bool Cédric Le Goater
2020-04-03 14:00 ` [PATCH v4 3/4] target/ppc: Rework ppc_radix64_walk_tree() for partition-scoped translation Cédric Le Goater
2020-04-03 14:00 ` [PATCH v4 4/4] target/ppc: Add support for Radix " Cédric Le Goater
2020-04-03 15:11   ` Greg Kurz
2020-04-08  3:09     ` David Gibson
2020-04-08  7:22       ` Cédric Le Goater

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.