From: Jan Kiszka <jan.kiszka@xxxxxxxxxxx> 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@xxxxxxxxxxx> --- configure | 39 ++++++++++++++++++++++----------- kvm-all.c | 61 ++++++++++++++++++++++----------------------------- kvm.h | 10 ++++++++ target-i386/kvm.c | 39 ++++++-------------------------- target-ppc/kvm.c | 4 +++ target-s390x/kvm.c | 4 +++ 6 files changed, 78 insertions(+), 79 deletions(-) diff --git a/configure b/configure index ec37a91..e6ee5c3 100755 --- a/configure +++ b/configure @@ -1665,18 +1665,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 @@ -1711,8 +1724,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 190fcdf..7a5b299 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -57,9 +57,7 @@ static 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; @@ -73,6 +71,12 @@ static struct KVMState { int xsave, xcrs; } 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(void) { int i; @@ -214,12 +218,10 @@ int kvm_init_vcpu(CPUState *env) goto err; } -#ifdef KVM_CAP_COALESCED_MMIO if (kvm_state.coalesced_mmio && !kvm_state.coalesced_mmio_ring) { kvm_state.coalesced_mmio_ring = (void *)env->kvm_run + kvm_state.coalesced_mmio * PAGE_SIZE; } -#endif ret = kvm_arch_init_vcpu(env); if (ret == 0) { @@ -386,7 +388,6 @@ int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) { int ret = -ENOSYS; -#ifdef KVM_CAP_COALESCED_MMIO if (kvm_state.coalesced_mmio) { struct kvm_coalesced_mmio_zone zone; @@ -395,7 +396,6 @@ int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) ret = kvm_vm_ioctl(KVM_REGISTER_COALESCED_MMIO, &zone); } -#endif return ret; } @@ -404,7 +404,6 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) { int ret = -ENOSYS; -#ifdef KVM_CAP_COALESCED_MMIO if (kvm_state.coalesced_mmio) { struct kvm_coalesced_mmio_zone zone; @@ -413,7 +412,6 @@ int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) ret = kvm_vm_ioctl(KVM_UNREGISTER_COALESCED_MMIO, &zone); } -#endif return ret; } @@ -430,6 +428,18 @@ int kvm_check_extension(unsigned int extension) return ret; } +static const KVMCapabilityInfo * +kvm_check_extension_list(const KVMCapabilityInfo *list) +{ + while (list->name) { + if (!kvm_check_extension(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) { @@ -589,6 +599,7 @@ int kvm_init(void) static const char upgrade_note[] = "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n" "(see http://sourceforge.net/projects/kvm).\n"; + const KVMCapabilityInfo *missing_cap; int ret; int i; @@ -630,33 +641,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(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(kvm_required_capabilites); + if (!missing_cap) { + missing_cap = + kvm_check_extension_list(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(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; } -#ifdef KVM_CAP_COALESCED_MMIO kvm_state.coalesced_mmio = kvm_check_extension(KVM_CAP_COALESCED_MMIO); -#endif kvm_state.broken_set_mem_region = 1; #ifdef KVM_CAP_JOIN_MEMORY_REGIONS_WORKS @@ -777,7 +774,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 if (kvm_state.coalesced_mmio_ring) { struct kvm_coalesced_mmio_ring *ring = kvm_state.coalesced_mmio_ring; while (ring->first != ring->last) { @@ -790,7 +786,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) @@ -988,11 +983,7 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...) int kvm_has_sync_mmu(void) { -#ifdef KVM_CAP_SYNC_MMU return kvm_check_extension(KVM_CAP_SYNC_MMU); -#else - return 0; -#endif } int kvm_has_vcpu_events(void) diff --git a/kvm.h b/kvm.h index 31d9f21..153d7b9 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); @@ -82,6 +90,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 a907578..58122d9 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -55,12 +55,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(int max) { struct kvm_cpuid2 *cpuid; @@ -94,10 +99,6 @@ uint32_t kvm_x86_get_supported_cpuid(uint32_t function, uint32_t index, uint32_t ret = 0; uint32_t cpuid_1_edx; - if (!kvm_check_extension(KVM_CAP_EXT_CPUID)) { - return -1U; - } - max = 1; while ((cpuid = try_get_cpuid(max)) == NULL) { max *= 2; @@ -141,30 +142,14 @@ uint32_t kvm_x86_get_supported_cpuid(uint32_t function, uint32_t index, return ret; } -#else - -uint32_t kvm_x86_get_supported_cpuid(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 @@ -631,15 +616,7 @@ int kvm_arch_init(void) /* 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(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 72f2f94..7918426 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 4f9075c..29fcd46 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(void) { return 0; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html