All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling
@ 2016-10-30 11:11 David Gibson
  2016-10-30 11:11 ` [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models David Gibson
                   ` (16 more replies)
  0 siblings, 17 replies; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

This series is a significant rework to how we handle CPU compatibility
modes on ppc.

 * Information about compatibility modes was previously open coded and
   scattered across a number of functions in both target-ppc and spapr
   code.  It's now brought together into a common table of
   compatibility modes.

 * There was significant conceptual confusion about what a
   compatibility mode means, and how it interacts with the machine
   type.  This cleans that up, clarifying that a compatibility mode
   (as an externally set option) only makes sense on machine types
   that don't permit the guest hypervisor privilege (i.e. 'pseries')
 
 * It was previously the user's (or management layer's) responsibility
   to determine compatibility of CPUs on either end for migration.
   This uses the compatibility modes to check that properly during an
   incoming migration.

 * Some ill-considered sanity checks broke migration from 2.6 to 2.7,
   due to some new instruction classes being added.  This should avoid
   a repeat of that problem for 2.8 (we may be able to backport a
   minimal subset to 2.7-stable to fix the existing problem).

Patches 1-5 are preliminary cleanups which could stand on their own.
Patches 6-16 are the compatibility mode cleanup proper.

So far, this has been mimimally tested.  There are quite a few
migration cases to check.

David Gibson (17):
  ppc: Remove some stub POWER6 models
  powernv: CPU compatibility modes don't make sense for powernv
  pseries: Always use core objects for CPU construction
  pseries: Make cpu_update during CAS unconditional
  ppc: Clean up and QOMify hypercall emulation
  ppc: Rename cpu_version to compat_pvr
  ppc: Rewrite ppc_set_compat()
  ppc: Rewrite ppc_get_compat_smt_threads()
  ppc: Validate compatibility modes when setting
  pseries: Rewrite CAS PVR compatibility logic
  ppc: Add ppc_set_compat_all()
  ppc: Migrate compatibility mode
  pseries: Move CPU compatibility property to machine
  pseries: Reset CPU compatibility mode
  ppc: Check that CPU model stays consistent across migration
  ppc: Remove counter-productive "sanity checks" in migration
  pseries: Default to POWER8 compatibility mode

 hw/ppc/pnv.c                |   6 +-
 hw/ppc/spapr.c              | 159 ++++++++++++++++------------
 hw/ppc/spapr_cpu_core.c     |  84 +++++++++++----
 hw/ppc/spapr_hcall.c        | 142 ++++++++-----------------
 hw/ppc/trace-events         |   2 +-
 include/hw/ppc/spapr.h      |  12 ++-
 target-ppc/Makefile.objs    |   1 +
 target-ppc/compat.c         | 251 ++++++++++++++++++++++++++++++++++++++++++++
 target-ppc/cpu-models.c     |   4 -
 target-ppc/cpu-models.h     |   2 -
 target-ppc/cpu.h            |  49 +++++++--
 target-ppc/excp_helper.c    |  11 +-
 target-ppc/kvm.c            |   4 +-
 target-ppc/kvm_ppc.h        |   4 +-
 target-ppc/machine.c        |  55 ++++++++--
 target-ppc/translate_init.c | 146 +++-----------------------
 16 files changed, 564 insertions(+), 368 deletions(-)
 create mode 100644 target-ppc/compat.c

-- 
2.7.4

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

* [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
@ 2016-10-30 11:11 ` David Gibson
  2016-10-31  7:38   ` Thomas Huth
  2016-11-08  3:40   ` David Gibson
  2016-10-30 11:11 ` [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv David Gibson
                   ` (15 subsequent siblings)
  16 siblings, 2 replies; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

The CPU model table includes stub (commented out) definitions for
CPU_POWERPC_POWER6_5 and CPU_POWERPC_POWER6A.  These are not real cpu
models, but represent the POWER6 in some compatiblity modes.  If we ever
do implement POWER6 (unlikely), we'll implement its compatibility modes in
a different way (similar to what we do for POWER7 and POWER8).  So these
stub definitions can be removed.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/cpu-models.c | 4 ----
 target-ppc/cpu-models.h | 2 --
 2 files changed, 6 deletions(-)

diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
index 901cf40..506dee1 100644
--- a/target-ppc/cpu-models.c
+++ b/target-ppc/cpu-models.c
@@ -1130,10 +1130,6 @@
 #if defined(TODO)
     POWERPC_DEF("POWER6",        CPU_POWERPC_POWER6,                 POWER6,
                 "POWER6")
-    POWERPC_DEF("POWER6_5",      CPU_POWERPC_POWER6_5,               POWER5,
-                "POWER6 running in POWER5 mode")
-    POWERPC_DEF("POWER6A",       CPU_POWERPC_POWER6A,                POWER6,
-                "POWER6A")
 #endif
     POWERPC_DEF("POWER7_v2.3",   CPU_POWERPC_POWER7_v23,             POWER7,
                 "POWER7 v2.3")
diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
index 7d9e6a2..aafbbd7 100644
--- a/target-ppc/cpu-models.h
+++ b/target-ppc/cpu-models.h
@@ -549,8 +549,6 @@ enum {
     CPU_POWERPC_POWER5             = 0x003A0203,
     CPU_POWERPC_POWER5P_v21        = 0x003B0201,
     CPU_POWERPC_POWER6             = 0x003E0000,
-    CPU_POWERPC_POWER6_5           = 0x0F000001, /* POWER6 in POWER5 mode */
-    CPU_POWERPC_POWER6A            = 0x0F000002,
     CPU_POWERPC_POWER_SERVER_MASK  = 0xFFFF0000,
     CPU_POWERPC_POWER7_BASE        = 0x003F0000,
     CPU_POWERPC_POWER7_v23         = 0x003F0203,
-- 
2.7.4

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

* [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
  2016-10-30 11:11 ` [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models David Gibson
@ 2016-10-30 11:11 ` David Gibson
  2016-10-31  7:46   ` Thomas Huth
  2016-10-31 10:35   ` Greg Kurz
  2016-10-30 11:11 ` [Qemu-devel] [RFC 03/17] pseries: Always use core objects for CPU construction David Gibson
                   ` (14 subsequent siblings)
  16 siblings, 2 replies; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

powernv has some code (derived from the spapr equivalent) used in device
tree generation which depends on the CPU's compatibility mode / logical
PVR.  However, compatibility modes don't make sense on powernv - at least
not as a property controlled by the host - because the guest in powernv
has full hypervisor level access to the virtual system, and so owns the
PCR (Processor Compatibility Register) which implements compatiblity modes.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/pnv.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 82276e0..6af3424 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -110,7 +110,7 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
     CPUState *cs = CPU(DEVICE(pc->threads));
     DeviceClass *dc = DEVICE_GET_CLASS(cs);
     PowerPCCPU *cpu = POWERPC_CPU(cs);
-    int smt_threads = ppc_get_compat_smt_threads(cpu);
+    int smt_threads = CPU_CORE(pc)->nr_threads;
     CPUPPCState *env = &cpu->env;
     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
     uint32_t servers_prop[smt_threads];
@@ -206,10 +206,6 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
                        pa_features, sizeof(pa_features))));
 
-    if (cpu->cpu_version) {
-        _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
-    }
-
     /* Build interrupt servers properties */
     for (i = 0; i < smt_threads; i++) {
         servers_prop[i] = cpu_to_be32(pc->pir + i);
-- 
2.7.4

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

* [Qemu-devel] [RFC 03/17] pseries: Always use core objects for CPU construction
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
  2016-10-30 11:11 ` [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models David Gibson
  2016-10-30 11:11 ` [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv David Gibson
@ 2016-10-30 11:11 ` David Gibson
  2016-11-03  8:11   ` Alexey Kardashevskiy
  2016-10-30 11:11 ` [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional David Gibson
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

Currently the pseries machine has two paths for constructing CPUs.  On
newer machine type versions, which support cpu hotplug, it constructs
cpu core objects, which in turn construct CPU threads.  For older machine
versions it individually constructs the CPU threads.

This division is going to make some future changes to the cpu construction
harder, so this patch unifies them.  Now cpu core objects are always
created.  This requires some updates to allow core objects to be created
without a full complement of threads (since older versions allowed a
number of cpus not a multiple of the threads-per-core).  Likewise it needs
some changes to the cpu core hot/cold plug path so as not to choke on the
old machine types without hotplug support.

For good measure, we move the cpu construction to its own subfunction,
spapr_init_cpus().

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c          | 125 +++++++++++++++++++++++++++---------------------
 hw/ppc/spapr_cpu_core.c |  30 +++++++-----
 include/hw/ppc/spapr.h  |   1 -
 3 files changed, 89 insertions(+), 67 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index c8e2921..ad68a9d 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1688,11 +1688,80 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp)
     }
 }
 
+static void spapr_init_cpus(sPAPRMachineState *spapr)
+{
+    MachineState *machine = MACHINE(spapr);
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+    char *type = spapr_get_cpu_core_type(machine->cpu_model);
+    int smt = kvmppc_smt_threads();
+    int spapr_max_cores, spapr_cores;
+    int i;
+
+    if (!type) {
+        error_report("Unable to find sPAPR CPU Core definition");
+        exit(1);
+    }
+
+    if (mc->query_hotpluggable_cpus) {
+        if (smp_cpus % smp_threads) {
+            error_report("smp_cpus (%u) must be multiple of threads (%u)",
+                         smp_cpus, smp_threads);
+            exit(1);
+        }
+        if (max_cpus % smp_threads) {
+            error_report("max_cpus (%u) must be multiple of threads (%u)",
+                         max_cpus, smp_threads);
+            exit(1);
+        }
+
+        spapr_max_cores = max_cpus / smp_threads;
+        spapr_cores = smp_cpus / smp_threads;
+    } else {
+        if (max_cpus != smp_cpus) {
+            error_report("This machine version does not support CPU hotplug");
+            exit(1);
+        }
+
+        spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
+        spapr_cores = spapr_max_cores;
+    }
+
+    spapr->cores = g_new0(Object *, spapr_max_cores);
+    for (i = 0; i < spapr_max_cores; i++) {
+        int core_id = i * smp_threads;
+
+        if (mc->query_hotpluggable_cpus) {
+            sPAPRDRConnector *drc =
+                spapr_dr_connector_new(OBJECT(spapr),
+                                       SPAPR_DR_CONNECTOR_TYPE_CPU,
+                                       (core_id / smp_threads) * smt);
+
+            qemu_register_reset(spapr_drc_reset, drc);
+        }
+
+        if (i < spapr_cores) {
+            Object *core  = object_new(type);
+            int nr_threads = smp_threads;
+
+            /* Handle the partially filled core for older machine types */
+            if ((i + 1) * smp_threads >= smp_cpus) {
+                nr_threads = smp_cpus - i * smp_threads;
+            }
+
+            object_property_set_int(core, nr_threads, "nr-threads",
+                                    &error_fatal);
+            object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
+                                    &error_fatal);
+            object_property_set_bool(core, true, "realized", &error_fatal);
+        }
+    }
+    g_free(type);
+}
+
 /* pSeries LPAR / sPAPR hardware init */
 static void ppc_spapr_init(MachineState *machine)
 {
     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
-    MachineClass *mc = MACHINE_GET_CLASS(machine);
     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
     const char *kernel_filename = machine->kernel_filename;
     const char *initrd_filename = machine->initrd_filename;
@@ -1707,21 +1776,6 @@ static void ppc_spapr_init(MachineState *machine)
     long load_limit, fw_size;
     char *filename;
     int smt = kvmppc_smt_threads();
-    int spapr_cores = smp_cpus / smp_threads;
-    int spapr_max_cores = max_cpus / smp_threads;
-
-    if (mc->query_hotpluggable_cpus) {
-        if (smp_cpus % smp_threads) {
-            error_report("smp_cpus (%u) must be multiple of threads (%u)",
-                         smp_cpus, smp_threads);
-            exit(1);
-        }
-        if (max_cpus % smp_threads) {
-            error_report("max_cpus (%u) must be multiple of threads (%u)",
-                         max_cpus, smp_threads);
-            exit(1);
-        }
-    }
 
     msi_nonbroken = true;
 
@@ -1801,44 +1855,7 @@ static void ppc_spapr_init(MachineState *machine)
 
     ppc_cpu_parse_features(machine->cpu_model);
 
-    if (mc->query_hotpluggable_cpus) {
-        char *type = spapr_get_cpu_core_type(machine->cpu_model);
-
-        if (type == NULL) {
-            error_report("Unable to find sPAPR CPU Core definition");
-            exit(1);
-        }
-
-        spapr->cores = g_new0(Object *, spapr_max_cores);
-        for (i = 0; i < spapr_max_cores; i++) {
-            int core_id = i * smp_threads;
-            sPAPRDRConnector *drc =
-                spapr_dr_connector_new(OBJECT(spapr),
-                                       SPAPR_DR_CONNECTOR_TYPE_CPU,
-                                       (core_id / smp_threads) * smt);
-
-            qemu_register_reset(spapr_drc_reset, drc);
-
-            if (i < spapr_cores) {
-                Object *core  = object_new(type);
-                object_property_set_int(core, smp_threads, "nr-threads",
-                                        &error_fatal);
-                object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
-                                        &error_fatal);
-                object_property_set_bool(core, true, "realized", &error_fatal);
-            }
-        }
-        g_free(type);
-    } else {
-        for (i = 0; i < smp_cpus; i++) {
-            PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model);
-            if (cpu == NULL) {
-                error_report("Unable to find PowerPC CPU definition");
-                exit(1);
-            }
-            spapr_cpu_init(spapr, cpu, &error_fatal);
-       }
-    }
+    spapr_init_cpus(spapr);
 
     if (kvm_enabled()) {
         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index e0c14f6..1357293 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -46,7 +46,8 @@ static void spapr_cpu_destroy(PowerPCCPU *cpu)
     qemu_unregister_reset(spapr_cpu_reset, cpu);
 }
 
-void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp)
+static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+                           Error **errp)
 {
     CPUPPCState *env = &cpu->env;
     CPUState *cs = CPU(cpu);
@@ -166,6 +167,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
                      Error **errp)
 {
     sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+    MachineClass *mc = MACHINE_GET_CLASS(spapr);
     sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
     CPUCore *cc = CPU_CORE(dev);
     CPUState *cs = CPU(core->threads);
@@ -180,7 +182,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
     drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
     spapr->cores[index] = OBJECT(dev);
 
-    g_assert(drc);
+    g_assert(drc || !mc->query_hotpluggable_cpus);
 
     /*
      * Setup CPU DT entries only for hotplugged CPUs. For boot time or
@@ -190,13 +192,15 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
         fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
     }
 
-    drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-    drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
-    if (local_err) {
-        g_free(fdt);
-        spapr->cores[index] = NULL;
-        error_propagate(errp, local_err);
-        return;
+    if (drc) {
+        drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+        drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
+        if (local_err) {
+            g_free(fdt);
+            spapr->cores[index] = NULL;
+            error_propagate(errp, local_err);
+            return;
+        }
     }
 
     if (dev->hotplugged) {
@@ -209,8 +213,10 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
         /*
          * Set the right DRC states for cold plugged CPU.
          */
-        drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
-        drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
+        if (drc) {
+            drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
+            drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
+        }
     }
 }
 
@@ -227,7 +233,7 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
     char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model);
     const char *type = object_get_typename(OBJECT(dev));
 
-    if (!mc->query_hotpluggable_cpus) {
+    if (dev->hotplugged && !mc->query_hotpluggable_cpus) {
         error_setg(&local_err, "CPU hotplug not supported for this machine");
         goto out;
     }
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index bd5bcf7..f8d444d 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -614,7 +614,6 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
                                             uint32_t count, uint32_t index);
 void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
                                                uint32_t count, uint32_t index);
-void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp);
 void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
                                     sPAPRMachineState *spapr);
 
-- 
2.7.4

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

* [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (2 preceding siblings ...)
  2016-10-30 11:11 ` [Qemu-devel] [RFC 03/17] pseries: Always use core objects for CPU construction David Gibson
@ 2016-10-30 11:11 ` David Gibson
  2016-11-03  8:24   ` Alexey Kardashevskiy
  2016-11-04 10:45   ` Thomas Huth
  2016-10-30 11:11 ` [Qemu-devel] [RFC 05/17] ppc: Clean up and QOMify hypercall emulation David Gibson
                   ` (12 subsequent siblings)
  16 siblings, 2 replies; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

spapr_h_cas_compose_response() includes a cpu_update parameter which
controls whether it includes updated information on the CPUs in the device
tree fragment returned from the ibm,client-architecture-support (CAS) call.

Providing the updated information is essential when CAS has negotiated
compatibility options which require different cpu information to be
presented to the guest.  However, it should be safe to provide in other
cases (it will just override the existing data in the device tree with
identical data).  This simplifies the code by removing the parameter and
always providing the cpu update information.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c         | 5 +----
 hw/ppc/spapr_hcall.c   | 8 ++------
 include/hw/ppc/spapr.h | 1 -
 3 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index ad68a9d..3551439 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -686,7 +686,6 @@ out:
 
 int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
                                  target_ulong addr, target_ulong size,
-                                 bool cpu_update,
                                  sPAPROptionVector *ov5_updates)
 {
     void *fdt, *fdt_skel;
@@ -705,9 +704,7 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
     g_free(fdt_skel);
 
     /* Fixup cpu nodes */
-    if (cpu_update) {
-        _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
-    }
+    _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
 
     if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
         return -1;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 7c46d46..b5544cb 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -945,7 +945,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
     target_ulong ov_table;
     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
     CPUState *cs;
-    bool cpu_match = false, cpu_update = true;
+    bool cpu_match = false;
     unsigned old_cpu_version = cpu_->cpu_version;
     unsigned compat_lvl = 0, cpu_version = 0;
     unsigned max_lvl = get_compat_level(cpu_->max_compat);
@@ -999,10 +999,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
         }
     }
 
-    if (!cpu_version) {
-        cpu_update = false;
-    }
-
     /* For the future use: here @ov_table points to the first option vector */
     ov_table = list;
 
@@ -1028,7 +1024,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
 
     if (!spapr->cas_reboot) {
         spapr->cas_reboot =
-            (spapr_h_cas_compose_response(spapr, args[1], args[2], cpu_update,
+            (spapr_h_cas_compose_response(spapr, args[1], args[2],
                                           ov5_updates) != 0);
     }
     spapr_ovec_cleanup(ov5_updates);
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index f8d444d..04d2821 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -589,7 +589,6 @@ void spapr_events_init(sPAPRMachineState *sm);
 void spapr_dt_events(sPAPRMachineState *sm, void *fdt);
 int spapr_h_cas_compose_response(sPAPRMachineState *sm,
                                  target_ulong addr, target_ulong size,
-                                 bool cpu_update,
                                  sPAPROptionVector *ov5_updates);
 sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
 void spapr_tce_table_enable(sPAPRTCETable *tcet,
-- 
2.7.4

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

* [Qemu-devel] [RFC 05/17] ppc: Clean up and QOMify hypercall emulation
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (3 preceding siblings ...)
  2016-10-30 11:11 ` [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional David Gibson
@ 2016-10-30 11:11 ` David Gibson
  2016-11-03  8:50   ` Alexey Kardashevskiy
  2016-10-30 11:11 ` [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr David Gibson
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

The pseries machine type is a bit unusual in that it runs a paravirtualized
guest.  The guest expects to interact with a hypervisor, and qemu
emulates the functions of that hypervisor directly, rather than executing
hypervisor code within the emulated system.

To implement this in TCG, we need to intercept hypercall instructions and
direct them to the machine's hypercall handlers, rather than attempting to
perform a privilege change within TCG.  This is controlled by a global
hook - cpu_ppc_hypercall.

This cleanup makes the handling a little cleaner and more extensible that
a single global variable.  Instead, each CPU to have hypercalls intercepted
has a pointer set to a QOM object implementing a new virtual hypervisor
interface.  A method in that interface is called by TCG when it sees a
hypercall instruction.  It's possible we may want to add other methods in
future.

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

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 3551439..b7762ee 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1006,7 +1006,8 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
 }
 
-static void emulate_spapr_hypercall(PowerPCCPU *cpu)
+static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
+                                    PowerPCCPU *cpu)
 {
     CPUPPCState *env = &cpu->env;
 
@@ -1778,8 +1779,6 @@ static void ppc_spapr_init(MachineState *machine)
 
     QLIST_INIT(&spapr->phbs);
 
-    cpu_ppc_hypercall = emulate_spapr_hypercall;
-
     /* Allocate RMA if necessary */
     rma_alloc_size = kvmppc_alloc_rma(&rma);
 
@@ -2610,6 +2609,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
     NMIClass *nc = NMI_CLASS(oc);
     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
+    PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
 
     mc->desc = "pSeries Logical Partition (PAPR compliant)";
 
@@ -2641,6 +2641,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
     fwc->get_dev_path = spapr_get_fw_dev_path;
     nc->nmi_monitor_handler = spapr_nmi;
     smc->phb_placement = spapr_phb_placement;
+    vhc->hypercall = emulate_spapr_hypercall;
 }
 
 static const TypeInfo spapr_machine_info = {
@@ -2656,6 +2657,7 @@ static const TypeInfo spapr_machine_info = {
         { TYPE_FW_PATH_PROVIDER },
         { TYPE_NMI },
         { TYPE_HOTPLUG_HANDLER },
+        { TYPE_PPC_VIRTUAL_HYPERVISOR },
         { }
     },
 };
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 1357293..ee5cd14 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -57,6 +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);
 
     if (cpu->max_compat) {
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 1c90adb..a655105 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1148,6 +1148,9 @@ do {                                            \
     env->wdt_period[3] = (d_);                  \
  } while (0)
 
+typedef struct PPCVirtualHypervisor PPCVirtualHypervisor;
+typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
+
 /**
  * PowerPCCPU:
  * @env: #CPUPPCState
@@ -1166,6 +1169,7 @@ struct PowerPCCPU {
     int cpu_dt_id;
     uint32_t max_compat;
     uint32_t cpu_version;
+    PPCVirtualHypervisor *vhyp;
 };
 
 static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
@@ -1180,6 +1184,25 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
 PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
 PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr);
 
+struct PPCVirtualHypervisor {
+    Object parent;
+};
+
+struct PPCVirtualHypervisorClass {
+    InterfaceClass parent;
+    void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
+};
+
+#define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
+#define PPC_VIRTUAL_HYPERVISOR(obj)                 \
+    OBJECT_CHECK(PPCVirtualHypervisor, (obj), TYPE_PPC_VIRTUAL_HYPERVISOR)
+#define PPC_VIRTUAL_HYPERVISOR_CLASS(klass)         \
+    OBJECT_CLASS_CHECK(PPCVirtualHypervisorClass, (klass), \
+                       TYPE_PPC_VIRTUAL_HYPERVISOR)
+#define PPC_VIRTUAL_HYPERVISOR_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(PPCVirtualHypervisorClass, (obj), \
+                     TYPE_PPC_VIRTUAL_HYPERVISOR)
+
 void ppc_cpu_do_interrupt(CPUState *cpu);
 bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
 void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
@@ -1252,6 +1275,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);
 #endif
 #endif
@@ -2421,8 +2445,6 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx)
            (start + nregs > 32 && (rx >= start || rx < start + nregs - 32));
 }
 
-extern void (*cpu_ppc_hypercall)(PowerPCCPU *);
-
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
 
 /**
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 808760b..a077939 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -35,11 +35,6 @@
 #endif
 
 /*****************************************************************************/
-/* PowerPC Hypercall emulation */
-
-void (*cpu_ppc_hypercall)(PowerPCCPU *);
-
-/*****************************************************************************/
 /* Exception processing */
 #if defined(CONFIG_USER_ONLY)
 void ppc_cpu_do_interrupt(CPUState *cs)
@@ -318,8 +313,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         env->nip += 4;
 
         /* "PAPR mode" built-in hypercall emulation */
-        if ((lev == 1) && cpu_ppc_hypercall) {
-            cpu_ppc_hypercall(cpu);
+        if ((lev == 1) && cpu->vhyp) {
+            PPCVirtualHypervisorClass *vhc =
+                PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+            vhc->hypercall(cpu->vhyp, cpu);
             return;
         }
         if (lev == 1) {
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 208fa1e..21899a4 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8857,6 +8857,11 @@ 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)
 {
     CPUPPCState *env = &cpu->env;
@@ -10587,9 +10592,16 @@ static const TypeInfo ppc_cpu_type_info = {
     .class_init = ppc_cpu_class_init,
 };
 
+static const TypeInfo ppc_vhyp_type_info = {
+    .name = TYPE_PPC_VIRTUAL_HYPERVISOR,
+    .parent = TYPE_INTERFACE,
+    .class_size = sizeof(PPCVirtualHypervisorClass),
+};
+
 static void ppc_cpu_register_types(void)
 {
     type_register_static(&ppc_cpu_type_info);
+    type_register_static(&ppc_vhyp_type_info);
 }
 
 type_init(ppc_cpu_register_types)
-- 
2.7.4

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

* [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (4 preceding siblings ...)
  2016-10-30 11:11 ` [Qemu-devel] [RFC 05/17] ppc: Clean up and QOMify hypercall emulation David Gibson
@ 2016-10-30 11:11 ` David Gibson
  2016-11-04  2:26   ` Alexey Kardashevskiy
  2016-11-04 10:51   ` Thomas Huth
  2016-10-30 11:11 ` [Qemu-devel] [RFC 07/17] ppc: Rewrite ppc_set_compat() David Gibson
                   ` (10 subsequent siblings)
  16 siblings, 2 replies; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

The 'cpu_version' field in PowerPCCPU is badly named.  It's named after the
'cpu-version' device tree property where it is advertised, but that meaning
may not be obvious in most places it appears.

Worse, it doesn't even really correspond to that device tree property.  The
property contains either the processor's PVR, or, if the CPU is running in
a compatibility mode, a special "logical PVR" representing which mode.

Rename the cpu_version field, and a number of related variables to
compat_pvr to make this clearer.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c              |  4 ++--
 hw/ppc/spapr_hcall.c        | 30 +++++++++++++++---------------
 target-ppc/cpu.h            |  6 +++---
 target-ppc/kvm.c            |  4 ++--
 target-ppc/kvm_ppc.h        |  4 ++--
 target-ppc/translate_init.c | 10 +++++-----
 6 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index b7762ee..276cefa 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -149,8 +149,8 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
     uint32_t gservers_prop[smt_threads * 2];
     int index = ppc_get_vcpu_dt_id(cpu);
 
-    if (cpu->cpu_version) {
-        ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version);
+    if (cpu->compat_pvr) {
+        ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
         if (ret < 0) {
             return ret;
         }
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index b5544cb..d93f580 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -882,7 +882,7 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 }
 
 typedef struct {
-    uint32_t cpu_version;
+    uint32_t compat_pvr;
     Error *err;
 } SetCompatState;
 
@@ -892,7 +892,7 @@ static void do_set_compat(CPUState *cs, void *arg)
     SetCompatState *s = arg;
 
     cpu_synchronize_state(cs);
-    ppc_set_compat(cpu, s->cpu_version, &s->err);
+    ppc_set_compat(cpu, s->compat_pvr, &s->err);
 }
 
 #define get_compat_level(cpuver) ( \
@@ -903,7 +903,7 @@ static void do_set_compat(CPUState *cs, void *arg)
 
 static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
                                   unsigned max_lvl, unsigned *compat_lvl,
-                                  unsigned *cpu_version)
+                                  unsigned *compat_pvr)
 {
     unsigned lvl = get_compat_level(pvr);
     bool is205, is206, is207;
@@ -926,12 +926,12 @@ static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
             /* User did not set the level, choose the highest */
             if (*compat_lvl <= lvl) {
                 *compat_lvl = lvl;
-                *cpu_version = pvr;
+                *compat_pvr = pvr;
             }
         } else if (max_lvl >= lvl) {
             /* User chose the level, don't set higher than this */
             *compat_lvl = lvl;
-            *cpu_version = pvr;
+            *compat_pvr = pvr;
         }
     }
 }
@@ -946,8 +946,8 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
     CPUState *cs;
     bool cpu_match = false;
-    unsigned old_cpu_version = cpu_->cpu_version;
-    unsigned compat_lvl = 0, cpu_version = 0;
+    unsigned old_compat_pvr = cpu_->compat_pvr;
+    unsigned compat_lvl = 0, compat_pvr = 0;
     unsigned max_lvl = get_compat_level(cpu_->max_compat);
     int counter;
     sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
@@ -965,12 +965,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
         if (!max_lvl &&
             ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
             cpu_match = true;
-            cpu_version = 0;
-        } else if (pvr == cpu_->cpu_version) {
+            compat_pvr = 0;
+        } else if (pvr == cpu_->compat_pvr) {
             cpu_match = true;
-            cpu_version = cpu_->cpu_version;
+            compat_pvr = cpu_->compat_pvr;
         } else if (!cpu_match) {
-            cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &cpu_version);
+            cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &compat_pvr);
         }
         /* Terminator record */
         if (~pvr_mask & pvr) {
@@ -979,14 +979,14 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
     }
 
     /* Parsing finished */
-    trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match,
-                        cpu_version, pcc->pcr_mask);
+    trace_spapr_cas_pvr(cpu_->compat_pvr, cpu_match,
+                        compat_pvr, pcc->pcr_mask);
 
     /* Update CPUs */
-    if (old_cpu_version != cpu_version) {
+    if (old_compat_pvr != compat_pvr) {
         CPU_FOREACH(cs) {
             SetCompatState s = {
-                .cpu_version = cpu_version,
+                .compat_pvr = compat_pvr,
                 .err = NULL,
             };
 
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index a655105..f7656cb 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1156,7 +1156,7 @@ typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
  * @env: #CPUPPCState
  * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
  * @max_compat: Maximal supported logical PVR from the command line
- * @cpu_version: Current logical PVR, zero if in "raw" mode
+ * @compat_pvr: Current logical PVR, zero if in "raw" mode
  *
  * A PowerPC CPU.
  */
@@ -1168,7 +1168,7 @@ struct PowerPCCPU {
     CPUPPCState env;
     int cpu_dt_id;
     uint32_t max_compat;
-    uint32_t cpu_version;
+    uint32_t compat_pvr;
     PPCVirtualHypervisor *vhyp;
 };
 
@@ -1243,7 +1243,7 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value);
 void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
 int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
 #if defined(TARGET_PPC64)
-void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp);
+void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
 #endif
 
 /* Time-base and decrementer management */
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 9c4834c..15e12f3 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -2103,9 +2103,9 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
     cap_papr = 1;
 }
 
-int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
+int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr)
 {
-    return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &cpu_version);
+    return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &compat_pvr);
 }
 
 void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index bd1d78b..841a29b 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -26,7 +26,7 @@ void kvmppc_enable_logical_ci_hcalls(void);
 void kvmppc_enable_set_mode_hcall(void);
 void kvmppc_enable_clear_ref_mod_hcalls(void);
 void kvmppc_set_papr(PowerPCCPU *cpu);
-int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version);
+int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr);
 void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
 int kvmppc_smt_threads(void);
 int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
@@ -123,7 +123,7 @@ static inline void kvmppc_set_papr(PowerPCCPU *cpu)
 {
 }
 
-static inline int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
+static inline int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr)
 {
     return 0;
 }
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 21899a4..c35065d 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9957,7 +9957,7 @@ int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
     CPUState *cs = CPU(cpu);
     int ret = MIN(cs->nr_threads, kvmppc_smt_threads());
 
-    switch (cpu->cpu_version) {
+    switch (cpu->compat_pvr) {
     case CPU_POWERPC_LOGICAL_2_05:
         ret = MIN(ret, 2);
         break;
@@ -9973,15 +9973,15 @@ int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
 }
 
 #ifdef TARGET_PPC64
-void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp)
+void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
 {
     int ret = 0;
     CPUPPCState *env = &cpu->env;
     PowerPCCPUClass *host_pcc;
 
-    cpu->cpu_version = cpu_version;
+    cpu->compat_pvr = compat_pvr;
 
-    switch (cpu_version) {
+    switch (compat_pvr) {
     case CPU_POWERPC_LOGICAL_2_05:
         env->spr[SPR_PCR] = PCR_TM_DIS | PCR_VSX_DIS | PCR_COMPAT_2_07 |
                             PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -10004,7 +10004,7 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp)
     }
 
     if (kvm_enabled()) {
-        ret = kvmppc_set_compat(cpu, cpu->cpu_version);
+        ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
         if (ret < 0) {
             error_setg_errno(errp, -ret,
                              "Unable to set CPU compatibility mode in KVM");
-- 
2.7.4

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

* [Qemu-devel] [RFC 07/17] ppc: Rewrite ppc_set_compat()
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (5 preceding siblings ...)
  2016-10-30 11:11 ` [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr David Gibson
@ 2016-10-30 11:11 ` David Gibson
  2016-11-04  2:57   ` Alexey Kardashevskiy
  2016-10-30 11:11 ` [Qemu-devel] [RFC 08/17] ppc: Rewrite ppc_get_compat_smt_threads() David Gibson
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

This rewrites the ppc_set_compat() function so that instead of open coding
the various compatibility modes, it reads the relevant data from a table.
This is a first step in consolidating the information on compatibility
modes scattered across the code into a single place.

It also makes one change to the logic.  The old code masked the bits to be
set in the PCR (Processor Compatibility Register) by which bits are valid
on the host CPU.  This made no sense, since it was done regardless of
whether our guest CPU was the same as the host CPU or not.  Futhermore,
the actual PCR bits are only relevant for TCG[1] - KVM instead uses the
compatibility mode we tell it in kvmppc_set_compat().  When using TCG
host cpu information usually isn't even present.

While we're at it, we put the new implementation in a new file to make the
enormouse translate_init.c a little smaller.

[1] Actually it doesn't even do anything in TCG, but it will if / when we
    get to implementing compatibility mode logic at that level.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/Makefile.objs    |  1 +
 target-ppc/compat.c         | 91 +++++++++++++++++++++++++++++++++++++++++++++
 target-ppc/cpu.h            |  6 ++-
 target-ppc/translate_init.c | 41 --------------------
 4 files changed, 97 insertions(+), 42 deletions(-)
 create mode 100644 target-ppc/compat.c

diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
index e667e69..feb5c30 100644
--- a/target-ppc/Makefile.objs
+++ b/target-ppc/Makefile.objs
@@ -15,3 +15,4 @@ obj-y += misc_helper.o
 obj-y += mem_helper.o
 obj-$(CONFIG_USER_ONLY) += user_only_helper.o
 obj-y += gdbstub.o
+obj-$(TARGET_PPC64) += compat.o
diff --git a/target-ppc/compat.c b/target-ppc/compat.c
new file mode 100644
index 0000000..f3fd9c6
--- /dev/null
+++ b/target-ppc/compat.c
@@ -0,0 +1,91 @@
+/*
+ *  PowerPC CPU initialization for qemu.
+ *
+ *  Copyright 2016, David Gibson, Red Hat Inc. <dgibson@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "sysemu/cpus.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "cpu-models.h"
+
+typedef struct {
+    uint32_t pvr;
+    uint64_t pcr;
+} CompatInfo;
+
+static const CompatInfo compat_table[] = {
+    { /* POWER6, ISA2.05 */
+        .pvr = CPU_POWERPC_LOGICAL_2_05,
+        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
+               | PCR_TM_DIS | PCR_VSX_DIS,
+    },
+    { /* POWER7, ISA2.06 */
+        .pvr = CPU_POWERPC_LOGICAL_2_06,
+        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+    },
+    {
+        .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
+        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+    },
+    { /* POWER8, ISA2.07 */
+        .pvr = CPU_POWERPC_LOGICAL_2_07,
+        .pcr = PCR_COMPAT_2_07,
+    },
+};
+
+static const CompatInfo *compat_by_pvr(uint32_t pvr)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
+        if (compat_table[i].pvr == pvr) {
+            return &compat_table[i];
+        }
+    }
+    return NULL;
+}
+
+void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
+{
+    const CompatInfo *compat = compat_by_pvr(compat_pvr);
+    CPUPPCState *env = &cpu->env;
+    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+    uint64_t pcr;
+
+    if (!compat_pvr) {
+        pcr = 0;
+    } else if (!compat) {
+        error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
+        return;
+    } else {
+        pcr = compat->pcr;
+    }
+
+    cpu->compat_pvr = compat_pvr;
+    env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
+
+    if (kvm_enabled()) {
+        int ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
+        if (ret < 0) {
+            error_setg_errno(errp, -ret,
+                             "Unable to set CPU compatibility mode in KVM");
+        }
+    }
+}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index f7656cb..15d5e4b 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1243,7 +1243,6 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value);
 void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
 int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
 #if defined(TARGET_PPC64)
-void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
 #endif
 
 /* Time-base and decrementer management */
@@ -1314,6 +1313,11 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
     return ifetch ? env->immu_idx : env->dmmu_idx;
 }
 
+/* Compatibility modes */
+#if defined(TARGET_PPC64)
+void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
+#endif /* defined(TARGET_PPC64) */
+
 #include "exec/cpu-all.h"
 
 /*****************************************************************************/
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index c35065d..a70eafb 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9972,47 +9972,6 @@ int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
     return ret;
 }
 
-#ifdef TARGET_PPC64
-void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
-{
-    int ret = 0;
-    CPUPPCState *env = &cpu->env;
-    PowerPCCPUClass *host_pcc;
-
-    cpu->compat_pvr = compat_pvr;
-
-    switch (compat_pvr) {
-    case CPU_POWERPC_LOGICAL_2_05:
-        env->spr[SPR_PCR] = PCR_TM_DIS | PCR_VSX_DIS | PCR_COMPAT_2_07 |
-                            PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
-        break;
-    case CPU_POWERPC_LOGICAL_2_06:
-    case CPU_POWERPC_LOGICAL_2_06_PLUS:
-        env->spr[SPR_PCR] = PCR_TM_DIS | PCR_COMPAT_2_07 | PCR_COMPAT_2_06;
-        break;
-    case CPU_POWERPC_LOGICAL_2_07:
-        env->spr[SPR_PCR] = PCR_COMPAT_2_07;
-        break;
-    default:
-        env->spr[SPR_PCR] = 0;
-        break;
-    }
-
-    host_pcc = kvm_ppc_get_host_cpu_class();
-    if (host_pcc) {
-        env->spr[SPR_PCR] &= host_pcc->pcr_mask;
-    }
-
-    if (kvm_enabled()) {
-        ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
-        if (ret < 0) {
-            error_setg_errno(errp, -ret,
-                             "Unable to set CPU compatibility mode in KVM");
-        }
-    }
-}
-#endif
-
 static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
 {
     ObjectClass *oc = (ObjectClass *)a;
-- 
2.7.4

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

* [Qemu-devel] [RFC 08/17] ppc: Rewrite ppc_get_compat_smt_threads()
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (6 preceding siblings ...)
  2016-10-30 11:11 ` [Qemu-devel] [RFC 07/17] ppc: Rewrite ppc_set_compat() David Gibson
@ 2016-10-30 11:11 ` David Gibson
  2016-11-04  3:37   ` Alexey Kardashevskiy
  2016-10-30 11:12 ` [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting David Gibson
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:11 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

To continue consolidation of compatibility mode information, this rewrites
the ppc_get_compat_smt_threads() function using the table of compatiblity
modes in target-ppc/compat.c.

It's not a direct replacement, the new ppc_compat_max_threads() function
has simpler semantics - it just returns the number of threads the cpu
model has, taking into account any compatiblity mode it is in.

This no longer takes into account kvmppc_smt_threads() as the previous
version did.  That check wasn't useful because we check elsewhere that
CPUs aren't instantiated with more threads than kvm allows (or if we didn't
things will already be broken and this won't make it any worse).

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c              |  8 ++++----
 target-ppc/compat.c         | 18 ++++++++++++++++++
 target-ppc/cpu.h            |  2 +-
 target-ppc/translate_init.c | 20 --------------------
 4 files changed, 23 insertions(+), 25 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 276cefa..6c78889 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -207,6 +207,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
         PowerPCCPU *cpu = POWERPC_CPU(cs);
         DeviceClass *dc = DEVICE_GET_CLASS(cs);
         int index = ppc_get_vcpu_dt_id(cpu);
+        int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
 
         if ((index % smt) != 0) {
             continue;
@@ -241,8 +242,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
             return ret;
         }
 
-        ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
-                                     ppc_get_compat_smt_threads(cpu));
+        ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
         if (ret < 0) {
             return ret;
         }
@@ -408,6 +408,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
     size_t page_sizes_prop_size;
     uint32_t vcpus_per_socket = smp_threads * smp_cores;
     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
+    int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
     sPAPRDRConnector *drc;
     sPAPRDRConnectorClass *drck;
     int drc_index;
@@ -495,8 +496,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
 
     _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs));
 
-    _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
-                                ppc_get_compat_smt_threads(cpu)));
+    _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
 }
 
 static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
diff --git a/target-ppc/compat.c b/target-ppc/compat.c
index f3fd9c6..66529a6 100644
--- a/target-ppc/compat.c
+++ b/target-ppc/compat.c
@@ -28,6 +28,7 @@
 typedef struct {
     uint32_t pvr;
     uint64_t pcr;
+    int max_threads;
 } CompatInfo;
 
 static const CompatInfo compat_table[] = {
@@ -35,18 +36,22 @@ static const CompatInfo compat_table[] = {
         .pvr = CPU_POWERPC_LOGICAL_2_05,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
                | PCR_TM_DIS | PCR_VSX_DIS,
+        .max_threads = 2,
     },
     { /* POWER7, ISA2.06 */
         .pvr = CPU_POWERPC_LOGICAL_2_06,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+        .max_threads = 4,
     },
     {
         .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+        .max_threads = 4,
     },
     { /* POWER8, ISA2.07 */
         .pvr = CPU_POWERPC_LOGICAL_2_07,
         .pcr = PCR_COMPAT_2_07,
+        .max_threads = 8,
     },
 };
 
@@ -89,3 +94,16 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
         }
     }
 }
+
+int ppc_compat_max_threads(PowerPCCPU *cpu)
+{
+    const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
+    int n_threads = CPU(cpu)->nr_threads;
+
+    if (cpu->compat_pvr) {
+        g_assert(compat);
+        n_threads = MIN(n_threads, compat->max_threads);
+    }
+
+    return n_threads;
+}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 15d5e4b..cfda7b2 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1241,7 +1241,6 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
 void ppc_store_msr (CPUPPCState *env, target_ulong value);
 
 void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
-int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
 #if defined(TARGET_PPC64)
 #endif
 
@@ -1316,6 +1315,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 /* Compatibility modes */
 #if defined(TARGET_PPC64)
 void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
+int ppc_compat_max_threads(PowerPCCPU *cpu);
 #endif /* defined(TARGET_PPC64) */
 
 #include "exec/cpu-all.h"
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index a70eafb..ba48242 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -9952,26 +9952,6 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp)
     }
 }
 
-int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
-{
-    CPUState *cs = CPU(cpu);
-    int ret = MIN(cs->nr_threads, kvmppc_smt_threads());
-
-    switch (cpu->compat_pvr) {
-    case CPU_POWERPC_LOGICAL_2_05:
-        ret = MIN(ret, 2);
-        break;
-    case CPU_POWERPC_LOGICAL_2_06:
-        ret = MIN(ret, 4);
-        break;
-    case CPU_POWERPC_LOGICAL_2_07:
-        ret = MIN(ret, 8);
-        break;
-    }
-
-    return ret;
-}
-
 static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
 {
     ObjectClass *oc = (ObjectClass *)a;
-- 
2.7.4

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

* [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (7 preceding siblings ...)
  2016-10-30 11:11 ` [Qemu-devel] [RFC 08/17] ppc: Rewrite ppc_get_compat_smt_threads() David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-10-31  5:55   ` Alexey Kardashevskiy
  2016-10-30 11:12 ` [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic David Gibson
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

Current ppc_set_compat() will attempt to set any compatiblity mode
specified, regardless of whether it's available on the CPU.  The caller is
expected to make sure it is setting a possible mode, which is awkwward
because most of the information to make that decision is at the CPU level.

This begins to clean this up by introducing a ppc_check_compat() function
which will determine if a given compatiblity mode is supported on a CPU
(and also whether it lies within specified minimum and maximum compat
levels, which will be useful later).  It also contains an assertion that
the CPU has a "virtual hypervisor"[1], that is, that the guest isn't
permitted to execute hypervisor privilege code.  Without that, the guest
would own the PCR and so could override any mode set here.  Only machine
types which use a virtual hypervisor (i.e. 'pseries') should use
ppc_check_compat().

ppc_set_compat() is modified to validate the compatibility mode it is given
and fail if it's not available on this CPU.

[1] Or user-only mode, which also obviously doesn't allow access to the
hypervisor privileged PCR.  We don't use that now, but could in future.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/compat.c | 41 +++++++++++++++++++++++++++++++++++++++++
 target-ppc/cpu.h    |  2 ++
 2 files changed, 43 insertions(+)

diff --git a/target-ppc/compat.c b/target-ppc/compat.c
index 66529a6..1059555 100644
--- a/target-ppc/compat.c
+++ b/target-ppc/compat.c
@@ -28,29 +28,37 @@
 typedef struct {
     uint32_t pvr;
     uint64_t pcr;
+    uint64_t pcr_level;
     int max_threads;
 } CompatInfo;
 
 static const CompatInfo compat_table[] = {
+    /*
+     * Ordered from oldest to newest - the code relies on this
+     */
     { /* POWER6, ISA2.05 */
         .pvr = CPU_POWERPC_LOGICAL_2_05,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
                | PCR_TM_DIS | PCR_VSX_DIS,
+        .pcr_level = PCR_COMPAT_2_05,
         .max_threads = 2,
     },
     { /* POWER7, ISA2.06 */
         .pvr = CPU_POWERPC_LOGICAL_2_06,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+        .pcr_level = PCR_COMPAT_2_06,
         .max_threads = 4,
     },
     {
         .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+        .pcr_level = PCR_COMPAT_2_06,
         .max_threads = 4,
     },
     { /* POWER8, ISA2.07 */
         .pvr = CPU_POWERPC_LOGICAL_2_07,
         .pcr = PCR_COMPAT_2_07,
+        .pcr_level = PCR_COMPAT_2_07,
         .max_threads = 8,
     },
 };
@@ -67,6 +75,35 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr)
     return NULL;
 }
 
+bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
+                      uint32_t min_compat_pvr, uint32_t max_compat_pvr)
+{
+    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+    const CompatInfo *compat = compat_by_pvr(compat_pvr);
+    const CompatInfo *min = compat_by_pvr(min_compat_pvr);
+    const CompatInfo *max = compat_by_pvr(max_compat_pvr);
+
+#if !defined(CONFIG_USER_ONLY)
+    g_assert(cpu->vhyp);
+#endif
+    g_assert(!min_compat_pvr || min);
+    g_assert(!max_compat_pvr || max);
+
+    if (!compat) {
+        /* Not a recognized logical PVR */
+        return false;
+    }
+    if ((min && (compat < min)) || (max && (compat > max))) {
+        /* Outside specified range */
+        return false;
+    }
+    if (!(pcc->pcr_supported & compat->pcr_level)) {
+        /* Not supported by this CPU */
+        return false;
+    }
+    return true;
+}
+
 void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
 {
     const CompatInfo *compat = compat_by_pvr(compat_pvr);
@@ -79,6 +116,10 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
     } else if (!compat) {
         error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
         return;
+    } else if (!ppc_check_compat(cpu, compat_pvr, 0, 0)) {
+        error_setg(errp, "Compatibility PVR 0x%08"PRIx32" not valid for CPU",
+                   compat_pvr);
+        return;
     } else {
         pcr = compat->pcr;
     }
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index cfda7b2..91e8be8 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1314,6 +1314,8 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 
 /* Compatibility modes */
 #if defined(TARGET_PPC64)
+bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
+                      uint32_t min_compat_pvr, uint32_t max_compat_pvr);
 void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
 int ppc_compat_max_threads(PowerPCCPU *cpu);
 #endif /* defined(TARGET_PPC64) */
-- 
2.7.4

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

* [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (8 preceding siblings ...)
  2016-10-30 11:12 ` [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-10-31  5:00   ` Alexey Kardashevskiy
  2016-11-10 17:54   ` Michael Roth
  2016-10-30 11:12 ` [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all() David Gibson
                   ` (6 subsequent siblings)
  16 siblings, 2 replies; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

During boot, PAPR guests negotiate CPU model support with the
ibm,client-architecture-support mechanism.  The logic to implement this in
qemu is very convoluted.  This cleans it up to be cleaner, using the new
ppc_check_compat() call.

The new logic for choosing a compatibility mode is:
    1. If the guest lists the CPU's real PVR as supported *AND* no
       maximum compatibility mode has been requested on the command line
       then we use "raw" mode - the CPU acts with full capabilities.
    2. Otherwise, we pick the most recent compatibility mode which is
       both supported by the CPU, and is advertised as supported by the
       guest.
I think the original code approximated the same thing, but it's hard to be
sure, and I think it had some weird edge cases.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_hcall.c | 107 +++++++++++++++++----------------------------------
 hw/ppc/trace-events  |   2 +-
 2 files changed, 37 insertions(+), 72 deletions(-)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index d93f580..3bd6d06 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -895,98 +895,63 @@ static void do_set_compat(CPUState *cs, void *arg)
     ppc_set_compat(cpu, s->compat_pvr, &s->err);
 }
 
-#define get_compat_level(cpuver) ( \
-    ((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \
-    ((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \
-    ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
-    ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
-
-static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
-                                  unsigned max_lvl, unsigned *compat_lvl,
-                                  unsigned *compat_pvr)
-{
-    unsigned lvl = get_compat_level(pvr);
-    bool is205, is206, is207;
-
-    if (!lvl) {
-        return;
-    }
-
-    /* If it is a logical PVR, try to determine the highest level */
-    is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) &&
-            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
-    is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) &&
-            ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
-             (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
-    is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) &&
-            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07));
-
-    if (is205 || is206 || is207) {
-        if (!max_lvl) {
-            /* User did not set the level, choose the highest */
-            if (*compat_lvl <= lvl) {
-                *compat_lvl = lvl;
-                *compat_pvr = pvr;
-            }
-        } else if (max_lvl >= lvl) {
-            /* User chose the level, don't set higher than this */
-            *compat_lvl = lvl;
-            *compat_pvr = pvr;
-        }
-    }
-}
-
-static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
+static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
                                                   sPAPRMachineState *spapr,
                                                   target_ulong opcode,
                                                   target_ulong *args)
 {
     target_ulong list = ppc64_phys_to_real(args[0]);
     target_ulong ov_table;
-    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
     CPUState *cs;
-    bool cpu_match = false;
-    unsigned old_compat_pvr = cpu_->compat_pvr;
-    unsigned compat_lvl = 0, compat_pvr = 0;
-    unsigned max_lvl = get_compat_level(cpu_->max_compat);
-    int counter;
+    bool explicit_match = false; /* Matched the CPU's real PVR */
+    uint32_t max_compat = cpu->max_compat;
+    uint32_t best_compat = 0;
+    int i;
     sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
 
-    /* Parse PVR list */
-    for (counter = 0; counter < 512; ++counter) {
+    /*
+     * We scan the supplied table of PVRs looking for two things
+     *   1. Is our real CPU PVR in the list?
+     *   2. What's the "best" listed logical PVR
+     */
+    for (i = 0; i < 512; ++i) {
         uint32_t pvr, pvr_mask;
 
-        pvr_mask = ldl_be_phys(&address_space_memory, list);
-        list += 4;
         pvr = ldl_be_phys(&address_space_memory, list);
-        list += 4;
-
-        trace_spapr_cas_pvr_try(pvr);
-        if (!max_lvl &&
-            ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
-            cpu_match = true;
-            compat_pvr = 0;
-        } else if (pvr == cpu_->compat_pvr) {
-            cpu_match = true;
-            compat_pvr = cpu_->compat_pvr;
-        } else if (!cpu_match) {
-            cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &compat_pvr);
-        }
-        /* Terminator record */
+        pvr_mask = ldl_be_phys(&address_space_memory, list + 4);
+        list += 8;
+
         if (~pvr_mask & pvr) {
-            break;
+            break; /* Terminator record */
         }
+
+        if ((cpu->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask)) {
+            explicit_match = true;
+        } else {
+            if (ppc_check_compat(cpu, pvr, best_compat, max_compat)) {
+                best_compat = pvr;
+            }
+        }
+    }
+
+    if (!max_compat && explicit_match) {
+        /* If the guest explicitly supports the CPU, *and* user hasn't
+         * requested a compatibility mode, use "raw" mode */
+        best_compat = 0;
+    } else if (best_compat == 0) {
+        /* Didn't find any supported compat modes */
+        /* FIXME: what's the right error here? */
+        return H_HARDWARE;
     }
 
     /* Parsing finished */
-    trace_spapr_cas_pvr(cpu_->compat_pvr, cpu_match,
-                        compat_pvr, pcc->pcr_mask);
+    trace_spapr_cas_pvr(cpu->compat_pvr, explicit_match, best_compat);
 
     /* Update CPUs */
-    if (old_compat_pvr != compat_pvr) {
+    if (cpu->compat_pvr != best_compat) {
         CPU_FOREACH(cs) {
             SetCompatState s = {
-                .compat_pvr = compat_pvr,
+                .compat_pvr = best_compat,
                 .err = NULL,
             };
 
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index 2297ead..604ac92 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -15,7 +15,7 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
 
 # hw/ppc/spapr_hcall.c
 spapr_cas_pvr_try(uint32_t pvr) "%x"
-spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64
+spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=%x, explicit_match=%u, new=%x"
 
 # hw/ppc/spapr_iommu.c
 spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
-- 
2.7.4

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

* [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all()
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (9 preceding siblings ...)
  2016-10-30 11:12 ` [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-11-04  4:01   ` Alexey Kardashevskiy
  2016-10-30 11:12 ` [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode David Gibson
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

Once a compatiblity mode is negotiated with the guest,
h_client_architecture_support() uses run_on_cpu() to update each CPU to
the new mode.  We're going to want this logic somewhere else shortly,
so make a helper function to do this global update.

We put it in target-ppc/compat.c - it makes as much sense at the CPU level
as it does at the machine level.  We also move the cpu_synchronize_state()
into ppc_set_compat(), since it doesn't really make any sense to call that
without synchronizing state.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_hcall.c | 31 +++++--------------------------
 target-ppc/compat.c  | 36 ++++++++++++++++++++++++++++++++++++
 target-ppc/cpu.h     |  3 +++
 3 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 3bd6d06..4eaf9a6 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -881,20 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     return ret;
 }
 
-typedef struct {
-    uint32_t compat_pvr;
-    Error *err;
-} SetCompatState;
-
-static void do_set_compat(CPUState *cs, void *arg)
-{
-    PowerPCCPU *cpu = POWERPC_CPU(cs);
-    SetCompatState *s = arg;
-
-    cpu_synchronize_state(cs);
-    ppc_set_compat(cpu, s->compat_pvr, &s->err);
-}
-
 static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
                                                   sPAPRMachineState *spapr,
                                                   target_ulong opcode,
@@ -902,7 +888,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
 {
     target_ulong list = ppc64_phys_to_real(args[0]);
     target_ulong ov_table;
-    CPUState *cs;
     bool explicit_match = false; /* Matched the CPU's real PVR */
     uint32_t max_compat = cpu->max_compat;
     uint32_t best_compat = 0;
@@ -949,18 +934,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
 
     /* Update CPUs */
     if (cpu->compat_pvr != best_compat) {
-        CPU_FOREACH(cs) {
-            SetCompatState s = {
-                .compat_pvr = best_compat,
-                .err = NULL,
-            };
+        Error *local_err = NULL;
 
-            run_on_cpu(cs, do_set_compat, &s);
-
-            if (s.err) {
-                error_report_err(s.err);
-                return H_HARDWARE;
-            }
+        ppc_set_compat_all(best_compat, &local_err);
+        if (local_err) {
+            error_report_err(local_err);
+            return H_HARDWARE;
         }
     }
 
diff --git a/target-ppc/compat.c b/target-ppc/compat.c
index 1059555..0b12b58 100644
--- a/target-ppc/compat.c
+++ b/target-ppc/compat.c
@@ -124,6 +124,8 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
         pcr = compat->pcr;
     }
 
+    cpu_synchronize_state(CPU(cpu));
+
     cpu->compat_pvr = compat_pvr;
     env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
 
@@ -136,6 +138,40 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
     }
 }
 
+#if !defined(CONFIG_USER_ONLY)
+typedef struct {
+    uint32_t compat_pvr;
+    Error *err;
+} SetCompatState;
+
+static void do_set_compat(CPUState *cs, void *arg)
+{
+    PowerPCCPU *cpu = POWERPC_CPU(cs);
+    SetCompatState *s = arg;
+
+    ppc_set_compat(cpu, s->compat_pvr, &s->err);
+}
+
+void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
+{
+    CPUState *cs;
+
+    CPU_FOREACH(cs) {
+        SetCompatState s = {
+            .compat_pvr = compat_pvr,
+            .err = NULL,
+        };
+
+        run_on_cpu(cs, do_set_compat, &s);
+
+        if (s.err) {
+            error_propagate(errp, s.err);
+            return;
+        }
+    }
+}
+#endif
+
 int ppc_compat_max_threads(PowerPCCPU *cpu)
 {
     const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 91e8be8..201a655 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1317,6 +1317,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
 bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
                       uint32_t min_compat_pvr, uint32_t max_compat_pvr);
 void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
+#if !defined(CONFIG_USER_ONLY)
+void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
+#endif
 int ppc_compat_max_threads(PowerPCCPU *cpu);
 #endif /* defined(TARGET_PPC64) */
 
-- 
2.7.4

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

* [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (10 preceding siblings ...)
  2016-10-30 11:12 ` [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all() David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-11-04  5:58   ` Alexey Kardashevskiy
  2016-10-30 11:12 ` [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine David Gibson
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

Server-class POWER CPUs can be put into several compatibility modes.  These
can be specified on the command line, or negotiated by the guest during
boot.

Currently we don't migrate the compatibility mode, which means after a
migration the guest will revert to running with whatever compatibility
mode (or none) specified on the command line.

With the limited range of CPUs currently used, this doesn't usually cause
a problem, but it could.  Fix this by adding the compatibility mode (if
set) to the migration stream.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/machine.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 4820f22..5d87ff6 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -9,6 +9,7 @@
 #include "mmu-hash64.h"
 #include "migration/cpu.h"
 #include "exec/exec-all.h"
+#include "qapi/error.h"
 
 static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
 {
@@ -176,6 +177,20 @@ static int cpu_post_load(void *opaque, int version_id)
      * software has to take care of running QEMU in a compatible mode.
      */
     env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
+
+#if defined(TARGET_PPC64)
+    if (cpu->compat_pvr) {
+        Error *local_err = NULL;
+
+        ppc_set_compat(cpu, cpu->compat_pvr, &local_err);
+        if (local_err) {
+            error_report_err(local_err);
+            error_free(local_err);
+            return -1;
+        }
+    }
+#endif
+
     env->lr = env->spr[SPR_LR];
     env->ctr = env->spr[SPR_CTR];
     cpu_write_xer(env, env->spr[SPR_XER]);
@@ -528,6 +543,24 @@ static const VMStateDescription vmstate_tlbmas = {
     }
 };
 
+static bool compat_needed(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+
+    return cpu->compat_pvr != 0;
+}
+
+static const VMStateDescription vmstate_compat = {
+    .name = "cpu/compat",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = compat_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(compat_pvr, PowerPCCPU),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_ppc_cpu = {
     .name = "cpu",
     .version_id = 5,
@@ -580,6 +613,7 @@ const VMStateDescription vmstate_ppc_cpu = {
         &vmstate_tlb6xx,
         &vmstate_tlbemb,
         &vmstate_tlbmas,
+        &vmstate_compat,
         NULL
     }
 };
-- 
2.7.4

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

* [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (11 preceding siblings ...)
  2016-10-30 11:12 ` [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-11-04  7:43   ` Alexey Kardashevskiy
  2016-10-30 11:12 ` [Qemu-devel] [RFC 14/17] pseries: Reset CPU compatibility mode David Gibson
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

Server class POWER CPUs have a "compat" property, which is used to set the
backwards compatibility mode for the processor.  However, this only makes
sense for machine types which don't give the guest access to hypervisor
privilege - otherwise the compatibility level is under the guest's control.

To reflect this, this removes the CPU 'compat' property and instead
creates a 'max-cpu-compat' property on the pseries machine.  Strictly
speaking this breaks compatibility, but AFAIK the 'compat' option was
never (directly) used with -device or device_add.

The option was used with -cpu.  So, to maintain compatibility, this patch
adds a hack to the cpu option parsing to strip out any compat options
supplied with -cpu and set them on the machine property instead of the new
removed cpu property.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c              |  6 +++-
 hw/ppc/spapr_cpu_core.c     | 47 +++++++++++++++++++++++++++--
 hw/ppc/spapr_hcall.c        |  2 +-
 include/hw/ppc/spapr.h      | 10 +++++--
 target-ppc/compat.c         | 65 ++++++++++++++++++++++++++++++++++++++++
 target-ppc/cpu.h            |  6 ++--
 target-ppc/translate_init.c | 73 ---------------------------------------------
 7 files changed, 127 insertions(+), 82 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 6c78889..b983faa 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1849,7 +1849,7 @@ static void ppc_spapr_init(MachineState *machine)
         machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu;
     }
 
-    ppc_cpu_parse_features(machine->cpu_model);
+    spapr_cpu_parse_features(spapr);
 
     spapr_init_cpus(spapr);
 
@@ -2191,6 +2191,10 @@ static void spapr_machine_initfn(Object *obj)
                                     " place of standard EPOW events when possible"
                                     " (required for memory hot-unplug support)",
                                     NULL);
+
+    object_property_add(obj, "max-cpu-compat", "str",
+                        ppc_compat_prop_get, ppc_compat_prop_set,
+                        NULL, &spapr->max_compat_pvr, &error_fatal);
 }
 
 static void spapr_machine_finalizefn(Object *obj)
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index ee5cd14..0319516 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -18,6 +18,49 @@
 #include "target-ppc/mmu-hash64.h"
 #include "sysemu/numa.h"
 
+void spapr_cpu_parse_features(sPAPRMachineState *spapr)
+{
+    /*
+     * Backwards compatibility hack:
+
+     *   CPUs had a "compat=" property which didn't make sense for
+     *   anything except pseries.  It was replaced by "max-cpu-compat"
+     *   machine option.  This supports old command lines like
+     *       -cpu POWER8,compat=power7
+     *   By stripping the compat option and applying it to the machine
+     *   before passing it on to the cpu level parser.
+     */
+    gchar **inpieces, **outpieces;
+    int n, i, j;
+    gchar *compat_str = NULL;
+    gchar *filtered_model;
+
+    inpieces = g_strsplit(MACHINE(spapr)->cpu_model, ",", 0);
+    n = g_strv_length(inpieces);
+    outpieces = g_new0(gchar *, g_strv_length(inpieces));
+
+    /* inpieces[0] is the actual model string */
+    for (i = 0, j = 0; i < n; i++) {
+        if (g_str_has_prefix(inpieces[i], "compat=")) {
+            compat_str = inpieces[i];
+        } else {
+            outpieces[j++] = g_strdup(inpieces[i]);
+        }
+    }
+
+    if (compat_str) {
+        char *val = compat_str + strlen("compat=");
+        object_property_set_str(OBJECT(spapr), val, "max-cpu-compat",
+                                &error_fatal);
+    }
+
+    filtered_model = g_strjoinv(",", outpieces);
+    ppc_cpu_parse_features(filtered_model);
+
+    g_strfreev(inpieces);
+    g_strfreev(outpieces);
+}
+
 static void spapr_cpu_reset(void *opaque)
 {
     sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
@@ -60,10 +103,10 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
     cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
     cpu_ppc_set_papr(cpu);
 
-    if (cpu->max_compat) {
+    if (spapr->max_compat_pvr) {
         Error *local_err = NULL;
 
-        ppc_set_compat(cpu, cpu->max_compat, &local_err);
+        ppc_set_compat(cpu, spapr->max_compat_pvr, &local_err);
         if (local_err) {
             error_propagate(errp, local_err);
             return;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 4eaf9a6..5efa57f 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -889,7 +889,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
     target_ulong list = ppc64_phys_to_real(args[0]);
     target_ulong ov_table;
     bool explicit_match = false; /* Matched the CPU's real PVR */
-    uint32_t max_compat = cpu->max_compat;
+    uint32_t max_compat = spapr->max_compat_pvr;
     uint32_t best_compat = 0;
     int i;
     sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 04d2821..d2a40e9 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -74,15 +74,18 @@ struct sPAPRMachineState {
     uint64_t rtc_offset; /* Now used only during incoming migration */
     struct PPCTimebase tb;
     bool has_graphics;
-    sPAPROptionVector *ov5;         /* QEMU-supported option vectors */
-    sPAPROptionVector *ov5_cas;     /* negotiated (via CAS) option vectors */
-    bool cas_reboot;
 
     Notifier epow_notifier;
     QTAILQ_HEAD(, sPAPREventLogEntry) pending_events;
     bool use_hotplug_event_source;
     sPAPREventSource *event_sources;
 
+    /* ibm,client-architecture-support option negotiation */
+    bool cas_reboot;
+    sPAPROptionVector *ov5;         /* QEMU-supported option vectors */
+    sPAPROptionVector *ov5_cas;     /* negotiated (via CAS) option vectors */
+    uint32_t max_compat_pvr;
+
     /* Migration state */
     int htab_save_index;
     bool htab_first_pass;
@@ -613,6 +616,7 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
                                             uint32_t count, uint32_t index);
 void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
                                                uint32_t count, uint32_t index);
+void spapr_cpu_parse_features(sPAPRMachineState *spapr);
 void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
                                     sPAPRMachineState *spapr);
 
diff --git a/target-ppc/compat.c b/target-ppc/compat.c
index 0b12b58..c3ae52d 100644
--- a/target-ppc/compat.c
+++ b/target-ppc/compat.c
@@ -23,9 +23,11 @@
 #include "sysemu/cpus.h"
 #include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "qapi/visitor.h"
 #include "cpu-models.h"
 
 typedef struct {
+    const char *name;
     uint32_t pvr;
     uint64_t pcr;
     uint64_t pcr_level;
@@ -37,6 +39,7 @@ static const CompatInfo compat_table[] = {
      * Ordered from oldest to newest - the code relies on this
      */
     { /* POWER6, ISA2.05 */
+        .name = "power6",
         .pvr = CPU_POWERPC_LOGICAL_2_05,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
                | PCR_TM_DIS | PCR_VSX_DIS,
@@ -44,18 +47,21 @@ static const CompatInfo compat_table[] = {
         .max_threads = 2,
     },
     { /* POWER7, ISA2.06 */
+        .name = "power7",
         .pvr = CPU_POWERPC_LOGICAL_2_06,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
         .pcr_level = PCR_COMPAT_2_06,
         .max_threads = 4,
     },
     {
+        .name = "power7+",
         .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
         .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
         .pcr_level = PCR_COMPAT_2_06,
         .max_threads = 4,
     },
     { /* POWER8, ISA2.07 */
+        .name = "power8",
         .pvr = CPU_POWERPC_LOGICAL_2_07,
         .pcr = PCR_COMPAT_2_07,
         .pcr_level = PCR_COMPAT_2_07,
@@ -184,3 +190,62 @@ int ppc_compat_max_threads(PowerPCCPU *cpu)
 
     return n_threads;
 }
+
+void ppc_compat_prop_get(Object *obj, Visitor *v, const char *name,
+                         void *opaque, Error **errp)
+{
+    uint32_t compat_pvr = *((uint32_t *)opaque);
+    const char *value;
+
+    if (!compat_pvr) {
+        value = "";
+    } else {
+        const CompatInfo *compat = compat_by_pvr(compat_pvr);
+
+        g_assert(compat);
+
+        value = compat->name;
+    }
+
+    visit_type_str(v, name, (char **)&value, errp);
+}
+
+void ppc_compat_prop_set(Object *obj, Visitor *v, const char *name,
+                         void *opaque, Error **errp)
+{
+    Error *error = NULL;
+    char *value;
+    uint32_t compat_pvr;
+
+    visit_type_str(v, name, &value, &error);
+    if (error) {
+        error_propagate(errp, error);
+        return;
+    }
+
+    if (strcmp(value, "") == 0) {
+        compat_pvr = 0;
+    } else {
+        int i;
+        const CompatInfo *compat = NULL;
+
+        for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
+            if (strcmp(value, compat_table[i].name) == 0) {
+                compat = &compat_table[i];
+                break;
+
+            }
+        }
+
+        if (!compat) {
+            error_setg(errp, "Invalid compatibility mode \"%s\"", value);
+            goto out;
+        }
+        compat_pvr = compat->pvr;
+    }
+
+    *((uint32_t *)opaque) = compat_pvr;
+
+out:
+    g_free(value);
+}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 201a655..51d21bb 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1155,7 +1155,6 @@ typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
  * PowerPCCPU:
  * @env: #CPUPPCState
  * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
- * @max_compat: Maximal supported logical PVR from the command line
  * @compat_pvr: Current logical PVR, zero if in "raw" mode
  *
  * A PowerPC CPU.
@@ -1167,7 +1166,6 @@ struct PowerPCCPU {
 
     CPUPPCState env;
     int cpu_dt_id;
-    uint32_t max_compat;
     uint32_t compat_pvr;
     PPCVirtualHypervisor *vhyp;
 };
@@ -1321,6 +1319,10 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
 void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
 #endif
 int ppc_compat_max_threads(PowerPCCPU *cpu);
+void ppc_compat_prop_get(Object *obj, Visitor *v,
+                         const char *name, void *opaque, Error **err);
+void ppc_compat_prop_set(Object *obj, Visitor *v,
+                         const char *name, void *opaque, Error **err);
 #endif /* defined(TARGET_PPC64) */
 
 #include "exec/cpu-all.h"
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index ba48242..40abd23 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8428,76 +8428,6 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
     pcc->l1_icache_size = 0x10000;
 }
 
-static void powerpc_get_compat(Object *obj, Visitor *v, const char *name,
-                               void *opaque, Error **errp)
-{
-    char *value = (char *)"";
-    Property *prop = opaque;
-    uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
-
-    switch (*max_compat) {
-    case CPU_POWERPC_LOGICAL_2_05:
-        value = (char *)"power6";
-        break;
-    case CPU_POWERPC_LOGICAL_2_06:
-        value = (char *)"power7";
-        break;
-    case CPU_POWERPC_LOGICAL_2_07:
-        value = (char *)"power8";
-        break;
-    case 0:
-        break;
-    default:
-        error_report("Internal error: compat is set to %x", *max_compat);
-        abort();
-        break;
-    }
-
-    visit_type_str(v, name, &value, errp);
-}
-
-static void powerpc_set_compat(Object *obj, Visitor *v, const char *name,
-                               void *opaque, Error **errp)
-{
-    Error *error = NULL;
-    char *value = NULL;
-    Property *prop = opaque;
-    uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
-
-    visit_type_str(v, name, &value, &error);
-    if (error) {
-        error_propagate(errp, error);
-        return;
-    }
-
-    if (strcmp(value, "power6") == 0) {
-        *max_compat = CPU_POWERPC_LOGICAL_2_05;
-    } else if (strcmp(value, "power7") == 0) {
-        *max_compat = CPU_POWERPC_LOGICAL_2_06;
-    } else if (strcmp(value, "power8") == 0) {
-        *max_compat = CPU_POWERPC_LOGICAL_2_07;
-    } else {
-        error_setg(errp, "Invalid compatibility mode \"%s\"", value);
-    }
-
-    g_free(value);
-}
-
-static PropertyInfo powerpc_compat_propinfo = {
-    .name = "str",
-    .description = "compatibility mode, power6/power7/power8",
-    .get = powerpc_get_compat,
-    .set = powerpc_set_compat,
-};
-
-#define DEFINE_PROP_POWERPC_COMPAT(_n, _s, _f) \
-    DEFINE_PROP(_n, _s, _f, powerpc_compat_propinfo, uint32_t)
-
-static Property powerpc_servercpu_properties[] = {
-    DEFINE_PROP_POWERPC_COMPAT("compat", PowerPCCPU, max_compat),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
 #ifdef CONFIG_SOFTMMU
 static const struct ppc_segment_page_sizes POWER7_POWER8_sps = {
     .sps = {
@@ -8586,7 +8516,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 
     dc->fw_name = "PowerPC,POWER7";
     dc->desc = "POWER7";
-    dc->props = powerpc_servercpu_properties;
     pcc->pvr_match = ppc_pvr_match_power7;
     pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
     pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -8713,7 +8642,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 
     dc->fw_name = "PowerPC,POWER8";
     dc->desc = "POWER8";
-    dc->props = powerpc_servercpu_properties;
     pcc->pvr_match = ppc_pvr_match_power8;
     pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
     pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
@@ -8794,7 +8722,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
 
     dc->fw_name = "PowerPC,POWER9";
     dc->desc = "POWER9";
-    dc->props = powerpc_servercpu_properties;
     pcc->pvr_match = ppc_pvr_match_power9;
     pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
     pcc->init_proc = init_proc_POWER9;
-- 
2.7.4

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

* [Qemu-devel] [RFC 14/17] pseries: Reset CPU compatibility mode
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (12 preceding siblings ...)
  2016-10-30 11:12 ` [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-11-04  7:50   ` Alexey Kardashevskiy
  2016-10-30 11:12 ` [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration David Gibson
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

Currently, the CPU compatibility mode is set when the cpu is initialized,
then again when the guest negotiates features.  This means if a guest
negotiates a compatibility mode, then reboots, that compatibility mode
will be retained across the reset.

Usually that will get overridden when features are negotiated on the next
boot, but it's still not really correct.  This patch moves the initial set
up of the compatibility mode from cpu init to reset time.  The mode *is*
retained if the reboot was caused by the feature negotiation (it might
be important in that case, though it's unlikely).

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c          |  2 ++
 hw/ppc/spapr_cpu_core.c | 10 ----------
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index b983faa..2aa0900 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1169,6 +1169,8 @@ static void ppc_spapr_reset(void)
     if (!spapr->cas_reboot) {
         spapr_ovec_cleanup(spapr->ov5_cas);
         spapr->ov5_cas = spapr_ovec_new();
+
+        ppc_set_compat_all(spapr->max_compat_pvr, &error_abort);
     }
 
     fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size);
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 0319516..4b6134b 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -103,16 +103,6 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
     cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
     cpu_ppc_set_papr(cpu);
 
-    if (spapr->max_compat_pvr) {
-        Error *local_err = NULL;
-
-        ppc_set_compat(cpu, spapr->max_compat_pvr, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
-            return;
-        }
-    }
-
     /* Set NUMA node for the added CPUs  */
     i = numa_get_node_for_cpu(cs->cpu_index);
     if (i < nb_numa_nodes) {
-- 
2.7.4

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

* [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (13 preceding siblings ...)
  2016-10-30 11:12 ` [Qemu-devel] [RFC 14/17] pseries: Reset CPU compatibility mode David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-11-04  7:54   ` Alexey Kardashevskiy
  2016-10-30 11:12 ` [Qemu-devel] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration David Gibson
  2016-10-30 11:12 ` [Qemu-devel] [RFC 17/17] pseries: Default to POWER8 compatibility mode David Gibson
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

When a vmstate for the ppc cpu was first introduced (a90db15 "target-ppc:
Convert ppc cpu savevm to VMStateDescription"), a VMSTATE_EQUAL was used
to ensure that identical CPU models were used at source and destination
as based on the PVR (Processor Version Register).

However this was a problem for HV KVM, where due to hardware limitations
we always need to use the real PVR of the host CPU.  So, to allow
migration between hosts with "similar enough" CPUs, the PVR check was
removed in 569be9f0 "target-ppc: Remove PVR check from migration".  This
left the onus on user / management to only attempt migration between
compatible CPUs.

Now that we've reworked the handling of compatiblity modes, we have the
information to actually determine if we're making a compatible migration.
So this patch partially restores the PVR check.  If the source was running
in a compatibility mode, we just make sure that the destination cpu can
also run in that compatibility mode.  However, if the source was running
in "raw" mode, we verify that the destination has the same PVR value.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/machine.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 5d87ff6..62b9e94 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -173,10 +173,12 @@ static int cpu_post_load(void *opaque, int version_id)
     target_ulong msr;
 
     /*
-     * We always ignore the source PVR. The user or management
-     * software has to take care of running QEMU in a compatible mode.
+     * If we're operating in compat mode, we should be ok as long as
+     * the destination supports the same compatiblity mode.
+     *
+     * Otherwise, however, we require that the destination has exactly
+     * the same CPU model as the source.
      */
-    env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
 
 #if defined(TARGET_PPC64)
     if (cpu->compat_pvr) {
@@ -188,8 +190,13 @@ static int cpu_post_load(void *opaque, int version_id)
             error_free(local_err);
             return -1;
         }
-    }
+    } else
 #endif
+    {
+        if (env->spr[SPR_PVR] != env->spr_cb[SPR_PVR].default_value) {
+            return -1;
+        }
+    }
 
     env->lr = env->spr[SPR_LR];
     env->ctr = env->spr[SPR_CTR];
-- 
2.7.4

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

* [Qemu-devel] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (14 preceding siblings ...)
  2016-10-30 11:12 ` [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-11-04  5:52   ` Alexey Kardashevskiy
  2016-10-30 11:12 ` [Qemu-devel] [RFC 17/17] pseries: Default to POWER8 compatibility mode David Gibson
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

When vmstate for the ppc cpu was introduced in a90db158 "target-ppc:
Convert ppc cpu savevm to VMStateDescription", several "sanity check"
fields were included, verifying that certain cpu parameters matched between
source and destination.

This turns out not to have been a good idea.  For one thing it's redundant
with existing checks for a compatible cpu version at either end.  But more
importantly the insns_flags and insns_flags2 checks actively break things:
they expose what's essentially an internal TCG implementation detail in the
migration stream.  That means that when new instruction classes are added
or rearranged, migration can break.

This removes these ill-considered sanity checks.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target-ppc/machine.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 62b9e94..453ef0a 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -602,10 +602,10 @@ const VMStateDescription vmstate_ppc_cpu = {
         /* FIXME: access_type? */
 
         /* Sanity checking */
-        VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU),
-        VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU),
-        VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU),
-        VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU),
+        VMSTATE_UNUSED(sizeof(target_ulong) /* msr_mask */
+                       + sizeof(uint64_t) /* insns_flags */
+                       + sizeof(uint64_t) /* insns_flags2 */
+                       + sizeof(uint32_t)), /* nb_BATs */
         VMSTATE_END_OF_LIST()
     },
     .subsections = (const VMStateDescription*[]) {
-- 
2.7.4

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

* [Qemu-devel] [RFC 17/17] pseries: Default to POWER8 compatibility mode
  2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
                   ` (15 preceding siblings ...)
  2016-10-30 11:12 ` [Qemu-devel] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration David Gibson
@ 2016-10-30 11:12 ` David Gibson
  2016-10-30 11:58   ` David Gibson
  16 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:12 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, David Gibson

Currently, the pseries machine defaults to running in the "raw" mode of
whatever the CPU version is - that is, without any compatibility options
enabled in the CPU.

However, migration is only really safe in "raw" mode if source and
destination have exactly the same cpu model.  Since HV KVM exposes the
version of the host CPU to the guest, that means "raw" migration between
hosts with different minor revisions isn't strictly safe, although it
generally works in practice.

To allow this sort of migration in a more clearly defined way, instead
default to running in POWER8 compatibility mode - if an older CPU is used
that will automatically be downgraded to the higest available compatibility
mode.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 2aa0900..8c18dc8 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2194,6 +2194,7 @@ static void spapr_machine_initfn(Object *obj)
                                     " (required for memory hot-unplug support)",
                                     NULL);
 
+    spapr->max_compat_pvr = CPU_POWERPC_LOGICAL_2_07; /* POWER8 */
     object_property_add(obj, "max-cpu-compat", "str",
                         ppc_compat_prop_get, ppc_compat_prop_set,
                         NULL, &spapr->max_compat_pvr, &error_fatal);
-- 
2.7.4

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

* Re: [Qemu-devel] [RFC 17/17] pseries: Default to POWER8 compatibility mode
  2016-10-30 11:12 ` [Qemu-devel] [RFC 17/17] pseries: Default to POWER8 compatibility mode David Gibson
@ 2016-10-30 11:58   ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-10-30 11:58 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

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

On Sun, Oct 30, 2016 at 10:12:08PM +1100, David Gibson wrote:
> Currently, the pseries machine defaults to running in the "raw" mode of
> whatever the CPU version is - that is, without any compatibility options
> enabled in the CPU.
> 
> However, migration is only really safe in "raw" mode if source and
> destination have exactly the same cpu model.  Since HV KVM exposes the
> version of the host CPU to the guest, that means "raw" migration between
> hosts with different minor revisions isn't strictly safe, although it
> generally works in practice.
> 
> To allow this sort of migration in a more clearly defined way, instead
> default to running in POWER8 compatibility mode - if an older CPU is used
> that will automatically be downgraded to the higest available compatibility
> mode.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Ugh, sorry.  When I said minimally tested I did mean that it passed
make check, but unfortunately I was sloppy and this last patch breaks
a bunch of stuff.

> ---
>  hw/ppc/spapr.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index 2aa0900..8c18dc8 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -2194,6 +2194,7 @@ static void spapr_machine_initfn(Object *obj)
>                                      " (required for memory hot-unplug support)",
>                                      NULL);
>  
> +    spapr->max_compat_pvr = CPU_POWERPC_LOGICAL_2_07; /* POWER8 */
>      object_property_add(obj, "max-cpu-compat", "str",
>                          ppc_compat_prop_get, ppc_compat_prop_set,
>                          NULL, &spapr->max_compat_pvr, &error_fatal);

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic
  2016-10-30 11:12 ` [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic David Gibson
@ 2016-10-31  5:00   ` Alexey Kardashevskiy
  2016-10-31  5:44     ` David Gibson
  2016-11-10 17:54   ` Michael Roth
  1 sibling, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-10-31  5:00 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:12, David Gibson wrote:
> During boot, PAPR guests negotiate CPU model support with the
> ibm,client-architecture-support mechanism.  The logic to implement this in
> qemu is very convoluted.  This cleans it up to be cleaner, using the new
> ppc_check_compat() call.
> 
> The new logic for choosing a compatibility mode is:
>     1. If the guest lists the CPU's real PVR as supported *AND* no
>        maximum compatibility mode has been requested on the command line
>        then we use "raw" mode - the CPU acts with full capabilities.
>     2. Otherwise, we pick the most recent compatibility mode which is
>        both supported by the CPU, and is advertised as supported by the
>        guest.
> I think the original code approximated the same thing, but it's hard to be
> sure, and I think it had some weird edge cases.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr_hcall.c | 107 +++++++++++++++++----------------------------------
>  hw/ppc/trace-events  |   2 +-
>  2 files changed, 37 insertions(+), 72 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index d93f580..3bd6d06 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -895,98 +895,63 @@ static void do_set_compat(CPUState *cs, void *arg)
>      ppc_set_compat(cpu, s->compat_pvr, &s->err);
>  }
>  
> -#define get_compat_level(cpuver) ( \
> -    ((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \
> -    ((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \
> -    ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
> -    ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
> -
> -static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
> -                                  unsigned max_lvl, unsigned *compat_lvl,
> -                                  unsigned *compat_pvr)
> -{
> -    unsigned lvl = get_compat_level(pvr);
> -    bool is205, is206, is207;
> -
> -    if (!lvl) {
> -        return;
> -    }
> -
> -    /* If it is a logical PVR, try to determine the highest level */
> -    is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) &&
> -            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
> -    is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) &&
> -            ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
> -             (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
> -    is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) &&
> -            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07));
> -
> -    if (is205 || is206 || is207) {
> -        if (!max_lvl) {
> -            /* User did not set the level, choose the highest */
> -            if (*compat_lvl <= lvl) {
> -                *compat_lvl = lvl;
> -                *compat_pvr = pvr;
> -            }
> -        } else if (max_lvl >= lvl) {
> -            /* User chose the level, don't set higher than this */
> -            *compat_lvl = lvl;
> -            *compat_pvr = pvr;
> -        }
> -    }
> -}
> -
> -static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
> +static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>                                                    sPAPRMachineState *spapr,
>                                                    target_ulong opcode,
>                                                    target_ulong *args)
>  {
>      target_ulong list = ppc64_phys_to_real(args[0]);
>      target_ulong ov_table;
> -    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
>      CPUState *cs;
> -    bool cpu_match = false;
> -    unsigned old_compat_pvr = cpu_->compat_pvr;
> -    unsigned compat_lvl = 0, compat_pvr = 0;
> -    unsigned max_lvl = get_compat_level(cpu_->max_compat);
> -    int counter;
> +    bool explicit_match = false; /* Matched the CPU's real PVR */
> +    uint32_t max_compat = cpu->max_compat;
> +    uint32_t best_compat = 0;
> +    int i;
>      sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
>  
> -    /* Parse PVR list */
> -    for (counter = 0; counter < 512; ++counter) {
> +    /*
> +     * We scan the supplied table of PVRs looking for two things
> +     *   1. Is our real CPU PVR in the list?
> +     *   2. What's the "best" listed logical PVR
> +     */
> +    for (i = 0; i < 512; ++i) {
>          uint32_t pvr, pvr_mask;
>  
> -        pvr_mask = ldl_be_phys(&address_space_memory, list);
> -        list += 4;
>          pvr = ldl_be_phys(&address_space_memory, list);


LoPAPR: List-entry = 4-byte-mask : 4-byte-PVR-value

This patch changes the order and "cas" fails.


> -        list += 4;
> -
> -        trace_spapr_cas_pvr_try(pvr);
> -        if (!max_lvl &&
> -            ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
> -            cpu_match = true;
> -            compat_pvr = 0;
> -        } else if (pvr == cpu_->compat_pvr) {
> -            cpu_match = true;
> -            compat_pvr = cpu_->compat_pvr;
> -        } else if (!cpu_match) {
> -            cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &compat_pvr);
> -        }
> -        /* Terminator record */
> +        pvr_mask = ldl_be_phys(&address_space_memory, list + 4);
> +        list += 8;
> +
>          if (~pvr_mask & pvr) {
> -            break;
> +            break; /* Terminator record */
>          }
> +
> +        if ((cpu->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask)) {
> +            explicit_match = true;
> +        } else {
> +            if (ppc_check_compat(cpu, pvr, best_compat, max_compat)) {
> +                best_compat = pvr;
> +            }
> +        }
> +    }
> +
> +    if (!max_compat && explicit_match) {
> +        /* If the guest explicitly supports the CPU, *and* user hasn't
> +         * requested a compatibility mode, use "raw" mode */
> +        best_compat = 0;
> +    } else if (best_compat == 0) {
> +        /* Didn't find any supported compat modes */
> +        /* FIXME: what's the right error here? */
> +        return H_HARDWARE;
>      }
>  
>      /* Parsing finished */
> -    trace_spapr_cas_pvr(cpu_->compat_pvr, cpu_match,
> -                        compat_pvr, pcc->pcr_mask);
> +    trace_spapr_cas_pvr(cpu->compat_pvr, explicit_match, best_compat);
>  
>      /* Update CPUs */
> -    if (old_compat_pvr != compat_pvr) {
> +    if (cpu->compat_pvr != best_compat) {
>          CPU_FOREACH(cs) {
>              SetCompatState s = {
> -                .compat_pvr = compat_pvr,
> +                .compat_pvr = best_compat,
>                  .err = NULL,
>              };
>  
> diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
> index 2297ead..604ac92 100644
> --- a/hw/ppc/trace-events
> +++ b/hw/ppc/trace-events
> @@ -15,7 +15,7 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
>  
>  # hw/ppc/spapr_hcall.c
>  spapr_cas_pvr_try(uint32_t pvr) "%x"
> -spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64
> +spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=%x, explicit_match=%u, new=%x"
>  
>  # hw/ppc/spapr_iommu.c
>  spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic
  2016-10-31  5:00   ` Alexey Kardashevskiy
@ 2016-10-31  5:44     ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-10-31  5:44 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Mon, Oct 31, 2016 at 04:00:14PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:12, David Gibson wrote:
> > During boot, PAPR guests negotiate CPU model support with the
> > ibm,client-architecture-support mechanism.  The logic to implement this in
> > qemu is very convoluted.  This cleans it up to be cleaner, using the new
> > ppc_check_compat() call.
> > 
> > The new logic for choosing a compatibility mode is:
> >     1. If the guest lists the CPU's real PVR as supported *AND* no
> >        maximum compatibility mode has been requested on the command line
> >        then we use "raw" mode - the CPU acts with full capabilities.
> >     2. Otherwise, we pick the most recent compatibility mode which is
> >        both supported by the CPU, and is advertised as supported by the
> >        guest.
> > I think the original code approximated the same thing, but it's hard to be
> > sure, and I think it had some weird edge cases.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr_hcall.c | 107 +++++++++++++++++----------------------------------
> >  hw/ppc/trace-events  |   2 +-
> >  2 files changed, 37 insertions(+), 72 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index d93f580..3bd6d06 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -895,98 +895,63 @@ static void do_set_compat(CPUState *cs, void *arg)
> >      ppc_set_compat(cpu, s->compat_pvr, &s->err);
> >  }
> >  
> > -#define get_compat_level(cpuver) ( \
> > -    ((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \
> > -    ((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \
> > -    ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
> > -    ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
> > -
> > -static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
> > -                                  unsigned max_lvl, unsigned *compat_lvl,
> > -                                  unsigned *compat_pvr)
> > -{
> > -    unsigned lvl = get_compat_level(pvr);
> > -    bool is205, is206, is207;
> > -
> > -    if (!lvl) {
> > -        return;
> > -    }
> > -
> > -    /* If it is a logical PVR, try to determine the highest level */
> > -    is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) &&
> > -            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
> > -    is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) &&
> > -            ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
> > -             (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
> > -    is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) &&
> > -            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07));
> > -
> > -    if (is205 || is206 || is207) {
> > -        if (!max_lvl) {
> > -            /* User did not set the level, choose the highest */
> > -            if (*compat_lvl <= lvl) {
> > -                *compat_lvl = lvl;
> > -                *compat_pvr = pvr;
> > -            }
> > -        } else if (max_lvl >= lvl) {
> > -            /* User chose the level, don't set higher than this */
> > -            *compat_lvl = lvl;
> > -            *compat_pvr = pvr;
> > -        }
> > -    }
> > -}
> > -
> > -static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
> > +static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >                                                    sPAPRMachineState *spapr,
> >                                                    target_ulong opcode,
> >                                                    target_ulong *args)
> >  {
> >      target_ulong list = ppc64_phys_to_real(args[0]);
> >      target_ulong ov_table;
> > -    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
> >      CPUState *cs;
> > -    bool cpu_match = false;
> > -    unsigned old_compat_pvr = cpu_->compat_pvr;
> > -    unsigned compat_lvl = 0, compat_pvr = 0;
> > -    unsigned max_lvl = get_compat_level(cpu_->max_compat);
> > -    int counter;
> > +    bool explicit_match = false; /* Matched the CPU's real PVR */
> > +    uint32_t max_compat = cpu->max_compat;
> > +    uint32_t best_compat = 0;
> > +    int i;
> >      sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
> >  
> > -    /* Parse PVR list */
> > -    for (counter = 0; counter < 512; ++counter) {
> > +    /*
> > +     * We scan the supplied table of PVRs looking for two things
> > +     *   1. Is our real CPU PVR in the list?
> > +     *   2. What's the "best" listed logical PVR
> > +     */
> > +    for (i = 0; i < 512; ++i) {
> >          uint32_t pvr, pvr_mask;
> >  
> > -        pvr_mask = ldl_be_phys(&address_space_memory, list);
> > -        list += 4;
> >          pvr = ldl_be_phys(&address_space_memory, list);
> 
> 
> LoPAPR: List-entry = 4-byte-mask : 4-byte-PVR-value
> 
> This patch changes the order and "cas" fails.

Oops, yes, thanks for the catch.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting
  2016-10-30 11:12 ` [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting David Gibson
@ 2016-10-31  5:55   ` Alexey Kardashevskiy
  2016-10-31  8:39     ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-10-31  5:55 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:12, David Gibson wrote:
> Current ppc_set_compat() will attempt to set any compatiblity mode
> specified, regardless of whether it's available on the CPU.  The caller is
> expected to make sure it is setting a possible mode, which is awkwward
> because most of the information to make that decision is at the CPU level.
> 
> This begins to clean this up by introducing a ppc_check_compat() function
> which will determine if a given compatiblity mode is supported on a CPU
> (and also whether it lies within specified minimum and maximum compat
> levels, which will be useful later).  It also contains an assertion that
> the CPU has a "virtual hypervisor"[1], that is, that the guest isn't
> permitted to execute hypervisor privilege code.  Without that, the guest
> would own the PCR and so could override any mode set here.  Only machine
> types which use a virtual hypervisor (i.e. 'pseries') should use
> ppc_check_compat().
> 
> ppc_set_compat() is modified to validate the compatibility mode it is given
> and fail if it's not available on this CPU.
> 
> [1] Or user-only mode, which also obviously doesn't allow access to the
> hypervisor privileged PCR.  We don't use that now, but could in future.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  target-ppc/compat.c | 41 +++++++++++++++++++++++++++++++++++++++++
>  target-ppc/cpu.h    |  2 ++
>  2 files changed, 43 insertions(+)
> 
> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> index 66529a6..1059555 100644
> --- a/target-ppc/compat.c
> +++ b/target-ppc/compat.c
> @@ -28,29 +28,37 @@
>  typedef struct {
>      uint32_t pvr;
>      uint64_t pcr;
> +    uint64_t pcr_level;
>      int max_threads;
>  } CompatInfo;
>  
>  static const CompatInfo compat_table[] = {
> +    /*
> +     * Ordered from oldest to newest - the code relies on this
> +     */
>      { /* POWER6, ISA2.05 */
>          .pvr = CPU_POWERPC_LOGICAL_2_05,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
>                 | PCR_TM_DIS | PCR_VSX_DIS,
> +        .pcr_level = PCR_COMPAT_2_05,
>          .max_threads = 2,
>      },
>      { /* POWER7, ISA2.06 */
>          .pvr = CPU_POWERPC_LOGICAL_2_06,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> +        .pcr_level = PCR_COMPAT_2_06,
>          .max_threads = 4,
>      },
>      {
>          .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> +        .pcr_level = PCR_COMPAT_2_06,
>          .max_threads = 4,
>      },
>      { /* POWER8, ISA2.07 */
>          .pvr = CPU_POWERPC_LOGICAL_2_07,
>          .pcr = PCR_COMPAT_2_07,
> +        .pcr_level = PCR_COMPAT_2_07,
>          .max_threads = 8,
>      },
>  };
> @@ -67,6 +75,35 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr)
>      return NULL;
>  }
>  
> +bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
> +                      uint32_t min_compat_pvr, uint32_t max_compat_pvr)
> +{
> +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
> +    const CompatInfo *compat = compat_by_pvr(compat_pvr);
> +    const CompatInfo *min = compat_by_pvr(min_compat_pvr);
> +    const CompatInfo *max = compat_by_pvr(max_compat_pvr);


You keep giving very generic names (as "min" and "max") to local variables ;)


> +
> +#if !defined(CONFIG_USER_ONLY)
> +    g_assert(cpu->vhyp);
> +#endif
> +    g_assert(!min_compat_pvr || min);
> +    g_assert(!max_compat_pvr || max);
> +
> +    if (!compat) {
> +        /* Not a recognized logical PVR */
> +        return false;
> +    }
> +    if ((min && (compat < min)) || (max && (compat > max))) {
> +        /* Outside specified range */
> +        return false;
> +    }
> +    if (!(pcc->pcr_supported & compat->pcr_level)) {
> +        /* Not supported by this CPU */
> +        return false;
> +    }
> +    return true;
> +}
> +
>  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>  {
>      const CompatInfo *compat = compat_by_pvr(compat_pvr);
> @@ -79,6 +116,10 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>      } else if (!compat) {
>          error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
>          return;
> +    } else if (!ppc_check_compat(cpu, compat_pvr, 0, 0)) {
> +        error_setg(errp, "Compatibility PVR 0x%08"PRIx32" not valid for CPU",
> +                   compat_pvr);
> +        return;
>      } else {
>          pcr = compat->pcr;
>      }
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index cfda7b2..91e8be8 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -1314,6 +1314,8 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
>  
>  /* Compatibility modes */
>  #if defined(TARGET_PPC64)
> +bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
> +                      uint32_t min_compat_pvr, uint32_t max_compat_pvr);
>  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
>  int ppc_compat_max_threads(PowerPCCPU *cpu);
>  #endif /* defined(TARGET_PPC64) */
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models
  2016-10-30 11:11 ` [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models David Gibson
@ 2016-10-31  7:38   ` Thomas Huth
  2016-10-31  8:37     ` David Gibson
  2016-11-08  3:40   ` David Gibson
  1 sibling, 1 reply; 75+ messages in thread
From: Thomas Huth @ 2016-10-31  7:38 UTC (permalink / raw)
  To: David Gibson, nikunj, aik, mdroth; +Cc: lvivier, qemu-ppc, qemu-devel

On 30.10.2016 12:11, David Gibson wrote:
> The CPU model table includes stub (commented out) definitions for
> CPU_POWERPC_POWER6_5 and CPU_POWERPC_POWER6A.  These are not real cpu
> models, but represent the POWER6 in some compatiblity modes.  If we ever
> do implement POWER6 (unlikely),

I think we should finally add at least basic support for POWER6. It
always confused me (from a user's point of view) that we have support
for POWER5+ and POWER7, but not for POWER6.

> we'll implement its compatibility modes in
> a different way (similar to what we do for POWER7 and POWER8).  So these
> stub definitions can be removed.
[...]
> diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
> index 901cf40..506dee1 100644
> --- a/target-ppc/cpu-models.c
> +++ b/target-ppc/cpu-models.c
> @@ -1130,10 +1130,6 @@
>  #if defined(TODO)
>      POWERPC_DEF("POWER6",        CPU_POWERPC_POWER6,                 POWER6,
>                  "POWER6")
> -    POWERPC_DEF("POWER6_5",      CPU_POWERPC_POWER6_5,               POWER5,
> -                "POWER6 running in POWER5 mode")
> -    POWERPC_DEF("POWER6A",       CPU_POWERPC_POWER6A,                POWER6,
> -                "POWER6A")
>  #endif
>      POWERPC_DEF("POWER7_v2.3",   CPU_POWERPC_POWER7_v23,             POWER7,
>                  "POWER7 v2.3")
> diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
> index 7d9e6a2..aafbbd7 100644
> --- a/target-ppc/cpu-models.h
> +++ b/target-ppc/cpu-models.h
> @@ -549,8 +549,6 @@ enum {
>      CPU_POWERPC_POWER5             = 0x003A0203,
>      CPU_POWERPC_POWER5P_v21        = 0x003B0201,
>      CPU_POWERPC_POWER6             = 0x003E0000,
> -    CPU_POWERPC_POWER6_5           = 0x0F000001, /* POWER6 in POWER5 mode */
> -    CPU_POWERPC_POWER6A            = 0x0F000002,
>      CPU_POWERPC_POWER_SERVER_MASK  = 0xFFFF0000,
>      CPU_POWERPC_POWER7_BASE        = 0x003F0000,
>      CPU_POWERPC_POWER7_v23         = 0x003F0203,


Patch looks good.

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv
  2016-10-30 11:11 ` [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv David Gibson
@ 2016-10-31  7:46   ` Thomas Huth
  2016-10-31  8:38     ` David Gibson
  2016-10-31 10:35   ` Greg Kurz
  1 sibling, 1 reply; 75+ messages in thread
From: Thomas Huth @ 2016-10-31  7:46 UTC (permalink / raw)
  To: David Gibson, nikunj, aik, mdroth; +Cc: lvivier, qemu-ppc, qemu-devel

On 30.10.2016 12:11, David Gibson wrote:
> powernv has some code (derived from the spapr equivalent) used in device
> tree generation which depends on the CPU's compatibility mode / logical
> PVR.  However, compatibility modes don't make sense on powernv - at least
> not as a property controlled by the host - because the guest in powernv
> has full hypervisor level access to the virtual system, and so owns the
> PCR (Processor Compatibility Register) which implements compatiblity modes.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/pnv.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 82276e0..6af3424 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -110,7 +110,7 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
>      CPUState *cs = CPU(DEVICE(pc->threads));
>      DeviceClass *dc = DEVICE_GET_CLASS(cs);
>      PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    int smt_threads = ppc_get_compat_smt_threads(cpu);
> +    int smt_threads = CPU_CORE(pc)->nr_threads;

ppc_get_compat_smt_threads() also checks kvmppc_smt_threads() ... as
long as we do not run the powernv architecture with KVM PR, your change
should be OK, but if we support that one day, we might need to check
kvmppc_smt_threads() here, too?

>      CPUPPCState *env = &cpu->env;
>      PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
>      uint32_t servers_prop[smt_threads];
> @@ -206,10 +206,6 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
>      _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
>                         pa_features, sizeof(pa_features))));
>  
> -    if (cpu->cpu_version) {
> -        _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
> -    }
> -
>      /* Build interrupt servers properties */
>      for (i = 0; i < smt_threads; i++) {
>          servers_prop[i] = cpu_to_be32(pc->pir + i);
> 

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models
  2016-10-31  7:38   ` Thomas Huth
@ 2016-10-31  8:37     ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-10-31  8:37 UTC (permalink / raw)
  To: Thomas Huth; +Cc: nikunj, aik, mdroth, lvivier, qemu-ppc, qemu-devel

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

On Mon, Oct 31, 2016 at 08:38:53AM +0100, Thomas Huth wrote:
> On 30.10.2016 12:11, David Gibson wrote:
> > The CPU model table includes stub (commented out) definitions for
> > CPU_POWERPC_POWER6_5 and CPU_POWERPC_POWER6A.  These are not real cpu
> > models, but represent the POWER6 in some compatiblity modes.  If we ever
> > do implement POWER6 (unlikely),
> 
> I think we should finally add at least basic support for POWER6. It
> always confused me (from a user's point of view) that we have support
> for POWER5+ and POWER7, but not for POWER6.

I think it's just because at the time POWER6 was current, no-one was
working on qemu for Power.  It'd be nice to have, but I don't know
that it's actually worth anyone's time to make happen.

> > we'll implement its compatibility modes in
> > a different way (similar to what we do for POWER7 and POWER8).  So these
> > stub definitions can be removed.
> [...]
> > diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
> > index 901cf40..506dee1 100644
> > --- a/target-ppc/cpu-models.c
> > +++ b/target-ppc/cpu-models.c
> > @@ -1130,10 +1130,6 @@
> >  #if defined(TODO)
> >      POWERPC_DEF("POWER6",        CPU_POWERPC_POWER6,                 POWER6,
> >                  "POWER6")
> > -    POWERPC_DEF("POWER6_5",      CPU_POWERPC_POWER6_5,               POWER5,
> > -                "POWER6 running in POWER5 mode")
> > -    POWERPC_DEF("POWER6A",       CPU_POWERPC_POWER6A,                POWER6,
> > -                "POWER6A")
> >  #endif
> >      POWERPC_DEF("POWER7_v2.3",   CPU_POWERPC_POWER7_v23,             POWER7,
> >                  "POWER7 v2.3")
> > diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
> > index 7d9e6a2..aafbbd7 100644
> > --- a/target-ppc/cpu-models.h
> > +++ b/target-ppc/cpu-models.h
> > @@ -549,8 +549,6 @@ enum {
> >      CPU_POWERPC_POWER5             = 0x003A0203,
> >      CPU_POWERPC_POWER5P_v21        = 0x003B0201,
> >      CPU_POWERPC_POWER6             = 0x003E0000,
> > -    CPU_POWERPC_POWER6_5           = 0x0F000001, /* POWER6 in POWER5 mode */
> > -    CPU_POWERPC_POWER6A            = 0x0F000002,
> >      CPU_POWERPC_POWER_SERVER_MASK  = 0xFFFF0000,
> >      CPU_POWERPC_POWER7_BASE        = 0x003F0000,
> >      CPU_POWERPC_POWER7_v23         = 0x003F0203,
> 
> 
> Patch looks good.
> 
> Reviewed-by: Thomas Huth <thuth@redhat.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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv
  2016-10-31  7:46   ` Thomas Huth
@ 2016-10-31  8:38     ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-10-31  8:38 UTC (permalink / raw)
  To: Thomas Huth; +Cc: nikunj, aik, mdroth, lvivier, qemu-ppc, qemu-devel

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

On Mon, Oct 31, 2016 at 08:46:55AM +0100, Thomas Huth wrote:
> On 30.10.2016 12:11, David Gibson wrote:
> > powernv has some code (derived from the spapr equivalent) used in device
> > tree generation which depends on the CPU's compatibility mode / logical
> > PVR.  However, compatibility modes don't make sense on powernv - at least
> > not as a property controlled by the host - because the guest in powernv
> > has full hypervisor level access to the virtual system, and so owns the
> > PCR (Processor Compatibility Register) which implements compatiblity modes.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/pnv.c | 6 +-----
> >  1 file changed, 1 insertion(+), 5 deletions(-)
> > 
> > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> > index 82276e0..6af3424 100644
> > --- a/hw/ppc/pnv.c
> > +++ b/hw/ppc/pnv.c
> > @@ -110,7 +110,7 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
> >      CPUState *cs = CPU(DEVICE(pc->threads));
> >      DeviceClass *dc = DEVICE_GET_CLASS(cs);
> >      PowerPCCPU *cpu = POWERPC_CPU(cs);
> > -    int smt_threads = ppc_get_compat_smt_threads(cpu);
> > +    int smt_threads = CPU_CORE(pc)->nr_threads;
> 
> ppc_get_compat_smt_threads() also checks kvmppc_smt_threads() ... as
> long as we do not run the powernv architecture with KVM PR, your change
> should be OK, but if we support that one day, we might need to check
> kvmppc_smt_threads() here, too?

No, actually.  I covered this when I posted this patch standalone
earlier, but forgot to add it to the commit message.  If nr_threads
exceeds kvmppc_smt_threads() then things are already broken, and
clamping the value here isn't going to save us.

> 
> >      CPUPPCState *env = &cpu->env;
> >      PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
> >      uint32_t servers_prop[smt_threads];
> > @@ -206,10 +206,6 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
> >      _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
> >                         pa_features, sizeof(pa_features))));
> >  
> > -    if (cpu->cpu_version) {
> > -        _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
> > -    }
> > -
> >      /* Build interrupt servers properties */
> >      for (i = 0; i < smt_threads; i++) {
> >          servers_prop[i] = cpu_to_be32(pc->pir + i);
> > 
> 
> Reviewed-by: Thomas Huth <thuth@redhat.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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting
  2016-10-31  5:55   ` Alexey Kardashevskiy
@ 2016-10-31  8:39     ` David Gibson
  2016-11-04  3:45       ` Alexey Kardashevskiy
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-10-31  8:39 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Mon, Oct 31, 2016 at 04:55:42PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:12, David Gibson wrote:
> > Current ppc_set_compat() will attempt to set any compatiblity mode
> > specified, regardless of whether it's available on the CPU.  The caller is
> > expected to make sure it is setting a possible mode, which is awkwward
> > because most of the information to make that decision is at the CPU level.
> > 
> > This begins to clean this up by introducing a ppc_check_compat() function
> > which will determine if a given compatiblity mode is supported on a CPU
> > (and also whether it lies within specified minimum and maximum compat
> > levels, which will be useful later).  It also contains an assertion that
> > the CPU has a "virtual hypervisor"[1], that is, that the guest isn't
> > permitted to execute hypervisor privilege code.  Without that, the guest
> > would own the PCR and so could override any mode set here.  Only machine
> > types which use a virtual hypervisor (i.e. 'pseries') should use
> > ppc_check_compat().
> > 
> > ppc_set_compat() is modified to validate the compatibility mode it is given
> > and fail if it's not available on this CPU.
> > 
> > [1] Or user-only mode, which also obviously doesn't allow access to the
> > hypervisor privileged PCR.  We don't use that now, but could in future.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  target-ppc/compat.c | 41 +++++++++++++++++++++++++++++++++++++++++
> >  target-ppc/cpu.h    |  2 ++
> >  2 files changed, 43 insertions(+)
> > 
> > diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> > index 66529a6..1059555 100644
> > --- a/target-ppc/compat.c
> > +++ b/target-ppc/compat.c
> > @@ -28,29 +28,37 @@
> >  typedef struct {
> >      uint32_t pvr;
> >      uint64_t pcr;
> > +    uint64_t pcr_level;
> >      int max_threads;
> >  } CompatInfo;
> >  
> >  static const CompatInfo compat_table[] = {
> > +    /*
> > +     * Ordered from oldest to newest - the code relies on this
> > +     */
> >      { /* POWER6, ISA2.05 */
> >          .pvr = CPU_POWERPC_LOGICAL_2_05,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
> >                 | PCR_TM_DIS | PCR_VSX_DIS,
> > +        .pcr_level = PCR_COMPAT_2_05,
> >          .max_threads = 2,
> >      },
> >      { /* POWER7, ISA2.06 */
> >          .pvr = CPU_POWERPC_LOGICAL_2_06,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> > +        .pcr_level = PCR_COMPAT_2_06,
> >          .max_threads = 4,
> >      },
> >      {
> >          .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> > +        .pcr_level = PCR_COMPAT_2_06,
> >          .max_threads = 4,
> >      },
> >      { /* POWER8, ISA2.07 */
> >          .pvr = CPU_POWERPC_LOGICAL_2_07,
> >          .pcr = PCR_COMPAT_2_07,
> > +        .pcr_level = PCR_COMPAT_2_07,
> >          .max_threads = 8,
> >      },
> >  };
> > @@ -67,6 +75,35 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr)
> >      return NULL;
> >  }
> >  
> > +bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
> > +                      uint32_t min_compat_pvr, uint32_t max_compat_pvr)
> > +{
> > +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
> > +    const CompatInfo *compat = compat_by_pvr(compat_pvr);
> > +    const CompatInfo *min = compat_by_pvr(min_compat_pvr);
> > +    const CompatInfo *max = compat_by_pvr(max_compat_pvr);
> 
> 
> You keep giving very generic names (as "min" and "max") to local
> variables ;)

For local variables, brevity is a virtue.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv
  2016-10-30 11:11 ` [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv David Gibson
  2016-10-31  7:46   ` Thomas Huth
@ 2016-10-31 10:35   ` Greg Kurz
  1 sibling, 0 replies; 75+ messages in thread
From: Greg Kurz @ 2016-10-31 10:35 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, aik, mdroth, lvivier, thuth, qemu-ppc, qemu-devel

On Sun, 30 Oct 2016 22:11:53 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:

> powernv has some code (derived from the spapr equivalent) used in device
> tree generation which depends on the CPU's compatibility mode / logical
> PVR.  However, compatibility modes don't make sense on powernv - at least
> not as a property controlled by the host - because the guest in powernv
> has full hypervisor level access to the virtual system, and so owns the
> PCR (Processor Compatibility Register) which implements compatiblity modes.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---

As said with the standalone version:

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

>  hw/ppc/pnv.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
> index 82276e0..6af3424 100644
> --- a/hw/ppc/pnv.c
> +++ b/hw/ppc/pnv.c
> @@ -110,7 +110,7 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
>      CPUState *cs = CPU(DEVICE(pc->threads));
>      DeviceClass *dc = DEVICE_GET_CLASS(cs);
>      PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    int smt_threads = ppc_get_compat_smt_threads(cpu);
> +    int smt_threads = CPU_CORE(pc)->nr_threads;
>      CPUPPCState *env = &cpu->env;
>      PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
>      uint32_t servers_prop[smt_threads];
> @@ -206,10 +206,6 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt)
>      _FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
>                         pa_features, sizeof(pa_features))));
>  
> -    if (cpu->cpu_version) {
> -        _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version)));
> -    }
> -
>      /* Build interrupt servers properties */
>      for (i = 0; i < smt_threads; i++) {
>          servers_prop[i] = cpu_to_be32(pc->pir + i);

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

* Re: [Qemu-devel] [RFC 03/17] pseries: Always use core objects for CPU construction
  2016-10-30 11:11 ` [Qemu-devel] [RFC 03/17] pseries: Always use core objects for CPU construction David Gibson
@ 2016-11-03  8:11   ` Alexey Kardashevskiy
  2016-11-04  9:51     ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-03  8:11 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:11, David Gibson wrote:
> Currently the pseries machine has two paths for constructing CPUs.  On
> newer machine type versions, which support cpu hotplug, it constructs
> cpu core objects, which in turn construct CPU threads.  For older machine
> versions it individually constructs the CPU threads.
> 
> This division is going to make some future changes to the cpu construction
> harder, so this patch unifies them.  Now cpu core objects are always
> created.  This requires some updates to allow core objects to be created
> without a full complement of threads (since older versions allowed a
> number of cpus not a multiple of the threads-per-core).  Likewise it needs
> some changes to the cpu core hot/cold plug path so as not to choke on the
> old machine types without hotplug support.
> 
> For good measure, we move the cpu construction to its own subfunction,
> spapr_init_cpus().
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr.c          | 125 +++++++++++++++++++++++++++---------------------
>  hw/ppc/spapr_cpu_core.c |  30 +++++++-----
>  include/hw/ppc/spapr.h  |   1 -
>  3 files changed, 89 insertions(+), 67 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index c8e2921..ad68a9d 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1688,11 +1688,80 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp)
>      }
>  }
>  
> +static void spapr_init_cpus(sPAPRMachineState *spapr)
> +{
> +    MachineState *machine = MACHINE(spapr);
> +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> +    char *type = spapr_get_cpu_core_type(machine->cpu_model);
> +    int smt = kvmppc_smt_threads();
> +    int spapr_max_cores, spapr_cores;
> +    int i;
> +
> +    if (!type) {
> +        error_report("Unable to find sPAPR CPU Core definition");
> +        exit(1);
> +    }
> +
> +    if (mc->query_hotpluggable_cpus) {
> +        if (smp_cpus % smp_threads) {
> +            error_report("smp_cpus (%u) must be multiple of threads (%u)",
> +                         smp_cpus, smp_threads);
> +            exit(1);
> +        }
> +        if (max_cpus % smp_threads) {
> +            error_report("max_cpus (%u) must be multiple of threads (%u)",
> +                         max_cpus, smp_threads);
> +            exit(1);
> +        }
> +
> +        spapr_max_cores = max_cpus / smp_threads;
> +        spapr_cores = smp_cpus / smp_threads;
> +    } else {
> +        if (max_cpus != smp_cpus) {
> +            error_report("This machine version does not support CPU hotplug");
> +            exit(1);
> +        }
> +
> +        spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
> +        spapr_cores = spapr_max_cores;
> +    }
> +
> +    spapr->cores = g_new0(Object *, spapr_max_cores);
> +    for (i = 0; i < spapr_max_cores; i++) {
> +        int core_id = i * smp_threads;
> +
> +        if (mc->query_hotpluggable_cpus) {
> +            sPAPRDRConnector *drc =
> +                spapr_dr_connector_new(OBJECT(spapr),
> +                                       SPAPR_DR_CONNECTOR_TYPE_CPU,
> +                                       (core_id / smp_threads) * smt);
> +
> +            qemu_register_reset(spapr_drc_reset, drc);
> +        }
> +
> +        if (i < spapr_cores) {
> +            Object *core  = object_new(type);
> +            int nr_threads = smp_threads;
> +
> +            /* Handle the partially filled core for older machine types */
> +            if ((i + 1) * smp_threads >= smp_cpus) {
> +                nr_threads = smp_cpus - i * smp_threads;
> +            }


What is this exactly for? Older machines report "qemu-system-ppc64: threads
must be 8" when I do "-smp 12,threads=8 -machine pseries-2.2".



> +
> +            object_property_set_int(core, nr_threads, "nr-threads",
> +                                    &error_fatal);
> +            object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
> +                                    &error_fatal);
> +            object_property_set_bool(core, true, "realized", &error_fatal);
> +        }
> +    }
> +    g_free(type);
> +}
> +
>  /* pSeries LPAR / sPAPR hardware init */
>  static void ppc_spapr_init(MachineState *machine)
>  {
>      sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
> -    MachineClass *mc = MACHINE_GET_CLASS(machine);
>      sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
>      const char *kernel_filename = machine->kernel_filename;
>      const char *initrd_filename = machine->initrd_filename;
> @@ -1707,21 +1776,6 @@ static void ppc_spapr_init(MachineState *machine)
>      long load_limit, fw_size;
>      char *filename;
>      int smt = kvmppc_smt_threads();
> -    int spapr_cores = smp_cpus / smp_threads;
> -    int spapr_max_cores = max_cpus / smp_threads;
> -
> -    if (mc->query_hotpluggable_cpus) {
> -        if (smp_cpus % smp_threads) {
> -            error_report("smp_cpus (%u) must be multiple of threads (%u)",
> -                         smp_cpus, smp_threads);
> -            exit(1);
> -        }
> -        if (max_cpus % smp_threads) {
> -            error_report("max_cpus (%u) must be multiple of threads (%u)",
> -                         max_cpus, smp_threads);
> -            exit(1);
> -        }
> -    }
>  
>      msi_nonbroken = true;
>  
> @@ -1801,44 +1855,7 @@ static void ppc_spapr_init(MachineState *machine)
>  
>      ppc_cpu_parse_features(machine->cpu_model);
>  
> -    if (mc->query_hotpluggable_cpus) {
> -        char *type = spapr_get_cpu_core_type(machine->cpu_model);
> -
> -        if (type == NULL) {
> -            error_report("Unable to find sPAPR CPU Core definition");
> -            exit(1);
> -        }
> -
> -        spapr->cores = g_new0(Object *, spapr_max_cores);
> -        for (i = 0; i < spapr_max_cores; i++) {
> -            int core_id = i * smp_threads;
> -            sPAPRDRConnector *drc =
> -                spapr_dr_connector_new(OBJECT(spapr),
> -                                       SPAPR_DR_CONNECTOR_TYPE_CPU,
> -                                       (core_id / smp_threads) * smt);
> -
> -            qemu_register_reset(spapr_drc_reset, drc);
> -
> -            if (i < spapr_cores) {
> -                Object *core  = object_new(type);
> -                object_property_set_int(core, smp_threads, "nr-threads",
> -                                        &error_fatal);
> -                object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
> -                                        &error_fatal);
> -                object_property_set_bool(core, true, "realized", &error_fatal);
> -            }
> -        }
> -        g_free(type);
> -    } else {
> -        for (i = 0; i < smp_cpus; i++) {
> -            PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model);
> -            if (cpu == NULL) {
> -                error_report("Unable to find PowerPC CPU definition");
> -                exit(1);
> -            }
> -            spapr_cpu_init(spapr, cpu, &error_fatal);
> -       }
> -    }
> +    spapr_init_cpus(spapr);
>  
>      if (kvm_enabled()) {
>          /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> index e0c14f6..1357293 100644
> --- a/hw/ppc/spapr_cpu_core.c
> +++ b/hw/ppc/spapr_cpu_core.c
> @@ -46,7 +46,8 @@ static void spapr_cpu_destroy(PowerPCCPU *cpu)
>      qemu_unregister_reset(spapr_cpu_reset, cpu);
>  }
>  
> -void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp)
> +static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
> +                           Error **errp)
>  {
>      CPUPPCState *env = &cpu->env;
>      CPUState *cs = CPU(cpu);
> @@ -166,6 +167,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
>                       Error **errp)
>  {
>      sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
> +    MachineClass *mc = MACHINE_GET_CLASS(spapr);
>      sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
>      CPUCore *cc = CPU_CORE(dev);
>      CPUState *cs = CPU(core->threads);
> @@ -180,7 +182,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
>      drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
>      spapr->cores[index] = OBJECT(dev);
>  
> -    g_assert(drc);
> +    g_assert(drc || !mc->query_hotpluggable_cpus);
>  
>      /*
>       * Setup CPU DT entries only for hotplugged CPUs. For boot time or
> @@ -190,13 +192,15 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
>          fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
>      }
>  
> -    drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> -    drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
> -    if (local_err) {
> -        g_free(fdt);
> -        spapr->cores[index] = NULL;
> -        error_propagate(errp, local_err);
> -        return;
> +    if (drc) {
> +        drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> +        drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
> +        if (local_err) {
> +            g_free(fdt);
> +            spapr->cores[index] = NULL;
> +            error_propagate(errp, local_err);
> +            return;
> +        }
>      }
>  
>      if (dev->hotplugged) {
> @@ -209,8 +213,10 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
>          /*
>           * Set the right DRC states for cold plugged CPU.
>           */
> -        drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
> -        drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
> +        if (drc) {
> +            drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
> +            drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
> +        }
>      }
>  }
>  
> @@ -227,7 +233,7 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
>      char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model);
>      const char *type = object_get_typename(OBJECT(dev));
>  
> -    if (!mc->query_hotpluggable_cpus) {
> +    if (dev->hotplugged && !mc->query_hotpluggable_cpus) {
>          error_setg(&local_err, "CPU hotplug not supported for this machine");
>          goto out;
>      }
> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> index bd5bcf7..f8d444d 100644
> --- a/include/hw/ppc/spapr.h
> +++ b/include/hw/ppc/spapr.h
> @@ -614,7 +614,6 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
>                                              uint32_t count, uint32_t index);
>  void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
>                                                 uint32_t count, uint32_t index);
> -void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp);
>  void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
>                                      sPAPRMachineState *spapr);
>  
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional
  2016-10-30 11:11 ` [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional David Gibson
@ 2016-11-03  8:24   ` Alexey Kardashevskiy
  2016-11-04 10:45   ` Thomas Huth
  1 sibling, 0 replies; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-03  8:24 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:11, David Gibson wrote:
> spapr_h_cas_compose_response() includes a cpu_update parameter which
> controls whether it includes updated information on the CPUs in the device
> tree fragment returned from the ibm,client-architecture-support (CAS) call.
> 
> Providing the updated information is essential when CAS has negotiated
> compatibility options which require different cpu information to be
> presented to the guest.  However, it should be safe to provide in other
> cases (it will just override the existing data in the device tree with
> identical data).  This simplifies the code by removing the parameter and
> always providing the cpu update information.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>


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



> ---
>  hw/ppc/spapr.c         | 5 +----
>  hw/ppc/spapr_hcall.c   | 8 ++------
>  include/hw/ppc/spapr.h | 1 -
>  3 files changed, 3 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index ad68a9d..3551439 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -686,7 +686,6 @@ out:
>  
>  int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
>                                   target_ulong addr, target_ulong size,
> -                                 bool cpu_update,
>                                   sPAPROptionVector *ov5_updates)
>  {
>      void *fdt, *fdt_skel;
> @@ -705,9 +704,7 @@ int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
>      g_free(fdt_skel);
>  
>      /* Fixup cpu nodes */
> -    if (cpu_update) {
> -        _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
> -    }
> +    _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
>  
>      if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
>          return -1;
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 7c46d46..b5544cb 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -945,7 +945,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
>      target_ulong ov_table;
>      PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
>      CPUState *cs;
> -    bool cpu_match = false, cpu_update = true;
> +    bool cpu_match = false;
>      unsigned old_cpu_version = cpu_->cpu_version;
>      unsigned compat_lvl = 0, cpu_version = 0;
>      unsigned max_lvl = get_compat_level(cpu_->max_compat);
> @@ -999,10 +999,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
>          }
>      }
>  
> -    if (!cpu_version) {
> -        cpu_update = false;
> -    }
> -
>      /* For the future use: here @ov_table points to the first option vector */
>      ov_table = list;
>  
> @@ -1028,7 +1024,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
>  
>      if (!spapr->cas_reboot) {
>          spapr->cas_reboot =
> -            (spapr_h_cas_compose_response(spapr, args[1], args[2], cpu_update,
> +            (spapr_h_cas_compose_response(spapr, args[1], args[2],
>                                            ov5_updates) != 0);
>      }
>      spapr_ovec_cleanup(ov5_updates);
> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> index f8d444d..04d2821 100644
> --- a/include/hw/ppc/spapr.h
> +++ b/include/hw/ppc/spapr.h
> @@ -589,7 +589,6 @@ void spapr_events_init(sPAPRMachineState *sm);
>  void spapr_dt_events(sPAPRMachineState *sm, void *fdt);
>  int spapr_h_cas_compose_response(sPAPRMachineState *sm,
>                                   target_ulong addr, target_ulong size,
> -                                 bool cpu_update,
>                                   sPAPROptionVector *ov5_updates);
>  sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
>  void spapr_tce_table_enable(sPAPRTCETable *tcet,
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 05/17] ppc: Clean up and QOMify hypercall emulation
  2016-10-30 11:11 ` [Qemu-devel] [RFC 05/17] ppc: Clean up and QOMify hypercall emulation David Gibson
@ 2016-11-03  8:50   ` Alexey Kardashevskiy
  0 siblings, 0 replies; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-03  8:50 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:11, David Gibson wrote:
> The pseries machine type is a bit unusual in that it runs a paravirtualized
> guest.  The guest expects to interact with a hypervisor, and qemu
> emulates the functions of that hypervisor directly, rather than executing
> hypervisor code within the emulated system.
> 
> To implement this in TCG, we need to intercept hypercall instructions and
> direct them to the machine's hypercall handlers, rather than attempting to
> perform a privilege change within TCG.  This is controlled by a global
> hook - cpu_ppc_hypercall.
> 
> This cleanup makes the handling a little cleaner and more extensible that
> a single global variable.  Instead, each CPU to have hypercalls intercepted
> has a pointer set to a QOM object implementing a new virtual hypervisor
> interface.  A method in that interface is called by TCG when it sees a
> hypercall instruction.  It's possible we may want to add other methods in
> future.


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

I did not realize it is a global hook :)

> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr.c              |  8 +++++---
>  hw/ppc/spapr_cpu_core.c     |  1 +
>  target-ppc/cpu.h            | 26 ++++++++++++++++++++++++--
>  target-ppc/excp_helper.c    | 11 ++++-------
>  target-ppc/translate_init.c | 12 ++++++++++++
>  5 files changed, 46 insertions(+), 12 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index 3551439..b7762ee 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1006,7 +1006,8 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
>      return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
>  }
>  
> -static void emulate_spapr_hypercall(PowerPCCPU *cpu)
> +static void emulate_spapr_hypercall(PPCVirtualHypervisor *vhyp,
> +                                    PowerPCCPU *cpu)
>  {
>      CPUPPCState *env = &cpu->env;
>  
> @@ -1778,8 +1779,6 @@ static void ppc_spapr_init(MachineState *machine)
>  
>      QLIST_INIT(&spapr->phbs);
>  
> -    cpu_ppc_hypercall = emulate_spapr_hypercall;
> -
>      /* Allocate RMA if necessary */
>      rma_alloc_size = kvmppc_alloc_rma(&rma);
>  
> @@ -2610,6 +2609,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
>      FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
>      NMIClass *nc = NMI_CLASS(oc);
>      HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
> +    PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc);
>  
>      mc->desc = "pSeries Logical Partition (PAPR compliant)";
>  
> @@ -2641,6 +2641,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
>      fwc->get_dev_path = spapr_get_fw_dev_path;
>      nc->nmi_monitor_handler = spapr_nmi;
>      smc->phb_placement = spapr_phb_placement;
> +    vhc->hypercall = emulate_spapr_hypercall;
>  }
>  
>  static const TypeInfo spapr_machine_info = {
> @@ -2656,6 +2657,7 @@ static const TypeInfo spapr_machine_info = {
>          { TYPE_FW_PATH_PROVIDER },
>          { TYPE_NMI },
>          { TYPE_HOTPLUG_HANDLER },
> +        { TYPE_PPC_VIRTUAL_HYPERVISOR },
>          { }
>      },
>  };
> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> index 1357293..ee5cd14 100644
> --- a/hw/ppc/spapr_cpu_core.c
> +++ b/hw/ppc/spapr_cpu_core.c
> @@ -57,6 +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);
>  
>      if (cpu->max_compat) {
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index 1c90adb..a655105 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -1148,6 +1148,9 @@ do {                                            \
>      env->wdt_period[3] = (d_);                  \
>   } while (0)
>  
> +typedef struct PPCVirtualHypervisor PPCVirtualHypervisor;
> +typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
> +
>  /**
>   * PowerPCCPU:
>   * @env: #CPUPPCState
> @@ -1166,6 +1169,7 @@ struct PowerPCCPU {
>      int cpu_dt_id;
>      uint32_t max_compat;
>      uint32_t cpu_version;
> +    PPCVirtualHypervisor *vhyp;
>  };
>  
>  static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
> @@ -1180,6 +1184,25 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
>  PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
>  PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr);
>  
> +struct PPCVirtualHypervisor {
> +    Object parent;
> +};
> +
> +struct PPCVirtualHypervisorClass {
> +    InterfaceClass parent;
> +    void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
> +};
> +
> +#define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
> +#define PPC_VIRTUAL_HYPERVISOR(obj)                 \
> +    OBJECT_CHECK(PPCVirtualHypervisor, (obj), TYPE_PPC_VIRTUAL_HYPERVISOR)
> +#define PPC_VIRTUAL_HYPERVISOR_CLASS(klass)         \
> +    OBJECT_CLASS_CHECK(PPCVirtualHypervisorClass, (klass), \
> +                       TYPE_PPC_VIRTUAL_HYPERVISOR)
> +#define PPC_VIRTUAL_HYPERVISOR_GET_CLASS(obj) \
> +    OBJECT_GET_CLASS(PPCVirtualHypervisorClass, (obj), \
> +                     TYPE_PPC_VIRTUAL_HYPERVISOR)
> +
>  void ppc_cpu_do_interrupt(CPUState *cpu);
>  bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
>  void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
> @@ -1252,6 +1275,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);
>  #endif
>  #endif
> @@ -2421,8 +2445,6 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx)
>             (start + nregs > 32 && (rx >= start || rx < start + nregs - 32));
>  }
>  
> -extern void (*cpu_ppc_hypercall)(PowerPCCPU *);
> -
>  void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
>  
>  /**
> diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
> index 808760b..a077939 100644
> --- a/target-ppc/excp_helper.c
> +++ b/target-ppc/excp_helper.c
> @@ -35,11 +35,6 @@
>  #endif
>  
>  /*****************************************************************************/
> -/* PowerPC Hypercall emulation */
> -
> -void (*cpu_ppc_hypercall)(PowerPCCPU *);
> -
> -/*****************************************************************************/
>  /* Exception processing */
>  #if defined(CONFIG_USER_ONLY)
>  void ppc_cpu_do_interrupt(CPUState *cs)
> @@ -318,8 +313,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          env->nip += 4;
>  
>          /* "PAPR mode" built-in hypercall emulation */
> -        if ((lev == 1) && cpu_ppc_hypercall) {
> -            cpu_ppc_hypercall(cpu);
> +        if ((lev == 1) && cpu->vhyp) {
> +            PPCVirtualHypervisorClass *vhc =
> +                PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> +            vhc->hypercall(cpu->vhyp, cpu);
>              return;
>          }
>          if (lev == 1) {
> diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> index 208fa1e..21899a4 100644
> --- a/target-ppc/translate_init.c
> +++ b/target-ppc/translate_init.c
> @@ -8857,6 +8857,11 @@ 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)
>  {
>      CPUPPCState *env = &cpu->env;
> @@ -10587,9 +10592,16 @@ static const TypeInfo ppc_cpu_type_info = {
>      .class_init = ppc_cpu_class_init,
>  };
>  
> +static const TypeInfo ppc_vhyp_type_info = {
> +    .name = TYPE_PPC_VIRTUAL_HYPERVISOR,
> +    .parent = TYPE_INTERFACE,
> +    .class_size = sizeof(PPCVirtualHypervisorClass),
> +};
> +
>  static void ppc_cpu_register_types(void)
>  {
>      type_register_static(&ppc_cpu_type_info);
> +    type_register_static(&ppc_vhyp_type_info);
>  }
>  
>  type_init(ppc_cpu_register_types)
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr
  2016-10-30 11:11 ` [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr David Gibson
@ 2016-11-04  2:26   ` Alexey Kardashevskiy
  2016-11-08  3:48     ` David Gibson
  2016-11-04 10:51   ` Thomas Huth
  1 sibling, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  2:26 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:11, David Gibson wrote:
> The 'cpu_version' field in PowerPCCPU is badly named.  It's named after the
> 'cpu-version' device tree property where it is advertised, but that meaning
> may not be obvious in most places it appears.
> 
> Worse, it doesn't even really correspond to that device tree property.  The
> property contains either the processor's PVR, or, if the CPU is running in
> a compatibility mode, a special "logical PVR" representing which mode.
> 
> Rename the cpu_version field, and a number of related variables to
> compat_pvr to make this clearer.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr.c              |  4 ++--
>  hw/ppc/spapr_hcall.c        | 30 +++++++++++++++---------------
>  target-ppc/cpu.h            |  6 +++---
>  target-ppc/kvm.c            |  4 ++--
>  target-ppc/kvm_ppc.h        |  4 ++--
>  target-ppc/translate_init.c | 10 +++++-----
>  6 files changed, 29 insertions(+), 29 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index b7762ee..276cefa 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -149,8 +149,8 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
>      uint32_t gservers_prop[smt_threads * 2];
>      int index = ppc_get_vcpu_dt_id(cpu);
>  
> -    if (cpu->cpu_version) {
> -        ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version);
> +    if (cpu->compat_pvr) {


Nit: g_assert(cpu->compat_pvr & 0x0F000000); may be?


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




> +        ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->compat_pvr);
>          if (ret < 0) {
>              return ret;
>          }
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index b5544cb..d93f580 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -882,7 +882,7 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>  }
>  
>  typedef struct {
> -    uint32_t cpu_version;
> +    uint32_t compat_pvr;
>      Error *err;
>  } SetCompatState;
>  
> @@ -892,7 +892,7 @@ static void do_set_compat(CPUState *cs, void *arg)
>      SetCompatState *s = arg;
>  
>      cpu_synchronize_state(cs);
> -    ppc_set_compat(cpu, s->cpu_version, &s->err);
> +    ppc_set_compat(cpu, s->compat_pvr, &s->err);
>  }
>  
>  #define get_compat_level(cpuver) ( \
> @@ -903,7 +903,7 @@ static void do_set_compat(CPUState *cs, void *arg)
>  
>  static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
>                                    unsigned max_lvl, unsigned *compat_lvl,
> -                                  unsigned *cpu_version)
> +                                  unsigned *compat_pvr)
>  {
>      unsigned lvl = get_compat_level(pvr);
>      bool is205, is206, is207;
> @@ -926,12 +926,12 @@ static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
>              /* User did not set the level, choose the highest */
>              if (*compat_lvl <= lvl) {
>                  *compat_lvl = lvl;
> -                *cpu_version = pvr;
> +                *compat_pvr = pvr;
>              }
>          } else if (max_lvl >= lvl) {
>              /* User chose the level, don't set higher than this */
>              *compat_lvl = lvl;
> -            *cpu_version = pvr;
> +            *compat_pvr = pvr;
>          }
>      }
>  }
> @@ -946,8 +946,8 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
>      PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
>      CPUState *cs;
>      bool cpu_match = false;
> -    unsigned old_cpu_version = cpu_->cpu_version;
> -    unsigned compat_lvl = 0, cpu_version = 0;
> +    unsigned old_compat_pvr = cpu_->compat_pvr;
> +    unsigned compat_lvl = 0, compat_pvr = 0;
>      unsigned max_lvl = get_compat_level(cpu_->max_compat);
>      int counter;
>      sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
> @@ -965,12 +965,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
>          if (!max_lvl &&
>              ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
>              cpu_match = true;
> -            cpu_version = 0;
> -        } else if (pvr == cpu_->cpu_version) {
> +            compat_pvr = 0;
> +        } else if (pvr == cpu_->compat_pvr) {
>              cpu_match = true;
> -            cpu_version = cpu_->cpu_version;
> +            compat_pvr = cpu_->compat_pvr;
>          } else if (!cpu_match) {
> -            cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &cpu_version);
> +            cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &compat_pvr);
>          }
>          /* Terminator record */
>          if (~pvr_mask & pvr) {
> @@ -979,14 +979,14 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
>      }
>  
>      /* Parsing finished */
> -    trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match,
> -                        cpu_version, pcc->pcr_mask);
> +    trace_spapr_cas_pvr(cpu_->compat_pvr, cpu_match,
> +                        compat_pvr, pcc->pcr_mask);
>  
>      /* Update CPUs */
> -    if (old_cpu_version != cpu_version) {
> +    if (old_compat_pvr != compat_pvr) {
>          CPU_FOREACH(cs) {
>              SetCompatState s = {
> -                .cpu_version = cpu_version,
> +                .compat_pvr = compat_pvr,
>                  .err = NULL,
>              };
>  
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index a655105..f7656cb 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -1156,7 +1156,7 @@ typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
>   * @env: #CPUPPCState
>   * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
>   * @max_compat: Maximal supported logical PVR from the command line
> - * @cpu_version: Current logical PVR, zero if in "raw" mode
> + * @compat_pvr: Current logical PVR, zero if in "raw" mode
>   *
>   * A PowerPC CPU.
>   */
> @@ -1168,7 +1168,7 @@ struct PowerPCCPU {
>      CPUPPCState env;
>      int cpu_dt_id;
>      uint32_t max_compat;
> -    uint32_t cpu_version;
> +    uint32_t compat_pvr;
>      PPCVirtualHypervisor *vhyp;
>  };
>  
> @@ -1243,7 +1243,7 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value);
>  void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
>  int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
>  #if defined(TARGET_PPC64)
> -void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp);
> +void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
>  #endif
>  
>  /* Time-base and decrementer management */
> diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
> index 9c4834c..15e12f3 100644
> --- a/target-ppc/kvm.c
> +++ b/target-ppc/kvm.c
> @@ -2103,9 +2103,9 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
>      cap_papr = 1;
>  }
>  
> -int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
> +int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr)
>  {
> -    return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &cpu_version);
> +    return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &compat_pvr);
>  }
>  
>  void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
> diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
> index bd1d78b..841a29b 100644
> --- a/target-ppc/kvm_ppc.h
> +++ b/target-ppc/kvm_ppc.h
> @@ -26,7 +26,7 @@ void kvmppc_enable_logical_ci_hcalls(void);
>  void kvmppc_enable_set_mode_hcall(void);
>  void kvmppc_enable_clear_ref_mod_hcalls(void);
>  void kvmppc_set_papr(PowerPCCPU *cpu);
> -int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version);
> +int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr);
>  void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
>  int kvmppc_smt_threads(void);
>  int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
> @@ -123,7 +123,7 @@ static inline void kvmppc_set_papr(PowerPCCPU *cpu)
>  {
>  }
>  
> -static inline int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
> +static inline int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr)
>  {
>      return 0;
>  }
> diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> index 21899a4..c35065d 100644
> --- a/target-ppc/translate_init.c
> +++ b/target-ppc/translate_init.c
> @@ -9957,7 +9957,7 @@ int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
>      CPUState *cs = CPU(cpu);
>      int ret = MIN(cs->nr_threads, kvmppc_smt_threads());
>  
> -    switch (cpu->cpu_version) {
> +    switch (cpu->compat_pvr) {
>      case CPU_POWERPC_LOGICAL_2_05:
>          ret = MIN(ret, 2);
>          break;
> @@ -9973,15 +9973,15 @@ int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
>  }
>  
>  #ifdef TARGET_PPC64
> -void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp)
> +void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>  {
>      int ret = 0;
>      CPUPPCState *env = &cpu->env;
>      PowerPCCPUClass *host_pcc;
>  
> -    cpu->cpu_version = cpu_version;
> +    cpu->compat_pvr = compat_pvr;
>  
> -    switch (cpu_version) {
> +    switch (compat_pvr) {
>      case CPU_POWERPC_LOGICAL_2_05:
>          env->spr[SPR_PCR] = PCR_TM_DIS | PCR_VSX_DIS | PCR_COMPAT_2_07 |
>                              PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> @@ -10004,7 +10004,7 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp)
>      }
>  
>      if (kvm_enabled()) {
> -        ret = kvmppc_set_compat(cpu, cpu->cpu_version);
> +        ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
>          if (ret < 0) {
>              error_setg_errno(errp, -ret,
>                               "Unable to set CPU compatibility mode in KVM");
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 07/17] ppc: Rewrite ppc_set_compat()
  2016-10-30 11:11 ` [Qemu-devel] [RFC 07/17] ppc: Rewrite ppc_set_compat() David Gibson
@ 2016-11-04  2:57   ` Alexey Kardashevskiy
  2016-11-08  3:49     ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  2:57 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:11, David Gibson wrote:
> This rewrites the ppc_set_compat() function so that instead of open coding
> the various compatibility modes, it reads the relevant data from a table.
> This is a first step in consolidating the information on compatibility
> modes scattered across the code into a single place.
> 
> It also makes one change to the logic.  The old code masked the bits to be
> set in the PCR (Processor Compatibility Register) by which bits are valid
> on the host CPU.  This made no sense, since it was done regardless of
> whether our guest CPU was the same as the host CPU or not.  Futhermore,

s/Futhermore/Furthermore/


> the actual PCR bits are only relevant for TCG[1] - KVM instead uses the
> compatibility mode we tell it in kvmppc_set_compat().  When using TCG
> host cpu information usually isn't even present.
> 
> While we're at it, we put the new implementation in a new file to make the
> enormouse translate_init.c a little smaller.

s/enormouse/enormous/


> 
> [1] Actually it doesn't even do anything in TCG, but it will if / when we
>     get to implementing compatibility mode logic at that level.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

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

> ---
>  target-ppc/Makefile.objs    |  1 +
>  target-ppc/compat.c         | 91 +++++++++++++++++++++++++++++++++++++++++++++
>  target-ppc/cpu.h            |  6 ++-
>  target-ppc/translate_init.c | 41 --------------------
>  4 files changed, 97 insertions(+), 42 deletions(-)
>  create mode 100644 target-ppc/compat.c
> 
> diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
> index e667e69..feb5c30 100644
> --- a/target-ppc/Makefile.objs
> +++ b/target-ppc/Makefile.objs
> @@ -15,3 +15,4 @@ obj-y += misc_helper.o
>  obj-y += mem_helper.o
>  obj-$(CONFIG_USER_ONLY) += user_only_helper.o
>  obj-y += gdbstub.o
> +obj-$(TARGET_PPC64) += compat.o
> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> new file mode 100644
> index 0000000..f3fd9c6
> --- /dev/null
> +++ b/target-ppc/compat.c
> @@ -0,0 +1,91 @@
> +/*
> + *  PowerPC CPU initialization for qemu.
> + *
> + *  Copyright 2016, David Gibson, Red Hat Inc. <dgibson@redhat.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "sysemu/kvm.h"
> +#include "kvm_ppc.h"
> +#include "sysemu/cpus.h"
> +#include "qemu/error-report.h"
> +#include "qapi/error.h"
> +#include "cpu-models.h"
> +
> +typedef struct {
> +    uint32_t pvr;
> +    uint64_t pcr;
> +} CompatInfo;
> +
> +static const CompatInfo compat_table[] = {
> +    { /* POWER6, ISA2.05 */
> +        .pvr = CPU_POWERPC_LOGICAL_2_05,
> +        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
> +               | PCR_TM_DIS | PCR_VSX_DIS,
> +    },
> +    { /* POWER7, ISA2.06 */
> +        .pvr = CPU_POWERPC_LOGICAL_2_06,
> +        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> +    },
> +    {
> +        .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
> +        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> +    },
> +    { /* POWER8, ISA2.07 */
> +        .pvr = CPU_POWERPC_LOGICAL_2_07,
> +        .pcr = PCR_COMPAT_2_07,
> +    },
> +};
> +
> +static const CompatInfo *compat_by_pvr(uint32_t pvr)
> +{
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
> +        if (compat_table[i].pvr == pvr) {
> +            return &compat_table[i];
> +        }
> +    }
> +    return NULL;
> +}
> +
> +void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> +{
> +    const CompatInfo *compat = compat_by_pvr(compat_pvr);
> +    CPUPPCState *env = &cpu->env;
> +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
> +    uint64_t pcr;
> +
> +    if (!compat_pvr) {
> +        pcr = 0;
> +    } else if (!compat) {
> +        error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
> +        return;
> +    } else {
> +        pcr = compat->pcr;
> +    }
> +
> +    cpu->compat_pvr = compat_pvr;
> +    env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
> +
> +    if (kvm_enabled()) {
> +        int ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
> +        if (ret < 0) {
> +            error_setg_errno(errp, -ret,
> +                             "Unable to set CPU compatibility mode in KVM");
> +        }
> +    }
> +}
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index f7656cb..15d5e4b 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -1243,7 +1243,6 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value);
>  void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
>  int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
>  #if defined(TARGET_PPC64)
> -void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
>  #endif
>  
>  /* Time-base and decrementer management */
> @@ -1314,6 +1313,11 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
>      return ifetch ? env->immu_idx : env->dmmu_idx;
>  }
>  
> +/* Compatibility modes */
> +#if defined(TARGET_PPC64)
> +void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> +#endif /* defined(TARGET_PPC64) */
> +
>  #include "exec/cpu-all.h"
>  
>  /*****************************************************************************/
> diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> index c35065d..a70eafb 100644
> --- a/target-ppc/translate_init.c
> +++ b/target-ppc/translate_init.c
> @@ -9972,47 +9972,6 @@ int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
>      return ret;
>  }
>  
> -#ifdef TARGET_PPC64
> -void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> -{
> -    int ret = 0;
> -    CPUPPCState *env = &cpu->env;
> -    PowerPCCPUClass *host_pcc;
> -
> -    cpu->compat_pvr = compat_pvr;
> -
> -    switch (compat_pvr) {
> -    case CPU_POWERPC_LOGICAL_2_05:
> -        env->spr[SPR_PCR] = PCR_TM_DIS | PCR_VSX_DIS | PCR_COMPAT_2_07 |
> -                            PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> -        break;
> -    case CPU_POWERPC_LOGICAL_2_06:
> -    case CPU_POWERPC_LOGICAL_2_06_PLUS:
> -        env->spr[SPR_PCR] = PCR_TM_DIS | PCR_COMPAT_2_07 | PCR_COMPAT_2_06;
> -        break;
> -    case CPU_POWERPC_LOGICAL_2_07:
> -        env->spr[SPR_PCR] = PCR_COMPAT_2_07;
> -        break;
> -    default:
> -        env->spr[SPR_PCR] = 0;
> -        break;
> -    }
> -
> -    host_pcc = kvm_ppc_get_host_cpu_class();
> -    if (host_pcc) {
> -        env->spr[SPR_PCR] &= host_pcc->pcr_mask;
> -    }
> -
> -    if (kvm_enabled()) {
> -        ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
> -        if (ret < 0) {
> -            error_setg_errno(errp, -ret,
> -                             "Unable to set CPU compatibility mode in KVM");
> -        }
> -    }
> -}
> -#endif
> -
>  static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
>  {
>      ObjectClass *oc = (ObjectClass *)a;
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 08/17] ppc: Rewrite ppc_get_compat_smt_threads()
  2016-10-30 11:11 ` [Qemu-devel] [RFC 08/17] ppc: Rewrite ppc_get_compat_smt_threads() David Gibson
@ 2016-11-04  3:37   ` Alexey Kardashevskiy
  2016-11-08  5:13     ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  3:37 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:11, David Gibson wrote:
> To continue consolidation of compatibility mode information, this rewrites
> the ppc_get_compat_smt_threads() function using the table of compatiblity
> modes in target-ppc/compat.c.
> 
> It's not a direct replacement, the new ppc_compat_max_threads() function
> has simpler semantics - it just returns the number of threads the cpu
> model has, taking into account any compatiblity mode it is in.
> 
> This no longer takes into account kvmppc_smt_threads() as the previous
> version did.  That check wasn't useful because we check elsewhere that

Nit: s/elsewhere/in ppc_cpu_realizefn()/


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




> CPUs aren't instantiated with more threads than kvm allows (or if we didn't
> things will already be broken and this won't make it any worse).
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr.c              |  8 ++++----
>  target-ppc/compat.c         | 18 ++++++++++++++++++
>  target-ppc/cpu.h            |  2 +-
>  target-ppc/translate_init.c | 20 --------------------
>  4 files changed, 23 insertions(+), 25 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index 276cefa..6c78889 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -207,6 +207,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
>          PowerPCCPU *cpu = POWERPC_CPU(cs);
>          DeviceClass *dc = DEVICE_GET_CLASS(cs);
>          int index = ppc_get_vcpu_dt_id(cpu);
> +        int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
>  
>          if ((index % smt) != 0) {
>              continue;
> @@ -241,8 +242,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
>              return ret;
>          }
>  
> -        ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
> -                                     ppc_get_compat_smt_threads(cpu));
> +        ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
>          if (ret < 0) {
>              return ret;
>          }
> @@ -408,6 +408,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
>      size_t page_sizes_prop_size;
>      uint32_t vcpus_per_socket = smp_threads * smp_cores;
>      uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
> +    int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
>      sPAPRDRConnector *drc;
>      sPAPRDRConnectorClass *drck;
>      int drc_index;
> @@ -495,8 +496,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
>  
>      _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs));
>  
> -    _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
> -                                ppc_get_compat_smt_threads(cpu)));
> +    _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
>  }
>  
>  static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> index f3fd9c6..66529a6 100644
> --- a/target-ppc/compat.c
> +++ b/target-ppc/compat.c
> @@ -28,6 +28,7 @@
>  typedef struct {
>      uint32_t pvr;
>      uint64_t pcr;
> +    int max_threads;
>  } CompatInfo;
>  
>  static const CompatInfo compat_table[] = {
> @@ -35,18 +36,22 @@ static const CompatInfo compat_table[] = {
>          .pvr = CPU_POWERPC_LOGICAL_2_05,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
>                 | PCR_TM_DIS | PCR_VSX_DIS,
> +        .max_threads = 2,
>      },
>      { /* POWER7, ISA2.06 */
>          .pvr = CPU_POWERPC_LOGICAL_2_06,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> +        .max_threads = 4,
>      },
>      {
>          .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> +        .max_threads = 4,
>      },
>      { /* POWER8, ISA2.07 */
>          .pvr = CPU_POWERPC_LOGICAL_2_07,
>          .pcr = PCR_COMPAT_2_07,
> +        .max_threads = 8,
>      },
>  };
>  
> @@ -89,3 +94,16 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>          }
>      }
>  }
> +
> +int ppc_compat_max_threads(PowerPCCPU *cpu)
> +{
> +    const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
> +    int n_threads = CPU(cpu)->nr_threads;
> +
> +    if (cpu->compat_pvr) {
> +        g_assert(compat);
> +        n_threads = MIN(n_threads, compat->max_threads);
> +    }
> +
> +    return n_threads;
> +}
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index 15d5e4b..cfda7b2 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -1241,7 +1241,6 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
>  void ppc_store_msr (CPUPPCState *env, target_ulong value);
>  
>  void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
> -int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
>  #if defined(TARGET_PPC64)
>  #endif
>  
> @@ -1316,6 +1315,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
>  /* Compatibility modes */
>  #if defined(TARGET_PPC64)
>  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> +int ppc_compat_max_threads(PowerPCCPU *cpu);
>  #endif /* defined(TARGET_PPC64) */
>  
>  #include "exec/cpu-all.h"
> diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> index a70eafb..ba48242 100644
> --- a/target-ppc/translate_init.c
> +++ b/target-ppc/translate_init.c
> @@ -9952,26 +9952,6 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp)
>      }
>  }
>  
> -int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
> -{
> -    CPUState *cs = CPU(cpu);
> -    int ret = MIN(cs->nr_threads, kvmppc_smt_threads());
> -
> -    switch (cpu->compat_pvr) {
> -    case CPU_POWERPC_LOGICAL_2_05:
> -        ret = MIN(ret, 2);
> -        break;
> -    case CPU_POWERPC_LOGICAL_2_06:
> -        ret = MIN(ret, 4);
> -        break;
> -    case CPU_POWERPC_LOGICAL_2_07:
> -        ret = MIN(ret, 8);
> -        break;
> -    }
> -
> -    return ret;
> -}
> -
>  static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
>  {
>      ObjectClass *oc = (ObjectClass *)a;
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting
  2016-10-31  8:39     ` David Gibson
@ 2016-11-04  3:45       ` Alexey Kardashevskiy
  2016-11-08  5:14         ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  3:45 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On 31/10/16 19:39, David Gibson wrote:
> On Mon, Oct 31, 2016 at 04:55:42PM +1100, Alexey Kardashevskiy wrote:
>> On 30/10/16 22:12, David Gibson wrote:
>>> Current ppc_set_compat() will attempt to set any compatiblity mode
>>> specified, regardless of whether it's available on the CPU.  The caller is
>>> expected to make sure it is setting a possible mode, which is awkwward
>>> because most of the information to make that decision is at the CPU level.
>>>
>>> This begins to clean this up by introducing a ppc_check_compat() function
>>> which will determine if a given compatiblity mode is supported on a CPU
>>> (and also whether it lies within specified minimum and maximum compat
>>> levels, which will be useful later).  It also contains an assertion that
>>> the CPU has a "virtual hypervisor"[1], that is, that the guest isn't
>>> permitted to execute hypervisor privilege code.  Without that, the guest
>>> would own the PCR and so could override any mode set here.  Only machine
>>> types which use a virtual hypervisor (i.e. 'pseries') should use
>>> ppc_check_compat().
>>>
>>> ppc_set_compat() is modified to validate the compatibility mode it is given
>>> and fail if it's not available on this CPU.
>>>
>>> [1] Or user-only mode, which also obviously doesn't allow access to the
>>> hypervisor privileged PCR.  We don't use that now, but could in future.
>>>
>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
>>> ---
>>>  target-ppc/compat.c | 41 +++++++++++++++++++++++++++++++++++++++++
>>>  target-ppc/cpu.h    |  2 ++
>>>  2 files changed, 43 insertions(+)
>>>
>>> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
>>> index 66529a6..1059555 100644
>>> --- a/target-ppc/compat.c
>>> +++ b/target-ppc/compat.c
>>> @@ -28,29 +28,37 @@
>>>  typedef struct {
>>>      uint32_t pvr;
>>>      uint64_t pcr;
>>> +    uint64_t pcr_level;
>>>      int max_threads;
>>>  } CompatInfo;
>>>  
>>>  static const CompatInfo compat_table[] = {
>>> +    /*
>>> +     * Ordered from oldest to newest - the code relies on this

In last 5+ years, I have never seen pointer compared anyhow but using "=="
and "!=". A bit unusual.


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





>>> +     */
>>>      { /* POWER6, ISA2.05 */
>>>          .pvr = CPU_POWERPC_LOGICAL_2_05,
>>>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
>>>                 | PCR_TM_DIS | PCR_VSX_DIS,
>>> +        .pcr_level = PCR_COMPAT_2_05,
>>>          .max_threads = 2,
>>>      },
>>>      { /* POWER7, ISA2.06 */
>>>          .pvr = CPU_POWERPC_LOGICAL_2_06,
>>>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
>>> +        .pcr_level = PCR_COMPAT_2_06,
>>>          .max_threads = 4,
>>>      },
>>>      {
>>>          .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
>>>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
>>> +        .pcr_level = PCR_COMPAT_2_06,
>>>          .max_threads = 4,
>>>      },
>>>      { /* POWER8, ISA2.07 */
>>>          .pvr = CPU_POWERPC_LOGICAL_2_07,
>>>          .pcr = PCR_COMPAT_2_07,
>>> +        .pcr_level = PCR_COMPAT_2_07,
>>>          .max_threads = 8,
>>>      },
>>>  };
>>> @@ -67,6 +75,35 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr)
>>>      return NULL;
>>>  }
>>>  
>>> +bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
>>> +                      uint32_t min_compat_pvr, uint32_t max_compat_pvr)
>>> +{
>>> +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
>>> +    const CompatInfo *compat = compat_by_pvr(compat_pvr);
>>> +    const CompatInfo *min = compat_by_pvr(min_compat_pvr);
>>> +    const CompatInfo *max = compat_by_pvr(max_compat_pvr);
>>
>>
>> You keep giving very generic names (as "min" and "max") to local
>> variables ;)
> 
> For local variables, brevity is a virtue.





-- 
Alexey


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 839 bytes --]

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

* Re: [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all()
  2016-10-30 11:12 ` [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all() David Gibson
@ 2016-11-04  4:01   ` Alexey Kardashevskiy
  2016-11-08  5:18     ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  4:01 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:12, David Gibson wrote:
> Once a compatiblity mode is negotiated with the guest,
> h_client_architecture_support() uses run_on_cpu() to update each CPU to
> the new mode.  We're going to want this logic somewhere else shortly,
> so make a helper function to do this global update.
> 
> We put it in target-ppc/compat.c - it makes as much sense at the CPU level
> as it does at the machine level.  We also move the cpu_synchronize_state()
> into ppc_set_compat(), since it doesn't really make any sense to call that
> without synchronizing state.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr_hcall.c | 31 +++++--------------------------
>  target-ppc/compat.c  | 36 ++++++++++++++++++++++++++++++++++++
>  target-ppc/cpu.h     |  3 +++
>  3 files changed, 44 insertions(+), 26 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 3bd6d06..4eaf9a6 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -881,20 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>      return ret;
>  }
>  
> -typedef struct {
> -    uint32_t compat_pvr;
> -    Error *err;
> -} SetCompatState;
> -
> -static void do_set_compat(CPUState *cs, void *arg)
> -{
> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> -    SetCompatState *s = arg;
> -
> -    cpu_synchronize_state(cs);
> -    ppc_set_compat(cpu, s->compat_pvr, &s->err);
> -}
> -
>  static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>                                                    sPAPRMachineState *spapr,
>                                                    target_ulong opcode,
> @@ -902,7 +888,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>  {
>      target_ulong list = ppc64_phys_to_real(args[0]);
>      target_ulong ov_table;
> -    CPUState *cs;
>      bool explicit_match = false; /* Matched the CPU's real PVR */
>      uint32_t max_compat = cpu->max_compat;
>      uint32_t best_compat = 0;
> @@ -949,18 +934,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>  
>      /* Update CPUs */
>      if (cpu->compat_pvr != best_compat) {
> -        CPU_FOREACH(cs) {
> -            SetCompatState s = {
> -                .compat_pvr = best_compat,
> -                .err = NULL,
> -            };
> +        Error *local_err = NULL;
>  
> -            run_on_cpu(cs, do_set_compat, &s);
> -
> -            if (s.err) {
> -                error_report_err(s.err);
> -                return H_HARDWARE;
> -            }
> +        ppc_set_compat_all(best_compat, &local_err);
> +        if (local_err) {
> +            error_report_err(local_err);
> +            return H_HARDWARE;
>          }
>      }
>  
> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> index 1059555..0b12b58 100644
> --- a/target-ppc/compat.c
> +++ b/target-ppc/compat.c
> @@ -124,6 +124,8 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>          pcr = compat->pcr;
>      }
>  
> +    cpu_synchronize_state(CPU(cpu));
> +
>      cpu->compat_pvr = compat_pvr;
>      env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
>  
> @@ -136,6 +138,40 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>      }
>  }
>  
> +#if !defined(CONFIG_USER_ONLY)
> +typedef struct {
> +    uint32_t compat_pvr;
> +    Error *err;
> +} SetCompatState;
> +
> +static void do_set_compat(CPUState *cs, void *arg)
> +{
> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> +    SetCompatState *s = arg;
> +
> +    ppc_set_compat(cpu, s->compat_pvr, &s->err);
> +}
> +
> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
> +{
> +    CPUState *cs;
> +
> +    CPU_FOREACH(cs) {
> +        SetCompatState s = {
> +            .compat_pvr = compat_pvr,
> +            .err = NULL,
> +        };
> +
> +        run_on_cpu(cs, do_set_compat, &s);
> +
> +        if (s.err) {
> +            error_propagate(errp, s.err);
> +            return;
> +        }
> +    }
> +}
> +#endif
> +
>  int ppc_compat_max_threads(PowerPCCPU *cpu)
>  {
>      const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index 91e8be8..201a655 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -1317,6 +1317,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
>  bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
>                        uint32_t min_compat_pvr, uint32_t max_compat_pvr);
>  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> +#if !defined(CONFIG_USER_ONLY)
> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
> +#endif

I would put all ppc*compat*() under #if defined(CONFIG_USER_ONLY) &&
defined(TARGET_PPC64) (or even moved this to target-ppc/Makefile.objs).
Otherwise, functions like ppc_check_compat() have #if
!defined(CONFIG_USER_ONLY) which suggests that the rest of
ppc_check_compat() can actually be executed in ppc64-linux-user (while it
cannot, can it?).




>  int ppc_compat_max_threads(PowerPCCPU *cpu);
>  #endif /* defined(TARGET_PPC64) */
>  
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration
  2016-10-30 11:12 ` [Qemu-devel] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration David Gibson
@ 2016-11-04  5:52   ` Alexey Kardashevskiy
  2016-11-08  5:31     ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  5:52 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:12, David Gibson wrote:
> When vmstate for the ppc cpu was introduced in a90db158 "target-ppc:
> Convert ppc cpu savevm to VMStateDescription", several "sanity check"
> fields were included, verifying that certain cpu parameters matched between
> source and destination.
> 
> This turns out not to have been a good idea.  For one thing it's redundant
> with existing checks for a compatible cpu version at either end.  But more
> importantly the insns_flags and insns_flags2 checks actively break things:
> they expose what's essentially an internal TCG implementation detail in the
> migration stream.  That means that when new instruction classes are added
> or rearranged, migration can break.
> 
> This removes these ill-considered sanity checks.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  target-ppc/machine.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> index 62b9e94..453ef0a 100644
> --- a/target-ppc/machine.c
> +++ b/target-ppc/machine.c
> @@ -602,10 +602,10 @@ const VMStateDescription vmstate_ppc_cpu = {
>          /* FIXME: access_type? */
>  
>          /* Sanity checking */
> -        VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU),
> -        VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU),
> -        VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU),
> -        VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU),
> +        VMSTATE_UNUSED(sizeof(target_ulong) /* msr_mask */
> +                       + sizeof(uint64_t) /* insns_flags */
> +                       + sizeof(uint64_t) /* insns_flags2 */
> +                       + sizeof(uint32_t)), /* nb_BATs */


This breaks migration to older QEMU:

25055@1478238734.537761:vmstate_load_field_error field "env.msr_mask" load
failed, ret = -22



>          VMSTATE_END_OF_LIST()
>      },
>      .subsections = (const VMStateDescription*[]) {
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode
  2016-10-30 11:12 ` [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode David Gibson
@ 2016-11-04  5:58   ` Alexey Kardashevskiy
  2016-11-08  5:19     ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  5:58 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:12, David Gibson wrote:
> Server-class POWER CPUs can be put into several compatibility modes.  These
> can be specified on the command line, or negotiated by the guest during
> boot.
> 
> Currently we don't migrate the compatibility mode, which means after a
> migration the guest will revert to running with whatever compatibility
> mode (or none) specified on the command line.
> 
> With the limited range of CPUs currently used, this doesn't usually cause
> a problem, but it could.  Fix this by adding the compatibility mode (if
> set) to the migration stream.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  target-ppc/machine.c | 34 ++++++++++++++++++++++++++++++++++
>  1 file changed, 34 insertions(+)
> 
> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> index 4820f22..5d87ff6 100644
> --- a/target-ppc/machine.c
> +++ b/target-ppc/machine.c
> @@ -9,6 +9,7 @@
>  #include "mmu-hash64.h"
>  #include "migration/cpu.h"
>  #include "exec/exec-all.h"
> +#include "qapi/error.h"
>  
>  static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
>  {
> @@ -176,6 +177,20 @@ static int cpu_post_load(void *opaque, int version_id)
>       * software has to take care of running QEMU in a compatible mode.
>       */
>      env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
> +
> +#if defined(TARGET_PPC64)
> +    if (cpu->compat_pvr) {
> +        Error *local_err = NULL;
> +
> +        ppc_set_compat(cpu, cpu->compat_pvr, &local_err);
> +        if (local_err) {
> +            error_report_err(local_err);
> +            error_free(local_err);
> +            return -1;
> +        }
> +    }
> +#endif
> +
>      env->lr = env->spr[SPR_LR];
>      env->ctr = env->spr[SPR_CTR];
>      cpu_write_xer(env, env->spr[SPR_XER]);
> @@ -528,6 +543,24 @@ static const VMStateDescription vmstate_tlbmas = {
>      }
>  };
>  
> +static bool compat_needed(void *opaque)
> +{
> +    PowerPCCPU *cpu = opaque;
> +
> +    return cpu->compat_pvr != 0;


Finally got to trying how this affects migration :)

This breaks migration to QEMU <=2.7, and it should not at least when both
source and destination are running with  -cpu host,compat=power7.


> +}
> +
> +static const VMStateDescription vmstate_compat = {
> +    .name = "cpu/compat",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = compat_needed,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(compat_pvr, PowerPCCPU),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  const VMStateDescription vmstate_ppc_cpu = {
>      .name = "cpu",
>      .version_id = 5,
> @@ -580,6 +613,7 @@ const VMStateDescription vmstate_ppc_cpu = {
>          &vmstate_tlb6xx,
>          &vmstate_tlbemb,
>          &vmstate_tlbmas,
> +        &vmstate_compat,
>          NULL
>      }
>  };
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine
  2016-10-30 11:12 ` [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine David Gibson
@ 2016-11-04  7:43   ` Alexey Kardashevskiy
  2016-11-08  5:26     ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  7:43 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:12, David Gibson wrote:
> Server class POWER CPUs have a "compat" property, which is used to set the
> backwards compatibility mode for the processor.  However, this only makes
> sense for machine types which don't give the guest access to hypervisor
> privilege - otherwise the compatibility level is under the guest's control.
> 
> To reflect this, this removes the CPU 'compat' property and instead
> creates a 'max-cpu-compat' property on the pseries machine.  Strictly
> speaking this breaks compatibility, but AFAIK the 'compat' option was
> never (directly) used with -device or device_add.
> 
> The option was used with -cpu.  So, to maintain compatibility, this patch
> adds a hack to the cpu option parsing to strip out any compat options
> supplied with -cpu and set them on the machine property instead of the new
> removed cpu property.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr.c              |  6 +++-
>  hw/ppc/spapr_cpu_core.c     | 47 +++++++++++++++++++++++++++--
>  hw/ppc/spapr_hcall.c        |  2 +-
>  include/hw/ppc/spapr.h      | 10 +++++--
>  target-ppc/compat.c         | 65 ++++++++++++++++++++++++++++++++++++++++
>  target-ppc/cpu.h            |  6 ++--
>  target-ppc/translate_init.c | 73 ---------------------------------------------
>  7 files changed, 127 insertions(+), 82 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index 6c78889..b983faa 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1849,7 +1849,7 @@ static void ppc_spapr_init(MachineState *machine)
>          machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu;
>      }
>  
> -    ppc_cpu_parse_features(machine->cpu_model);
> +    spapr_cpu_parse_features(spapr);
>  
>      spapr_init_cpus(spapr);
>  
> @@ -2191,6 +2191,10 @@ static void spapr_machine_initfn(Object *obj)
>                                      " place of standard EPOW events when possible"
>                                      " (required for memory hot-unplug support)",
>                                      NULL);
> +
> +    object_property_add(obj, "max-cpu-compat", "str",
> +                        ppc_compat_prop_get, ppc_compat_prop_set,
> +                        NULL, &spapr->max_compat_pvr, &error_fatal);
>  }
>  
>  static void spapr_machine_finalizefn(Object *obj)
> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> index ee5cd14..0319516 100644
> --- a/hw/ppc/spapr_cpu_core.c
> +++ b/hw/ppc/spapr_cpu_core.c
> @@ -18,6 +18,49 @@
>  #include "target-ppc/mmu-hash64.h"
>  #include "sysemu/numa.h"
>  
> +void spapr_cpu_parse_features(sPAPRMachineState *spapr)
> +{
> +    /*
> +     * Backwards compatibility hack:
> +
> +     *   CPUs had a "compat=" property which didn't make sense for
> +     *   anything except pseries.  It was replaced by "max-cpu-compat"
> +     *   machine option.  This supports old command lines like
> +     *       -cpu POWER8,compat=power7
> +     *   By stripping the compat option and applying it to the machine
> +     *   before passing it on to the cpu level parser.
> +     */
> +    gchar **inpieces, **outpieces;
> +    int n, i, j;
> +    gchar *compat_str = NULL;
> +    gchar *filtered_model;
> +
> +    inpieces = g_strsplit(MACHINE(spapr)->cpu_model, ",", 0);
> +    n = g_strv_length(inpieces);
> +    outpieces = g_new0(gchar *, g_strv_length(inpieces));
> +
> +    /* inpieces[0] is the actual model string */
> +    for (i = 0, j = 0; i < n; i++) {
> +        if (g_str_has_prefix(inpieces[i], "compat=")) {
> +            compat_str = inpieces[i];
> +        } else {
> +            outpieces[j++] = g_strdup(inpieces[i]);
> +        }
> +    }
> +
> +    if (compat_str) {
> +        char *val = compat_str + strlen("compat=");
> +        object_property_set_str(OBJECT(spapr), val, "max-cpu-compat",
> +                                &error_fatal);

This part is ok.

> +    }
> +
> +    filtered_model = g_strjoinv(",", outpieces);
> +    ppc_cpu_parse_features(filtered_model);


Rather than reducing the CPU parameters string from the command line, I'd
keep "dc->props = powerpc_servercpu_properties" and make them noop + warn
to use the machine option instead. One day QEMU may start calling the CPU
features parser itself and somebody will have to hack this thing again.


> +
> +    g_strfreev(inpieces);
> +    g_strfreev(outpieces);
> +}
> +
>  static void spapr_cpu_reset(void *opaque)
>  {
>      sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
> @@ -60,10 +103,10 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
>      cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
>      cpu_ppc_set_papr(cpu);
>  
> -    if (cpu->max_compat) {
> +    if (spapr->max_compat_pvr) {
>          Error *local_err = NULL;
>  
> -        ppc_set_compat(cpu, cpu->max_compat, &local_err);
> +        ppc_set_compat(cpu, spapr->max_compat_pvr, &local_err);
>          if (local_err) {
>              error_propagate(errp, local_err);
>              return;
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index 4eaf9a6..5efa57f 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -889,7 +889,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>      target_ulong list = ppc64_phys_to_real(args[0]);
>      target_ulong ov_table;
>      bool explicit_match = false; /* Matched the CPU's real PVR */
> -    uint32_t max_compat = cpu->max_compat;
> +    uint32_t max_compat = spapr->max_compat_pvr;
>      uint32_t best_compat = 0;
>      int i;
>      sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
> diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> index 04d2821..d2a40e9 100644
> --- a/include/hw/ppc/spapr.h
> +++ b/include/hw/ppc/spapr.h
> @@ -74,15 +74,18 @@ struct sPAPRMachineState {
>      uint64_t rtc_offset; /* Now used only during incoming migration */
>      struct PPCTimebase tb;
>      bool has_graphics;
> -    sPAPROptionVector *ov5;         /* QEMU-supported option vectors */
> -    sPAPROptionVector *ov5_cas;     /* negotiated (via CAS) option vectors */
> -    bool cas_reboot;
>  
>      Notifier epow_notifier;
>      QTAILQ_HEAD(, sPAPREventLogEntry) pending_events;
>      bool use_hotplug_event_source;
>      sPAPREventSource *event_sources;
>  
> +    /* ibm,client-architecture-support option negotiation */
> +    bool cas_reboot;
> +    sPAPROptionVector *ov5;         /* QEMU-supported option vectors */
> +    sPAPROptionVector *ov5_cas;     /* negotiated (via CAS) option vectors */
> +    uint32_t max_compat_pvr;
> +

Nit: 3 of 5 lines were just moved while you could just add max_compat_pvr
and the comment before ov5. QEMU already has too many patches moving lines
around, sometime it is getting annoying while browsing with git blame.



>      /* Migration state */
>      int htab_save_index;
>      bool htab_first_pass;
> @@ -613,6 +616,7 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
>                                              uint32_t count, uint32_t index);
>  void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
>                                                 uint32_t count, uint32_t index);
> +void spapr_cpu_parse_features(sPAPRMachineState *spapr);
>  void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
>                                      sPAPRMachineState *spapr);
>  
> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> index 0b12b58..c3ae52d 100644
> --- a/target-ppc/compat.c
> +++ b/target-ppc/compat.c
> @@ -23,9 +23,11 @@
>  #include "sysemu/cpus.h"
>  #include "qemu/error-report.h"
>  #include "qapi/error.h"
> +#include "qapi/visitor.h"
>  #include "cpu-models.h"
>  
>  typedef struct {
> +    const char *name;
>      uint32_t pvr;
>      uint64_t pcr;
>      uint64_t pcr_level;
> @@ -37,6 +39,7 @@ static const CompatInfo compat_table[] = {
>       * Ordered from oldest to newest - the code relies on this
>       */
>      { /* POWER6, ISA2.05 */
> +        .name = "power6",
>          .pvr = CPU_POWERPC_LOGICAL_2_05,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
>                 | PCR_TM_DIS | PCR_VSX_DIS,
> @@ -44,18 +47,21 @@ static const CompatInfo compat_table[] = {
>          .max_threads = 2,
>      },
>      { /* POWER7, ISA2.06 */
> +        .name = "power7",
>          .pvr = CPU_POWERPC_LOGICAL_2_06,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
>          .pcr_level = PCR_COMPAT_2_06,
>          .max_threads = 4,
>      },
>      {
> +        .name = "power7+",
>          .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
>          .pcr_level = PCR_COMPAT_2_06,
>          .max_threads = 4,
>      },
>      { /* POWER8, ISA2.07 */
> +        .name = "power8",
>          .pvr = CPU_POWERPC_LOGICAL_2_07,
>          .pcr = PCR_COMPAT_2_07,
>          .pcr_level = PCR_COMPAT_2_07,
> @@ -184,3 +190,62 @@ int ppc_compat_max_threads(PowerPCCPU *cpu)
>  
>      return n_threads;
>  }
> +
> +void ppc_compat_prop_get(Object *obj, Visitor *v, const char *name,
> +                         void *opaque, Error **errp)
> +{
> +    uint32_t compat_pvr = *((uint32_t *)opaque);
> +    const char *value;
> +
> +    if (!compat_pvr) {
> +        value = "";
> +    } else {
> +        const CompatInfo *compat = compat_by_pvr(compat_pvr);
> +
> +        g_assert(compat);
> +
> +        value = compat->name;
> +    }
> +
> +    visit_type_str(v, name, (char **)&value, errp);
> +}
> +
> +void ppc_compat_prop_set(Object *obj, Visitor *v, const char *name,
> +                         void *opaque, Error **errp)
> +{
> +    Error *error = NULL;
> +    char *value;
> +    uint32_t compat_pvr;
> +
> +    visit_type_str(v, name, &value, &error);
> +    if (error) {
> +        error_propagate(errp, error);
> +        return;
> +    }
> +
> +    if (strcmp(value, "") == 0) {
> +        compat_pvr = 0;
> +    } else {
> +        int i;
> +        const CompatInfo *compat = NULL;
> +
> +        for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
> +            if (strcmp(value, compat_table[i].name) == 0) {
> +                compat = &compat_table[i];
> +                break;
> +
> +            }
> +        }
> +
> +        if (!compat) {
> +            error_setg(errp, "Invalid compatibility mode \"%s\"", value);
> +            goto out;
> +        }
> +        compat_pvr = compat->pvr;
> +    }
> +
> +    *((uint32_t *)opaque) = compat_pvr;
> +
> +out:
> +    g_free(value);
> +}
> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> index 201a655..51d21bb 100644
> --- a/target-ppc/cpu.h
> +++ b/target-ppc/cpu.h
> @@ -1155,7 +1155,6 @@ typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
>   * PowerPCCPU:
>   * @env: #CPUPPCState
>   * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
> - * @max_compat: Maximal supported logical PVR from the command line
>   * @compat_pvr: Current logical PVR, zero if in "raw" mode
>   *
>   * A PowerPC CPU.
> @@ -1167,7 +1166,6 @@ struct PowerPCCPU {
>  
>      CPUPPCState env;
>      int cpu_dt_id;
> -    uint32_t max_compat;
>      uint32_t compat_pvr;
>      PPCVirtualHypervisor *vhyp;
>  };
> @@ -1321,6 +1319,10 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
>  void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
>  #endif
>  int ppc_compat_max_threads(PowerPCCPU *cpu);
> +void ppc_compat_prop_get(Object *obj, Visitor *v,
> +                         const char *name, void *opaque, Error **err);
> +void ppc_compat_prop_set(Object *obj, Visitor *v,
> +                         const char *name, void *opaque, Error **err);
>  #endif /* defined(TARGET_PPC64) */
>  
>  #include "exec/cpu-all.h"
> diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> index ba48242..40abd23 100644
> --- a/target-ppc/translate_init.c
> +++ b/target-ppc/translate_init.c
> @@ -8428,76 +8428,6 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
>      pcc->l1_icache_size = 0x10000;
>  }
>  
> -static void powerpc_get_compat(Object *obj, Visitor *v, const char *name,
> -                               void *opaque, Error **errp)
> -{
> -    char *value = (char *)"";
> -    Property *prop = opaque;
> -    uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
> -
> -    switch (*max_compat) {
> -    case CPU_POWERPC_LOGICAL_2_05:
> -        value = (char *)"power6";
> -        break;
> -    case CPU_POWERPC_LOGICAL_2_06:
> -        value = (char *)"power7";
> -        break;
> -    case CPU_POWERPC_LOGICAL_2_07:
> -        value = (char *)"power8";
> -        break;
> -    case 0:
> -        break;
> -    default:
> -        error_report("Internal error: compat is set to %x", *max_compat);
> -        abort();
> -        break;
> -    }
> -
> -    visit_type_str(v, name, &value, errp);
> -}
> -
> -static void powerpc_set_compat(Object *obj, Visitor *v, const char *name,
> -                               void *opaque, Error **errp)
> -{
> -    Error *error = NULL;
> -    char *value = NULL;
> -    Property *prop = opaque;
> -    uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
> -
> -    visit_type_str(v, name, &value, &error);
> -    if (error) {
> -        error_propagate(errp, error);
> -        return;
> -    }
> -
> -    if (strcmp(value, "power6") == 0) {
> -        *max_compat = CPU_POWERPC_LOGICAL_2_05;
> -    } else if (strcmp(value, "power7") == 0) {
> -        *max_compat = CPU_POWERPC_LOGICAL_2_06;
> -    } else if (strcmp(value, "power8") == 0) {
> -        *max_compat = CPU_POWERPC_LOGICAL_2_07;
> -    } else {
> -        error_setg(errp, "Invalid compatibility mode \"%s\"", value);
> -    }
> -
> -    g_free(value);
> -}
> -
> -static PropertyInfo powerpc_compat_propinfo = {
> -    .name = "str",
> -    .description = "compatibility mode, power6/power7/power8",
> -    .get = powerpc_get_compat,
> -    .set = powerpc_set_compat,
> -};
> -
> -#define DEFINE_PROP_POWERPC_COMPAT(_n, _s, _f) \
> -    DEFINE_PROP(_n, _s, _f, powerpc_compat_propinfo, uint32_t)
> -
> -static Property powerpc_servercpu_properties[] = {
> -    DEFINE_PROP_POWERPC_COMPAT("compat", PowerPCCPU, max_compat),
> -    DEFINE_PROP_END_OF_LIST(),
> -};
> -
>  #ifdef CONFIG_SOFTMMU
>  static const struct ppc_segment_page_sizes POWER7_POWER8_sps = {
>      .sps = {
> @@ -8586,7 +8516,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
>  
>      dc->fw_name = "PowerPC,POWER7";
>      dc->desc = "POWER7";
> -    dc->props = powerpc_servercpu_properties;
>      pcc->pvr_match = ppc_pvr_match_power7;
>      pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
>      pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> @@ -8713,7 +8642,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
>  
>      dc->fw_name = "PowerPC,POWER8";
>      dc->desc = "POWER8";
> -    dc->props = powerpc_servercpu_properties;
>      pcc->pvr_match = ppc_pvr_match_power8;
>      pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
>      pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> @@ -8794,7 +8722,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
>  
>      dc->fw_name = "PowerPC,POWER9";
>      dc->desc = "POWER9";
> -    dc->props = powerpc_servercpu_properties;
>      pcc->pvr_match = ppc_pvr_match_power9;
>      pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
>      pcc->init_proc = init_proc_POWER9;
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 14/17] pseries: Reset CPU compatibility mode
  2016-10-30 11:12 ` [Qemu-devel] [RFC 14/17] pseries: Reset CPU compatibility mode David Gibson
@ 2016-11-04  7:50   ` Alexey Kardashevskiy
  0 siblings, 0 replies; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  7:50 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:12, David Gibson wrote:
> Currently, the CPU compatibility mode is set when the cpu is initialized,
> then again when the guest negotiates features.  This means if a guest
> negotiates a compatibility mode, then reboots, that compatibility mode
> will be retained across the reset.
> 
> Usually that will get overridden when features are negotiated on the next
> boot, but it's still not really correct.  This patch moves the initial set
> up of the compatibility mode from cpu init to reset time.  The mode *is*
> retained if the reboot was caused by the feature negotiation (it might
> be important in that case, though it's unlikely).
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

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

> ---
>  hw/ppc/spapr.c          |  2 ++
>  hw/ppc/spapr_cpu_core.c | 10 ----------
>  2 files changed, 2 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> index b983faa..2aa0900 100644
> --- a/hw/ppc/spapr.c
> +++ b/hw/ppc/spapr.c
> @@ -1169,6 +1169,8 @@ static void ppc_spapr_reset(void)
>      if (!spapr->cas_reboot) {
>          spapr_ovec_cleanup(spapr->ov5_cas);
>          spapr->ov5_cas = spapr_ovec_new();
> +
> +        ppc_set_compat_all(spapr->max_compat_pvr, &error_abort);
>      }
>  
>      fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size);
> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> index 0319516..4b6134b 100644
> --- a/hw/ppc/spapr_cpu_core.c
> +++ b/hw/ppc/spapr_cpu_core.c
> @@ -103,16 +103,6 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
>      cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
>      cpu_ppc_set_papr(cpu);
>  
> -    if (spapr->max_compat_pvr) {
> -        Error *local_err = NULL;
> -
> -        ppc_set_compat(cpu, spapr->max_compat_pvr, &local_err);
> -        if (local_err) {
> -            error_propagate(errp, local_err);
> -            return;
> -        }
> -    }
> -
>      /* Set NUMA node for the added CPUs  */
>      i = numa_get_node_for_cpu(cs->cpu_index);
>      if (i < nb_numa_nodes) {
> 


-- 
Alexey

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

* Re: [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration
  2016-10-30 11:12 ` [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration David Gibson
@ 2016-11-04  7:54   ` Alexey Kardashevskiy
  2016-11-08  5:29     ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-04  7:54 UTC (permalink / raw)
  To: David Gibson, nikunj, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

On 30/10/16 22:12, David Gibson wrote:
> When a vmstate for the ppc cpu was first introduced (a90db15 "target-ppc:
> Convert ppc cpu savevm to VMStateDescription"), a VMSTATE_EQUAL was used
> to ensure that identical CPU models were used at source and destination
> as based on the PVR (Processor Version Register).
> 
> However this was a problem for HV KVM, where due to hardware limitations
> we always need to use the real PVR of the host CPU.  So, to allow
> migration between hosts with "similar enough" CPUs, the PVR check was
> removed in 569be9f0 "target-ppc: Remove PVR check from migration".  This
> left the onus on user / management to only attempt migration between
> compatible CPUs.
> 
> Now that we've reworked the handling of compatiblity modes, we have the
> information to actually determine if we're making a compatible migration.
> So this patch partially restores the PVR check.  If the source was running
> in a compatibility mode, we just make sure that the destination cpu can
> also run in that compatibility mode.  However, if the source was running
> in "raw" mode, we verify that the destination has the same PVR value.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  target-ppc/machine.c | 15 +++++++++++----
>  1 file changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> index 5d87ff6..62b9e94 100644
> --- a/target-ppc/machine.c
> +++ b/target-ppc/machine.c
> @@ -173,10 +173,12 @@ static int cpu_post_load(void *opaque, int version_id)
>      target_ulong msr;
>  
>      /*
> -     * We always ignore the source PVR. The user or management
> -     * software has to take care of running QEMU in a compatible mode.
> +     * If we're operating in compat mode, we should be ok as long as
> +     * the destination supports the same compatiblity mode.
> +     *
> +     * Otherwise, however, we require that the destination has exactly
> +     * the same CPU model as the source.
>       */
> -    env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
>  
>  #if defined(TARGET_PPC64)
>      if (cpu->compat_pvr) {
> @@ -188,8 +190,13 @@ static int cpu_post_load(void *opaque, int version_id)
>              error_free(local_err);
>              return -1;
>          }
> -    }
> +    } else
>  #endif
> +    {
> +        if (env->spr[SPR_PVR] != env->spr_cb[SPR_PVR].default_value) {
> +            return -1;
> +        }
> +    }

This should break migration from host with PVR=004d0200 to host with
PVR=004d0201, what is the benefit of such limitation?


>  
>      env->lr = env->spr[SPR_LR];
>      env->ctr = env->spr[SPR_CTR];
> 


-- 
Alexey

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

* Re: [Qemu-devel] [Qemu-ppc] [RFC 03/17] pseries: Always use core objects for CPU construction
  2016-11-03  8:11   ` Alexey Kardashevskiy
@ 2016-11-04  9:51     ` Greg Kurz
  2016-11-08  5:34       ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Greg Kurz @ 2016-11-04  9:51 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: David Gibson, nikunj, mdroth, lvivier, thuth, qemu-ppc, qemu-devel

On Thu, 3 Nov 2016 19:11:48 +1100
Alexey Kardashevskiy <aik@ozlabs.ru> wrote:

> On 30/10/16 22:11, David Gibson wrote:
> > Currently the pseries machine has two paths for constructing CPUs.  On
> > newer machine type versions, which support cpu hotplug, it constructs
> > cpu core objects, which in turn construct CPU threads.  For older machine
> > versions it individually constructs the CPU threads.
> > 
> > This division is going to make some future changes to the cpu construction
> > harder, so this patch unifies them.  Now cpu core objects are always
> > created.  This requires some updates to allow core objects to be created
> > without a full complement of threads (since older versions allowed a
> > number of cpus not a multiple of the threads-per-core).  Likewise it needs
> > some changes to the cpu core hot/cold plug path so as not to choke on the
> > old machine types without hotplug support.
> > 
> > For good measure, we move the cpu construction to its own subfunction,
> > spapr_init_cpus().
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr.c          | 125 +++++++++++++++++++++++++++---------------------
> >  hw/ppc/spapr_cpu_core.c |  30 +++++++-----
> >  include/hw/ppc/spapr.h  |   1 -
> >  3 files changed, 89 insertions(+), 67 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> > index c8e2921..ad68a9d 100644
> > --- a/hw/ppc/spapr.c
> > +++ b/hw/ppc/spapr.c
> > @@ -1688,11 +1688,80 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp)
> >      }
> >  }
> >  
> > +static void spapr_init_cpus(sPAPRMachineState *spapr)
> > +{
> > +    MachineState *machine = MACHINE(spapr);
> > +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> > +    char *type = spapr_get_cpu_core_type(machine->cpu_model);
> > +    int smt = kvmppc_smt_threads();
> > +    int spapr_max_cores, spapr_cores;
> > +    int i;
> > +
> > +    if (!type) {
> > +        error_report("Unable to find sPAPR CPU Core definition");
> > +        exit(1);
> > +    }
> > +
> > +    if (mc->query_hotpluggable_cpus) {
> > +        if (smp_cpus % smp_threads) {
> > +            error_report("smp_cpus (%u) must be multiple of threads (%u)",
> > +                         smp_cpus, smp_threads);
> > +            exit(1);
> > +        }
> > +        if (max_cpus % smp_threads) {
> > +            error_report("max_cpus (%u) must be multiple of threads (%u)",
> > +                         max_cpus, smp_threads);
> > +            exit(1);
> > +        }
> > +
> > +        spapr_max_cores = max_cpus / smp_threads;
> > +        spapr_cores = smp_cpus / smp_threads;
> > +    } else {
> > +        if (max_cpus != smp_cpus) {
> > +            error_report("This machine version does not support CPU hotplug");
> > +            exit(1);
> > +        }
> > +
> > +        spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
> > +        spapr_cores = spapr_max_cores;
> > +    }
> > +
> > +    spapr->cores = g_new0(Object *, spapr_max_cores);
> > +    for (i = 0; i < spapr_max_cores; i++) {
> > +        int core_id = i * smp_threads;
> > +
> > +        if (mc->query_hotpluggable_cpus) {
> > +            sPAPRDRConnector *drc =
> > +                spapr_dr_connector_new(OBJECT(spapr),
> > +                                       SPAPR_DR_CONNECTOR_TYPE_CPU,
> > +                                       (core_id / smp_threads) * smt);
> > +
> > +            qemu_register_reset(spapr_drc_reset, drc);
> > +        }
> > +
> > +        if (i < spapr_cores) {
> > +            Object *core  = object_new(type);
> > +            int nr_threads = smp_threads;
> > +
> > +            /* Handle the partially filled core for older machine types */
> > +            if ((i + 1) * smp_threads >= smp_cpus) {
> > +                nr_threads = smp_cpus - i * smp_threads;
> > +            }  
> 
> 
> What is this exactly for? Older machines report "qemu-system-ppc64: threads
> must be 8" when I do "-smp 12,threads=8 -machine pseries-2.2".
> 

IIUC, this lowers nr_threads for the last core to end up with the requested
number of vCPUs... but spapr_core_pre_plug() doesn't like partially filled
cores.

    if (cc->nr_threads != smp_threads) {
        error_setg(&local_err, "threads must be %d", smp_threads);
        goto out;
    }

BTW, this error message looks weird when ones has passed "-smp threads=8"...
It should better reads:

    "unsupported partially filled core (%d threads, should have %d)"

If this check is removed, then we hit:

qemu-system-ppc64: core id 8 out of range

because of:

    int spapr_max_cores = max_cpus / smp_threads;

    index = cc->core_id / smp_threads;
    if (index < 0 || index >= spapr_max_cores) {
        error_setg(&local_err, "core id %d out of range", cc->core_id);
        goto out;
    }

Since the cc->core_id / smp_threads pattern is only used on the plug/unplug
paths, maybe these checks in spapr_core_pre_plug() should only be done
when mc->query_hotpluggable_cpus != NULL ?

> 
> 
> > +
> > +            object_property_set_int(core, nr_threads, "nr-threads",
> > +                                    &error_fatal);
> > +            object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
> > +                                    &error_fatal);
> > +            object_property_set_bool(core, true, "realized", &error_fatal);
> > +        }
> > +    }
> > +    g_free(type);
> > +}
> > +
> >  /* pSeries LPAR / sPAPR hardware init */
> >  static void ppc_spapr_init(MachineState *machine)
> >  {
> >      sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
> > -    MachineClass *mc = MACHINE_GET_CLASS(machine);
> >      sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
> >      const char *kernel_filename = machine->kernel_filename;
> >      const char *initrd_filename = machine->initrd_filename;
> > @@ -1707,21 +1776,6 @@ static void ppc_spapr_init(MachineState *machine)
> >      long load_limit, fw_size;
> >      char *filename;
> >      int smt = kvmppc_smt_threads();
> > -    int spapr_cores = smp_cpus / smp_threads;
> > -    int spapr_max_cores = max_cpus / smp_threads;
> > -
> > -    if (mc->query_hotpluggable_cpus) {
> > -        if (smp_cpus % smp_threads) {
> > -            error_report("smp_cpus (%u) must be multiple of threads (%u)",
> > -                         smp_cpus, smp_threads);
> > -            exit(1);
> > -        }
> > -        if (max_cpus % smp_threads) {
> > -            error_report("max_cpus (%u) must be multiple of threads (%u)",
> > -                         max_cpus, smp_threads);
> > -            exit(1);
> > -        }
> > -    }
> >  
> >      msi_nonbroken = true;
> >  
> > @@ -1801,44 +1855,7 @@ static void ppc_spapr_init(MachineState *machine)
> >  
> >      ppc_cpu_parse_features(machine->cpu_model);
> >  
> > -    if (mc->query_hotpluggable_cpus) {
> > -        char *type = spapr_get_cpu_core_type(machine->cpu_model);
> > -
> > -        if (type == NULL) {
> > -            error_report("Unable to find sPAPR CPU Core definition");
> > -            exit(1);
> > -        }
> > -
> > -        spapr->cores = g_new0(Object *, spapr_max_cores);
> > -        for (i = 0; i < spapr_max_cores; i++) {
> > -            int core_id = i * smp_threads;
> > -            sPAPRDRConnector *drc =
> > -                spapr_dr_connector_new(OBJECT(spapr),
> > -                                       SPAPR_DR_CONNECTOR_TYPE_CPU,
> > -                                       (core_id / smp_threads) * smt);
> > -
> > -            qemu_register_reset(spapr_drc_reset, drc);
> > -
> > -            if (i < spapr_cores) {
> > -                Object *core  = object_new(type);
> > -                object_property_set_int(core, smp_threads, "nr-threads",
> > -                                        &error_fatal);
> > -                object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
> > -                                        &error_fatal);
> > -                object_property_set_bool(core, true, "realized", &error_fatal);
> > -            }
> > -        }
> > -        g_free(type);
> > -    } else {
> > -        for (i = 0; i < smp_cpus; i++) {
> > -            PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model);
> > -            if (cpu == NULL) {
> > -                error_report("Unable to find PowerPC CPU definition");
> > -                exit(1);
> > -            }
> > -            spapr_cpu_init(spapr, cpu, &error_fatal);
> > -       }
> > -    }
> > +    spapr_init_cpus(spapr);
> >  
> >      if (kvm_enabled()) {
> >          /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
> > diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> > index e0c14f6..1357293 100644
> > --- a/hw/ppc/spapr_cpu_core.c
> > +++ b/hw/ppc/spapr_cpu_core.c
> > @@ -46,7 +46,8 @@ static void spapr_cpu_destroy(PowerPCCPU *cpu)
> >      qemu_unregister_reset(spapr_cpu_reset, cpu);
> >  }
> >  
> > -void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp)
> > +static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
> > +                           Error **errp)
> >  {
> >      CPUPPCState *env = &cpu->env;
> >      CPUState *cs = CPU(cpu);
> > @@ -166,6 +167,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> >                       Error **errp)
> >  {
> >      sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
> > +    MachineClass *mc = MACHINE_GET_CLASS(spapr);
> >      sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
> >      CPUCore *cc = CPU_CORE(dev);
> >      CPUState *cs = CPU(core->threads);
> > @@ -180,7 +182,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> >      drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
> >      spapr->cores[index] = OBJECT(dev);
> >  
> > -    g_assert(drc);
> > +    g_assert(drc || !mc->query_hotpluggable_cpus);
> >  
> >      /*
> >       * Setup CPU DT entries only for hotplugged CPUs. For boot time or
> > @@ -190,13 +192,15 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> >          fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
> >      }
> >  
> > -    drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> > -    drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
> > -    if (local_err) {
> > -        g_free(fdt);
> > -        spapr->cores[index] = NULL;
> > -        error_propagate(errp, local_err);
> > -        return;
> > +    if (drc) {
> > +        drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> > +        drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
> > +        if (local_err) {
> > +            g_free(fdt);
> > +            spapr->cores[index] = NULL;
> > +            error_propagate(errp, local_err);
> > +            return;
> > +        }
> >      }
> >  
> >      if (dev->hotplugged) {
> > @@ -209,8 +213,10 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> >          /*
> >           * Set the right DRC states for cold plugged CPU.
> >           */
> > -        drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
> > -        drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
> > +        if (drc) {
> > +            drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
> > +            drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
> > +        }
> >      }
> >  }
> >  
> > @@ -227,7 +233,7 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> >      char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model);
> >      const char *type = object_get_typename(OBJECT(dev));
> >  
> > -    if (!mc->query_hotpluggable_cpus) {
> > +    if (dev->hotplugged && !mc->query_hotpluggable_cpus) {
> >          error_setg(&local_err, "CPU hotplug not supported for this machine");
> >          goto out;
> >      }
> > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> > index bd5bcf7..f8d444d 100644
> > --- a/include/hw/ppc/spapr.h
> > +++ b/include/hw/ppc/spapr.h
> > @@ -614,7 +614,6 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
> >                                              uint32_t count, uint32_t index);
> >  void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
> >                                                 uint32_t count, uint32_t index);
> > -void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp);
> >  void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
> >                                      sPAPRMachineState *spapr);
> >  
> >   
> 
> 

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

* Re: [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional
  2016-10-30 11:11 ` [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional David Gibson
  2016-11-03  8:24   ` Alexey Kardashevskiy
@ 2016-11-04 10:45   ` Thomas Huth
  2016-11-08  3:44     ` David Gibson
  1 sibling, 1 reply; 75+ messages in thread
From: Thomas Huth @ 2016-11-04 10:45 UTC (permalink / raw)
  To: David Gibson, nikunj, aik, mdroth; +Cc: lvivier, qemu-ppc, qemu-devel

On 30.10.2016 12:11, David Gibson wrote:
> spapr_h_cas_compose_response() includes a cpu_update parameter which
> controls whether it includes updated information on the CPUs in the device
> tree fragment returned from the ibm,client-architecture-support (CAS) call.
> 
> Providing the updated information is essential when CAS has negotiated
> compatibility options which require different cpu information to be
> presented to the guest.  However, it should be safe to provide in other
> cases (it will just override the existing data in the device tree with
> identical data).  This simplifies the code by removing the parameter and
> always providing the cpu update information.

But updating the CPU device tree again and again will also increase the
QEMU start-up time... Considering that guest start up time is sometimes
also an issue, do you think that this code simplification really worth
the effort here?

 Thomas

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

* Re: [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr
  2016-10-30 11:11 ` [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr David Gibson
  2016-11-04  2:26   ` Alexey Kardashevskiy
@ 2016-11-04 10:51   ` Thomas Huth
  1 sibling, 0 replies; 75+ messages in thread
From: Thomas Huth @ 2016-11-04 10:51 UTC (permalink / raw)
  To: David Gibson, nikunj, aik, mdroth; +Cc: lvivier, qemu-ppc, qemu-devel

On 30.10.2016 12:11, David Gibson wrote:
> The 'cpu_version' field in PowerPCCPU is badly named.  It's named after the
> 'cpu-version' device tree property where it is advertised, but that meaning
> may not be obvious in most places it appears.
> 
> Worse, it doesn't even really correspond to that device tree property.  The
> property contains either the processor's PVR, or, if the CPU is running in
> a compatibility mode, a special "logical PVR" representing which mode.
> 
> Rename the cpu_version field, and a number of related variables to
> compat_pvr to make this clearer.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr.c              |  4 ++--
>  hw/ppc/spapr_hcall.c        | 30 +++++++++++++++---------------
>  target-ppc/cpu.h            |  6 +++---
>  target-ppc/kvm.c            |  4 ++--
>  target-ppc/kvm_ppc.h        |  4 ++--
>  target-ppc/translate_init.c | 10 +++++-----
>  6 files changed, 29 insertions(+), 29 deletions(-)

Reviewed-by: Thomas Huth <thuth@redhat.com>

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

* Re: [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models
  2016-10-30 11:11 ` [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models David Gibson
  2016-10-31  7:38   ` Thomas Huth
@ 2016-11-08  3:40   ` David Gibson
  1 sibling, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-08  3:40 UTC (permalink / raw)
  To: nikunj, aik, mdroth; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

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

On Sun, Oct 30, 2016 at 10:11:52PM +1100, David Gibson wrote:
> The CPU model table includes stub (commented out) definitions for
> CPU_POWERPC_POWER6_5 and CPU_POWERPC_POWER6A.  These are not real cpu
> models, but represent the POWER6 in some compatiblity modes.  If we ever
> do implement POWER6 (unlikely), we'll implement its compatibility modes in
> a different way (similar to what we do for POWER7 and POWER8).  So these
> stub definitions can be removed.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

I think this one is sufficiently non-controversial that I've merged it
into ppc-for-2.8.

> ---
>  target-ppc/cpu-models.c | 4 ----
>  target-ppc/cpu-models.h | 2 --
>  2 files changed, 6 deletions(-)
> 
> diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
> index 901cf40..506dee1 100644
> --- a/target-ppc/cpu-models.c
> +++ b/target-ppc/cpu-models.c
> @@ -1130,10 +1130,6 @@
>  #if defined(TODO)
>      POWERPC_DEF("POWER6",        CPU_POWERPC_POWER6,                 POWER6,
>                  "POWER6")
> -    POWERPC_DEF("POWER6_5",      CPU_POWERPC_POWER6_5,               POWER5,
> -                "POWER6 running in POWER5 mode")
> -    POWERPC_DEF("POWER6A",       CPU_POWERPC_POWER6A,                POWER6,
> -                "POWER6A")
>  #endif
>      POWERPC_DEF("POWER7_v2.3",   CPU_POWERPC_POWER7_v23,             POWER7,
>                  "POWER7 v2.3")
> diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
> index 7d9e6a2..aafbbd7 100644
> --- a/target-ppc/cpu-models.h
> +++ b/target-ppc/cpu-models.h
> @@ -549,8 +549,6 @@ enum {
>      CPU_POWERPC_POWER5             = 0x003A0203,
>      CPU_POWERPC_POWER5P_v21        = 0x003B0201,
>      CPU_POWERPC_POWER6             = 0x003E0000,
> -    CPU_POWERPC_POWER6_5           = 0x0F000001, /* POWER6 in POWER5 mode */
> -    CPU_POWERPC_POWER6A            = 0x0F000002,
>      CPU_POWERPC_POWER_SERVER_MASK  = 0xFFFF0000,
>      CPU_POWERPC_POWER7_BASE        = 0x003F0000,
>      CPU_POWERPC_POWER7_v23         = 0x003F0203,

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional
  2016-11-04 10:45   ` Thomas Huth
@ 2016-11-08  3:44     ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-08  3:44 UTC (permalink / raw)
  To: Thomas Huth; +Cc: nikunj, aik, mdroth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 11:45:43AM +0100, Thomas Huth wrote:
> On 30.10.2016 12:11, David Gibson wrote:
> > spapr_h_cas_compose_response() includes a cpu_update parameter which
> > controls whether it includes updated information on the CPUs in the device
> > tree fragment returned from the ibm,client-architecture-support (CAS) call.
> > 
> > Providing the updated information is essential when CAS has negotiated
> > compatibility options which require different cpu information to be
> > presented to the guest.  However, it should be safe to provide in other
> > cases (it will just override the existing data in the device tree with
> > identical data).  This simplifies the code by removing the parameter and
> > always providing the cpu update information.
> 
> But updating the CPU device tree again and again will also increase the
> QEMU start-up time... Considering that guest start up time is sometimes
> also an issue, do you think that this code simplification really worth
> the effort here?

Given how much it made my brain hurt to try to work the subsequent
changes around that parameter; yes.

If we really have problems with startup time we can revisit this - and
we can probably do better in the context of cleaned up dt building.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr
  2016-11-04  2:26   ` Alexey Kardashevskiy
@ 2016-11-08  3:48     ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-08  3:48 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 01:26:41PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:11, David Gibson wrote:
> > The 'cpu_version' field in PowerPCCPU is badly named.  It's named after the
> > 'cpu-version' device tree property where it is advertised, but that meaning
> > may not be obvious in most places it appears.
> > 
> > Worse, it doesn't even really correspond to that device tree property.  The
> > property contains either the processor's PVR, or, if the CPU is running in
> > a compatibility mode, a special "logical PVR" representing which mode.
> > 
> > Rename the cpu_version field, and a number of related variables to
> > compat_pvr to make this clearer.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr.c              |  4 ++--
> >  hw/ppc/spapr_hcall.c        | 30 +++++++++++++++---------------
> >  target-ppc/cpu.h            |  6 +++---
> >  target-ppc/kvm.c            |  4 ++--
> >  target-ppc/kvm_ppc.h        |  4 ++--
> >  target-ppc/translate_init.c | 10 +++++-----
> >  6 files changed, 29 insertions(+), 29 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> > index b7762ee..276cefa 100644
> > --- a/hw/ppc/spapr.c
> > +++ b/hw/ppc/spapr.c
> > @@ -149,8 +149,8 @@ static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
> >      uint32_t gservers_prop[smt_threads * 2];
> >      int index = ppc_get_vcpu_dt_id(cpu);
> >  
> > -    if (cpu->cpu_version) {
> > -        ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version);
> > +    if (cpu->compat_pvr) {
> 
> 
> Nit: g_assert(cpu->compat_pvr & 0x0F000000); may be?

That change wouldn't belong in this patch, which is purely a
mechanical s/cpu_version/compat_pvr/.

In general, I have considered such an assert(), but held back, because
I hand't spotted an actual document saying that range was explicitly
reserved for logical PVRs.  If you have such a reference, I'll look at
adding such an assert somewhere.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 07/17] ppc: Rewrite ppc_set_compat()
  2016-11-04  2:57   ` Alexey Kardashevskiy
@ 2016-11-08  3:49     ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-08  3:49 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 01:57:45PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:11, David Gibson wrote:
> > This rewrites the ppc_set_compat() function so that instead of open coding
> > the various compatibility modes, it reads the relevant data from a table.
> > This is a first step in consolidating the information on compatibility
> > modes scattered across the code into a single place.
> > 
> > It also makes one change to the logic.  The old code masked the bits to be
> > set in the PCR (Processor Compatibility Register) by which bits are valid
> > on the host CPU.  This made no sense, since it was done regardless of
> > whether our guest CPU was the same as the host CPU or not.  Futhermore,
> 
> s/Futhermore/Furthermore/
> 
> 
> > the actual PCR bits are only relevant for TCG[1] - KVM instead uses the
> > compatibility mode we tell it in kvmppc_set_compat().  When using TCG
> > host cpu information usually isn't even present.
> > 
> > While we're at it, we put the new implementation in a new file to make the
> > enormouse translate_init.c a little smaller.
> 
> s/enormouse/enormous/

Thanks, spelling corrections applied.

> 
> 
> > 
> > [1] Actually it doesn't even do anything in TCG, but it will if / when we
> >     get to implementing compatibility mode logic at that level.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> 
> Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> 
> > ---
> >  target-ppc/Makefile.objs    |  1 +
> >  target-ppc/compat.c         | 91 +++++++++++++++++++++++++++++++++++++++++++++
> >  target-ppc/cpu.h            |  6 ++-
> >  target-ppc/translate_init.c | 41 --------------------
> >  4 files changed, 97 insertions(+), 42 deletions(-)
> >  create mode 100644 target-ppc/compat.c
> > 
> > diff --git a/target-ppc/Makefile.objs b/target-ppc/Makefile.objs
> > index e667e69..feb5c30 100644
> > --- a/target-ppc/Makefile.objs
> > +++ b/target-ppc/Makefile.objs
> > @@ -15,3 +15,4 @@ obj-y += misc_helper.o
> >  obj-y += mem_helper.o
> >  obj-$(CONFIG_USER_ONLY) += user_only_helper.o
> >  obj-y += gdbstub.o
> > +obj-$(TARGET_PPC64) += compat.o
> > diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> > new file mode 100644
> > index 0000000..f3fd9c6
> > --- /dev/null
> > +++ b/target-ppc/compat.c
> > @@ -0,0 +1,91 @@
> > +/*
> > + *  PowerPC CPU initialization for qemu.
> > + *
> > + *  Copyright 2016, David Gibson, Red Hat Inc. <dgibson@redhat.com>
> > + *
> > + * This library is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU Lesser General Public
> > + * License as published by the Free Software Foundation; either
> > + * version 2 of the License, or (at your option) any later version.
> > + *
> > + * This library is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + * Lesser General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU Lesser General Public
> > + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "sysemu/kvm.h"
> > +#include "kvm_ppc.h"
> > +#include "sysemu/cpus.h"
> > +#include "qemu/error-report.h"
> > +#include "qapi/error.h"
> > +#include "cpu-models.h"
> > +
> > +typedef struct {
> > +    uint32_t pvr;
> > +    uint64_t pcr;
> > +} CompatInfo;
> > +
> > +static const CompatInfo compat_table[] = {
> > +    { /* POWER6, ISA2.05 */
> > +        .pvr = CPU_POWERPC_LOGICAL_2_05,
> > +        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
> > +               | PCR_TM_DIS | PCR_VSX_DIS,
> > +    },
> > +    { /* POWER7, ISA2.06 */
> > +        .pvr = CPU_POWERPC_LOGICAL_2_06,
> > +        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> > +    },
> > +    {
> > +        .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
> > +        .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> > +    },
> > +    { /* POWER8, ISA2.07 */
> > +        .pvr = CPU_POWERPC_LOGICAL_2_07,
> > +        .pcr = PCR_COMPAT_2_07,
> > +    },
> > +};
> > +
> > +static const CompatInfo *compat_by_pvr(uint32_t pvr)
> > +{
> > +    int i;
> > +
> > +    for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
> > +        if (compat_table[i].pvr == pvr) {
> > +            return &compat_table[i];
> > +        }
> > +    }
> > +    return NULL;
> > +}
> > +
> > +void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> > +{
> > +    const CompatInfo *compat = compat_by_pvr(compat_pvr);
> > +    CPUPPCState *env = &cpu->env;
> > +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
> > +    uint64_t pcr;
> > +
> > +    if (!compat_pvr) {
> > +        pcr = 0;
> > +    } else if (!compat) {
> > +        error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
> > +        return;
> > +    } else {
> > +        pcr = compat->pcr;
> > +    }
> > +
> > +    cpu->compat_pvr = compat_pvr;
> > +    env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
> > +
> > +    if (kvm_enabled()) {
> > +        int ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
> > +        if (ret < 0) {
> > +            error_setg_errno(errp, -ret,
> > +                             "Unable to set CPU compatibility mode in KVM");
> > +        }
> > +    }
> > +}
> > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> > index f7656cb..15d5e4b 100644
> > --- a/target-ppc/cpu.h
> > +++ b/target-ppc/cpu.h
> > @@ -1243,7 +1243,6 @@ void ppc_store_msr (CPUPPCState *env, target_ulong value);
> >  void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
> >  int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
> >  #if defined(TARGET_PPC64)
> > -void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> >  #endif
> >  
> >  /* Time-base and decrementer management */
> > @@ -1314,6 +1313,11 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
> >      return ifetch ? env->immu_idx : env->dmmu_idx;
> >  }
> >  
> > +/* Compatibility modes */
> > +#if defined(TARGET_PPC64)
> > +void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> > +#endif /* defined(TARGET_PPC64) */
> > +
> >  #include "exec/cpu-all.h"
> >  
> >  /*****************************************************************************/
> > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> > index c35065d..a70eafb 100644
> > --- a/target-ppc/translate_init.c
> > +++ b/target-ppc/translate_init.c
> > @@ -9972,47 +9972,6 @@ int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
> >      return ret;
> >  }
> >  
> > -#ifdef TARGET_PPC64
> > -void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> > -{
> > -    int ret = 0;
> > -    CPUPPCState *env = &cpu->env;
> > -    PowerPCCPUClass *host_pcc;
> > -
> > -    cpu->compat_pvr = compat_pvr;
> > -
> > -    switch (compat_pvr) {
> > -    case CPU_POWERPC_LOGICAL_2_05:
> > -        env->spr[SPR_PCR] = PCR_TM_DIS | PCR_VSX_DIS | PCR_COMPAT_2_07 |
> > -                            PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> > -        break;
> > -    case CPU_POWERPC_LOGICAL_2_06:
> > -    case CPU_POWERPC_LOGICAL_2_06_PLUS:
> > -        env->spr[SPR_PCR] = PCR_TM_DIS | PCR_COMPAT_2_07 | PCR_COMPAT_2_06;
> > -        break;
> > -    case CPU_POWERPC_LOGICAL_2_07:
> > -        env->spr[SPR_PCR] = PCR_COMPAT_2_07;
> > -        break;
> > -    default:
> > -        env->spr[SPR_PCR] = 0;
> > -        break;
> > -    }
> > -
> > -    host_pcc = kvm_ppc_get_host_cpu_class();
> > -    if (host_pcc) {
> > -        env->spr[SPR_PCR] &= host_pcc->pcr_mask;
> > -    }
> > -
> > -    if (kvm_enabled()) {
> > -        ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
> > -        if (ret < 0) {
> > -            error_setg_errno(errp, -ret,
> > -                             "Unable to set CPU compatibility mode in KVM");
> > -        }
> > -    }
> > -}
> > -#endif
> > -
> >  static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
> >  {
> >      ObjectClass *oc = (ObjectClass *)a;
> > 
> 
> 

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 08/17] ppc: Rewrite ppc_get_compat_smt_threads()
  2016-11-04  3:37   ` Alexey Kardashevskiy
@ 2016-11-08  5:13     ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-08  5:13 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 02:37:18PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:11, David Gibson wrote:
> > To continue consolidation of compatibility mode information, this rewrites
> > the ppc_get_compat_smt_threads() function using the table of compatiblity
> > modes in target-ppc/compat.c.
> > 
> > It's not a direct replacement, the new ppc_compat_max_threads() function
> > has simpler semantics - it just returns the number of threads the cpu
> > model has, taking into account any compatiblity mode it is in.
> > 
> > This no longer takes into account kvmppc_smt_threads() as the previous
> > version did.  That check wasn't useful because we check elsewhere that
> 
> Nit: s/elsewhere/in ppc_cpu_realizefn()/

Changed.

> 
> 
> Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> 
> 
> 
> 
> > CPUs aren't instantiated with more threads than kvm allows (or if we didn't
> > things will already be broken and this won't make it any worse).
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr.c              |  8 ++++----
> >  target-ppc/compat.c         | 18 ++++++++++++++++++
> >  target-ppc/cpu.h            |  2 +-
> >  target-ppc/translate_init.c | 20 --------------------
> >  4 files changed, 23 insertions(+), 25 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> > index 276cefa..6c78889 100644
> > --- a/hw/ppc/spapr.c
> > +++ b/hw/ppc/spapr.c
> > @@ -207,6 +207,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
> >          PowerPCCPU *cpu = POWERPC_CPU(cs);
> >          DeviceClass *dc = DEVICE_GET_CLASS(cs);
> >          int index = ppc_get_vcpu_dt_id(cpu);
> > +        int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
> >  
> >          if ((index % smt) != 0) {
> >              continue;
> > @@ -241,8 +242,7 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
> >              return ret;
> >          }
> >  
> > -        ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
> > -                                     ppc_get_compat_smt_threads(cpu));
> > +        ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
> >          if (ret < 0) {
> >              return ret;
> >          }
> > @@ -408,6 +408,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
> >      size_t page_sizes_prop_size;
> >      uint32_t vcpus_per_socket = smp_threads * smp_cores;
> >      uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
> > +    int compat_smt = MIN(smp_threads, ppc_compat_max_threads(cpu));
> >      sPAPRDRConnector *drc;
> >      sPAPRDRConnectorClass *drck;
> >      int drc_index;
> > @@ -495,8 +496,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
> >  
> >      _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs));
> >  
> > -    _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
> > -                                ppc_get_compat_smt_threads(cpu)));
> > +    _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt));
> >  }
> >  
> >  static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
> > diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> > index f3fd9c6..66529a6 100644
> > --- a/target-ppc/compat.c
> > +++ b/target-ppc/compat.c
> > @@ -28,6 +28,7 @@
> >  typedef struct {
> >      uint32_t pvr;
> >      uint64_t pcr;
> > +    int max_threads;
> >  } CompatInfo;
> >  
> >  static const CompatInfo compat_table[] = {
> > @@ -35,18 +36,22 @@ static const CompatInfo compat_table[] = {
> >          .pvr = CPU_POWERPC_LOGICAL_2_05,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
> >                 | PCR_TM_DIS | PCR_VSX_DIS,
> > +        .max_threads = 2,
> >      },
> >      { /* POWER7, ISA2.06 */
> >          .pvr = CPU_POWERPC_LOGICAL_2_06,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> > +        .max_threads = 4,
> >      },
> >      {
> >          .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> > +        .max_threads = 4,
> >      },
> >      { /* POWER8, ISA2.07 */
> >          .pvr = CPU_POWERPC_LOGICAL_2_07,
> >          .pcr = PCR_COMPAT_2_07,
> > +        .max_threads = 8,
> >      },
> >  };
> >  
> > @@ -89,3 +94,16 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> >          }
> >      }
> >  }
> > +
> > +int ppc_compat_max_threads(PowerPCCPU *cpu)
> > +{
> > +    const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
> > +    int n_threads = CPU(cpu)->nr_threads;
> > +
> > +    if (cpu->compat_pvr) {
> > +        g_assert(compat);
> > +        n_threads = MIN(n_threads, compat->max_threads);
> > +    }
> > +
> > +    return n_threads;
> > +}
> > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> > index 15d5e4b..cfda7b2 100644
> > --- a/target-ppc/cpu.h
> > +++ b/target-ppc/cpu.h
> > @@ -1241,7 +1241,6 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
> >  void ppc_store_msr (CPUPPCState *env, target_ulong value);
> >  
> >  void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
> > -int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
> >  #if defined(TARGET_PPC64)
> >  #endif
> >  
> > @@ -1316,6 +1315,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
> >  /* Compatibility modes */
> >  #if defined(TARGET_PPC64)
> >  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> > +int ppc_compat_max_threads(PowerPCCPU *cpu);
> >  #endif /* defined(TARGET_PPC64) */
> >  
> >  #include "exec/cpu-all.h"
> > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> > index a70eafb..ba48242 100644
> > --- a/target-ppc/translate_init.c
> > +++ b/target-ppc/translate_init.c
> > @@ -9952,26 +9952,6 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp)
> >      }
> >  }
> >  
> > -int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
> > -{
> > -    CPUState *cs = CPU(cpu);
> > -    int ret = MIN(cs->nr_threads, kvmppc_smt_threads());
> > -
> > -    switch (cpu->compat_pvr) {
> > -    case CPU_POWERPC_LOGICAL_2_05:
> > -        ret = MIN(ret, 2);
> > -        break;
> > -    case CPU_POWERPC_LOGICAL_2_06:
> > -        ret = MIN(ret, 4);
> > -        break;
> > -    case CPU_POWERPC_LOGICAL_2_07:
> > -        ret = MIN(ret, 8);
> > -        break;
> > -    }
> > -
> > -    return ret;
> > -}
> > -
> >  static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
> >  {
> >      ObjectClass *oc = (ObjectClass *)a;
> > 
> 
> 

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting
  2016-11-04  3:45       ` Alexey Kardashevskiy
@ 2016-11-08  5:14         ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-08  5:14 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 02:45:02PM +1100, Alexey Kardashevskiy wrote:
> On 31/10/16 19:39, David Gibson wrote:
> > On Mon, Oct 31, 2016 at 04:55:42PM +1100, Alexey Kardashevskiy wrote:
> >> On 30/10/16 22:12, David Gibson wrote:
> >>> Current ppc_set_compat() will attempt to set any compatiblity mode
> >>> specified, regardless of whether it's available on the CPU.  The caller is
> >>> expected to make sure it is setting a possible mode, which is awkwward
> >>> because most of the information to make that decision is at the CPU level.
> >>>
> >>> This begins to clean this up by introducing a ppc_check_compat() function
> >>> which will determine if a given compatiblity mode is supported on a CPU
> >>> (and also whether it lies within specified minimum and maximum compat
> >>> levels, which will be useful later).  It also contains an assertion that
> >>> the CPU has a "virtual hypervisor"[1], that is, that the guest isn't
> >>> permitted to execute hypervisor privilege code.  Without that, the guest
> >>> would own the PCR and so could override any mode set here.  Only machine
> >>> types which use a virtual hypervisor (i.e. 'pseries') should use
> >>> ppc_check_compat().
> >>>
> >>> ppc_set_compat() is modified to validate the compatibility mode it is given
> >>> and fail if it's not available on this CPU.
> >>>
> >>> [1] Or user-only mode, which also obviously doesn't allow access to the
> >>> hypervisor privileged PCR.  We don't use that now, but could in future.
> >>>
> >>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> >>> ---
> >>>  target-ppc/compat.c | 41 +++++++++++++++++++++++++++++++++++++++++
> >>>  target-ppc/cpu.h    |  2 ++
> >>>  2 files changed, 43 insertions(+)
> >>>
> >>> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> >>> index 66529a6..1059555 100644
> >>> --- a/target-ppc/compat.c
> >>> +++ b/target-ppc/compat.c
> >>> @@ -28,29 +28,37 @@
> >>>  typedef struct {
> >>>      uint32_t pvr;
> >>>      uint64_t pcr;
> >>> +    uint64_t pcr_level;
> >>>      int max_threads;
> >>>  } CompatInfo;
> >>>  
> >>>  static const CompatInfo compat_table[] = {
> >>> +    /*
> >>> +     * Ordered from oldest to newest - the code relies on this
> 
> In last 5+ years, I have never seen pointer compared anyhow but using "=="
> and "!=". A bit unusual.

Unusual, yes, but it has its uses from time to time.

> 
> 
> Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> 
> 
> 
> 
> 
> >>> +     */
> >>>      { /* POWER6, ISA2.05 */
> >>>          .pvr = CPU_POWERPC_LOGICAL_2_05,
> >>>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
> >>>                 | PCR_TM_DIS | PCR_VSX_DIS,
> >>> +        .pcr_level = PCR_COMPAT_2_05,
> >>>          .max_threads = 2,
> >>>      },
> >>>      { /* POWER7, ISA2.06 */
> >>>          .pvr = CPU_POWERPC_LOGICAL_2_06,
> >>>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> >>> +        .pcr_level = PCR_COMPAT_2_06,
> >>>          .max_threads = 4,
> >>>      },
> >>>      {
> >>>          .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
> >>>          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> >>> +        .pcr_level = PCR_COMPAT_2_06,
> >>>          .max_threads = 4,
> >>>      },
> >>>      { /* POWER8, ISA2.07 */
> >>>          .pvr = CPU_POWERPC_LOGICAL_2_07,
> >>>          .pcr = PCR_COMPAT_2_07,
> >>> +        .pcr_level = PCR_COMPAT_2_07,
> >>>          .max_threads = 8,
> >>>      },
> >>>  };
> >>> @@ -67,6 +75,35 @@ static const CompatInfo *compat_by_pvr(uint32_t pvr)
> >>>      return NULL;
> >>>  }
> >>>  
> >>> +bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
> >>> +                      uint32_t min_compat_pvr, uint32_t max_compat_pvr)
> >>> +{
> >>> +    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
> >>> +    const CompatInfo *compat = compat_by_pvr(compat_pvr);
> >>> +    const CompatInfo *min = compat_by_pvr(min_compat_pvr);
> >>> +    const CompatInfo *max = compat_by_pvr(max_compat_pvr);
> >>
> >>
> >> You keep giving very generic names (as "min" and "max") to local
> >> variables ;)
> > 
> > For local variables, brevity is a virtue.
> 
> 
> 
> 
> 




-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all()
  2016-11-04  4:01   ` Alexey Kardashevskiy
@ 2016-11-08  5:18     ` David Gibson
  2016-11-09  1:27       ` Alexey Kardashevskiy
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-11-08  5:18 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 03:01:40PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:12, David Gibson wrote:
> > Once a compatiblity mode is negotiated with the guest,
> > h_client_architecture_support() uses run_on_cpu() to update each CPU to
> > the new mode.  We're going to want this logic somewhere else shortly,
> > so make a helper function to do this global update.
> > 
> > We put it in target-ppc/compat.c - it makes as much sense at the CPU level
> > as it does at the machine level.  We also move the cpu_synchronize_state()
> > into ppc_set_compat(), since it doesn't really make any sense to call that
> > without synchronizing state.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr_hcall.c | 31 +++++--------------------------
> >  target-ppc/compat.c  | 36 ++++++++++++++++++++++++++++++++++++
> >  target-ppc/cpu.h     |  3 +++
> >  3 files changed, 44 insertions(+), 26 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index 3bd6d06..4eaf9a6 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -881,20 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> >      return ret;
> >  }
> >  
> > -typedef struct {
> > -    uint32_t compat_pvr;
> > -    Error *err;
> > -} SetCompatState;
> > -
> > -static void do_set_compat(CPUState *cs, void *arg)
> > -{
> > -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> > -    SetCompatState *s = arg;
> > -
> > -    cpu_synchronize_state(cs);
> > -    ppc_set_compat(cpu, s->compat_pvr, &s->err);
> > -}
> > -
> >  static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >                                                    sPAPRMachineState *spapr,
> >                                                    target_ulong opcode,
> > @@ -902,7 +888,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >  {
> >      target_ulong list = ppc64_phys_to_real(args[0]);
> >      target_ulong ov_table;
> > -    CPUState *cs;
> >      bool explicit_match = false; /* Matched the CPU's real PVR */
> >      uint32_t max_compat = cpu->max_compat;
> >      uint32_t best_compat = 0;
> > @@ -949,18 +934,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >  
> >      /* Update CPUs */
> >      if (cpu->compat_pvr != best_compat) {
> > -        CPU_FOREACH(cs) {
> > -            SetCompatState s = {
> > -                .compat_pvr = best_compat,
> > -                .err = NULL,
> > -            };
> > +        Error *local_err = NULL;
> >  
> > -            run_on_cpu(cs, do_set_compat, &s);
> > -
> > -            if (s.err) {
> > -                error_report_err(s.err);
> > -                return H_HARDWARE;
> > -            }
> > +        ppc_set_compat_all(best_compat, &local_err);
> > +        if (local_err) {
> > +            error_report_err(local_err);
> > +            return H_HARDWARE;
> >          }
> >      }
> >  
> > diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> > index 1059555..0b12b58 100644
> > --- a/target-ppc/compat.c
> > +++ b/target-ppc/compat.c
> > @@ -124,6 +124,8 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> >          pcr = compat->pcr;
> >      }
> >  
> > +    cpu_synchronize_state(CPU(cpu));
> > +
> >      cpu->compat_pvr = compat_pvr;
> >      env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
> >  
> > @@ -136,6 +138,40 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> >      }
> >  }
> >  
> > +#if !defined(CONFIG_USER_ONLY)
> > +typedef struct {
> > +    uint32_t compat_pvr;
> > +    Error *err;
> > +} SetCompatState;
> > +
> > +static void do_set_compat(CPUState *cs, void *arg)
> > +{
> > +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> > +    SetCompatState *s = arg;
> > +
> > +    ppc_set_compat(cpu, s->compat_pvr, &s->err);
> > +}
> > +
> > +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
> > +{
> > +    CPUState *cs;
> > +
> > +    CPU_FOREACH(cs) {
> > +        SetCompatState s = {
> > +            .compat_pvr = compat_pvr,
> > +            .err = NULL,
> > +        };
> > +
> > +        run_on_cpu(cs, do_set_compat, &s);
> > +
> > +        if (s.err) {
> > +            error_propagate(errp, s.err);
> > +            return;
> > +        }
> > +    }
> > +}
> > +#endif
> > +
> >  int ppc_compat_max_threads(PowerPCCPU *cpu)
> >  {
> >      const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
> > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> > index 91e8be8..201a655 100644
> > --- a/target-ppc/cpu.h
> > +++ b/target-ppc/cpu.h
> > @@ -1317,6 +1317,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
> >  bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
> >                        uint32_t min_compat_pvr, uint32_t max_compat_pvr);
> >  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> > +#if !defined(CONFIG_USER_ONLY)
> > +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
> > +#endif
> 
> I would put all ppc*compat*() under #if defined(CONFIG_USER_ONLY) &&
> defined(TARGET_PPC64) (or even moved this to target-ppc/Makefile.objs).

I was originally going to do that, but decided against it.

> Otherwise, functions like ppc_check_compat() have #if
> !defined(CONFIG_USER_ONLY) which suggests that the rest of
> ppc_check_compat() can actually be executed in ppc64-linux-user (while it
> cannot, can it?).

It won't be, but there's no theoretical reason they couldn't be.  User
mode, like spapr, doesn't execute hypervisor privilege code, and so
the PCR isn't owned by the "guest" (if you can call the user mode
executable that).  Which means it could make sense to set it from the
outside, although that's not something we currently do.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode
  2016-11-04  5:58   ` Alexey Kardashevskiy
@ 2016-11-08  5:19     ` David Gibson
  2016-11-08  5:51       ` Alexey Kardashevskiy
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-11-08  5:19 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 04:58:47PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:12, David Gibson wrote:
> > Server-class POWER CPUs can be put into several compatibility modes.  These
> > can be specified on the command line, or negotiated by the guest during
> > boot.
> > 
> > Currently we don't migrate the compatibility mode, which means after a
> > migration the guest will revert to running with whatever compatibility
> > mode (or none) specified on the command line.
> > 
> > With the limited range of CPUs currently used, this doesn't usually cause
> > a problem, but it could.  Fix this by adding the compatibility mode (if
> > set) to the migration stream.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  target-ppc/machine.c | 34 ++++++++++++++++++++++++++++++++++
> >  1 file changed, 34 insertions(+)
> > 
> > diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> > index 4820f22..5d87ff6 100644
> > --- a/target-ppc/machine.c
> > +++ b/target-ppc/machine.c
> > @@ -9,6 +9,7 @@
> >  #include "mmu-hash64.h"
> >  #include "migration/cpu.h"
> >  #include "exec/exec-all.h"
> > +#include "qapi/error.h"
> >  
> >  static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
> >  {
> > @@ -176,6 +177,20 @@ static int cpu_post_load(void *opaque, int version_id)
> >       * software has to take care of running QEMU in a compatible mode.
> >       */
> >      env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
> > +
> > +#if defined(TARGET_PPC64)
> > +    if (cpu->compat_pvr) {
> > +        Error *local_err = NULL;
> > +
> > +        ppc_set_compat(cpu, cpu->compat_pvr, &local_err);
> > +        if (local_err) {
> > +            error_report_err(local_err);
> > +            error_free(local_err);
> > +            return -1;
> > +        }
> > +    }
> > +#endif
> > +
> >      env->lr = env->spr[SPR_LR];
> >      env->ctr = env->spr[SPR_CTR];
> >      cpu_write_xer(env, env->spr[SPR_XER]);
> > @@ -528,6 +543,24 @@ static const VMStateDescription vmstate_tlbmas = {
> >      }
> >  };
> >  
> > +static bool compat_needed(void *opaque)
> > +{
> > +    PowerPCCPU *cpu = opaque;
> > +
> > +    return cpu->compat_pvr != 0;
> 
> 
> Finally got to trying how this affects migration :)
> 
> This breaks migration to QEMU <=2.7, and it should not at least when both
> source and destination are running with  -cpu host,compat=power7.

IIUC, we don't generally try to maintain backwards migration, even for
old machine types.

> 
> 
> > +}
> > +
> > +static const VMStateDescription vmstate_compat = {
> > +    .name = "cpu/compat",
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .needed = compat_needed,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT32(compat_pvr, PowerPCCPU),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> >  const VMStateDescription vmstate_ppc_cpu = {
> >      .name = "cpu",
> >      .version_id = 5,
> > @@ -580,6 +613,7 @@ const VMStateDescription vmstate_ppc_cpu = {
> >          &vmstate_tlb6xx,
> >          &vmstate_tlbemb,
> >          &vmstate_tlbmas,
> > +        &vmstate_compat,
> >          NULL
> >      }
> >  };
> > 
> 
> 

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine
  2016-11-04  7:43   ` Alexey Kardashevskiy
@ 2016-11-08  5:26     ` David Gibson
  2016-11-08  5:56       ` Alexey Kardashevskiy
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-11-08  5:26 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 06:43:52PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:12, David Gibson wrote:
> > Server class POWER CPUs have a "compat" property, which is used to set the
> > backwards compatibility mode for the processor.  However, this only makes
> > sense for machine types which don't give the guest access to hypervisor
> > privilege - otherwise the compatibility level is under the guest's control.
> > 
> > To reflect this, this removes the CPU 'compat' property and instead
> > creates a 'max-cpu-compat' property on the pseries machine.  Strictly
> > speaking this breaks compatibility, but AFAIK the 'compat' option was
> > never (directly) used with -device or device_add.
> > 
> > The option was used with -cpu.  So, to maintain compatibility, this patch
> > adds a hack to the cpu option parsing to strip out any compat options
> > supplied with -cpu and set them on the machine property instead of the new
> > removed cpu property.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr.c              |  6 +++-
> >  hw/ppc/spapr_cpu_core.c     | 47 +++++++++++++++++++++++++++--
> >  hw/ppc/spapr_hcall.c        |  2 +-
> >  include/hw/ppc/spapr.h      | 10 +++++--
> >  target-ppc/compat.c         | 65 ++++++++++++++++++++++++++++++++++++++++
> >  target-ppc/cpu.h            |  6 ++--
> >  target-ppc/translate_init.c | 73 ---------------------------------------------
> >  7 files changed, 127 insertions(+), 82 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> > index 6c78889..b983faa 100644
> > --- a/hw/ppc/spapr.c
> > +++ b/hw/ppc/spapr.c
> > @@ -1849,7 +1849,7 @@ static void ppc_spapr_init(MachineState *machine)
> >          machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu;
> >      }
> >  
> > -    ppc_cpu_parse_features(machine->cpu_model);
> > +    spapr_cpu_parse_features(spapr);
> >  
> >      spapr_init_cpus(spapr);
> >  
> > @@ -2191,6 +2191,10 @@ static void spapr_machine_initfn(Object *obj)
> >                                      " place of standard EPOW events when possible"
> >                                      " (required for memory hot-unplug support)",
> >                                      NULL);
> > +
> > +    object_property_add(obj, "max-cpu-compat", "str",
> > +                        ppc_compat_prop_get, ppc_compat_prop_set,
> > +                        NULL, &spapr->max_compat_pvr, &error_fatal);
> >  }
> >  
> >  static void spapr_machine_finalizefn(Object *obj)
> > diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> > index ee5cd14..0319516 100644
> > --- a/hw/ppc/spapr_cpu_core.c
> > +++ b/hw/ppc/spapr_cpu_core.c
> > @@ -18,6 +18,49 @@
> >  #include "target-ppc/mmu-hash64.h"
> >  #include "sysemu/numa.h"
> >  
> > +void spapr_cpu_parse_features(sPAPRMachineState *spapr)
> > +{
> > +    /*
> > +     * Backwards compatibility hack:
> > +
> > +     *   CPUs had a "compat=" property which didn't make sense for
> > +     *   anything except pseries.  It was replaced by "max-cpu-compat"
> > +     *   machine option.  This supports old command lines like
> > +     *       -cpu POWER8,compat=power7
> > +     *   By stripping the compat option and applying it to the machine
> > +     *   before passing it on to the cpu level parser.
> > +     */
> > +    gchar **inpieces, **outpieces;
> > +    int n, i, j;
> > +    gchar *compat_str = NULL;
> > +    gchar *filtered_model;
> > +
> > +    inpieces = g_strsplit(MACHINE(spapr)->cpu_model, ",", 0);
> > +    n = g_strv_length(inpieces);
> > +    outpieces = g_new0(gchar *, g_strv_length(inpieces));
> > +
> > +    /* inpieces[0] is the actual model string */
> > +    for (i = 0, j = 0; i < n; i++) {
> > +        if (g_str_has_prefix(inpieces[i], "compat=")) {
> > +            compat_str = inpieces[i];
> > +        } else {
> > +            outpieces[j++] = g_strdup(inpieces[i]);
> > +        }
> > +    }
> > +
> > +    if (compat_str) {
> > +        char *val = compat_str + strlen("compat=");
> > +        object_property_set_str(OBJECT(spapr), val, "max-cpu-compat",
> > +                                &error_fatal);
> 
> This part is ok.
> 
> > +    }
> > +
> > +    filtered_model = g_strjoinv(",", outpieces);
> > +    ppc_cpu_parse_features(filtered_model);
> 
> 
> Rather than reducing the CPU parameters string from the command line, I'd
> keep "dc->props = powerpc_servercpu_properties" and make them noop + warn
> to use the machine option instead. One day QEMU may start calling the CPU
> features parser itself and somebody will have to hack this thing
> again.

Hrm.  A deprecation message like that only works if a human is reading
it.  Usually qemu will be invoked by libvirt and the message will
probably disappear into some log file to scare someone unnecessarily.

Meanwhile, what will the actual behaviour be?  Pulling the CPU's
property value into the machine instead would be really ugly.
Ignoring it would break users with existing libvirt.

The hack above is nasty, but I'm not really seeing a better option.


> 
> 
> > +
> > +    g_strfreev(inpieces);
> > +    g_strfreev(outpieces);
> > +}
> > +
> >  static void spapr_cpu_reset(void *opaque)
> >  {
> >      sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
> > @@ -60,10 +103,10 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
> >      cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
> >      cpu_ppc_set_papr(cpu);
> >  
> > -    if (cpu->max_compat) {
> > +    if (spapr->max_compat_pvr) {
> >          Error *local_err = NULL;
> >  
> > -        ppc_set_compat(cpu, cpu->max_compat, &local_err);
> > +        ppc_set_compat(cpu, spapr->max_compat_pvr, &local_err);
> >          if (local_err) {
> >              error_propagate(errp, local_err);
> >              return;
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index 4eaf9a6..5efa57f 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -889,7 +889,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >      target_ulong list = ppc64_phys_to_real(args[0]);
> >      target_ulong ov_table;
> >      bool explicit_match = false; /* Matched the CPU's real PVR */
> > -    uint32_t max_compat = cpu->max_compat;
> > +    uint32_t max_compat = spapr->max_compat_pvr;
> >      uint32_t best_compat = 0;
> >      int i;
> >      sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
> > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> > index 04d2821..d2a40e9 100644
> > --- a/include/hw/ppc/spapr.h
> > +++ b/include/hw/ppc/spapr.h
> > @@ -74,15 +74,18 @@ struct sPAPRMachineState {
> >      uint64_t rtc_offset; /* Now used only during incoming migration */
> >      struct PPCTimebase tb;
> >      bool has_graphics;
> > -    sPAPROptionVector *ov5;         /* QEMU-supported option vectors */
> > -    sPAPROptionVector *ov5_cas;     /* negotiated (via CAS) option vectors */
> > -    bool cas_reboot;
> >  
> >      Notifier epow_notifier;
> >      QTAILQ_HEAD(, sPAPREventLogEntry) pending_events;
> >      bool use_hotplug_event_source;
> >      sPAPREventSource *event_sources;
> >  
> > +    /* ibm,client-architecture-support option negotiation */
> > +    bool cas_reboot;
> > +    sPAPROptionVector *ov5;         /* QEMU-supported option vectors */
> > +    sPAPROptionVector *ov5_cas;     /* negotiated (via CAS) option vectors */
> > +    uint32_t max_compat_pvr;
> > +
> 
> Nit: 3 of 5 lines were just moved while you could just add max_compat_pvr
> and the comment before ov5. QEMU already has too many patches moving lines
> around, sometime it is getting annoying while browsing with git blame.
> 
> 
> 
> >      /* Migration state */
> >      int htab_save_index;
> >      bool htab_first_pass;
> > @@ -613,6 +616,7 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
> >                                              uint32_t count, uint32_t index);
> >  void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
> >                                                 uint32_t count, uint32_t index);
> > +void spapr_cpu_parse_features(sPAPRMachineState *spapr);
> >  void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
> >                                      sPAPRMachineState *spapr);
> >  
> > diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> > index 0b12b58..c3ae52d 100644
> > --- a/target-ppc/compat.c
> > +++ b/target-ppc/compat.c
> > @@ -23,9 +23,11 @@
> >  #include "sysemu/cpus.h"
> >  #include "qemu/error-report.h"
> >  #include "qapi/error.h"
> > +#include "qapi/visitor.h"
> >  #include "cpu-models.h"
> >  
> >  typedef struct {
> > +    const char *name;
> >      uint32_t pvr;
> >      uint64_t pcr;
> >      uint64_t pcr_level;
> > @@ -37,6 +39,7 @@ static const CompatInfo compat_table[] = {
> >       * Ordered from oldest to newest - the code relies on this
> >       */
> >      { /* POWER6, ISA2.05 */
> > +        .name = "power6",
> >          .pvr = CPU_POWERPC_LOGICAL_2_05,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
> >                 | PCR_TM_DIS | PCR_VSX_DIS,
> > @@ -44,18 +47,21 @@ static const CompatInfo compat_table[] = {
> >          .max_threads = 2,
> >      },
> >      { /* POWER7, ISA2.06 */
> > +        .name = "power7",
> >          .pvr = CPU_POWERPC_LOGICAL_2_06,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> >          .pcr_level = PCR_COMPAT_2_06,
> >          .max_threads = 4,
> >      },
> >      {
> > +        .name = "power7+",
> >          .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
> >          .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
> >          .pcr_level = PCR_COMPAT_2_06,
> >          .max_threads = 4,
> >      },
> >      { /* POWER8, ISA2.07 */
> > +        .name = "power8",
> >          .pvr = CPU_POWERPC_LOGICAL_2_07,
> >          .pcr = PCR_COMPAT_2_07,
> >          .pcr_level = PCR_COMPAT_2_07,
> > @@ -184,3 +190,62 @@ int ppc_compat_max_threads(PowerPCCPU *cpu)
> >  
> >      return n_threads;
> >  }
> > +
> > +void ppc_compat_prop_get(Object *obj, Visitor *v, const char *name,
> > +                         void *opaque, Error **errp)
> > +{
> > +    uint32_t compat_pvr = *((uint32_t *)opaque);
> > +    const char *value;
> > +
> > +    if (!compat_pvr) {
> > +        value = "";
> > +    } else {
> > +        const CompatInfo *compat = compat_by_pvr(compat_pvr);
> > +
> > +        g_assert(compat);
> > +
> > +        value = compat->name;
> > +    }
> > +
> > +    visit_type_str(v, name, (char **)&value, errp);
> > +}
> > +
> > +void ppc_compat_prop_set(Object *obj, Visitor *v, const char *name,
> > +                         void *opaque, Error **errp)
> > +{
> > +    Error *error = NULL;
> > +    char *value;
> > +    uint32_t compat_pvr;
> > +
> > +    visit_type_str(v, name, &value, &error);
> > +    if (error) {
> > +        error_propagate(errp, error);
> > +        return;
> > +    }
> > +
> > +    if (strcmp(value, "") == 0) {
> > +        compat_pvr = 0;
> > +    } else {
> > +        int i;
> > +        const CompatInfo *compat = NULL;
> > +
> > +        for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
> > +            if (strcmp(value, compat_table[i].name) == 0) {
> > +                compat = &compat_table[i];
> > +                break;
> > +
> > +            }
> > +        }
> > +
> > +        if (!compat) {
> > +            error_setg(errp, "Invalid compatibility mode \"%s\"", value);
> > +            goto out;
> > +        }
> > +        compat_pvr = compat->pvr;
> > +    }
> > +
> > +    *((uint32_t *)opaque) = compat_pvr;
> > +
> > +out:
> > +    g_free(value);
> > +}
> > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> > index 201a655..51d21bb 100644
> > --- a/target-ppc/cpu.h
> > +++ b/target-ppc/cpu.h
> > @@ -1155,7 +1155,6 @@ typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
> >   * PowerPCCPU:
> >   * @env: #CPUPPCState
> >   * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
> > - * @max_compat: Maximal supported logical PVR from the command line
> >   * @compat_pvr: Current logical PVR, zero if in "raw" mode
> >   *
> >   * A PowerPC CPU.
> > @@ -1167,7 +1166,6 @@ struct PowerPCCPU {
> >  
> >      CPUPPCState env;
> >      int cpu_dt_id;
> > -    uint32_t max_compat;
> >      uint32_t compat_pvr;
> >      PPCVirtualHypervisor *vhyp;
> >  };
> > @@ -1321,6 +1319,10 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> >  void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
> >  #endif
> >  int ppc_compat_max_threads(PowerPCCPU *cpu);
> > +void ppc_compat_prop_get(Object *obj, Visitor *v,
> > +                         const char *name, void *opaque, Error **err);
> > +void ppc_compat_prop_set(Object *obj, Visitor *v,
> > +                         const char *name, void *opaque, Error **err);
> >  #endif /* defined(TARGET_PPC64) */
> >  
> >  #include "exec/cpu-all.h"
> > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
> > index ba48242..40abd23 100644
> > --- a/target-ppc/translate_init.c
> > +++ b/target-ppc/translate_init.c
> > @@ -8428,76 +8428,6 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
> >      pcc->l1_icache_size = 0x10000;
> >  }
> >  
> > -static void powerpc_get_compat(Object *obj, Visitor *v, const char *name,
> > -                               void *opaque, Error **errp)
> > -{
> > -    char *value = (char *)"";
> > -    Property *prop = opaque;
> > -    uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
> > -
> > -    switch (*max_compat) {
> > -    case CPU_POWERPC_LOGICAL_2_05:
> > -        value = (char *)"power6";
> > -        break;
> > -    case CPU_POWERPC_LOGICAL_2_06:
> > -        value = (char *)"power7";
> > -        break;
> > -    case CPU_POWERPC_LOGICAL_2_07:
> > -        value = (char *)"power8";
> > -        break;
> > -    case 0:
> > -        break;
> > -    default:
> > -        error_report("Internal error: compat is set to %x", *max_compat);
> > -        abort();
> > -        break;
> > -    }
> > -
> > -    visit_type_str(v, name, &value, errp);
> > -}
> > -
> > -static void powerpc_set_compat(Object *obj, Visitor *v, const char *name,
> > -                               void *opaque, Error **errp)
> > -{
> > -    Error *error = NULL;
> > -    char *value = NULL;
> > -    Property *prop = opaque;
> > -    uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
> > -
> > -    visit_type_str(v, name, &value, &error);
> > -    if (error) {
> > -        error_propagate(errp, error);
> > -        return;
> > -    }
> > -
> > -    if (strcmp(value, "power6") == 0) {
> > -        *max_compat = CPU_POWERPC_LOGICAL_2_05;
> > -    } else if (strcmp(value, "power7") == 0) {
> > -        *max_compat = CPU_POWERPC_LOGICAL_2_06;
> > -    } else if (strcmp(value, "power8") == 0) {
> > -        *max_compat = CPU_POWERPC_LOGICAL_2_07;
> > -    } else {
> > -        error_setg(errp, "Invalid compatibility mode \"%s\"", value);
> > -    }
> > -
> > -    g_free(value);
> > -}
> > -
> > -static PropertyInfo powerpc_compat_propinfo = {
> > -    .name = "str",
> > -    .description = "compatibility mode, power6/power7/power8",
> > -    .get = powerpc_get_compat,
> > -    .set = powerpc_set_compat,
> > -};
> > -
> > -#define DEFINE_PROP_POWERPC_COMPAT(_n, _s, _f) \
> > -    DEFINE_PROP(_n, _s, _f, powerpc_compat_propinfo, uint32_t)
> > -
> > -static Property powerpc_servercpu_properties[] = {
> > -    DEFINE_PROP_POWERPC_COMPAT("compat", PowerPCCPU, max_compat),
> > -    DEFINE_PROP_END_OF_LIST(),
> > -};
> > -
> >  #ifdef CONFIG_SOFTMMU
> >  static const struct ppc_segment_page_sizes POWER7_POWER8_sps = {
> >      .sps = {
> > @@ -8586,7 +8516,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
> >  
> >      dc->fw_name = "PowerPC,POWER7";
> >      dc->desc = "POWER7";
> > -    dc->props = powerpc_servercpu_properties;
> >      pcc->pvr_match = ppc_pvr_match_power7;
> >      pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
> >      pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> > @@ -8713,7 +8642,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
> >  
> >      dc->fw_name = "PowerPC,POWER8";
> >      dc->desc = "POWER8";
> > -    dc->props = powerpc_servercpu_properties;
> >      pcc->pvr_match = ppc_pvr_match_power8;
> >      pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> >      pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
> > @@ -8794,7 +8722,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
> >  
> >      dc->fw_name = "PowerPC,POWER9";
> >      dc->desc = "POWER9";
> > -    dc->props = powerpc_servercpu_properties;
> >      pcc->pvr_match = ppc_pvr_match_power9;
> >      pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
> >      pcc->init_proc = init_proc_POWER9;
> > 
> 
> 

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration
  2016-11-04  7:54   ` Alexey Kardashevskiy
@ 2016-11-08  5:29     ` David Gibson
  2016-11-08  6:03       ` Alexey Kardashevskiy
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-11-08  5:29 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 06:54:48PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:12, David Gibson wrote:
> > When a vmstate for the ppc cpu was first introduced (a90db15 "target-ppc:
> > Convert ppc cpu savevm to VMStateDescription"), a VMSTATE_EQUAL was used
> > to ensure that identical CPU models were used at source and destination
> > as based on the PVR (Processor Version Register).
> > 
> > However this was a problem for HV KVM, where due to hardware limitations
> > we always need to use the real PVR of the host CPU.  So, to allow
> > migration between hosts with "similar enough" CPUs, the PVR check was
> > removed in 569be9f0 "target-ppc: Remove PVR check from migration".  This
> > left the onus on user / management to only attempt migration between
> > compatible CPUs.
> > 
> > Now that we've reworked the handling of compatiblity modes, we have the
> > information to actually determine if we're making a compatible migration.
> > So this patch partially restores the PVR check.  If the source was running
> > in a compatibility mode, we just make sure that the destination cpu can
> > also run in that compatibility mode.  However, if the source was running
> > in "raw" mode, we verify that the destination has the same PVR value.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  target-ppc/machine.c | 15 +++++++++++----
> >  1 file changed, 11 insertions(+), 4 deletions(-)
> > 
> > diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> > index 5d87ff6..62b9e94 100644
> > --- a/target-ppc/machine.c
> > +++ b/target-ppc/machine.c
> > @@ -173,10 +173,12 @@ static int cpu_post_load(void *opaque, int version_id)
> >      target_ulong msr;
> >  
> >      /*
> > -     * We always ignore the source PVR. The user or management
> > -     * software has to take care of running QEMU in a compatible mode.
> > +     * If we're operating in compat mode, we should be ok as long as
> > +     * the destination supports the same compatiblity mode.
> > +     *
> > +     * Otherwise, however, we require that the destination has exactly
> > +     * the same CPU model as the source.
> >       */
> > -    env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
> >  
> >  #if defined(TARGET_PPC64)
> >      if (cpu->compat_pvr) {
> > @@ -188,8 +190,13 @@ static int cpu_post_load(void *opaque, int version_id)
> >              error_free(local_err);
> >              return -1;
> >          }
> > -    }
> > +    } else
> >  #endif
> > +    {
> > +        if (env->spr[SPR_PVR] != env->spr_cb[SPR_PVR].default_value) {
> > +            return -1;
> > +        }
> > +    }
> 
> This should break migration from host with PVR=004d0200 to host with
> PVR=004d0201, what is the benefit of such limitation?

There probably isn't one.  But the point is it also blocks migration
from a host with PVR=004B0201 (POWER8) to one with PVR=00201400
(403GCX) and *that* has a clear benefit.  I don't see a way to block
the second without the first, except by creating a huge compatibility
matrix table, which would require inordinate amounts of time to
research carefully.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration
  2016-11-04  5:52   ` Alexey Kardashevskiy
@ 2016-11-08  5:31     ` David Gibson
  2016-11-11 18:13       ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-11-08  5:31 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Fri, Nov 04, 2016 at 04:52:39PM +1100, Alexey Kardashevskiy wrote:
> On 30/10/16 22:12, David Gibson wrote:
> > When vmstate for the ppc cpu was introduced in a90db158 "target-ppc:
> > Convert ppc cpu savevm to VMStateDescription", several "sanity check"
> > fields were included, verifying that certain cpu parameters matched between
> > source and destination.
> > 
> > This turns out not to have been a good idea.  For one thing it's redundant
> > with existing checks for a compatible cpu version at either end.  But more
> > importantly the insns_flags and insns_flags2 checks actively break things:
> > they expose what's essentially an internal TCG implementation detail in the
> > migration stream.  That means that when new instruction classes are added
> > or rearranged, migration can break.
> > 
> > This removes these ill-considered sanity checks.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  target-ppc/machine.c | 8 ++++----
> >  1 file changed, 4 insertions(+), 4 deletions(-)
> > 
> > diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> > index 62b9e94..453ef0a 100644
> > --- a/target-ppc/machine.c
> > +++ b/target-ppc/machine.c
> > @@ -602,10 +602,10 @@ const VMStateDescription vmstate_ppc_cpu = {
> >          /* FIXME: access_type? */
> >  
> >          /* Sanity checking */
> > -        VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU),
> > -        VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU),
> > -        VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU),
> > -        VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU),
> > +        VMSTATE_UNUSED(sizeof(target_ulong) /* msr_mask */
> > +                       + sizeof(uint64_t) /* insns_flags */
> > +                       + sizeof(uint64_t) /* insns_flags2 */
> > +                       + sizeof(uint32_t)), /* nb_BATs */
> 
> 
> This breaks migration to older QEMU:
> 
> 25055@1478238734.537761:vmstate_load_field_error field "env.msr_mask" load
> failed, ret = -22

Again, I don't think we generally support backwards migration.

That said, it would be nice here to do a "set to this field on
ourgoing migration, but ignore on incoming migration".  Do you know a
way to do that?

a
> 
> 
> 
> >          VMSTATE_END_OF_LIST()
> >      },
> >      .subsections = (const VMStateDescription*[]) {
> > 
> 
> 

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [RFC 03/17] pseries: Always use core objects for CPU construction
  2016-11-04  9:51     ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
@ 2016-11-08  5:34       ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-08  5:34 UTC (permalink / raw)
  To: Greg Kurz
  Cc: Alexey Kardashevskiy, nikunj, mdroth, lvivier, thuth, qemu-ppc,
	qemu-devel

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

On Fri, Nov 04, 2016 at 10:51:40AM +0100, Greg Kurz wrote:
> On Thu, 3 Nov 2016 19:11:48 +1100
> Alexey Kardashevskiy <aik@ozlabs.ru> wrote:
> 
> > On 30/10/16 22:11, David Gibson wrote:
> > > Currently the pseries machine has two paths for constructing CPUs.  On
> > > newer machine type versions, which support cpu hotplug, it constructs
> > > cpu core objects, which in turn construct CPU threads.  For older machine
> > > versions it individually constructs the CPU threads.
> > > 
> > > This division is going to make some future changes to the cpu construction
> > > harder, so this patch unifies them.  Now cpu core objects are always
> > > created.  This requires some updates to allow core objects to be created
> > > without a full complement of threads (since older versions allowed a
> > > number of cpus not a multiple of the threads-per-core).  Likewise it needs
> > > some changes to the cpu core hot/cold plug path so as not to choke on the
> > > old machine types without hotplug support.
> > > 
> > > For good measure, we move the cpu construction to its own subfunction,
> > > spapr_init_cpus().
> > > 
> > > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > > ---
> > >  hw/ppc/spapr.c          | 125 +++++++++++++++++++++++++++---------------------
> > >  hw/ppc/spapr_cpu_core.c |  30 +++++++-----
> > >  include/hw/ppc/spapr.h  |   1 -
> > >  3 files changed, 89 insertions(+), 67 deletions(-)
> > > 
> > > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> > > index c8e2921..ad68a9d 100644
> > > --- a/hw/ppc/spapr.c
> > > +++ b/hw/ppc/spapr.c
> > > @@ -1688,11 +1688,80 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp)
> > >      }
> > >  }
> > >  
> > > +static void spapr_init_cpus(sPAPRMachineState *spapr)
> > > +{
> > > +    MachineState *machine = MACHINE(spapr);
> > > +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> > > +    char *type = spapr_get_cpu_core_type(machine->cpu_model);
> > > +    int smt = kvmppc_smt_threads();
> > > +    int spapr_max_cores, spapr_cores;
> > > +    int i;
> > > +
> > > +    if (!type) {
> > > +        error_report("Unable to find sPAPR CPU Core definition");
> > > +        exit(1);
> > > +    }
> > > +
> > > +    if (mc->query_hotpluggable_cpus) {
> > > +        if (smp_cpus % smp_threads) {
> > > +            error_report("smp_cpus (%u) must be multiple of threads (%u)",
> > > +                         smp_cpus, smp_threads);
> > > +            exit(1);
> > > +        }
> > > +        if (max_cpus % smp_threads) {
> > > +            error_report("max_cpus (%u) must be multiple of threads (%u)",
> > > +                         max_cpus, smp_threads);
> > > +            exit(1);
> > > +        }
> > > +
> > > +        spapr_max_cores = max_cpus / smp_threads;
> > > +        spapr_cores = smp_cpus / smp_threads;
> > > +    } else {
> > > +        if (max_cpus != smp_cpus) {
> > > +            error_report("This machine version does not support CPU hotplug");
> > > +            exit(1);
> > > +        }
> > > +
> > > +        spapr_max_cores = QEMU_ALIGN_UP(smp_cpus, smp_threads) / smp_threads;
> > > +        spapr_cores = spapr_max_cores;
> > > +    }
> > > +
> > > +    spapr->cores = g_new0(Object *, spapr_max_cores);
> > > +    for (i = 0; i < spapr_max_cores; i++) {
> > > +        int core_id = i * smp_threads;
> > > +
> > > +        if (mc->query_hotpluggable_cpus) {
> > > +            sPAPRDRConnector *drc =
> > > +                spapr_dr_connector_new(OBJECT(spapr),
> > > +                                       SPAPR_DR_CONNECTOR_TYPE_CPU,
> > > +                                       (core_id / smp_threads) * smt);
> > > +
> > > +            qemu_register_reset(spapr_drc_reset, drc);
> > > +        }
> > > +
> > > +        if (i < spapr_cores) {
> > > +            Object *core  = object_new(type);
> > > +            int nr_threads = smp_threads;
> > > +
> > > +            /* Handle the partially filled core for older machine types */
> > > +            if ((i + 1) * smp_threads >= smp_cpus) {
> > > +                nr_threads = smp_cpus - i * smp_threads;
> > > +            }  
> > 
> > 
> > What is this exactly for? Older machines report "qemu-system-ppc64: threads
> > must be 8" when I do "-smp 12,threads=8 -machine pseries-2.2".
> > 
> 
> IIUC, this lowers nr_threads for the last core to end up with the requested
> number of vCPUs... but spapr_core_pre_plug() doesn't like partially filled
> cores.
> 
>     if (cc->nr_threads != smp_threads) {
>         error_setg(&local_err, "threads must be %d", smp_threads);
>         goto out;
>     }

Ah, yeah, that's a bug.  I hadn't had a chance to test on real
hardware yet, just TCG, which only supports 1 thread per core, so I
hadn't spotted this.  I'll fix it in the next spin.

> BTW, this error message looks weird when ones has passed "-smp threads=8"...
> It should better reads:
> 
>     "unsupported partially filled core (%d threads, should have %d)"
> 
> If this check is removed, then we hit:
> 
> qemu-system-ppc64: core id 8 out of range
> 
> because of:
> 
>     int spapr_max_cores = max_cpus / smp_threads;
> 
>     index = cc->core_id / smp_threads;
>     if (index < 0 || index >= spapr_max_cores) {
>         error_setg(&local_err, "core id %d out of range", cc->core_id);
>         goto out;
>     }
> 
> Since the cc->core_id / smp_threads pattern is only used on the plug/unplug
> paths, maybe these checks in spapr_core_pre_plug() should only be done
> when mc->query_hotpluggable_cpus != NULL ?
> 
> > 
> > 
> > > +
> > > +            object_property_set_int(core, nr_threads, "nr-threads",
> > > +                                    &error_fatal);
> > > +            object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
> > > +                                    &error_fatal);
> > > +            object_property_set_bool(core, true, "realized", &error_fatal);
> > > +        }
> > > +    }
> > > +    g_free(type);
> > > +}
> > > +
> > >  /* pSeries LPAR / sPAPR hardware init */
> > >  static void ppc_spapr_init(MachineState *machine)
> > >  {
> > >      sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
> > > -    MachineClass *mc = MACHINE_GET_CLASS(machine);
> > >      sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
> > >      const char *kernel_filename = machine->kernel_filename;
> > >      const char *initrd_filename = machine->initrd_filename;
> > > @@ -1707,21 +1776,6 @@ static void ppc_spapr_init(MachineState *machine)
> > >      long load_limit, fw_size;
> > >      char *filename;
> > >      int smt = kvmppc_smt_threads();
> > > -    int spapr_cores = smp_cpus / smp_threads;
> > > -    int spapr_max_cores = max_cpus / smp_threads;
> > > -
> > > -    if (mc->query_hotpluggable_cpus) {
> > > -        if (smp_cpus % smp_threads) {
> > > -            error_report("smp_cpus (%u) must be multiple of threads (%u)",
> > > -                         smp_cpus, smp_threads);
> > > -            exit(1);
> > > -        }
> > > -        if (max_cpus % smp_threads) {
> > > -            error_report("max_cpus (%u) must be multiple of threads (%u)",
> > > -                         max_cpus, smp_threads);
> > > -            exit(1);
> > > -        }
> > > -    }
> > >  
> > >      msi_nonbroken = true;
> > >  
> > > @@ -1801,44 +1855,7 @@ static void ppc_spapr_init(MachineState *machine)
> > >  
> > >      ppc_cpu_parse_features(machine->cpu_model);
> > >  
> > > -    if (mc->query_hotpluggable_cpus) {
> > > -        char *type = spapr_get_cpu_core_type(machine->cpu_model);
> > > -
> > > -        if (type == NULL) {
> > > -            error_report("Unable to find sPAPR CPU Core definition");
> > > -            exit(1);
> > > -        }
> > > -
> > > -        spapr->cores = g_new0(Object *, spapr_max_cores);
> > > -        for (i = 0; i < spapr_max_cores; i++) {
> > > -            int core_id = i * smp_threads;
> > > -            sPAPRDRConnector *drc =
> > > -                spapr_dr_connector_new(OBJECT(spapr),
> > > -                                       SPAPR_DR_CONNECTOR_TYPE_CPU,
> > > -                                       (core_id / smp_threads) * smt);
> > > -
> > > -            qemu_register_reset(spapr_drc_reset, drc);
> > > -
> > > -            if (i < spapr_cores) {
> > > -                Object *core  = object_new(type);
> > > -                object_property_set_int(core, smp_threads, "nr-threads",
> > > -                                        &error_fatal);
> > > -                object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
> > > -                                        &error_fatal);
> > > -                object_property_set_bool(core, true, "realized", &error_fatal);
> > > -            }
> > > -        }
> > > -        g_free(type);
> > > -    } else {
> > > -        for (i = 0; i < smp_cpus; i++) {
> > > -            PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model);
> > > -            if (cpu == NULL) {
> > > -                error_report("Unable to find PowerPC CPU definition");
> > > -                exit(1);
> > > -            }
> > > -            spapr_cpu_init(spapr, cpu, &error_fatal);
> > > -       }
> > > -    }
> > > +    spapr_init_cpus(spapr);
> > >  
> > >      if (kvm_enabled()) {
> > >          /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
> > > diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> > > index e0c14f6..1357293 100644
> > > --- a/hw/ppc/spapr_cpu_core.c
> > > +++ b/hw/ppc/spapr_cpu_core.c
> > > @@ -46,7 +46,8 @@ static void spapr_cpu_destroy(PowerPCCPU *cpu)
> > >      qemu_unregister_reset(spapr_cpu_reset, cpu);
> > >  }
> > >  
> > > -void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp)
> > > +static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
> > > +                           Error **errp)
> > >  {
> > >      CPUPPCState *env = &cpu->env;
> > >      CPUState *cs = CPU(cpu);
> > > @@ -166,6 +167,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> > >                       Error **errp)
> > >  {
> > >      sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
> > > +    MachineClass *mc = MACHINE_GET_CLASS(spapr);
> > >      sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev));
> > >      CPUCore *cc = CPU_CORE(dev);
> > >      CPUState *cs = CPU(core->threads);
> > > @@ -180,7 +182,7 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> > >      drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt);
> > >      spapr->cores[index] = OBJECT(dev);
> > >  
> > > -    g_assert(drc);
> > > +    g_assert(drc || !mc->query_hotpluggable_cpus);
> > >  
> > >      /*
> > >       * Setup CPU DT entries only for hotplugged CPUs. For boot time or
> > > @@ -190,13 +192,15 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> > >          fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr);
> > >      }
> > >  
> > > -    drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> > > -    drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
> > > -    if (local_err) {
> > > -        g_free(fdt);
> > > -        spapr->cores[index] = NULL;
> > > -        error_propagate(errp, local_err);
> > > -        return;
> > > +    if (drc) {
> > > +        drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> > > +        drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err);
> > > +        if (local_err) {
> > > +            g_free(fdt);
> > > +            spapr->cores[index] = NULL;
> > > +            error_propagate(errp, local_err);
> > > +            return;
> > > +        }
> > >      }
> > >  
> > >      if (dev->hotplugged) {
> > > @@ -209,8 +213,10 @@ void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> > >          /*
> > >           * Set the right DRC states for cold plugged CPU.
> > >           */
> > > -        drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
> > > -        drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
> > > +        if (drc) {
> > > +            drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE);
> > > +            drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED);
> > > +        }
> > >      }
> > >  }
> > >  
> > > @@ -227,7 +233,7 @@ void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
> > >      char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model);
> > >      const char *type = object_get_typename(OBJECT(dev));
> > >  
> > > -    if (!mc->query_hotpluggable_cpus) {
> > > +    if (dev->hotplugged && !mc->query_hotpluggable_cpus) {
> > >          error_setg(&local_err, "CPU hotplug not supported for this machine");
> > >          goto out;
> > >      }
> > > diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
> > > index bd5bcf7..f8d444d 100644
> > > --- a/include/hw/ppc/spapr.h
> > > +++ b/include/hw/ppc/spapr.h
> > > @@ -614,7 +614,6 @@ void spapr_hotplug_req_add_by_count_indexed(sPAPRDRConnectorType drc_type,
> > >                                              uint32_t count, uint32_t index);
> > >  void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type,
> > >                                                 uint32_t count, uint32_t index);
> > > -void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp);
> > >  void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
> > >                                      sPAPRMachineState *spapr);
> > >  
> > >   
> > 
> > 
> 

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode
  2016-11-08  5:19     ` David Gibson
@ 2016-11-08  5:51       ` Alexey Kardashevskiy
  2016-11-10  1:59         ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-08  5:51 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On 08/11/16 16:19, David Gibson wrote:
> On Fri, Nov 04, 2016 at 04:58:47PM +1100, Alexey Kardashevskiy wrote:
>> On 30/10/16 22:12, David Gibson wrote:
>>> Server-class POWER CPUs can be put into several compatibility modes.  These
>>> can be specified on the command line, or negotiated by the guest during
>>> boot.
>>>
>>> Currently we don't migrate the compatibility mode, which means after a
>>> migration the guest will revert to running with whatever compatibility
>>> mode (or none) specified on the command line.
>>>
>>> With the limited range of CPUs currently used, this doesn't usually cause
>>> a problem, but it could.  Fix this by adding the compatibility mode (if
>>> set) to the migration stream.
>>>
>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
>>> ---
>>>  target-ppc/machine.c | 34 ++++++++++++++++++++++++++++++++++
>>>  1 file changed, 34 insertions(+)
>>>
>>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
>>> index 4820f22..5d87ff6 100644
>>> --- a/target-ppc/machine.c
>>> +++ b/target-ppc/machine.c
>>> @@ -9,6 +9,7 @@
>>>  #include "mmu-hash64.h"
>>>  #include "migration/cpu.h"
>>>  #include "exec/exec-all.h"
>>> +#include "qapi/error.h"
>>>  
>>>  static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
>>>  {
>>> @@ -176,6 +177,20 @@ static int cpu_post_load(void *opaque, int version_id)
>>>       * software has to take care of running QEMU in a compatible mode.
>>>       */
>>>      env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
>>> +
>>> +#if defined(TARGET_PPC64)
>>> +    if (cpu->compat_pvr) {
>>> +        Error *local_err = NULL;
>>> +
>>> +        ppc_set_compat(cpu, cpu->compat_pvr, &local_err);
>>> +        if (local_err) {
>>> +            error_report_err(local_err);
>>> +            error_free(local_err);
>>> +            return -1;
>>> +        }
>>> +    }
>>> +#endif
>>> +
>>>      env->lr = env->spr[SPR_LR];
>>>      env->ctr = env->spr[SPR_CTR];
>>>      cpu_write_xer(env, env->spr[SPR_XER]);
>>> @@ -528,6 +543,24 @@ static const VMStateDescription vmstate_tlbmas = {
>>>      }
>>>  };
>>>  
>>> +static bool compat_needed(void *opaque)
>>> +{
>>> +    PowerPCCPU *cpu = opaque;
>>> +
>>> +    return cpu->compat_pvr != 0;
>>
>>
>> Finally got to trying how this affects migration :)
>>
>> This breaks migration to QEMU <=2.7, and it should not at least when both
>> source and destination are running with  -cpu host,compat=power7.
> 
> IIUC, we don't generally try to maintain backwards migration, even for
> old machine types.


I thought the opposite - we generally try to maintain it, this is pretty
much why we use these subsections in cases like this; otherwise you could
just add a new field and bump the vmstate_ppc_cpu.version.


> 
>>
>>
>>> +}
>>> +
>>> +static const VMStateDescription vmstate_compat = {
>>> +    .name = "cpu/compat",
>>> +    .version_id = 1,
>>> +    .minimum_version_id = 1,
>>> +    .needed = compat_needed,
>>> +    .fields = (VMStateField[]) {
>>> +        VMSTATE_UINT32(compat_pvr, PowerPCCPU),
>>> +        VMSTATE_END_OF_LIST()
>>> +    }
>>> +};
>>> +
>>>  const VMStateDescription vmstate_ppc_cpu = {
>>>      .name = "cpu",
>>>      .version_id = 5,
>>> @@ -580,6 +613,7 @@ const VMStateDescription vmstate_ppc_cpu = {
>>>          &vmstate_tlb6xx,
>>>          &vmstate_tlbemb,
>>>          &vmstate_tlbmas,
>>> +        &vmstate_compat,
>>>          NULL
>>>      }
>>>  };
>>>
>>
>>
> 


-- 
Alexey


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 839 bytes --]

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

* Re: [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine
  2016-11-08  5:26     ` David Gibson
@ 2016-11-08  5:56       ` Alexey Kardashevskiy
  2016-11-09  4:41         ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-08  5:56 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On 08/11/16 16:26, David Gibson wrote:
> On Fri, Nov 04, 2016 at 06:43:52PM +1100, Alexey Kardashevskiy wrote:
>> On 30/10/16 22:12, David Gibson wrote:
>>> Server class POWER CPUs have a "compat" property, which is used to set the
>>> backwards compatibility mode for the processor.  However, this only makes
>>> sense for machine types which don't give the guest access to hypervisor
>>> privilege - otherwise the compatibility level is under the guest's control.
>>>
>>> To reflect this, this removes the CPU 'compat' property and instead
>>> creates a 'max-cpu-compat' property on the pseries machine.  Strictly
>>> speaking this breaks compatibility, but AFAIK the 'compat' option was
>>> never (directly) used with -device or device_add.
>>>
>>> The option was used with -cpu.  So, to maintain compatibility, this patch
>>> adds a hack to the cpu option parsing to strip out any compat options
>>> supplied with -cpu and set them on the machine property instead of the new
>>> removed cpu property.
>>>
>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
>>> ---
>>>  hw/ppc/spapr.c              |  6 +++-
>>>  hw/ppc/spapr_cpu_core.c     | 47 +++++++++++++++++++++++++++--
>>>  hw/ppc/spapr_hcall.c        |  2 +-
>>>  include/hw/ppc/spapr.h      | 10 +++++--
>>>  target-ppc/compat.c         | 65 ++++++++++++++++++++++++++++++++++++++++
>>>  target-ppc/cpu.h            |  6 ++--
>>>  target-ppc/translate_init.c | 73 ---------------------------------------------
>>>  7 files changed, 127 insertions(+), 82 deletions(-)
>>>
>>> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
>>> index 6c78889..b983faa 100644
>>> --- a/hw/ppc/spapr.c
>>> +++ b/hw/ppc/spapr.c
>>> @@ -1849,7 +1849,7 @@ static void ppc_spapr_init(MachineState *machine)
>>>          machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu;
>>>      }
>>>  
>>> -    ppc_cpu_parse_features(machine->cpu_model);
>>> +    spapr_cpu_parse_features(spapr);
>>>  
>>>      spapr_init_cpus(spapr);
>>>  
>>> @@ -2191,6 +2191,10 @@ static void spapr_machine_initfn(Object *obj)
>>>                                      " place of standard EPOW events when possible"
>>>                                      " (required for memory hot-unplug support)",
>>>                                      NULL);
>>> +
>>> +    object_property_add(obj, "max-cpu-compat", "str",
>>> +                        ppc_compat_prop_get, ppc_compat_prop_set,
>>> +                        NULL, &spapr->max_compat_pvr, &error_fatal);
>>>  }
>>>  
>>>  static void spapr_machine_finalizefn(Object *obj)
>>> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
>>> index ee5cd14..0319516 100644
>>> --- a/hw/ppc/spapr_cpu_core.c
>>> +++ b/hw/ppc/spapr_cpu_core.c
>>> @@ -18,6 +18,49 @@
>>>  #include "target-ppc/mmu-hash64.h"
>>>  #include "sysemu/numa.h"
>>>  
>>> +void spapr_cpu_parse_features(sPAPRMachineState *spapr)
>>> +{
>>> +    /*
>>> +     * Backwards compatibility hack:
>>> +
>>> +     *   CPUs had a "compat=" property which didn't make sense for
>>> +     *   anything except pseries.  It was replaced by "max-cpu-compat"
>>> +     *   machine option.  This supports old command lines like
>>> +     *       -cpu POWER8,compat=power7
>>> +     *   By stripping the compat option and applying it to the machine
>>> +     *   before passing it on to the cpu level parser.
>>> +     */
>>> +    gchar **inpieces, **outpieces;
>>> +    int n, i, j;
>>> +    gchar *compat_str = NULL;
>>> +    gchar *filtered_model;
>>> +
>>> +    inpieces = g_strsplit(MACHINE(spapr)->cpu_model, ",", 0);
>>> +    n = g_strv_length(inpieces);
>>> +    outpieces = g_new0(gchar *, g_strv_length(inpieces));
>>> +
>>> +    /* inpieces[0] is the actual model string */
>>> +    for (i = 0, j = 0; i < n; i++) {
>>> +        if (g_str_has_prefix(inpieces[i], "compat=")) {
>>> +            compat_str = inpieces[i];
>>> +        } else {
>>> +            outpieces[j++] = g_strdup(inpieces[i]);
>>> +        }
>>> +    }
>>> +
>>> +    if (compat_str) {
>>> +        char *val = compat_str + strlen("compat=");
>>> +        object_property_set_str(OBJECT(spapr), val, "max-cpu-compat",
>>> +                                &error_fatal);
>>
>> This part is ok.
>>
>>> +    }
>>> +
>>> +    filtered_model = g_strjoinv(",", outpieces);
>>> +    ppc_cpu_parse_features(filtered_model);
>>
>>
>> Rather than reducing the CPU parameters string from the command line, I'd
>> keep "dc->props = powerpc_servercpu_properties" and make them noop + warn
>> to use the machine option instead. One day QEMU may start calling the CPU
>> features parser itself and somebody will have to hack this thing
>> again.
> 
> Hrm.  A deprecation message like that only works if a human is reading
> it.  Usually qemu will be invoked by libvirt and the message will
> probably disappear into some log file to scare someone unnecessarily.
> 
> Meanwhile, what will the actual behaviour be?  Pulling the CPU's
> property value into the machine instead would be really ugly.
> Ignoring it would break users with existing libvirt.


I only suggested instead of removing "compat=" from the model string,
- pass the model as is to ppc_cpu_parse_features() with no changes;
- change powerpc_set_compat() to print a message and do nothing else, and
add a comment there saying why it is so.



> The hack above is nasty, but I'm not really seeing a better option.



-- 
Alexey


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 839 bytes --]

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

* Re: [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration
  2016-11-08  5:29     ` David Gibson
@ 2016-11-08  6:03       ` Alexey Kardashevskiy
  2016-11-09  4:24         ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-08  6:03 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On 08/11/16 16:29, David Gibson wrote:
> On Fri, Nov 04, 2016 at 06:54:48PM +1100, Alexey Kardashevskiy wrote:
>> On 30/10/16 22:12, David Gibson wrote:
>>> When a vmstate for the ppc cpu was first introduced (a90db15 "target-ppc:
>>> Convert ppc cpu savevm to VMStateDescription"), a VMSTATE_EQUAL was used
>>> to ensure that identical CPU models were used at source and destination
>>> as based on the PVR (Processor Version Register).
>>>
>>> However this was a problem for HV KVM, where due to hardware limitations
>>> we always need to use the real PVR of the host CPU.  So, to allow
>>> migration between hosts with "similar enough" CPUs, the PVR check was
>>> removed in 569be9f0 "target-ppc: Remove PVR check from migration".  This
>>> left the onus on user / management to only attempt migration between
>>> compatible CPUs.
>>>
>>> Now that we've reworked the handling of compatiblity modes, we have the
>>> information to actually determine if we're making a compatible migration.
>>> So this patch partially restores the PVR check.  If the source was running
>>> in a compatibility mode, we just make sure that the destination cpu can
>>> also run in that compatibility mode.  However, if the source was running
>>> in "raw" mode, we verify that the destination has the same PVR value.
>>>
>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
>>> ---
>>>  target-ppc/machine.c | 15 +++++++++++----
>>>  1 file changed, 11 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
>>> index 5d87ff6..62b9e94 100644
>>> --- a/target-ppc/machine.c
>>> +++ b/target-ppc/machine.c
>>> @@ -173,10 +173,12 @@ static int cpu_post_load(void *opaque, int version_id)
>>>      target_ulong msr;
>>>  
>>>      /*
>>> -     * We always ignore the source PVR. The user or management
>>> -     * software has to take care of running QEMU in a compatible mode.
>>> +     * If we're operating in compat mode, we should be ok as long as
>>> +     * the destination supports the same compatiblity mode.
>>> +     *
>>> +     * Otherwise, however, we require that the destination has exactly
>>> +     * the same CPU model as the source.
>>>       */
>>> -    env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
>>>  
>>>  #if defined(TARGET_PPC64)
>>>      if (cpu->compat_pvr) {
>>> @@ -188,8 +190,13 @@ static int cpu_post_load(void *opaque, int version_id)
>>>              error_free(local_err);
>>>              return -1;
>>>          }
>>> -    }
>>> +    } else
>>>  #endif
>>> +    {
>>> +        if (env->spr[SPR_PVR] != env->spr_cb[SPR_PVR].default_value) {
>>> +            return -1;
>>> +        }
>>> +    }
>>
>> This should break migration from host with PVR=004d0200 to host with
>> PVR=004d0201, what is the benefit of such limitation?
> 
> There probably isn't one.  But the point is it also blocks migration
> from a host with PVR=004B0201 (POWER8) to one with PVR=00201400
> (403GCX) and *that* has a clear benefit.  I don't see a way to block
> the second without the first, except by creating a huge compatibility
> matrix table, which would require inordinate amounts of time to
> research carefully.


This is pcc->pvr_match() for this purpose.



-- 
Alexey


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 839 bytes --]

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

* Re: [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all()
  2016-11-08  5:18     ` David Gibson
@ 2016-11-09  1:27       ` Alexey Kardashevskiy
  2016-11-09  3:52         ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-09  1:27 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On 08/11/16 16:18, David Gibson wrote:
> On Fri, Nov 04, 2016 at 03:01:40PM +1100, Alexey Kardashevskiy wrote:
>> On 30/10/16 22:12, David Gibson wrote:
>>> Once a compatiblity mode is negotiated with the guest,
>>> h_client_architecture_support() uses run_on_cpu() to update each CPU to
>>> the new mode.  We're going to want this logic somewhere else shortly,
>>> so make a helper function to do this global update.
>>>
>>> We put it in target-ppc/compat.c - it makes as much sense at the CPU level
>>> as it does at the machine level.  We also move the cpu_synchronize_state()
>>> into ppc_set_compat(), since it doesn't really make any sense to call that
>>> without synchronizing state.
>>>
>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
>>> ---
>>>  hw/ppc/spapr_hcall.c | 31 +++++--------------------------
>>>  target-ppc/compat.c  | 36 ++++++++++++++++++++++++++++++++++++
>>>  target-ppc/cpu.h     |  3 +++
>>>  3 files changed, 44 insertions(+), 26 deletions(-)
>>>
>>> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
>>> index 3bd6d06..4eaf9a6 100644
>>> --- a/hw/ppc/spapr_hcall.c
>>> +++ b/hw/ppc/spapr_hcall.c
>>> @@ -881,20 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>>>      return ret;
>>>  }
>>>  
>>> -typedef struct {
>>> -    uint32_t compat_pvr;
>>> -    Error *err;
>>> -} SetCompatState;
>>> -
>>> -static void do_set_compat(CPUState *cs, void *arg)
>>> -{
>>> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
>>> -    SetCompatState *s = arg;
>>> -
>>> -    cpu_synchronize_state(cs);
>>> -    ppc_set_compat(cpu, s->compat_pvr, &s->err);
>>> -}
>>> -
>>>  static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>>>                                                    sPAPRMachineState *spapr,
>>>                                                    target_ulong opcode,
>>> @@ -902,7 +888,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>>>  {
>>>      target_ulong list = ppc64_phys_to_real(args[0]);
>>>      target_ulong ov_table;
>>> -    CPUState *cs;
>>>      bool explicit_match = false; /* Matched the CPU's real PVR */
>>>      uint32_t max_compat = cpu->max_compat;
>>>      uint32_t best_compat = 0;
>>> @@ -949,18 +934,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>>>  
>>>      /* Update CPUs */
>>>      if (cpu->compat_pvr != best_compat) {
>>> -        CPU_FOREACH(cs) {
>>> -            SetCompatState s = {
>>> -                .compat_pvr = best_compat,
>>> -                .err = NULL,
>>> -            };
>>> +        Error *local_err = NULL;
>>>  
>>> -            run_on_cpu(cs, do_set_compat, &s);
>>> -
>>> -            if (s.err) {
>>> -                error_report_err(s.err);
>>> -                return H_HARDWARE;
>>> -            }
>>> +        ppc_set_compat_all(best_compat, &local_err);
>>> +        if (local_err) {
>>> +            error_report_err(local_err);
>>> +            return H_HARDWARE;
>>>          }
>>>      }
>>>  
>>> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
>>> index 1059555..0b12b58 100644
>>> --- a/target-ppc/compat.c
>>> +++ b/target-ppc/compat.c
>>> @@ -124,6 +124,8 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>>>          pcr = compat->pcr;
>>>      }
>>>  
>>> +    cpu_synchronize_state(CPU(cpu));
>>> +
>>>      cpu->compat_pvr = compat_pvr;
>>>      env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
>>>  
>>> @@ -136,6 +138,40 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>>>      }
>>>  }
>>>  
>>> +#if !defined(CONFIG_USER_ONLY)
>>> +typedef struct {
>>> +    uint32_t compat_pvr;
>>> +    Error *err;
>>> +} SetCompatState;
>>> +
>>> +static void do_set_compat(CPUState *cs, void *arg)
>>> +{
>>> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
>>> +    SetCompatState *s = arg;
>>> +
>>> +    ppc_set_compat(cpu, s->compat_pvr, &s->err);
>>> +}
>>> +
>>> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
>>> +{
>>> +    CPUState *cs;
>>> +
>>> +    CPU_FOREACH(cs) {
>>> +        SetCompatState s = {
>>> +            .compat_pvr = compat_pvr,
>>> +            .err = NULL,
>>> +        };
>>> +
>>> +        run_on_cpu(cs, do_set_compat, &s);
>>> +
>>> +        if (s.err) {
>>> +            error_propagate(errp, s.err);
>>> +            return;
>>> +        }
>>> +    }
>>> +}
>>> +#endif
>>> +
>>>  int ppc_compat_max_threads(PowerPCCPU *cpu)
>>>  {
>>>      const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
>>> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
>>> index 91e8be8..201a655 100644
>>> --- a/target-ppc/cpu.h
>>> +++ b/target-ppc/cpu.h
>>> @@ -1317,6 +1317,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
>>>  bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
>>>                        uint32_t min_compat_pvr, uint32_t max_compat_pvr);
>>>  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
>>> +#if !defined(CONFIG_USER_ONLY)
>>> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
>>> +#endif
>>
>> I would put all ppc*compat*() under #if defined(CONFIG_USER_ONLY) &&
>> defined(TARGET_PPC64) (or even moved this to target-ppc/Makefile.objs).
> 
> I was originally going to do that, but decided against it.
> 
>> Otherwise, functions like ppc_check_compat() have #if
>> !defined(CONFIG_USER_ONLY) which suggests that the rest of
>> ppc_check_compat() can actually be executed in ppc64-linux-user (while it
>> cannot, can it?).
> 
> It won't be, but there's no theoretical reason they couldn't be.  User
> mode, like spapr, doesn't execute hypervisor privilege code, and so
> the PCR isn't owned by the "guest" (if you can call the user mode
> executable that).  Which means it could make sense to set it from the
> outside, although that's not something we currently do.

Compatibility modes are designed to disable sets of instructions to keep
working old userspace software which relies on some opcodes to be invalid.

linux-user is TCG, right? The user can pick any CPU he likes if there is
need to run such an old software, why on earth would anyone bother with
this compat mode in linux-user?



-- 
Alexey


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 839 bytes --]

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

* Re: [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all()
  2016-11-09  1:27       ` Alexey Kardashevskiy
@ 2016-11-09  3:52         ` David Gibson
  2016-11-09  5:18           ` Alexey Kardashevskiy
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-11-09  3:52 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Wed, Nov 09, 2016 at 12:27:47PM +1100, Alexey Kardashevskiy wrote:
> On 08/11/16 16:18, David Gibson wrote:
> > On Fri, Nov 04, 2016 at 03:01:40PM +1100, Alexey Kardashevskiy wrote:
> >> On 30/10/16 22:12, David Gibson wrote:
> >>> Once a compatiblity mode is negotiated with the guest,
> >>> h_client_architecture_support() uses run_on_cpu() to update each CPU to
> >>> the new mode.  We're going to want this logic somewhere else shortly,
> >>> so make a helper function to do this global update.
> >>>
> >>> We put it in target-ppc/compat.c - it makes as much sense at the CPU level
> >>> as it does at the machine level.  We also move the cpu_synchronize_state()
> >>> into ppc_set_compat(), since it doesn't really make any sense to call that
> >>> without synchronizing state.
> >>>
> >>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> >>> ---
> >>>  hw/ppc/spapr_hcall.c | 31 +++++--------------------------
> >>>  target-ppc/compat.c  | 36 ++++++++++++++++++++++++++++++++++++
> >>>  target-ppc/cpu.h     |  3 +++
> >>>  3 files changed, 44 insertions(+), 26 deletions(-)
> >>>
> >>> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> >>> index 3bd6d06..4eaf9a6 100644
> >>> --- a/hw/ppc/spapr_hcall.c
> >>> +++ b/hw/ppc/spapr_hcall.c
> >>> @@ -881,20 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> >>>      return ret;
> >>>  }
> >>>  
> >>> -typedef struct {
> >>> -    uint32_t compat_pvr;
> >>> -    Error *err;
> >>> -} SetCompatState;
> >>> -
> >>> -static void do_set_compat(CPUState *cs, void *arg)
> >>> -{
> >>> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> >>> -    SetCompatState *s = arg;
> >>> -
> >>> -    cpu_synchronize_state(cs);
> >>> -    ppc_set_compat(cpu, s->compat_pvr, &s->err);
> >>> -}
> >>> -
> >>>  static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >>>                                                    sPAPRMachineState *spapr,
> >>>                                                    target_ulong opcode,
> >>> @@ -902,7 +888,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >>>  {
> >>>      target_ulong list = ppc64_phys_to_real(args[0]);
> >>>      target_ulong ov_table;
> >>> -    CPUState *cs;
> >>>      bool explicit_match = false; /* Matched the CPU's real PVR */
> >>>      uint32_t max_compat = cpu->max_compat;
> >>>      uint32_t best_compat = 0;
> >>> @@ -949,18 +934,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >>>  
> >>>      /* Update CPUs */
> >>>      if (cpu->compat_pvr != best_compat) {
> >>> -        CPU_FOREACH(cs) {
> >>> -            SetCompatState s = {
> >>> -                .compat_pvr = best_compat,
> >>> -                .err = NULL,
> >>> -            };
> >>> +        Error *local_err = NULL;
> >>>  
> >>> -            run_on_cpu(cs, do_set_compat, &s);
> >>> -
> >>> -            if (s.err) {
> >>> -                error_report_err(s.err);
> >>> -                return H_HARDWARE;
> >>> -            }
> >>> +        ppc_set_compat_all(best_compat, &local_err);
> >>> +        if (local_err) {
> >>> +            error_report_err(local_err);
> >>> +            return H_HARDWARE;
> >>>          }
> >>>      }
> >>>  
> >>> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> >>> index 1059555..0b12b58 100644
> >>> --- a/target-ppc/compat.c
> >>> +++ b/target-ppc/compat.c
> >>> @@ -124,6 +124,8 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> >>>          pcr = compat->pcr;
> >>>      }
> >>>  
> >>> +    cpu_synchronize_state(CPU(cpu));
> >>> +
> >>>      cpu->compat_pvr = compat_pvr;
> >>>      env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
> >>>  
> >>> @@ -136,6 +138,40 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> >>>      }
> >>>  }
> >>>  
> >>> +#if !defined(CONFIG_USER_ONLY)
> >>> +typedef struct {
> >>> +    uint32_t compat_pvr;
> >>> +    Error *err;
> >>> +} SetCompatState;
> >>> +
> >>> +static void do_set_compat(CPUState *cs, void *arg)
> >>> +{
> >>> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> >>> +    SetCompatState *s = arg;
> >>> +
> >>> +    ppc_set_compat(cpu, s->compat_pvr, &s->err);
> >>> +}
> >>> +
> >>> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
> >>> +{
> >>> +    CPUState *cs;
> >>> +
> >>> +    CPU_FOREACH(cs) {
> >>> +        SetCompatState s = {
> >>> +            .compat_pvr = compat_pvr,
> >>> +            .err = NULL,
> >>> +        };
> >>> +
> >>> +        run_on_cpu(cs, do_set_compat, &s);
> >>> +
> >>> +        if (s.err) {
> >>> +            error_propagate(errp, s.err);
> >>> +            return;
> >>> +        }
> >>> +    }
> >>> +}
> >>> +#endif
> >>> +
> >>>  int ppc_compat_max_threads(PowerPCCPU *cpu)
> >>>  {
> >>>      const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
> >>> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> >>> index 91e8be8..201a655 100644
> >>> --- a/target-ppc/cpu.h
> >>> +++ b/target-ppc/cpu.h
> >>> @@ -1317,6 +1317,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
> >>>  bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
> >>>                        uint32_t min_compat_pvr, uint32_t max_compat_pvr);
> >>>  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> >>> +#if !defined(CONFIG_USER_ONLY)
> >>> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
> >>> +#endif
> >>
> >> I would put all ppc*compat*() under #if defined(CONFIG_USER_ONLY) &&
> >> defined(TARGET_PPC64) (or even moved this to target-ppc/Makefile.objs).
> > 
> > I was originally going to do that, but decided against it.
> > 
> >> Otherwise, functions like ppc_check_compat() have #if
> >> !defined(CONFIG_USER_ONLY) which suggests that the rest of
> >> ppc_check_compat() can actually be executed in ppc64-linux-user (while it
> >> cannot, can it?).
> > 
> > It won't be, but there's no theoretical reason they couldn't be.  User
> > mode, like spapr, doesn't execute hypervisor privilege code, and so
> > the PCR isn't owned by the "guest" (if you can call the user mode
> > executable that).  Which means it could make sense to set it from the
> > outside, although that's not something we currently do.
> 
> Compatibility modes are designed to disable sets of instructions to keep
> working old userspace software which relies on some opcodes to be invalid.
> 
> linux-user is TCG, right? The user can pick any CPU he likes if there is
> need to run such an old software, why on earth would anyone bother with
> this compat mode in linux-user?

True, I can't really see any reason to do that.

On the other hand, compat mode does at least make theoretical sense,
whereas, for example, compat mode on powernv is fundamentally
nonsense.  At this point I'm not terribly include to take away the
(token) user-only support unless there's a compelling reason *not* to
include it.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration
  2016-11-08  6:03       ` Alexey Kardashevskiy
@ 2016-11-09  4:24         ` David Gibson
  2016-11-09  6:06           ` Alexey Kardashevskiy
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-11-09  4:24 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Tue, Nov 08, 2016 at 05:03:49PM +1100, Alexey Kardashevskiy wrote:
> On 08/11/16 16:29, David Gibson wrote:
> > On Fri, Nov 04, 2016 at 06:54:48PM +1100, Alexey Kardashevskiy wrote:
> >> On 30/10/16 22:12, David Gibson wrote:
> >>> When a vmstate for the ppc cpu was first introduced (a90db15 "target-ppc:
> >>> Convert ppc cpu savevm to VMStateDescription"), a VMSTATE_EQUAL was used
> >>> to ensure that identical CPU models were used at source and destination
> >>> as based on the PVR (Processor Version Register).
> >>>
> >>> However this was a problem for HV KVM, where due to hardware limitations
> >>> we always need to use the real PVR of the host CPU.  So, to allow
> >>> migration between hosts with "similar enough" CPUs, the PVR check was
> >>> removed in 569be9f0 "target-ppc: Remove PVR check from migration".  This
> >>> left the onus on user / management to only attempt migration between
> >>> compatible CPUs.
> >>>
> >>> Now that we've reworked the handling of compatiblity modes, we have the
> >>> information to actually determine if we're making a compatible migration.
> >>> So this patch partially restores the PVR check.  If the source was running
> >>> in a compatibility mode, we just make sure that the destination cpu can
> >>> also run in that compatibility mode.  However, if the source was running
> >>> in "raw" mode, we verify that the destination has the same PVR value.
> >>>
> >>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> >>> ---
> >>>  target-ppc/machine.c | 15 +++++++++++----
> >>>  1 file changed, 11 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> >>> index 5d87ff6..62b9e94 100644
> >>> --- a/target-ppc/machine.c
> >>> +++ b/target-ppc/machine.c
> >>> @@ -173,10 +173,12 @@ static int cpu_post_load(void *opaque, int version_id)
> >>>      target_ulong msr;
> >>>  
> >>>      /*
> >>> -     * We always ignore the source PVR. The user or management
> >>> -     * software has to take care of running QEMU in a compatible mode.
> >>> +     * If we're operating in compat mode, we should be ok as long as
> >>> +     * the destination supports the same compatiblity mode.
> >>> +     *
> >>> +     * Otherwise, however, we require that the destination has exactly
> >>> +     * the same CPU model as the source.
> >>>       */
> >>> -    env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
> >>>  
> >>>  #if defined(TARGET_PPC64)
> >>>      if (cpu->compat_pvr) {
> >>> @@ -188,8 +190,13 @@ static int cpu_post_load(void *opaque, int version_id)
> >>>              error_free(local_err);
> >>>              return -1;
> >>>          }
> >>> -    }
> >>> +    } else
> >>>  #endif
> >>> +    {
> >>> +        if (env->spr[SPR_PVR] != env->spr_cb[SPR_PVR].default_value) {
> >>> +            return -1;
> >>> +        }
> >>> +    }
> >>
> >> This should break migration from host with PVR=004d0200 to host with
> >> PVR=004d0201, what is the benefit of such limitation?
> > 
> > There probably isn't one.  But the point is it also blocks migration
> > from a host with PVR=004B0201 (POWER8) to one with PVR=00201400
> > (403GCX) and *that* has a clear benefit.  I don't see a way to block
> > the second without the first, except by creating a huge compatibility
> > matrix table, which would require inordinate amounts of time to
> > research carefully.
> 
> 
> This is pcc->pvr_match() for this purpose.

Hmm.. thinking about this.  Obviously requiring an exactly matching
PVR is the architecturally "safest" approach.  For TCG and PR KVM, it
really should be sufficient - if you can select "close" PVRs at each
end, you should be able to select exactly matching ones just as well.

For HV KVM, we should generally be using compatibility modes to allow
migration between a relatively wide range of CPUs.  My intention was
basically to require moving to that model, rather than "approximate
matching" real PVRs.

I'm still convinced using compat modes is the right way to go medium
to long term.  However, allowing the approximate matches could make
for a more forgiving transition, if people have existing hosts in
"raw" mode.

Ok, I'll add pvr_match checking to this.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine
  2016-11-08  5:56       ` Alexey Kardashevskiy
@ 2016-11-09  4:41         ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-09  4:41 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Tue, Nov 08, 2016 at 04:56:10PM +1100, Alexey Kardashevskiy wrote:
> On 08/11/16 16:26, David Gibson wrote:
> > On Fri, Nov 04, 2016 at 06:43:52PM +1100, Alexey Kardashevskiy wrote:
> >> On 30/10/16 22:12, David Gibson wrote:
> >>> Server class POWER CPUs have a "compat" property, which is used to set the
> >>> backwards compatibility mode for the processor.  However, this only makes
> >>> sense for machine types which don't give the guest access to hypervisor
> >>> privilege - otherwise the compatibility level is under the guest's control.
> >>>
> >>> To reflect this, this removes the CPU 'compat' property and instead
> >>> creates a 'max-cpu-compat' property on the pseries machine.  Strictly
> >>> speaking this breaks compatibility, but AFAIK the 'compat' option was
> >>> never (directly) used with -device or device_add.
> >>>
> >>> The option was used with -cpu.  So, to maintain compatibility, this patch
> >>> adds a hack to the cpu option parsing to strip out any compat options
> >>> supplied with -cpu and set them on the machine property instead of the new
> >>> removed cpu property.
> >>>
> >>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> >>> ---
> >>>  hw/ppc/spapr.c              |  6 +++-
> >>>  hw/ppc/spapr_cpu_core.c     | 47 +++++++++++++++++++++++++++--
> >>>  hw/ppc/spapr_hcall.c        |  2 +-
> >>>  include/hw/ppc/spapr.h      | 10 +++++--
> >>>  target-ppc/compat.c         | 65 ++++++++++++++++++++++++++++++++++++++++
> >>>  target-ppc/cpu.h            |  6 ++--
> >>>  target-ppc/translate_init.c | 73 ---------------------------------------------
> >>>  7 files changed, 127 insertions(+), 82 deletions(-)
> >>>
> >>> diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
> >>> index 6c78889..b983faa 100644
> >>> --- a/hw/ppc/spapr.c
> >>> +++ b/hw/ppc/spapr.c
> >>> @@ -1849,7 +1849,7 @@ static void ppc_spapr_init(MachineState *machine)
> >>>          machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu;
> >>>      }
> >>>  
> >>> -    ppc_cpu_parse_features(machine->cpu_model);
> >>> +    spapr_cpu_parse_features(spapr);
> >>>  
> >>>      spapr_init_cpus(spapr);
> >>>  
> >>> @@ -2191,6 +2191,10 @@ static void spapr_machine_initfn(Object *obj)
> >>>                                      " place of standard EPOW events when possible"
> >>>                                      " (required for memory hot-unplug support)",
> >>>                                      NULL);
> >>> +
> >>> +    object_property_add(obj, "max-cpu-compat", "str",
> >>> +                        ppc_compat_prop_get, ppc_compat_prop_set,
> >>> +                        NULL, &spapr->max_compat_pvr, &error_fatal);
> >>>  }
> >>>  
> >>>  static void spapr_machine_finalizefn(Object *obj)
> >>> diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
> >>> index ee5cd14..0319516 100644
> >>> --- a/hw/ppc/spapr_cpu_core.c
> >>> +++ b/hw/ppc/spapr_cpu_core.c
> >>> @@ -18,6 +18,49 @@
> >>>  #include "target-ppc/mmu-hash64.h"
> >>>  #include "sysemu/numa.h"
> >>>  
> >>> +void spapr_cpu_parse_features(sPAPRMachineState *spapr)
> >>> +{
> >>> +    /*
> >>> +     * Backwards compatibility hack:
> >>> +
> >>> +     *   CPUs had a "compat=" property which didn't make sense for
> >>> +     *   anything except pseries.  It was replaced by "max-cpu-compat"
> >>> +     *   machine option.  This supports old command lines like
> >>> +     *       -cpu POWER8,compat=power7
> >>> +     *   By stripping the compat option and applying it to the machine
> >>> +     *   before passing it on to the cpu level parser.
> >>> +     */
> >>> +    gchar **inpieces, **outpieces;
> >>> +    int n, i, j;
> >>> +    gchar *compat_str = NULL;
> >>> +    gchar *filtered_model;
> >>> +
> >>> +    inpieces = g_strsplit(MACHINE(spapr)->cpu_model, ",", 0);
> >>> +    n = g_strv_length(inpieces);
> >>> +    outpieces = g_new0(gchar *, g_strv_length(inpieces));
> >>> +
> >>> +    /* inpieces[0] is the actual model string */
> >>> +    for (i = 0, j = 0; i < n; i++) {
> >>> +        if (g_str_has_prefix(inpieces[i], "compat=")) {
> >>> +            compat_str = inpieces[i];
> >>> +        } else {
> >>> +            outpieces[j++] = g_strdup(inpieces[i]);
> >>> +        }
> >>> +    }
> >>> +
> >>> +    if (compat_str) {
> >>> +        char *val = compat_str + strlen("compat=");
> >>> +        object_property_set_str(OBJECT(spapr), val, "max-cpu-compat",
> >>> +                                &error_fatal);
> >>
> >> This part is ok.
> >>
> >>> +    }
> >>> +
> >>> +    filtered_model = g_strjoinv(",", outpieces);
> >>> +    ppc_cpu_parse_features(filtered_model);
> >>
> >>
> >> Rather than reducing the CPU parameters string from the command line, I'd
> >> keep "dc->props = powerpc_servercpu_properties" and make them noop + warn
> >> to use the machine option instead. One day QEMU may start calling the CPU
> >> features parser itself and somebody will have to hack this thing
> >> again.
> > 
> > Hrm.  A deprecation message like that only works if a human is reading
> > it.  Usually qemu will be invoked by libvirt and the message will
> > probably disappear into some log file to scare someone unnecessarily.
> > 
> > Meanwhile, what will the actual behaviour be?  Pulling the CPU's
> > property value into the machine instead would be really ugly.
> > Ignoring it would break users with existing libvirt.
> 
> 
> I only suggested instead of removing "compat=" from the model string,
> - pass the model as is to ppc_cpu_parse_features() with no changes;
> - change powerpc_set_compat() to print a message and do nothing else, and
> add a comment there saying why it is so.

Ah, right, now I understand.  Yes, that's a good idea.  It will
greatly simplify the rather hideous string mangling, too.

> > The hack above is nasty, but I'm not really seeing a better option.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all()
  2016-11-09  3:52         ` David Gibson
@ 2016-11-09  5:18           ` Alexey Kardashevskiy
  2016-11-10  3:13             ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-09  5:18 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On 09/11/16 14:52, David Gibson wrote:
> On Wed, Nov 09, 2016 at 12:27:47PM +1100, Alexey Kardashevskiy wrote:
>> On 08/11/16 16:18, David Gibson wrote:
>>> On Fri, Nov 04, 2016 at 03:01:40PM +1100, Alexey Kardashevskiy wrote:
>>>> On 30/10/16 22:12, David Gibson wrote:
>>>>> Once a compatiblity mode is negotiated with the guest,
>>>>> h_client_architecture_support() uses run_on_cpu() to update each CPU to
>>>>> the new mode.  We're going to want this logic somewhere else shortly,
>>>>> so make a helper function to do this global update.
>>>>>
>>>>> We put it in target-ppc/compat.c - it makes as much sense at the CPU level
>>>>> as it does at the machine level.  We also move the cpu_synchronize_state()
>>>>> into ppc_set_compat(), since it doesn't really make any sense to call that
>>>>> without synchronizing state.
>>>>>
>>>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
>>>>> ---
>>>>>  hw/ppc/spapr_hcall.c | 31 +++++--------------------------
>>>>>  target-ppc/compat.c  | 36 ++++++++++++++++++++++++++++++++++++
>>>>>  target-ppc/cpu.h     |  3 +++
>>>>>  3 files changed, 44 insertions(+), 26 deletions(-)
>>>>>
>>>>> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
>>>>> index 3bd6d06..4eaf9a6 100644
>>>>> --- a/hw/ppc/spapr_hcall.c
>>>>> +++ b/hw/ppc/spapr_hcall.c
>>>>> @@ -881,20 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>>>>>      return ret;
>>>>>  }
>>>>>  
>>>>> -typedef struct {
>>>>> -    uint32_t compat_pvr;
>>>>> -    Error *err;
>>>>> -} SetCompatState;
>>>>> -
>>>>> -static void do_set_compat(CPUState *cs, void *arg)
>>>>> -{
>>>>> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
>>>>> -    SetCompatState *s = arg;
>>>>> -
>>>>> -    cpu_synchronize_state(cs);
>>>>> -    ppc_set_compat(cpu, s->compat_pvr, &s->err);
>>>>> -}
>>>>> -
>>>>>  static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>>>>>                                                    sPAPRMachineState *spapr,
>>>>>                                                    target_ulong opcode,
>>>>> @@ -902,7 +888,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>>>>>  {
>>>>>      target_ulong list = ppc64_phys_to_real(args[0]);
>>>>>      target_ulong ov_table;
>>>>> -    CPUState *cs;
>>>>>      bool explicit_match = false; /* Matched the CPU's real PVR */
>>>>>      uint32_t max_compat = cpu->max_compat;
>>>>>      uint32_t best_compat = 0;
>>>>> @@ -949,18 +934,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>>>>>  
>>>>>      /* Update CPUs */
>>>>>      if (cpu->compat_pvr != best_compat) {
>>>>> -        CPU_FOREACH(cs) {
>>>>> -            SetCompatState s = {
>>>>> -                .compat_pvr = best_compat,
>>>>> -                .err = NULL,
>>>>> -            };
>>>>> +        Error *local_err = NULL;
>>>>>  
>>>>> -            run_on_cpu(cs, do_set_compat, &s);
>>>>> -
>>>>> -            if (s.err) {
>>>>> -                error_report_err(s.err);
>>>>> -                return H_HARDWARE;
>>>>> -            }
>>>>> +        ppc_set_compat_all(best_compat, &local_err);
>>>>> +        if (local_err) {
>>>>> +            error_report_err(local_err);
>>>>> +            return H_HARDWARE;
>>>>>          }
>>>>>      }
>>>>>  
>>>>> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
>>>>> index 1059555..0b12b58 100644
>>>>> --- a/target-ppc/compat.c
>>>>> +++ b/target-ppc/compat.c
>>>>> @@ -124,6 +124,8 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>>>>>          pcr = compat->pcr;
>>>>>      }
>>>>>  
>>>>> +    cpu_synchronize_state(CPU(cpu));
>>>>> +
>>>>>      cpu->compat_pvr = compat_pvr;
>>>>>      env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
>>>>>  
>>>>> @@ -136,6 +138,40 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
>>>>>      }
>>>>>  }
>>>>>  
>>>>> +#if !defined(CONFIG_USER_ONLY)
>>>>> +typedef struct {
>>>>> +    uint32_t compat_pvr;
>>>>> +    Error *err;
>>>>> +} SetCompatState;
>>>>> +
>>>>> +static void do_set_compat(CPUState *cs, void *arg)
>>>>> +{
>>>>> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
>>>>> +    SetCompatState *s = arg;
>>>>> +
>>>>> +    ppc_set_compat(cpu, s->compat_pvr, &s->err);
>>>>> +}
>>>>> +
>>>>> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
>>>>> +{
>>>>> +    CPUState *cs;
>>>>> +
>>>>> +    CPU_FOREACH(cs) {
>>>>> +        SetCompatState s = {
>>>>> +            .compat_pvr = compat_pvr,
>>>>> +            .err = NULL,
>>>>> +        };
>>>>> +
>>>>> +        run_on_cpu(cs, do_set_compat, &s);
>>>>> +
>>>>> +        if (s.err) {
>>>>> +            error_propagate(errp, s.err);
>>>>> +            return;
>>>>> +        }
>>>>> +    }
>>>>> +}
>>>>> +#endif
>>>>> +
>>>>>  int ppc_compat_max_threads(PowerPCCPU *cpu)
>>>>>  {
>>>>>      const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
>>>>> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
>>>>> index 91e8be8..201a655 100644
>>>>> --- a/target-ppc/cpu.h
>>>>> +++ b/target-ppc/cpu.h
>>>>> @@ -1317,6 +1317,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
>>>>>  bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
>>>>>                        uint32_t min_compat_pvr, uint32_t max_compat_pvr);
>>>>>  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
>>>>> +#if !defined(CONFIG_USER_ONLY)
>>>>> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
>>>>> +#endif
>>>>
>>>> I would put all ppc*compat*() under #if defined(CONFIG_USER_ONLY) &&
>>>> defined(TARGET_PPC64) (or even moved this to target-ppc/Makefile.objs).
>>>
>>> I was originally going to do that, but decided against it.
>>>
>>>> Otherwise, functions like ppc_check_compat() have #if
>>>> !defined(CONFIG_USER_ONLY) which suggests that the rest of
>>>> ppc_check_compat() can actually be executed in ppc64-linux-user (while it
>>>> cannot, can it?).
>>>
>>> It won't be, but there's no theoretical reason they couldn't be.  User
>>> mode, like spapr, doesn't execute hypervisor privilege code, and so
>>> the PCR isn't owned by the "guest" (if you can call the user mode
>>> executable that).  Which means it could make sense to set it from the
>>> outside, although that's not something we currently do.
>>
>> Compatibility modes are designed to disable sets of instructions to keep
>> working old userspace software which relies on some opcodes to be invalid.
>>
>> linux-user is TCG, right? The user can pick any CPU he likes if there is
>> need to run such an old software, why on earth would anyone bother with
>> this compat mode in linux-user?
> 
> True, I can't really see any reason to do that.
> 
> On the other hand, compat mode does at least make theoretical sense,
> whereas, for example, compat mode on powernv is fundamentally
> nonsense.  At this point I'm not terribly include to take away the
> (token) user-only support unless there's a compelling reason *not* to
> include it.

What would make a compelling reason? :)

This will make makefile simpler and will reduce number of #ifdef, and in
fact it is not supported now anyway, it has not even been tried.



-- 
Alexey


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 839 bytes --]

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

* Re: [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration
  2016-11-09  4:24         ` David Gibson
@ 2016-11-09  6:06           ` Alexey Kardashevskiy
  2016-11-09  6:40             ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-09  6:06 UTC (permalink / raw)
  To: David Gibson; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On 09/11/16 15:24, David Gibson wrote:
> On Tue, Nov 08, 2016 at 05:03:49PM +1100, Alexey Kardashevskiy wrote:
>> On 08/11/16 16:29, David Gibson wrote:
>>> On Fri, Nov 04, 2016 at 06:54:48PM +1100, Alexey Kardashevskiy wrote:
>>>> On 30/10/16 22:12, David Gibson wrote:
>>>>> When a vmstate for the ppc cpu was first introduced (a90db15 "target-ppc:
>>>>> Convert ppc cpu savevm to VMStateDescription"), a VMSTATE_EQUAL was used
>>>>> to ensure that identical CPU models were used at source and destination
>>>>> as based on the PVR (Processor Version Register).
>>>>>
>>>>> However this was a problem for HV KVM, where due to hardware limitations
>>>>> we always need to use the real PVR of the host CPU.  So, to allow
>>>>> migration between hosts with "similar enough" CPUs, the PVR check was
>>>>> removed in 569be9f0 "target-ppc: Remove PVR check from migration".  This
>>>>> left the onus on user / management to only attempt migration between
>>>>> compatible CPUs.
>>>>>
>>>>> Now that we've reworked the handling of compatiblity modes, we have the
>>>>> information to actually determine if we're making a compatible migration.
>>>>> So this patch partially restores the PVR check.  If the source was running
>>>>> in a compatibility mode, we just make sure that the destination cpu can
>>>>> also run in that compatibility mode.  However, if the source was running
>>>>> in "raw" mode, we verify that the destination has the same PVR value.
>>>>>
>>>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
>>>>> ---
>>>>>  target-ppc/machine.c | 15 +++++++++++----
>>>>>  1 file changed, 11 insertions(+), 4 deletions(-)
>>>>>
>>>>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
>>>>> index 5d87ff6..62b9e94 100644
>>>>> --- a/target-ppc/machine.c
>>>>> +++ b/target-ppc/machine.c
>>>>> @@ -173,10 +173,12 @@ static int cpu_post_load(void *opaque, int version_id)
>>>>>      target_ulong msr;
>>>>>  
>>>>>      /*
>>>>> -     * We always ignore the source PVR. The user or management
>>>>> -     * software has to take care of running QEMU in a compatible mode.
>>>>> +     * If we're operating in compat mode, we should be ok as long as
>>>>> +     * the destination supports the same compatiblity mode.
>>>>> +     *
>>>>> +     * Otherwise, however, we require that the destination has exactly
>>>>> +     * the same CPU model as the source.
>>>>>       */
>>>>> -    env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
>>>>>  
>>>>>  #if defined(TARGET_PPC64)
>>>>>      if (cpu->compat_pvr) {
>>>>> @@ -188,8 +190,13 @@ static int cpu_post_load(void *opaque, int version_id)
>>>>>              error_free(local_err);
>>>>>              return -1;
>>>>>          }
>>>>> -    }
>>>>> +    } else
>>>>>  #endif
>>>>> +    {
>>>>> +        if (env->spr[SPR_PVR] != env->spr_cb[SPR_PVR].default_value) {
>>>>> +            return -1;
>>>>> +        }
>>>>> +    }
>>>>
>>>> This should break migration from host with PVR=004d0200 to host with
>>>> PVR=004d0201, what is the benefit of such limitation?
>>>
>>> There probably isn't one.  But the point is it also blocks migration
>>> from a host with PVR=004B0201 (POWER8) to one with PVR=00201400
>>> (403GCX) and *that* has a clear benefit.  I don't see a way to block
>>> the second without the first, except by creating a huge compatibility
>>> matrix table, which would require inordinate amounts of time to
>>> research carefully.
>>
>>
>> This is pcc->pvr_match() for this purpose.
> 
> Hmm.. thinking about this.  Obviously requiring an exactly matching
> PVR is the architecturally "safest" approach.  For TCG and PR KVM, it
> really should be sufficient - if you can select "close" PVRs at each
> end, you should be able to select exactly matching ones just as well.
> 
> For HV KVM, we should generally be using compatibility modes to allow
> migration between a relatively wide range of CPUs.  My intention was
> basically to require moving to that model, rather than "approximate
> matching" real PVRs.

So the management stack (libvirt) will need to know that if it is HV KVM,
then -cpu host,compat=xxxx; if it is PR KVM, then -cpu XXXX and no compat.
That was really annoying when we had exact PVR matching.


> I'm still convinced using compat modes is the right way to go medium
> to long term.  However, allowing the approximate matches could make
> for a more forgiving transition, if people have existing hosts in
> "raw" mode.

Within the family, CPUs behave exactly (not slightly but exactly) the same
even though 3 of 4 bytes of the PVR value are different so enforcing PVR to
match or enforcing compatibility (which as a feature was not a great idea
from the day one) does not sound compelling.

Does x86 have anything like this compatibility thingy?


> Ok, I'll add pvr_match checking to this.
> 


-- 
Alexey


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 839 bytes --]

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

* Re: [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration
  2016-11-09  6:06           ` Alexey Kardashevskiy
@ 2016-11-09  6:40             ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-09  6:40 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Wed, Nov 09, 2016 at 05:06:23PM +1100, Alexey Kardashevskiy wrote:
> On 09/11/16 15:24, David Gibson wrote:
> > On Tue, Nov 08, 2016 at 05:03:49PM +1100, Alexey Kardashevskiy wrote:
> >> On 08/11/16 16:29, David Gibson wrote:
> >>> On Fri, Nov 04, 2016 at 06:54:48PM +1100, Alexey Kardashevskiy wrote:
> >>>> On 30/10/16 22:12, David Gibson wrote:
> >>>>> When a vmstate for the ppc cpu was first introduced (a90db15 "target-ppc:
> >>>>> Convert ppc cpu savevm to VMStateDescription"), a VMSTATE_EQUAL was used
> >>>>> to ensure that identical CPU models were used at source and destination
> >>>>> as based on the PVR (Processor Version Register).
> >>>>>
> >>>>> However this was a problem for HV KVM, where due to hardware limitations
> >>>>> we always need to use the real PVR of the host CPU.  So, to allow
> >>>>> migration between hosts with "similar enough" CPUs, the PVR check was
> >>>>> removed in 569be9f0 "target-ppc: Remove PVR check from migration".  This
> >>>>> left the onus on user / management to only attempt migration between
> >>>>> compatible CPUs.
> >>>>>
> >>>>> Now that we've reworked the handling of compatiblity modes, we have the
> >>>>> information to actually determine if we're making a compatible migration.
> >>>>> So this patch partially restores the PVR check.  If the source was running
> >>>>> in a compatibility mode, we just make sure that the destination cpu can
> >>>>> also run in that compatibility mode.  However, if the source was running
> >>>>> in "raw" mode, we verify that the destination has the same PVR value.
> >>>>>
> >>>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> >>>>> ---
> >>>>>  target-ppc/machine.c | 15 +++++++++++----
> >>>>>  1 file changed, 11 insertions(+), 4 deletions(-)
> >>>>>
> >>>>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> >>>>> index 5d87ff6..62b9e94 100644
> >>>>> --- a/target-ppc/machine.c
> >>>>> +++ b/target-ppc/machine.c
> >>>>> @@ -173,10 +173,12 @@ static int cpu_post_load(void *opaque, int version_id)
> >>>>>      target_ulong msr;
> >>>>>  
> >>>>>      /*
> >>>>> -     * We always ignore the source PVR. The user or management
> >>>>> -     * software has to take care of running QEMU in a compatible mode.
> >>>>> +     * If we're operating in compat mode, we should be ok as long as
> >>>>> +     * the destination supports the same compatiblity mode.
> >>>>> +     *
> >>>>> +     * Otherwise, however, we require that the destination has exactly
> >>>>> +     * the same CPU model as the source.
> >>>>>       */
> >>>>> -    env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
> >>>>>  
> >>>>>  #if defined(TARGET_PPC64)
> >>>>>      if (cpu->compat_pvr) {
> >>>>> @@ -188,8 +190,13 @@ static int cpu_post_load(void *opaque, int version_id)
> >>>>>              error_free(local_err);
> >>>>>              return -1;
> >>>>>          }
> >>>>> -    }
> >>>>> +    } else
> >>>>>  #endif
> >>>>> +    {
> >>>>> +        if (env->spr[SPR_PVR] != env->spr_cb[SPR_PVR].default_value) {
> >>>>> +            return -1;
> >>>>> +        }
> >>>>> +    }
> >>>>
> >>>> This should break migration from host with PVR=004d0200 to host with
> >>>> PVR=004d0201, what is the benefit of such limitation?
> >>>
> >>> There probably isn't one.  But the point is it also blocks migration
> >>> from a host with PVR=004B0201 (POWER8) to one with PVR=00201400
> >>> (403GCX) and *that* has a clear benefit.  I don't see a way to block
> >>> the second without the first, except by creating a huge compatibility
> >>> matrix table, which would require inordinate amounts of time to
> >>> research carefully.
> >>
> >>
> >> This is pcc->pvr_match() for this purpose.
> > 
> > Hmm.. thinking about this.  Obviously requiring an exactly matching
> > PVR is the architecturally "safest" approach.  For TCG and PR KVM, it
> > really should be sufficient - if you can select "close" PVRs at each
> > end, you should be able to select exactly matching ones just as well.
> > 
> > For HV KVM, we should generally be using compatibility modes to allow
> > migration between a relatively wide range of CPUs.  My intention was
> > basically to require moving to that model, rather than "approximate
> > matching" real PVRs.
> 
> So the management stack (libvirt) will need to know that if it is HV KVM,
> then -cpu host,compat=xxxx; if it is PR KVM, then -cpu XXXX and no compat.
> That was really annoying when we had exact PVR matching.
> 
> 
> > I'm still convinced using compat modes is the right way to go medium
> > to long term.  However, allowing the approximate matches could make
> > for a more forgiving transition, if people have existing hosts in
> > "raw" mode.
> 
> Within the family, CPUs behave exactly (not slightly but exactly) the same
> even though 3 of 4 bytes of the PVR value are different so enforcing PVR to
> match or enforcing compatibility (which as a feature was not a great idea
> from the day one) does not sound compelling.

Ah, ok.  pvr_match sounds reasonable then - I've already implemented
that.

> Does x86 have anything like this compatibility thingy?

It's better thought out on x86.  AIUI compatibility options are set in
the VM control block, so it is under host control even though the
guest is not para-virtualized.  I believe CPUID (unlike mfpvr) *is*
virtualized so the guest simply sees the compatible CPU, not something
else running in a compatibility mode.  So, there's no need for
compatibility modes as such, you just set the CPU to an older one, and
qemu and KVM between them make it appear that way to the guest.

It helps that compatibility is 1 dimensional on x86 - basically
any model can be run to be compatible with any older model.  That's
true for sufficiently recent Power server CPUs, but not across Power
in general.

Actually, I'm not sure where Atom and AMD vs. Intel fit into that
picture, but at any rate, I believe they're closer to 1 dimensional
compatibility than Power / PowerPC is.

> > Ok, I'll add pvr_match checking to this.
> > 
> 
> 




-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode
  2016-11-08  5:51       ` Alexey Kardashevskiy
@ 2016-11-10  1:59         ` David Gibson
  2016-11-10 23:55           ` Michael Roth
  0 siblings, 1 reply; 75+ messages in thread
From: David Gibson @ 2016-11-10  1:59 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Tue, Nov 08, 2016 at 04:51:10PM +1100, Alexey Kardashevskiy wrote:
> On 08/11/16 16:19, David Gibson wrote:
> > On Fri, Nov 04, 2016 at 04:58:47PM +1100, Alexey Kardashevskiy wrote:
> >> On 30/10/16 22:12, David Gibson wrote:
> >>> Server-class POWER CPUs can be put into several compatibility modes.  These
> >>> can be specified on the command line, or negotiated by the guest during
> >>> boot.
> >>>
> >>> Currently we don't migrate the compatibility mode, which means after a
> >>> migration the guest will revert to running with whatever compatibility
> >>> mode (or none) specified on the command line.
> >>>
> >>> With the limited range of CPUs currently used, this doesn't usually cause
> >>> a problem, but it could.  Fix this by adding the compatibility mode (if
> >>> set) to the migration stream.
> >>>
> >>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> >>> ---
> >>>  target-ppc/machine.c | 34 ++++++++++++++++++++++++++++++++++
> >>>  1 file changed, 34 insertions(+)
> >>>
> >>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> >>> index 4820f22..5d87ff6 100644
> >>> --- a/target-ppc/machine.c
> >>> +++ b/target-ppc/machine.c
> >>> @@ -9,6 +9,7 @@
> >>>  #include "mmu-hash64.h"
> >>>  #include "migration/cpu.h"
> >>>  #include "exec/exec-all.h"
> >>> +#include "qapi/error.h"
> >>>  
> >>>  static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
> >>>  {
> >>> @@ -176,6 +177,20 @@ static int cpu_post_load(void *opaque, int version_id)
> >>>       * software has to take care of running QEMU in a compatible mode.
> >>>       */
> >>>      env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
> >>> +
> >>> +#if defined(TARGET_PPC64)
> >>> +    if (cpu->compat_pvr) {
> >>> +        Error *local_err = NULL;
> >>> +
> >>> +        ppc_set_compat(cpu, cpu->compat_pvr, &local_err);
> >>> +        if (local_err) {
> >>> +            error_report_err(local_err);
> >>> +            error_free(local_err);
> >>> +            return -1;
> >>> +        }
> >>> +    }
> >>> +#endif
> >>> +
> >>>      env->lr = env->spr[SPR_LR];
> >>>      env->ctr = env->spr[SPR_CTR];
> >>>      cpu_write_xer(env, env->spr[SPR_XER]);
> >>> @@ -528,6 +543,24 @@ static const VMStateDescription vmstate_tlbmas = {
> >>>      }
> >>>  };
> >>>  
> >>> +static bool compat_needed(void *opaque)
> >>> +{
> >>> +    PowerPCCPU *cpu = opaque;
> >>> +
> >>> +    return cpu->compat_pvr != 0;
> >>
> >>
> >> Finally got to trying how this affects migration :)
> >>
> >> This breaks migration to QEMU <=2.7, and it should not at least when both
> >> source and destination are running with  -cpu host,compat=power7.
> > 
> > IIUC, we don't generally try to maintain backwards migration, even for
> > old machine types.
> 
> 
> I thought the opposite - we generally try to maintain it, this is pretty
> much why we use these subsections in cases like this; otherwise you could
> just add a new field and bump the vmstate_ppc_cpu.version.

Hm, I guess that's true.  We do at least try to allow backwards
migration, we just don't insist on it.  The example here partially
suceeds - it will allow backwards migration for CPUs in raw mode.

I'll look at just bumping the version instead.

> 
> 
> > 
> >>
> >>
> >>> +}
> >>> +
> >>> +static const VMStateDescription vmstate_compat = {
> >>> +    .name = "cpu/compat",
> >>> +    .version_id = 1,
> >>> +    .minimum_version_id = 1,
> >>> +    .needed = compat_needed,
> >>> +    .fields = (VMStateField[]) {
> >>> +        VMSTATE_UINT32(compat_pvr, PowerPCCPU),
> >>> +        VMSTATE_END_OF_LIST()
> >>> +    }
> >>> +};
> >>> +
> >>>  const VMStateDescription vmstate_ppc_cpu = {
> >>>      .name = "cpu",
> >>>      .version_id = 5,
> >>> @@ -580,6 +613,7 @@ const VMStateDescription vmstate_ppc_cpu = {
> >>>          &vmstate_tlb6xx,
> >>>          &vmstate_tlbemb,
> >>>          &vmstate_tlbmas,
> >>> +        &vmstate_compat,
> >>>          NULL
> >>>      }
> >>>  };
> >>>
> >>
> >>
> > 
> 
> 




-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all()
  2016-11-09  5:18           ` Alexey Kardashevskiy
@ 2016-11-10  3:13             ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-10  3:13 UTC (permalink / raw)
  To: Alexey Kardashevskiy; +Cc: nikunj, mdroth, thuth, lvivier, qemu-ppc, qemu-devel

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

On Wed, Nov 09, 2016 at 04:18:20PM +1100, Alexey Kardashevskiy wrote:
> On 09/11/16 14:52, David Gibson wrote:
> > On Wed, Nov 09, 2016 at 12:27:47PM +1100, Alexey Kardashevskiy wrote:
> >> On 08/11/16 16:18, David Gibson wrote:
> >>> On Fri, Nov 04, 2016 at 03:01:40PM +1100, Alexey Kardashevskiy wrote:
> >>>> On 30/10/16 22:12, David Gibson wrote:
> >>>>> Once a compatiblity mode is negotiated with the guest,
> >>>>> h_client_architecture_support() uses run_on_cpu() to update each CPU to
> >>>>> the new mode.  We're going to want this logic somewhere else shortly,
> >>>>> so make a helper function to do this global update.
> >>>>>
> >>>>> We put it in target-ppc/compat.c - it makes as much sense at the CPU level
> >>>>> as it does at the machine level.  We also move the cpu_synchronize_state()
> >>>>> into ppc_set_compat(), since it doesn't really make any sense to call that
> >>>>> without synchronizing state.
> >>>>>
> >>>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> >>>>> ---
> >>>>>  hw/ppc/spapr_hcall.c | 31 +++++--------------------------
> >>>>>  target-ppc/compat.c  | 36 ++++++++++++++++++++++++++++++++++++
> >>>>>  target-ppc/cpu.h     |  3 +++
> >>>>>  3 files changed, 44 insertions(+), 26 deletions(-)
> >>>>>
> >>>>> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> >>>>> index 3bd6d06..4eaf9a6 100644
> >>>>> --- a/hw/ppc/spapr_hcall.c
> >>>>> +++ b/hw/ppc/spapr_hcall.c
> >>>>> @@ -881,20 +881,6 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> >>>>>      return ret;
> >>>>>  }
> >>>>>  
> >>>>> -typedef struct {
> >>>>> -    uint32_t compat_pvr;
> >>>>> -    Error *err;
> >>>>> -} SetCompatState;
> >>>>> -
> >>>>> -static void do_set_compat(CPUState *cs, void *arg)
> >>>>> -{
> >>>>> -    PowerPCCPU *cpu = POWERPC_CPU(cs);
> >>>>> -    SetCompatState *s = arg;
> >>>>> -
> >>>>> -    cpu_synchronize_state(cs);
> >>>>> -    ppc_set_compat(cpu, s->compat_pvr, &s->err);
> >>>>> -}
> >>>>> -
> >>>>>  static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >>>>>                                                    sPAPRMachineState *spapr,
> >>>>>                                                    target_ulong opcode,
> >>>>> @@ -902,7 +888,6 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >>>>>  {
> >>>>>      target_ulong list = ppc64_phys_to_real(args[0]);
> >>>>>      target_ulong ov_table;
> >>>>> -    CPUState *cs;
> >>>>>      bool explicit_match = false; /* Matched the CPU's real PVR */
> >>>>>      uint32_t max_compat = cpu->max_compat;
> >>>>>      uint32_t best_compat = 0;
> >>>>> @@ -949,18 +934,12 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >>>>>  
> >>>>>      /* Update CPUs */
> >>>>>      if (cpu->compat_pvr != best_compat) {
> >>>>> -        CPU_FOREACH(cs) {
> >>>>> -            SetCompatState s = {
> >>>>> -                .compat_pvr = best_compat,
> >>>>> -                .err = NULL,
> >>>>> -            };
> >>>>> +        Error *local_err = NULL;
> >>>>>  
> >>>>> -            run_on_cpu(cs, do_set_compat, &s);
> >>>>> -
> >>>>> -            if (s.err) {
> >>>>> -                error_report_err(s.err);
> >>>>> -                return H_HARDWARE;
> >>>>> -            }
> >>>>> +        ppc_set_compat_all(best_compat, &local_err);
> >>>>> +        if (local_err) {
> >>>>> +            error_report_err(local_err);
> >>>>> +            return H_HARDWARE;
> >>>>>          }
> >>>>>      }
> >>>>>  
> >>>>> diff --git a/target-ppc/compat.c b/target-ppc/compat.c
> >>>>> index 1059555..0b12b58 100644
> >>>>> --- a/target-ppc/compat.c
> >>>>> +++ b/target-ppc/compat.c
> >>>>> @@ -124,6 +124,8 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> >>>>>          pcr = compat->pcr;
> >>>>>      }
> >>>>>  
> >>>>> +    cpu_synchronize_state(CPU(cpu));
> >>>>> +
> >>>>>      cpu->compat_pvr = compat_pvr;
> >>>>>      env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
> >>>>>  
> >>>>> @@ -136,6 +138,40 @@ void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
> >>>>>      }
> >>>>>  }
> >>>>>  
> >>>>> +#if !defined(CONFIG_USER_ONLY)
> >>>>> +typedef struct {
> >>>>> +    uint32_t compat_pvr;
> >>>>> +    Error *err;
> >>>>> +} SetCompatState;
> >>>>> +
> >>>>> +static void do_set_compat(CPUState *cs, void *arg)
> >>>>> +{
> >>>>> +    PowerPCCPU *cpu = POWERPC_CPU(cs);
> >>>>> +    SetCompatState *s = arg;
> >>>>> +
> >>>>> +    ppc_set_compat(cpu, s->compat_pvr, &s->err);
> >>>>> +}
> >>>>> +
> >>>>> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
> >>>>> +{
> >>>>> +    CPUState *cs;
> >>>>> +
> >>>>> +    CPU_FOREACH(cs) {
> >>>>> +        SetCompatState s = {
> >>>>> +            .compat_pvr = compat_pvr,
> >>>>> +            .err = NULL,
> >>>>> +        };
> >>>>> +
> >>>>> +        run_on_cpu(cs, do_set_compat, &s);
> >>>>> +
> >>>>> +        if (s.err) {
> >>>>> +            error_propagate(errp, s.err);
> >>>>> +            return;
> >>>>> +        }
> >>>>> +    }
> >>>>> +}
> >>>>> +#endif
> >>>>> +
> >>>>>  int ppc_compat_max_threads(PowerPCCPU *cpu)
> >>>>>  {
> >>>>>      const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
> >>>>> diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
> >>>>> index 91e8be8..201a655 100644
> >>>>> --- a/target-ppc/cpu.h
> >>>>> +++ b/target-ppc/cpu.h
> >>>>> @@ -1317,6 +1317,9 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
> >>>>>  bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
> >>>>>                        uint32_t min_compat_pvr, uint32_t max_compat_pvr);
> >>>>>  void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
> >>>>> +#if !defined(CONFIG_USER_ONLY)
> >>>>> +void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
> >>>>> +#endif
> >>>>
> >>>> I would put all ppc*compat*() under #if defined(CONFIG_USER_ONLY) &&
> >>>> defined(TARGET_PPC64) (or even moved this to target-ppc/Makefile.objs).
> >>>
> >>> I was originally going to do that, but decided against it.
> >>>
> >>>> Otherwise, functions like ppc_check_compat() have #if
> >>>> !defined(CONFIG_USER_ONLY) which suggests that the rest of
> >>>> ppc_check_compat() can actually be executed in ppc64-linux-user (while it
> >>>> cannot, can it?).
> >>>
> >>> It won't be, but there's no theoretical reason they couldn't be.  User
> >>> mode, like spapr, doesn't execute hypervisor privilege code, and so
> >>> the PCR isn't owned by the "guest" (if you can call the user mode
> >>> executable that).  Which means it could make sense to set it from the
> >>> outside, although that's not something we currently do.
> >>
> >> Compatibility modes are designed to disable sets of instructions to keep
> >> working old userspace software which relies on some opcodes to be invalid.
> >>
> >> linux-user is TCG, right? The user can pick any CPU he likes if there is
> >> need to run such an old software, why on earth would anyone bother with
> >> this compat mode in linux-user?
> > 
> > True, I can't really see any reason to do that.
> > 
> > On the other hand, compat mode does at least make theoretical sense,
> > whereas, for example, compat mode on powernv is fundamentally
> > nonsense.  At this point I'm not terribly include to take away the
> > (token) user-only support unless there's a compelling reason *not* to
> > include it.
> 
> What would make a compelling reason? :)
> 
> This will make makefile simpler and will reduce number of #ifdef, and in
> fact it is not supported now anyway, it has not even been tried.

Hm, ok, you convinced me.  I'll make the compat stuff only compile on
softmmu.

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic
  2016-10-30 11:12 ` [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic David Gibson
  2016-10-31  5:00   ` Alexey Kardashevskiy
@ 2016-11-10 17:54   ` Michael Roth
  2016-11-10 23:50     ` David Gibson
  1 sibling, 1 reply; 75+ messages in thread
From: Michael Roth @ 2016-11-10 17:54 UTC (permalink / raw)
  To: David Gibson, nikunj, aik; +Cc: thuth, lvivier, qemu-ppc, qemu-devel

Quoting David Gibson (2016-10-30 06:12:01)
> During boot, PAPR guests negotiate CPU model support with the
> ibm,client-architecture-support mechanism.  The logic to implement this in
> qemu is very convoluted.  This cleans it up to be cleaner, using the new
> ppc_check_compat() call.
> 
> The new logic for choosing a compatibility mode is:
>     1. If the guest lists the CPU's real PVR as supported *AND* no
>        maximum compatibility mode has been requested on the command line
>        then we use "raw" mode - the CPU acts with full capabilities.
>     2. Otherwise, we pick the most recent compatibility mode which is
>        both supported by the CPU, and is advertised as supported by the
>        guest.
> I think the original code approximated the same thing, but it's hard to be
> sure, and I think it had some weird edge cases.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/ppc/spapr_hcall.c | 107 +++++++++++++++++----------------------------------
>  hw/ppc/trace-events  |   2 +-
>  2 files changed, 37 insertions(+), 72 deletions(-)
> 
> diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> index d93f580..3bd6d06 100644
> --- a/hw/ppc/spapr_hcall.c
> +++ b/hw/ppc/spapr_hcall.c
> @@ -895,98 +895,63 @@ static void do_set_compat(CPUState *cs, void *arg)
>      ppc_set_compat(cpu, s->compat_pvr, &s->err);
>  }
> 
> -#define get_compat_level(cpuver) ( \
> -    ((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \
> -    ((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \
> -    ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
> -    ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
> -
> -static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
> -                                  unsigned max_lvl, unsigned *compat_lvl,
> -                                  unsigned *compat_pvr)
> -{
> -    unsigned lvl = get_compat_level(pvr);
> -    bool is205, is206, is207;
> -
> -    if (!lvl) {
> -        return;
> -    }
> -
> -    /* If it is a logical PVR, try to determine the highest level */
> -    is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) &&
> -            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
> -    is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) &&
> -            ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
> -             (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
> -    is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) &&
> -            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07));
> -
> -    if (is205 || is206 || is207) {
> -        if (!max_lvl) {
> -            /* User did not set the level, choose the highest */
> -            if (*compat_lvl <= lvl) {
> -                *compat_lvl = lvl;
> -                *compat_pvr = pvr;
> -            }
> -        } else if (max_lvl >= lvl) {
> -            /* User chose the level, don't set higher than this */
> -            *compat_lvl = lvl;
> -            *compat_pvr = pvr;
> -        }
> -    }
> -}
> -
> -static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
> +static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
>                                                    sPAPRMachineState *spapr,
>                                                    target_ulong opcode,
>                                                    target_ulong *args)
>  {
>      target_ulong list = ppc64_phys_to_real(args[0]);
>      target_ulong ov_table;
> -    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
>      CPUState *cs;
> -    bool cpu_match = false;
> -    unsigned old_compat_pvr = cpu_->compat_pvr;
> -    unsigned compat_lvl = 0, compat_pvr = 0;
> -    unsigned max_lvl = get_compat_level(cpu_->max_compat);
> -    int counter;
> +    bool explicit_match = false; /* Matched the CPU's real PVR */
> +    uint32_t max_compat = cpu->max_compat;
> +    uint32_t best_compat = 0;
> +    int i;
>      sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
> 
> -    /* Parse PVR list */
> -    for (counter = 0; counter < 512; ++counter) {
> +    /*
> +     * We scan the supplied table of PVRs looking for two things
> +     *   1. Is our real CPU PVR in the list?
> +     *   2. What's the "best" listed logical PVR
> +     */
> +    for (i = 0; i < 512; ++i) {
>          uint32_t pvr, pvr_mask;
> 
> -        pvr_mask = ldl_be_phys(&address_space_memory, list);
> -        list += 4;
>          pvr = ldl_be_phys(&address_space_memory, list);
> -        list += 4;
> -
> -        trace_spapr_cas_pvr_try(pvr);
> -        if (!max_lvl &&
> -            ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
> -            cpu_match = true;
> -            compat_pvr = 0;
> -        } else if (pvr == cpu_->compat_pvr) {
> -            cpu_match = true;
> -            compat_pvr = cpu_->compat_pvr;
> -        } else if (!cpu_match) {
> -            cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &compat_pvr);
> -        }
> -        /* Terminator record */
> +        pvr_mask = ldl_be_phys(&address_space_memory, list + 4);
> +        list += 8;
> +
>          if (~pvr_mask & pvr) {
> -            break;
> +            break; /* Terminator record */
>          }
> +
> +        if ((cpu->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask)) {
> +            explicit_match = true;

The previous code only did this check if max_lvl/max_compat was set. I'm
not sure if it's possible in practice, but in theory this PVR might also
happen to be the next best_compat PVR, but since we test positive here
we may not not set best_compat accordingly.

> +        } else {
> +            if (ppc_check_compat(cpu, pvr, best_compat, max_compat)) {
> +                best_compat = pvr;
> +            }
> +        }
> +    }
> +
> +    if (!max_compat && explicit_match) {
> +        /* If the guest explicitly supports the CPU, *and* user hasn't
> +         * requested a compatibility mode, use "raw" mode */
> +        best_compat = 0;
> +    } else if (best_compat == 0) {
> +        /* Didn't find any supported compat modes */
> +        /* FIXME: what's the right error here? */
> +        return H_HARDWARE;
>      }
> 
>      /* Parsing finished */
> -    trace_spapr_cas_pvr(cpu_->compat_pvr, cpu_match,
> -                        compat_pvr, pcc->pcr_mask);
> +    trace_spapr_cas_pvr(cpu->compat_pvr, explicit_match, best_compat);
> 
>      /* Update CPUs */
> -    if (old_compat_pvr != compat_pvr) {
> +    if (cpu->compat_pvr != best_compat) {
>          CPU_FOREACH(cs) {
>              SetCompatState s = {
> -                .compat_pvr = compat_pvr,
> +                .compat_pvr = best_compat,
>                  .err = NULL,
>              };
> 
> diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
> index 2297ead..604ac92 100644
> --- a/hw/ppc/trace-events
> +++ b/hw/ppc/trace-events
> @@ -15,7 +15,7 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
> 
>  # hw/ppc/spapr_hcall.c
>  spapr_cas_pvr_try(uint32_t pvr) "%x"
> -spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64
> +spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=%x, explicit_match=%u, new=%x"
> 
>  # hw/ppc/spapr_iommu.c
>  spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
> -- 
> 2.7.4
> 

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

* Re: [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic
  2016-11-10 17:54   ` Michael Roth
@ 2016-11-10 23:50     ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-10 23:50 UTC (permalink / raw)
  To: Michael Roth; +Cc: nikunj, aik, thuth, lvivier, qemu-ppc, qemu-devel

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

On Thu, Nov 10, 2016 at 11:54:13AM -0600, Michael Roth wrote:
> Quoting David Gibson (2016-10-30 06:12:01)
> > During boot, PAPR guests negotiate CPU model support with the
> > ibm,client-architecture-support mechanism.  The logic to implement this in
> > qemu is very convoluted.  This cleans it up to be cleaner, using the new
> > ppc_check_compat() call.
> > 
> > The new logic for choosing a compatibility mode is:
> >     1. If the guest lists the CPU's real PVR as supported *AND* no
> >        maximum compatibility mode has been requested on the command line
> >        then we use "raw" mode - the CPU acts with full capabilities.
> >     2. Otherwise, we pick the most recent compatibility mode which is
> >        both supported by the CPU, and is advertised as supported by the
> >        guest.
> > I think the original code approximated the same thing, but it's hard to be
> > sure, and I think it had some weird edge cases.
> > 
> > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > ---
> >  hw/ppc/spapr_hcall.c | 107 +++++++++++++++++----------------------------------
> >  hw/ppc/trace-events  |   2 +-
> >  2 files changed, 37 insertions(+), 72 deletions(-)
> > 
> > diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
> > index d93f580..3bd6d06 100644
> > --- a/hw/ppc/spapr_hcall.c
> > +++ b/hw/ppc/spapr_hcall.c
> > @@ -895,98 +895,63 @@ static void do_set_compat(CPUState *cs, void *arg)
> >      ppc_set_compat(cpu, s->compat_pvr, &s->err);
> >  }
> > 
> > -#define get_compat_level(cpuver) ( \
> > -    ((cpuver) == CPU_POWERPC_LOGICAL_2_05) ? 2050 : \
> > -    ((cpuver) == CPU_POWERPC_LOGICAL_2_06) ? 2060 : \
> > -    ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
> > -    ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
> > -
> > -static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
> > -                                  unsigned max_lvl, unsigned *compat_lvl,
> > -                                  unsigned *compat_pvr)
> > -{
> > -    unsigned lvl = get_compat_level(pvr);
> > -    bool is205, is206, is207;
> > -
> > -    if (!lvl) {
> > -        return;
> > -    }
> > -
> > -    /* If it is a logical PVR, try to determine the highest level */
> > -    is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) &&
> > -            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
> > -    is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) &&
> > -            ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
> > -             (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
> > -    is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) &&
> > -            (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07));
> > -
> > -    if (is205 || is206 || is207) {
> > -        if (!max_lvl) {
> > -            /* User did not set the level, choose the highest */
> > -            if (*compat_lvl <= lvl) {
> > -                *compat_lvl = lvl;
> > -                *compat_pvr = pvr;
> > -            }
> > -        } else if (max_lvl >= lvl) {
> > -            /* User chose the level, don't set higher than this */
> > -            *compat_lvl = lvl;
> > -            *compat_pvr = pvr;
> > -        }
> > -    }
> > -}
> > -
> > -static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
> > +static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
> >                                                    sPAPRMachineState *spapr,
> >                                                    target_ulong opcode,
> >                                                    target_ulong *args)
> >  {
> >      target_ulong list = ppc64_phys_to_real(args[0]);
> >      target_ulong ov_table;
> > -    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
> >      CPUState *cs;
> > -    bool cpu_match = false;
> > -    unsigned old_compat_pvr = cpu_->compat_pvr;
> > -    unsigned compat_lvl = 0, compat_pvr = 0;
> > -    unsigned max_lvl = get_compat_level(cpu_->max_compat);
> > -    int counter;
> > +    bool explicit_match = false; /* Matched the CPU's real PVR */
> > +    uint32_t max_compat = cpu->max_compat;
> > +    uint32_t best_compat = 0;
> > +    int i;
> >      sPAPROptionVector *ov5_guest, *ov5_cas_old, *ov5_updates;
> > 
> > -    /* Parse PVR list */
> > -    for (counter = 0; counter < 512; ++counter) {
> > +    /*
> > +     * We scan the supplied table of PVRs looking for two things
> > +     *   1. Is our real CPU PVR in the list?
> > +     *   2. What's the "best" listed logical PVR
> > +     */
> > +    for (i = 0; i < 512; ++i) {
> >          uint32_t pvr, pvr_mask;
> > 
> > -        pvr_mask = ldl_be_phys(&address_space_memory, list);
> > -        list += 4;
> >          pvr = ldl_be_phys(&address_space_memory, list);
> > -        list += 4;
> > -
> > -        trace_spapr_cas_pvr_try(pvr);
> > -        if (!max_lvl &&
> > -            ((cpu_->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask))) {
> > -            cpu_match = true;
> > -            compat_pvr = 0;
> > -        } else if (pvr == cpu_->compat_pvr) {
> > -            cpu_match = true;
> > -            compat_pvr = cpu_->compat_pvr;
> > -        } else if (!cpu_match) {
> > -            cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &compat_pvr);
> > -        }
> > -        /* Terminator record */
> > +        pvr_mask = ldl_be_phys(&address_space_memory, list + 4);
> > +        list += 8;
> > +
> >          if (~pvr_mask & pvr) {
> > -            break;
> > +            break; /* Terminator record */
> >          }
> > +
> > +        if ((cpu->env.spr[SPR_PVR] & pvr_mask) == (pvr & pvr_mask)) {
> > +            explicit_match = true;
> 
> The previous code only did this check if max_lvl/max_compat was set. I'm
> not sure if it's possible in practice, but in theory this PVR might also
> happen to be the next best_compat PVR, but since we test positive here
> we may not not set best_compat accordingly.

I guess it's theoretically possible.  But that would only happen if
the guest advertised a pvr+mask which covered both a valid real PVR
and a valid compatibility PVR.  Since the logical PVRs are in a wholly
different range and don't look like real PVR values at all, I think
that's vanishingly unlikely.

> 
> > +        } else {
> > +            if (ppc_check_compat(cpu, pvr, best_compat, max_compat)) {
> > +                best_compat = pvr;
> > +            }
> > +        }
> > +    }
> > +
> > +    if (!max_compat && explicit_match) {
> > +        /* If the guest explicitly supports the CPU, *and* user hasn't
> > +         * requested a compatibility mode, use "raw" mode */
> > +        best_compat = 0;
> > +    } else if (best_compat == 0) {
> > +        /* Didn't find any supported compat modes */
> > +        /* FIXME: what's the right error here? */
> > +        return H_HARDWARE;
> >      }
> > 
> >      /* Parsing finished */
> > -    trace_spapr_cas_pvr(cpu_->compat_pvr, cpu_match,
> > -                        compat_pvr, pcc->pcr_mask);
> > +    trace_spapr_cas_pvr(cpu->compat_pvr, explicit_match, best_compat);
> > 
> >      /* Update CPUs */
> > -    if (old_compat_pvr != compat_pvr) {
> > +    if (cpu->compat_pvr != best_compat) {
> >          CPU_FOREACH(cs) {
> >              SetCompatState s = {
> > -                .compat_pvr = compat_pvr,
> > +                .compat_pvr = best_compat,
> >                  .err = NULL,
> >              };
> > 
> > diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
> > index 2297ead..604ac92 100644
> > --- a/hw/ppc/trace-events
> > +++ b/hw/ppc/trace-events
> > @@ -15,7 +15,7 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
> > 
> >  # hw/ppc/spapr_hcall.c
> >  spapr_cas_pvr_try(uint32_t pvr) "%x"
> > -spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64
> > +spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=%x, explicit_match=%u, new=%x"
> > 
> >  # hw/ppc/spapr_iommu.c
> >  spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
> 

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode
  2016-11-10  1:59         ` David Gibson
@ 2016-11-10 23:55           ` Michael Roth
  2016-11-14  1:15             ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Michael Roth @ 2016-11-10 23:55 UTC (permalink / raw)
  To: David Gibson, Alexey Kardashevskiy
  Cc: nikunj, thuth, lvivier, qemu-ppc, qemu-devel

Quoting David Gibson (2016-11-09 19:59:37)
> On Tue, Nov 08, 2016 at 04:51:10PM +1100, Alexey Kardashevskiy wrote:
> > On 08/11/16 16:19, David Gibson wrote:
> > > On Fri, Nov 04, 2016 at 04:58:47PM +1100, Alexey Kardashevskiy wrote:
> > >> On 30/10/16 22:12, David Gibson wrote:
> > >>> Server-class POWER CPUs can be put into several compatibility modes.  These
> > >>> can be specified on the command line, or negotiated by the guest during
> > >>> boot.
> > >>>
> > >>> Currently we don't migrate the compatibility mode, which means after a
> > >>> migration the guest will revert to running with whatever compatibility
> > >>> mode (or none) specified on the command line.
> > >>>
> > >>> With the limited range of CPUs currently used, this doesn't usually cause
> > >>> a problem, but it could.  Fix this by adding the compatibility mode (if
> > >>> set) to the migration stream.
> > >>>
> > >>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > >>> ---
> > >>>  target-ppc/machine.c | 34 ++++++++++++++++++++++++++++++++++
> > >>>  1 file changed, 34 insertions(+)
> > >>>
> > >>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> > >>> index 4820f22..5d87ff6 100644
> > >>> --- a/target-ppc/machine.c
> > >>> +++ b/target-ppc/machine.c
> > >>> @@ -9,6 +9,7 @@
> > >>>  #include "mmu-hash64.h"
> > >>>  #include "migration/cpu.h"
> > >>>  #include "exec/exec-all.h"
> > >>> +#include "qapi/error.h"
> > >>>  
> > >>>  static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
> > >>>  {
> > >>> @@ -176,6 +177,20 @@ static int cpu_post_load(void *opaque, int version_id)
> > >>>       * software has to take care of running QEMU in a compatible mode.
> > >>>       */
> > >>>      env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
> > >>> +
> > >>> +#if defined(TARGET_PPC64)
> > >>> +    if (cpu->compat_pvr) {
> > >>> +        Error *local_err = NULL;
> > >>> +
> > >>> +        ppc_set_compat(cpu, cpu->compat_pvr, &local_err);
> > >>> +        if (local_err) {
> > >>> +            error_report_err(local_err);
> > >>> +            error_free(local_err);
> > >>> +            return -1;
> > >>> +        }
> > >>> +    }
> > >>> +#endif
> > >>> +
> > >>>      env->lr = env->spr[SPR_LR];
> > >>>      env->ctr = env->spr[SPR_CTR];
> > >>>      cpu_write_xer(env, env->spr[SPR_XER]);
> > >>> @@ -528,6 +543,24 @@ static const VMStateDescription vmstate_tlbmas = {
> > >>>      }
> > >>>  };
> > >>>  
> > >>> +static bool compat_needed(void *opaque)
> > >>> +{
> > >>> +    PowerPCCPU *cpu = opaque;
> > >>> +
> > >>> +    return cpu->compat_pvr != 0;
> > >>
> > >>
> > >> Finally got to trying how this affects migration :)
> > >>
> > >> This breaks migration to QEMU <=2.7, and it should not at least when both
> > >> source and destination are running with  -cpu host,compat=power7.
> > > 
> > > IIUC, we don't generally try to maintain backwards migration, even for
> > > old machine types.
> > 
> > 
> > I thought the opposite - we generally try to maintain it, this is pretty
> > much why we use these subsections in cases like this; otherwise you could
> > just add a new field and bump the vmstate_ppc_cpu.version.
> 
> Hm, I guess that's true.  We do at least try to allow backwards
> migration, we just don't insist on it.  The example here partially
> suceeds - it will allow backwards migration for CPUs in raw mode.

What if we changed the condition to cpu->compat_pvr != cpu->max_compat?
Assuming each end sets compat=powerX (which seems like a reasonable
requirement for migration), it seems like in  most cases the guest would end
up negotiating max_compat anyway. It's only in cases where it doesn't that we
end up in an ambiguous state.

Newer QEMU would guard against this by migrating it's compat_pvr
accordingly (which will probably become more important with p9 guests
potentially running older kernels), but otherwise it seems like we could
maintain backwards migration in most cases.

Although with the proposed version bump for vmstate_spapr_pci I guess
the discussion is somewhat moot unless we decide we rely want to
maintain backward migration...

> 
> I'll look at just bumping the version instead.
> 
> > 
> > 
> > > 
> > >>
> > >>
> > >>> +}
> > >>> +
> > >>> +static const VMStateDescription vmstate_compat = {
> > >>> +    .name = "cpu/compat",
> > >>> +    .version_id = 1,
> > >>> +    .minimum_version_id = 1,
> > >>> +    .needed = compat_needed,
> > >>> +    .fields = (VMStateField[]) {
> > >>> +        VMSTATE_UINT32(compat_pvr, PowerPCCPU),
> > >>> +        VMSTATE_END_OF_LIST()
> > >>> +    }
> > >>> +};
> > >>> +
> > >>>  const VMStateDescription vmstate_ppc_cpu = {
> > >>>      .name = "cpu",
> > >>>      .version_id = 5,
> > >>> @@ -580,6 +613,7 @@ const VMStateDescription vmstate_ppc_cpu = {
> > >>>          &vmstate_tlb6xx,
> > >>>          &vmstate_tlbemb,
> > >>>          &vmstate_tlbmas,
> > >>> +        &vmstate_compat,
> > >>>          NULL
> > >>>      }
> > >>>  };
> > >>>
> > >>
> > >>
> > > 
> > 
> > 
> 
> 
> 
> 
> -- 
> 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

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

* Re: [Qemu-devel] [Qemu-ppc] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration
  2016-11-08  5:31     ` David Gibson
@ 2016-11-11 18:13       ` Greg Kurz
  2016-11-14  2:34         ` Alexey Kardashevskiy
  0 siblings, 1 reply; 75+ messages in thread
From: Greg Kurz @ 2016-11-11 18:13 UTC (permalink / raw)
  To: David Gibson
  Cc: Alexey Kardashevskiy, lvivier, thuth, mdroth, qemu-devel, qemu-ppc

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

On Tue, 8 Nov 2016 16:31:08 +1100
David Gibson <david@gibson.dropbear.id.au> wrote:

> On Fri, Nov 04, 2016 at 04:52:39PM +1100, Alexey Kardashevskiy wrote:
> > On 30/10/16 22:12, David Gibson wrote:  
> > > When vmstate for the ppc cpu was introduced in a90db158 "target-ppc:
> > > Convert ppc cpu savevm to VMStateDescription", several "sanity check"
> > > fields were included, verifying that certain cpu parameters matched between
> > > source and destination.
> > > 
> > > This turns out not to have been a good idea.  For one thing it's redundant
> > > with existing checks for a compatible cpu version at either end.  But more
> > > importantly the insns_flags and insns_flags2 checks actively break things:
> > > they expose what's essentially an internal TCG implementation detail in the
> > > migration stream.  That means that when new instruction classes are added
> > > or rearranged, migration can break.
> > > 
> > > This removes these ill-considered sanity checks.
> > > 
> > > Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > > ---
> > >  target-ppc/machine.c | 8 ++++----
> > >  1 file changed, 4 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> > > index 62b9e94..453ef0a 100644
> > > --- a/target-ppc/machine.c
> > > +++ b/target-ppc/machine.c
> > > @@ -602,10 +602,10 @@ const VMStateDescription vmstate_ppc_cpu = {
> > >          /* FIXME: access_type? */
> > >  
> > >          /* Sanity checking */
> > > -        VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU),
> > > -        VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU),
> > > -        VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU),
> > > -        VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU),
> > > +        VMSTATE_UNUSED(sizeof(target_ulong) /* msr_mask */
> > > +                       + sizeof(uint64_t) /* insns_flags */
> > > +                       + sizeof(uint64_t) /* insns_flags2 */
> > > +                       + sizeof(uint32_t)), /* nb_BATs */  
> > 
> > 
> > This breaks migration to older QEMU:
> > 
> > 25055@1478238734.537761:vmstate_load_field_error field "env.msr_mask" load
> > failed, ret = -22  
> 
> Again, I don't think we generally support backwards migration.
> 
> That said, it would be nice here to do a "set to this field on
> ourgoing migration, but ignore on incoming migration".  Do you know a
> way to do that?
> 

This doesn't exist in vmstate but it is certainly doable. An alternative
would be to always send the fields, but have the destination to use
pre_load and post_load callbacks to preserve its state.

> a
> > 
> > 
> >   
> > >          VMSTATE_END_OF_LIST()
> > >      },
> > >      .subsections = (const VMStateDescription*[]) {
> > >   
> > 
> >   
> 


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

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

* Re: [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode
  2016-11-10 23:55           ` Michael Roth
@ 2016-11-14  1:15             ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-14  1:15 UTC (permalink / raw)
  To: Michael Roth
  Cc: Alexey Kardashevskiy, nikunj, thuth, lvivier, qemu-ppc, qemu-devel

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

On Thu, Nov 10, 2016 at 05:55:36PM -0600, Michael Roth wrote:
> Quoting David Gibson (2016-11-09 19:59:37)
> > On Tue, Nov 08, 2016 at 04:51:10PM +1100, Alexey Kardashevskiy wrote:
> > > On 08/11/16 16:19, David Gibson wrote:
> > > > On Fri, Nov 04, 2016 at 04:58:47PM +1100, Alexey Kardashevskiy wrote:
> > > >> On 30/10/16 22:12, David Gibson wrote:
> > > >>> Server-class POWER CPUs can be put into several compatibility modes.  These
> > > >>> can be specified on the command line, or negotiated by the guest during
> > > >>> boot.
> > > >>>
> > > >>> Currently we don't migrate the compatibility mode, which means after a
> > > >>> migration the guest will revert to running with whatever compatibility
> > > >>> mode (or none) specified on the command line.
> > > >>>
> > > >>> With the limited range of CPUs currently used, this doesn't usually cause
> > > >>> a problem, but it could.  Fix this by adding the compatibility mode (if
> > > >>> set) to the migration stream.
> > > >>>
> > > >>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > > >>> ---
> > > >>>  target-ppc/machine.c | 34 ++++++++++++++++++++++++++++++++++
> > > >>>  1 file changed, 34 insertions(+)
> > > >>>
> > > >>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> > > >>> index 4820f22..5d87ff6 100644
> > > >>> --- a/target-ppc/machine.c
> > > >>> +++ b/target-ppc/machine.c
> > > >>> @@ -9,6 +9,7 @@
> > > >>>  #include "mmu-hash64.h"
> > > >>>  #include "migration/cpu.h"
> > > >>>  #include "exec/exec-all.h"
> > > >>> +#include "qapi/error.h"
> > > >>>  
> > > >>>  static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
> > > >>>  {
> > > >>> @@ -176,6 +177,20 @@ static int cpu_post_load(void *opaque, int version_id)
> > > >>>       * software has to take care of running QEMU in a compatible mode.
> > > >>>       */
> > > >>>      env->spr[SPR_PVR] = env->spr_cb[SPR_PVR].default_value;
> > > >>> +
> > > >>> +#if defined(TARGET_PPC64)
> > > >>> +    if (cpu->compat_pvr) {
> > > >>> +        Error *local_err = NULL;
> > > >>> +
> > > >>> +        ppc_set_compat(cpu, cpu->compat_pvr, &local_err);
> > > >>> +        if (local_err) {
> > > >>> +            error_report_err(local_err);
> > > >>> +            error_free(local_err);
> > > >>> +            return -1;
> > > >>> +        }
> > > >>> +    }
> > > >>> +#endif
> > > >>> +
> > > >>>      env->lr = env->spr[SPR_LR];
> > > >>>      env->ctr = env->spr[SPR_CTR];
> > > >>>      cpu_write_xer(env, env->spr[SPR_XER]);
> > > >>> @@ -528,6 +543,24 @@ static const VMStateDescription vmstate_tlbmas = {
> > > >>>      }
> > > >>>  };
> > > >>>  
> > > >>> +static bool compat_needed(void *opaque)
> > > >>> +{
> > > >>> +    PowerPCCPU *cpu = opaque;
> > > >>> +
> > > >>> +    return cpu->compat_pvr != 0;
> > > >>
> > > >>
> > > >> Finally got to trying how this affects migration :)
> > > >>
> > > >> This breaks migration to QEMU <=2.7, and it should not at least when both
> > > >> source and destination are running with  -cpu host,compat=power7.
> > > > 
> > > > IIUC, we don't generally try to maintain backwards migration, even for
> > > > old machine types.
> > > 
> > > 
> > > I thought the opposite - we generally try to maintain it, this is pretty
> > > much why we use these subsections in cases like this; otherwise you could
> > > just add a new field and bump the vmstate_ppc_cpu.version.
> > 
> > Hm, I guess that's true.  We do at least try to allow backwards
> > migration, we just don't insist on it.  The example here partially
> > suceeds - it will allow backwards migration for CPUs in raw mode.
> 
> What if we changed the condition to cpu->compat_pvr != cpu->max_compat?
> Assuming each end sets compat=powerX (which seems like a reasonable
> requirement for migration), it seems like in  most cases the guest would end
> up negotiating max_compat anyway. It's only in cases where it doesn't that we
> end up in an ambiguous state.

So, since I've already given up on backwards migration in other cases,
I've changed this in my next version to simply (cpu->vhyp != NULL), so
the compat mode (including raw) is always transferred on pseries.

> Newer QEMU would guard against this by migrating it's compat_pvr
> accordingly (which will probably become more important with p9 guests
> potentially running older kernels), but otherwise it seems like we could
> maintain backwards migration in most cases.
> 
> Although with the proposed version bump for vmstate_spapr_pci I guess
> the discussion is somewhat moot unless we decide we rely want to
> maintain backward migration...

Not enough that it's worth the considerable extra difficulty it
entails, I think.

> 
> > 
> > I'll look at just bumping the version instead.
> > 
> > > 
> > > 
> > > > 
> > > >>
> > > >>
> > > >>> +}
> > > >>> +
> > > >>> +static const VMStateDescription vmstate_compat = {
> > > >>> +    .name = "cpu/compat",
> > > >>> +    .version_id = 1,
> > > >>> +    .minimum_version_id = 1,
> > > >>> +    .needed = compat_needed,
> > > >>> +    .fields = (VMStateField[]) {
> > > >>> +        VMSTATE_UINT32(compat_pvr, PowerPCCPU),
> > > >>> +        VMSTATE_END_OF_LIST()
> > > >>> +    }
> > > >>> +};
> > > >>> +
> > > >>>  const VMStateDescription vmstate_ppc_cpu = {
> > > >>>      .name = "cpu",
> > > >>>      .version_id = 5,
> > > >>> @@ -580,6 +613,7 @@ const VMStateDescription vmstate_ppc_cpu = {
> > > >>>          &vmstate_tlb6xx,
> > > >>>          &vmstate_tlbemb,
> > > >>>          &vmstate_tlbmas,
> > > >>> +        &vmstate_compat,
> > > >>>          NULL
> > > >>>      }
> > > >>>  };
> > > >>>
> > > >>
> > > >>
> > > > 
> > > 
> > > 
> > 
> > 
> > 
> > 
> 

-- 
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] 75+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration
  2016-11-11 18:13       ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
@ 2016-11-14  2:34         ` Alexey Kardashevskiy
  2016-11-14  6:08           ` David Gibson
  0 siblings, 1 reply; 75+ messages in thread
From: Alexey Kardashevskiy @ 2016-11-14  2:34 UTC (permalink / raw)
  To: Greg Kurz, David Gibson; +Cc: lvivier, thuth, mdroth, qemu-devel, qemu-ppc

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

On 12/11/16 05:13, Greg Kurz wrote:
> On Tue, 8 Nov 2016 16:31:08 +1100
> David Gibson <david@gibson.dropbear.id.au> wrote:
> 
>> On Fri, Nov 04, 2016 at 04:52:39PM +1100, Alexey Kardashevskiy wrote:
>>> On 30/10/16 22:12, David Gibson wrote:  
>>>> When vmstate for the ppc cpu was introduced in a90db158 "target-ppc:
>>>> Convert ppc cpu savevm to VMStateDescription", several "sanity check"
>>>> fields were included, verifying that certain cpu parameters matched between
>>>> source and destination.
>>>>
>>>> This turns out not to have been a good idea.  For one thing it's redundant
>>>> with existing checks for a compatible cpu version at either end.  But more
>>>> importantly the insns_flags and insns_flags2 checks actively break things:
>>>> they expose what's essentially an internal TCG implementation detail in the
>>>> migration stream.  That means that when new instruction classes are added
>>>> or rearranged, migration can break.
>>>>
>>>> This removes these ill-considered sanity checks.
>>>>
>>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
>>>> ---
>>>>  target-ppc/machine.c | 8 ++++----
>>>>  1 file changed, 4 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
>>>> index 62b9e94..453ef0a 100644
>>>> --- a/target-ppc/machine.c
>>>> +++ b/target-ppc/machine.c
>>>> @@ -602,10 +602,10 @@ const VMStateDescription vmstate_ppc_cpu = {
>>>>          /* FIXME: access_type? */
>>>>  
>>>>          /* Sanity checking */
>>>> -        VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU),
>>>> -        VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU),
>>>> -        VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU),
>>>> -        VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU),
>>>> +        VMSTATE_UNUSED(sizeof(target_ulong) /* msr_mask */
>>>> +                       + sizeof(uint64_t) /* insns_flags */
>>>> +                       + sizeof(uint64_t) /* insns_flags2 */
>>>> +                       + sizeof(uint32_t)), /* nb_BATs */  
>>>
>>>
>>> This breaks migration to older QEMU:
>>>
>>> 25055@1478238734.537761:vmstate_load_field_error field "env.msr_mask" load
>>> failed, ret = -22  
>>
>> Again, I don't think we generally support backwards migration.
>>
>> That said, it would be nice here to do a "set to this field on
>> ourgoing migration, but ignore on incoming migration".  Do you know a
>> way to do that?
>>
> 
> This doesn't exist in vmstate but it is certainly doable. An alternative
> would be to always send the fields, but have the destination to use
> pre_load and post_load callbacks to preserve its state.


A simpler way would be:

1. add a copy for each field (s/msr_mask/mig_msr_mask/),
2. get rid of _EQUAL bits,
3. implement .pre_save callback which would initialize mig_xxx

And that's it, .pre_load/.post_load is not needed.




> 
>> a
>>>
>>>
>>>   
>>>>          VMSTATE_END_OF_LIST()
>>>>      },
>>>>      .subsections = (const VMStateDescription*[]) {
>>>>   
>>>
>>>   
>>
> 


-- 
Alexey


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 839 bytes --]

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

* Re: [Qemu-devel] [Qemu-ppc] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration
  2016-11-14  2:34         ` Alexey Kardashevskiy
@ 2016-11-14  6:08           ` David Gibson
  0 siblings, 0 replies; 75+ messages in thread
From: David Gibson @ 2016-11-14  6:08 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: Greg Kurz, lvivier, thuth, mdroth, qemu-devel, qemu-ppc

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

On Mon, Nov 14, 2016 at 01:34:55PM +1100, Alexey Kardashevskiy wrote:
> On 12/11/16 05:13, Greg Kurz wrote:
> > On Tue, 8 Nov 2016 16:31:08 +1100
> > David Gibson <david@gibson.dropbear.id.au> wrote:
> > 
> >> On Fri, Nov 04, 2016 at 04:52:39PM +1100, Alexey Kardashevskiy wrote:
> >>> On 30/10/16 22:12, David Gibson wrote:  
> >>>> When vmstate for the ppc cpu was introduced in a90db158 "target-ppc:
> >>>> Convert ppc cpu savevm to VMStateDescription", several "sanity check"
> >>>> fields were included, verifying that certain cpu parameters matched between
> >>>> source and destination.
> >>>>
> >>>> This turns out not to have been a good idea.  For one thing it's redundant
> >>>> with existing checks for a compatible cpu version at either end.  But more
> >>>> importantly the insns_flags and insns_flags2 checks actively break things:
> >>>> they expose what's essentially an internal TCG implementation detail in the
> >>>> migration stream.  That means that when new instruction classes are added
> >>>> or rearranged, migration can break.
> >>>>
> >>>> This removes these ill-considered sanity checks.
> >>>>
> >>>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> >>>> ---
> >>>>  target-ppc/machine.c | 8 ++++----
> >>>>  1 file changed, 4 insertions(+), 4 deletions(-)
> >>>>
> >>>> diff --git a/target-ppc/machine.c b/target-ppc/machine.c
> >>>> index 62b9e94..453ef0a 100644
> >>>> --- a/target-ppc/machine.c
> >>>> +++ b/target-ppc/machine.c
> >>>> @@ -602,10 +602,10 @@ const VMStateDescription vmstate_ppc_cpu = {
> >>>>          /* FIXME: access_type? */
> >>>>  
> >>>>          /* Sanity checking */
> >>>> -        VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU),
> >>>> -        VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU),
> >>>> -        VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU),
> >>>> -        VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU),
> >>>> +        VMSTATE_UNUSED(sizeof(target_ulong) /* msr_mask */
> >>>> +                       + sizeof(uint64_t) /* insns_flags */
> >>>> +                       + sizeof(uint64_t) /* insns_flags2 */
> >>>> +                       + sizeof(uint32_t)), /* nb_BATs */  
> >>>
> >>>
> >>> This breaks migration to older QEMU:
> >>>
> >>> 25055@1478238734.537761:vmstate_load_field_error field "env.msr_mask" load
> >>> failed, ret = -22  
> >>
> >> Again, I don't think we generally support backwards migration.
> >>
> >> That said, it would be nice here to do a "set to this field on
> >> ourgoing migration, but ignore on incoming migration".  Do you know a
> >> way to do that?
> >>
> > 
> > This doesn't exist in vmstate but it is certainly doable. An alternative
> > would be to always send the fields, but have the destination to use
> > pre_load and post_load callbacks to preserve its state.
> 
> 
> A simpler way would be:
> 
> 1. add a copy for each field (s/msr_mask/mig_msr_mask/),
> 2. get rid of _EQUAL bits,
> 3. implement .pre_save callback which would initialize mig_xxx
> 
> And that's it, .pre_load/.post_load is not needed.

Yeah, it works, but crufts up the runtime structures with extra fields
related only to migration with old versions.  I think just dropping
the backwards migration is a better option in this case.

> 
> 
> 
> 
> > 
> >> a
> >>>
> >>>
> >>>   
> >>>>          VMSTATE_END_OF_LIST()
> >>>>      },
> >>>>      .subsections = (const VMStateDescription*[]) {
> >>>>   
> >>>
> >>>   
> >>
> > 
> 
> 




-- 
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] 75+ messages in thread

end of thread, other threads:[~2016-11-14  6:54 UTC | newest]

Thread overview: 75+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-30 11:11 [Qemu-devel] [RFC 00/17] Clean up compatibility mode handling David Gibson
2016-10-30 11:11 ` [Qemu-devel] [RFC 01/17] ppc: Remove some stub POWER6 models David Gibson
2016-10-31  7:38   ` Thomas Huth
2016-10-31  8:37     ` David Gibson
2016-11-08  3:40   ` David Gibson
2016-10-30 11:11 ` [Qemu-devel] [RFC 02/17] powernv: CPU compatibility modes don't make sense for powernv David Gibson
2016-10-31  7:46   ` Thomas Huth
2016-10-31  8:38     ` David Gibson
2016-10-31 10:35   ` Greg Kurz
2016-10-30 11:11 ` [Qemu-devel] [RFC 03/17] pseries: Always use core objects for CPU construction David Gibson
2016-11-03  8:11   ` Alexey Kardashevskiy
2016-11-04  9:51     ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
2016-11-08  5:34       ` David Gibson
2016-10-30 11:11 ` [Qemu-devel] [RFC 04/17] pseries: Make cpu_update during CAS unconditional David Gibson
2016-11-03  8:24   ` Alexey Kardashevskiy
2016-11-04 10:45   ` Thomas Huth
2016-11-08  3:44     ` David Gibson
2016-10-30 11:11 ` [Qemu-devel] [RFC 05/17] ppc: Clean up and QOMify hypercall emulation David Gibson
2016-11-03  8:50   ` Alexey Kardashevskiy
2016-10-30 11:11 ` [Qemu-devel] [RFC 06/17] ppc: Rename cpu_version to compat_pvr David Gibson
2016-11-04  2:26   ` Alexey Kardashevskiy
2016-11-08  3:48     ` David Gibson
2016-11-04 10:51   ` Thomas Huth
2016-10-30 11:11 ` [Qemu-devel] [RFC 07/17] ppc: Rewrite ppc_set_compat() David Gibson
2016-11-04  2:57   ` Alexey Kardashevskiy
2016-11-08  3:49     ` David Gibson
2016-10-30 11:11 ` [Qemu-devel] [RFC 08/17] ppc: Rewrite ppc_get_compat_smt_threads() David Gibson
2016-11-04  3:37   ` Alexey Kardashevskiy
2016-11-08  5:13     ` David Gibson
2016-10-30 11:12 ` [Qemu-devel] [RFC 09/17] ppc: Validate compatibility modes when setting David Gibson
2016-10-31  5:55   ` Alexey Kardashevskiy
2016-10-31  8:39     ` David Gibson
2016-11-04  3:45       ` Alexey Kardashevskiy
2016-11-08  5:14         ` David Gibson
2016-10-30 11:12 ` [Qemu-devel] [RFC 10/17] pseries: Rewrite CAS PVR compatibility logic David Gibson
2016-10-31  5:00   ` Alexey Kardashevskiy
2016-10-31  5:44     ` David Gibson
2016-11-10 17:54   ` Michael Roth
2016-11-10 23:50     ` David Gibson
2016-10-30 11:12 ` [Qemu-devel] [RFC 11/17] ppc: Add ppc_set_compat_all() David Gibson
2016-11-04  4:01   ` Alexey Kardashevskiy
2016-11-08  5:18     ` David Gibson
2016-11-09  1:27       ` Alexey Kardashevskiy
2016-11-09  3:52         ` David Gibson
2016-11-09  5:18           ` Alexey Kardashevskiy
2016-11-10  3:13             ` David Gibson
2016-10-30 11:12 ` [Qemu-devel] [RFC 12/17] ppc: Migrate compatibility mode David Gibson
2016-11-04  5:58   ` Alexey Kardashevskiy
2016-11-08  5:19     ` David Gibson
2016-11-08  5:51       ` Alexey Kardashevskiy
2016-11-10  1:59         ` David Gibson
2016-11-10 23:55           ` Michael Roth
2016-11-14  1:15             ` David Gibson
2016-10-30 11:12 ` [Qemu-devel] [RFC 13/17] pseries: Move CPU compatibility property to machine David Gibson
2016-11-04  7:43   ` Alexey Kardashevskiy
2016-11-08  5:26     ` David Gibson
2016-11-08  5:56       ` Alexey Kardashevskiy
2016-11-09  4:41         ` David Gibson
2016-10-30 11:12 ` [Qemu-devel] [RFC 14/17] pseries: Reset CPU compatibility mode David Gibson
2016-11-04  7:50   ` Alexey Kardashevskiy
2016-10-30 11:12 ` [Qemu-devel] [RFC 15/17] ppc: Check that CPU model stays consistent across migration David Gibson
2016-11-04  7:54   ` Alexey Kardashevskiy
2016-11-08  5:29     ` David Gibson
2016-11-08  6:03       ` Alexey Kardashevskiy
2016-11-09  4:24         ` David Gibson
2016-11-09  6:06           ` Alexey Kardashevskiy
2016-11-09  6:40             ` David Gibson
2016-10-30 11:12 ` [Qemu-devel] [RFC 16/17] ppc: Remove counter-productive "sanity checks" in migration David Gibson
2016-11-04  5:52   ` Alexey Kardashevskiy
2016-11-08  5:31     ` David Gibson
2016-11-11 18:13       ` [Qemu-devel] [Qemu-ppc] " Greg Kurz
2016-11-14  2:34         ` Alexey Kardashevskiy
2016-11-14  6:08           ` David Gibson
2016-10-30 11:12 ` [Qemu-devel] [RFC 17/17] pseries: Default to POWER8 compatibility mode David Gibson
2016-10-30 11:58   ` David Gibson

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.