qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 8/9] spapr: Implement processor compatibility


From: Alexander Graf
Subject: Re: [Qemu-devel] [PATCH v2 8/9] spapr: Implement processor compatibility in ibm, client-architecture-support
Date: Wed, 21 May 2014 11:57:49 +0200
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:24.0) Gecko/20100101 Thunderbird/24.5.0


On 21.05.14 11:36, Alexey Kardashevskiy wrote:
On 05/21/2014 07:21 PM, Alexander Graf wrote:
On 21.05.14 10:27, Alexey Kardashevskiy wrote:
Modern Linux kernels support last POWERPC CPUs so when a kernel boots,
in most cases it can find a matching cpu_spec in the kernel's cpu_specs
list. However if the kernel is quite old, it may be missing a definition
of the actual CPU. To provide an ability for old kernels to work on modern
hardware, a Processor Compatibility Mode has been introduced
by the PowerISA specification.

  From the hardware prospective, it is supported by the Processor
Compatibility Register (PCR) which is defined in PowerISA. The register
enables one of the compatibility modes (2.05/2.06/2.07).
Since PCR is a hypervisor privileged register and cannot be
directly accessed from the guest, the mode selection is done via
ibm,client-architecture-support (CAS) RTAS call using which the guest
specifies what "raw" and "architected" CPU versions it supports.
QEMU works out the best match, changes a "cpu-version" property of
every CPU and notifies the guest about the change by setting these
properties in the buffer passed as a response on a custom H_CAS hypercall.

This implements ibm,client-architecture-support parameters parsing
(now only for PVRs) and cooks the device tree diff with new values for
"cpu-version", "ibm,ppc-interrupt-server#s" and
"ibm,ppc-interrupt-server#s" properties.

Signed-off-by: Alexey Kardashevskiy <address@hidden>
---
   hw/ppc/spapr.c       |  4 ++-
   hw/ppc/spapr_hcall.c | 85
++++++++++++++++++++++++++++++++++++++++++++++++++++
   trace-events         |  4 +++
   3 files changed, 92 insertions(+), 1 deletion(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 14c72d9..020426a 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -34,6 +34,7 @@
   #include "sysemu/kvm.h"
   #include "kvm_ppc.h"
   #include "mmu-hash64.h"
+#include "qom/cpu.h"
     #include "hw/boards.h"
   #include "hw/ppc/ppc.h"
@@ -601,7 +602,8 @@ int spapr_h_cas_compose_response(target_ulong addr,
target_ulong size)
       _FDT((fdt_open_into(fdt_skel, fdt, size)));
       g_free(fdt_skel);
   -    /* Place to make changes to the tree */
+    /* Fix skeleton up */
+    _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
         /* Pack resulting tree */
       _FDT((fdt_pack(fdt)));
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 2f6aa5c..2e0a49c 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -3,6 +3,9 @@
   #include "helper_regs.h"
   #include "hw/ppc/spapr.h"
   #include "mmu-hash64.h"
+#include "cpu-models.h"
+#include "trace.h"
+#include "kvm_ppc.h"
     struct SPRSyncState {
       CPUState *cs;
@@ -752,12 +755,94 @@ out:
       return ret;
   }
   +#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 target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
                                                     sPAPREnvironment *spapr,
                                                     target_ulong opcode,
                                                     target_ulong *args)
   {
       target_ulong list = args[0];
+    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 max_lvl = get_compat_level(cpu_->max_compat);
+
+    /* Parse PVR list */
+    for ( ; ; ) {
+        uint32_t pvr, pvr_mask;
+
+        pvr_mask = rtas_ld(list, 0);
+        list += 4;
+        pvr = rtas_ld(list, 0);
+        list += 4;
+
+        trace_spapr_cas_pvr_try(pvr);
+        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) {
+            cpu_match = true;
+            cpu_version = cpu_->cpu_version;
+        } else if (!cpu_match) {
+            /* If it is a logical PVR, try to determine the highest
level */
+            unsigned lvl = get_compat_level(pvr);
+            if (lvl) {
+                bool is205 = (pcc_->pcr_mask & PCR_COMPAT_2_05) &&
+                     (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
+                bool is206 = (pcc_->pcr_mask & PCR_COMPAT_2_06) &&
+                    ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
+                    (lvl ==
get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
+
+                if (is205 || is206) {
+                    if (!max_lvl) {
+                        /* User did not set the level, choose the
highest */
+                        if (compat_lvl <= lvl) {
+                            compat_lvl = lvl;
+                            cpu_version = pvr;
+                        }
+                    } else if (max_lvl >= lvl) {
+                        /* User chose the level, don't set higher than
this */
+                        compat_lvl = lvl;
+                        cpu_version = pvr;
+                    }
+                }
+            }
+        }
+        /* Terminator record */
+        if (~pvr_mask & pvr) {
This loop can be used by the guest to stall QEMU for a long period of time,
no? Better add a safety net check somewhere to allow for early abort.
Like what? No more than 64 PVRs would be enough?

Yeah, choose a random (high) number. If you like make it 512 to be safe for a few generations :).


Alex




reply via email to

[Prev in Thread] Current Thread [Next in Thread]