summary refs log tree commit diff stats
path: root/hw/spapr_hcall.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2011-04-01 15:15:23 +1100
committerAlexander Graf <agraf@suse.de>2011-04-01 18:34:56 +0200
commit39ac8455106af1ed669b8e10223420cf1ac5b190 (patch)
tree48c935a56286ff50f76982c9d7aab1a0eb835e03 /hw/spapr_hcall.c
parentf43e35255cffb6ac6230dd09d308f7909f823f96 (diff)
downloadfocaccia-qemu-39ac8455106af1ed669b8e10223420cf1ac5b190.tar.gz
focaccia-qemu-39ac8455106af1ed669b8e10223420cf1ac5b190.zip
Implement hcall based RTAS for pSeries machines
On pSeries machines, operating systems can instantiate "RTAS" (Run-Time
Abstraction Services), a runtime component of the firmware which implements
a number of low-level, infrequently used operations.  On logical partitions
under a hypervisor, many of the RTAS functions require hypervisor
privilege.  For simplicity, therefore, hypervisor systems typically
implement the in-partition RTAS as just a tiny wrapper around a hypercall
which actually implements the various RTAS functions.

This patch implements such a hypercall based RTAS for our emulated pSeries
machine.  A tiny in-partition "firmware" calls a new hypercall, which
looks up available RTAS services in a table.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/spapr_hcall.c')
-rw-r--r--hw/spapr_hcall.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 0ba17172da..d8c721e472 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -248,20 +248,38 @@ static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
-spapr_hcall_fn hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
+static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    target_ulong rtas_r3 = args[0];
+    uint32_t token = ldl_phys(rtas_r3);
+    uint32_t nargs = ldl_phys(rtas_r3 + 4);
+    uint32_t nret = ldl_phys(rtas_r3 + 8);
+
+    return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
+                           nret, rtas_r3 + 12 + 4*nargs);
+}
+
+spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
+spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE];
 
 void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
 {
-    spapr_hcall_fn old_fn;
+    spapr_hcall_fn *slot;
+
+    if (opcode <= MAX_HCALL_OPCODE) {
+        assert((opcode & 0x3) == 0);
 
-    assert(opcode <= MAX_HCALL_OPCODE);
-    assert((opcode & 0x3) == 0);
+        slot = &papr_hypercall_table[opcode / 4];
+    } else {
+        assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
 
-    old_fn = hypercall_table[opcode / 4];
 
-    assert(!old_fn || (fn == old_fn));
+        slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
+    }
 
-    hypercall_table[opcode / 4] = fn;
+    assert(!(*slot) || (fn == *slot));
+    *slot = fn;
 }
 
 target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
@@ -274,7 +292,14 @@ target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
 
     if ((opcode <= MAX_HCALL_OPCODE)
         && ((opcode & 0x3) == 0)) {
-        spapr_hcall_fn fn = hypercall_table[opcode / 4];
+        spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
+
+        if (fn) {
+            return fn(env, spapr, opcode, args);
+        }
+    } else if ((opcode >= KVMPPC_HCALL_BASE) &&
+               (opcode <= KVMPPC_HCALL_MAX)) {
+        spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
 
         if (fn) {
             return fn(env, spapr, opcode, args);
@@ -291,5 +316,8 @@ static void hypercall_init(void)
     spapr_register_hypercall(H_ENTER, h_enter);
     spapr_register_hypercall(H_REMOVE, h_remove);
     spapr_register_hypercall(H_PROTECT, h_protect);
+
+    /* qemu/KVM-PPC specific hcalls */
+    spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
 }
 device_init(hypercall_init);