From patchwork Fri Jan 21 20:48:17 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 79943 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 2DEDFB70AF for ; Sat, 22 Jan 2011 08:32:35 +1100 (EST) Received: from localhost ([127.0.0.1]:42133 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PgNxV-0006Qq-Gv for incoming@patchwork.ozlabs.org; Fri, 21 Jan 2011 15:51:49 -0500 Received: from [140.186.70.92] (port=53100 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PgNuM-00051Y-W3 for qemu-devel@nongnu.org; Fri, 21 Jan 2011 15:48:37 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PgNuK-00040V-1f for qemu-devel@nongnu.org; Fri, 21 Jan 2011 15:48:35 -0500 Received: from fmmailgate03.web.de ([217.72.192.234]:55691) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PgNuJ-0003ze-AL for qemu-devel@nongnu.org; Fri, 21 Jan 2011 15:48:32 -0500 Received: from smtp02.web.de ( [172.20.0.184]) by fmmailgate03.web.de (Postfix) with ESMTP id 6623E18467B07; Fri, 21 Jan 2011 21:48:29 +0100 (CET) Received: from [92.75.143.98] (helo=localhost.localdomain) by smtp02.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #2) id 1PgNuH-0007KF-00; Fri, 21 Jan 2011 21:48:29 +0100 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Date: Fri, 21 Jan 2011 21:48:17 +0100 Message-Id: <7a828e1c68c15eb932ef2cc159cf41fa1bc26ca2.1295642900.git.jan.kiszka@web.de> X-Mailer: git-send-email 1.7.1 In-Reply-To: References: In-Reply-To: References: X-Sender: jan.kiszka@web.de X-Provags-ID: V01U2FsdGVkX1+qHExefDwZdOaypJ9pJyJrKkDYB/egX+6XNytt ZwAiLsoqzxp+eWqSBzfx6Ahhkm7Ow+mb9EKvn5QL1zlzBTOxCZ ldy3ekKWg= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org Subject: [Qemu-devel] [PATCH 13/18] kvm: Consolidate must-have capability checks X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Jan Kiszka 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 --- configure | 39 ++++++++++++++++++++---------- kvm-all.c | 67 +++++++++++++++++++++------------------------------- kvm.h | 10 +++++++ target-i386/kvm.c | 39 ++++++------------------------ target-ppc/kvm.c | 4 +++ target-s390x/kvm.c | 4 +++ 6 files changed, 79 insertions(+), 84 deletions(-) diff --git a/configure b/configure index 9a02d1f..4673bf0 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 <> $TMPC <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 8053f92..3a1f63b 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 a971752..ca57517 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 016b67d..1db8227 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 3c05630..710eca1 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 b177e10..38823f5 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;