]> git.proxmox.com Git - qemu.git/commitdiff
PPC: Add PV hypercall transport through fw_cfg
authorAlexander Graf <agraf@suse.de>
Tue, 3 Aug 2010 13:22:42 +0000 (15:22 +0200)
committerAlexander Graf <agraf@suse.de>
Thu, 26 Aug 2010 16:13:38 +0000 (18:13 +0200)
On KVM for PPC we need to tell the guest which instructions to use when
doing a hypercall. The clean way to do this is to go through an ioctl
from userspace and passing it on to the guest using the device tree.

So let's do the qemu part here: read out the hypercall and pass it on
to the guest's fw_cfg so openBIOS can read it out and expose it again.

Signed-off-by: Alexander Graf <agraf@suse.de>
hw/ppc.h
hw/ppc_newworld.c
hw/ppc_oldworld.c
target-ppc/kvm.c
target-ppc/kvm_ppc.h

index de13092ae4202a7da595187f5f8123f16b011e37..125193210387121541bd6117168614543a1d1059 100644 (file)
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -47,5 +47,8 @@ enum {
 #define FW_CFG_PPC_HEIGHT      (FW_CFG_ARCH_LOCAL + 0x01)
 #define FW_CFG_PPC_DEPTH       (FW_CFG_ARCH_LOCAL + 0x02)
 #define FW_CFG_PPC_TBFREQ      (FW_CFG_ARCH_LOCAL + 0x03)
+#define FW_CFG_PPC_IS_KVM       (FW_CFG_ARCH_LOCAL + 0x05)
+#define FW_CFG_PPC_KVM_HC       (FW_CFG_ARCH_LOCAL + 0x06)
+#define FW_CFG_PPC_KVM_PID      (FW_CFG_ARCH_LOCAL + 0x07)
 
 #define PPC_SERIAL_MM_BAUDBASE 399193
index 639dcde00024c873ffedde423129dff1a73f5288..809a1cfcbbddf17ace290b0ca8a9ec0cf0234cfa 100644 (file)
@@ -427,9 +427,16 @@ static void ppc_core99_init (ram_addr_t ram_size,
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
 
+    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
     if (kvm_enabled()) {
 #ifdef CONFIG_KVM
+        uint8_t *hypercall;
+
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+        hypercall = qemu_malloc(16);
+        kvmppc_get_hypercall(env, hypercall, 16);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
 #endif
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
index de6005e3595675f111d1f3741bc5e48adc8b1043..a12a812970766d7e271192b5b5dacd3bcad4874a 100644 (file)
@@ -399,9 +399,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height);
     fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth);
 
+    fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_IS_KVM, kvm_enabled());
     if (kvm_enabled()) {
 #ifdef CONFIG_KVM
+        uint8_t *hypercall;
+
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq());
+        hypercall = qemu_malloc(16);
+        kvmppc_get_hypercall(env, hypercall, 16);
+        fw_cfg_add_bytes(fw_cfg, FW_CFG_PPC_KVM_HC, hypercall, 16);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid());
 #endif
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec());
index 1079ce1e61c7e9cccb20b23e84062efbe1cfa676..14d6365ee254c4bea735a44b6024920d18bcfd03 100644 (file)
@@ -327,6 +327,38 @@ uint32_t kvmppc_get_tbfreq(void)
     return retval;
 }
 
+int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len)
+{
+    uint32_t *hc = (uint32_t*)buf;
+
+#ifdef KVM_CAP_PPC_GET_PVINFO
+    struct kvm_ppc_pvinfo pvinfo;
+
+    if (kvm_check_extension(env->kvm_state, KVM_CAP_PPC_GET_PVINFO) &&
+        !kvm_vm_ioctl(env->kvm_state, KVM_PPC_GET_PVINFO, &pvinfo)) {
+        memcpy(buf, pvinfo.hcall, buf_len);
+
+        return 0;
+    }
+#endif
+
+    /*
+     * Fallback to always fail hypercalls:
+     *
+     *     li r3, -1
+     *     nop
+     *     nop
+     *     nop
+     */
+
+    hc[0] = 0x3860ffff;
+    hc[1] = 0x60000000;
+    hc[2] = 0x60000000;
+    hc[3] = 0x60000000;
+
+    return 0;
+}
+
 bool kvm_arch_stop_on_emulation_error(CPUState *env)
 {
     return true;
index e8d66e88e494d5e61cd8e3e2565621176a9c4b2b..65e31c9b9e1ead8672b652d69d1268078ccfc3ca 100644 (file)
@@ -15,5 +15,6 @@ int kvmppc_read_host_property(const char *node_path, const char *prop,
                                      void *val, size_t len);
 
 uint32_t kvmppc_get_tbfreq(void);
+int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
 
 #endif /* __KVM_PPC_H__ */