mirror of https://gitee.com/openkylin/qemu.git
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>
This commit is contained in:
parent
cad1e2827b
commit
94a8d39afd
|
@ -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"
|
||||
|
|
69
kvm-all.c
69
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)) {
|
||||
missing_cap = kvm_check_extension_list(s, kvm_required_capabilites);
|
||||
if (!missing_cap) {
|
||||
missing_cap =
|
||||
kvm_check_extension_list(s, kvm_arch_required_capabilities);
|
||||
}
|
||||
if (missing_cap) {
|
||||
ret = -EINVAL;
|
||||
fprintf(stderr, "kvm does not support KVM_CAP_USER_MEMORY\n%s",
|
||||
upgrade_note);
|
||||
fprintf(stderr, "kvm does not support %s\n%s",
|
||||
missing_cap->name, upgrade_note);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
ret = -EINVAL;
|
||||
|
||||
fprintf(stderr,
|
||||
"KVM kernel module broken (DESTROY_MEMORY_REGION).\n%s",
|
||||
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)
|
||||
|
|
10
kvm.h
10
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue