summary refs log tree commit diff stats
path: root/hw/ppc/spapr_hcall.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2013-08-19 21:04:20 +1000
committerAlexander Graf <agraf@suse.de>2013-09-02 10:06:42 +0200
commit42561bf2e464a2d682707af1640fc2db1e937c42 (patch)
tree9ff135561555618458d6bf6fe9b14b2ee5a6627a /hw/ppc/spapr_hcall.c
parent33a0e5d8c555091eef6944595d8787cb9274e451 (diff)
downloadfocaccia-qemu-42561bf2e464a2d682707af1640fc2db1e937c42.tar.gz
focaccia-qemu-42561bf2e464a2d682707af1640fc2db1e937c42.zip
pseries: Add H_SET_MODE hcall to change guest exception endianness
H_SET_MODE is used for controlling various partition settings. One
of these settings is the endianness a guest takes its exceptions in.

Signed-off-by: Anton Blanchard <anton@samba.org>
[agraf: fix whitespace]
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/ppc/spapr_hcall.c')
-rw-r--r--hw/ppc/spapr_hcall.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 67d6cd91d1..89e6a00dd9 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -657,6 +657,54 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
+static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    CPUState *cs;
+    target_ulong mflags = args[0];
+    target_ulong resource = args[1];
+    target_ulong value1 = args[2];
+    target_ulong value2 = args[3];
+    target_ulong ret = H_P2;
+
+    if (resource == H_SET_MODE_ENDIAN) {
+        if (value1) {
+            ret = H_P3;
+            goto out;
+        }
+        if (value2) {
+            ret = H_P4;
+            goto out;
+        }
+
+        switch (mflags) {
+        case H_SET_MODE_ENDIAN_BIG:
+            for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+                PowerPCCPU *cp = POWERPC_CPU(cs);
+                CPUPPCState *env = &cp->env;
+                env->spr[SPR_LPCR] &= ~LPCR_ILE;
+            }
+            ret = H_SUCCESS;
+            break;
+
+        case H_SET_MODE_ENDIAN_LITTLE:
+            for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+                PowerPCCPU *cp = POWERPC_CPU(cs);
+                CPUPPCState *env = &cp->env;
+                env->spr[SPR_LPCR] |= LPCR_ILE;
+            }
+            ret = H_SUCCESS;
+            break;
+
+        default:
+            ret = H_UNSUPPORTED_FLAG;
+        }
+    }
+
+out:
+    return ret;
+}
+
 static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
 static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
 
@@ -734,6 +782,8 @@ static void hypercall_register_types(void)
 
     /* qemu/KVM-PPC specific hcalls */
     spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
+
+    spapr_register_hypercall(H_SET_MODE, h_set_mode);
 }
 
 type_init(hypercall_register_types)