aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2011-01-21 21:48:17 +0100
committerMarcelo Tosatti <mtosatti@redhat.com>2011-01-23 02:27:22 -0200
commit94a8d39afd8ccfdbf578af04c3385fdb5f545af1 (patch)
tree0271405cd56c03f2a7578169e4682e731d4f80ab
parentcad1e2827b616487e3574300f2eaeea13a355197 (diff)
kvm: Consolidate must-have capability checks
Instead of splattering the code with #ifdefs and runtime checks for capabilities we cannot work without anyway, provide central test infrastructure for verifying their availability both at build and runtime. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rwxr-xr-xconfigure39
-rw-r--r--kvm-all.c67
-rw-r--r--kvm.h10
-rw-r--r--target-i386/kvm.c39
-rw-r--r--target-ppc/kvm.c4
-rw-r--r--target-s390x/kvm.c4
6 files changed, 79 insertions, 84 deletions
diff --git a/configure b/configure
index 9a02d1f730..4673bf04c0 100755
--- a/configure
+++ b/configure
@@ -1662,18 +1662,31 @@ if test "$kvm" != "no" ; then
#if !defined(KVM_API_VERSION) || KVM_API_VERSION < 12 || KVM_API_VERSION > 12
#error Invalid KVM version
#endif
-#if !defined(KVM_CAP_USER_MEMORY)
-#error Missing KVM capability KVM_CAP_USER_MEMORY
-#endif
-#if !defined(KVM_CAP_SET_TSS_ADDR)
-#error Missing KVM capability KVM_CAP_SET_TSS_ADDR
-#endif
-#if !defined(KVM_CAP_DESTROY_MEMORY_REGION_WORKS)
-#error Missing KVM capability KVM_CAP_DESTROY_MEMORY_REGION_WORKS
-#endif
-#if !defined(KVM_CAP_USER_NMI)
-#error Missing KVM capability KVM_CAP_USER_NMI
+EOF
+ must_have_caps="KVM_CAP_USER_MEMORY \
+ KVM_CAP_DESTROY_MEMORY_REGION_WORKS \
+ KVM_CAP_COALESCED_MMIO \
+ KVM_CAP_SYNC_MMU \
+ "
+ if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) ; then
+ must_have_caps="$caps \
+ KVM_CAP_SET_TSS_ADDR \
+ KVM_CAP_EXT_CPUID \
+ KVM_CAP_CLOCKSOURCE \
+ KVM_CAP_NOP_IO_DELAY \
+ KVM_CAP_PV_MMU \
+ KVM_CAP_MP_STATE \
+ KVM_CAP_USER_NMI \
+ "
+ fi
+ for c in $must_have_caps ; do
+ cat >> $TMPC <<EOF
+#if !defined($c)
+#error Missing KVM capability $c
#endif
+EOF
+ done
+ cat >> $TMPC <<EOF
int main(void) { return 0; }
EOF
if test "$kerneldir" != "" ; then
@@ -1708,8 +1721,8 @@ EOF
| awk -F "error: " '{if (NR>1) printf(", "); printf("%s",$2);}'`
if test "$kvmerr" != "" ; then
echo -e "${kvmerr}\n\
- NOTE: To enable KVM support, update your kernel to 2.6.29+ or install \
- recent kvm-kmod from http://sourceforge.net/projects/kvm."
+NOTE: To enable KVM support, update your kernel to 2.6.29+ or install \
+recent kvm-kmod from http://sourceforge.net/projects/kvm."
fi
fi
feature_not_found "kvm"
diff --git a/kvm-all.c b/kvm-all.c
index 8053f92105..3a1f63b5b1 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -63,9 +63,7 @@ struct KVMState
int fd;
int vmfd;
int coalesced_mmio;
-#ifdef KVM_CAP_COALESCED_MMIO
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
-#endif
int broken_set_mem_region;
int migration_log;
int vcpu_events;
@@ -82,6 +80,12 @@ struct KVMState
static KVMState *kvm_state;
+static const KVMCapabilityInfo kvm_required_capabilites[] = {
+ KVM_CAP_INFO(USER_MEMORY),
+ KVM_CAP_INFO(DESTROY_MEMORY_REGION_WORKS),
+ KVM_CAP_LAST_INFO
+};
+
static KVMSlot *kvm_alloc_slot(KVMState *s)
{
int i;
@@ -227,12 +231,10 @@ int kvm_init_vcpu(CPUState *env)
goto err;
}
-#ifdef KVM_CAP_COALESCED_MMIO
if (s->coalesced_mmio && !s->coalesced_mmio_ring) {
s->coalesced_mmio_ring =
(void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE;
}
-#endif
ret = kvm_arch_init_vcpu(env);
if (ret == 0) {
@@ -401,7 +403,6 @@ static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
{
int ret = -ENOSYS;
-#ifdef KVM_CAP_COALESCED_MMIO
KVMState *s = kvm_state;
if (s->coalesced_mmio) {
@@ -412,7 +413,6 @@ int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone);
}
-#endif
return ret;
}
@@ -420,7 +420,6 @@ int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
{
int ret = -ENOSYS;
-#ifdef KVM_CAP_COALESCED_MMIO
KVMState *s = kvm_state;
if (s->coalesced_mmio) {
@@ -431,7 +430,6 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone);
}
-#endif
return ret;
}
@@ -481,6 +479,18 @@ static int kvm_check_many_ioeventfds(void)
#endif
}
+static const KVMCapabilityInfo *
+kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list)
+{
+ while (list->name) {
+ if (!kvm_check_extension(s, list->value)) {
+ return list;
+ }
+ list++;
+ }
+ return NULL;
+}
+
static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
ram_addr_t phys_offset)
{
@@ -642,6 +652,7 @@ int kvm_init(void)
"Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
"(see http://sourceforge.net/projects/kvm).\n";
KVMState *s;
+ const KVMCapabilityInfo *missing_cap;
int ret;
int i;
@@ -685,35 +696,19 @@ int kvm_init(void)
goto err;
}
- /* initially, KVM allocated its own memory and we had to jump through
- * hooks to make phys_ram_base point to this. Modern versions of KVM
- * just use a user allocated buffer so we can use regular pages
- * unmodified. Make sure we have a sufficiently modern version of KVM.
- */
- if (!kvm_check_extension(s, KVM_CAP_USER_MEMORY)) {
- ret = -EINVAL;
- fprintf(stderr, "kvm does not support KVM_CAP_USER_MEMORY\n%s",
- upgrade_note);
- goto err;
+ missing_cap = kvm_check_extension_list(s, kvm_required_capabilites);
+ if (!missing_cap) {
+ missing_cap =
+ kvm_check_extension_list(s, kvm_arch_required_capabilities);
}
-
- /* There was a nasty bug in < kvm-80 that prevents memory slots from being
- * destroyed properly. Since we rely on this capability, refuse to work
- * with any kernel without this capability. */
- if (!kvm_check_extension(s, KVM_CAP_DESTROY_MEMORY_REGION_WORKS)) {
+ if (missing_cap) {
ret = -EINVAL;
-
- fprintf(stderr,
- "KVM kernel module broken (DESTROY_MEMORY_REGION).\n%s",
- upgrade_note);
+ fprintf(stderr, "kvm does not support %s\n%s",
+ missing_cap->name, upgrade_note);
goto err;
}
- s->coalesced_mmio = 0;
-#ifdef KVM_CAP_COALESCED_MMIO
s->coalesced_mmio = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO);
- s->coalesced_mmio_ring = NULL;
-#endif
s->broken_set_mem_region = 1;
#ifdef KVM_CAP_JOIN_MEMORY_REGIONS_WORKS
@@ -845,7 +840,6 @@ static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
void kvm_flush_coalesced_mmio_buffer(void)
{
-#ifdef KVM_CAP_COALESCED_MMIO
KVMState *s = kvm_state;
if (s->coalesced_mmio_ring) {
struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring;
@@ -859,7 +853,6 @@ void kvm_flush_coalesced_mmio_buffer(void)
ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
}
}
-#endif
}
static void do_kvm_cpu_synchronize_state(void *_env)
@@ -1059,13 +1052,7 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...)
int kvm_has_sync_mmu(void)
{
-#ifdef KVM_CAP_SYNC_MMU
- KVMState *s = kvm_state;
-
- return kvm_check_extension(s, KVM_CAP_SYNC_MMU);
-#else
- return 0;
-#endif
+ return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
}
int kvm_has_vcpu_events(void)
diff --git a/kvm.h b/kvm.h
index a9717528e2..ca57517af2 100644
--- a/kvm.h
+++ b/kvm.h
@@ -32,6 +32,14 @@ extern int kvm_allowed;
struct kvm_run;
+typedef struct KVMCapabilityInfo {
+ const char *name;
+ int value;
+} KVMCapabilityInfo;
+
+#define KVM_CAP_INFO(CAP) { "KVM_CAP_" stringify(CAP), KVM_CAP_##CAP }
+#define KVM_CAP_LAST_INFO { NULL, 0 }
+
/* external API */
int kvm_init(void);
@@ -86,6 +94,8 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...);
/* Arch specific hooks */
+extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
+
int kvm_arch_post_run(CPUState *env, struct kvm_run *run);
int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 016b67d5ec..1db8227db9 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -54,12 +54,17 @@
#define BUS_MCEERR_AO 5
#endif
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+ KVM_CAP_INFO(SET_TSS_ADDR),
+ KVM_CAP_INFO(EXT_CPUID),
+ KVM_CAP_INFO(MP_STATE),
+ KVM_CAP_LAST_INFO
+};
+
static bool has_msr_star;
static bool has_msr_hsave_pa;
static int lm_capable_kernel;
-#ifdef KVM_CAP_EXT_CPUID
-
static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
{
struct kvm_cpuid2 *cpuid;
@@ -93,10 +98,6 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
uint32_t ret = 0;
uint32_t cpuid_1_edx;
- if (!kvm_check_extension(env->kvm_state, KVM_CAP_EXT_CPUID)) {
- return -1U;
- }
-
max = 1;
while ((cpuid = try_get_cpuid(env->kvm_state, max)) == NULL) {
max *= 2;
@@ -140,30 +141,14 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
return ret;
}
-#else
-
-uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
- uint32_t index, int reg)
-{
- return -1U;
-}
-
-#endif
-
#ifdef CONFIG_KVM_PARA
struct kvm_para_features {
int cap;
int feature;
} para_features[] = {
-#ifdef KVM_CAP_CLOCKSOURCE
{ KVM_CAP_CLOCKSOURCE, KVM_FEATURE_CLOCKSOURCE },
-#endif
-#ifdef KVM_CAP_NOP_IO_DELAY
{ KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY },
-#endif
-#ifdef KVM_CAP_PV_MMU
{ KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP },
-#endif
#ifdef KVM_CAP_ASYNC_PF
{ KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF },
#endif
@@ -542,15 +527,7 @@ int kvm_arch_init(KVMState *s)
/* create vm86 tss. KVM uses vm86 mode to emulate 16-bit code
* directly. In order to use vm86 mode, a TSS is needed. Since this
- * must be part of guest physical memory, we need to allocate it. Older
- * versions of KVM just assumed that it would be at the end of physical
- * memory but that doesn't work with more than 4GB of memory. We simply
- * refuse to work with those older versions of KVM. */
- ret = kvm_check_extension(s, KVM_CAP_SET_TSS_ADDR);
- if (ret <= 0) {
- fprintf(stderr, "kvm does not support KVM_CAP_SET_TSS_ADDR\n");
- return ret;
- }
+ * must be part of guest physical memory, we need to allocate it. */
/* this address is 3 pages before the bios, and the bios should present
* as unavaible memory. FIXME, need to ensure the e820 map deals with
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 3c05630fb9..710eca1dca 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -37,6 +37,10 @@
do { } while (0)
#endif
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+ KVM_CAP_LAST_INFO
+};
+
static int cap_interrupt_unset = false;
static int cap_interrupt_level = false;
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index b177e10126..38823f54f7 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -70,6 +70,10 @@
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
+const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
+ KVM_CAP_LAST_INFO
+};
+
int kvm_arch_init(KVMState *s)
{
return 0;