All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/6] Cleanups to handling of hash MMU
@ 2017-02-23  2:09 David Gibson
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 1/6] pseries: Minor cleanups to HPT management hypercalls David Gibson
                   ` (5 more replies)
  0 siblings, 6 replies; 22+ messages in thread
From: David Gibson @ 2017-02-23  2:09 UTC (permalink / raw)
  To: qemu-ppc, aik, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus, David Gibson

This series has an assortment of cleanups to the handling of the hash
based MMU for 64-bit ppc machines.  In particular it better handles
the case of "external" hash table - this is used on the pseries
machine type, which being a paravirtualized platform has the hashed
page table - along with other hypervisor resources - outside the
direct reach of the guest OS.  This series integrates the handling of
the external HPT with the externalized handling of hypercalls via the
"virtual hypervisor" mechanism.

These cleanups are expected to make integrating the new MMU model for
POWER9 easier; in particular dealing with both the new POWER9 radix
MMU and also the POWER9 legacy hash compatibility mode.

This series is based on my current ppc-for-2.9 branch, which I've just
sent a pull request for.

David Gibson (6):
  pseries: Minor cleanups to HPT management hypercalls
  target/ppc: Merge cpu_ppc_set_vhyp() with cpu_ppc_set_papr()
  target/ppc: SDR1 is a hypervisor resource
  target/ppc: Cleanup HPTE accessors for 64-bit hash MMU
  target/ppc: Eliminate htab_base and htab_mask variables
  target/ppc: Manage external HPT via virtual hypervisor

 hw/ppc/spapr.c              |  58 +++++++++++++++
 hw/ppc/spapr_cpu_core.c     |  20 ++++-
 hw/ppc/spapr_hcall.c        |  89 +++++++++++-----------
 target/ppc/cpu.h            |  24 +++---
 target/ppc/kvm.c            |  27 +++----
 target/ppc/kvm_ppc.h        |  43 +++++------
 target/ppc/machine.c        |   5 +-
 target/ppc/misc_helper.c    |   8 +-
 target/ppc/mmu-hash32.c     |  14 ++--
 target/ppc/mmu-hash32.h     |  32 ++++----
 target/ppc/mmu-hash64.c     | 177 ++++++++++++++++++--------------------------
 target/ppc/mmu-hash64.h     |  66 +++++++++--------
 target/ppc/mmu_helper.c     |  34 +++++----
 target/ppc/translate_init.c |  30 +++++---
 14 files changed, 332 insertions(+), 295 deletions(-)

-- 
2.9.3

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

* [Qemu-devel] [PATCH 1/6] pseries: Minor cleanups to HPT management hypercalls
  2017-02-23  2:09 [Qemu-devel] [PATCH 0/6] Cleanups to handling of hash MMU David Gibson
@ 2017-02-23  2:09 ` David Gibson
  2017-02-23  4:08   ` Suraj Jitindar Singh
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 2/6] target/ppc: Merge cpu_ppc_set_vhyp() with cpu_ppc_set_papr() David Gibson
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 22+ messages in thread
From: David Gibson @ 2017-02-23  2:09 UTC (permalink / raw)
  To: qemu-ppc, aik, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus, David Gibson

 * Standardize on 'ptex' instead of 'pte_index' for HPTE index variables
   for consistency and brevity
 * Avoid variables named 'index'; shadowing index(3) from libc can lead to
   surprising bugs if the variable is removed, because compiler errors
   might not appear for remaining references
 * Clarify index calculations in h_enter() - we have two cases, H_EXACT
   where the exact HPTE slot is given, and !H_EXACT where we search for
   an empty slot within the hash bucket.  Make the calculation more
   consistent between the cases.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_hcall.c | 58 +++++++++++++++++++++++++---------------------------
 1 file changed, 28 insertions(+), 30 deletions(-)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 42d20e0..3298a14 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -47,12 +47,12 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
     return cpu->env.spr_cb[spr].name != NULL;
 }
 
-static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
+static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
 {
     /*
      * hash value/pteg group index is normalized by htab_mask
      */
-    if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
+    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) {
         return false;
     }
     return true;
@@ -77,14 +77,13 @@ static bool is_ram_address(sPAPRMachineState *spapr, hwaddr addr)
 static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
                             target_ulong opcode, target_ulong *args)
 {
-    CPUPPCState *env = &cpu->env;
     target_ulong flags = args[0];
-    target_ulong pte_index = args[1];
+    target_ulong ptex = args[1];
     target_ulong pteh = args[2];
     target_ulong ptel = args[3];
     unsigned apshift;
     target_ulong raddr;
-    target_ulong index;
+    target_ulong slot;
     uint64_t token;
 
     apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
@@ -116,25 +115,26 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 
     pteh &= ~0x60ULL;
 
-    if (!valid_pte_index(env, pte_index)) {
+    if (!valid_ptex(cpu, ptex)) {
         return H_PARAMETER;
     }
 
-    index = 0;
+    slot = ptex & 7ULL;
+    ptex = ptex & ~7ULL;
+
     if (likely((flags & H_EXACT) == 0)) {
-        pte_index &= ~7ULL;
-        token = ppc_hash64_start_access(cpu, pte_index);
-        for (; index < 8; index++) {
-            if (!(ppc_hash64_load_hpte0(cpu, token, index) & HPTE64_V_VALID)) {
+        token = ppc_hash64_start_access(cpu, ptex);
+        for (slot = 0; slot < 8; slot++) {
+            if (!(ppc_hash64_load_hpte0(cpu, token, slot) & HPTE64_V_VALID)) {
                 break;
             }
         }
         ppc_hash64_stop_access(cpu, token);
-        if (index == 8) {
+        if (slot == 8) {
             return H_PTEG_FULL;
         }
     } else {
-        token = ppc_hash64_start_access(cpu, pte_index);
+        token = ppc_hash64_start_access(cpu, ptex);
         if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
             ppc_hash64_stop_access(cpu, token);
             return H_PTEG_FULL;
@@ -142,10 +142,9 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
         ppc_hash64_stop_access(cpu, token);
     }
 
-    ppc_hash64_store_hpte(cpu, pte_index + index,
-                          pteh | HPTE64_V_HPTE_DIRTY, ptel);
+    ppc_hash64_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
 
-    args[0] = pte_index + index;
+    args[0] = ptex + slot;
     return H_SUCCESS;
 }
 
@@ -161,11 +160,10 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
                                 target_ulong flags,
                                 target_ulong *vp, target_ulong *rp)
 {
-    CPUPPCState *env = &cpu->env;
     uint64_t token;
     target_ulong v, r;
 
-    if (!valid_pte_index(env, ptex)) {
+    if (!valid_ptex(cpu, ptex)) {
         return REMOVE_PARM;
     }
 
@@ -191,11 +189,11 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 {
     CPUPPCState *env = &cpu->env;
     target_ulong flags = args[0];
-    target_ulong pte_index = args[1];
+    target_ulong ptex = args[1];
     target_ulong avpn = args[2];
     RemoveResult ret;
 
-    ret = remove_hpte(cpu, pte_index, avpn, flags,
+    ret = remove_hpte(cpu, ptex, avpn, flags,
                       &args[0], &args[1]);
 
     switch (ret) {
@@ -291,16 +289,16 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 {
     CPUPPCState *env = &cpu->env;
     target_ulong flags = args[0];
-    target_ulong pte_index = args[1];
+    target_ulong ptex = args[1];
     target_ulong avpn = args[2];
     uint64_t token;
     target_ulong v, r;
 
-    if (!valid_pte_index(env, pte_index)) {
+    if (!valid_ptex(cpu, ptex)) {
         return H_PARAMETER;
     }
 
-    token = ppc_hash64_start_access(cpu, pte_index);
+    token = ppc_hash64_start_access(cpu, ptex);
     v = ppc_hash64_load_hpte0(cpu, token, 0);
     r = ppc_hash64_load_hpte1(cpu, token, 0);
     ppc_hash64_stop_access(cpu, token);
@@ -315,13 +313,13 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     r |= (flags << 55) & HPTE64_R_PP0;
     r |= (flags << 48) & HPTE64_R_KEY_HI;
     r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
-    ppc_hash64_store_hpte(cpu, pte_index,
+    ppc_hash64_store_hpte(cpu, ptex,
                           (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
-    ppc_hash64_tlb_flush_hpte(cpu, pte_index, v, r);
+    ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
     /* Flush the tlb */
     check_tlb_flush(env, true);
     /* Don't need a memory barrier, due to qemu's global lock */
-    ppc_hash64_store_hpte(cpu, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
+    ppc_hash64_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
     return H_SUCCESS;
 }
 
@@ -330,21 +328,21 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 {
     CPUPPCState *env = &cpu->env;
     target_ulong flags = args[0];
-    target_ulong pte_index = args[1];
+    target_ulong ptex = args[1];
     uint8_t *hpte;
     int i, ridx, n_entries = 1;
 
-    if (!valid_pte_index(env, pte_index)) {
+    if (!valid_ptex(cpu, ptex)) {
         return H_PARAMETER;
     }
 
     if (flags & H_READ_4) {
         /* Clear the two low order bits */
-        pte_index &= ~(3ULL);
+        ptex &= ~(3ULL);
         n_entries = 4;
     }
 
-    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+    hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
 
     for (i = 0, ridx = 0; i < n_entries; i++) {
         args[ridx++] = ldq_p(hpte);
-- 
2.9.3

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

* [Qemu-devel] [PATCH 2/6] target/ppc: Merge cpu_ppc_set_vhyp() with cpu_ppc_set_papr()
  2017-02-23  2:09 [Qemu-devel] [PATCH 0/6] Cleanups to handling of hash MMU David Gibson
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 1/6] pseries: Minor cleanups to HPT management hypercalls David Gibson
@ 2017-02-23  2:09 ` David Gibson
  2017-02-23  4:27   ` Suraj Jitindar Singh
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 3/6] target/ppc: SDR1 is a hypervisor resource David Gibson
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 22+ messages in thread
From: David Gibson @ 2017-02-23  2:09 UTC (permalink / raw)
  To: qemu-ppc, aik, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus, David Gibson

cpu_ppc_set_papr() sets up various aspects of CPU state for use with PAPR
paravirtualized guests.  However, it doesn't set the virtual hypervisor,
so callers must also call cpu_ppc_set_vhyp() so that PAPR hypercalls are
handled properly.  This is a bit silly, so fold setting the virtual
hypervisor into cpu_ppc_set_papr().

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_cpu_core.c     |  3 +--
 target/ppc/cpu.h            |  3 +--
 target/ppc/translate_init.c | 10 +++-------
 3 files changed, 5 insertions(+), 11 deletions(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 55cd045..76563c4 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -57,8 +57,7 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
     cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ);
 
     /* Enable PAPR mode in TCG or KVM */
-    cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
-    cpu_ppc_set_papr(cpu);
+    cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
 
     if (cpu->max_compat) {
         Error *local_err = NULL;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 425e79d..f99bcae 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1300,8 +1300,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val);
 void store_booke_tsr (CPUPPCState *env, target_ulong val);
 void ppc_tlb_invalidate_all (CPUPPCState *env);
 void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
-void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
-void cpu_ppc_set_papr(PowerPCCPU *cpu);
+void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
 #endif
 #endif
 
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index be35cbd..a1405e9 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -8835,18 +8835,14 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 }
 
 #if !defined(CONFIG_USER_ONLY)
-
-void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
-{
-    cpu->vhyp = vhyp;
-}
-
-void cpu_ppc_set_papr(PowerPCCPU *cpu)
+void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
 {
     CPUPPCState *env = &cpu->env;
     ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR];
     ppc_spr_t *amor = &env->spr_cb[SPR_AMOR];
 
+    cpu->vhyp = vhyp;
+
     /* PAPR always has exception vectors in RAM not ROM. To ensure this,
      * MSR[IP] should never be set.
      *
-- 
2.9.3

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

* [Qemu-devel] [PATCH 3/6] target/ppc: SDR1 is a hypervisor resource
  2017-02-23  2:09 [Qemu-devel] [PATCH 0/6] Cleanups to handling of hash MMU David Gibson
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 1/6] pseries: Minor cleanups to HPT management hypercalls David Gibson
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 2/6] target/ppc: Merge cpu_ppc_set_vhyp() with cpu_ppc_set_papr() David Gibson
@ 2017-02-23  2:09 ` David Gibson
  2017-02-23  4:32   ` Suraj Jitindar Singh
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU David Gibson
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 22+ messages in thread
From: David Gibson @ 2017-02-23  2:09 UTC (permalink / raw)
  To: qemu-ppc, aik, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus, David Gibson

At present the SDR1 register - the base of the system's hashed page table
(HPT) - is represented as an SPR with supervisor read and write permission.
However, on CPUs which have a hypervisor mode, the SDR1 is a hypervisor
only resource.  Change the permission checking on the SPR to reflect this.

Now that this is done, we don't need to check for an external HPT executing
mtsdr1: an external HPT only applies when we're emulating the behaviour of
a hypervisor, rather than modelling the CPU's hypervisor mode internally,
so if we're permitted to execute mtsdr1, we don't have an external HPT.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target/ppc/misc_helper.c    |  8 +++-----
 target/ppc/translate_init.c | 20 ++++++++++++++++----
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index ab432ba..fa573dd 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -82,11 +82,9 @@ void helper_store_sdr1(CPUPPCState *env, target_ulong val)
 {
     PowerPCCPU *cpu = ppc_env_get_cpu(env);
 
-    if (!env->external_htab) {
-        if (env->spr[SPR_SDR1] != val) {
-            ppc_store_sdr1(env, val);
-            tlb_flush(CPU(cpu));
-        }
+    if (env->spr[SPR_SDR1] != val) {
+        ppc_store_sdr1(env, val);
+        tlb_flush(CPU(cpu));
     }
 }
 
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index a1405e9..c92435d 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -740,10 +740,22 @@ static void gen_spr_ne_601 (CPUPPCState *env)
                  &spr_read_decr, &spr_write_decr,
                  0x00000000);
     /* Memory management */
-    spr_register(env, SPR_SDR1, "SDR1",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_sdr1,
-                 0x00000000);
+#ifndef CONFIG_USER_ONLY
+    if (env->has_hv_mode) {
+        /* SDR1 is a hypervisor resource on CPUs which have a
+         * hypervisor mode */
+        spr_register_hv(env, SPR_SDR1, "SDR1",
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        SPR_NOACCESS, SPR_NOACCESS,
+                        &spr_read_generic, &spr_write_sdr1,
+                        0x00000000);
+    } else {
+        spr_register(env, SPR_SDR1, "SDR1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_sdr1,
+                     0x00000000);
+    }
+#endif
 }
 
 /* BATs 0-3 */
-- 
2.9.3

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

* [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU
  2017-02-23  2:09 [Qemu-devel] [PATCH 0/6] Cleanups to handling of hash MMU David Gibson
                   ` (2 preceding siblings ...)
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 3/6] target/ppc: SDR1 is a hypervisor resource David Gibson
@ 2017-02-23  2:09 ` David Gibson
  2017-02-23  5:02   ` Alexey Kardashevskiy
  2017-02-23  5:37   ` Suraj Jitindar Singh
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables David Gibson
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 6/6] target/ppc: Manage external HPT via virtual hypervisor David Gibson
  5 siblings, 2 replies; 22+ messages in thread
From: David Gibson @ 2017-02-23  2:09 UTC (permalink / raw)
  To: qemu-ppc, aik, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus, David Gibson

Accesses to the hashed page table (HPT) are complicated by the fact that
the HPT could be in one of three places:
   1) Within guest memory - when we're emulating a full guest CPU at the
      hardware level (e.g. powernv, mac99, g3beige)
   2) Within qemu, but outside guest memory - when we're emulating user and
      supervisor instructions within TCG, but instead of emulating
      the CPU's hypervisor mode, we just emulate a hypervisor's behaviour
      (pseries in TCG)
   3) Within KVM - a pseries machine using KVM acceleration.  Mostly
      accesses to the HPT are handled by KVM, but there are a few cases
      where qemu needs to access it via a special fd for the purpose.

In order to batch accesses to the fd in case (3), we use a somewhat awkward
ppc_hash64_start_access() / ppc_hash64_stop_access() pair, which for case
(3) reads / releases a whole PTEG from the kernel.  For cases (1) & (2)
it just returns an address value.  The actual HPTE load helpers then need
to interpret the returned token differently in the 3 cases.

This patch keeps the same basic structure, but simplfiies the details.
First start_access() / stop_access() are renamed to get_pteg() and
put_pteg() to make their operation more obvious.  Second, read_pteg() now
always returns a qemu pointer, which can always be used in the same way
by the load_hpte() helpers.  In case (1) it comes from address_space_map()
in case (2) directly from qemu's HPT buffer and in case (3) from a
temporary buffer read from the KVM fd.

While we're at it, make things a bit more consistent in terms of types and
variable names: avoid variables named 'index' (it shadows index(3) which
can lead to confusing results), use 'hwaddr ptex' for HPTE indices and
uint64_t for each of the HPTE words, use ptex throughout the call stack
instead of pte_offset in some places (we still need that at the bottom
layer, but nowhere else).

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_hcall.c    | 36 +++++++++---------
 target/ppc/cpu.h        |  3 +-
 target/ppc/kvm.c        | 25 ++++++-------
 target/ppc/kvm_ppc.h    | 43 ++++++++++------------
 target/ppc/mmu-hash64.c | 98 ++++++++++++++++++++++++++-----------------------
 target/ppc/mmu-hash64.h | 46 ++++++++---------------
 6 files changed, 119 insertions(+), 132 deletions(-)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 3298a14..fd961b5 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -84,7 +84,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     unsigned apshift;
     target_ulong raddr;
     target_ulong slot;
-    uint64_t token;
+    const ppc_hash_pte64_t *hptes;
 
     apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
     if (!apshift) {
@@ -123,23 +123,23 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     ptex = ptex & ~7ULL;
 
     if (likely((flags & H_EXACT) == 0)) {
-        token = ppc_hash64_start_access(cpu, ptex);
+        hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
         for (slot = 0; slot < 8; slot++) {
-            if (!(ppc_hash64_load_hpte0(cpu, token, slot) & HPTE64_V_VALID)) {
+            if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
                 break;
             }
         }
-        ppc_hash64_stop_access(cpu, token);
+        ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
         if (slot == 8) {
             return H_PTEG_FULL;
         }
     } else {
-        token = ppc_hash64_start_access(cpu, ptex);
-        if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
-            ppc_hash64_stop_access(cpu, token);
+        hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
+        if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
+            ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
             return H_PTEG_FULL;
         }
-        ppc_hash64_stop_access(cpu, token);
+        ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
     }
 
     ppc_hash64_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
@@ -160,17 +160,17 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
                                 target_ulong flags,
                                 target_ulong *vp, target_ulong *rp)
 {
-    uint64_t token;
+    const ppc_hash_pte64_t *hptes;
     target_ulong v, r;
 
     if (!valid_ptex(cpu, ptex)) {
         return REMOVE_PARM;
     }
 
-    token = ppc_hash64_start_access(cpu, ptex);
-    v = ppc_hash64_load_hpte0(cpu, token, 0);
-    r = ppc_hash64_load_hpte1(cpu, token, 0);
-    ppc_hash64_stop_access(cpu, token);
+    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
+    v = ppc_hash64_hpte0(cpu, hptes, 0);
+    r = ppc_hash64_hpte1(cpu, hptes, 0);
+    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
 
     if ((v & HPTE64_V_VALID) == 0 ||
         ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
@@ -291,17 +291,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     target_ulong flags = args[0];
     target_ulong ptex = args[1];
     target_ulong avpn = args[2];
-    uint64_t token;
+    const ppc_hash_pte64_t *hptes;
     target_ulong v, r;
 
     if (!valid_ptex(cpu, ptex)) {
         return H_PARAMETER;
     }
 
-    token = ppc_hash64_start_access(cpu, ptex);
-    v = ppc_hash64_load_hpte0(cpu, token, 0);
-    r = ppc_hash64_load_hpte1(cpu, token, 0);
-    ppc_hash64_stop_access(cpu, token);
+    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
+    v = ppc_hash64_hpte0(cpu, hptes, 0);
+    r = ppc_hash64_hpte1(cpu, hptes, 0);
+    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
 
     if ((v & HPTE64_V_VALID) == 0 ||
         ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index f99bcae..c89973e 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -223,11 +223,12 @@ enum {
 typedef struct opc_handler_t opc_handler_t;
 
 /*****************************************************************************/
-/* Types used to describe some PowerPC registers */
+/* Types used to describe some PowerPC registers etc. */
 typedef struct DisasContext DisasContext;
 typedef struct ppc_spr_t ppc_spr_t;
 typedef union ppc_avr_t ppc_avr_t;
 typedef union ppc_tlb_t ppc_tlb_t;
+typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
 
 /* SPR access micro-ops generations callbacks */
 struct ppc_spr_t {
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 52bbea5..9d3e57e 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2601,17 +2601,17 @@ struct kvm_get_htab_buf {
     /*
      * We require one extra byte for read
      */
-    target_ulong hpte[(HPTES_PER_GROUP * 2) + 1];
+    ppc_hash_pte64_t hpte[HPTES_PER_GROUP];
 };
 
-uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
+const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)
 {
     int htab_fd;
     struct kvm_get_htab_fd ghf;
-    struct kvm_get_htab_buf  *hpte_buf;
+    struct kvm_get_htab_buf *hpte_buf;
 
     ghf.flags = 0;
-    ghf.start_index = pte_index;
+    ghf.start_index = ptex;
     htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
     if (htab_fd < 0) {
         goto error_out;
@@ -2626,7 +2626,7 @@ uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
     }
 
     close(htab_fd);
-    return (uint64_t)(uintptr_t) hpte_buf->hpte;
+    return hpte_buf->hpte;
 
 out_close:
     g_free(hpte_buf);
@@ -2635,18 +2635,15 @@ error_out:
     return 0;
 }
 
-void kvmppc_hash64_free_pteg(uint64_t token)
+void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex, int n)
 {
     struct kvm_get_htab_buf *htab_buf;
 
-    htab_buf = container_of((void *)(uintptr_t) token, struct kvm_get_htab_buf,
-                            hpte);
+    htab_buf = container_of((void *)hptes, struct kvm_get_htab_buf, hpte);
     g_free(htab_buf);
-    return;
 }
 
-void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
-                             target_ulong pte0, target_ulong pte1)
+void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t pte1)
 {
     int htab_fd;
     struct kvm_get_htab_fd ghf;
@@ -2661,9 +2658,9 @@ void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
 
     hpte_buf.header.n_valid = 1;
     hpte_buf.header.n_invalid = 0;
-    hpte_buf.header.index = pte_index;
-    hpte_buf.hpte[0] = pte0;
-    hpte_buf.hpte[1] = pte1;
+    hpte_buf.header.index = ptex;
+    hpte_buf.hpte[0].pte0 = pte0;
+    hpte_buf.hpte[0].pte1 = pte1;
     /*
      * Write the hpte entry.
      * CAUTION: write() has the warn_unused_result attribute. Hence we
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 8da2ee4..3f8fccd 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -41,6 +41,10 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd,
 int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
 int kvmppc_reset_htab(int shift_hint);
 uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
+const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n);
+void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex, int n);
+
+void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t pte1);
 #endif /* !CONFIG_USER_ONLY */
 bool kvmppc_has_cap_epr(void);
 int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function);
@@ -49,11 +53,6 @@ int kvmppc_get_htab_fd(bool write);
 int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns);
 int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
                            uint16_t n_valid, uint16_t n_invalid);
-uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index);
-void kvmppc_hash64_free_pteg(uint64_t token);
-
-void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
-                             target_ulong pte0, target_ulong pte1);
 bool kvmppc_has_cap_fixup_hcalls(void);
 bool kvmppc_has_cap_htm(void);
 int kvmppc_enable_hwrng(void);
@@ -199,6 +198,22 @@ static inline bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
     return true;
 }
 
+static inline const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)
+{
+    abort();
+}
+
+static inline void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes,
+                                      hwaddr ptex, int n)
+{
+    abort();
+}
+
+static inline void kvmppc_hash64_write_pte(hwaddr ptex,
+                                           uint64_t pte0, uint64_t pte1)
+{
+    abort();
+}
 #endif /* !CONFIG_USER_ONLY */
 
 static inline bool kvmppc_has_cap_epr(void)
@@ -234,24 +249,6 @@ static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
     abort();
 }
 
-static inline uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu,
-                                               target_ulong pte_index)
-{
-    abort();
-}
-
-static inline void kvmppc_hash64_free_pteg(uint64_t token)
-{
-    abort();
-}
-
-static inline void kvmppc_hash64_write_pte(CPUPPCState *env,
-                                           target_ulong pte_index,
-                                           target_ulong pte0, target_ulong pte1)
-{
-    abort();
-}
-
 static inline bool kvmppc_has_cap_fixup_hcalls(void)
 {
     abort();
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index 76669ed..c59db47 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -27,6 +27,7 @@
 #include "kvm_ppc.h"
 #include "mmu-hash64.h"
 #include "exec/log.h"
+#include "hw/hw.h"
 
 //#define DEBUG_SLB
 
@@ -431,33 +432,42 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
     return prot;
 }
 
-uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
+const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
+                                             hwaddr ptex, int n)
 {
-    uint64_t token = 0;
-    hwaddr pte_offset;
+    const ppc_hash_pte64_t *hptes = NULL;
+    hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
 
-    pte_offset = pte_index * HASH_PTE_SIZE_64;
     if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
         /*
          * HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
          */
-        token = kvmppc_hash64_read_pteg(cpu, pte_index);
+        hptes = kvmppc_map_hptes(ptex, n);
     } else if (cpu->env.external_htab) {
         /*
          * HTAB is controlled by QEMU. Just point to the internally
          * accessible PTEG.
          */
-        token = (uint64_t)(uintptr_t) cpu->env.external_htab + pte_offset;
+        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
     } else if (cpu->env.htab_base) {
-        token = cpu->env.htab_base + pte_offset;
+        hwaddr plen = n * HASH_PTE_SIZE_64;
+        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base + pte_offset,
+                                 &plen, false);
+        if (plen < (n * HASH_PTE_SIZE_64)) {
+            hw_error("%s: Unable to map all requested HPTEs\n", __FUNCTION__);
+        }
     }
-    return token;
+    return hptes;
 }
 
-void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token)
+void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
+                            hwaddr ptex, int n)
 {
     if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
-        kvmppc_hash64_free_pteg(token);
+        kvmppc_unmap_hptes(hptes, ptex, n);
+    } else if (!cpu->env.external_htab) {
+        address_space_unmap(CPU(cpu)->as, (void *)hptes, n * HASH_PTE_SIZE_64,
+                            false, n * HASH_PTE_SIZE_64);
     }
 }
 
@@ -505,18 +515,18 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
 {
     CPUPPCState *env = &cpu->env;
     int i;
-    uint64_t token;
+    const ppc_hash_pte64_t *pteg;
     target_ulong pte0, pte1;
-    target_ulong pte_index;
+    target_ulong ptex;
 
-    pte_index = (hash & env->htab_mask) * HPTES_PER_GROUP;
-    token = ppc_hash64_start_access(cpu, pte_index);
-    if (!token) {
+    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
+    pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
+    if (!pteg) {
         return -1;
     }
     for (i = 0; i < HPTES_PER_GROUP; i++) {
-        pte0 = ppc_hash64_load_hpte0(cpu, token, i);
-        pte1 = ppc_hash64_load_hpte1(cpu, token, i);
+        pte0 = ppc_hash64_hpte0(cpu, pteg, i);
+        pte1 = ppc_hash64_hpte1(cpu, pteg, i);
 
         /* This compares V, B, H (secondary) and the AVPN */
         if (HPTE64_V_COMPARE(pte0, ptem)) {
@@ -536,11 +546,11 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
              */
             pte->pte0 = pte0;
             pte->pte1 = pte1;
-            ppc_hash64_stop_access(cpu, token);
-            return (pte_index + i) * HASH_PTE_SIZE_64;
+            ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
+            return ptex + i;
         }
     }
-    ppc_hash64_stop_access(cpu, token);
+    ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
     /*
      * We didn't find a valid entry.
      */
@@ -552,8 +562,7 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
                                      ppc_hash_pte64_t *pte, unsigned *pshift)
 {
     CPUPPCState *env = &cpu->env;
-    hwaddr pte_offset;
-    hwaddr hash;
+    hwaddr hash, ptex;
     uint64_t vsid, epnmask, epn, ptem;
     const struct ppc_one_seg_page_size *sps = slb->sps;
 
@@ -596,9 +605,9 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
             " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
             " hash=" TARGET_FMT_plx "\n",
             env->htab_base, env->htab_mask, vsid, ptem,  hash);
-    pte_offset = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
+    ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
 
-    if (pte_offset == -1) {
+    if (ptex == -1) {
         /* Secondary PTEG lookup */
         ptem |= HPTE64_V_SECONDARY;
         qemu_log_mask(CPU_LOG_MMU,
@@ -607,10 +616,10 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
                 " hash=" TARGET_FMT_plx "\n", env->htab_base,
                 env->htab_mask, vsid, ptem, ~hash);
 
-        pte_offset = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
+        ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
     }
 
-    return pte_offset;
+    return ptex;
 }
 
 unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
@@ -708,7 +717,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
     CPUPPCState *env = &cpu->env;
     ppc_slb_t *slb;
     unsigned apshift;
-    hwaddr pte_offset;
+    hwaddr ptex;
     ppc_hash_pte64_t pte;
     int pp_prot, amr_prot, prot;
     uint64_t new_pte1, dsisr;
@@ -792,8 +801,8 @@ skip_slb_search:
     }
 
     /* 4. Locate the PTE in the hash table */
-    pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
-    if (pte_offset == -1) {
+    ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
+    if (ptex == -1) {
         dsisr = 0x40000000;
         if (rwx == 2) {
             ppc_hash64_set_isi(cs, env, dsisr);
@@ -806,7 +815,7 @@ skip_slb_search:
         return 1;
     }
     qemu_log_mask(CPU_LOG_MMU,
-                "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
+                  "found PTE at index %08" HWADDR_PRIx "\n", ptex);
 
     /* 5. Check access permissions */
 
@@ -849,8 +858,7 @@ skip_slb_search:
     }
 
     if (new_pte1 != pte.pte1) {
-        ppc_hash64_store_hpte(cpu, pte_offset / HASH_PTE_SIZE_64,
-                              pte.pte0, new_pte1);
+        ppc_hash64_store_hpte(cpu, ptex, pte.pte0, new_pte1);
     }
 
     /* 7. Determine the real address from the PTE */
@@ -867,7 +875,7 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
 {
     CPUPPCState *env = &cpu->env;
     ppc_slb_t *slb;
-    hwaddr pte_offset, raddr;
+    hwaddr ptex, raddr;
     ppc_hash_pte64_t pte;
     unsigned apshift;
 
@@ -900,8 +908,8 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
         }
     }
 
-    pte_offset = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
-    if (pte_offset == -1) {
+    ptex = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
+    if (ptex == -1) {
         return -1;
     }
 
@@ -909,30 +917,28 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
         & TARGET_PAGE_MASK;
 }
 
-void ppc_hash64_store_hpte(PowerPCCPU *cpu,
-                           target_ulong pte_index,
-                           target_ulong pte0, target_ulong pte1)
+void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
+                           uint64_t pte0, uint64_t pte1)
 {
     CPUPPCState *env = &cpu->env;
+    hwaddr offset = ptex * HASH_PTE_SIZE_64;
 
     if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
-        kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
+        kvmppc_hash64_write_pte(ptex, pte0, pte1);
         return;
     }
 
-    pte_index *= HASH_PTE_SIZE_64;
     if (env->external_htab) {
-        stq_p(env->external_htab + pte_index, pte0);
-        stq_p(env->external_htab + pte_index + HASH_PTE_SIZE_64 / 2, pte1);
+        stq_p(env->external_htab + offset, pte0);
+        stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
     } else {
-        stq_phys(CPU(cpu)->as, env->htab_base + pte_index, pte0);
+        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
         stq_phys(CPU(cpu)->as,
-                 env->htab_base + pte_index + HASH_PTE_SIZE_64 / 2, pte1);
+                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2, pte1);
     }
 }
 
-void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
-                               target_ulong pte_index,
+void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
                                target_ulong pte0, target_ulong pte1)
 {
     /*
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index 7a0b7fc..8637fe4 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -10,8 +10,8 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot,
 hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr);
 int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
                                 int mmu_idx);
-void ppc_hash64_store_hpte(PowerPCCPU *cpu, target_ulong index,
-                           target_ulong pte0, target_ulong pte1);
+void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
+                           uint64_t pte0, uint64_t pte1);
 void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
                                target_ulong pte_index,
                                target_ulong pte0, target_ulong pte1);
@@ -96,41 +96,27 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
 void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
                                  Error **errp);
 
-uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index);
-void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token);
+struct ppc_hash_pte64 {
+    uint64_t pte0, pte1;
+};
+
+const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,\
+                                             hwaddr ptex, int n);
+void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
+                            hwaddr ptex, int n);
 
-static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
-                                                 uint64_t token, int index)
+static inline uint64_t ppc_hash64_hpte0(PowerPCCPU *cpu,
+                                        const ppc_hash_pte64_t *hptes, int i)
 {
-    CPUPPCState *env = &cpu->env;
-    uint64_t addr;
-
-    addr = token + (index * HASH_PTE_SIZE_64);
-    if (env->external_htab) {
-        return  ldq_p((const void *)(uintptr_t)addr);
-    } else {
-        return ldq_phys(CPU(cpu)->as, addr);
-    }
+    return ldq_p(&(hptes[i].pte0));
 }
 
-static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu,
-                                                 uint64_t token, int index)
+static inline uint64_t ppc_hash64_hpte1(PowerPCCPU *cpu,
+                                        const ppc_hash_pte64_t *hptes, int i)
 {
-    CPUPPCState *env = &cpu->env;
-    uint64_t addr;
-
-    addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
-    if (env->external_htab) {
-        return  ldq_p((const void *)(uintptr_t)addr);
-    } else {
-        return ldq_phys(CPU(cpu)->as, addr);
-    }
+    return ldq_p(&(hptes[i].pte1));
 }
 
-typedef struct {
-    uint64_t pte0, pte1;
-} ppc_hash_pte64_t;
-
 #endif /* CONFIG_USER_ONLY */
 
 #endif /* MMU_HASH64_H */
-- 
2.9.3

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

* [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables
  2017-02-23  2:09 [Qemu-devel] [PATCH 0/6] Cleanups to handling of hash MMU David Gibson
                   ` (3 preceding siblings ...)
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU David Gibson
@ 2017-02-23  2:09 ` David Gibson
  2017-02-23  5:43   ` Alexey Kardashevskiy
  2017-02-23  5:52   ` Suraj Jitindar Singh
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 6/6] target/ppc: Manage external HPT via virtual hypervisor David Gibson
  5 siblings, 2 replies; 22+ messages in thread
From: David Gibson @ 2017-02-23  2:09 UTC (permalink / raw)
  To: qemu-ppc, aik, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus, David Gibson

CPUPPCState includes fields htab_base and htab_mask which store the base
address (GPA) and size (as a mask) of the guest's hashed page table (HPT).
These are set when the SDR1 register is updated.

Keeping these in sync with the SDR1 is actually a little bit fiddly, and
probably not useful for performance, since keeping them expands the size of
CPUPPCState.  It also makes some upcoming changes harder to implement.

This patch removes these fields, in favour of calculating them directly
from the SDR1 contents when necessary.

This does make a change to the behaviour of attempting to write a bad value
(invalid HPT size) to the SDR1 with an mtspr instruction.  Previously, the
bad value would be stored in SDR1 and could be retrieved with a later
mfspr, but the HPT size as used by the softmmu would be, clamped to the
allowed values.  Now, writing a bad value is treated as a no-op.  An error
message is printed in both new and old versions.

I'm not sure which behaviour, if either, matches real hardware.  I don't
think it matters that much, since it's pretty clear that if an OS writes
a bad value to SDR1, it's not going to boot.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_hcall.c    |  4 ++--
 target/ppc/cpu.h        |  8 --------
 target/ppc/machine.c    |  1 -
 target/ppc/mmu-hash32.c | 14 +++++++-------
 target/ppc/mmu-hash32.h | 24 ++++++++++++++++++------
 target/ppc/mmu-hash64.c | 37 ++++++++++++++++---------------------
 target/ppc/mmu-hash64.h | 13 +++++++++++++
 target/ppc/mmu_helper.c | 31 ++++++++++++++++---------------
 8 files changed, 72 insertions(+), 60 deletions(-)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index fd961b5..85d96f6 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -50,9 +50,9 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
 static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
 {
     /*
-     * hash value/pteg group index is normalized by htab_mask
+     * hash value/pteg group index is normalized by HPT mask
      */
-    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) {
+    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) {
         return false;
     }
     return true;
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index c89973e..c6cd9ab 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -309,11 +309,6 @@ union ppc_tlb_t {
 #define SDR_32_HTABORG         0xFFFF0000UL
 #define SDR_32_HTABMASK        0x000001FFUL
 
-#if defined(TARGET_PPC64)
-#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
-#define SDR_64_HTABSIZE        0x000000000000001FULL
-#endif /* defined(TARGET_PPC64 */
-
 typedef struct ppc_slb_t ppc_slb_t;
 struct ppc_slb_t {
     uint64_t esid;
@@ -1006,9 +1001,6 @@ struct CPUPPCState {
     /* tcg TLB needs flush (deferred slb inval instruction typically) */
 #endif
     /* segment registers */
-    hwaddr htab_base;
-    /* mask used to normalize hash value to PTEG index */
-    hwaddr htab_mask;
     target_ulong sr[32];
     /* externally stored hash table */
     uint8_t *external_htab;
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index df9f7a4..1ccbc8a 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -229,7 +229,6 @@ static int cpu_post_load(void *opaque, int version_id)
     }
 
     if (!env->external_htab) {
-        /* Restore htab_base and htab_mask variables */
         ppc_store_sdr1(env, env->spr[SPR_SDR1]);
     }
 
diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
index 29bace6..03ae3c1 100644
--- a/target/ppc/mmu-hash32.c
+++ b/target/ppc/mmu-hash32.c
@@ -304,9 +304,9 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
 
 hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
 {
-    CPUPPCState *env = &cpu->env;
+    target_ulong mask = ppc_hash32_hpt_mask(cpu);
 
-    return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
+    return (hash * HASH_PTEG_SIZE_32) & mask;
 }
 
 static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
@@ -339,7 +339,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
                                      target_ulong sr, target_ulong eaddr,
                                      ppc_hash_pte32_t *pte)
 {
-    CPUPPCState *env = &cpu->env;
     hwaddr pteg_off, pte_offset;
     hwaddr hash;
     uint32_t vsid, pgidx, ptem;
@@ -353,21 +352,22 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
     qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
             " htab_mask " TARGET_FMT_plx
             " hash " TARGET_FMT_plx "\n",
-            env->htab_base, env->htab_mask, hash);
+            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
 
     /* Primary PTEG lookup */
     qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
             " vsid=%" PRIx32 " ptem=%" PRIx32
             " hash=" TARGET_FMT_plx "\n",
-            env->htab_base, env->htab_mask, vsid, ptem, hash);
+            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
+            vsid, ptem, hash);
     pteg_off = get_pteg_offset32(cpu, hash);
     pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
     if (pte_offset == -1) {
         /* Secondary PTEG lookup */
         qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
                 " vsid=%" PRIx32 " api=%" PRIx32
-                " hash=" TARGET_FMT_plx "\n", env->htab_base,
-                env->htab_mask, vsid, ptem, ~hash);
+                " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
+                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
         pteg_off = get_pteg_offset32(cpu, ~hash);
         pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
     }
diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
index 5b9fb08..054be65 100644
--- a/target/ppc/mmu-hash32.h
+++ b/target/ppc/mmu-hash32.h
@@ -65,42 +65,54 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
 #define HPTE32_R_WIMG           0x00000078
 #define HPTE32_R_PP             0x00000003
 
+static inline hwaddr ppc_hash32_hpt_base(PowerPCCPU *cpu)
+{
+    return cpu->env.spr[SPR_SDR1] & SDR_32_HTABORG;
+}
+
+static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
+{
+    return ((cpu->env.spr[SPR_SDR1] & SDR_32_HTABMASK) << 16) | 0xFFFF;
+}
+
 static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
                                                  hwaddr pte_offset)
 {
     CPUPPCState *env = &cpu->env;
+    target_ulong base = ppc_hash32_hpt_base(cpu);
 
     assert(!env->external_htab); /* Not supported on 32-bit for now */
-    return ldl_phys(CPU(cpu)->as, env->htab_base + pte_offset);
+    return ldl_phys(CPU(cpu)->as, base + pte_offset);
 }
 
 static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
                                                  hwaddr pte_offset)
 {
+    target_ulong base = ppc_hash32_hpt_base(cpu);
     CPUPPCState *env = &cpu->env;
 
     assert(!env->external_htab); /* Not supported on 32-bit for now */
-    return ldl_phys(CPU(cpu)->as,
-                    env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2);
+    return ldl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2);
 }
 
 static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
                                           hwaddr pte_offset, target_ulong pte0)
 {
     CPUPPCState *env = &cpu->env;
+    target_ulong base = ppc_hash32_hpt_base(cpu);
 
     assert(!env->external_htab); /* Not supported on 32-bit for now */
-    stl_phys(CPU(cpu)->as, env->htab_base + pte_offset, pte0);
+    stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
 }
 
 static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
                                           hwaddr pte_offset, target_ulong pte1)
 {
     CPUPPCState *env = &cpu->env;
+    target_ulong base = ppc_hash32_hpt_base(cpu);
 
     assert(!env->external_htab); /* Not supported on 32-bit for now */
-    stl_phys(CPU(cpu)->as,
-             env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
+    stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
 }
 
 typedef struct {
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index c59db47..bb87777 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -304,15 +304,13 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
     CPUPPCState *env = &cpu->env;
     target_ulong htabsize = value & SDR_64_HTABSIZE;
 
-    env->spr[SPR_SDR1] = value;
     if (htabsize > 28) {
         error_setg(errp,
                    "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
                    htabsize);
-        htabsize = 28;
+        return;
     }
-    env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
-    env->htab_base = value & SDR_64_HTABORG;
+    env->spr[SPR_SDR1] = value;
 }
 
 void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
@@ -333,10 +331,6 @@ void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
         return;
     }
 
-    /* Not strictly necessary, but makes it clearer that an external
-     * htab is in use when debugging */
-    env->htab_base = -1;
-
     if (kvm_enabled()) {
         if (kvmppc_put_books_sregs(cpu) < 0) {
             error_setg(errp, "Unable to update SDR1 in KVM");
@@ -448,11 +442,12 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
          * HTAB is controlled by QEMU. Just point to the internally
          * accessible PTEG.
          */
-        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
-    } else if (cpu->env.htab_base) {
+        hptes = (const ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
+    } else if (ppc_hash64_hpt_base(cpu)) {
+        hwaddr base = ppc_hash64_hpt_base(cpu);
         hwaddr plen = n * HASH_PTE_SIZE_64;
-        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base + pte_offset,
-                                 &plen, false);
+        hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
+                                  &plen, false);
         if (plen < (n * HASH_PTE_SIZE_64)) {
             hw_error("%s: Unable to map all requested HPTEs\n", __FUNCTION__);
         }
@@ -513,13 +508,12 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
                                      target_ulong ptem,
                                      ppc_hash_pte64_t *pte, unsigned *pshift)
 {
-    CPUPPCState *env = &cpu->env;
     int i;
     const ppc_hash_pte64_t *pteg;
     target_ulong pte0, pte1;
     target_ulong ptex;
 
-    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
+    ptex = (hash & ppc_hash64_hpt_mask(cpu)) * HPTES_PER_GROUP;
     pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
     if (!pteg) {
         return -1;
@@ -597,14 +591,15 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
     qemu_log_mask(CPU_LOG_MMU,
             "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
             " hash " TARGET_FMT_plx "\n",
-            env->htab_base, env->htab_mask, hash);
+            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), hash);
 
     /* Primary PTEG lookup */
     qemu_log_mask(CPU_LOG_MMU,
             "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
             " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
             " hash=" TARGET_FMT_plx "\n",
-            env->htab_base, env->htab_mask, vsid, ptem,  hash);
+            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
+            vsid, ptem,  hash);
     ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
 
     if (ptex == -1) {
@@ -613,8 +608,8 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
         qemu_log_mask(CPU_LOG_MMU,
                 "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
                 " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
-                " hash=" TARGET_FMT_plx "\n", env->htab_base,
-                env->htab_mask, vsid, ptem, ~hash);
+                " hash=" TARGET_FMT_plx "\n", ppc_hash64_hpt_base(cpu),
+                ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash);
 
         ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
     }
@@ -932,9 +927,9 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
         stq_p(env->external_htab + offset, pte0);
         stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
     } else {
-        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
-        stq_phys(CPU(cpu)->as,
-                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2, pte1);
+        hwaddr base = ppc_hash64_hpt_base(cpu);
+        stq_phys(CPU(cpu)->as, base + offset, pte0);
+        stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
     }
 }
 
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index 8637fe4..dc0bc99 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -56,6 +56,9 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
  * Hash page table definitions
  */
 
+#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
+#define SDR_64_HTABSIZE        0x000000000000001FULL
+
 #define HPTES_PER_GROUP         8
 #define HASH_PTE_SIZE_64        16
 #define HASH_PTEG_SIZE_64       (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
@@ -91,6 +94,16 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
 #define HPTE64_V_1TB_SEG        0x4000000000000000ULL
 #define HPTE64_V_VRMA_MASK      0x4001ffffff000000ULL
 
+static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
+{
+    return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG;
+}
+
+static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
+{
+    return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18 - 7)) - 1;
+}
+
 void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
                          Error **errp);
 void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index eb2d482..1381635 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -466,6 +466,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
                                       target_ulong eaddr, int rw, int type)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     hwaddr hash;
     target_ulong vsid;
     int ds, pr, target_page_bits;
@@ -503,7 +504,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
             qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
                     " htab_mask " TARGET_FMT_plx
                     " hash " TARGET_FMT_plx "\n",
-                    env->htab_base, env->htab_mask, hash);
+                    ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
             ctx->hash[0] = hash;
             ctx->hash[1] = ~hash;
 
@@ -518,9 +519,11 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
                 uint32_t a0, a1, a2, a3;
 
                 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
-                         "\n", env->htab_base, env->htab_mask + 0x80);
-                for (curaddr = env->htab_base;
-                     curaddr < (env->htab_base + env->htab_mask + 0x80);
+                         "\n", ppc_hash32_hpt_base(cpu),
+                         ppc_hash32_hpt_mask(env) + 0x80);
+                for (curaddr = ppc_hash32_hpt_base(cpu);
+                     curaddr < (ppc_hash32_hpt_base(cpu)
+                                + ppc_hash32_hpt_mask(cpu) + 0x80);
                      curaddr += 16) {
                     a0 = ldl_phys(cs->as, curaddr);
                     a1 = ldl_phys(cs->as, curaddr + 4);
@@ -1205,12 +1208,13 @@ static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
                             CPUPPCState *env)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     ppc6xx_tlb_t *tlb;
     target_ulong sr;
     int type, way, entry, i;
 
-    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
-    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
+    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
+    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
 
     cpu_fprintf(f, "\nSegment registers:\n");
     for (i = 0; i < 32; i++) {
@@ -1592,9 +1596,9 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
                     env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
                 tlb_miss:
                     env->error_code |= ctx.key << 19;
-                    env->spr[SPR_HASH1] = env->htab_base +
+                    env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
                         get_pteg_offset32(cpu, ctx.hash[0]);
-                    env->spr[SPR_HASH2] = env->htab_base +
+                    env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
                         get_pteg_offset32(cpu, ctx.hash[1]);
                     break;
                 case POWERPC_MMU_SOFT_74xx:
@@ -1999,7 +2003,6 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
 {
     qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
     assert(!env->external_htab);
-    env->spr[SPR_SDR1] = value;
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64) {
         PowerPCCPU *cpu = ppc_env_get_cpu(env);
@@ -2009,14 +2012,12 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
         if (local_err) {
             error_report_err(local_err);
             error_free(local_err);
+            return;
         }
-    } else
-#endif /* defined(TARGET_PPC64) */
-    {
-        /* FIXME: Should check for valid HTABMASK values */
-        env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
-        env->htab_base = value & SDR_32_HTABORG;
     }
+#endif /* defined(TARGET_PPC64) */
+    /* FIXME: Should check for valid HTABMASK values in 32-bit case */
+    env->spr[SPR_SDR1] = value;
 }
 
 /* Segment registers load and store */
-- 
2.9.3

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

* [Qemu-devel] [PATCH 6/6] target/ppc: Manage external HPT via virtual hypervisor
  2017-02-23  2:09 [Qemu-devel] [PATCH 0/6] Cleanups to handling of hash MMU David Gibson
                   ` (4 preceding siblings ...)
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables David Gibson
@ 2017-02-23  2:09 ` David Gibson
  2017-02-23  6:20   ` Suraj Jitindar Singh
  5 siblings, 1 reply; 22+ messages in thread
From: David Gibson @ 2017-02-23  2:09 UTC (permalink / raw)
  To: qemu-ppc, aik, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus, David Gibson

The pseries machine type implements the behaviour of a PAPR compliant
hypervisor, without actually executing such a hypervisor on the virtual
CPU.  To do this we need some hooks in the CPU code to make hypervisor
facilities get redirected to the machine instead of emulated internally.

For hypercalls this is managed through the cpu->vhyp field, which points
to a QOM interface with a method implementing the hypercall.

For the hashed page table (HPT) - also a hypervisor resource - we use an
older hack.  CPUPPCState has an 'external_htab' field which when non-NULL
indicates that the HPT is stored in qemu memory, rather than within the
guest's address space.

For consistency - and to make some future extensions easier - this merges
the external HPT mechanism into the vhyp mechanism.  Methods are added
to vhyp for the basic operations the core hash MMU code needs: map_hptes()
and unmap_hptes() for reading the HPT, store_hpte() for updating it and
hpt_mask() to retrieve its size.

To match this, the pseries machine now sets these vhyp fields in its
existing vhyp class, rather than reaching into the cpu object to set the
external_htab field.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c          | 58 +++++++++++++++++++++++++++++
 hw/ppc/spapr_cpu_core.c | 17 ++++++++-
 hw/ppc/spapr_hcall.c    |  3 +-
 target/ppc/cpu.h        | 10 ++++-
 target/ppc/kvm.c        |  2 +-
 target/ppc/machine.c    |  4 +-
 target/ppc/mmu-hash32.h |  8 ----
 target/ppc/mmu-hash64.c | 98 ++++++++++++++++---------------------------------
 target/ppc/mmu-hash64.h |  7 +++-
 target/ppc/mmu_helper.c |  3 +-
 10 files changed, 123 insertions(+), 87 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 5904e64..c159961 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1050,6 +1050,60 @@ static void close_htab_fd(sPAPRMachineState *spapr)
     spapr->htab_fd = -1;
 }
 
+static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
+{
+    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+
+    return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
+}
+
+static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp,
+                                                hwaddr ptex, int n)
+{
+    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+    hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
+
+    if (!spapr->htab) {
+        /*
+         * HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
+         */
+        return kvmppc_map_hptes(ptex, n);
+    }
+
+    /*
+     * HTAB is controlled by QEMU. Just point to the internally
+     * accessible PTEG.
+     */
+    return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
+}
+
+static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
+                              const ppc_hash_pte64_t *hptes,
+                              hwaddr ptex, int n)
+{
+    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+
+    if (!spapr->htab) {
+        kvmppc_unmap_hptes(hptes, ptex, n);
+    }
+
+    /* Nothing to do for qemu managed HPT */
+}
+
+static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr ptex,
+                             uint64_t pte0, uint64_t pte1)
+{
+    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
+    hwaddr offset = ptex * HASH_PTE_SIZE_64;
+
+    if (!spapr->htab) {
+        kvmppc_hash64_write_pte(ptex, pte0, pte1);
+    } else {
+        stq_p(spapr->htab + offset, pte0);
+        stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
+    }
+}
+
 static int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
 {
     int shift;
@@ -2910,6 +2964,10 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
     nc->nmi_monitor_handler = spapr_nmi;
     smc->phb_placement = spapr_phb_placement;
     vhc->hypercall = emulate_spapr_hypercall;
+    vhc->hpt_mask = spapr_hpt_mask;
+    vhc->map_hptes = spapr_map_hptes;
+    vhc->unmap_hptes = spapr_unmap_hptes;
+    vhc->store_hpte = spapr_store_hpte;
 }
 
 static const TypeInfo spapr_machine_info = {
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 76563c4..ddb130f 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -13,10 +13,12 @@
 #include "hw/boards.h"
 #include "qapi/error.h"
 #include "sysemu/cpus.h"
+#include "sysemu/kvm.h"
 #include "target/ppc/kvm_ppc.h"
 #include "hw/ppc/ppc.h"
 #include "target/ppc/mmu-hash64.h"
 #include "sysemu/numa.h"
+#include "qemu/error-report.h"
 
 static void spapr_cpu_reset(void *opaque)
 {
@@ -34,8 +36,19 @@ static void spapr_cpu_reset(void *opaque)
 
     env->spr[SPR_HIOR] = 0;
 
-    ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift,
-                                &error_fatal);
+    /*
+     * This is a hack for the benefit of KVM PR - it abuses the SDR1
+     * slot in kvm_sregs to communicate the userspace address of the
+     * HPT
+     */
+    if (kvm_enabled()) {
+        env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab
+            | (spapr->htab_shift - 18);
+        if (kvmppc_put_books_sregs(cpu) < 0) {
+            error_report("Unable to update SDR1 in KVM");
+            exit(1);
+        }
+    }
 }
 
 static void spapr_cpu_destroy(PowerPCCPU *cpu)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 85d96f6..f05a90e 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -326,7 +326,6 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
                            target_ulong opcode, target_ulong *args)
 {
-    CPUPPCState *env = &cpu->env;
     target_ulong flags = args[0];
     target_ulong ptex = args[1];
     uint8_t *hpte;
@@ -342,7 +341,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
         n_entries = 4;
     }
 
-    hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
+    hpte = spapr->htab + (ptex * HASH_PTE_SIZE_64);
 
     for (i = 0, ridx = 0; i < n_entries; i++) {
         args[ridx++] = ldq_p(hpte);
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index c6cd9ab..27b78ca 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1002,8 +1002,6 @@ struct CPUPPCState {
 #endif
     /* segment registers */
     target_ulong sr[32];
-    /* externally stored hash table */
-    uint8_t *external_htab;
     /* BATs */
     uint32_t nb_BATs;
     target_ulong DBAT[2][8];
@@ -1211,6 +1209,14 @@ struct PPCVirtualHypervisor {
 struct PPCVirtualHypervisorClass {
     InterfaceClass parent;
     void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
+    hwaddr (*hpt_mask)(PPCVirtualHypervisor *vhyp);
+    const ppc_hash_pte64_t *(*map_hptes)(PPCVirtualHypervisor *vhyp,
+                                         hwaddr ptex, int n);
+    void (*unmap_hptes)(PPCVirtualHypervisor *vhyp,
+                        const ppc_hash_pte64_t *hptes,
+                        hwaddr ptex, int n);
+    void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
+                       uint64_t pte0, uint64_t pte1);
 };
 
 #define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 9d3e57e..c40f6aa 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1251,7 +1251,7 @@ static int kvmppc_get_books_sregs(PowerPCCPU *cpu)
         return ret;
     }
 
-    if (!env->external_htab) {
+    if (!cpu->vhyp) {
         ppc_store_sdr1(env, sregs.u.s.sdr1);
     }
 
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 1ccbc8a..6cb3a48 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -76,7 +76,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
         qemu_get_betls(f, &env->pb[i]);
     for (i = 0; i < 1024; i++)
         qemu_get_betls(f, &env->spr[i]);
-    if (!env->external_htab) {
+    if (!cpu->vhyp) {
         ppc_store_sdr1(env, sdr1);
     }
     qemu_get_be32s(f, &env->vscr);
@@ -228,7 +228,7 @@ static int cpu_post_load(void *opaque, int version_id)
         env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1];
     }
 
-    if (!env->external_htab) {
+    if (!cpu->vhyp) {
         ppc_store_sdr1(env, env->spr[SPR_SDR1]);
     }
 
diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
index 054be65..644cfe6 100644
--- a/target/ppc/mmu-hash32.h
+++ b/target/ppc/mmu-hash32.h
@@ -78,10 +78,8 @@ static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
 static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
                                                  hwaddr pte_offset)
 {
-    CPUPPCState *env = &cpu->env;
     target_ulong base = ppc_hash32_hpt_base(cpu);
 
-    assert(!env->external_htab); /* Not supported on 32-bit for now */
     return ldl_phys(CPU(cpu)->as, base + pte_offset);
 }
 
@@ -89,29 +87,23 @@ static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
                                                  hwaddr pte_offset)
 {
     target_ulong base = ppc_hash32_hpt_base(cpu);
-    CPUPPCState *env = &cpu->env;
 
-    assert(!env->external_htab); /* Not supported on 32-bit for now */
     return ldl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2);
 }
 
 static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
                                           hwaddr pte_offset, target_ulong pte0)
 {
-    CPUPPCState *env = &cpu->env;
     target_ulong base = ppc_hash32_hpt_base(cpu);
 
-    assert(!env->external_htab); /* Not supported on 32-bit for now */
     stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
 }
 
 static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
                                           hwaddr pte_offset, target_ulong pte1)
 {
-    CPUPPCState *env = &cpu->env;
     target_ulong base = ppc_hash32_hpt_base(cpu);
 
-    assert(!env->external_htab); /* Not supported on 32-bit for now */
     stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
 }
 
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index bb87777..ce96823 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -38,12 +38,6 @@
 #endif
 
 /*
- * Used to indicate that a CPU has its hash page table (HPT) managed
- * within the host kernel
- */
-#define MMU_HASH64_KVM_MANAGED_HPT      ((void *)-1)
-
-/*
  * SLB handling
  */
 
@@ -313,31 +307,6 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
     env->spr[SPR_SDR1] = value;
 }
 
-void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
-                                 Error **errp)
-{
-    CPUPPCState *env = &cpu->env;
-    Error *local_err = NULL;
-
-    if (hpt) {
-        env->external_htab = hpt;
-    } else {
-        env->external_htab = MMU_HASH64_KVM_MANAGED_HPT;
-    }
-    ppc_hash64_set_sdr1(cpu, (target_ulong)(uintptr_t)hpt | (shift - 18),
-                        &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-
-    if (kvm_enabled()) {
-        if (kvmppc_put_books_sregs(cpu) < 0) {
-            error_setg(errp, "Unable to update SDR1 in KVM");
-        }
-    }
-}
-
 static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
                                ppc_slb_t *slb, ppc_hash_pte64_t pte)
 {
@@ -429,28 +398,24 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
 const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
                                              hwaddr ptex, int n)
 {
-    const ppc_hash_pte64_t *hptes = NULL;
     hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
+    hwaddr base = ppc_hash64_hpt_base(cpu);
+    hwaddr plen = n * HASH_PTE_SIZE_64;
+    const ppc_hash_pte64_t *hptes;
+
+    if (cpu->vhyp) {
+        PPCVirtualHypervisorClass *vhc =
+            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+        return vhc->map_hptes(cpu->vhyp, ptex, n);
+    }
 
-    if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
-        /*
-         * HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
-         */
-        hptes = kvmppc_map_hptes(ptex, n);
-    } else if (cpu->env.external_htab) {
-        /*
-         * HTAB is controlled by QEMU. Just point to the internally
-         * accessible PTEG.
-         */
-        hptes = (const ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
-    } else if (ppc_hash64_hpt_base(cpu)) {
-        hwaddr base = ppc_hash64_hpt_base(cpu);
-        hwaddr plen = n * HASH_PTE_SIZE_64;
-        hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
-                                  &plen, false);
-        if (plen < (n * HASH_PTE_SIZE_64)) {
-            hw_error("%s: Unable to map all requested HPTEs\n", __FUNCTION__);
-        }
+    if (!base) {
+        return NULL;
+    }
+
+    hptes = address_space_map(CPU(cpu)->as, base + pte_offset, &plen, false);
+    if (plen < (n * HASH_PTE_SIZE_64)) {
+        hw_error("%s: Unable to map all requested HPTEs\n", __FUNCTION__);
     }
     return hptes;
 }
@@ -458,12 +423,15 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
 void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
                             hwaddr ptex, int n)
 {
-    if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
-        kvmppc_unmap_hptes(hptes, ptex, n);
-    } else if (!cpu->env.external_htab) {
-        address_space_unmap(CPU(cpu)->as, (void *)hptes, n * HASH_PTE_SIZE_64,
-                            false, n * HASH_PTE_SIZE_64);
+    if (cpu->vhyp) {
+        PPCVirtualHypervisorClass *vhc =
+            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+        vhc->unmap_hptes(cpu->vhyp, hptes, ptex, n);
+        return;
     }
+
+    address_space_unmap(CPU(cpu)->as, (void *)hptes, n * HASH_PTE_SIZE_64,
+                        false, n * HASH_PTE_SIZE_64);
 }
 
 static unsigned hpte_page_shift(const struct ppc_one_seg_page_size *sps,
@@ -915,22 +883,18 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
 void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
                            uint64_t pte0, uint64_t pte1)
 {
-    CPUPPCState *env = &cpu->env;
+    hwaddr base = ppc_hash64_hpt_base(cpu);
     hwaddr offset = ptex * HASH_PTE_SIZE_64;
 
-    if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
-        kvmppc_hash64_write_pte(ptex, pte0, pte1);
+    if (cpu->vhyp) {
+        PPCVirtualHypervisorClass *vhc =
+            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+        vhc->store_hpte(cpu->vhyp, ptex, pte0, pte1);
         return;
     }
 
-    if (env->external_htab) {
-        stq_p(env->external_htab + offset, pte0);
-        stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
-    } else {
-        hwaddr base = ppc_hash64_hpt_base(cpu);
-        stq_phys(CPU(cpu)->as, base + offset, pte0);
-        stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
-    }
+    stq_phys(CPU(cpu)->as, base + offset, pte0);
+    stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
 }
 
 void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index dc0bc99..9c33e9d 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -101,13 +101,16 @@ static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
 
 static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
 {
+    if (cpu->vhyp) {
+        PPCVirtualHypervisorClass *vhc =
+            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+        return vhc->hpt_mask(cpu->vhyp);
+    }
     return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18 - 7)) - 1;
 }
 
 void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
                          Error **errp);
-void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
-                                 Error **errp);
 
 struct ppc_hash_pte64 {
     uint64_t pte0, pte1;
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index 1381635..0176ab6 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -2001,8 +2001,9 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
 /* Special registers manipulation */
 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
 {
+    PowerPCCPU *cpu = ppc_env_get_cpu(env);
     qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
-    assert(!env->external_htab);
+    assert(!cpu->vhyp);
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64) {
         PowerPCCPU *cpu = ppc_env_get_cpu(env);
-- 
2.9.3

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

* Re: [Qemu-devel] [PATCH 1/6] pseries: Minor cleanups to HPT management hypercalls
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 1/6] pseries: Minor cleanups to HPT management hypercalls David Gibson
@ 2017-02-23  4:08   ` Suraj Jitindar Singh
  0 siblings, 0 replies; 22+ messages in thread
From: Suraj Jitindar Singh @ 2017-02-23  4:08 UTC (permalink / raw)
  To: David Gibson, qemu-ppc, aik
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus

On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
>  * Standardize on 'ptex' instead of 'pte_index' for HPTE index
> variables
>    for consistency and brevity
>  * Avoid variables named 'index'; shadowing index(3) from libc can
> lead to
>    surprising bugs if the variable is removed, because compiler
> errors
>    might not appear for remaining references
>  * Clarify index calculations in h_enter() - we have two cases,
> H_EXACT
>    where the exact HPTE slot is given, and !H_EXACT where we search
> for
>    an empty slot within the hash bucket.  Make the calculation more
>    consistent between the cases.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr_hcall.c | 58 +++++++++++++++++++++++++-----------------
> ----------
>  1 file changed, 28 insertions(+), 30 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 42d20e0..3298a14 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -47,12 +47,12 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
>      return cpu->env.spr_cb[spr].name != NULL;
>  }
>  
> -static inline bool valid_pte_index(CPUPPCState *env, target_ulong
> pte_index)
> +static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
>  {
>      /*
>       * hash value/pteg group index is normalized by htab_mask
>       */
> -    if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
> +    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) {
>          return false;
>      }
>      return true;
> @@ -77,14 +77,13 @@ static bool is_ram_address(sPAPRMachineState
> *spapr, hwaddr addr)
>  static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState
> *spapr,
>                              target_ulong opcode, target_ulong *args)
>  {
> -    CPUPPCState *env = &cpu->env;
>      target_ulong flags = args[0];
> -    target_ulong pte_index = args[1];
> +    target_ulong ptex = args[1];
>      target_ulong pteh = args[2];
>      target_ulong ptel = args[3];
>      unsigned apshift;
>      target_ulong raddr;
> -    target_ulong index;
> +    target_ulong slot;
>      uint64_t token;
>  
>      apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
> @@ -116,25 +115,26 @@ static target_ulong h_enter(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>  
>      pteh &= ~0x60ULL;
>  
> -    if (!valid_pte_index(env, pte_index)) {
> +    if (!valid_ptex(cpu, ptex)) {
>          return H_PARAMETER;
>      }
>  
> -    index = 0;
> +    slot = ptex & 7ULL;
> +    ptex = ptex & ~7ULL;
> +
>      if (likely((flags & H_EXACT) == 0)) {
> -        pte_index &= ~7ULL;
> -        token = ppc_hash64_start_access(cpu, pte_index);
> -        for (; index < 8; index++) {
> -            if (!(ppc_hash64_load_hpte0(cpu, token, index) &
> HPTE64_V_VALID)) {
> +        token = ppc_hash64_start_access(cpu, ptex);
> +        for (slot = 0; slot < 8; slot++) {
> +            if (!(ppc_hash64_load_hpte0(cpu, token, slot) &
> HPTE64_V_VALID)) {
>                  break;
>              }
>          }
>          ppc_hash64_stop_access(cpu, token);
> -        if (index == 8) {
> +        if (slot == 8) {
>              return H_PTEG_FULL;
>          }
>      } else {
> -        token = ppc_hash64_start_access(cpu, pte_index);
> +        token = ppc_hash64_start_access(cpu, ptex);
>          if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
>              ppc_hash64_stop_access(cpu, token);
>              return H_PTEG_FULL;
> @@ -142,10 +142,9 @@ static target_ulong h_enter(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>          ppc_hash64_stop_access(cpu, token);
>      }
>  
> -    ppc_hash64_store_hpte(cpu, pte_index + index,
> -                          pteh | HPTE64_V_HPTE_DIRTY, ptel);
> +    ppc_hash64_store_hpte(cpu, ptex + slot, pteh |
> HPTE64_V_HPTE_DIRTY, ptel);
>  
> -    args[0] = pte_index + index;
> +    args[0] = ptex + slot;
>      return H_SUCCESS;
>  }
>  
> @@ -161,11 +160,10 @@ static RemoveResult remove_hpte(PowerPCCPU
> *cpu, target_ulong ptex,
>                                  target_ulong flags,
>                                  target_ulong *vp, target_ulong *rp)
>  {
> -    CPUPPCState *env = &cpu->env;
>      uint64_t token;
>      target_ulong v, r;
>  
> -    if (!valid_pte_index(env, ptex)) {
> +    if (!valid_ptex(cpu, ptex)) {
>          return REMOVE_PARM;
>      }
>  
> @@ -191,11 +189,11 @@ static target_ulong h_remove(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>  {
>      CPUPPCState *env = &cpu->env;
>      target_ulong flags = args[0];
> -    target_ulong pte_index = args[1];
> +    target_ulong ptex = args[1];
>      target_ulong avpn = args[2];
>      RemoveResult ret;
>  
> -    ret = remove_hpte(cpu, pte_index, avpn, flags,
> +    ret = remove_hpte(cpu, ptex, avpn, flags,
>                        &args[0], &args[1]);
>  
>      switch (ret) {
> @@ -291,16 +289,16 @@ static target_ulong h_protect(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>  {
>      CPUPPCState *env = &cpu->env;
>      target_ulong flags = args[0];
> -    target_ulong pte_index = args[1];
> +    target_ulong ptex = args[1];
>      target_ulong avpn = args[2];
>      uint64_t token;
>      target_ulong v, r;
>  
> -    if (!valid_pte_index(env, pte_index)) {
> +    if (!valid_ptex(cpu, ptex)) {
>          return H_PARAMETER;
>      }
>  
> -    token = ppc_hash64_start_access(cpu, pte_index);
> +    token = ppc_hash64_start_access(cpu, ptex);
>      v = ppc_hash64_load_hpte0(cpu, token, 0);
>      r = ppc_hash64_load_hpte1(cpu, token, 0);
>      ppc_hash64_stop_access(cpu, token);
> @@ -315,13 +313,13 @@ static target_ulong h_protect(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>      r |= (flags << 55) & HPTE64_R_PP0;
>      r |= (flags << 48) & HPTE64_R_KEY_HI;
>      r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
> -    ppc_hash64_store_hpte(cpu, pte_index,
> +    ppc_hash64_store_hpte(cpu, ptex,
>                            (v & ~HPTE64_V_VALID) |
> HPTE64_V_HPTE_DIRTY, 0);
> -    ppc_hash64_tlb_flush_hpte(cpu, pte_index, v, r);
> +    ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
>      /* Flush the tlb */
>      check_tlb_flush(env, true);
>      /* Don't need a memory barrier, due to qemu's global lock */
> -    ppc_hash64_store_hpte(cpu, pte_index, v | HPTE64_V_HPTE_DIRTY,
> r);
> +    ppc_hash64_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
>      return H_SUCCESS;
>  }
>  
> @@ -330,21 +328,21 @@ static target_ulong h_read(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>  {
>      CPUPPCState *env = &cpu->env;
>      target_ulong flags = args[0];
> -    target_ulong pte_index = args[1];
> +    target_ulong ptex = args[1];
>      uint8_t *hpte;
>      int i, ridx, n_entries = 1;
>  
> -    if (!valid_pte_index(env, pte_index)) {
> +    if (!valid_ptex(cpu, ptex)) {
>          return H_PARAMETER;
>      }
>  
>      if (flags & H_READ_4) {
>          /* Clear the two low order bits */
> -        pte_index &= ~(3ULL);
> +        ptex &= ~(3ULL);
>          n_entries = 4;
>      }
>  
> -    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
> +    hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
>  
>      for (i = 0, ridx = 0; i < n_entries; i++) {
>          args[ridx++] = ldq_p(hpte);
I wholeheartedly agree with this rename.

Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>

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

* Re: [Qemu-devel] [PATCH 2/6] target/ppc: Merge cpu_ppc_set_vhyp() with cpu_ppc_set_papr()
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 2/6] target/ppc: Merge cpu_ppc_set_vhyp() with cpu_ppc_set_papr() David Gibson
@ 2017-02-23  4:27   ` Suraj Jitindar Singh
  0 siblings, 0 replies; 22+ messages in thread
From: Suraj Jitindar Singh @ 2017-02-23  4:27 UTC (permalink / raw)
  To: David Gibson, qemu-ppc, aik
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus

On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> cpu_ppc_set_papr() sets up various aspects of CPU state for use with
> PAPR
> paravirtualized guests.  However, it doesn't set the virtual
> hypervisor,
> so callers must also call cpu_ppc_set_vhyp() so that PAPR hypercalls
> are
> handled properly.  This is a bit silly, so fold setting the virtual
> hypervisor into cpu_ppc_set_papr().
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr_cpu_core.c     |  3 +--
>  target/ppc/cpu.h            |  3 +--
>  target/ppc/translate_init.c | 10 +++-------
>  3 files changed, 5 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> index 55cd045..76563c4 100644
> --- a/hw/ppc/spapr_cpu_core.c
> +++ b/hw/ppc/spapr_cpu_core.c
> @@ -57,8 +57,7 @@ static void spapr_cpu_init(sPAPRMachineState
> *spapr, PowerPCCPU *cpu,
>      cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ);
>  
>      /* Enable PAPR mode in TCG or KVM */
> -    cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
> -    cpu_ppc_set_papr(cpu);
> +    cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
>  
>      if (cpu->max_compat) {
>          Error *local_err = NULL;
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index 425e79d..f99bcae 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1300,8 +1300,7 @@ void store_booke_tcr (CPUPPCState *env,
> target_ulong val);
>  void store_booke_tsr (CPUPPCState *env, target_ulong val);
>  void ppc_tlb_invalidate_all (CPUPPCState *env);
>  void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
> -void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
> -void cpu_ppc_set_papr(PowerPCCPU *cpu);
> +void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
>  #endif
>  #endif
>  
> diff --git a/target/ppc/translate_init.c
> b/target/ppc/translate_init.c
> index be35cbd..a1405e9 100644
> --- a/target/ppc/translate_init.c
> +++ b/target/ppc/translate_init.c
> @@ -8835,18 +8835,14 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void
> *data)
>  }
>  
>  #if !defined(CONFIG_USER_ONLY)
> -
> -void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
> -{
> -    cpu->vhyp = vhyp;
> -}
> -
> -void cpu_ppc_set_papr(PowerPCCPU *cpu)
> +void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
>  {
>      CPUPPCState *env = &cpu->env;
>      ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR];
>      ppc_spr_t *amor = &env->spr_cb[SPR_AMOR];
>  
> +    cpu->vhyp = vhyp;
> +
>      /* PAPR always has exception vectors in RAM not ROM. To ensure
> this,
>       * MSR[IP] should never be set.
>       *

Sounds Good

Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>

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

* Re: [Qemu-devel] [PATCH 3/6] target/ppc: SDR1 is a hypervisor resource
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 3/6] target/ppc: SDR1 is a hypervisor resource David Gibson
@ 2017-02-23  4:32   ` Suraj Jitindar Singh
  2017-02-23  5:11     ` David Gibson
  0 siblings, 1 reply; 22+ messages in thread
From: Suraj Jitindar Singh @ 2017-02-23  4:32 UTC (permalink / raw)
  To: David Gibson, qemu-ppc, aik
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus

On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> At present the SDR1 register - the base of the system's hashed page
> table
> (HPT) - is represented as an SPR with supervisor read and write
> permission.
> However, on CPUs which have a hypervisor mode, the SDR1 is a
> hypervisor
> only resource.  Change the permission checking on the SPR to reflect
> this.
> 
> Now that this is done, we don't need to check for an external HPT
> executing
> mtsdr1: an external HPT only applies when we're emulating the
> behaviour of
> a hypervisor, rather than modelling the CPU's hypervisor mode
> internally,
> so if we're permitted to execute mtsdr1, we don't have an external
> HPT.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  target/ppc/misc_helper.c    |  8 +++-----
>  target/ppc/translate_init.c | 20 ++++++++++++++++----
>  2 files changed, 19 insertions(+), 9 deletions(-)
> 
> diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
> index ab432ba..fa573dd 100644
> --- a/target/ppc/misc_helper.c
> +++ b/target/ppc/misc_helper.c
> @@ -82,11 +82,9 @@ void helper_store_sdr1(CPUPPCState *env,
> target_ulong val)
>  {
>      PowerPCCPU *cpu = ppc_env_get_cpu(env);
>  
> -    if (!env->external_htab) {
> -        if (env->spr[SPR_SDR1] != val) {
> -            ppc_store_sdr1(env, val);
> -            tlb_flush(CPU(cpu));
> -        }

It may have been the case we didn't have to check this before anyway...
Oh well

> +    if (env->spr[SPR_SDR1] != val) {
> +        ppc_store_sdr1(env, val);
> +        tlb_flush(CPU(cpu));
>      }
>  }
>  
> diff --git a/target/ppc/translate_init.c
> b/target/ppc/translate_init.c
> index a1405e9..c92435d 100644
> --- a/target/ppc/translate_init.c
> +++ b/target/ppc/translate_init.c
> @@ -740,10 +740,22 @@ static void gen_spr_ne_601 (CPUPPCState *env)
>                   &spr_read_decr, &spr_write_decr,
>                   0x00000000);
>      /* Memory management */
> -    spr_register(env, SPR_SDR1, "SDR1",
> -                 SPR_NOACCESS, SPR_NOACCESS,
> -                 &spr_read_generic, &spr_write_sdr1,
> -                 0x00000000);
> +#ifndef CONFIG_USER_ONLY
> +    if (env->has_hv_mode) {
> +        /* SDR1 is a hypervisor resource on CPUs which have a
> +         * hypervisor mode */
> +        spr_register_hv(env, SPR_SDR1, "SDR1",
> +                        SPR_NOACCESS, SPR_NOACCESS,
> +                        SPR_NOACCESS, SPR_NOACCESS,
> +                        &spr_read_generic, &spr_write_sdr1,
> +                        0x00000000);
> +    } else {
> +        spr_register(env, SPR_SDR1, "SDR1",
> +                     SPR_NOACCESS, SPR_NOACCESS,
> +                     &spr_read_generic, &spr_write_sdr1,
> +                     0x00000000);
> +    }
> +#endif
>  }
>  
>  /* BATs 0-3 */

Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>

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

* Re: [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU David Gibson
@ 2017-02-23  5:02   ` Alexey Kardashevskiy
  2017-02-23  5:23     ` David Gibson
  2017-02-27  5:06     ` David Gibson
  2017-02-23  5:37   ` Suraj Jitindar Singh
  1 sibling, 2 replies; 22+ messages in thread
From: Alexey Kardashevskiy @ 2017-02-23  5:02 UTC (permalink / raw)
  To: David Gibson, qemu-ppc, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus

On 23/02/17 13:09, David Gibson wrote:
> Accesses to the hashed page table (HPT) are complicated by the fact that
> the HPT could be in one of three places:
>    1) Within guest memory - when we're emulating a full guest CPU at the
>       hardware level (e.g. powernv, mac99, g3beige)
>    2) Within qemu, but outside guest memory - when we're emulating user and
>       supervisor instructions within TCG, but instead of emulating
>       the CPU's hypervisor mode, we just emulate a hypervisor's behaviour
>       (pseries in TCG)
>    3) Within KVM - a pseries machine using KVM acceleration.  Mostly
>       accesses to the HPT are handled by KVM, but there are a few cases
>       where qemu needs to access it via a special fd for the purpose.
> 
> In order to batch accesses to the fd in case (3), we use a somewhat awkward
> ppc_hash64_start_access() / ppc_hash64_stop_access() pair, which for case
> (3) reads / releases a whole PTEG from the kernel.  For cases (1) & (2)
> it just returns an address value.  The actual HPTE load helpers then need
> to interpret the returned token differently in the 3 cases.
> 
> This patch keeps the same basic structure, but simplfiies the details.
> First start_access() / stop_access() are renamed to get_pteg() and
> put_pteg() to make their operation more obvious.


They are renamed to map_hptes/unmap_hptes actually.


> Second, read_pteg() now
> always returns a qemu pointer, which can always be used in the same way
> by the load_hpte() helpers.  In case (1) it comes from address_space_map()
> in case (2) directly from qemu's HPT buffer and in case (3) from a
> temporary buffer read from the KVM fd.
> 
> While we're at it, make things a bit more consistent in terms of types and
> variable names: avoid variables named 'index' (it shadows index(3) which
> can lead to confusing results), use 'hwaddr ptex' for HPTE indices and
> uint64_t for each of the HPTE words, use ptex throughout the call stack
> instead of pte_offset in some places (we still need that at the bottom
> layer, but nowhere else).
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr_hcall.c    | 36 +++++++++---------
>  target/ppc/cpu.h        |  3 +-
>  target/ppc/kvm.c        | 25 ++++++-------
>  target/ppc/kvm_ppc.h    | 43 ++++++++++------------
>  target/ppc/mmu-hash64.c | 98 ++++++++++++++++++++++++++-----------------------
>  target/ppc/mmu-hash64.h | 46 ++++++++---------------
>  6 files changed, 119 insertions(+), 132 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 3298a14..fd961b5 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -84,7 +84,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>      unsigned apshift;
>      target_ulong raddr;
>      target_ulong slot;
> -    uint64_t token;
> +    const ppc_hash_pte64_t *hptes;
>  
>      apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
>      if (!apshift) {
> @@ -123,23 +123,23 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>      ptex = ptex & ~7ULL;
>  
>      if (likely((flags & H_EXACT) == 0)) {
> -        token = ppc_hash64_start_access(cpu, ptex);
> +        hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
>          for (slot = 0; slot < 8; slot++) {
> -            if (!(ppc_hash64_load_hpte0(cpu, token, slot) & HPTE64_V_VALID)) {
> +            if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
>                  break;
>              }
>          }
> -        ppc_hash64_stop_access(cpu, token);
> +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
>          if (slot == 8) {
>              return H_PTEG_FULL;
>          }
>      } else {
> -        token = ppc_hash64_start_access(cpu, ptex);
> -        if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
> -            ppc_hash64_stop_access(cpu, token);
> +        hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
> +        if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
> +            ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
>              return H_PTEG_FULL;
>          }
> -        ppc_hash64_stop_access(cpu, token);
> +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
>      }
>  
>      ppc_hash64_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
> @@ -160,17 +160,17 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
>                                  target_ulong flags,
>                                  target_ulong *vp, target_ulong *rp)
>  {
> -    uint64_t token;
> +    const ppc_hash_pte64_t *hptes;
>      target_ulong v, r;
>  
>      if (!valid_ptex(cpu, ptex)) {
>          return REMOVE_PARM;
>      }
>  
> -    token = ppc_hash64_start_access(cpu, ptex);
> -    v = ppc_hash64_load_hpte0(cpu, token, 0);
> -    r = ppc_hash64_load_hpte1(cpu, token, 0);
> -    ppc_hash64_stop_access(cpu, token);
> +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
>  
>      if ((v & HPTE64_V_VALID) == 0 ||
>          ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
> @@ -291,17 +291,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>      target_ulong flags = args[0];
>      target_ulong ptex = args[1];
>      target_ulong avpn = args[2];
> -    uint64_t token;
> +    const ppc_hash_pte64_t *hptes;
>      target_ulong v, r;
>  
>      if (!valid_ptex(cpu, ptex)) {
>          return H_PARAMETER;
>      }
>  
> -    token = ppc_hash64_start_access(cpu, ptex);
> -    v = ppc_hash64_load_hpte0(cpu, token, 0);
> -    r = ppc_hash64_load_hpte1(cpu, token, 0);
> -    ppc_hash64_stop_access(cpu, token);
> +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
>  
>      if ((v & HPTE64_V_VALID) == 0 ||
>          ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index f99bcae..c89973e 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -223,11 +223,12 @@ enum {
>  typedef struct opc_handler_t opc_handler_t;
>  
>  /*****************************************************************************/
> -/* Types used to describe some PowerPC registers */
> +/* Types used to describe some PowerPC registers etc. */
>  typedef struct DisasContext DisasContext;
>  typedef struct ppc_spr_t ppc_spr_t;
>  typedef union ppc_avr_t ppc_avr_t;
>  typedef union ppc_tlb_t ppc_tlb_t;
> +typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
>  
>  /* SPR access micro-ops generations callbacks */
>  struct ppc_spr_t {
> diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> index 52bbea5..9d3e57e 100644
> --- a/target/ppc/kvm.c
> +++ b/target/ppc/kvm.c
> @@ -2601,17 +2601,17 @@ struct kvm_get_htab_buf {
>      /*
>       * We require one extra byte for read
>       */
> -    target_ulong hpte[(HPTES_PER_GROUP * 2) + 1];
> +    ppc_hash_pte64_t hpte[HPTES_PER_GROUP];


The "one extra byte" (which was ulong) is not needed any more why?


>  };
>  
> -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
> +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)


This "int n" is ignored here by a reason?


>  {
>      int htab_fd;
>      struct kvm_get_htab_fd ghf;
> -    struct kvm_get_htab_buf  *hpte_buf;
> +    struct kvm_get_htab_buf *hpte_buf;
>  
>      ghf.flags = 0;
> -    ghf.start_index = pte_index;
> +    ghf.start_index = ptex;
>      htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
>      if (htab_fd < 0) {
>          goto error_out;
> @@ -2626,7 +2626,7 @@ uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
>      }
>  
>      close(htab_fd);
> -    return (uint64_t)(uintptr_t) hpte_buf->hpte;
> +    return hpte_buf->hpte;
>  
>  out_close:
>      g_free(hpte_buf);
> @@ -2635,18 +2635,15 @@ error_out:
>      return 0;
>  }
>  
> -void kvmppc_hash64_free_pteg(uint64_t token)
> +void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex, int n)
>  {
>      struct kvm_get_htab_buf *htab_buf;
>  
> -    htab_buf = container_of((void *)(uintptr_t) token, struct kvm_get_htab_buf,
> -                            hpte);
> +    htab_buf = container_of((void *)hptes, struct kvm_get_htab_buf, hpte);
>      g_free(htab_buf);
> -    return;
>  }
>  
> -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
> -                             target_ulong pte0, target_ulong pte1)
> +void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t pte1)
>  {
>      int htab_fd;
>      struct kvm_get_htab_fd ghf;
> @@ -2661,9 +2658,9 @@ void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
>  
>      hpte_buf.header.n_valid = 1;
>      hpte_buf.header.n_invalid = 0;
> -    hpte_buf.header.index = pte_index;
> -    hpte_buf.hpte[0] = pte0;
> -    hpte_buf.hpte[1] = pte1;
> +    hpte_buf.header.index = ptex;
> +    hpte_buf.hpte[0].pte0 = pte0;
> +    hpte_buf.hpte[0].pte1 = pte1;
>      /*
>       * Write the hpte entry.
>       * CAUTION: write() has the warn_unused_result attribute. Hence we
> diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> index 8da2ee4..3f8fccd 100644
> --- a/target/ppc/kvm_ppc.h
> +++ b/target/ppc/kvm_ppc.h
> @@ -41,6 +41,10 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd,
>  int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
>  int kvmppc_reset_htab(int shift_hint);
>  uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
> +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n);
> +void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex, int n);
> +
> +void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t pte1);
>  #endif /* !CONFIG_USER_ONLY */
>  bool kvmppc_has_cap_epr(void);
>  int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function);
> @@ -49,11 +53,6 @@ int kvmppc_get_htab_fd(bool write);
>  int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns);
>  int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
>                             uint16_t n_valid, uint16_t n_invalid);
> -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index);
> -void kvmppc_hash64_free_pteg(uint64_t token);
> -
> -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
> -                             target_ulong pte0, target_ulong pte1);
>  bool kvmppc_has_cap_fixup_hcalls(void);
>  bool kvmppc_has_cap_htm(void);
>  int kvmppc_enable_hwrng(void);
> @@ -199,6 +198,22 @@ static inline bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
>      return true;
>  }
>  
> +static inline const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)
> +{
> +    abort();
> +}
> +
> +static inline void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes,
> +                                      hwaddr ptex, int n)
> +{
> +    abort();
> +}
> +
> +static inline void kvmppc_hash64_write_pte(hwaddr ptex,
> +                                           uint64_t pte0, uint64_t pte1)
> +{
> +    abort();
> +}
>  #endif /* !CONFIG_USER_ONLY */
>  
>  static inline bool kvmppc_has_cap_epr(void)
> @@ -234,24 +249,6 @@ static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
>      abort();
>  }
>  
> -static inline uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu,
> -                                               target_ulong pte_index)
> -{
> -    abort();
> -}
> -
> -static inline void kvmppc_hash64_free_pteg(uint64_t token)
> -{
> -    abort();
> -}
> -
> -static inline void kvmppc_hash64_write_pte(CPUPPCState *env,
> -                                           target_ulong pte_index,
> -                                           target_ulong pte0, target_ulong pte1)
> -{
> -    abort();
> -}
> -
>  static inline bool kvmppc_has_cap_fixup_hcalls(void)
>  {
>      abort();
> diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> index 76669ed..c59db47 100644
> --- a/target/ppc/mmu-hash64.c
> +++ b/target/ppc/mmu-hash64.c
> @@ -27,6 +27,7 @@
>  #include "kvm_ppc.h"
>  #include "mmu-hash64.h"
>  #include "exec/log.h"
> +#include "hw/hw.h"
>  
>  //#define DEBUG_SLB
>  
> @@ -431,33 +432,42 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
>      return prot;
>  }
>  
> -uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
> +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
> +                                             hwaddr ptex, int n)
>  {
> -    uint64_t token = 0;
> -    hwaddr pte_offset;
> +    const ppc_hash_pte64_t *hptes = NULL;
> +    hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
>  
> -    pte_offset = pte_index * HASH_PTE_SIZE_64;
>      if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
>          /*
>           * HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
>           */
> -        token = kvmppc_hash64_read_pteg(cpu, pte_index);
> +        hptes = kvmppc_map_hptes(ptex, n);
>      } else if (cpu->env.external_htab) {
>          /*
>           * HTAB is controlled by QEMU. Just point to the internally
>           * accessible PTEG.
>           */
> -        token = (uint64_t)(uintptr_t) cpu->env.external_htab + pte_offset;
> +        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
>      } else if (cpu->env.htab_base) {
> -        token = cpu->env.htab_base + pte_offset;
> +        hwaddr plen = n * HASH_PTE_SIZE_64;
> +        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base + pte_offset,
> +                                 &plen, false);
> +        if (plen < (n * HASH_PTE_SIZE_64)) {
> +            hw_error("%s: Unable to map all requested HPTEs\n", __FUNCTION__);
> +        }
>      }
> -    return token;
> +    return hptes;
>  }
>  
> -void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token)
> +void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
> +                            hwaddr ptex, int n)
>  {
>      if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> -        kvmppc_hash64_free_pteg(token);
> +        kvmppc_unmap_hptes(hptes, ptex, n);
> +    } else if (!cpu->env.external_htab) {
> +        address_space_unmap(CPU(cpu)->as, (void *)hptes, n * HASH_PTE_SIZE_64,
> +                            false, n * HASH_PTE_SIZE_64);
>      }
>  }
>  
> @@ -505,18 +515,18 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
>  {
>      CPUPPCState *env = &cpu->env;
>      int i;
> -    uint64_t token;
> +    const ppc_hash_pte64_t *pteg;
>      target_ulong pte0, pte1;
> -    target_ulong pte_index;
> +    target_ulong ptex;
>  
> -    pte_index = (hash & env->htab_mask) * HPTES_PER_GROUP;
> -    token = ppc_hash64_start_access(cpu, pte_index);
> -    if (!token) {
> +    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> +    pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> +    if (!pteg) {
>          return -1;
>      }
>      for (i = 0; i < HPTES_PER_GROUP; i++) {
> -        pte0 = ppc_hash64_load_hpte0(cpu, token, i);
> -        pte1 = ppc_hash64_load_hpte1(cpu, token, i);
> +        pte0 = ppc_hash64_hpte0(cpu, pteg, i);
> +        pte1 = ppc_hash64_hpte1(cpu, pteg, i);
>  
>          /* This compares V, B, H (secondary) and the AVPN */
>          if (HPTE64_V_COMPARE(pte0, ptem)) {
> @@ -536,11 +546,11 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
>               */
>              pte->pte0 = pte0;
>              pte->pte1 = pte1;
> -            ppc_hash64_stop_access(cpu, token);
> -            return (pte_index + i) * HASH_PTE_SIZE_64;
> +            ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
> +            return ptex + i;
>          }
>      }
> -    ppc_hash64_stop_access(cpu, token);
> +    ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
>      /*
>       * We didn't find a valid entry.
>       */
> @@ -552,8 +562,7 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
>                                       ppc_hash_pte64_t *pte, unsigned *pshift)
>  {
>      CPUPPCState *env = &cpu->env;
> -    hwaddr pte_offset;
> -    hwaddr hash;
> +    hwaddr hash, ptex;
>      uint64_t vsid, epnmask, epn, ptem;
>      const struct ppc_one_seg_page_size *sps = slb->sps;
>  
> @@ -596,9 +605,9 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
>              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
>              " hash=" TARGET_FMT_plx "\n",
>              env->htab_base, env->htab_mask, vsid, ptem,  hash);
> -    pte_offset = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
> +    ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
>  
> -    if (pte_offset == -1) {
> +    if (ptex == -1) {
>          /* Secondary PTEG lookup */
>          ptem |= HPTE64_V_SECONDARY;
>          qemu_log_mask(CPU_LOG_MMU,
> @@ -607,10 +616,10 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
>                  " hash=" TARGET_FMT_plx "\n", env->htab_base,
>                  env->htab_mask, vsid, ptem, ~hash);
>  
> -        pte_offset = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
> +        ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
>      }
>  
> -    return pte_offset;
> +    return ptex;
>  }
>  
>  unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
> @@ -708,7 +717,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
>      CPUPPCState *env = &cpu->env;
>      ppc_slb_t *slb;
>      unsigned apshift;
> -    hwaddr pte_offset;
> +    hwaddr ptex;
>      ppc_hash_pte64_t pte;
>      int pp_prot, amr_prot, prot;
>      uint64_t new_pte1, dsisr;
> @@ -792,8 +801,8 @@ skip_slb_search:
>      }
>  
>      /* 4. Locate the PTE in the hash table */
> -    pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
> -    if (pte_offset == -1) {
> +    ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
> +    if (ptex == -1) {
>          dsisr = 0x40000000;
>          if (rwx == 2) {
>              ppc_hash64_set_isi(cs, env, dsisr);
> @@ -806,7 +815,7 @@ skip_slb_search:
>          return 1;
>      }
>      qemu_log_mask(CPU_LOG_MMU,
> -                "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
> +                  "found PTE at index %08" HWADDR_PRIx "\n", ptex);
>  
>      /* 5. Check access permissions */
>  
> @@ -849,8 +858,7 @@ skip_slb_search:
>      }
>  
>      if (new_pte1 != pte.pte1) {
> -        ppc_hash64_store_hpte(cpu, pte_offset / HASH_PTE_SIZE_64,
> -                              pte.pte0, new_pte1);
> +        ppc_hash64_store_hpte(cpu, ptex, pte.pte0, new_pte1);
>      }
>  
>      /* 7. Determine the real address from the PTE */
> @@ -867,7 +875,7 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
>  {
>      CPUPPCState *env = &cpu->env;
>      ppc_slb_t *slb;
> -    hwaddr pte_offset, raddr;
> +    hwaddr ptex, raddr;
>      ppc_hash_pte64_t pte;
>      unsigned apshift;
>  
> @@ -900,8 +908,8 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
>          }
>      }
>  
> -    pte_offset = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
> -    if (pte_offset == -1) {
> +    ptex = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
> +    if (ptex == -1) {
>          return -1;
>      }
>  
> @@ -909,30 +917,28 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
>          & TARGET_PAGE_MASK;
>  }
>  
> -void ppc_hash64_store_hpte(PowerPCCPU *cpu,
> -                           target_ulong pte_index,
> -                           target_ulong pte0, target_ulong pte1)
> +void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> +                           uint64_t pte0, uint64_t pte1)
>  {
>      CPUPPCState *env = &cpu->env;
> +    hwaddr offset = ptex * HASH_PTE_SIZE_64;
>  
>      if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> -        kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
> +        kvmppc_hash64_write_pte(ptex, pte0, pte1);
>          return;
>      }
>  
> -    pte_index *= HASH_PTE_SIZE_64;
>      if (env->external_htab) {
> -        stq_p(env->external_htab + pte_index, pte0);
> -        stq_p(env->external_htab + pte_index + HASH_PTE_SIZE_64 / 2, pte1);
> +        stq_p(env->external_htab + offset, pte0);
> +        stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
>      } else {
> -        stq_phys(CPU(cpu)->as, env->htab_base + pte_index, pte0);
> +        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
>          stq_phys(CPU(cpu)->as,
> -                 env->htab_base + pte_index + HASH_PTE_SIZE_64 / 2, pte1);
> +                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2, pte1);
>      }
>  }
>  
> -void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
> -                               target_ulong pte_index,
> +void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
>                                 target_ulong pte0, target_ulong pte1)
>  {
>      /*
> diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> index 7a0b7fc..8637fe4 100644
> --- a/target/ppc/mmu-hash64.h
> +++ b/target/ppc/mmu-hash64.h
> @@ -10,8 +10,8 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot,
>  hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr);
>  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
>                                  int mmu_idx);
> -void ppc_hash64_store_hpte(PowerPCCPU *cpu, target_ulong index,
> -                           target_ulong pte0, target_ulong pte1);
> +void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> +                           uint64_t pte0, uint64_t pte1);
>  void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
>                                 target_ulong pte_index,
>                                 target_ulong pte0, target_ulong pte1);
> @@ -96,41 +96,27 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
>  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
>                                   Error **errp);
>  
> -uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index);
> -void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token);
> +struct ppc_hash_pte64 {
> +    uint64_t pte0, pte1;
> +};
> +
> +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,\


You do not need the trailing '\'.


> +                                             hwaddr ptex, int n);
> +void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
> +                            hwaddr ptex, int n);
>  
> -static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
> -                                                 uint64_t token, int index)
> +static inline uint64_t ppc_hash64_hpte0(PowerPCCPU *cpu,
> +                                        const ppc_hash_pte64_t *hptes, int i)
>  {
> -    CPUPPCState *env = &cpu->env;
> -    uint64_t addr;
> -
> -    addr = token + (index * HASH_PTE_SIZE_64);
> -    if (env->external_htab) {
> -        return  ldq_p((const void *)(uintptr_t)addr);
> -    } else {
> -        return ldq_phys(CPU(cpu)->as, addr);
> -    }
> +    return ldq_p(&(hptes[i].pte0));
>  }
>  
> -static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu,
> -                                                 uint64_t token, int index)
> +static inline uint64_t ppc_hash64_hpte1(PowerPCCPU *cpu,
> +                                        const ppc_hash_pte64_t *hptes, int i)
>  {
> -    CPUPPCState *env = &cpu->env;
> -    uint64_t addr;
> -
> -    addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
> -    if (env->external_htab) {
> -        return  ldq_p((const void *)(uintptr_t)addr);
> -    } else {
> -        return ldq_phys(CPU(cpu)->as, addr);
> -    }
> +    return ldq_p(&(hptes[i].pte1));
>  }
>  
> -typedef struct {
> -    uint64_t pte0, pte1;
> -} ppc_hash_pte64_t;
> -
>  #endif /* CONFIG_USER_ONLY */
>  
>  #endif /* MMU_HASH64_H */
> 


-- 
Alexey

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

* Re: [Qemu-devel] [PATCH 3/6] target/ppc: SDR1 is a hypervisor resource
  2017-02-23  4:32   ` Suraj Jitindar Singh
@ 2017-02-23  5:11     ` David Gibson
  0 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-02-23  5:11 UTC (permalink / raw)
  To: Suraj Jitindar Singh
  Cc: qemu-ppc, aik, qemu-devel, agraf, thuth, lvivier, mdroth, paulus

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

On Thu, Feb 23, 2017 at 03:32:04PM +1100, Suraj Jitindar Singh wrote:
> On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> > At present the SDR1 register - the base of the system's hashed page
> > table
> > (HPT) - is represented as an SPR with supervisor read and write
> > permission.
> > However, on CPUs which have a hypervisor mode, the SDR1 is a
> > hypervisor
> > only resource.  Change the permission checking on the SPR to reflect
> > this.
> > 
> > Now that this is done, we don't need to check for an external HPT
> > executing
> > mtsdr1: an external HPT only applies when we're emulating the
> > behaviour of
> > a hypervisor, rather than modelling the CPU's hypervisor mode
> > internally,
> > so if we're permitted to execute mtsdr1, we don't have an external
> > HPT.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  target/ppc/misc_helper.c    |  8 +++-----
> >  target/ppc/translate_init.c | 20 ++++++++++++++++----
> >  2 files changed, 19 insertions(+), 9 deletions(-)
> > 
> > diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
> > index ab432ba..fa573dd 100644
> > --- a/target/ppc/misc_helper.c
> > +++ b/target/ppc/misc_helper.c
> > @@ -82,11 +82,9 @@ void helper_store_sdr1(CPUPPCState *env,
> > target_ulong val)
> >  {
> >      PowerPCCPU *cpu = ppc_env_get_cpu(env);
> >  
> > -    if (!env->external_htab) {
> > -        if (env->spr[SPR_SDR1] != val) {
> > -            ppc_store_sdr1(env, val);
> > -            tlb_flush(CPU(cpu));
> > -        }
> 
> It may have been the case we didn't have to check this before anyway...
> Oh well

Actually I think we did.  At least with a TCG (and maybe KVM PR)
guest, because the SDR1 was previously treated as a supervisor
resource, the guest could have issued an mtsdr1, changing the size of
the HPT.  We still would have read from the external_htab, but if the
size was changed the guest could have triggered accesses beyond the
end of it, crashing qemu.

With this check in place the behaviour of mtsdr1 was wrong (it was a
no-op instead of causing a privlieged instruction exception), but not
dangerous.

>
> > +    if (env->spr[SPR_SDR1] != val) {
> > +        ppc_store_sdr1(env, val);
> > +        tlb_flush(CPU(cpu));
> >      }
> >  }
> >  
> > diff --git a/target/ppc/translate_init.c
> > b/target/ppc/translate_init.c
> > index a1405e9..c92435d 100644
> > --- a/target/ppc/translate_init.c
> > +++ b/target/ppc/translate_init.c
> > @@ -740,10 +740,22 @@ static void gen_spr_ne_601 (CPUPPCState *env)
> >                   &spr_read_decr, &spr_write_decr,
> >                   0x00000000);
> >      /* Memory management */
> > -    spr_register(env, SPR_SDR1, "SDR1",
> > -                 SPR_NOACCESS, SPR_NOACCESS,
> > -                 &spr_read_generic, &spr_write_sdr1,
> > -                 0x00000000);
> > +#ifndef CONFIG_USER_ONLY
> > +    if (env->has_hv_mode) {
> > +        /* SDR1 is a hypervisor resource on CPUs which have a
> > +         * hypervisor mode */
> > +        spr_register_hv(env, SPR_SDR1, "SDR1",
> > +                        SPR_NOACCESS, SPR_NOACCESS,
> > +                        SPR_NOACCESS, SPR_NOACCESS,
> > +                        &spr_read_generic, &spr_write_sdr1,
> > +                        0x00000000);
> > +    } else {
> > +        spr_register(env, SPR_SDR1, "SDR1",
> > +                     SPR_NOACCESS, SPR_NOACCESS,
> > +                     &spr_read_generic, &spr_write_sdr1,
> > +                     0x00000000);
> > +    }
> > +#endif
> >  }
> >  
> >  /* BATs 0-3 */
> 
> Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> 

-- 
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: 819 bytes --]

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

* Re: [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU
  2017-02-23  5:02   ` Alexey Kardashevskiy
@ 2017-02-23  5:23     ` David Gibson
  2017-02-27  5:06     ` David Gibson
  1 sibling, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-02-23  5:23 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: qemu-ppc, sjitindarsingh, qemu-devel, agraf, thuth, lvivier,
	mdroth, paulus

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

On Thu, Feb 23, 2017 at 04:02:54PM +1100, Alexey Kardashevskiy wrote:
> On 23/02/17 13:09, David Gibson wrote:
> > Accesses to the hashed page table (HPT) are complicated by the fact that
> > the HPT could be in one of three places:
> >    1) Within guest memory - when we're emulating a full guest CPU at the
> >       hardware level (e.g. powernv, mac99, g3beige)
> >    2) Within qemu, but outside guest memory - when we're emulating user and
> >       supervisor instructions within TCG, but instead of emulating
> >       the CPU's hypervisor mode, we just emulate a hypervisor's behaviour
> >       (pseries in TCG)
> >    3) Within KVM - a pseries machine using KVM acceleration.  Mostly
> >       accesses to the HPT are handled by KVM, but there are a few cases
> >       where qemu needs to access it via a special fd for the purpose.
> > 
> > In order to batch accesses to the fd in case (3), we use a somewhat awkward
> > ppc_hash64_start_access() / ppc_hash64_stop_access() pair, which for case
> > (3) reads / releases a whole PTEG from the kernel.  For cases (1) & (2)
> > it just returns an address value.  The actual HPTE load helpers then need
> > to interpret the returned token differently in the 3 cases.
> > 
> > This patch keeps the same basic structure, but simplfiies the details.
> > First start_access() / stop_access() are renamed to get_pteg() and
> > put_pteg() to make their operation more obvious.
> 
> 
> They are renamed to map_hptes/unmap_hptes actually.

Oops.  Adjusted.

> 
> 
> > Second, read_pteg() now
> > always returns a qemu pointer, which can always be used in the same way
> > by the load_hpte() helpers.  In case (1) it comes from address_space_map()
> > in case (2) directly from qemu's HPT buffer and in case (3) from a
> > temporary buffer read from the KVM fd.
> > 
> > While we're at it, make things a bit more consistent in terms of types and
> > variable names: avoid variables named 'index' (it shadows index(3) which
> > can lead to confusing results), use 'hwaddr ptex' for HPTE indices and
> > uint64_t for each of the HPTE words, use ptex throughout the call stack
> > instead of pte_offset in some places (we still need that at the bottom
> > layer, but nowhere else).
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr_hcall.c    | 36 +++++++++---------
> >  target/ppc/cpu.h        |  3 +-
> >  target/ppc/kvm.c        | 25 ++++++-------
> >  target/ppc/kvm_ppc.h    | 43 ++++++++++------------
> >  target/ppc/mmu-hash64.c | 98 ++++++++++++++++++++++++++-----------------------
> >  target/ppc/mmu-hash64.h | 46 ++++++++---------------
> >  6 files changed, 119 insertions(+), 132 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index 3298a14..fd961b5 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -84,7 +84,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> >      unsigned apshift;
> >      target_ulong raddr;
> >      target_ulong slot;
> > -    uint64_t token;
> > +    const ppc_hash_pte64_t *hptes;
> >  
> >      apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
> >      if (!apshift) {
> > @@ -123,23 +123,23 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> >      ptex = ptex & ~7ULL;
> >  
> >      if (likely((flags & H_EXACT) == 0)) {
> > -        token = ppc_hash64_start_access(cpu, ptex);
> > +        hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> >          for (slot = 0; slot < 8; slot++) {
> > -            if (!(ppc_hash64_load_hpte0(cpu, token, slot) & HPTE64_V_VALID)) {
> > +            if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
> >                  break;
> >              }
> >          }
> > -        ppc_hash64_stop_access(cpu, token);
> > +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
> >          if (slot == 8) {
> >              return H_PTEG_FULL;
> >          }
> >      } else {
> > -        token = ppc_hash64_start_access(cpu, ptex);
> > -        if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
> > -            ppc_hash64_stop_access(cpu, token);
> > +        hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
> > +        if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
> > +            ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
> >              return H_PTEG_FULL;
> >          }
> > -        ppc_hash64_stop_access(cpu, token);
> > +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> >      }
> >  
> >      ppc_hash64_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
> > @@ -160,17 +160,17 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex,
> >                                  target_ulong flags,
> >                                  target_ulong *vp, target_ulong *rp)
> >  {
> > -    uint64_t token;
> > +    const ppc_hash_pte64_t *hptes;
> >      target_ulong v, r;
> >  
> >      if (!valid_ptex(cpu, ptex)) {
> >          return REMOVE_PARM;
> >      }
> >  
> > -    token = ppc_hash64_start_access(cpu, ptex);
> > -    v = ppc_hash64_load_hpte0(cpu, token, 0);
> > -    r = ppc_hash64_load_hpte1(cpu, token, 0);
> > -    ppc_hash64_stop_access(cpu, token);
> > +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> > +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> > +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> > +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> >  
> >      if ((v & HPTE64_V_VALID) == 0 ||
> >          ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
> > @@ -291,17 +291,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> >      target_ulong flags = args[0];
> >      target_ulong ptex = args[1];
> >      target_ulong avpn = args[2];
> > -    uint64_t token;
> > +    const ppc_hash_pte64_t *hptes;
> >      target_ulong v, r;
> >  
> >      if (!valid_ptex(cpu, ptex)) {
> >          return H_PARAMETER;
> >      }
> >  
> > -    token = ppc_hash64_start_access(cpu, ptex);
> > -    v = ppc_hash64_load_hpte0(cpu, token, 0);
> > -    r = ppc_hash64_load_hpte1(cpu, token, 0);
> > -    ppc_hash64_stop_access(cpu, token);
> > +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> > +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> > +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> > +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> >  
> >      if ((v & HPTE64_V_VALID) == 0 ||
> >          ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index f99bcae..c89973e 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -223,11 +223,12 @@ enum {
> >  typedef struct opc_handler_t opc_handler_t;
> >  
> >  /*****************************************************************************/
> > -/* Types used to describe some PowerPC registers */
> > +/* Types used to describe some PowerPC registers etc. */
> >  typedef struct DisasContext DisasContext;
> >  typedef struct ppc_spr_t ppc_spr_t;
> >  typedef union ppc_avr_t ppc_avr_t;
> >  typedef union ppc_tlb_t ppc_tlb_t;
> > +typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
> >  
> >  /* SPR access micro-ops generations callbacks */
> >  struct ppc_spr_t {
> > diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> > index 52bbea5..9d3e57e 100644
> > --- a/target/ppc/kvm.c
> > +++ b/target/ppc/kvm.c
> > @@ -2601,17 +2601,17 @@ struct kvm_get_htab_buf {
> >      /*
> >       * We require one extra byte for read
> >       */
> > -    target_ulong hpte[(HPTES_PER_GROUP * 2) + 1];
> > +    ppc_hash_pte64_t hpte[HPTES_PER_GROUP];
> 
> 
> The "one extra byte" (which was ulong) is not needed any more why?

Ah.. good question.  A better one is why was it needed in the first
place, to which I don't have a good answer :/.

> 
> 
> >  };
> >  
> > -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
> > +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)
> 
> 
> This "int n" is ignored here by a reason?

Uh.. only by reason that I forgot to get around to handling that
properly.  Actually.. I rather suspect there are several things broken
with this function in any case (and equally it's predecessor) - I
think it will return bogus things if there are any invalid HPTEs in
the region read.

I think we're getting away with it because this interface is never
actually used: if we have KVM then we don't ever enter the MMU code
paths that could call this.  I should probably just change the KVM
mode hooks to abort()s.
> 
> 
> >  {
> >      int htab_fd;
> >      struct kvm_get_htab_fd ghf;
> > -    struct kvm_get_htab_buf  *hpte_buf;
> > +    struct kvm_get_htab_buf *hpte_buf;
> >  
> >      ghf.flags = 0;
> > -    ghf.start_index = pte_index;
> > +    ghf.start_index = ptex;
> >      htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
> >      if (htab_fd < 0) {
> >          goto error_out;
> > @@ -2626,7 +2626,7 @@ uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
> >      }
> >  
> >      close(htab_fd);
> > -    return (uint64_t)(uintptr_t) hpte_buf->hpte;
> > +    return hpte_buf->hpte;
> >  
> >  out_close:
> >      g_free(hpte_buf);
> > @@ -2635,18 +2635,15 @@ error_out:
> >      return 0;
> >  }
> >  
> > -void kvmppc_hash64_free_pteg(uint64_t token)
> > +void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex, int n)
> >  {
> >      struct kvm_get_htab_buf *htab_buf;
> >  
> > -    htab_buf = container_of((void *)(uintptr_t) token, struct kvm_get_htab_buf,
> > -                            hpte);
> > +    htab_buf = container_of((void *)hptes, struct kvm_get_htab_buf, hpte);
> >      g_free(htab_buf);
> > -    return;
> >  }
> >  
> > -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
> > -                             target_ulong pte0, target_ulong pte1)
> > +void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t pte1)
> >  {
> >      int htab_fd;
> >      struct kvm_get_htab_fd ghf;
> > @@ -2661,9 +2658,9 @@ void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
> >  
> >      hpte_buf.header.n_valid = 1;
> >      hpte_buf.header.n_invalid = 0;
> > -    hpte_buf.header.index = pte_index;
> > -    hpte_buf.hpte[0] = pte0;
> > -    hpte_buf.hpte[1] = pte1;
> > +    hpte_buf.header.index = ptex;
> > +    hpte_buf.hpte[0].pte0 = pte0;
> > +    hpte_buf.hpte[0].pte1 = pte1;
> >      /*
> >       * Write the hpte entry.
> >       * CAUTION: write() has the warn_unused_result attribute. Hence we
> > diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> > index 8da2ee4..3f8fccd 100644
> > --- a/target/ppc/kvm_ppc.h
> > +++ b/target/ppc/kvm_ppc.h
> > @@ -41,6 +41,10 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd,
> >  int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
> >  int kvmppc_reset_htab(int shift_hint);
> >  uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
> > +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n);
> > +void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex, int n);
> > +
> > +void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t pte1);
> >  #endif /* !CONFIG_USER_ONLY */
> >  bool kvmppc_has_cap_epr(void);
> >  int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function);
> > @@ -49,11 +53,6 @@ int kvmppc_get_htab_fd(bool write);
> >  int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns);
> >  int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
> >                             uint16_t n_valid, uint16_t n_invalid);
> > -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index);
> > -void kvmppc_hash64_free_pteg(uint64_t token);
> > -
> > -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
> > -                             target_ulong pte0, target_ulong pte1);
> >  bool kvmppc_has_cap_fixup_hcalls(void);
> >  bool kvmppc_has_cap_htm(void);
> >  int kvmppc_enable_hwrng(void);
> > @@ -199,6 +198,22 @@ static inline bool kvmppc_is_mem_backend_page_size_ok(char *obj_path)
> >      return true;
> >  }
> >  
> > +static inline const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)
> > +{
> > +    abort();
> > +}
> > +
> > +static inline void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes,
> > +                                      hwaddr ptex, int n)
> > +{
> > +    abort();
> > +}
> > +
> > +static inline void kvmppc_hash64_write_pte(hwaddr ptex,
> > +                                           uint64_t pte0, uint64_t pte1)
> > +{
> > +    abort();
> > +}
> >  #endif /* !CONFIG_USER_ONLY */
> >  
> >  static inline bool kvmppc_has_cap_epr(void)
> > @@ -234,24 +249,6 @@ static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
> >      abort();
> >  }
> >  
> > -static inline uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu,
> > -                                               target_ulong pte_index)
> > -{
> > -    abort();
> > -}
> > -
> > -static inline void kvmppc_hash64_free_pteg(uint64_t token)
> > -{
> > -    abort();
> > -}
> > -
> > -static inline void kvmppc_hash64_write_pte(CPUPPCState *env,
> > -                                           target_ulong pte_index,
> > -                                           target_ulong pte0, target_ulong pte1)
> > -{
> > -    abort();
> > -}
> > -
> >  static inline bool kvmppc_has_cap_fixup_hcalls(void)
> >  {
> >      abort();
> > diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> > index 76669ed..c59db47 100644
> > --- a/target/ppc/mmu-hash64.c
> > +++ b/target/ppc/mmu-hash64.c
> > @@ -27,6 +27,7 @@
> >  #include "kvm_ppc.h"
> >  #include "mmu-hash64.h"
> >  #include "exec/log.h"
> > +#include "hw/hw.h"
> >  
> >  //#define DEBUG_SLB
> >  
> > @@ -431,33 +432,42 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
> >      return prot;
> >  }
> >  
> > -uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
> > +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
> > +                                             hwaddr ptex, int n)
> >  {
> > -    uint64_t token = 0;
> > -    hwaddr pte_offset;
> > +    const ppc_hash_pte64_t *hptes = NULL;
> > +    hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
> >  
> > -    pte_offset = pte_index * HASH_PTE_SIZE_64;
> >      if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> >          /*
> >           * HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
> >           */
> > -        token = kvmppc_hash64_read_pteg(cpu, pte_index);
> > +        hptes = kvmppc_map_hptes(ptex, n);
> >      } else if (cpu->env.external_htab) {
> >          /*
> >           * HTAB is controlled by QEMU. Just point to the internally
> >           * accessible PTEG.
> >           */
> > -        token = (uint64_t)(uintptr_t) cpu->env.external_htab + pte_offset;
> > +        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
> >      } else if (cpu->env.htab_base) {
> > -        token = cpu->env.htab_base + pte_offset;
> > +        hwaddr plen = n * HASH_PTE_SIZE_64;
> > +        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base + pte_offset,
> > +                                 &plen, false);
> > +        if (plen < (n * HASH_PTE_SIZE_64)) {
> > +            hw_error("%s: Unable to map all requested HPTEs\n", __FUNCTION__);
> > +        }
> >      }
> > -    return token;
> > +    return hptes;
> >  }
> >  
> > -void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token)
> > +void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
> > +                            hwaddr ptex, int n)
> >  {
> >      if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> > -        kvmppc_hash64_free_pteg(token);
> > +        kvmppc_unmap_hptes(hptes, ptex, n);
> > +    } else if (!cpu->env.external_htab) {
> > +        address_space_unmap(CPU(cpu)->as, (void *)hptes, n * HASH_PTE_SIZE_64,
> > +                            false, n * HASH_PTE_SIZE_64);
> >      }
> >  }
> >  
> > @@ -505,18 +515,18 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
> >  {
> >      CPUPPCState *env = &cpu->env;
> >      int i;
> > -    uint64_t token;
> > +    const ppc_hash_pte64_t *pteg;
> >      target_ulong pte0, pte1;
> > -    target_ulong pte_index;
> > +    target_ulong ptex;
> >  
> > -    pte_index = (hash & env->htab_mask) * HPTES_PER_GROUP;
> > -    token = ppc_hash64_start_access(cpu, pte_index);
> > -    if (!token) {
> > +    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> > +    pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> > +    if (!pteg) {
> >          return -1;
> >      }
> >      for (i = 0; i < HPTES_PER_GROUP; i++) {
> > -        pte0 = ppc_hash64_load_hpte0(cpu, token, i);
> > -        pte1 = ppc_hash64_load_hpte1(cpu, token, i);
> > +        pte0 = ppc_hash64_hpte0(cpu, pteg, i);
> > +        pte1 = ppc_hash64_hpte1(cpu, pteg, i);
> >  
> >          /* This compares V, B, H (secondary) and the AVPN */
> >          if (HPTE64_V_COMPARE(pte0, ptem)) {
> > @@ -536,11 +546,11 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
> >               */
> >              pte->pte0 = pte0;
> >              pte->pte1 = pte1;
> > -            ppc_hash64_stop_access(cpu, token);
> > -            return (pte_index + i) * HASH_PTE_SIZE_64;
> > +            ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
> > +            return ptex + i;
> >          }
> >      }
> > -    ppc_hash64_stop_access(cpu, token);
> > +    ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
> >      /*
> >       * We didn't find a valid entry.
> >       */
> > @@ -552,8 +562,7 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
> >                                       ppc_hash_pte64_t *pte, unsigned *pshift)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > -    hwaddr pte_offset;
> > -    hwaddr hash;
> > +    hwaddr hash, ptex;
> >      uint64_t vsid, epnmask, epn, ptem;
> >      const struct ppc_one_seg_page_size *sps = slb->sps;
> >  
> > @@ -596,9 +605,9 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
> >              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
> >              " hash=" TARGET_FMT_plx "\n",
> >              env->htab_base, env->htab_mask, vsid, ptem,  hash);
> > -    pte_offset = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
> > +    ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
> >  
> > -    if (pte_offset == -1) {
> > +    if (ptex == -1) {
> >          /* Secondary PTEG lookup */
> >          ptem |= HPTE64_V_SECONDARY;
> >          qemu_log_mask(CPU_LOG_MMU,
> > @@ -607,10 +616,10 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
> >                  " hash=" TARGET_FMT_plx "\n", env->htab_base,
> >                  env->htab_mask, vsid, ptem, ~hash);
> >  
> > -        pte_offset = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
> > +        ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
> >      }
> >  
> > -    return pte_offset;
> > +    return ptex;
> >  }
> >  
> >  unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
> > @@ -708,7 +717,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
> >      CPUPPCState *env = &cpu->env;
> >      ppc_slb_t *slb;
> >      unsigned apshift;
> > -    hwaddr pte_offset;
> > +    hwaddr ptex;
> >      ppc_hash_pte64_t pte;
> >      int pp_prot, amr_prot, prot;
> >      uint64_t new_pte1, dsisr;
> > @@ -792,8 +801,8 @@ skip_slb_search:
> >      }
> >  
> >      /* 4. Locate the PTE in the hash table */
> > -    pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
> > -    if (pte_offset == -1) {
> > +    ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
> > +    if (ptex == -1) {
> >          dsisr = 0x40000000;
> >          if (rwx == 2) {
> >              ppc_hash64_set_isi(cs, env, dsisr);
> > @@ -806,7 +815,7 @@ skip_slb_search:
> >          return 1;
> >      }
> >      qemu_log_mask(CPU_LOG_MMU,
> > -                "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
> > +                  "found PTE at index %08" HWADDR_PRIx "\n", ptex);
> >  
> >      /* 5. Check access permissions */
> >  
> > @@ -849,8 +858,7 @@ skip_slb_search:
> >      }
> >  
> >      if (new_pte1 != pte.pte1) {
> > -        ppc_hash64_store_hpte(cpu, pte_offset / HASH_PTE_SIZE_64,
> > -                              pte.pte0, new_pte1);
> > +        ppc_hash64_store_hpte(cpu, ptex, pte.pte0, new_pte1);
> >      }
> >  
> >      /* 7. Determine the real address from the PTE */
> > @@ -867,7 +875,7 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
> >  {
> >      CPUPPCState *env = &cpu->env;
> >      ppc_slb_t *slb;
> > -    hwaddr pte_offset, raddr;
> > +    hwaddr ptex, raddr;
> >      ppc_hash_pte64_t pte;
> >      unsigned apshift;
> >  
> > @@ -900,8 +908,8 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
> >          }
> >      }
> >  
> > -    pte_offset = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
> > -    if (pte_offset == -1) {
> > +    ptex = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
> > +    if (ptex == -1) {
> >          return -1;
> >      }
> >  
> > @@ -909,30 +917,28 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
> >          & TARGET_PAGE_MASK;
> >  }
> >  
> > -void ppc_hash64_store_hpte(PowerPCCPU *cpu,
> > -                           target_ulong pte_index,
> > -                           target_ulong pte0, target_ulong pte1)
> > +void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> > +                           uint64_t pte0, uint64_t pte1)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    hwaddr offset = ptex * HASH_PTE_SIZE_64;
> >  
> >      if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> > -        kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
> > +        kvmppc_hash64_write_pte(ptex, pte0, pte1);
> >          return;
> >      }
> >  
> > -    pte_index *= HASH_PTE_SIZE_64;
> >      if (env->external_htab) {
> > -        stq_p(env->external_htab + pte_index, pte0);
> > -        stq_p(env->external_htab + pte_index + HASH_PTE_SIZE_64 / 2, pte1);
> > +        stq_p(env->external_htab + offset, pte0);
> > +        stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
> >      } else {
> > -        stq_phys(CPU(cpu)->as, env->htab_base + pte_index, pte0);
> > +        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
> >          stq_phys(CPU(cpu)->as,
> > -                 env->htab_base + pte_index + HASH_PTE_SIZE_64 / 2, pte1);
> > +                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2, pte1);
> >      }
> >  }
> >  
> > -void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
> > -                               target_ulong pte_index,
> > +void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
> >                                 target_ulong pte0, target_ulong pte1)
> >  {
> >      /*
> > diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> > index 7a0b7fc..8637fe4 100644
> > --- a/target/ppc/mmu-hash64.h
> > +++ b/target/ppc/mmu-hash64.h
> > @@ -10,8 +10,8 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot,
> >  hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr);
> >  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
> >                                  int mmu_idx);
> > -void ppc_hash64_store_hpte(PowerPCCPU *cpu, target_ulong index,
> > -                           target_ulong pte0, target_ulong pte1);
> > +void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> > +                           uint64_t pte0, uint64_t pte1);
> >  void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
> >                                 target_ulong pte_index,
> >                                 target_ulong pte0, target_ulong pte1);
> > @@ -96,41 +96,27 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
> >  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
> >                                   Error **errp);
> >  
> > -uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index);
> > -void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token);
> > +struct ppc_hash_pte64 {
> > +    uint64_t pte0, pte1;
> > +};
> > +
> > +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,\
> 
> 
> You do not need the trailing '\'.
> 
> 
> > +                                             hwaddr ptex, int n);
> > +void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
> > +                            hwaddr ptex, int n);
> >  
> > -static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
> > -                                                 uint64_t token, int index)
> > +static inline uint64_t ppc_hash64_hpte0(PowerPCCPU *cpu,
> > +                                        const ppc_hash_pte64_t *hptes, int i)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> > -    uint64_t addr;
> > -
> > -    addr = token + (index * HASH_PTE_SIZE_64);
> > -    if (env->external_htab) {
> > -        return  ldq_p((const void *)(uintptr_t)addr);
> > -    } else {
> > -        return ldq_phys(CPU(cpu)->as, addr);
> > -    }
> > +    return ldq_p(&(hptes[i].pte0));
> >  }
> >  
> > -static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu,
> > -                                                 uint64_t token, int index)
> > +static inline uint64_t ppc_hash64_hpte1(PowerPCCPU *cpu,
> > +                                        const ppc_hash_pte64_t *hptes, int i)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> > -    uint64_t addr;
> > -
> > -    addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
> > -    if (env->external_htab) {
> > -        return  ldq_p((const void *)(uintptr_t)addr);
> > -    } else {
> > -        return ldq_phys(CPU(cpu)->as, addr);
> > -    }
> > +    return ldq_p(&(hptes[i].pte1));
> >  }
> >  
> > -typedef struct {
> > -    uint64_t pte0, pte1;
> > -} ppc_hash_pte64_t;
> > -
> >  #endif /* CONFIG_USER_ONLY */
> >  
> >  #endif /* MMU_HASH64_H */
> > 
> 
> 

-- 
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: 819 bytes --]

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

* Re: [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU David Gibson
  2017-02-23  5:02   ` Alexey Kardashevskiy
@ 2017-02-23  5:37   ` Suraj Jitindar Singh
  2017-02-24  5:25     ` David Gibson
  1 sibling, 1 reply; 22+ messages in thread
From: Suraj Jitindar Singh @ 2017-02-23  5:37 UTC (permalink / raw)
  To: David Gibson, qemu-ppc, aik
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus

On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> Accesses to the hashed page table (HPT) are complicated by the fact
> that
> the HPT could be in one of three places:
>    1) Within guest memory - when we're emulating a full guest CPU at
> the
>       hardware level (e.g. powernv, mac99, g3beige)
>    2) Within qemu, but outside guest memory - when we're emulating
> user and
>       supervisor instructions within TCG, but instead of emulating
>       the CPU's hypervisor mode, we just emulate a hypervisor's
> behaviour
>       (pseries in TCG)
>    3) Within KVM - a pseries machine using KVM acceleration.  Mostly
>       accesses to the HPT are handled by KVM, but there are a few
> cases
>       where qemu needs to access it via a special fd for the purpose.

Should you clarify that this is the case for KVM-HV with KVM-PR the
same as (2)?

> 
> In order to batch accesses to the fd in case (3), we use a somewhat
> awkward
> ppc_hash64_start_access() / ppc_hash64_stop_access() pair, which for
> case
> (3) reads / releases a whole PTEG from the kernel.  For cases (1) &
> (2)
> it just returns an address value.  The actual HPTE load helpers then
> need
> to interpret the returned token differently in the 3 cases.
> 
> This patch keeps the same basic structure, but simplfiies the
> details.
> First start_access() / stop_access() are renamed to get_pteg() and
> put_pteg() to make their operation more obvious.  Second, read_pteg()

Here you say they've been renamed to get/put/read_pteg, but in the code
they're called map/unmap_hptes and it looks like map_hptes does both
the get and the read?

> now
> always returns a qemu pointer, which can always be used in the same
> way
> by the load_hpte() helpers.  In case (1) it comes from
> address_space_map()
> in case (2) directly from qemu's HPT buffer and in case (3) from a
> temporary buffer read from the KVM fd.
> 
> While we're at it, make things a bit more consistent in terms of
> types and
> variable names: avoid variables named 'index' (it shadows index(3)
> which
> can lead to confusing results), use 'hwaddr ptex' for HPTE indices
> and
> uint64_t for each of the HPTE words, use ptex throughout the call
> stack
> instead of pte_offset in some places (we still need that at the
> bottom
> layer, but nowhere else).
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Other than the commit message:

Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>

> ---
>  hw/ppc/spapr_hcall.c    | 36 +++++++++---------
>  target/ppc/cpu.h        |  3 +-
>  target/ppc/kvm.c        | 25 ++++++-------
>  target/ppc/kvm_ppc.h    | 43 ++++++++++------------
>  target/ppc/mmu-hash64.c | 98 ++++++++++++++++++++++++++-------------
> ----------
>  target/ppc/mmu-hash64.h | 46 ++++++++---------------
>  6 files changed, 119 insertions(+), 132 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 3298a14..fd961b5 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -84,7 +84,7 @@ static target_ulong h_enter(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>      unsigned apshift;
>      target_ulong raddr;
>      target_ulong slot;
> -    uint64_t token;
> +    const ppc_hash_pte64_t *hptes;
>  
>      apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
>      if (!apshift) {
> @@ -123,23 +123,23 @@ static target_ulong h_enter(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>      ptex = ptex & ~7ULL;
>  
>      if (likely((flags & H_EXACT) == 0)) {
> -        token = ppc_hash64_start_access(cpu, ptex);
> +        hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
>          for (slot = 0; slot < 8; slot++) {
> -            if (!(ppc_hash64_load_hpte0(cpu, token, slot) &
> HPTE64_V_VALID)) {
> +            if (!(ppc_hash64_hpte0(cpu, hptes, slot) &
> HPTE64_V_VALID)) {
>                  break;
>              }
>          }
> -        ppc_hash64_stop_access(cpu, token);
> +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
>          if (slot == 8) {
>              return H_PTEG_FULL;
>          }
>      } else {
> -        token = ppc_hash64_start_access(cpu, ptex);
> -        if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
> -            ppc_hash64_stop_access(cpu, token);
> +        hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
> +        if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
> +            ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
>              return H_PTEG_FULL;
>          }
> -        ppc_hash64_stop_access(cpu, token);
> +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
>      }
>  
>      ppc_hash64_store_hpte(cpu, ptex + slot, pteh |
> HPTE64_V_HPTE_DIRTY, ptel);
> @@ -160,17 +160,17 @@ static RemoveResult remove_hpte(PowerPCCPU
> *cpu, target_ulong ptex,
>                                  target_ulong flags,
>                                  target_ulong *vp, target_ulong *rp)
>  {
> -    uint64_t token;
> +    const ppc_hash_pte64_t *hptes;
>      target_ulong v, r;
>  
>      if (!valid_ptex(cpu, ptex)) {
>          return REMOVE_PARM;
>      }
>  
> -    token = ppc_hash64_start_access(cpu, ptex);
> -    v = ppc_hash64_load_hpte0(cpu, token, 0);
> -    r = ppc_hash64_load_hpte1(cpu, token, 0);
> -    ppc_hash64_stop_access(cpu, token);
> +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
>  
>      if ((v & HPTE64_V_VALID) == 0 ||
>          ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
> @@ -291,17 +291,17 @@ static target_ulong h_protect(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>      target_ulong flags = args[0];
>      target_ulong ptex = args[1];
>      target_ulong avpn = args[2];
> -    uint64_t token;
> +    const ppc_hash_pte64_t *hptes;
>      target_ulong v, r;
>  
>      if (!valid_ptex(cpu, ptex)) {
>          return H_PARAMETER;
>      }
>  
> -    token = ppc_hash64_start_access(cpu, ptex);
> -    v = ppc_hash64_load_hpte0(cpu, token, 0);
> -    r = ppc_hash64_load_hpte1(cpu, token, 0);
> -    ppc_hash64_stop_access(cpu, token);
> +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
>  
>      if ((v & HPTE64_V_VALID) == 0 ||
>          ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index f99bcae..c89973e 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -223,11 +223,12 @@ enum {
>  typedef struct opc_handler_t opc_handler_t;
>  
>  /*******************************************************************
> **********/
> -/* Types used to describe some PowerPC registers */
> +/* Types used to describe some PowerPC registers etc. */
>  typedef struct DisasContext DisasContext;
>  typedef struct ppc_spr_t ppc_spr_t;
>  typedef union ppc_avr_t ppc_avr_t;
>  typedef union ppc_tlb_t ppc_tlb_t;
> +typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
>  
>  /* SPR access micro-ops generations callbacks */
>  struct ppc_spr_t {
> diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> index 52bbea5..9d3e57e 100644
> --- a/target/ppc/kvm.c
> +++ b/target/ppc/kvm.c
> @@ -2601,17 +2601,17 @@ struct kvm_get_htab_buf {
>      /*
>       * We require one extra byte for read
>       */
> -    target_ulong hpte[(HPTES_PER_GROUP * 2) + 1];
> +    ppc_hash_pte64_t hpte[HPTES_PER_GROUP];
>  };
>  
> -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong
> pte_index)
> +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)
>  {
>      int htab_fd;
>      struct kvm_get_htab_fd ghf;
> -    struct kvm_get_htab_buf  *hpte_buf;
> +    struct kvm_get_htab_buf *hpte_buf;
>  
>      ghf.flags = 0;
> -    ghf.start_index = pte_index;
> +    ghf.start_index = ptex;
>      htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
>      if (htab_fd < 0) {
>          goto error_out;
> @@ -2626,7 +2626,7 @@ uint64_t kvmppc_hash64_read_pteg(PowerPCCPU
> *cpu, target_ulong pte_index)
>      }
>  
>      close(htab_fd);
> -    return (uint64_t)(uintptr_t) hpte_buf->hpte;
> +    return hpte_buf->hpte;
>  
>  out_close:
>      g_free(hpte_buf);
> @@ -2635,18 +2635,15 @@ error_out:
>      return 0;
>  }
>  
> -void kvmppc_hash64_free_pteg(uint64_t token)
> +void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex,
> int n)
>  {
>      struct kvm_get_htab_buf *htab_buf;
>  
> -    htab_buf = container_of((void *)(uintptr_t) token, struct
> kvm_get_htab_buf,
> -                            hpte);
> +    htab_buf = container_of((void *)hptes, struct kvm_get_htab_buf,
> hpte);
>      g_free(htab_buf);
> -    return;
>  }
>  
> -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong
> pte_index,
> -                             target_ulong pte0, target_ulong pte1)
> +void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t
> pte1)
>  {
>      int htab_fd;
>      struct kvm_get_htab_fd ghf;
> @@ -2661,9 +2658,9 @@ void kvmppc_hash64_write_pte(CPUPPCState *env,
> target_ulong pte_index,
>  
>      hpte_buf.header.n_valid = 1;
>      hpte_buf.header.n_invalid = 0;
> -    hpte_buf.header.index = pte_index;
> -    hpte_buf.hpte[0] = pte0;
> -    hpte_buf.hpte[1] = pte1;
> +    hpte_buf.header.index = ptex;
> +    hpte_buf.hpte[0].pte0 = pte0;
> +    hpte_buf.hpte[0].pte1 = pte1;
>      /*
>       * Write the hpte entry.
>       * CAUTION: write() has the warn_unused_result attribute. Hence
> we
> diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> index 8da2ee4..3f8fccd 100644
> --- a/target/ppc/kvm_ppc.h
> +++ b/target/ppc/kvm_ppc.h
> @@ -41,6 +41,10 @@ void *kvmppc_create_spapr_tce(uint32_t liobn,
> uint32_t window_size, int *pfd,
>  int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t
> window_size);
>  int kvmppc_reset_htab(int shift_hint);
>  uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int
> hash_shift);
> +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n);
> +void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex,
> int n);
> +
> +void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t
> pte1);
>  #endif /* !CONFIG_USER_ONLY */
>  bool kvmppc_has_cap_epr(void);
>  int kvmppc_define_rtas_kernel_token(uint32_t token, const char
> *function);
> @@ -49,11 +53,6 @@ int kvmppc_get_htab_fd(bool write);
>  int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t
> max_ns);
>  int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
>                             uint16_t n_valid, uint16_t n_invalid);
> -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong
> pte_index);
> -void kvmppc_hash64_free_pteg(uint64_t token);
> -
> -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong
> pte_index,
> -                             target_ulong pte0, target_ulong pte1);
>  bool kvmppc_has_cap_fixup_hcalls(void);
>  bool kvmppc_has_cap_htm(void);
>  int kvmppc_enable_hwrng(void);
> @@ -199,6 +198,22 @@ static inline bool
> kvmppc_is_mem_backend_page_size_ok(char *obj_path)
>      return true;
>  }
>  
> +static inline const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex,
> int n)
> +{
> +    abort();
> +}
> +
> +static inline void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes,
> +                                      hwaddr ptex, int n)
> +{
> +    abort();
> +}
> +
> +static inline void kvmppc_hash64_write_pte(hwaddr ptex,
> +                                           uint64_t pte0, uint64_t
> pte1)
> +{
> +    abort();
> +}
>  #endif /* !CONFIG_USER_ONLY */
>  
>  static inline bool kvmppc_has_cap_epr(void)
> @@ -234,24 +249,6 @@ static inline int
> kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
>      abort();
>  }
>  
> -static inline uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu,
> -                                               target_ulong
> pte_index)
> -{
> -    abort();
> -}
> -
> -static inline void kvmppc_hash64_free_pteg(uint64_t token)
> -{
> -    abort();
> -}
> -
> -static inline void kvmppc_hash64_write_pte(CPUPPCState *env,
> -                                           target_ulong pte_index,
> -                                           target_ulong pte0,
> target_ulong pte1)
> -{
> -    abort();
> -}
> -
>  static inline bool kvmppc_has_cap_fixup_hcalls(void)
>  {
>      abort();
> diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> index 76669ed..c59db47 100644
> --- a/target/ppc/mmu-hash64.c
> +++ b/target/ppc/mmu-hash64.c
> @@ -27,6 +27,7 @@
>  #include "kvm_ppc.h"
>  #include "mmu-hash64.h"
>  #include "exec/log.h"
> +#include "hw/hw.h"
>  
>  //#define DEBUG_SLB
>  
> @@ -431,33 +432,42 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu,
> ppc_hash_pte64_t pte)
>      return prot;
>  }
>  
> -uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong
> pte_index)
> +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
> +                                             hwaddr ptex, int n)
>  {
> -    uint64_t token = 0;
> -    hwaddr pte_offset;
> +    const ppc_hash_pte64_t *hptes = NULL;
> +    hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
>  
> -    pte_offset = pte_index * HASH_PTE_SIZE_64;
>      if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
>          /*
>           * HTAB is controlled by KVM. Fetch the PTEG into a new
> buffer.
>           */
> -        token = kvmppc_hash64_read_pteg(cpu, pte_index);
> +        hptes = kvmppc_map_hptes(ptex, n);
>      } else if (cpu->env.external_htab) {
>          /*
>           * HTAB is controlled by QEMU. Just point to the internally
>           * accessible PTEG.
>           */
> -        token = (uint64_t)(uintptr_t) cpu->env.external_htab +
> pte_offset;
> +        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab +
> pte_offset);
>      } else if (cpu->env.htab_base) {
> -        token = cpu->env.htab_base + pte_offset;
> +        hwaddr plen = n * HASH_PTE_SIZE_64;
> +        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base +
> pte_offset,
> +                                 &plen, false);
> +        if (plen < (n * HASH_PTE_SIZE_64)) {
> +            hw_error("%s: Unable to map all requested HPTEs\n",
> __FUNCTION__);
> +        }
>      }
> -    return token;
> +    return hptes;
>  }
>  
> -void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token)
> +void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t
> *hptes,
> +                            hwaddr ptex, int n)
>  {
>      if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> -        kvmppc_hash64_free_pteg(token);
> +        kvmppc_unmap_hptes(hptes, ptex, n);
> +    } else if (!cpu->env.external_htab) {
> +        address_space_unmap(CPU(cpu)->as, (void *)hptes, n *
> HASH_PTE_SIZE_64,
> +                            false, n * HASH_PTE_SIZE_64);
>      }
>  }
>  
> @@ -505,18 +515,18 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU
> *cpu, hwaddr hash,
>  {
>      CPUPPCState *env = &cpu->env;
>      int i;
> -    uint64_t token;
> +    const ppc_hash_pte64_t *pteg;
>      target_ulong pte0, pte1;
> -    target_ulong pte_index;
> +    target_ulong ptex;
>  
> -    pte_index = (hash & env->htab_mask) * HPTES_PER_GROUP;
> -    token = ppc_hash64_start_access(cpu, pte_index);
> -    if (!token) {
> +    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> +    pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> +    if (!pteg) {
>          return -1;
>      }
>      for (i = 0; i < HPTES_PER_GROUP; i++) {
> -        pte0 = ppc_hash64_load_hpte0(cpu, token, i);
> -        pte1 = ppc_hash64_load_hpte1(cpu, token, i);
> +        pte0 = ppc_hash64_hpte0(cpu, pteg, i);
> +        pte1 = ppc_hash64_hpte1(cpu, pteg, i);
>  
>          /* This compares V, B, H (secondary) and the AVPN */
>          if (HPTE64_V_COMPARE(pte0, ptem)) {
> @@ -536,11 +546,11 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU
> *cpu, hwaddr hash,
>               */
>              pte->pte0 = pte0;
>              pte->pte1 = pte1;
> -            ppc_hash64_stop_access(cpu, token);
> -            return (pte_index + i) * HASH_PTE_SIZE_64;
> +            ppc_hash64_unmap_hptes(cpu, pteg, ptex,
> HPTES_PER_GROUP);
> +            return ptex + i;
>          }
>      }
> -    ppc_hash64_stop_access(cpu, token);
> +    ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
>      /*
>       * We didn't find a valid entry.
>       */
> @@ -552,8 +562,7 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> *cpu,
>                                       ppc_hash_pte64_t *pte, unsigned
> *pshift)
>  {
>      CPUPPCState *env = &cpu->env;
> -    hwaddr pte_offset;
> -    hwaddr hash;
> +    hwaddr hash, ptex;
>      uint64_t vsid, epnmask, epn, ptem;
>      const struct ppc_one_seg_page_size *sps = slb->sps;
>  
> @@ -596,9 +605,9 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> *cpu,
>              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
>              " hash=" TARGET_FMT_plx "\n",
>              env->htab_base, env->htab_mask, vsid, ptem,  hash);
> -    pte_offset = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte,
> pshift);
> +    ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte,
> pshift);
>  
> -    if (pte_offset == -1) {
> +    if (ptex == -1) {
>          /* Secondary PTEG lookup */
>          ptem |= HPTE64_V_SECONDARY;
>          qemu_log_mask(CPU_LOG_MMU,
> @@ -607,10 +616,10 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> *cpu,
>                  " hash=" TARGET_FMT_plx "\n", env->htab_base,
>                  env->htab_mask, vsid, ptem, ~hash);
>  
> -        pte_offset = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem,
> pte, pshift);
> +        ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte,
> pshift);
>      }
>  
> -    return pte_offset;
> +    return ptex;
>  }
>  
>  unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
> @@ -708,7 +717,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
> vaddr eaddr,
>      CPUPPCState *env = &cpu->env;
>      ppc_slb_t *slb;
>      unsigned apshift;
> -    hwaddr pte_offset;
> +    hwaddr ptex;
>      ppc_hash_pte64_t pte;
>      int pp_prot, amr_prot, prot;
>      uint64_t new_pte1, dsisr;
> @@ -792,8 +801,8 @@ skip_slb_search:
>      }
>  
>      /* 4. Locate the PTE in the hash table */
> -    pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte,
> &apshift);
> -    if (pte_offset == -1) {
> +    ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
> +    if (ptex == -1) {
>          dsisr = 0x40000000;
>          if (rwx == 2) {
>              ppc_hash64_set_isi(cs, env, dsisr);
> @@ -806,7 +815,7 @@ skip_slb_search:
>          return 1;
>      }
>      qemu_log_mask(CPU_LOG_MMU,
> -                "found PTE at offset %08" HWADDR_PRIx "\n",
> pte_offset);
> +                  "found PTE at index %08" HWADDR_PRIx "\n", ptex);
>  
>      /* 5. Check access permissions */
>  
> @@ -849,8 +858,7 @@ skip_slb_search:
>      }
>  
>      if (new_pte1 != pte.pte1) {
> -        ppc_hash64_store_hpte(cpu, pte_offset / HASH_PTE_SIZE_64,
> -                              pte.pte0, new_pte1);
> +        ppc_hash64_store_hpte(cpu, ptex, pte.pte0, new_pte1);
>      }
>  
>      /* 7. Determine the real address from the PTE */
> @@ -867,7 +875,7 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU
> *cpu, target_ulong addr)
>  {
>      CPUPPCState *env = &cpu->env;
>      ppc_slb_t *slb;
> -    hwaddr pte_offset, raddr;
> +    hwaddr ptex, raddr;
>      ppc_hash_pte64_t pte;
>      unsigned apshift;
>  
> @@ -900,8 +908,8 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU
> *cpu, target_ulong addr)
>          }
>      }
>  
> -    pte_offset = ppc_hash64_htab_lookup(cpu, slb, addr, &pte,
> &apshift);
> -    if (pte_offset == -1) {
> +    ptex = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
> +    if (ptex == -1) {
>          return -1;
>      }
>  
> @@ -909,30 +917,28 @@ hwaddr
> ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
>          & TARGET_PAGE_MASK;
>  }
>  
> -void ppc_hash64_store_hpte(PowerPCCPU *cpu,
> -                           target_ulong pte_index,
> -                           target_ulong pte0, target_ulong pte1)
> +void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> +                           uint64_t pte0, uint64_t pte1)
>  {
>      CPUPPCState *env = &cpu->env;
> +    hwaddr offset = ptex * HASH_PTE_SIZE_64;
>  
>      if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> -        kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
> +        kvmppc_hash64_write_pte(ptex, pte0, pte1);
>          return;
>      }
>  
> -    pte_index *= HASH_PTE_SIZE_64;
>      if (env->external_htab) {
> -        stq_p(env->external_htab + pte_index, pte0);
> -        stq_p(env->external_htab + pte_index + HASH_PTE_SIZE_64 / 2,
> pte1);
> +        stq_p(env->external_htab + offset, pte0);
> +        stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2,
> pte1);
>      } else {
> -        stq_phys(CPU(cpu)->as, env->htab_base + pte_index, pte0);
> +        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
>          stq_phys(CPU(cpu)->as,
> -                 env->htab_base + pte_index + HASH_PTE_SIZE_64 / 2,
> pte1);
> +                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2,
> pte1);
>      }
>  }
>  
> -void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
> -                               target_ulong pte_index,
> +void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
>                                 target_ulong pte0, target_ulong pte1)
>  {
>      /*
> diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> index 7a0b7fc..8637fe4 100644
> --- a/target/ppc/mmu-hash64.h
> +++ b/target/ppc/mmu-hash64.h
> @@ -10,8 +10,8 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong
> slot,
>  hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong
> addr);
>  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int
> rw,
>                                  int mmu_idx);
> -void ppc_hash64_store_hpte(PowerPCCPU *cpu, target_ulong index,
> -                           target_ulong pte0, target_ulong pte1);
> +void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> +                           uint64_t pte0, uint64_t pte1);
>  void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
>                                 target_ulong pte_index,
>                                 target_ulong pte0, target_ulong
> pte1);
> @@ -96,41 +96,27 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu,
> target_ulong value,
>  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> shift,
>                                   Error **errp);
>  
> -uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong
> pte_index);
> -void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token);
> +struct ppc_hash_pte64 {
> +    uint64_t pte0, pte1;
> +};
> +
> +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,\
> +                                             hwaddr ptex, int n);
> +void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t
> *hptes,
> +                            hwaddr ptex, int n);
>  
> -static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
> -                                                 uint64_t token, int
> index)
> +static inline uint64_t ppc_hash64_hpte0(PowerPCCPU *cpu,
> +                                        const ppc_hash_pte64_t
> *hptes, int i)
>  {
> -    CPUPPCState *env = &cpu->env;
> -    uint64_t addr;
> -
> -    addr = token + (index * HASH_PTE_SIZE_64);
> -    if (env->external_htab) {
> -        return  ldq_p((const void *)(uintptr_t)addr);
> -    } else {
> -        return ldq_phys(CPU(cpu)->as, addr);
> -    }
> +    return ldq_p(&(hptes[i].pte0));
>  }
>  
> -static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu,
> -                                                 uint64_t token, int
> index)
> +static inline uint64_t ppc_hash64_hpte1(PowerPCCPU *cpu,
> +                                        const ppc_hash_pte64_t
> *hptes, int i)
>  {
> -    CPUPPCState *env = &cpu->env;
> -    uint64_t addr;
> -
> -    addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
> -    if (env->external_htab) {
> -        return  ldq_p((const void *)(uintptr_t)addr);
> -    } else {
> -        return ldq_phys(CPU(cpu)->as, addr);
> -    }
> +    return ldq_p(&(hptes[i].pte1));
>  }
>  
> -typedef struct {
> -    uint64_t pte0, pte1;
> -} ppc_hash_pte64_t;
> -
>  #endif /* CONFIG_USER_ONLY */
>  
>  #endif /* MMU_HASH64_H */

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

* Re: [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables David Gibson
@ 2017-02-23  5:43   ` Alexey Kardashevskiy
  2017-02-24  5:30     ` David Gibson
  2017-02-23  5:52   ` Suraj Jitindar Singh
  1 sibling, 1 reply; 22+ messages in thread
From: Alexey Kardashevskiy @ 2017-02-23  5:43 UTC (permalink / raw)
  To: David Gibson, qemu-ppc, sjitindarsingh
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus

On 23/02/17 13:09, David Gibson wrote:
> CPUPPCState includes fields htab_base and htab_mask which store the base
> address (GPA) and size (as a mask) of the guest's hashed page table (HPT).
> These are set when the SDR1 register is updated.
> 
> Keeping these in sync with the SDR1 is actually a little bit fiddly, and
> probably not useful for performance, since keeping them expands the size of
> CPUPPCState.  It also makes some upcoming changes harder to implement.
> 
> This patch removes these fields, in favour of calculating them directly
> from the SDR1 contents when necessary.
> 
> This does make a change to the behaviour of attempting to write a bad value
> (invalid HPT size) to the SDR1 with an mtspr instruction.  Previously, the
> bad value would be stored in SDR1 and could be retrieved with a later
> mfspr, but the HPT size as used by the softmmu would be, clamped to the
> allowed values.  Now, writing a bad value is treated as a no-op.  An error
> message is printed in both new and old versions.
> 
> I'm not sure which behaviour, if either, matches real hardware.  I don't
> think it matters that much, since it's pretty clear that if an OS writes
> a bad value to SDR1, it's not going to boot.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr_hcall.c    |  4 ++--
>  target/ppc/cpu.h        |  8 --------
>  target/ppc/machine.c    |  1 -
>  target/ppc/mmu-hash32.c | 14 +++++++-------
>  target/ppc/mmu-hash32.h | 24 ++++++++++++++++++------
>  target/ppc/mmu-hash64.c | 37 ++++++++++++++++---------------------
>  target/ppc/mmu-hash64.h | 13 +++++++++++++
>  target/ppc/mmu_helper.c | 31 ++++++++++++++++---------------
>  8 files changed, 72 insertions(+), 60 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index fd961b5..85d96f6 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -50,9 +50,9 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
>  static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
>  {
>      /*
> -     * hash value/pteg group index is normalized by htab_mask
> +     * hash value/pteg group index is normalized by HPT mask
>       */
> -    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) {
> +    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) {
>          return false;
>      }
>      return true;
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index c89973e..c6cd9ab 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -309,11 +309,6 @@ union ppc_tlb_t {
>  #define SDR_32_HTABORG         0xFFFF0000UL
>  #define SDR_32_HTABMASK        0x000001FFUL


You could move these to target/ppc/mmu-hash32.h as well.


Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>




>  
> -#if defined(TARGET_PPC64)
> -#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> -#define SDR_64_HTABSIZE        0x000000000000001FULL
> -#endif /* defined(TARGET_PPC64 */
> -
>  typedef struct ppc_slb_t ppc_slb_t;
>  struct ppc_slb_t {
>      uint64_t esid;
> @@ -1006,9 +1001,6 @@ struct CPUPPCState {
>      /* tcg TLB needs flush (deferred slb inval instruction typically) */
>  #endif
>      /* segment registers */
> -    hwaddr htab_base;
> -    /* mask used to normalize hash value to PTEG index */
> -    hwaddr htab_mask;
>      target_ulong sr[32];
>      /* externally stored hash table */
>      uint8_t *external_htab;
> diff --git a/target/ppc/machine.c b/target/ppc/machine.c
> index df9f7a4..1ccbc8a 100644
> --- a/target/ppc/machine.c
> +++ b/target/ppc/machine.c
> @@ -229,7 +229,6 @@ static int cpu_post_load(void *opaque, int version_id)
>      }
>  
>      if (!env->external_htab) {
> -        /* Restore htab_base and htab_mask variables */
>          ppc_store_sdr1(env, env->spr[SPR_SDR1]);
>      }
>  
> diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
> index 29bace6..03ae3c1 100644
> --- a/target/ppc/mmu-hash32.c
> +++ b/target/ppc/mmu-hash32.c
> @@ -304,9 +304,9 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
>  
>  hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
>  {
> -    CPUPPCState *env = &cpu->env;
> +    target_ulong mask = ppc_hash32_hpt_mask(cpu);
>  
> -    return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
> +    return (hash * HASH_PTEG_SIZE_32) & mask;
>  }
>  
>  static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
> @@ -339,7 +339,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
>                                       target_ulong sr, target_ulong eaddr,
>                                       ppc_hash_pte32_t *pte)
>  {
> -    CPUPPCState *env = &cpu->env;
>      hwaddr pteg_off, pte_offset;
>      hwaddr hash;
>      uint32_t vsid, pgidx, ptem;
> @@ -353,21 +352,22 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
>      qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
>              " htab_mask " TARGET_FMT_plx
>              " hash " TARGET_FMT_plx "\n",
> -            env->htab_base, env->htab_mask, hash);
> +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
>  
>      /* Primary PTEG lookup */
>      qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
>              " vsid=%" PRIx32 " ptem=%" PRIx32
>              " hash=" TARGET_FMT_plx "\n",
> -            env->htab_base, env->htab_mask, vsid, ptem, hash);
> +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
> +            vsid, ptem, hash);
>      pteg_off = get_pteg_offset32(cpu, hash);
>      pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
>      if (pte_offset == -1) {
>          /* Secondary PTEG lookup */
>          qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
>                  " vsid=%" PRIx32 " api=%" PRIx32
> -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> -                env->htab_mask, vsid, ptem, ~hash);
> +                " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
> +                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
>          pteg_off = get_pteg_offset32(cpu, ~hash);
>          pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
>      }
> diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
> index 5b9fb08..054be65 100644
> --- a/target/ppc/mmu-hash32.h
> +++ b/target/ppc/mmu-hash32.h
> @@ -65,42 +65,54 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
>  #define HPTE32_R_WIMG           0x00000078
>  #define HPTE32_R_PP             0x00000003
>  
> +static inline hwaddr ppc_hash32_hpt_base(PowerPCCPU *cpu)
> +{
> +    return cpu->env.spr[SPR_SDR1] & SDR_32_HTABORG;
> +}
> +
> +static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
> +{
> +    return ((cpu->env.spr[SPR_SDR1] & SDR_32_HTABMASK) << 16) | 0xFFFF;
> +}
> +
>  static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
>                                                   hwaddr pte_offset)
>  {
>      CPUPPCState *env = &cpu->env;
> +    target_ulong base = ppc_hash32_hpt_base(cpu);
>  
>      assert(!env->external_htab); /* Not supported on 32-bit for now */
> -    return ldl_phys(CPU(cpu)->as, env->htab_base + pte_offset);
> +    return ldl_phys(CPU(cpu)->as, base + pte_offset);
>  }
>  
>  static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
>                                                   hwaddr pte_offset)
>  {
> +    target_ulong base = ppc_hash32_hpt_base(cpu);
>      CPUPPCState *env = &cpu->env;
>  
>      assert(!env->external_htab); /* Not supported on 32-bit for now */
> -    return ldl_phys(CPU(cpu)->as,
> -                    env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2);
> +    return ldl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2);
>  }
>  
>  static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
>                                            hwaddr pte_offset, target_ulong pte0)
>  {
>      CPUPPCState *env = &cpu->env;
> +    target_ulong base = ppc_hash32_hpt_base(cpu);
>  
>      assert(!env->external_htab); /* Not supported on 32-bit for now */
> -    stl_phys(CPU(cpu)->as, env->htab_base + pte_offset, pte0);
> +    stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
>  }
>  
>  static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
>                                            hwaddr pte_offset, target_ulong pte1)
>  {
>      CPUPPCState *env = &cpu->env;
> +    target_ulong base = ppc_hash32_hpt_base(cpu);
>  
>      assert(!env->external_htab); /* Not supported on 32-bit for now */
> -    stl_phys(CPU(cpu)->as,
> -             env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
> +    stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
>  }
>  
>  typedef struct {
> diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> index c59db47..bb87777 100644
> --- a/target/ppc/mmu-hash64.c
> +++ b/target/ppc/mmu-hash64.c
> @@ -304,15 +304,13 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
>      CPUPPCState *env = &cpu->env;
>      target_ulong htabsize = value & SDR_64_HTABSIZE;
>  
> -    env->spr[SPR_SDR1] = value;
>      if (htabsize > 28) {
>          error_setg(errp,
>                     "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
>                     htabsize);
> -        htabsize = 28;
> +        return;
>      }
> -    env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
> -    env->htab_base = value & SDR_64_HTABORG;
> +    env->spr[SPR_SDR1] = value;
>  }
>  
>  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
> @@ -333,10 +331,6 @@ void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
>          return;
>      }
>  
> -    /* Not strictly necessary, but makes it clearer that an external
> -     * htab is in use when debugging */
> -    env->htab_base = -1;
> -
>      if (kvm_enabled()) {
>          if (kvmppc_put_books_sregs(cpu) < 0) {
>              error_setg(errp, "Unable to update SDR1 in KVM");
> @@ -448,11 +442,12 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
>           * HTAB is controlled by QEMU. Just point to the internally
>           * accessible PTEG.
>           */
> -        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
> -    } else if (cpu->env.htab_base) {
> +        hptes = (const ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
> +    } else if (ppc_hash64_hpt_base(cpu)) {
> +        hwaddr base = ppc_hash64_hpt_base(cpu);
>          hwaddr plen = n * HASH_PTE_SIZE_64;
> -        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base + pte_offset,
> -                                 &plen, false);
> +        hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
> +                                  &plen, false);
>          if (plen < (n * HASH_PTE_SIZE_64)) {
>              hw_error("%s: Unable to map all requested HPTEs\n", __FUNCTION__);
>          }
> @@ -513,13 +508,12 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
>                                       target_ulong ptem,
>                                       ppc_hash_pte64_t *pte, unsigned *pshift)
>  {
> -    CPUPPCState *env = &cpu->env;
>      int i;
>      const ppc_hash_pte64_t *pteg;
>      target_ulong pte0, pte1;
>      target_ulong ptex;
>  
> -    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> +    ptex = (hash & ppc_hash64_hpt_mask(cpu)) * HPTES_PER_GROUP;
>      pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
>      if (!pteg) {
>          return -1;
> @@ -597,14 +591,15 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
>      qemu_log_mask(CPU_LOG_MMU,
>              "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
>              " hash " TARGET_FMT_plx "\n",
> -            env->htab_base, env->htab_mask, hash);
> +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), hash);
>  
>      /* Primary PTEG lookup */
>      qemu_log_mask(CPU_LOG_MMU,
>              "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
>              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
>              " hash=" TARGET_FMT_plx "\n",
> -            env->htab_base, env->htab_mask, vsid, ptem,  hash);
> +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
> +            vsid, ptem,  hash);
>      ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
>  
>      if (ptex == -1) {
> @@ -613,8 +608,8 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
>          qemu_log_mask(CPU_LOG_MMU,
>                  "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
>                  " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
> -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> -                env->htab_mask, vsid, ptem, ~hash);
> +                " hash=" TARGET_FMT_plx "\n", ppc_hash64_hpt_base(cpu),
> +                ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash);
>  
>          ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
>      }
> @@ -932,9 +927,9 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
>          stq_p(env->external_htab + offset, pte0);
>          stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
>      } else {
> -        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
> -        stq_phys(CPU(cpu)->as,
> -                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2, pte1);
> +        hwaddr base = ppc_hash64_hpt_base(cpu);
> +        stq_phys(CPU(cpu)->as, base + offset, pte0);
> +        stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
>      }
>  }
>  
> diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> index 8637fe4..dc0bc99 100644
> --- a/target/ppc/mmu-hash64.h
> +++ b/target/ppc/mmu-hash64.h
> @@ -56,6 +56,9 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
>   * Hash page table definitions
>   */
>  
> +#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> +#define SDR_64_HTABSIZE        0x000000000000001FULL
> +
>  #define HPTES_PER_GROUP         8
>  #define HASH_PTE_SIZE_64        16
>  #define HASH_PTEG_SIZE_64       (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
> @@ -91,6 +94,16 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
>  #define HPTE64_V_1TB_SEG        0x4000000000000000ULL
>  #define HPTE64_V_VRMA_MASK      0x4001ffffff000000ULL
>  
> +static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
> +{
> +    return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG;
> +}
> +
> +static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
> +{
> +    return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18 - 7)) - 1;
> +}
> +
>  void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
>                           Error **errp);
>  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
> diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
> index eb2d482..1381635 100644
> --- a/target/ppc/mmu_helper.c
> +++ b/target/ppc/mmu_helper.c
> @@ -466,6 +466,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
>  static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
>                                        target_ulong eaddr, int rw, int type)
>  {
> +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
>      hwaddr hash;
>      target_ulong vsid;
>      int ds, pr, target_page_bits;
> @@ -503,7 +504,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
>              qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
>                      " htab_mask " TARGET_FMT_plx
>                      " hash " TARGET_FMT_plx "\n",
> -                    env->htab_base, env->htab_mask, hash);
> +                    ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
>              ctx->hash[0] = hash;
>              ctx->hash[1] = ~hash;
>  
> @@ -518,9 +519,11 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
>                  uint32_t a0, a1, a2, a3;
>  
>                  qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
> -                         "\n", env->htab_base, env->htab_mask + 0x80);
> -                for (curaddr = env->htab_base;
> -                     curaddr < (env->htab_base + env->htab_mask + 0x80);
> +                         "\n", ppc_hash32_hpt_base(cpu),
> +                         ppc_hash32_hpt_mask(env) + 0x80);
> +                for (curaddr = ppc_hash32_hpt_base(cpu);
> +                     curaddr < (ppc_hash32_hpt_base(cpu)
> +                                + ppc_hash32_hpt_mask(cpu) + 0x80);
>                       curaddr += 16) {
>                      a0 = ldl_phys(cs->as, curaddr);
>                      a1 = ldl_phys(cs->as, curaddr + 4);
> @@ -1205,12 +1208,13 @@ static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
>  static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
>                              CPUPPCState *env)
>  {
> +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
>      ppc6xx_tlb_t *tlb;
>      target_ulong sr;
>      int type, way, entry, i;
>  
> -    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
> -    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
> +    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
> +    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
>  
>      cpu_fprintf(f, "\nSegment registers:\n");
>      for (i = 0; i < 32; i++) {
> @@ -1592,9 +1596,9 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
>                      env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
>                  tlb_miss:
>                      env->error_code |= ctx.key << 19;
> -                    env->spr[SPR_HASH1] = env->htab_base +
> +                    env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
>                          get_pteg_offset32(cpu, ctx.hash[0]);
> -                    env->spr[SPR_HASH2] = env->htab_base +
> +                    env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
>                          get_pteg_offset32(cpu, ctx.hash[1]);
>                      break;
>                  case POWERPC_MMU_SOFT_74xx:
> @@ -1999,7 +2003,6 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
>  {
>      qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
>      assert(!env->external_htab);
> -    env->spr[SPR_SDR1] = value;
>  #if defined(TARGET_PPC64)
>      if (env->mmu_model & POWERPC_MMU_64) {
>          PowerPCCPU *cpu = ppc_env_get_cpu(env);
> @@ -2009,14 +2012,12 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
>          if (local_err) {
>              error_report_err(local_err);
>              error_free(local_err);
> +            return;
>          }
> -    } else
> -#endif /* defined(TARGET_PPC64) */
> -    {
> -        /* FIXME: Should check for valid HTABMASK values */
> -        env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
> -        env->htab_base = value & SDR_32_HTABORG;
>      }
> +#endif /* defined(TARGET_PPC64) */
> +    /* FIXME: Should check for valid HTABMASK values in 32-bit case */
> +    env->spr[SPR_SDR1] = value;
>  }
>  
>  /* Segment registers load and store */
> 


-- 
Alexey

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

* Re: [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables David Gibson
  2017-02-23  5:43   ` Alexey Kardashevskiy
@ 2017-02-23  5:52   ` Suraj Jitindar Singh
  2017-02-24  3:45     ` David Gibson
  2017-02-24  5:34     ` David Gibson
  1 sibling, 2 replies; 22+ messages in thread
From: Suraj Jitindar Singh @ 2017-02-23  5:52 UTC (permalink / raw)
  To: David Gibson, qemu-ppc, aik
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus

On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> CPUPPCState includes fields htab_base and htab_mask which store the
> base
> address (GPA) and size (as a mask) of the guest's hashed page table
> (HPT).
> These are set when the SDR1 register is updated.
> 
> Keeping these in sync with the SDR1 is actually a little bit fiddly,
> and
> probably not useful for performance, since keeping them expands the
> size of
> CPUPPCState.  It also makes some upcoming changes harder to
> implement.
> 
> This patch removes these fields, in favour of calculating them
> directly
> from the SDR1 contents when necessary.
> 
> This does make a change to the behaviour of attempting to write a bad
> value
> (invalid HPT size) to the SDR1 with an mtspr
> instruction.  Previously, the
> bad value would be stored in SDR1 and could be retrieved with a later
> mfspr, but the HPT size as used by the softmmu would be, clamped to
> the
> allowed values.  Now, writing a bad value is treated as a no-op.  An
> error
> message is printed in both new and old versions.
> 
> I'm not sure which behaviour, if either, matches real hardware.  I
> don't
> think it matters that much, since it's pretty clear that if an OS
> writes
> a bad value to SDR1, it's not going to boot.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Comments Below.

> ---
>  hw/ppc/spapr_hcall.c    |  4 ++--
>  target/ppc/cpu.h        |  8 --------
>  target/ppc/machine.c    |  1 -
>  target/ppc/mmu-hash32.c | 14 +++++++-------
>  target/ppc/mmu-hash32.h | 24 ++++++++++++++++++------
>  target/ppc/mmu-hash64.c | 37 ++++++++++++++++---------------------
>  target/ppc/mmu-hash64.h | 13 +++++++++++++
>  target/ppc/mmu_helper.c | 31 ++++++++++++++++---------------
>  8 files changed, 72 insertions(+), 60 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index fd961b5..85d96f6 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -50,9 +50,9 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
>  static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
>  {
>      /*
> -     * hash value/pteg group index is normalized by htab_mask
> +     * hash value/pteg group index is normalized by HPT mask
>       */
> -    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) {
> +    if (((ptex & ~7ULL) / HPTES_PER_GROUP) &
> ~ppc_hash64_hpt_mask(cpu)) {
>          return false;
>      }
>      return true;
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index c89973e..c6cd9ab 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -309,11 +309,6 @@ union ppc_tlb_t {
>  #define SDR_32_HTABORG         0xFFFF0000UL
>  #define SDR_32_HTABMASK        0x000001FFUL
>  
> -#if defined(TARGET_PPC64)
> -#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> -#define SDR_64_HTABSIZE        0x000000000000001FULL
> -#endif /* defined(TARGET_PPC64 */
> -
>  typedef struct ppc_slb_t ppc_slb_t;
>  struct ppc_slb_t {
>      uint64_t esid;
> @@ -1006,9 +1001,6 @@ struct CPUPPCState {
>      /* tcg TLB needs flush (deferred slb inval instruction
> typically) */
>  #endif
>      /* segment registers */
> -    hwaddr htab_base;
> -    /* mask used to normalize hash value to PTEG index */
> -    hwaddr htab_mask;
>      target_ulong sr[32];
>      /* externally stored hash table */
>      uint8_t *external_htab;
> diff --git a/target/ppc/machine.c b/target/ppc/machine.c
> index df9f7a4..1ccbc8a 100644
> --- a/target/ppc/machine.c
> +++ b/target/ppc/machine.c
> @@ -229,7 +229,6 @@ static int cpu_post_load(void *opaque, int
> version_id)
>      }
>  
>      if (!env->external_htab) {
> -        /* Restore htab_base and htab_mask variables */
>          ppc_store_sdr1(env, env->spr[SPR_SDR1]);

Do we still need to do this? As far as I can tell it pretty much does:
env->spr[SPR_SDR1] = env->spr[SPR_SDR1]
and checks the htab_size, which would have been done when we set SDR1
in the first place anyway?

>      }
>  
> diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
> index 29bace6..03ae3c1 100644
> --- a/target/ppc/mmu-hash32.c
> +++ b/target/ppc/mmu-hash32.c
> @@ -304,9 +304,9 @@ static int ppc_hash32_direct_store(PowerPCCPU
> *cpu, target_ulong sr,
>  
>  hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
>  {
> -    CPUPPCState *env = &cpu->env;
> +    target_ulong mask = ppc_hash32_hpt_mask(cpu);
>  
> -    return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
> +    return (hash * HASH_PTEG_SIZE_32) & mask;
>  }
>  
>  static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr
> pteg_off,
> @@ -339,7 +339,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU
> *cpu,
>                                       target_ulong sr, target_ulong
> eaddr,
>                                       ppc_hash_pte32_t *pte)
>  {
> -    CPUPPCState *env = &cpu->env;
>      hwaddr pteg_off, pte_offset;
>      hwaddr hash;
>      uint32_t vsid, pgidx, ptem;
> @@ -353,21 +352,22 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU
> *cpu,
>      qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
>              " htab_mask " TARGET_FMT_plx
>              " hash " TARGET_FMT_plx "\n",
> -            env->htab_base, env->htab_mask, hash);
> +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
> hash);
>  
>      /* Primary PTEG lookup */
>      qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/"
> TARGET_FMT_plx
>              " vsid=%" PRIx32 " ptem=%" PRIx32
>              " hash=" TARGET_FMT_plx "\n",
> -            env->htab_base, env->htab_mask, vsid, ptem, hash);
> +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
> +            vsid, ptem, hash);
>      pteg_off = get_pteg_offset32(cpu, hash);
>      pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem,
> pte);
>      if (pte_offset == -1) {
>          /* Secondary PTEG lookup */
>          qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/"
> TARGET_FMT_plx
>                  " vsid=%" PRIx32 " api=%" PRIx32
> -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> -                env->htab_mask, vsid, ptem, ~hash);
> +                " hash=" TARGET_FMT_plx "\n",
> ppc_hash32_hpt_base(cpu),
> +                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
>          pteg_off = get_pteg_offset32(cpu, ~hash);
>          pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem,
> pte);
>      }
> diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
> index 5b9fb08..054be65 100644
> --- a/target/ppc/mmu-hash32.h
> +++ b/target/ppc/mmu-hash32.h
> @@ -65,42 +65,54 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu,
> vaddr address, int rw,
>  #define HPTE32_R_WIMG           0x00000078
>  #define HPTE32_R_PP             0x00000003
>  
> +static inline hwaddr ppc_hash32_hpt_base(PowerPCCPU *cpu)
> +{
> +    return cpu->env.spr[SPR_SDR1] & SDR_32_HTABORG;
> +}
> +
> +static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
> +{
> +    return ((cpu->env.spr[SPR_SDR1] & SDR_32_HTABMASK) << 16) |
> 0xFFFF;
> +}
> +
>  static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
>                                                   hwaddr pte_offset)
>  {
>      CPUPPCState *env = &cpu->env;
> +    target_ulong base = ppc_hash32_hpt_base(cpu);
>  
>      assert(!env->external_htab); /* Not supported on 32-bit for now
> */
> -    return ldl_phys(CPU(cpu)->as, env->htab_base + pte_offset);
> +    return ldl_phys(CPU(cpu)->as, base + pte_offset);
>  }
>  
>  static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
>                                                   hwaddr pte_offset)
>  {
> +    target_ulong base = ppc_hash32_hpt_base(cpu);
>      CPUPPCState *env = &cpu->env;
>  
>      assert(!env->external_htab); /* Not supported on 32-bit for now
> */
> -    return ldl_phys(CPU(cpu)->as,
> -                    env->htab_base + pte_offset + HASH_PTE_SIZE_32 /
> 2);
> +    return ldl_phys(CPU(cpu)->as, base + pte_offset +
> HASH_PTE_SIZE_32 / 2);
>  }
>  
>  static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
>                                            hwaddr pte_offset,
> target_ulong pte0)
>  {
>      CPUPPCState *env = &cpu->env;
> +    target_ulong base = ppc_hash32_hpt_base(cpu);
>  
>      assert(!env->external_htab); /* Not supported on 32-bit for now
> */
> -    stl_phys(CPU(cpu)->as, env->htab_base + pte_offset, pte0);
> +    stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
>  }
>  
>  static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
>                                            hwaddr pte_offset,
> target_ulong pte1)
>  {
>      CPUPPCState *env = &cpu->env;
> +    target_ulong base = ppc_hash32_hpt_base(cpu);
>  
>      assert(!env->external_htab); /* Not supported on 32-bit for now
> */
> -    stl_phys(CPU(cpu)->as,
> -             env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2,
> pte1);
> +    stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2,
> pte1);
>  }
>  
>  typedef struct {
> diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> index c59db47..bb87777 100644
> --- a/target/ppc/mmu-hash64.c
> +++ b/target/ppc/mmu-hash64.c
> @@ -304,15 +304,13 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu,
> target_ulong value,
>      CPUPPCState *env = &cpu->env;
>      target_ulong htabsize = value & SDR_64_HTABSIZE;
>  
> -    env->spr[SPR_SDR1] = value;
>      if (htabsize > 28) {
>          error_setg(errp,
>                     "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in
> SDR1",
>                     htabsize);
> -        htabsize = 28;
> +        return;
>      }
> -    env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
> -    env->htab_base = value & SDR_64_HTABORG;
> +    env->spr[SPR_SDR1] = value;
>  }
>  
>  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> shift,
> @@ -333,10 +331,6 @@ void ppc_hash64_set_external_hpt(PowerPCCPU
> *cpu, void *hpt, int shift,
>          return;
>      }
>  
> -    /* Not strictly necessary, but makes it clearer that an external
> -     * htab is in use when debugging */
> -    env->htab_base = -1;
> -
>      if (kvm_enabled()) {
>          if (kvmppc_put_books_sregs(cpu) < 0) {
>              error_setg(errp, "Unable to update SDR1 in KVM");
> @@ -448,11 +442,12 @@ const ppc_hash_pte64_t
> *ppc_hash64_map_hptes(PowerPCCPU *cpu,
>           * HTAB is controlled by QEMU. Just point to the internally
>           * accessible PTEG.
>           */
> -        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab +
> pte_offset);
> -    } else if (cpu->env.htab_base) {
> +        hptes = (const ppc_hash_pte64_t *)(cpu->env.external_htab +
> pte_offset);
^^^ Does this particular line belong in the previous patch?
> +    } else if (ppc_hash64_hpt_base(cpu)) {
> +        hwaddr base = ppc_hash64_hpt_base(cpu);
>          hwaddr plen = n * HASH_PTE_SIZE_64;
> -        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base +
> pte_offset,
> -                                 &plen, false);
> +        hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
> +                                  &plen, false);
>          if (plen < (n * HASH_PTE_SIZE_64)) {
>              hw_error("%s: Unable to map all requested HPTEs\n",
> __FUNCTION__);
>          }
> @@ -513,13 +508,12 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU
> *cpu, hwaddr hash,
>                                       target_ulong ptem,
>                                       ppc_hash_pte64_t *pte, unsigned
> *pshift)
>  {
> -    CPUPPCState *env = &cpu->env;
>      int i;
>      const ppc_hash_pte64_t *pteg;
>      target_ulong pte0, pte1;
>      target_ulong ptex;
>  
> -    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> +    ptex = (hash & ppc_hash64_hpt_mask(cpu)) * HPTES_PER_GROUP;
>      pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
>      if (!pteg) {
>          return -1;
> @@ -597,14 +591,15 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> *cpu,
>      qemu_log_mask(CPU_LOG_MMU,
>              "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
>              " hash " TARGET_FMT_plx "\n",
> -            env->htab_base, env->htab_mask, hash);
> +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
> hash);
>  
>      /* Primary PTEG lookup */
>      qemu_log_mask(CPU_LOG_MMU,
>              "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
>              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
>              " hash=" TARGET_FMT_plx "\n",
> -            env->htab_base, env->htab_mask, vsid, ptem,  hash);
> +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
> +            vsid, ptem,  hash);
>      ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte,
> pshift);
>  
>      if (ptex == -1) {
> @@ -613,8 +608,8 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> *cpu,
>          qemu_log_mask(CPU_LOG_MMU,
>                  "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
>                  " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
> -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> -                env->htab_mask, vsid, ptem, ~hash);
> +                " hash=" TARGET_FMT_plx "\n",
> ppc_hash64_hpt_base(cpu),
> +                ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash);
>  
>          ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte,
> pshift);
>      }
> @@ -932,9 +927,9 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu,
> hwaddr ptex,
>          stq_p(env->external_htab + offset, pte0);
>          stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2,
> pte1);
>      } else {
> -        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
> -        stq_phys(CPU(cpu)->as,
> -                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2,
> pte1);
> +        hwaddr base = ppc_hash64_hpt_base(cpu);
> +        stq_phys(CPU(cpu)->as, base + offset, pte0);
> +        stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2,
> pte1);
>      }
>  }
>  
> diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> index 8637fe4..dc0bc99 100644
> --- a/target/ppc/mmu-hash64.h
> +++ b/target/ppc/mmu-hash64.h
> @@ -56,6 +56,9 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
>   * Hash page table definitions
>   */
>  
> +#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL

I think this was just always wrong, but it should be
0x0FFFFFFFFFFC0000ULL
  ^

> +#define SDR_64_HTABSIZE        0x000000000000001FULL
> +
>  #define HPTES_PER_GROUP         8
>  #define HASH_PTE_SIZE_64        16
>  #define HASH_PTEG_SIZE_64       (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
> @@ -91,6 +94,16 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
>  #define HPTE64_V_1TB_SEG        0x4000000000000000ULL
>  #define HPTE64_V_VRMA_MASK      0x4001ffffff000000ULL
>  
> +static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
> +{
> +    return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG;
> +}
> +
> +static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
> +{
> +    return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18
> - 7)) - 1;
> +}
> +
>  void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
>                           Error **errp);
>  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> shift,
> diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
> index eb2d482..1381635 100644
> --- a/target/ppc/mmu_helper.c
> +++ b/target/ppc/mmu_helper.c
> @@ -466,6 +466,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env,
> mmu_ctx_t *ctx,
>  static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t
> *ctx,
>                                        target_ulong eaddr, int rw,
> int type)
>  {
> +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
>      hwaddr hash;
>      target_ulong vsid;
>      int ds, pr, target_page_bits;
> @@ -503,7 +504,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState
> *env, mmu_ctx_t *ctx,
>              qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
>                      " htab_mask " TARGET_FMT_plx
>                      " hash " TARGET_FMT_plx "\n",
> -                    env->htab_base, env->htab_mask, hash);
> +                    ppc_hash32_hpt_base(cpu),
> ppc_hash32_hpt_mask(cpu), hash);
>              ctx->hash[0] = hash;
>              ctx->hash[1] = ~hash;
>  
> @@ -518,9 +519,11 @@ static inline int
> get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
>                  uint32_t a0, a1, a2, a3;
>  
>                  qemu_log("Page table: " TARGET_FMT_plx " len "
> TARGET_FMT_plx
> -                         "\n", env->htab_base, env->htab_mask +
> 0x80);
> -                for (curaddr = env->htab_base;
> -                     curaddr < (env->htab_base + env->htab_mask +
> 0x80);
> +                         "\n", ppc_hash32_hpt_base(cpu),
> +                         ppc_hash32_hpt_mask(env) + 0x80);
> +                for (curaddr = ppc_hash32_hpt_base(cpu);
> +                     curaddr < (ppc_hash32_hpt_base(cpu)
> +                                + ppc_hash32_hpt_mask(cpu) + 0x80);
>                       curaddr += 16) {
>                      a0 = ldl_phys(cs->as, curaddr);
>                      a1 = ldl_phys(cs->as, curaddr + 4);
> @@ -1205,12 +1208,13 @@ static void mmu6xx_dump_BATs(FILE *f,
> fprintf_function cpu_fprintf,
>  static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
>                              CPUPPCState *env)
>  {
> +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
>      ppc6xx_tlb_t *tlb;
>      target_ulong sr;
>      int type, way, entry, i;
>  
> -    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env-
> >htab_base);
> -    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env-
> >htab_mask);
> +    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n",
> ppc_hash32_hpt_base(cpu));
> +    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n",
> ppc_hash32_hpt_mask(cpu));
>  
>      cpu_fprintf(f, "\nSegment registers:\n");
>      for (i = 0; i < 32; i++) {
> @@ -1592,9 +1596,9 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState
> *env, target_ulong address,
>                      env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
>                  tlb_miss:
>                      env->error_code |= ctx.key << 19;
> -                    env->spr[SPR_HASH1] = env->htab_base +
> +                    env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
>                          get_pteg_offset32(cpu, ctx.hash[0]);
> -                    env->spr[SPR_HASH2] = env->htab_base +
> +                    env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
>                          get_pteg_offset32(cpu, ctx.hash[1]);
>                      break;
>                  case POWERPC_MMU_SOFT_74xx:
> @@ -1999,7 +2003,6 @@ void ppc_store_sdr1(CPUPPCState *env,
> target_ulong value)
>  {
>      qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__,
> value);
>      assert(!env->external_htab);
> -    env->spr[SPR_SDR1] = value;
>  #if defined(TARGET_PPC64)
>      if (env->mmu_model & POWERPC_MMU_64) {
>          PowerPCCPU *cpu = ppc_env_get_cpu(env);
> @@ -2009,14 +2012,12 @@ void ppc_store_sdr1(CPUPPCState *env,
> target_ulong value)
>          if (local_err) {
>              error_report_err(local_err);
>              error_free(local_err);
> +            return;
>          }
> -    } else
> -#endif /* defined(TARGET_PPC64) */
> -    {
> -        /* FIXME: Should check for valid HTABMASK values */
> -        env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
> -        env->htab_base = value & SDR_32_HTABORG;
>      }
> +#endif /* defined(TARGET_PPC64) */
> +    /* FIXME: Should check for valid HTABMASK values in 32-bit case
> */
> +    env->spr[SPR_SDR1] = value;
>  }
>  
>  /* Segment registers load and store */

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

* Re: [Qemu-devel] [PATCH 6/6] target/ppc: Manage external HPT via virtual hypervisor
  2017-02-23  2:09 ` [Qemu-devel] [PATCH 6/6] target/ppc: Manage external HPT via virtual hypervisor David Gibson
@ 2017-02-23  6:20   ` Suraj Jitindar Singh
  0 siblings, 0 replies; 22+ messages in thread
From: Suraj Jitindar Singh @ 2017-02-23  6:20 UTC (permalink / raw)
  To: David Gibson, qemu-ppc, aik
  Cc: qemu-devel, agraf, thuth, lvivier, mdroth, paulus

On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> The pseries machine type implements the behaviour of a PAPR compliant
> hypervisor, without actually executing such a hypervisor on the
> virtual
> CPU.  To do this we need some hooks in the CPU code to make
> hypervisor
> facilities get redirected to the machine instead of emulated
> internally.
> 
> For hypercalls this is managed through the cpu->vhyp field, which
> points
> to a QOM interface with a method implementing the hypercall.
> 
> For the hashed page table (HPT) - also a hypervisor resource - we use
> an
> older hack.  CPUPPCState has an 'external_htab' field which when non-
> NULL
> indicates that the HPT is stored in qemu memory, rather than within
> the
> guest's address space.
> 
> For consistency - and to make some future extensions easier - this
> merges
> the external HPT mechanism into the vhyp mechanism.  Methods are
> added
> to vhyp for the basic operations the core hash MMU code needs:
> map_hptes()
> and unmap_hptes() for reading the HPT, store_hpte() for updating it
> and
> hpt_mask() to retrieve its size.
> 
> To match this, the pseries machine now sets these vhyp fields in its
> existing vhyp class, rather than reaching into the cpu object to set
> the
> external_htab field.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>

> ---
>  hw/ppc/spapr.c          | 58 +++++++++++++++++++++++++++++
>  hw/ppc/spapr_cpu_core.c | 17 ++++++++-
>  hw/ppc/spapr_hcall.c    |  3 +-
>  target/ppc/cpu.h        | 10 ++++-
>  target/ppc/kvm.c        |  2 +-
>  target/ppc/machine.c    |  4 +-
>  target/ppc/mmu-hash32.h |  8 ----
>  target/ppc/mmu-hash64.c | 98 ++++++++++++++++-----------------------
> ----------
>  target/ppc/mmu-hash64.h |  7 +++-
>  target/ppc/mmu_helper.c |  3 +-
>  10 files changed, 123 insertions(+), 87 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index 5904e64..c159961 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1050,6 +1050,60 @@ static void close_htab_fd(sPAPRMachineState
> *spapr)
>      spapr->htab_fd = -1;
>  }
>  
> +static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp)
> +{
> +    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
> +
> +    return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1;
> +}
> +
> +static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor
> *vhyp,
> +                                                hwaddr ptex, int n)
> +{
> +    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
> +    hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
> +
> +    if (!spapr->htab) {
> +        /*
> +         * HTAB is controlled by KVM. Fetch the PTEG into a new
> buffer.
> +         */
> +        return kvmppc_map_hptes(ptex, n);
> +    }
> +
> +    /*
> +     * HTAB is controlled by QEMU. Just point to the internally
> +     * accessible PTEG.
> +     */
> +    return (const ppc_hash_pte64_t *)(spapr->htab + pte_offset);
> +}
> +
> +static void spapr_unmap_hptes(PPCVirtualHypervisor *vhyp,
> +                              const ppc_hash_pte64_t *hptes,
> +                              hwaddr ptex, int n)
> +{
> +    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
> +
> +    if (!spapr->htab) {
> +        kvmppc_unmap_hptes(hptes, ptex, n);
> +    }
> +
> +    /* Nothing to do for qemu managed HPT */
> +}
> +
> +static void spapr_store_hpte(PPCVirtualHypervisor *vhyp, hwaddr
> ptex,
> +                             uint64_t pte0, uint64_t pte1)
> +{
> +    sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp);
> +    hwaddr offset = ptex * HASH_PTE_SIZE_64;
> +
> +    if (!spapr->htab) {
> +        kvmppc_hash64_write_pte(ptex, pte0, pte1);
> +    } else {
> +        stq_p(spapr->htab + offset, pte0);
> +        stq_p(spapr->htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
> +    }
> +}
> +
>  static int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
>  {
>      int shift;
> @@ -2910,6 +2964,10 @@ static void
> spapr_machine_class_init(ObjectClass *oc, void *data)
>      nc->nmi_monitor_handler = spapr_nmi;
>      smc->phb_placement = spapr_phb_placement;
>      vhc->hypercall = emulate_spapr_hypercall;
> +    vhc->hpt_mask = spapr_hpt_mask;
> +    vhc->map_hptes = spapr_map_hptes;
> +    vhc->unmap_hptes = spapr_unmap_hptes;
> +    vhc->store_hpte = spapr_store_hpte;
>  }
>  
>  static const TypeInfo spapr_machine_info = {
> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> index 76563c4..ddb130f 100644
> --- a/hw/ppc/spapr_cpu_core.c
> +++ b/hw/ppc/spapr_cpu_core.c
> @@ -13,10 +13,12 @@
>  #include "hw/boards.h"
>  #include "qapi/error.h"
>  #include "sysemu/cpus.h"
> +#include "sysemu/kvm.h"
>  #include "target/ppc/kvm_ppc.h"
>  #include "hw/ppc/ppc.h"
>  #include "target/ppc/mmu-hash64.h"
>  #include "sysemu/numa.h"
> +#include "qemu/error-report.h"
>  
>  static void spapr_cpu_reset(void *opaque)
>  {
> @@ -34,8 +36,19 @@ static void spapr_cpu_reset(void *opaque)
>  
>      env->spr[SPR_HIOR] = 0;
>  
> -    ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift,
> -                                &error_fatal);
> +    /*
> +     * This is a hack for the benefit of KVM PR - it abuses the SDR1
> +     * slot in kvm_sregs to communicate the userspace address of the
> +     * HPT
> +     */
> +    if (kvm_enabled()) {
> +        env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab
> +            | (spapr->htab_shift - 18);
> +        if (kvmppc_put_books_sregs(cpu) < 0) {
> +            error_report("Unable to update SDR1 in KVM");
> +            exit(1);
> +        }
> +    }
>  }
>  
>  static void spapr_cpu_destroy(PowerPCCPU *cpu)
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 85d96f6..f05a90e 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -326,7 +326,6 @@ static target_ulong h_protect(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>  static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState
> *spapr,
>                             target_ulong opcode, target_ulong *args)
>  {
> -    CPUPPCState *env = &cpu->env;
>      target_ulong flags = args[0];
>      target_ulong ptex = args[1];
>      uint8_t *hpte;
> @@ -342,7 +341,7 @@ static target_ulong h_read(PowerPCCPU *cpu,
> sPAPRMachineState *spapr,
>          n_entries = 4;
>      }
>  
> -    hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
> +    hpte = spapr->htab + (ptex * HASH_PTE_SIZE_64);
>  
>      for (i = 0, ridx = 0; i < n_entries; i++) {
>          args[ridx++] = ldq_p(hpte);
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index c6cd9ab..27b78ca 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -1002,8 +1002,6 @@ struct CPUPPCState {
>  #endif
>      /* segment registers */
>      target_ulong sr[32];
> -    /* externally stored hash table */
> -    uint8_t *external_htab;
>      /* BATs */
>      uint32_t nb_BATs;
>      target_ulong DBAT[2][8];
> @@ -1211,6 +1209,14 @@ struct PPCVirtualHypervisor {
>  struct PPCVirtualHypervisorClass {
>      InterfaceClass parent;
>      void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
> +    hwaddr (*hpt_mask)(PPCVirtualHypervisor *vhyp);
> +    const ppc_hash_pte64_t *(*map_hptes)(PPCVirtualHypervisor *vhyp,
> +                                         hwaddr ptex, int n);
> +    void (*unmap_hptes)(PPCVirtualHypervisor *vhyp,
> +                        const ppc_hash_pte64_t *hptes,
> +                        hwaddr ptex, int n);
> +    void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex,
> +                       uint64_t pte0, uint64_t pte1);
>  };
>  
>  #define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
> diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> index 9d3e57e..c40f6aa 100644
> --- a/target/ppc/kvm.c
> +++ b/target/ppc/kvm.c
> @@ -1251,7 +1251,7 @@ static int kvmppc_get_books_sregs(PowerPCCPU
> *cpu)
>          return ret;
>      }
>  
> -    if (!env->external_htab) {
> +    if (!cpu->vhyp) {
>          ppc_store_sdr1(env, sregs.u.s.sdr1);
>      }
>  
> diff --git a/target/ppc/machine.c b/target/ppc/machine.c
> index 1ccbc8a..6cb3a48 100644
> --- a/target/ppc/machine.c
> +++ b/target/ppc/machine.c
> @@ -76,7 +76,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque,
> int version_id)
>          qemu_get_betls(f, &env->pb[i]);
>      for (i = 0; i < 1024; i++)
>          qemu_get_betls(f, &env->spr[i]);
> -    if (!env->external_htab) {
> +    if (!cpu->vhyp) {
>          ppc_store_sdr1(env, sdr1);
>      }
>      qemu_get_be32s(f, &env->vscr);
> @@ -228,7 +228,7 @@ static int cpu_post_load(void *opaque, int
> version_id)
>          env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1];
>      }
>  
> -    if (!env->external_htab) {
> +    if (!cpu->vhyp) {
>          ppc_store_sdr1(env, env->spr[SPR_SDR1]);

Not really relevant to this patch series, but do we really need to do
this? It's kinda a no-op.

>      }
>  
> diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
> index 054be65..644cfe6 100644
> --- a/target/ppc/mmu-hash32.h
> +++ b/target/ppc/mmu-hash32.h
> @@ -78,10 +78,8 @@ static inline hwaddr
> ppc_hash32_hpt_mask(PowerPCCPU *cpu)
>  static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
>                                                   hwaddr pte_offset)
>  {
> -    CPUPPCState *env = &cpu->env;
>      target_ulong base = ppc_hash32_hpt_base(cpu);
>  
> -    assert(!env->external_htab); /* Not supported on 32-bit for now
> */
>      return ldl_phys(CPU(cpu)->as, base + pte_offset);
>  }
>  
> @@ -89,29 +87,23 @@ static inline target_ulong
> ppc_hash32_load_hpte1(PowerPCCPU *cpu,
>                                                   hwaddr pte_offset)
>  {
>      target_ulong base = ppc_hash32_hpt_base(cpu);
> -    CPUPPCState *env = &cpu->env;
>  
> -    assert(!env->external_htab); /* Not supported on 32-bit for now
> */
>      return ldl_phys(CPU(cpu)->as, base + pte_offset +
> HASH_PTE_SIZE_32 / 2);
>  }
>  
>  static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
>                                            hwaddr pte_offset,
> target_ulong pte0)
>  {
> -    CPUPPCState *env = &cpu->env;
>      target_ulong base = ppc_hash32_hpt_base(cpu);
>  
> -    assert(!env->external_htab); /* Not supported on 32-bit for now
> */
>      stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
>  }
>  
>  static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
>                                            hwaddr pte_offset,
> target_ulong pte1)
>  {
> -    CPUPPCState *env = &cpu->env;
>      target_ulong base = ppc_hash32_hpt_base(cpu);
>  
> -    assert(!env->external_htab); /* Not supported on 32-bit for now
> */
>      stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2,
> pte1);
>  }
>  
> diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> index bb87777..ce96823 100644
> --- a/target/ppc/mmu-hash64.c
> +++ b/target/ppc/mmu-hash64.c
> @@ -38,12 +38,6 @@
>  #endif
>  
>  /*
> - * Used to indicate that a CPU has its hash page table (HPT) managed
> - * within the host kernel
> - */
> -#define MMU_HASH64_KVM_MANAGED_HPT      ((void *)-1)
> -
> -/*
>   * SLB handling
>   */
>  
> @@ -313,31 +307,6 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu,
> target_ulong value,
>      env->spr[SPR_SDR1] = value;
>  }
>  
> -void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> shift,
> -                                 Error **errp)
> -{
> -    CPUPPCState *env = &cpu->env;
> -    Error *local_err = NULL;
> -
> -    if (hpt) {
> -        env->external_htab = hpt;
> -    } else {
> -        env->external_htab = MMU_HASH64_KVM_MANAGED_HPT;
> -    }
> -    ppc_hash64_set_sdr1(cpu, (target_ulong)(uintptr_t)hpt | (shift -
> 18),
> -                        &local_err);
> -    if (local_err) {
> -        error_propagate(errp, local_err);
> -        return;
> -    }
> -
> -    if (kvm_enabled()) {
> -        if (kvmppc_put_books_sregs(cpu) < 0) {
> -            error_setg(errp, "Unable to update SDR1 in KVM");
> -        }
> -    }
> -}
> -
>  static int ppc_hash64_pte_prot(PowerPCCPU *cpu,
>                                 ppc_slb_t *slb, ppc_hash_pte64_t pte)
>  {
> @@ -429,28 +398,24 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu,
> ppc_hash_pte64_t pte)
>  const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
>                                               hwaddr ptex, int n)
>  {
> -    const ppc_hash_pte64_t *hptes = NULL;
>      hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
> +    hwaddr base = ppc_hash64_hpt_base(cpu);
> +    hwaddr plen = n * HASH_PTE_SIZE_64;
> +    const ppc_hash_pte64_t *hptes;
> +
> +    if (cpu->vhyp) {
> +        PPCVirtualHypervisorClass *vhc =
> +            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> +        return vhc->map_hptes(cpu->vhyp, ptex, n);
> +    }
>  
> -    if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> -        /*
> -         * HTAB is controlled by KVM. Fetch the PTEG into a new
> buffer.
> -         */
> -        hptes = kvmppc_map_hptes(ptex, n);
> -    } else if (cpu->env.external_htab) {
> -        /*
> -         * HTAB is controlled by QEMU. Just point to the internally
> -         * accessible PTEG.
> -         */
> -        hptes = (const ppc_hash_pte64_t *)(cpu->env.external_htab +
> pte_offset);
> -    } else if (ppc_hash64_hpt_base(cpu)) {
> -        hwaddr base = ppc_hash64_hpt_base(cpu);
> -        hwaddr plen = n * HASH_PTE_SIZE_64;
> -        hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
> -                                  &plen, false);
> -        if (plen < (n * HASH_PTE_SIZE_64)) {
> -            hw_error("%s: Unable to map all requested HPTEs\n",
> __FUNCTION__);
> -        }
> +    if (!base) {
> +        return NULL;
> +    }
> +
> +    hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
> &plen, false);
> +    if (plen < (n * HASH_PTE_SIZE_64)) {
> +        hw_error("%s: Unable to map all requested HPTEs\n",
> __FUNCTION__);
>      }
>      return hptes;
>  }
> @@ -458,12 +423,15 @@ const ppc_hash_pte64_t
> *ppc_hash64_map_hptes(PowerPCCPU *cpu,
>  void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t
> *hptes,
>                              hwaddr ptex, int n)
>  {
> -    if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> -        kvmppc_unmap_hptes(hptes, ptex, n);
> -    } else if (!cpu->env.external_htab) {
> -        address_space_unmap(CPU(cpu)->as, (void *)hptes, n *
> HASH_PTE_SIZE_64,
> -                            false, n * HASH_PTE_SIZE_64);
> +    if (cpu->vhyp) {
> +        PPCVirtualHypervisorClass *vhc =
> +            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> +        vhc->unmap_hptes(cpu->vhyp, hptes, ptex, n);
> +        return;
>      }
> +
> +    address_space_unmap(CPU(cpu)->as, (void *)hptes, n *
> HASH_PTE_SIZE_64,
> +                        false, n * HASH_PTE_SIZE_64);
>  }
>  
>  static unsigned hpte_page_shift(const struct ppc_one_seg_page_size
> *sps,
> @@ -915,22 +883,18 @@ hwaddr
> ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
>  void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
>                             uint64_t pte0, uint64_t pte1)
>  {
> -    CPUPPCState *env = &cpu->env;
> +    hwaddr base = ppc_hash64_hpt_base(cpu);
>      hwaddr offset = ptex * HASH_PTE_SIZE_64;
>  
> -    if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> -        kvmppc_hash64_write_pte(ptex, pte0, pte1);
> +    if (cpu->vhyp) {
> +        PPCVirtualHypervisorClass *vhc =
> +            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> +        vhc->store_hpte(cpu->vhyp, ptex, pte0, pte1);
>          return;
>      }
>  
> -    if (env->external_htab) {
> -        stq_p(env->external_htab + offset, pte0);
> -        stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2,
> pte1);
> -    } else {
> -        hwaddr base = ppc_hash64_hpt_base(cpu);
> -        stq_phys(CPU(cpu)->as, base + offset, pte0);
> -        stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2,
> pte1);
> -    }
> +    stq_phys(CPU(cpu)->as, base + offset, pte0);
> +    stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2,
> pte1);
>  }
>  
>  void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
> diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> index dc0bc99..9c33e9d 100644
> --- a/target/ppc/mmu-hash64.h
> +++ b/target/ppc/mmu-hash64.h
> @@ -101,13 +101,16 @@ static inline hwaddr
> ppc_hash64_hpt_base(PowerPCCPU *cpu)
>  
>  static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
>  {
> +    if (cpu->vhyp) {
> +        PPCVirtualHypervisorClass *vhc =
> +            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> +        return vhc->hpt_mask(cpu->vhyp);
> +    }
>      return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18
> - 7)) - 1;
>  }
>  
>  void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
>                           Error **errp);
> -void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> shift,
> -                                 Error **errp);
>  
>  struct ppc_hash_pte64 {
>      uint64_t pte0, pte1;
> diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
> index 1381635..0176ab6 100644
> --- a/target/ppc/mmu_helper.c
> +++ b/target/ppc/mmu_helper.c
> @@ -2001,8 +2001,9 @@ void ppc_tlb_invalidate_one(CPUPPCState *env,
> target_ulong addr)
>  /* Special registers manipulation */
>  void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
>  {
> +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
>      qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__,
> value);
> -    assert(!env->external_htab);
> +    assert(!cpu->vhyp);
>  #if defined(TARGET_PPC64)
>      if (env->mmu_model & POWERPC_MMU_64) {
>          PowerPCCPU *cpu = ppc_env_get_cpu(env);

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

* Re: [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables
  2017-02-23  5:52   ` Suraj Jitindar Singh
@ 2017-02-24  3:45     ` David Gibson
  2017-02-24  5:34     ` David Gibson
  1 sibling, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-02-24  3:45 UTC (permalink / raw)
  To: Suraj Jitindar Singh
  Cc: qemu-ppc, aik, qemu-devel, agraf, thuth, lvivier, mdroth, paulus

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

On Thu, Feb 23, 2017 at 04:52:59PM +1100, Suraj Jitindar Singh wrote:
> On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> > CPUPPCState includes fields htab_base and htab_mask which store the
> > base
> > address (GPA) and size (as a mask) of the guest's hashed page table
> > (HPT).
> > These are set when the SDR1 register is updated.
> > 
> > Keeping these in sync with the SDR1 is actually a little bit fiddly,
> > and
> > probably not useful for performance, since keeping them expands the
> > size of
> > CPUPPCState.  It also makes some upcoming changes harder to
> > implement.
> > 
> > This patch removes these fields, in favour of calculating them
> > directly
> > from the SDR1 contents when necessary.
> > 
> > This does make a change to the behaviour of attempting to write a bad
> > value
> > (invalid HPT size) to the SDR1 with an mtspr
> > instruction.  Previously, the
> > bad value would be stored in SDR1 and could be retrieved with a later
> > mfspr, but the HPT size as used by the softmmu would be, clamped to
> > the
> > allowed values.  Now, writing a bad value is treated as a no-op.  An
> > error
> > message is printed in both new and old versions.
> > 
> > I'm not sure which behaviour, if either, matches real hardware.  I
> > don't
> > think it matters that much, since it's pretty clear that if an OS
> > writes
> > a bad value to SDR1, it's not going to boot.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> 
> Comments Below.
> 
> > ---
> >  hw/ppc/spapr_hcall.c    |  4 ++--
> >  target/ppc/cpu.h        |  8 --------
> >  target/ppc/machine.c    |  1 -
> >  target/ppc/mmu-hash32.c | 14 +++++++-------
> >  target/ppc/mmu-hash32.h | 24 ++++++++++++++++++------
> >  target/ppc/mmu-hash64.c | 37 ++++++++++++++++---------------------
> >  target/ppc/mmu-hash64.h | 13 +++++++++++++
> >  target/ppc/mmu_helper.c | 31 ++++++++++++++++---------------
> >  8 files changed, 72 insertions(+), 60 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index fd961b5..85d96f6 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -50,9 +50,9 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
> >  static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
> >  {
> >      /*
> > -     * hash value/pteg group index is normalized by htab_mask
> > +     * hash value/pteg group index is normalized by HPT mask
> >       */
> > -    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) {
> > +    if (((ptex & ~7ULL) / HPTES_PER_GROUP) &
> > ~ppc_hash64_hpt_mask(cpu)) {
> >          return false;
> >      }
> >      return true;
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index c89973e..c6cd9ab 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -309,11 +309,6 @@ union ppc_tlb_t {
> >  #define SDR_32_HTABORG         0xFFFF0000UL
> >  #define SDR_32_HTABMASK        0x000001FFUL
> >  
> > -#if defined(TARGET_PPC64)
> > -#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> > -#define SDR_64_HTABSIZE        0x000000000000001FULL
> > -#endif /* defined(TARGET_PPC64 */
> > -
> >  typedef struct ppc_slb_t ppc_slb_t;
> >  struct ppc_slb_t {
> >      uint64_t esid;
> > @@ -1006,9 +1001,6 @@ struct CPUPPCState {
> >      /* tcg TLB needs flush (deferred slb inval instruction
> > typically) */
> >  #endif
> >      /* segment registers */
> > -    hwaddr htab_base;
> > -    /* mask used to normalize hash value to PTEG index */
> > -    hwaddr htab_mask;
> >      target_ulong sr[32];
> >      /* externally stored hash table */
> >      uint8_t *external_htab;
> > diff --git a/target/ppc/machine.c b/target/ppc/machine.c
> > index df9f7a4..1ccbc8a 100644
> > --- a/target/ppc/machine.c
> > +++ b/target/ppc/machine.c
> > @@ -229,7 +229,6 @@ static int cpu_post_load(void *opaque, int
> > version_id)
> >      }
> >  
> >      if (!env->external_htab) {
> > -        /* Restore htab_base and htab_mask variables */
> >          ppc_store_sdr1(env, env->spr[SPR_SDR1]);
> 
> Do we still need to do this? As far as I can tell it pretty much does:
> env->spr[SPR_SDR1] = env->spr[SPR_SDR1]
> and checks the htab_size, which would have been done when we set SDR1
> in the first place anyway?

I'd prefer to recheck it here: if we had a bug in the verification,
then fixed it, I wouldn't want the bugfix to be bypassed by migrating
in from an older version.

> >      }
> >  
> > diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
> > index 29bace6..03ae3c1 100644
> > --- a/target/ppc/mmu-hash32.c
> > +++ b/target/ppc/mmu-hash32.c
> > @@ -304,9 +304,9 @@ static int ppc_hash32_direct_store(PowerPCCPU
> > *cpu, target_ulong sr,
> >  
> >  hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> > +    target_ulong mask = ppc_hash32_hpt_mask(cpu);
> >  
> > -    return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
> > +    return (hash * HASH_PTEG_SIZE_32) & mask;
> >  }
> >  
> >  static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr
> > pteg_off,
> > @@ -339,7 +339,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU
> > *cpu,
> >                                       target_ulong sr, target_ulong
> > eaddr,
> >                                       ppc_hash_pte32_t *pte)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> >      hwaddr pteg_off, pte_offset;
> >      hwaddr hash;
> >      uint32_t vsid, pgidx, ptem;
> > @@ -353,21 +352,22 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU
> > *cpu,
> >      qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
> >              " htab_mask " TARGET_FMT_plx
> >              " hash " TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, hash);
> > +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
> > hash);
> >  
> >      /* Primary PTEG lookup */
> >      qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/"
> > TARGET_FMT_plx
> >              " vsid=%" PRIx32 " ptem=%" PRIx32
> >              " hash=" TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, vsid, ptem, hash);
> > +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
> > +            vsid, ptem, hash);
> >      pteg_off = get_pteg_offset32(cpu, hash);
> >      pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem,
> > pte);
> >      if (pte_offset == -1) {
> >          /* Secondary PTEG lookup */
> >          qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/"
> > TARGET_FMT_plx
> >                  " vsid=%" PRIx32 " api=%" PRIx32
> > -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> > -                env->htab_mask, vsid, ptem, ~hash);
> > +                " hash=" TARGET_FMT_plx "\n",
> > ppc_hash32_hpt_base(cpu),
> > +                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
> >          pteg_off = get_pteg_offset32(cpu, ~hash);
> >          pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem,
> > pte);
> >      }
> > diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
> > index 5b9fb08..054be65 100644
> > --- a/target/ppc/mmu-hash32.h
> > +++ b/target/ppc/mmu-hash32.h
> > @@ -65,42 +65,54 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu,
> > vaddr address, int rw,
> >  #define HPTE32_R_WIMG           0x00000078
> >  #define HPTE32_R_PP             0x00000003
> >  
> > +static inline hwaddr ppc_hash32_hpt_base(PowerPCCPU *cpu)
> > +{
> > +    return cpu->env.spr[SPR_SDR1] & SDR_32_HTABORG;
> > +}
> > +
> > +static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
> > +{
> > +    return ((cpu->env.spr[SPR_SDR1] & SDR_32_HTABMASK) << 16) |
> > 0xFFFF;
> > +}
> > +
> >  static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
> >                                                   hwaddr pte_offset)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now
> > */
> > -    return ldl_phys(CPU(cpu)->as, env->htab_base + pte_offset);
> > +    return ldl_phys(CPU(cpu)->as, base + pte_offset);
> >  }
> >  
> >  static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
> >                                                   hwaddr pte_offset)
> >  {
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >      CPUPPCState *env = &cpu->env;
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now
> > */
> > -    return ldl_phys(CPU(cpu)->as,
> > -                    env->htab_base + pte_offset + HASH_PTE_SIZE_32 /
> > 2);
> > +    return ldl_phys(CPU(cpu)->as, base + pte_offset +
> > HASH_PTE_SIZE_32 / 2);
> >  }
> >  
> >  static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
> >                                            hwaddr pte_offset,
> > target_ulong pte0)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now
> > */
> > -    stl_phys(CPU(cpu)->as, env->htab_base + pte_offset, pte0);
> > +    stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
> >  }
> >  
> >  static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
> >                                            hwaddr pte_offset,
> > target_ulong pte1)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now
> > */
> > -    stl_phys(CPU(cpu)->as,
> > -             env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2,
> > pte1);
> > +    stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2,
> > pte1);
> >  }
> >  
> >  typedef struct {
> > diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> > index c59db47..bb87777 100644
> > --- a/target/ppc/mmu-hash64.c
> > +++ b/target/ppc/mmu-hash64.c
> > @@ -304,15 +304,13 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu,
> > target_ulong value,
> >      CPUPPCState *env = &cpu->env;
> >      target_ulong htabsize = value & SDR_64_HTABSIZE;
> >  
> > -    env->spr[SPR_SDR1] = value;
> >      if (htabsize > 28) {
> >          error_setg(errp,
> >                     "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in
> > SDR1",
> >                     htabsize);
> > -        htabsize = 28;
> > +        return;
> >      }
> > -    env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
> > -    env->htab_base = value & SDR_64_HTABORG;
> > +    env->spr[SPR_SDR1] = value;
> >  }
> >  
> >  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> > shift,
> > @@ -333,10 +331,6 @@ void ppc_hash64_set_external_hpt(PowerPCCPU
> > *cpu, void *hpt, int shift,
> >          return;
> >      }
> >  
> > -    /* Not strictly necessary, but makes it clearer that an external
> > -     * htab is in use when debugging */
> > -    env->htab_base = -1;
> > -
> >      if (kvm_enabled()) {
> >          if (kvmppc_put_books_sregs(cpu) < 0) {
> >              error_setg(errp, "Unable to update SDR1 in KVM");
> > @@ -448,11 +442,12 @@ const ppc_hash_pte64_t
> > *ppc_hash64_map_hptes(PowerPCCPU *cpu,
> >           * HTAB is controlled by QEMU. Just point to the internally
> >           * accessible PTEG.
> >           */
> > -        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab +
> > pte_offset);
> > -    } else if (cpu->env.htab_base) {
> > +        hptes = (const ppc_hash_pte64_t *)(cpu->env.external_htab +
> > pte_offset);
> ^^^ Does this particular line belong in the previous patch?
> > +    } else if (ppc_hash64_hpt_base(cpu)) {
> > +        hwaddr base = ppc_hash64_hpt_base(cpu);
> >          hwaddr plen = n * HASH_PTE_SIZE_64;
> > -        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base +
> > pte_offset,
> > -                                 &plen, false);
> > +        hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
> > +                                  &plen, false);
> >          if (plen < (n * HASH_PTE_SIZE_64)) {
> >              hw_error("%s: Unable to map all requested HPTEs\n",
> > __FUNCTION__);
> >          }
> > @@ -513,13 +508,12 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU
> > *cpu, hwaddr hash,
> >                                       target_ulong ptem,
> >                                       ppc_hash_pte64_t *pte, unsigned
> > *pshift)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> >      int i;
> >      const ppc_hash_pte64_t *pteg;
> >      target_ulong pte0, pte1;
> >      target_ulong ptex;
> >  
> > -    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> > +    ptex = (hash & ppc_hash64_hpt_mask(cpu)) * HPTES_PER_GROUP;
> >      pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> >      if (!pteg) {
> >          return -1;
> > @@ -597,14 +591,15 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> > *cpu,
> >      qemu_log_mask(CPU_LOG_MMU,
> >              "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
> >              " hash " TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, hash);
> > +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
> > hash);
> >  
> >      /* Primary PTEG lookup */
> >      qemu_log_mask(CPU_LOG_MMU,
> >              "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
> >              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
> >              " hash=" TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, vsid, ptem,  hash);
> > +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
> > +            vsid, ptem,  hash);
> >      ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte,
> > pshift);
> >  
> >      if (ptex == -1) {
> > @@ -613,8 +608,8 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> > *cpu,
> >          qemu_log_mask(CPU_LOG_MMU,
> >                  "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
> >                  " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
> > -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> > -                env->htab_mask, vsid, ptem, ~hash);
> > +                " hash=" TARGET_FMT_plx "\n",
> > ppc_hash64_hpt_base(cpu),
> > +                ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash);
> >  
> >          ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte,
> > pshift);
> >      }
> > @@ -932,9 +927,9 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu,
> > hwaddr ptex,
> >          stq_p(env->external_htab + offset, pte0);
> >          stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2,
> > pte1);
> >      } else {
> > -        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
> > -        stq_phys(CPU(cpu)->as,
> > -                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2,
> > pte1);
> > +        hwaddr base = ppc_hash64_hpt_base(cpu);
> > +        stq_phys(CPU(cpu)->as, base + offset, pte0);
> > +        stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2,
> > pte1);
> >      }
> >  }
> >  
> > diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> > index 8637fe4..dc0bc99 100644
> > --- a/target/ppc/mmu-hash64.h
> > +++ b/target/ppc/mmu-hash64.h
> > @@ -56,6 +56,9 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
> >   * Hash page table definitions
> >   */
> >  
> > +#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> 
> I think this was just always wrong, but it should be
> 0x0FFFFFFFFFFC0000ULL
>   ^

Ah, good point.  I'll prepend a bugfix for that.

> > +#define SDR_64_HTABSIZE        0x000000000000001FULL
> > +
> >  #define HPTES_PER_GROUP         8
> >  #define HASH_PTE_SIZE_64        16
> >  #define HASH_PTEG_SIZE_64       (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
> > @@ -91,6 +94,16 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
> >  #define HPTE64_V_1TB_SEG        0x4000000000000000ULL
> >  #define HPTE64_V_VRMA_MASK      0x4001ffffff000000ULL
> >  
> > +static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
> > +{
> > +    return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG;
> > +}
> > +
> > +static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
> > +{
> > +    return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18
> > - 7)) - 1;
> > +}
> > +
> >  void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
> >                           Error **errp);
> >  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> > shift,
> > diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
> > index eb2d482..1381635 100644
> > --- a/target/ppc/mmu_helper.c
> > +++ b/target/ppc/mmu_helper.c
> > @@ -466,6 +466,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env,
> > mmu_ctx_t *ctx,
> >  static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t
> > *ctx,
> >                                        target_ulong eaddr, int rw,
> > int type)
> >  {
> > +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> >      hwaddr hash;
> >      target_ulong vsid;
> >      int ds, pr, target_page_bits;
> > @@ -503,7 +504,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState
> > *env, mmu_ctx_t *ctx,
> >              qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
> >                      " htab_mask " TARGET_FMT_plx
> >                      " hash " TARGET_FMT_plx "\n",
> > -                    env->htab_base, env->htab_mask, hash);
> > +                    ppc_hash32_hpt_base(cpu),
> > ppc_hash32_hpt_mask(cpu), hash);
> >              ctx->hash[0] = hash;
> >              ctx->hash[1] = ~hash;
> >  
> > @@ -518,9 +519,11 @@ static inline int
> > get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
> >                  uint32_t a0, a1, a2, a3;
> >  
> >                  qemu_log("Page table: " TARGET_FMT_plx " len "
> > TARGET_FMT_plx
> > -                         "\n", env->htab_base, env->htab_mask +
> > 0x80);
> > -                for (curaddr = env->htab_base;
> > -                     curaddr < (env->htab_base + env->htab_mask +
> > 0x80);
> > +                         "\n", ppc_hash32_hpt_base(cpu),
> > +                         ppc_hash32_hpt_mask(env) + 0x80);
> > +                for (curaddr = ppc_hash32_hpt_base(cpu);
> > +                     curaddr < (ppc_hash32_hpt_base(cpu)
> > +                                + ppc_hash32_hpt_mask(cpu) + 0x80);
> >                       curaddr += 16) {
> >                      a0 = ldl_phys(cs->as, curaddr);
> >                      a1 = ldl_phys(cs->as, curaddr + 4);
> > @@ -1205,12 +1208,13 @@ static void mmu6xx_dump_BATs(FILE *f,
> > fprintf_function cpu_fprintf,
> >  static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
> >                              CPUPPCState *env)
> >  {
> > +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> >      ppc6xx_tlb_t *tlb;
> >      target_ulong sr;
> >      int type, way, entry, i;
> >  
> > -    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env-
> > >htab_base);
> > -    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env-
> > >htab_mask);
> > +    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n",
> > ppc_hash32_hpt_base(cpu));
> > +    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n",
> > ppc_hash32_hpt_mask(cpu));
> >  
> >      cpu_fprintf(f, "\nSegment registers:\n");
> >      for (i = 0; i < 32; i++) {
> > @@ -1592,9 +1596,9 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState
> > *env, target_ulong address,
> >                      env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
> >                  tlb_miss:
> >                      env->error_code |= ctx.key << 19;
> > -                    env->spr[SPR_HASH1] = env->htab_base +
> > +                    env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
> >                          get_pteg_offset32(cpu, ctx.hash[0]);
> > -                    env->spr[SPR_HASH2] = env->htab_base +
> > +                    env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
> >                          get_pteg_offset32(cpu, ctx.hash[1]);
> >                      break;
> >                  case POWERPC_MMU_SOFT_74xx:
> > @@ -1999,7 +2003,6 @@ void ppc_store_sdr1(CPUPPCState *env,
> > target_ulong value)
> >  {
> >      qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__,
> > value);
> >      assert(!env->external_htab);
> > -    env->spr[SPR_SDR1] = value;
> >  #if defined(TARGET_PPC64)
> >      if (env->mmu_model & POWERPC_MMU_64) {
> >          PowerPCCPU *cpu = ppc_env_get_cpu(env);
> > @@ -2009,14 +2012,12 @@ void ppc_store_sdr1(CPUPPCState *env,
> > target_ulong value)
> >          if (local_err) {
> >              error_report_err(local_err);
> >              error_free(local_err);
> > +            return;
> >          }
> > -    } else
> > -#endif /* defined(TARGET_PPC64) */
> > -    {
> > -        /* FIXME: Should check for valid HTABMASK values */
> > -        env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
> > -        env->htab_base = value & SDR_32_HTABORG;
> >      }
> > +#endif /* defined(TARGET_PPC64) */
> > +    /* FIXME: Should check for valid HTABMASK values in 32-bit case
> > */
> > +    env->spr[SPR_SDR1] = value;
> >  }
> >  
> >  /* Segment registers load and store */
> 

-- 
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: 819 bytes --]

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

* Re: [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU
  2017-02-23  5:37   ` Suraj Jitindar Singh
@ 2017-02-24  5:25     ` David Gibson
  0 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-02-24  5:25 UTC (permalink / raw)
  To: Suraj Jitindar Singh
  Cc: qemu-ppc, aik, qemu-devel, agraf, thuth, lvivier, mdroth, paulus

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

On Thu, Feb 23, 2017 at 04:37:00PM +1100, Suraj Jitindar Singh wrote:
> On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> > Accesses to the hashed page table (HPT) are complicated by the fact
> > that
> > the HPT could be in one of three places:
> >    1) Within guest memory - when we're emulating a full guest CPU at
> > the
> >       hardware level (e.g. powernv, mac99, g3beige)
> >    2) Within qemu, but outside guest memory - when we're emulating
> > user and
> >       supervisor instructions within TCG, but instead of emulating
> >       the CPU's hypervisor mode, we just emulate a hypervisor's
> > behaviour
> >       (pseries in TCG)
> >    3) Within KVM - a pseries machine using KVM acceleration.  Mostly
> >       accesses to the HPT are handled by KVM, but there are a few
> > cases
> >       where qemu needs to access it via a special fd for the purpose.
> 
> Should you clarify that this is the case for KVM-HV with KVM-PR the
> same as (2)?

Ah, good idea.

> 
> > 
> > In order to batch accesses to the fd in case (3), we use a somewhat
> > awkward
> > ppc_hash64_start_access() / ppc_hash64_stop_access() pair, which for
> > case
> > (3) reads / releases a whole PTEG from the kernel.  For cases (1) &
> > (2)
> > it just returns an address value.  The actual HPTE load helpers then
> > need
> > to interpret the returned token differently in the 3 cases.
> > 
> > This patch keeps the same basic structure, but simplfiies the
> > details.
> > First start_access() / stop_access() are renamed to get_pteg() and
> > put_pteg() to make their operation more obvious.  Second, read_pteg()
> 
> Here you say they've been renamed to get/put/read_pteg, but in the code
> they're called map/unmap_hptes and it looks like map_hptes does both
> the get and the read?

Oops, I'll update.

> 
> > now
> > always returns a qemu pointer, which can always be used in the same
> > way
> > by the load_hpte() helpers.  In case (1) it comes from
> > address_space_map()
> > in case (2) directly from qemu's HPT buffer and in case (3) from a
> > temporary buffer read from the KVM fd.
> > 
> > While we're at it, make things a bit more consistent in terms of
> > types and
> > variable names: avoid variables named 'index' (it shadows index(3)
> > which
> > can lead to confusing results), use 'hwaddr ptex' for HPTE indices
> > and
> > uint64_t for each of the HPTE words, use ptex throughout the call
> > stack
> > instead of pte_offset in some places (we still need that at the
> > bottom
> > layer, but nowhere else).
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> 
> Other than the commit message:
> 
> Reviewed-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
> 
> > ---
> >  hw/ppc/spapr_hcall.c    | 36 +++++++++---------
> >  target/ppc/cpu.h        |  3 +-
> >  target/ppc/kvm.c        | 25 ++++++-------
> >  target/ppc/kvm_ppc.h    | 43 ++++++++++------------
> >  target/ppc/mmu-hash64.c | 98 ++++++++++++++++++++++++++-------------
> > ----------
> >  target/ppc/mmu-hash64.h | 46 ++++++++---------------
> >  6 files changed, 119 insertions(+), 132 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index 3298a14..fd961b5 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -84,7 +84,7 @@ static target_ulong h_enter(PowerPCCPU *cpu,
> > sPAPRMachineState *spapr,
> >      unsigned apshift;
> >      target_ulong raddr;
> >      target_ulong slot;
> > -    uint64_t token;
> > +    const ppc_hash_pte64_t *hptes;
> >  
> >      apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
> >      if (!apshift) {
> > @@ -123,23 +123,23 @@ static target_ulong h_enter(PowerPCCPU *cpu,
> > sPAPRMachineState *spapr,
> >      ptex = ptex & ~7ULL;
> >  
> >      if (likely((flags & H_EXACT) == 0)) {
> > -        token = ppc_hash64_start_access(cpu, ptex);
> > +        hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> >          for (slot = 0; slot < 8; slot++) {
> > -            if (!(ppc_hash64_load_hpte0(cpu, token, slot) &
> > HPTE64_V_VALID)) {
> > +            if (!(ppc_hash64_hpte0(cpu, hptes, slot) &
> > HPTE64_V_VALID)) {
> >                  break;
> >              }
> >          }
> > -        ppc_hash64_stop_access(cpu, token);
> > +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
> >          if (slot == 8) {
> >              return H_PTEG_FULL;
> >          }
> >      } else {
> > -        token = ppc_hash64_start_access(cpu, ptex);
> > -        if (ppc_hash64_load_hpte0(cpu, token, 0) & HPTE64_V_VALID) {
> > -            ppc_hash64_stop_access(cpu, token);
> > +        hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
> > +        if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
> > +            ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
> >              return H_PTEG_FULL;
> >          }
> > -        ppc_hash64_stop_access(cpu, token);
> > +        ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> >      }
> >  
> >      ppc_hash64_store_hpte(cpu, ptex + slot, pteh |
> > HPTE64_V_HPTE_DIRTY, ptel);
> > @@ -160,17 +160,17 @@ static RemoveResult remove_hpte(PowerPCCPU
> > *cpu, target_ulong ptex,
> >                                  target_ulong flags,
> >                                  target_ulong *vp, target_ulong *rp)
> >  {
> > -    uint64_t token;
> > +    const ppc_hash_pte64_t *hptes;
> >      target_ulong v, r;
> >  
> >      if (!valid_ptex(cpu, ptex)) {
> >          return REMOVE_PARM;
> >      }
> >  
> > -    token = ppc_hash64_start_access(cpu, ptex);
> > -    v = ppc_hash64_load_hpte0(cpu, token, 0);
> > -    r = ppc_hash64_load_hpte1(cpu, token, 0);
> > -    ppc_hash64_stop_access(cpu, token);
> > +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> > +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> > +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> > +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> >  
> >      if ((v & HPTE64_V_VALID) == 0 ||
> >          ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
> > @@ -291,17 +291,17 @@ static target_ulong h_protect(PowerPCCPU *cpu,
> > sPAPRMachineState *spapr,
> >      target_ulong flags = args[0];
> >      target_ulong ptex = args[1];
> >      target_ulong avpn = args[2];
> > -    uint64_t token;
> > +    const ppc_hash_pte64_t *hptes;
> >      target_ulong v, r;
> >  
> >      if (!valid_ptex(cpu, ptex)) {
> >          return H_PARAMETER;
> >      }
> >  
> > -    token = ppc_hash64_start_access(cpu, ptex);
> > -    v = ppc_hash64_load_hpte0(cpu, token, 0);
> > -    r = ppc_hash64_load_hpte1(cpu, token, 0);
> > -    ppc_hash64_stop_access(cpu, token);
> > +    hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
> > +    v = ppc_hash64_hpte0(cpu, hptes, 0);
> > +    r = ppc_hash64_hpte1(cpu, hptes, 0);
> > +    ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
> >  
> >      if ((v & HPTE64_V_VALID) == 0 ||
> >          ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index f99bcae..c89973e 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -223,11 +223,12 @@ enum {
> >  typedef struct opc_handler_t opc_handler_t;
> >  
> >  /*******************************************************************
> > **********/
> > -/* Types used to describe some PowerPC registers */
> > +/* Types used to describe some PowerPC registers etc. */
> >  typedef struct DisasContext DisasContext;
> >  typedef struct ppc_spr_t ppc_spr_t;
> >  typedef union ppc_avr_t ppc_avr_t;
> >  typedef union ppc_tlb_t ppc_tlb_t;
> > +typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
> >  
> >  /* SPR access micro-ops generations callbacks */
> >  struct ppc_spr_t {
> > diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> > index 52bbea5..9d3e57e 100644
> > --- a/target/ppc/kvm.c
> > +++ b/target/ppc/kvm.c
> > @@ -2601,17 +2601,17 @@ struct kvm_get_htab_buf {
> >      /*
> >       * We require one extra byte for read
> >       */
> > -    target_ulong hpte[(HPTES_PER_GROUP * 2) + 1];
> > +    ppc_hash_pte64_t hpte[HPTES_PER_GROUP];
> >  };
> >  
> > -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong
> > pte_index)
> > +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)
> >  {
> >      int htab_fd;
> >      struct kvm_get_htab_fd ghf;
> > -    struct kvm_get_htab_buf  *hpte_buf;
> > +    struct kvm_get_htab_buf *hpte_buf;
> >  
> >      ghf.flags = 0;
> > -    ghf.start_index = pte_index;
> > +    ghf.start_index = ptex;
> >      htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
> >      if (htab_fd < 0) {
> >          goto error_out;
> > @@ -2626,7 +2626,7 @@ uint64_t kvmppc_hash64_read_pteg(PowerPCCPU
> > *cpu, target_ulong pte_index)
> >      }
> >  
> >      close(htab_fd);
> > -    return (uint64_t)(uintptr_t) hpte_buf->hpte;
> > +    return hpte_buf->hpte;
> >  
> >  out_close:
> >      g_free(hpte_buf);
> > @@ -2635,18 +2635,15 @@ error_out:
> >      return 0;
> >  }
> >  
> > -void kvmppc_hash64_free_pteg(uint64_t token)
> > +void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex,
> > int n)
> >  {
> >      struct kvm_get_htab_buf *htab_buf;
> >  
> > -    htab_buf = container_of((void *)(uintptr_t) token, struct
> > kvm_get_htab_buf,
> > -                            hpte);
> > +    htab_buf = container_of((void *)hptes, struct kvm_get_htab_buf,
> > hpte);
> >      g_free(htab_buf);
> > -    return;
> >  }
> >  
> > -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong
> > pte_index,
> > -                             target_ulong pte0, target_ulong pte1)
> > +void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t
> > pte1)
> >  {
> >      int htab_fd;
> >      struct kvm_get_htab_fd ghf;
> > @@ -2661,9 +2658,9 @@ void kvmppc_hash64_write_pte(CPUPPCState *env,
> > target_ulong pte_index,
> >  
> >      hpte_buf.header.n_valid = 1;
> >      hpte_buf.header.n_invalid = 0;
> > -    hpte_buf.header.index = pte_index;
> > -    hpte_buf.hpte[0] = pte0;
> > -    hpte_buf.hpte[1] = pte1;
> > +    hpte_buf.header.index = ptex;
> > +    hpte_buf.hpte[0].pte0 = pte0;
> > +    hpte_buf.hpte[0].pte1 = pte1;
> >      /*
> >       * Write the hpte entry.
> >       * CAUTION: write() has the warn_unused_result attribute. Hence
> > we
> > diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
> > index 8da2ee4..3f8fccd 100644
> > --- a/target/ppc/kvm_ppc.h
> > +++ b/target/ppc/kvm_ppc.h
> > @@ -41,6 +41,10 @@ void *kvmppc_create_spapr_tce(uint32_t liobn,
> > uint32_t window_size, int *pfd,
> >  int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t
> > window_size);
> >  int kvmppc_reset_htab(int shift_hint);
> >  uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int
> > hash_shift);
> > +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n);
> > +void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes, hwaddr ptex,
> > int n);
> > +
> > +void kvmppc_hash64_write_pte(hwaddr ptex, uint64_t pte0, uint64_t
> > pte1);
> >  #endif /* !CONFIG_USER_ONLY */
> >  bool kvmppc_has_cap_epr(void);
> >  int kvmppc_define_rtas_kernel_token(uint32_t token, const char
> > *function);
> > @@ -49,11 +53,6 @@ int kvmppc_get_htab_fd(bool write);
> >  int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t
> > max_ns);
> >  int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
> >                             uint16_t n_valid, uint16_t n_invalid);
> > -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong
> > pte_index);
> > -void kvmppc_hash64_free_pteg(uint64_t token);
> > -
> > -void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong
> > pte_index,
> > -                             target_ulong pte0, target_ulong pte1);
> >  bool kvmppc_has_cap_fixup_hcalls(void);
> >  bool kvmppc_has_cap_htm(void);
> >  int kvmppc_enable_hwrng(void);
> > @@ -199,6 +198,22 @@ static inline bool
> > kvmppc_is_mem_backend_page_size_ok(char *obj_path)
> >      return true;
> >  }
> >  
> > +static inline const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex,
> > int n)
> > +{
> > +    abort();
> > +}
> > +
> > +static inline void kvmppc_unmap_hptes(const ppc_hash_pte64_t *hptes,
> > +                                      hwaddr ptex, int n)
> > +{
> > +    abort();
> > +}
> > +
> > +static inline void kvmppc_hash64_write_pte(hwaddr ptex,
> > +                                           uint64_t pte0, uint64_t
> > pte1)
> > +{
> > +    abort();
> > +}
> >  #endif /* !CONFIG_USER_ONLY */
> >  
> >  static inline bool kvmppc_has_cap_epr(void)
> > @@ -234,24 +249,6 @@ static inline int
> > kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
> >      abort();
> >  }
> >  
> > -static inline uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu,
> > -                                               target_ulong
> > pte_index)
> > -{
> > -    abort();
> > -}
> > -
> > -static inline void kvmppc_hash64_free_pteg(uint64_t token)
> > -{
> > -    abort();
> > -}
> > -
> > -static inline void kvmppc_hash64_write_pte(CPUPPCState *env,
> > -                                           target_ulong pte_index,
> > -                                           target_ulong pte0,
> > target_ulong pte1)
> > -{
> > -    abort();
> > -}
> > -
> >  static inline bool kvmppc_has_cap_fixup_hcalls(void)
> >  {
> >      abort();
> > diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> > index 76669ed..c59db47 100644
> > --- a/target/ppc/mmu-hash64.c
> > +++ b/target/ppc/mmu-hash64.c
> > @@ -27,6 +27,7 @@
> >  #include "kvm_ppc.h"
> >  #include "mmu-hash64.h"
> >  #include "exec/log.h"
> > +#include "hw/hw.h"
> >  
> >  //#define DEBUG_SLB
> >  
> > @@ -431,33 +432,42 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu,
> > ppc_hash_pte64_t pte)
> >      return prot;
> >  }
> >  
> > -uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong
> > pte_index)
> > +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
> > +                                             hwaddr ptex, int n)
> >  {
> > -    uint64_t token = 0;
> > -    hwaddr pte_offset;
> > +    const ppc_hash_pte64_t *hptes = NULL;
> > +    hwaddr pte_offset = ptex * HASH_PTE_SIZE_64;
> >  
> > -    pte_offset = pte_index * HASH_PTE_SIZE_64;
> >      if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> >          /*
> >           * HTAB is controlled by KVM. Fetch the PTEG into a new
> > buffer.
> >           */
> > -        token = kvmppc_hash64_read_pteg(cpu, pte_index);
> > +        hptes = kvmppc_map_hptes(ptex, n);
> >      } else if (cpu->env.external_htab) {
> >          /*
> >           * HTAB is controlled by QEMU. Just point to the internally
> >           * accessible PTEG.
> >           */
> > -        token = (uint64_t)(uintptr_t) cpu->env.external_htab +
> > pte_offset;
> > +        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab +
> > pte_offset);
> >      } else if (cpu->env.htab_base) {
> > -        token = cpu->env.htab_base + pte_offset;
> > +        hwaddr plen = n * HASH_PTE_SIZE_64;
> > +        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base +
> > pte_offset,
> > +                                 &plen, false);
> > +        if (plen < (n * HASH_PTE_SIZE_64)) {
> > +            hw_error("%s: Unable to map all requested HPTEs\n",
> > __FUNCTION__);
> > +        }
> >      }
> > -    return token;
> > +    return hptes;
> >  }
> >  
> > -void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token)
> > +void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t
> > *hptes,
> > +                            hwaddr ptex, int n)
> >  {
> >      if (cpu->env.external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> > -        kvmppc_hash64_free_pteg(token);
> > +        kvmppc_unmap_hptes(hptes, ptex, n);
> > +    } else if (!cpu->env.external_htab) {
> > +        address_space_unmap(CPU(cpu)->as, (void *)hptes, n *
> > HASH_PTE_SIZE_64,
> > +                            false, n * HASH_PTE_SIZE_64);
> >      }
> >  }
> >  
> > @@ -505,18 +515,18 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU
> > *cpu, hwaddr hash,
> >  {
> >      CPUPPCState *env = &cpu->env;
> >      int i;
> > -    uint64_t token;
> > +    const ppc_hash_pte64_t *pteg;
> >      target_ulong pte0, pte1;
> > -    target_ulong pte_index;
> > +    target_ulong ptex;
> >  
> > -    pte_index = (hash & env->htab_mask) * HPTES_PER_GROUP;
> > -    token = ppc_hash64_start_access(cpu, pte_index);
> > -    if (!token) {
> > +    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> > +    pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> > +    if (!pteg) {
> >          return -1;
> >      }
> >      for (i = 0; i < HPTES_PER_GROUP; i++) {
> > -        pte0 = ppc_hash64_load_hpte0(cpu, token, i);
> > -        pte1 = ppc_hash64_load_hpte1(cpu, token, i);
> > +        pte0 = ppc_hash64_hpte0(cpu, pteg, i);
> > +        pte1 = ppc_hash64_hpte1(cpu, pteg, i);
> >  
> >          /* This compares V, B, H (secondary) and the AVPN */
> >          if (HPTE64_V_COMPARE(pte0, ptem)) {
> > @@ -536,11 +546,11 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU
> > *cpu, hwaddr hash,
> >               */
> >              pte->pte0 = pte0;
> >              pte->pte1 = pte1;
> > -            ppc_hash64_stop_access(cpu, token);
> > -            return (pte_index + i) * HASH_PTE_SIZE_64;
> > +            ppc_hash64_unmap_hptes(cpu, pteg, ptex,
> > HPTES_PER_GROUP);
> > +            return ptex + i;
> >          }
> >      }
> > -    ppc_hash64_stop_access(cpu, token);
> > +    ppc_hash64_unmap_hptes(cpu, pteg, ptex, HPTES_PER_GROUP);
> >      /*
> >       * We didn't find a valid entry.
> >       */
> > @@ -552,8 +562,7 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> > *cpu,
> >                                       ppc_hash_pte64_t *pte, unsigned
> > *pshift)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > -    hwaddr pte_offset;
> > -    hwaddr hash;
> > +    hwaddr hash, ptex;
> >      uint64_t vsid, epnmask, epn, ptem;
> >      const struct ppc_one_seg_page_size *sps = slb->sps;
> >  
> > @@ -596,9 +605,9 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> > *cpu,
> >              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
> >              " hash=" TARGET_FMT_plx "\n",
> >              env->htab_base, env->htab_mask, vsid, ptem,  hash);
> > -    pte_offset = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte,
> > pshift);
> > +    ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte,
> > pshift);
> >  
> > -    if (pte_offset == -1) {
> > +    if (ptex == -1) {
> >          /* Secondary PTEG lookup */
> >          ptem |= HPTE64_V_SECONDARY;
> >          qemu_log_mask(CPU_LOG_MMU,
> > @@ -607,10 +616,10 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> > *cpu,
> >                  " hash=" TARGET_FMT_plx "\n", env->htab_base,
> >                  env->htab_mask, vsid, ptem, ~hash);
> >  
> > -        pte_offset = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem,
> > pte, pshift);
> > +        ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte,
> > pshift);
> >      }
> >  
> > -    return pte_offset;
> > +    return ptex;
> >  }
> >  
> >  unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
> > @@ -708,7 +717,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu,
> > vaddr eaddr,
> >      CPUPPCState *env = &cpu->env;
> >      ppc_slb_t *slb;
> >      unsigned apshift;
> > -    hwaddr pte_offset;
> > +    hwaddr ptex;
> >      ppc_hash_pte64_t pte;
> >      int pp_prot, amr_prot, prot;
> >      uint64_t new_pte1, dsisr;
> > @@ -792,8 +801,8 @@ skip_slb_search:
> >      }
> >  
> >      /* 4. Locate the PTE in the hash table */
> > -    pte_offset = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte,
> > &apshift);
> > -    if (pte_offset == -1) {
> > +    ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
> > +    if (ptex == -1) {
> >          dsisr = 0x40000000;
> >          if (rwx == 2) {
> >              ppc_hash64_set_isi(cs, env, dsisr);
> > @@ -806,7 +815,7 @@ skip_slb_search:
> >          return 1;
> >      }
> >      qemu_log_mask(CPU_LOG_MMU,
> > -                "found PTE at offset %08" HWADDR_PRIx "\n",
> > pte_offset);
> > +                  "found PTE at index %08" HWADDR_PRIx "\n", ptex);
> >  
> >      /* 5. Check access permissions */
> >  
> > @@ -849,8 +858,7 @@ skip_slb_search:
> >      }
> >  
> >      if (new_pte1 != pte.pte1) {
> > -        ppc_hash64_store_hpte(cpu, pte_offset / HASH_PTE_SIZE_64,
> > -                              pte.pte0, new_pte1);
> > +        ppc_hash64_store_hpte(cpu, ptex, pte.pte0, new_pte1);
> >      }
> >  
> >      /* 7. Determine the real address from the PTE */
> > @@ -867,7 +875,7 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU
> > *cpu, target_ulong addr)
> >  {
> >      CPUPPCState *env = &cpu->env;
> >      ppc_slb_t *slb;
> > -    hwaddr pte_offset, raddr;
> > +    hwaddr ptex, raddr;
> >      ppc_hash_pte64_t pte;
> >      unsigned apshift;
> >  
> > @@ -900,8 +908,8 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU
> > *cpu, target_ulong addr)
> >          }
> >      }
> >  
> > -    pte_offset = ppc_hash64_htab_lookup(cpu, slb, addr, &pte,
> > &apshift);
> > -    if (pte_offset == -1) {
> > +    ptex = ppc_hash64_htab_lookup(cpu, slb, addr, &pte, &apshift);
> > +    if (ptex == -1) {
> >          return -1;
> >      }
> >  
> > @@ -909,30 +917,28 @@ hwaddr
> > ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
> >          & TARGET_PAGE_MASK;
> >  }
> >  
> > -void ppc_hash64_store_hpte(PowerPCCPU *cpu,
> > -                           target_ulong pte_index,
> > -                           target_ulong pte0, target_ulong pte1)
> > +void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> > +                           uint64_t pte0, uint64_t pte1)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    hwaddr offset = ptex * HASH_PTE_SIZE_64;
> >  
> >      if (env->external_htab == MMU_HASH64_KVM_MANAGED_HPT) {
> > -        kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
> > +        kvmppc_hash64_write_pte(ptex, pte0, pte1);
> >          return;
> >      }
> >  
> > -    pte_index *= HASH_PTE_SIZE_64;
> >      if (env->external_htab) {
> > -        stq_p(env->external_htab + pte_index, pte0);
> > -        stq_p(env->external_htab + pte_index + HASH_PTE_SIZE_64 / 2,
> > pte1);
> > +        stq_p(env->external_htab + offset, pte0);
> > +        stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2,
> > pte1);
> >      } else {
> > -        stq_phys(CPU(cpu)->as, env->htab_base + pte_index, pte0);
> > +        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
> >          stq_phys(CPU(cpu)->as,
> > -                 env->htab_base + pte_index + HASH_PTE_SIZE_64 / 2,
> > pte1);
> > +                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2,
> > pte1);
> >      }
> >  }
> >  
> > -void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
> > -                               target_ulong pte_index,
> > +void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
> >                                 target_ulong pte0, target_ulong pte1)
> >  {
> >      /*
> > diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> > index 7a0b7fc..8637fe4 100644
> > --- a/target/ppc/mmu-hash64.h
> > +++ b/target/ppc/mmu-hash64.h
> > @@ -10,8 +10,8 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong
> > slot,
> >  hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong
> > addr);
> >  int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int
> > rw,
> >                                  int mmu_idx);
> > -void ppc_hash64_store_hpte(PowerPCCPU *cpu, target_ulong index,
> > -                           target_ulong pte0, target_ulong pte1);
> > +void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> > +                           uint64_t pte0, uint64_t pte1);
> >  void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
> >                                 target_ulong pte_index,
> >                                 target_ulong pte0, target_ulong
> > pte1);
> > @@ -96,41 +96,27 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu,
> > target_ulong value,
> >  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> > shift,
> >                                   Error **errp);
> >  
> > -uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong
> > pte_index);
> > -void ppc_hash64_stop_access(PowerPCCPU *cpu, uint64_t token);
> > +struct ppc_hash_pte64 {
> > +    uint64_t pte0, pte1;
> > +};
> > +
> > +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,\
> > +                                             hwaddr ptex, int n);
> > +void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t
> > *hptes,
> > +                            hwaddr ptex, int n);
> >  
> > -static inline target_ulong ppc_hash64_load_hpte0(PowerPCCPU *cpu,
> > -                                                 uint64_t token, int
> > index)
> > +static inline uint64_t ppc_hash64_hpte0(PowerPCCPU *cpu,
> > +                                        const ppc_hash_pte64_t
> > *hptes, int i)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> > -    uint64_t addr;
> > -
> > -    addr = token + (index * HASH_PTE_SIZE_64);
> > -    if (env->external_htab) {
> > -        return  ldq_p((const void *)(uintptr_t)addr);
> > -    } else {
> > -        return ldq_phys(CPU(cpu)->as, addr);
> > -    }
> > +    return ldq_p(&(hptes[i].pte0));
> >  }
> >  
> > -static inline target_ulong ppc_hash64_load_hpte1(PowerPCCPU *cpu,
> > -                                                 uint64_t token, int
> > index)
> > +static inline uint64_t ppc_hash64_hpte1(PowerPCCPU *cpu,
> > +                                        const ppc_hash_pte64_t
> > *hptes, int i)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> > -    uint64_t addr;
> > -
> > -    addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
> > -    if (env->external_htab) {
> > -        return  ldq_p((const void *)(uintptr_t)addr);
> > -    } else {
> > -        return ldq_phys(CPU(cpu)->as, addr);
> > -    }
> > +    return ldq_p(&(hptes[i].pte1));
> >  }
> >  
> > -typedef struct {
> > -    uint64_t pte0, pte1;
> > -} ppc_hash_pte64_t;
> > -
> >  #endif /* CONFIG_USER_ONLY */
> >  
> >  #endif /* MMU_HASH64_H */
> 

-- 
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: 819 bytes --]

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

* Re: [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables
  2017-02-23  5:43   ` Alexey Kardashevskiy
@ 2017-02-24  5:30     ` David Gibson
  0 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-02-24  5:30 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: qemu-ppc, sjitindarsingh, qemu-devel, agraf, thuth, lvivier,
	mdroth, paulus

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

On Thu, Feb 23, 2017 at 04:43:05PM +1100, Alexey Kardashevskiy wrote:
> On 23/02/17 13:09, David Gibson wrote:
> > CPUPPCState includes fields htab_base and htab_mask which store the base
> > address (GPA) and size (as a mask) of the guest's hashed page table (HPT).
> > These are set when the SDR1 register is updated.
> > 
> > Keeping these in sync with the SDR1 is actually a little bit fiddly, and
> > probably not useful for performance, since keeping them expands the size of
> > CPUPPCState.  It also makes some upcoming changes harder to implement.
> > 
> > This patch removes these fields, in favour of calculating them directly
> > from the SDR1 contents when necessary.
> > 
> > This does make a change to the behaviour of attempting to write a bad value
> > (invalid HPT size) to the SDR1 with an mtspr instruction.  Previously, the
> > bad value would be stored in SDR1 and could be retrieved with a later
> > mfspr, but the HPT size as used by the softmmu would be, clamped to the
> > allowed values.  Now, writing a bad value is treated as a no-op.  An error
> > message is printed in both new and old versions.
> > 
> > I'm not sure which behaviour, if either, matches real hardware.  I don't
> > think it matters that much, since it's pretty clear that if an OS writes
> > a bad value to SDR1, it's not going to boot.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr_hcall.c    |  4 ++--
> >  target/ppc/cpu.h        |  8 --------
> >  target/ppc/machine.c    |  1 -
> >  target/ppc/mmu-hash32.c | 14 +++++++-------
> >  target/ppc/mmu-hash32.h | 24 ++++++++++++++++++------
> >  target/ppc/mmu-hash64.c | 37 ++++++++++++++++---------------------
> >  target/ppc/mmu-hash64.h | 13 +++++++++++++
> >  target/ppc/mmu_helper.c | 31 ++++++++++++++++---------------
> >  8 files changed, 72 insertions(+), 60 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index fd961b5..85d96f6 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -50,9 +50,9 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
> >  static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
> >  {
> >      /*
> > -     * hash value/pteg group index is normalized by htab_mask
> > +     * hash value/pteg group index is normalized by HPT mask
> >       */
> > -    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) {
> > +    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) {
> >          return false;
> >      }
> >      return true;
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index c89973e..c6cd9ab 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -309,11 +309,6 @@ union ppc_tlb_t {
> >  #define SDR_32_HTABORG         0xFFFF0000UL
> >  #define SDR_32_HTABMASK        0x000001FFUL
> 
> 
> You could move these to target/ppc/mmu-hash32.h as well.

Good idea, done.

> Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> 
> 
> 
> 
> >  
> > -#if defined(TARGET_PPC64)
> > -#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> > -#define SDR_64_HTABSIZE        0x000000000000001FULL
> > -#endif /* defined(TARGET_PPC64 */
> > -
> >  typedef struct ppc_slb_t ppc_slb_t;
> >  struct ppc_slb_t {
> >      uint64_t esid;
> > @@ -1006,9 +1001,6 @@ struct CPUPPCState {
> >      /* tcg TLB needs flush (deferred slb inval instruction typically) */
> >  #endif
> >      /* segment registers */
> > -    hwaddr htab_base;
> > -    /* mask used to normalize hash value to PTEG index */
> > -    hwaddr htab_mask;
> >      target_ulong sr[32];
> >      /* externally stored hash table */
> >      uint8_t *external_htab;
> > diff --git a/target/ppc/machine.c b/target/ppc/machine.c
> > index df9f7a4..1ccbc8a 100644
> > --- a/target/ppc/machine.c
> > +++ b/target/ppc/machine.c
> > @@ -229,7 +229,6 @@ static int cpu_post_load(void *opaque, int version_id)
> >      }
> >  
> >      if (!env->external_htab) {
> > -        /* Restore htab_base and htab_mask variables */
> >          ppc_store_sdr1(env, env->spr[SPR_SDR1]);
> >      }
> >  
> > diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
> > index 29bace6..03ae3c1 100644
> > --- a/target/ppc/mmu-hash32.c
> > +++ b/target/ppc/mmu-hash32.c
> > @@ -304,9 +304,9 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
> >  
> >  hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> > +    target_ulong mask = ppc_hash32_hpt_mask(cpu);
> >  
> > -    return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
> > +    return (hash * HASH_PTEG_SIZE_32) & mask;
> >  }
> >  
> >  static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
> > @@ -339,7 +339,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
> >                                       target_ulong sr, target_ulong eaddr,
> >                                       ppc_hash_pte32_t *pte)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> >      hwaddr pteg_off, pte_offset;
> >      hwaddr hash;
> >      uint32_t vsid, pgidx, ptem;
> > @@ -353,21 +352,22 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
> >      qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
> >              " htab_mask " TARGET_FMT_plx
> >              " hash " TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, hash);
> > +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
> >  
> >      /* Primary PTEG lookup */
> >      qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
> >              " vsid=%" PRIx32 " ptem=%" PRIx32
> >              " hash=" TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, vsid, ptem, hash);
> > +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
> > +            vsid, ptem, hash);
> >      pteg_off = get_pteg_offset32(cpu, hash);
> >      pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
> >      if (pte_offset == -1) {
> >          /* Secondary PTEG lookup */
> >          qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
> >                  " vsid=%" PRIx32 " api=%" PRIx32
> > -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> > -                env->htab_mask, vsid, ptem, ~hash);
> > +                " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
> > +                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
> >          pteg_off = get_pteg_offset32(cpu, ~hash);
> >          pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
> >      }
> > diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
> > index 5b9fb08..054be65 100644
> > --- a/target/ppc/mmu-hash32.h
> > +++ b/target/ppc/mmu-hash32.h
> > @@ -65,42 +65,54 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr address, int rw,
> >  #define HPTE32_R_WIMG           0x00000078
> >  #define HPTE32_R_PP             0x00000003
> >  
> > +static inline hwaddr ppc_hash32_hpt_base(PowerPCCPU *cpu)
> > +{
> > +    return cpu->env.spr[SPR_SDR1] & SDR_32_HTABORG;
> > +}
> > +
> > +static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
> > +{
> > +    return ((cpu->env.spr[SPR_SDR1] & SDR_32_HTABMASK) << 16) | 0xFFFF;
> > +}
> > +
> >  static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
> >                                                   hwaddr pte_offset)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now */
> > -    return ldl_phys(CPU(cpu)->as, env->htab_base + pte_offset);
> > +    return ldl_phys(CPU(cpu)->as, base + pte_offset);
> >  }
> >  
> >  static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
> >                                                   hwaddr pte_offset)
> >  {
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >      CPUPPCState *env = &cpu->env;
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now */
> > -    return ldl_phys(CPU(cpu)->as,
> > -                    env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2);
> > +    return ldl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2);
> >  }
> >  
> >  static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
> >                                            hwaddr pte_offset, target_ulong pte0)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now */
> > -    stl_phys(CPU(cpu)->as, env->htab_base + pte_offset, pte0);
> > +    stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
> >  }
> >  
> >  static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
> >                                            hwaddr pte_offset, target_ulong pte1)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now */
> > -    stl_phys(CPU(cpu)->as,
> > -             env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
> > +    stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
> >  }
> >  
> >  typedef struct {
> > diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> > index c59db47..bb87777 100644
> > --- a/target/ppc/mmu-hash64.c
> > +++ b/target/ppc/mmu-hash64.c
> > @@ -304,15 +304,13 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
> >      CPUPPCState *env = &cpu->env;
> >      target_ulong htabsize = value & SDR_64_HTABSIZE;
> >  
> > -    env->spr[SPR_SDR1] = value;
> >      if (htabsize > 28) {
> >          error_setg(errp,
> >                     "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
> >                     htabsize);
> > -        htabsize = 28;
> > +        return;
> >      }
> > -    env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
> > -    env->htab_base = value & SDR_64_HTABORG;
> > +    env->spr[SPR_SDR1] = value;
> >  }
> >  
> >  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
> > @@ -333,10 +331,6 @@ void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
> >          return;
> >      }
> >  
> > -    /* Not strictly necessary, but makes it clearer that an external
> > -     * htab is in use when debugging */
> > -    env->htab_base = -1;
> > -
> >      if (kvm_enabled()) {
> >          if (kvmppc_put_books_sregs(cpu) < 0) {
> >              error_setg(errp, "Unable to update SDR1 in KVM");
> > @@ -448,11 +442,12 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
> >           * HTAB is controlled by QEMU. Just point to the internally
> >           * accessible PTEG.
> >           */
> > -        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
> > -    } else if (cpu->env.htab_base) {
> > +        hptes = (const ppc_hash_pte64_t *)(cpu->env.external_htab + pte_offset);
> > +    } else if (ppc_hash64_hpt_base(cpu)) {
> > +        hwaddr base = ppc_hash64_hpt_base(cpu);
> >          hwaddr plen = n * HASH_PTE_SIZE_64;
> > -        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base + pte_offset,
> > -                                 &plen, false);
> > +        hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
> > +                                  &plen, false);
> >          if (plen < (n * HASH_PTE_SIZE_64)) {
> >              hw_error("%s: Unable to map all requested HPTEs\n", __FUNCTION__);
> >          }
> > @@ -513,13 +508,12 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU *cpu, hwaddr hash,
> >                                       target_ulong ptem,
> >                                       ppc_hash_pte64_t *pte, unsigned *pshift)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> >      int i;
> >      const ppc_hash_pte64_t *pteg;
> >      target_ulong pte0, pte1;
> >      target_ulong ptex;
> >  
> > -    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> > +    ptex = (hash & ppc_hash64_hpt_mask(cpu)) * HPTES_PER_GROUP;
> >      pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> >      if (!pteg) {
> >          return -1;
> > @@ -597,14 +591,15 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
> >      qemu_log_mask(CPU_LOG_MMU,
> >              "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
> >              " hash " TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, hash);
> > +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu), hash);
> >  
> >      /* Primary PTEG lookup */
> >      qemu_log_mask(CPU_LOG_MMU,
> >              "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
> >              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
> >              " hash=" TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, vsid, ptem,  hash);
> > +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
> > +            vsid, ptem,  hash);
> >      ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte, pshift);
> >  
> >      if (ptex == -1) {
> > @@ -613,8 +608,8 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU *cpu,
> >          qemu_log_mask(CPU_LOG_MMU,
> >                  "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
> >                  " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
> > -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> > -                env->htab_mask, vsid, ptem, ~hash);
> > +                " hash=" TARGET_FMT_plx "\n", ppc_hash64_hpt_base(cpu),
> > +                ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash);
> >  
> >          ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte, pshift);
> >      }
> > @@ -932,9 +927,9 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
> >          stq_p(env->external_htab + offset, pte0);
> >          stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2, pte1);
> >      } else {
> > -        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
> > -        stq_phys(CPU(cpu)->as,
> > -                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2, pte1);
> > +        hwaddr base = ppc_hash64_hpt_base(cpu);
> > +        stq_phys(CPU(cpu)->as, base + offset, pte0);
> > +        stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2, pte1);
> >      }
> >  }
> >  
> > diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> > index 8637fe4..dc0bc99 100644
> > --- a/target/ppc/mmu-hash64.h
> > +++ b/target/ppc/mmu-hash64.h
> > @@ -56,6 +56,9 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
> >   * Hash page table definitions
> >   */
> >  
> > +#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> > +#define SDR_64_HTABSIZE        0x000000000000001FULL
> > +
> >  #define HPTES_PER_GROUP         8
> >  #define HASH_PTE_SIZE_64        16
> >  #define HASH_PTEG_SIZE_64       (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
> > @@ -91,6 +94,16 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
> >  #define HPTE64_V_1TB_SEG        0x4000000000000000ULL
> >  #define HPTE64_V_VRMA_MASK      0x4001ffffff000000ULL
> >  
> > +static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
> > +{
> > +    return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG;
> > +}
> > +
> > +static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
> > +{
> > +    return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18 - 7)) - 1;
> > +}
> > +
> >  void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
> >                           Error **errp);
> >  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int shift,
> > diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
> > index eb2d482..1381635 100644
> > --- a/target/ppc/mmu_helper.c
> > +++ b/target/ppc/mmu_helper.c
> > @@ -466,6 +466,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
> >  static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
> >                                        target_ulong eaddr, int rw, int type)
> >  {
> > +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> >      hwaddr hash;
> >      target_ulong vsid;
> >      int ds, pr, target_page_bits;
> > @@ -503,7 +504,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
> >              qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
> >                      " htab_mask " TARGET_FMT_plx
> >                      " hash " TARGET_FMT_plx "\n",
> > -                    env->htab_base, env->htab_mask, hash);
> > +                    ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
> >              ctx->hash[0] = hash;
> >              ctx->hash[1] = ~hash;
> >  
> > @@ -518,9 +519,11 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
> >                  uint32_t a0, a1, a2, a3;
> >  
> >                  qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
> > -                         "\n", env->htab_base, env->htab_mask + 0x80);
> > -                for (curaddr = env->htab_base;
> > -                     curaddr < (env->htab_base + env->htab_mask + 0x80);
> > +                         "\n", ppc_hash32_hpt_base(cpu),
> > +                         ppc_hash32_hpt_mask(env) + 0x80);
> > +                for (curaddr = ppc_hash32_hpt_base(cpu);
> > +                     curaddr < (ppc_hash32_hpt_base(cpu)
> > +                                + ppc_hash32_hpt_mask(cpu) + 0x80);
> >                       curaddr += 16) {
> >                      a0 = ldl_phys(cs->as, curaddr);
> >                      a1 = ldl_phys(cs->as, curaddr + 4);
> > @@ -1205,12 +1208,13 @@ static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
> >  static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
> >                              CPUPPCState *env)
> >  {
> > +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> >      ppc6xx_tlb_t *tlb;
> >      target_ulong sr;
> >      int type, way, entry, i;
> >  
> > -    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
> > -    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
> > +    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
> > +    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
> >  
> >      cpu_fprintf(f, "\nSegment registers:\n");
> >      for (i = 0; i < 32; i++) {
> > @@ -1592,9 +1596,9 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
> >                      env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
> >                  tlb_miss:
> >                      env->error_code |= ctx.key << 19;
> > -                    env->spr[SPR_HASH1] = env->htab_base +
> > +                    env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
> >                          get_pteg_offset32(cpu, ctx.hash[0]);
> > -                    env->spr[SPR_HASH2] = env->htab_base +
> > +                    env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
> >                          get_pteg_offset32(cpu, ctx.hash[1]);
> >                      break;
> >                  case POWERPC_MMU_SOFT_74xx:
> > @@ -1999,7 +2003,6 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
> >  {
> >      qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
> >      assert(!env->external_htab);
> > -    env->spr[SPR_SDR1] = value;
> >  #if defined(TARGET_PPC64)
> >      if (env->mmu_model & POWERPC_MMU_64) {
> >          PowerPCCPU *cpu = ppc_env_get_cpu(env);
> > @@ -2009,14 +2012,12 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
> >          if (local_err) {
> >              error_report_err(local_err);
> >              error_free(local_err);
> > +            return;
> >          }
> > -    } else
> > -#endif /* defined(TARGET_PPC64) */
> > -    {
> > -        /* FIXME: Should check for valid HTABMASK values */
> > -        env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
> > -        env->htab_base = value & SDR_32_HTABORG;
> >      }
> > +#endif /* defined(TARGET_PPC64) */
> > +    /* FIXME: Should check for valid HTABMASK values in 32-bit case */
> > +    env->spr[SPR_SDR1] = value;
> >  }
> >  
> >  /* Segment registers load and store */
> > 
> 
> 

-- 
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: 819 bytes --]

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

* Re: [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables
  2017-02-23  5:52   ` Suraj Jitindar Singh
  2017-02-24  3:45     ` David Gibson
@ 2017-02-24  5:34     ` David Gibson
  1 sibling, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-02-24  5:34 UTC (permalink / raw)
  To: Suraj Jitindar Singh
  Cc: qemu-ppc, aik, qemu-devel, agraf, thuth, lvivier, mdroth, paulus

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

On Thu, Feb 23, 2017 at 04:52:59PM +1100, Suraj Jitindar Singh wrote:
> On Thu, 2017-02-23 at 13:09 +1100, David Gibson wrote:
> > CPUPPCState includes fields htab_base and htab_mask which store the
> > base
> > address (GPA) and size (as a mask) of the guest's hashed page table
> > (HPT).
> > These are set when the SDR1 register is updated.
> > 
> > Keeping these in sync with the SDR1 is actually a little bit fiddly,
> > and
> > probably not useful for performance, since keeping them expands the
> > size of
> > CPUPPCState.  It also makes some upcoming changes harder to
> > implement.
> > 
> > This patch removes these fields, in favour of calculating them
> > directly
> > from the SDR1 contents when necessary.
> > 
> > This does make a change to the behaviour of attempting to write a bad
> > value
> > (invalid HPT size) to the SDR1 with an mtspr
> > instruction.  Previously, the
> > bad value would be stored in SDR1 and could be retrieved with a later
> > mfspr, but the HPT size as used by the softmmu would be, clamped to
> > the
> > allowed values.  Now, writing a bad value is treated as a no-op.  An
> > error
> > message is printed in both new and old versions.
> > 
> > I'm not sure which behaviour, if either, matches real hardware.  I
> > don't
> > think it matters that much, since it's pretty clear that if an OS
> > writes
> > a bad value to SDR1, it's not going to boot.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> 
> Comments Below.
> 
> > ---
> >  hw/ppc/spapr_hcall.c    |  4 ++--
> >  target/ppc/cpu.h        |  8 --------
> >  target/ppc/machine.c    |  1 -
> >  target/ppc/mmu-hash32.c | 14 +++++++-------
> >  target/ppc/mmu-hash32.h | 24 ++++++++++++++++++------
> >  target/ppc/mmu-hash64.c | 37 ++++++++++++++++---------------------
> >  target/ppc/mmu-hash64.h | 13 +++++++++++++
> >  target/ppc/mmu_helper.c | 31 ++++++++++++++++---------------
> >  8 files changed, 72 insertions(+), 60 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index fd961b5..85d96f6 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -50,9 +50,9 @@ static bool has_spr(PowerPCCPU *cpu, int spr)
> >  static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
> >  {
> >      /*
> > -     * hash value/pteg group index is normalized by htab_mask
> > +     * hash value/pteg group index is normalized by HPT mask
> >       */
> > -    if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~cpu->env.htab_mask) {
> > +    if (((ptex & ~7ULL) / HPTES_PER_GROUP) &
> > ~ppc_hash64_hpt_mask(cpu)) {
> >          return false;
> >      }
> >      return true;
> > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > index c89973e..c6cd9ab 100644
> > --- a/target/ppc/cpu.h
> > +++ b/target/ppc/cpu.h
> > @@ -309,11 +309,6 @@ union ppc_tlb_t {
> >  #define SDR_32_HTABORG         0xFFFF0000UL
> >  #define SDR_32_HTABMASK        0x000001FFUL
> >  
> > -#if defined(TARGET_PPC64)
> > -#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> > -#define SDR_64_HTABSIZE        0x000000000000001FULL
> > -#endif /* defined(TARGET_PPC64 */
> > -
> >  typedef struct ppc_slb_t ppc_slb_t;
> >  struct ppc_slb_t {
> >      uint64_t esid;
> > @@ -1006,9 +1001,6 @@ struct CPUPPCState {
> >      /* tcg TLB needs flush (deferred slb inval instruction
> > typically) */
> >  #endif
> >      /* segment registers */
> > -    hwaddr htab_base;
> > -    /* mask used to normalize hash value to PTEG index */
> > -    hwaddr htab_mask;
> >      target_ulong sr[32];
> >      /* externally stored hash table */
> >      uint8_t *external_htab;
> > diff --git a/target/ppc/machine.c b/target/ppc/machine.c
> > index df9f7a4..1ccbc8a 100644
> > --- a/target/ppc/machine.c
> > +++ b/target/ppc/machine.c
> > @@ -229,7 +229,6 @@ static int cpu_post_load(void *opaque, int
> > version_id)
> >      }
> >  
> >      if (!env->external_htab) {
> > -        /* Restore htab_base and htab_mask variables */
> >          ppc_store_sdr1(env, env->spr[SPR_SDR1]);
> 
> Do we still need to do this? As far as I can tell it pretty much does:
> env->spr[SPR_SDR1] = env->spr[SPR_SDR1]
> and checks the htab_size, which would have been done when we set SDR1
> in the first place anyway?
> 
> >      }
> >  
> > diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
> > index 29bace6..03ae3c1 100644
> > --- a/target/ppc/mmu-hash32.c
> > +++ b/target/ppc/mmu-hash32.c
> > @@ -304,9 +304,9 @@ static int ppc_hash32_direct_store(PowerPCCPU
> > *cpu, target_ulong sr,
> >  
> >  hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> > +    target_ulong mask = ppc_hash32_hpt_mask(cpu);
> >  
> > -    return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
> > +    return (hash * HASH_PTEG_SIZE_32) & mask;
> >  }
> >  
> >  static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr
> > pteg_off,
> > @@ -339,7 +339,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU
> > *cpu,
> >                                       target_ulong sr, target_ulong
> > eaddr,
> >                                       ppc_hash_pte32_t *pte)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> >      hwaddr pteg_off, pte_offset;
> >      hwaddr hash;
> >      uint32_t vsid, pgidx, ptem;
> > @@ -353,21 +352,22 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU
> > *cpu,
> >      qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
> >              " htab_mask " TARGET_FMT_plx
> >              " hash " TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, hash);
> > +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
> > hash);
> >  
> >      /* Primary PTEG lookup */
> >      qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/"
> > TARGET_FMT_plx
> >              " vsid=%" PRIx32 " ptem=%" PRIx32
> >              " hash=" TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, vsid, ptem, hash);
> > +            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
> > +            vsid, ptem, hash);
> >      pteg_off = get_pteg_offset32(cpu, hash);
> >      pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem,
> > pte);
> >      if (pte_offset == -1) {
> >          /* Secondary PTEG lookup */
> >          qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/"
> > TARGET_FMT_plx
> >                  " vsid=%" PRIx32 " api=%" PRIx32
> > -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> > -                env->htab_mask, vsid, ptem, ~hash);
> > +                " hash=" TARGET_FMT_plx "\n",
> > ppc_hash32_hpt_base(cpu),
> > +                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
> >          pteg_off = get_pteg_offset32(cpu, ~hash);
> >          pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem,
> > pte);
> >      }
> > diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
> > index 5b9fb08..054be65 100644
> > --- a/target/ppc/mmu-hash32.h
> > +++ b/target/ppc/mmu-hash32.h
> > @@ -65,42 +65,54 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu,
> > vaddr address, int rw,
> >  #define HPTE32_R_WIMG           0x00000078
> >  #define HPTE32_R_PP             0x00000003
> >  
> > +static inline hwaddr ppc_hash32_hpt_base(PowerPCCPU *cpu)
> > +{
> > +    return cpu->env.spr[SPR_SDR1] & SDR_32_HTABORG;
> > +}
> > +
> > +static inline hwaddr ppc_hash32_hpt_mask(PowerPCCPU *cpu)
> > +{
> > +    return ((cpu->env.spr[SPR_SDR1] & SDR_32_HTABMASK) << 16) |
> > 0xFFFF;
> > +}
> > +
> >  static inline target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu,
> >                                                   hwaddr pte_offset)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now
> > */
> > -    return ldl_phys(CPU(cpu)->as, env->htab_base + pte_offset);
> > +    return ldl_phys(CPU(cpu)->as, base + pte_offset);
> >  }
> >  
> >  static inline target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu,
> >                                                   hwaddr pte_offset)
> >  {
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >      CPUPPCState *env = &cpu->env;
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now
> > */
> > -    return ldl_phys(CPU(cpu)->as,
> > -                    env->htab_base + pte_offset + HASH_PTE_SIZE_32 /
> > 2);
> > +    return ldl_phys(CPU(cpu)->as, base + pte_offset +
> > HASH_PTE_SIZE_32 / 2);
> >  }
> >  
> >  static inline void ppc_hash32_store_hpte0(PowerPCCPU *cpu,
> >                                            hwaddr pte_offset,
> > target_ulong pte0)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now
> > */
> > -    stl_phys(CPU(cpu)->as, env->htab_base + pte_offset, pte0);
> > +    stl_phys(CPU(cpu)->as, base + pte_offset, pte0);
> >  }
> >  
> >  static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
> >                                            hwaddr pte_offset,
> > target_ulong pte1)
> >  {
> >      CPUPPCState *env = &cpu->env;
> > +    target_ulong base = ppc_hash32_hpt_base(cpu);
> >  
> >      assert(!env->external_htab); /* Not supported on 32-bit for now
> > */
> > -    stl_phys(CPU(cpu)->as,
> > -             env->htab_base + pte_offset + HASH_PTE_SIZE_32 / 2,
> > pte1);
> > +    stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2,
> > pte1);
> >  }
> >  
> >  typedef struct {
> > diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
> > index c59db47..bb87777 100644
> > --- a/target/ppc/mmu-hash64.c
> > +++ b/target/ppc/mmu-hash64.c
> > @@ -304,15 +304,13 @@ void ppc_hash64_set_sdr1(PowerPCCPU *cpu,
> > target_ulong value,
> >      CPUPPCState *env = &cpu->env;
> >      target_ulong htabsize = value & SDR_64_HTABSIZE;
> >  
> > -    env->spr[SPR_SDR1] = value;
> >      if (htabsize > 28) {
> >          error_setg(errp,
> >                     "Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in
> > SDR1",
> >                     htabsize);
> > -        htabsize = 28;
> > +        return;
> >      }
> > -    env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
> > -    env->htab_base = value & SDR_64_HTABORG;
> > +    env->spr[SPR_SDR1] = value;
> >  }
> >  
> >  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> > shift,
> > @@ -333,10 +331,6 @@ void ppc_hash64_set_external_hpt(PowerPCCPU
> > *cpu, void *hpt, int shift,
> >          return;
> >      }
> >  
> > -    /* Not strictly necessary, but makes it clearer that an external
> > -     * htab is in use when debugging */
> > -    env->htab_base = -1;
> > -
> >      if (kvm_enabled()) {
> >          if (kvmppc_put_books_sregs(cpu) < 0) {
> >              error_setg(errp, "Unable to update SDR1 in KVM");
> > @@ -448,11 +442,12 @@ const ppc_hash_pte64_t
> > *ppc_hash64_map_hptes(PowerPCCPU *cpu,
> >           * HTAB is controlled by QEMU. Just point to the internally
> >           * accessible PTEG.
> >           */
> > -        hptes = (ppc_hash_pte64_t *)(cpu->env.external_htab +
> > pte_offset);
> > -    } else if (cpu->env.htab_base) {
> > +        hptes = (const ppc_hash_pte64_t *)(cpu->env.external_htab +
> > pte_offset);
> ^^^ Does this particular line belong in the previous patch?

Yes, yes it does.  Nice catch.

> > +    } else if (ppc_hash64_hpt_base(cpu)) {
> > +        hwaddr base = ppc_hash64_hpt_base(cpu);
> >          hwaddr plen = n * HASH_PTE_SIZE_64;
> > -        hptes = address_space_map(CPU(cpu)->as, cpu->env.htab_base +
> > pte_offset,
> > -                                 &plen, false);
> > +        hptes = address_space_map(CPU(cpu)->as, base + pte_offset,
> > +                                  &plen, false);
> >          if (plen < (n * HASH_PTE_SIZE_64)) {
> >              hw_error("%s: Unable to map all requested HPTEs\n",
> > __FUNCTION__);
> >          }
> > @@ -513,13 +508,12 @@ static hwaddr ppc_hash64_pteg_search(PowerPCCPU
> > *cpu, hwaddr hash,
> >                                       target_ulong ptem,
> >                                       ppc_hash_pte64_t *pte, unsigned
> > *pshift)
> >  {
> > -    CPUPPCState *env = &cpu->env;
> >      int i;
> >      const ppc_hash_pte64_t *pteg;
> >      target_ulong pte0, pte1;
> >      target_ulong ptex;
> >  
> > -    ptex = (hash & env->htab_mask) * HPTES_PER_GROUP;
> > +    ptex = (hash & ppc_hash64_hpt_mask(cpu)) * HPTES_PER_GROUP;
> >      pteg = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
> >      if (!pteg) {
> >          return -1;
> > @@ -597,14 +591,15 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> > *cpu,
> >      qemu_log_mask(CPU_LOG_MMU,
> >              "htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
> >              " hash " TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, hash);
> > +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
> > hash);
> >  
> >      /* Primary PTEG lookup */
> >      qemu_log_mask(CPU_LOG_MMU,
> >              "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
> >              " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
> >              " hash=" TARGET_FMT_plx "\n",
> > -            env->htab_base, env->htab_mask, vsid, ptem,  hash);
> > +            ppc_hash64_hpt_base(cpu), ppc_hash64_hpt_mask(cpu),
> > +            vsid, ptem,  hash);
> >      ptex = ppc_hash64_pteg_search(cpu, hash, sps, ptem, pte,
> > pshift);
> >  
> >      if (ptex == -1) {
> > @@ -613,8 +608,8 @@ static hwaddr ppc_hash64_htab_lookup(PowerPCCPU
> > *cpu,
> >          qemu_log_mask(CPU_LOG_MMU,
> >                  "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
> >                  " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
> > -                " hash=" TARGET_FMT_plx "\n", env->htab_base,
> > -                env->htab_mask, vsid, ptem, ~hash);
> > +                " hash=" TARGET_FMT_plx "\n",
> > ppc_hash64_hpt_base(cpu),
> > +                ppc_hash64_hpt_mask(cpu), vsid, ptem, ~hash);
> >  
> >          ptex = ppc_hash64_pteg_search(cpu, ~hash, sps, ptem, pte,
> > pshift);
> >      }
> > @@ -932,9 +927,9 @@ void ppc_hash64_store_hpte(PowerPCCPU *cpu,
> > hwaddr ptex,
> >          stq_p(env->external_htab + offset, pte0);
> >          stq_p(env->external_htab + offset + HASH_PTE_SIZE_64 / 2,
> > pte1);
> >      } else {
> > -        stq_phys(CPU(cpu)->as, env->htab_base + offset, pte0);
> > -        stq_phys(CPU(cpu)->as,
> > -                 env->htab_base + offset + HASH_PTE_SIZE_64 / 2,
> > pte1);
> > +        hwaddr base = ppc_hash64_hpt_base(cpu);
> > +        stq_phys(CPU(cpu)->as, base + offset, pte0);
> > +        stq_phys(CPU(cpu)->as, base + offset + HASH_PTE_SIZE_64 / 2,
> > pte1);
> >      }
> >  }
> >  
> > diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
> > index 8637fe4..dc0bc99 100644
> > --- a/target/ppc/mmu-hash64.h
> > +++ b/target/ppc/mmu-hash64.h
> > @@ -56,6 +56,9 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
> >   * Hash page table definitions
> >   */
> >  
> > +#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
> 
> I think this was just always wrong, but it should be
> 0x0FFFFFFFFFFC0000ULL
>   ^
> 
> > +#define SDR_64_HTABSIZE        0x000000000000001FULL
> > +
> >  #define HPTES_PER_GROUP         8
> >  #define HASH_PTE_SIZE_64        16
> >  #define HASH_PTEG_SIZE_64       (HASH_PTE_SIZE_64 * HPTES_PER_GROUP)
> > @@ -91,6 +94,16 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
> >  #define HPTE64_V_1TB_SEG        0x4000000000000000ULL
> >  #define HPTE64_V_VRMA_MASK      0x4001ffffff000000ULL
> >  
> > +static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
> > +{
> > +    return cpu->env.spr[SPR_SDR1] & SDR_64_HTABORG;
> > +}
> > +
> > +static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
> > +{
> > +    return (1ULL << ((cpu->env.spr[SPR_SDR1] & SDR_64_HTABSIZE) + 18
> > - 7)) - 1;
> > +}
> > +
> >  void ppc_hash64_set_sdr1(PowerPCCPU *cpu, target_ulong value,
> >                           Error **errp);
> >  void ppc_hash64_set_external_hpt(PowerPCCPU *cpu, void *hpt, int
> > shift,
> > diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
> > index eb2d482..1381635 100644
> > --- a/target/ppc/mmu_helper.c
> > +++ b/target/ppc/mmu_helper.c
> > @@ -466,6 +466,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env,
> > mmu_ctx_t *ctx,
> >  static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t
> > *ctx,
> >                                        target_ulong eaddr, int rw,
> > int type)
> >  {
> > +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> >      hwaddr hash;
> >      target_ulong vsid;
> >      int ds, pr, target_page_bits;
> > @@ -503,7 +504,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState
> > *env, mmu_ctx_t *ctx,
> >              qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
> >                      " htab_mask " TARGET_FMT_plx
> >                      " hash " TARGET_FMT_plx "\n",
> > -                    env->htab_base, env->htab_mask, hash);
> > +                    ppc_hash32_hpt_base(cpu),
> > ppc_hash32_hpt_mask(cpu), hash);
> >              ctx->hash[0] = hash;
> >              ctx->hash[1] = ~hash;
> >  
> > @@ -518,9 +519,11 @@ static inline int
> > get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
> >                  uint32_t a0, a1, a2, a3;
> >  
> >                  qemu_log("Page table: " TARGET_FMT_plx " len "
> > TARGET_FMT_plx
> > -                         "\n", env->htab_base, env->htab_mask +
> > 0x80);
> > -                for (curaddr = env->htab_base;
> > -                     curaddr < (env->htab_base + env->htab_mask +
> > 0x80);
> > +                         "\n", ppc_hash32_hpt_base(cpu),
> > +                         ppc_hash32_hpt_mask(env) + 0x80);
> > +                for (curaddr = ppc_hash32_hpt_base(cpu);
> > +                     curaddr < (ppc_hash32_hpt_base(cpu)
> > +                                + ppc_hash32_hpt_mask(cpu) + 0x80);
> >                       curaddr += 16) {
> >                      a0 = ldl_phys(cs->as, curaddr);
> >                      a1 = ldl_phys(cs->as, curaddr + 4);
> > @@ -1205,12 +1208,13 @@ static void mmu6xx_dump_BATs(FILE *f,
> > fprintf_function cpu_fprintf,
> >  static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
> >                              CPUPPCState *env)
> >  {
> > +    PowerPCCPU *cpu = ppc_env_get_cpu(env);
> >      ppc6xx_tlb_t *tlb;
> >      target_ulong sr;
> >      int type, way, entry, i;
> >  
> > -    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env-
> > >htab_base);
> > -    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env-
> > >htab_mask);
> > +    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n",
> > ppc_hash32_hpt_base(cpu));
> > +    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n",
> > ppc_hash32_hpt_mask(cpu));
> >  
> >      cpu_fprintf(f, "\nSegment registers:\n");
> >      for (i = 0; i < 32; i++) {
> > @@ -1592,9 +1596,9 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState
> > *env, target_ulong address,
> >                      env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
> >                  tlb_miss:
> >                      env->error_code |= ctx.key << 19;
> > -                    env->spr[SPR_HASH1] = env->htab_base +
> > +                    env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
> >                          get_pteg_offset32(cpu, ctx.hash[0]);
> > -                    env->spr[SPR_HASH2] = env->htab_base +
> > +                    env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
> >                          get_pteg_offset32(cpu, ctx.hash[1]);
> >                      break;
> >                  case POWERPC_MMU_SOFT_74xx:
> > @@ -1999,7 +2003,6 @@ void ppc_store_sdr1(CPUPPCState *env,
> > target_ulong value)
> >  {
> >      qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__,
> > value);
> >      assert(!env->external_htab);
> > -    env->spr[SPR_SDR1] = value;
> >  #if defined(TARGET_PPC64)
> >      if (env->mmu_model & POWERPC_MMU_64) {
> >          PowerPCCPU *cpu = ppc_env_get_cpu(env);
> > @@ -2009,14 +2012,12 @@ void ppc_store_sdr1(CPUPPCState *env,
> > target_ulong value)
> >          if (local_err) {
> >              error_report_err(local_err);
> >              error_free(local_err);
> > +            return;
> >          }
> > -    } else
> > -#endif /* defined(TARGET_PPC64) */
> > -    {
> > -        /* FIXME: Should check for valid HTABMASK values */
> > -        env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
> > -        env->htab_base = value & SDR_32_HTABORG;
> >      }
> > +#endif /* defined(TARGET_PPC64) */
> > +    /* FIXME: Should check for valid HTABMASK values in 32-bit case
> > */
> > +    env->spr[SPR_SDR1] = value;
> >  }
> >  
> >  /* Segment registers load and store */
> 

-- 
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: 819 bytes --]

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

* Re: [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU
  2017-02-23  5:02   ` Alexey Kardashevskiy
  2017-02-23  5:23     ` David Gibson
@ 2017-02-27  5:06     ` David Gibson
  1 sibling, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-02-27  5:06 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: qemu-ppc, sjitindarsingh, qemu-devel, agraf, thuth, lvivier,
	mdroth, paulus

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

On Thu, Feb 23, 2017 at 04:02:54PM +1100, Alexey Kardashevskiy wrote:
> On 23/02/17 13:09, David Gibson wrote:
> > Accesses to the hashed page table (HPT) are complicated by the fact that
> > the HPT could be in one of three places:
> >    1) Within guest memory - when we're emulating a full guest CPU at the
> >       hardware level (e.g. powernv, mac99, g3beige)
> >    2) Within qemu, but outside guest memory - when we're emulating user and
> >       supervisor instructions within TCG, but instead of emulating
> >       the CPU's hypervisor mode, we just emulate a hypervisor's behaviour
> >       (pseries in TCG)
> >    3) Within KVM - a pseries machine using KVM acceleration.  Mostly
> >       accesses to the HPT are handled by KVM, but there are a few cases
> >       where qemu needs to access it via a special fd for the purpose.
> > 
> > In order to batch accesses to the fd in case (3), we use a somewhat awkward
> > ppc_hash64_start_access() / ppc_hash64_stop_access() pair, which for case
> > (3) reads / releases a whole PTEG from the kernel.  For cases (1) & (2)
> > it just returns an address value.  The actual HPTE load helpers then need
> > to interpret the returned token differently in the 3 cases.
> > 
> > This patch keeps the same basic structure, but simplfiies the details.
> > First start_access() / stop_access() are renamed to get_pteg() and
> > put_pteg() to make their operation more obvious.

[snip]
> >  /*****************************************************************************/
> > -/* Types used to describe some PowerPC registers */
> > +/* Types used to describe some PowerPC registers etc. */
> >  typedef struct DisasContext DisasContext;
> >  typedef struct ppc_spr_t ppc_spr_t;
> >  typedef union ppc_avr_t ppc_avr_t;
> >  typedef union ppc_tlb_t ppc_tlb_t;
> > +typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
> >  
> >  /* SPR access micro-ops generations callbacks */
> >  struct ppc_spr_t {
> > diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
> > index 52bbea5..9d3e57e 100644
> > --- a/target/ppc/kvm.c
> > +++ b/target/ppc/kvm.c
> > @@ -2601,17 +2601,17 @@ struct kvm_get_htab_buf {
> >      /*
> >       * We require one extra byte for read
> >       */
> > -    target_ulong hpte[(HPTES_PER_GROUP * 2) + 1];
> > +    ppc_hash_pte64_t hpte[HPTES_PER_GROUP];
> 
> 
> The "one extra byte" (which was ulong) is not needed any more why?
> 
> 
> >  };
> >  
> > -uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
> > +const ppc_hash_pte64_t *kvmppc_map_hptes(hwaddr ptex, int n)
> 
> 
> This "int n" is ignored here by a reason?

So looking at these comments, I realized the current code for reading
the HPTEs from KVM is just broken.  So, for v2, I've prepended a patch
to fix that first, after which I don't need to touch the KVM side for
the rest of the series.

[snip]
> > +const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,\
> 
> 
> You do not need the trailing '\'.

Missed this comment on my first pass, fixed now, thanks.

-- 
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: 819 bytes --]

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

end of thread, other threads:[~2017-02-27  5:07 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-23  2:09 [Qemu-devel] [PATCH 0/6] Cleanups to handling of hash MMU David Gibson
2017-02-23  2:09 ` [Qemu-devel] [PATCH 1/6] pseries: Minor cleanups to HPT management hypercalls David Gibson
2017-02-23  4:08   ` Suraj Jitindar Singh
2017-02-23  2:09 ` [Qemu-devel] [PATCH 2/6] target/ppc: Merge cpu_ppc_set_vhyp() with cpu_ppc_set_papr() David Gibson
2017-02-23  4:27   ` Suraj Jitindar Singh
2017-02-23  2:09 ` [Qemu-devel] [PATCH 3/6] target/ppc: SDR1 is a hypervisor resource David Gibson
2017-02-23  4:32   ` Suraj Jitindar Singh
2017-02-23  5:11     ` David Gibson
2017-02-23  2:09 ` [Qemu-devel] [PATCH 4/6] target/ppc: Cleanup HPTE accessors for 64-bit hash MMU David Gibson
2017-02-23  5:02   ` Alexey Kardashevskiy
2017-02-23  5:23     ` David Gibson
2017-02-27  5:06     ` David Gibson
2017-02-23  5:37   ` Suraj Jitindar Singh
2017-02-24  5:25     ` David Gibson
2017-02-23  2:09 ` [Qemu-devel] [PATCH 5/6] target/ppc: Eliminate htab_base and htab_mask variables David Gibson
2017-02-23  5:43   ` Alexey Kardashevskiy
2017-02-24  5:30     ` David Gibson
2017-02-23  5:52   ` Suraj Jitindar Singh
2017-02-24  3:45     ` David Gibson
2017-02-24  5:34     ` David Gibson
2017-02-23  2:09 ` [Qemu-devel] [PATCH 6/6] target/ppc: Manage external HPT via virtual hypervisor David Gibson
2017-02-23  6:20   ` Suraj Jitindar Singh

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.