qemu-ppc
[Top][All Lists]
Advanced

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

[Qemu-ppc] [PATCH v2 2/2] spapr-hcall: fix H_SET_MODE


From: Alexey Kardashevskiy
Subject: [Qemu-ppc] [PATCH v2 2/2] spapr-hcall: fix H_SET_MODE
Date: Tue, 21 Jan 2014 21:05:35 +1100

This changes resource code definitions to ones used in the host kernel.

This fixes H_SET_MODE_RESOURCE_LE (change between big endian and
little endian) to update registers from KVM before changing LPCR value.

This adds handling of H_SET_MODE_RESOURCE_ADDR_TRANS_MODE, for POWER8
(PowerISA 2.07) only.

This adds a set_spr() helper to update an SPR in a CPU's context to avoid 
possible
races.

This makes use of the set_spr() helper for LPCR update in H_SET_MODE handler.

Signed-off-by: Alexey Kardashevskiy <address@hidden>
---
 hw/ppc/spapr_hcall.c   | 64 +++++++++++++++++++++++++++++++++++++++++++-------
 include/hw/ppc/spapr.h |  9 +++++--
 target-ppc/cpu.h       |  2 ++
 3 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index f755a53..7e4fc5f 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -4,6 +4,33 @@
 #include "hw/ppc/spapr.h"
 #include "mmu-hash64.h"
 
+struct spr_sync_struct {
+    CPUState *cs;
+    int spr;
+    target_ulong value;
+    target_ulong mask;
+};
+
+static void do_spr_sync(void *arg)
+{
+    struct spr_sync_struct *s = arg;
+    PowerPCCPU *cp = POWERPC_CPU(s->cs);
+    CPUPPCState *env = &cp->env;
+
+    cpu_synchronize_state(s->cs);
+    env->spr[s->spr] &= ~s->mask;
+    env->spr[s->spr] |= s->value;
+}
+
+static void set_spr(CPUState *cs, int spr, target_ulong value,
+                    target_ulong mask)
+{
+    struct spr_sync_struct s = {
+        .cs = cs, .spr = spr, .value = value, .mask = mask
+    };
+    run_on_cpu(cs, do_spr_sync, &s);
+}
+
 static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
                                      target_ulong pte_index)
 {
@@ -667,7 +694,7 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, 
sPAPREnvironment *spapr,
     target_ulong value2 = args[3];
     target_ulong ret = H_P2;
 
-    if (resource == H_SET_MODE_ENDIAN) {
+    if (resource == H_SET_MODE_RESOURCE_LE) {
         if (value1) {
             ret = H_P3;
             goto out;
@@ -676,22 +703,17 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, 
sPAPREnvironment *spapr,
             ret = H_P4;
             goto out;
         }
-
         switch (mflags) {
         case H_SET_MODE_ENDIAN_BIG:
             CPU_FOREACH(cs) {
-                PowerPCCPU *cp = POWERPC_CPU(cs);
-                CPUPPCState *env = &cp->env;
-                env->spr[SPR_LPCR] &= ~LPCR_ILE;
+                set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
             }
             ret = H_SUCCESS;
             break;
 
         case H_SET_MODE_ENDIAN_LITTLE:
             CPU_FOREACH(cs) {
-                PowerPCCPU *cp = POWERPC_CPU(cs);
-                CPUPPCState *env = &cp->env;
-                env->spr[SPR_LPCR] |= LPCR_ILE;
+                set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
             }
             ret = H_SUCCESS;
             break;
@@ -699,6 +721,32 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, 
sPAPREnvironment *spapr,
         default:
             ret = H_UNSUPPORTED_FLAG;
         }
+    } else if (resource == H_SET_MODE_RESOURCE_ADDR_TRANS_MODE) {
+        PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+
+        if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
+            return H_P2;
+        }
+        if (value1) {
+            ret = H_P3;
+            goto out;
+        }
+        if (value2) {
+            ret = H_P4;
+            goto out;
+        }
+        switch (mflags) {
+        case 0:
+        case 2:
+        case 3:
+            CPU_FOREACH(cs) {
+                set_spr(cs, SPR_LPCR, mflags << LPCR_AIL_SH, LPCR_AIL);
+            }
+            return H_SUCCESS;
+
+        default:
+            return H_UNSUPPORTED_FLAG;
+        }
     }
 
 out:
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index b2f11e9..526faab 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -153,8 +153,13 @@ typedef struct sPAPREnvironment {
 #define H_PP1             (1ULL<<(63-62))
 #define H_PP2             (1ULL<<(63-63))
 
-/* H_SET_MODE flags */
-#define H_SET_MODE_ENDIAN        4
+/* Values for 2nd argument to H_SET_MODE */
+#define H_SET_MODE_RESOURCE_SET_CIABR           1
+#define H_SET_MODE_RESOURCE_SET_DAWR            2
+#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE     3
+#define H_SET_MODE_RESOURCE_LE                  4
+
+/* Flags for H_SET_MODE_RESOURCE_LE */
 #define H_SET_MODE_ENDIAN_BIG    0
 #define H_SET_MODE_ENDIAN_LITTLE 1
 
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 8e46bda..e1692b1 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -458,6 +458,8 @@ struct ppc_slb_t {
 #define MSR_LE   0  /* Little-endian mode                           1 hflags */
 
 #define LPCR_ILE (1 << (63-38))
+#define LPCR_AIL      0x01800000      /* Alternate interrupt location */
+#define LPCR_AIL_SH   (63-40)
 
 #define msr_sf   ((env->msr >> MSR_SF)   & 1)
 #define msr_isf  ((env->msr >> MSR_ISF)  & 1)
-- 
1.8.4.rc4




reply via email to

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