summaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2011-09-29 21:39:11 +0000
committerAlexander Graf <agraf@suse.de>2011-10-30 17:11:53 +0100
commit354ac20a36a82a5ee09b0a6c8ba8655358a7597f (patch)
tree1728b384c00b412a329179b72fc5f3bc69c90e06 /target-ppc
parente97c363638b32943afc4bd2845f4081496fabfbc (diff)
downloadqemu-354ac20a36a82a5ee09b0a6c8ba8655358a7597f.tar.gz
pseries: Allow KVM Book3S-HV on PPC970 CPUS
At present, using the hypervisor aware Book3S-HV KVM will only work with qemu on POWER7 CPUs. PPC970 CPUs also have hypervisor capability, but they lack the VRMA feature which makes assigning guest memory easier. In order to allow KVM Book3S-HV on PPC970, we need to specially allocate the first chunk of guest memory (the "Real Mode Area" or RMA), so that it is physically contiguous. Sufficiently recent host kernels allow such contiguous RMAs to be allocated, with a kvm capability advertising whether the feature is available and/or necessary on this hardware. This patch enables qemu to use this support, thus allowing kvm acceleration of pseries qemu machines on PPC970 hardware. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Alexander Graf <agraf@suse.de> --- agraf: fix to use memory api
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/kvm.c44
-rw-r--r--target-ppc/kvm_ppc.h8
2 files changed, 52 insertions, 0 deletions
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 6c7ca6fc50..fd17d23d2e 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -55,6 +55,7 @@ static int cap_interrupt_level = false;
static int cap_segstate;
static int cap_booke_sregs;
static int cap_ppc_smt;
+static int cap_ppc_rma;
/* XXX We have a race condition where we actually have a level triggered
* interrupt, but the infrastructure can't expose that yet, so the guest
@@ -79,6 +80,7 @@ int kvm_arch_init(KVMState *s)
cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT);
+ cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA);
if (!cap_interrupt_level) {
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
@@ -758,6 +760,48 @@ int kvmppc_smt_threads(void)
return cap_ppc_smt ? cap_ppc_smt : 1;
}
+off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
+{
+ void *rma;
+ off_t size;
+ int fd;
+ struct kvm_allocate_rma ret;
+ MemoryRegion *rma_region;
+
+ /* If cap_ppc_rma == 0, contiguous RMA allocation is not supported
+ * if cap_ppc_rma == 1, contiguous RMA allocation is supported, but
+ * not necessary on this hardware
+ * if cap_ppc_rma == 2, contiguous RMA allocation is needed on this hardware
+ *
+ * FIXME: We should allow the user to force contiguous RMA
+ * allocation in the cap_ppc_rma==1 case.
+ */
+ if (cap_ppc_rma < 2) {
+ return 0;
+ }
+
+ fd = kvm_vm_ioctl(kvm_state, KVM_ALLOCATE_RMA, &ret);
+ if (fd < 0) {
+ fprintf(stderr, "KVM: Error on KVM_ALLOCATE_RMA: %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ size = MIN(ret.rma_size, 256ul << 20);
+
+ rma = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (rma == MAP_FAILED) {
+ fprintf(stderr, "KVM: Error mapping RMA: %s\n", strerror(errno));
+ return -1;
+ };
+
+ rma_region = g_new(MemoryRegion, 1);
+ memory_region_init_ram_ptr(rma_region, NULL, name, size, rma);
+ memory_region_add_subregion(sysmem, 0, rma_region);
+
+ return size;
+}
+
bool kvm_arch_stop_on_emulation_error(CPUState *env)
{
return true;
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index c298411aa8..82f32f449e 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -9,6 +9,8 @@
#ifndef __KVM_PPC_H__
#define __KVM_PPC_H__
+#include "memory.h"
+
void kvmppc_init(void);
#ifdef CONFIG_KVM
@@ -19,6 +21,7 @@ int kvmppc_get_hypercall(CPUState *env, uint8_t *buf, int buf_len);
int kvmppc_set_interrupt(CPUState *env, int irq, int level);
void kvmppc_set_papr(CPUState *env);
int kvmppc_smt_threads(void);
+off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem);
#else
@@ -51,6 +54,11 @@ static inline int kvmppc_smt_threads(void)
return 1;
}
+static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
+{
+ return 0;
+}
+
#endif
#ifndef CONFIG_KVM