Merge remote branch 'qemu-kvm/uq/master' into staging

aliguori: fix build with !defined(KVM_CAP_ASYNC_PF)

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2011-02-01 15:23:24 -06:00
commit b3a98367ee
16 changed files with 717 additions and 489 deletions

32
configure vendored
View File

@ -1663,15 +1663,31 @@ if test "$kvm" != "no" ; then
#if !defined(KVM_API_VERSION) || KVM_API_VERSION < 12 || KVM_API_VERSION > 12 #if !defined(KVM_API_VERSION) || KVM_API_VERSION < 12 || KVM_API_VERSION > 12
#error Invalid KVM version #error Invalid KVM version
#endif #endif
#if !defined(KVM_CAP_USER_MEMORY) EOF
#error Missing KVM capability KVM_CAP_USER_MEMORY must_have_caps="KVM_CAP_USER_MEMORY \
#endif KVM_CAP_DESTROY_MEMORY_REGION_WORKS \
#if !defined(KVM_CAP_SET_TSS_ADDR) KVM_CAP_COALESCED_MMIO \
#error Missing KVM capability KVM_CAP_SET_TSS_ADDR KVM_CAP_SYNC_MMU \
#endif "
#if !defined(KVM_CAP_DESTROY_MEMORY_REGION_WORKS) if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) ; then
#error Missing KVM capability KVM_CAP_DESTROY_MEMORY_REGION_WORKS 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 #endif
EOF
done
cat >> $TMPC <<EOF
int main(void) { return 0; } int main(void) { return 0; }
EOF EOF
if test "$kerneldir" != "" ; then if test "$kerneldir" != "" ; then

View File

@ -765,6 +765,8 @@ int page_check_range(target_ulong start, target_ulong len, int flags);
CPUState *cpu_copy(CPUState *env); CPUState *cpu_copy(CPUState *env);
CPUState *qemu_get_cpu(int cpu); CPUState *qemu_get_cpu(int cpu);
#define CPU_DUMP_CODE 0x00010000
void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
void cpu_dump_statistics(CPUState *env, FILE *f, fprintf_function cpu_fprintf, void cpu_dump_statistics(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
@ -964,6 +966,7 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
uint8_t *buf, int len, int is_write); uint8_t *buf, int len, int is_write);
void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
uint64_t mcg_status, uint64_t addr, uint64_t misc); uint64_t mcg_status, uint64_t addr, uint64_t misc,
int broadcast);
#endif /* CPU_ALL_H */ #endif /* CPU_ALL_H */

2
cpus.c
View File

@ -735,9 +735,7 @@ static sigset_t block_io_signals(void)
void qemu_mutex_lock_iothread(void) void qemu_mutex_lock_iothread(void)
{ {
if (kvm_enabled()) { if (kvm_enabled()) {
qemu_mutex_lock(&qemu_fair_mutex);
qemu_mutex_lock(&qemu_global_mutex); qemu_mutex_lock(&qemu_global_mutex);
qemu_mutex_unlock(&qemu_fair_mutex);
} else { } else {
qemu_mutex_lock(&qemu_fair_mutex); qemu_mutex_lock(&qemu_fair_mutex);
if (qemu_mutex_trylock(&qemu_global_mutex)) { if (qemu_mutex_trylock(&qemu_global_mutex)) {

View File

@ -1152,9 +1152,9 @@ ETEXI
{ {
.name = "mce", .name = "mce",
.args_type = "cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l", .args_type = "broadcast:-b,cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l",
.params = "cpu bank status mcgstatus addr misc", .params = "[-b] cpu bank status mcgstatus addr misc",
.help = "inject a MCE on the given CPU", .help = "inject a MCE on the given CPU [and broadcast to other CPUs with -b option]",
.mhandler.cmd = do_inject_mce, .mhandler.cmd = do_inject_mce,
}, },

221
kvm-all.c
View File

@ -63,9 +63,7 @@ struct KVMState
int fd; int fd;
int vmfd; int vmfd;
int coalesced_mmio; int coalesced_mmio;
#ifdef KVM_CAP_COALESCED_MMIO
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring; struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
#endif
int broken_set_mem_region; int broken_set_mem_region;
int migration_log; int migration_log;
int vcpu_events; int vcpu_events;
@ -82,17 +80,25 @@ struct KVMState
static KVMState *kvm_state; 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) static KVMSlot *kvm_alloc_slot(KVMState *s)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(s->slots); i++) { for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
/* KVM private memory slots */ /* KVM private memory slots */
if (i >= 8 && i < 12) if (i >= 8 && i < 12) {
continue; continue;
if (s->slots[i].memory_size == 0) }
if (s->slots[i].memory_size == 0) {
return &s->slots[i]; return &s->slots[i];
} }
}
fprintf(stderr, "%s: no free slot available\n", __func__); fprintf(stderr, "%s: no free slot available\n", __func__);
abort(); abort();
@ -225,11 +231,10 @@ int kvm_init_vcpu(CPUState *env)
goto err; goto err;
} }
#ifdef KVM_CAP_COALESCED_MMIO if (s->coalesced_mmio && !s->coalesced_mmio_ring) {
if (s->coalesced_mmio && !s->coalesced_mmio_ring) s->coalesced_mmio_ring =
s->coalesced_mmio_ring = (void *) env->kvm_run + (void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE;
s->coalesced_mmio * PAGE_SIZE; }
#endif
ret = kvm_arch_init_vcpu(env); ret = kvm_arch_init_vcpu(env);
if (ret == 0) { if (ret == 0) {
@ -275,15 +280,13 @@ static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size) int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size)
{ {
return kvm_dirty_pages_log_change(phys_addr, size, return kvm_dirty_pages_log_change(phys_addr, size, KVM_MEM_LOG_DIRTY_PAGES,
KVM_MEM_LOG_DIRTY_PAGES,
KVM_MEM_LOG_DIRTY_PAGES); KVM_MEM_LOG_DIRTY_PAGES);
} }
int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size) int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size)
{ {
return kvm_dirty_pages_log_change(phys_addr, size, return kvm_dirty_pages_log_change(phys_addr, size, 0,
0,
KVM_MEM_LOG_DIRTY_PAGES); KVM_MEM_LOG_DIRTY_PAGES);
} }
@ -400,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 kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
{ {
int ret = -ENOSYS; int ret = -ENOSYS;
#ifdef KVM_CAP_COALESCED_MMIO
KVMState *s = kvm_state; KVMState *s = kvm_state;
if (s->coalesced_mmio) { if (s->coalesced_mmio) {
@ -411,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); ret = kvm_vm_ioctl(s, KVM_REGISTER_COALESCED_MMIO, &zone);
} }
#endif
return ret; return ret;
} }
@ -419,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 kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size)
{ {
int ret = -ENOSYS; int ret = -ENOSYS;
#ifdef KVM_CAP_COALESCED_MMIO
KVMState *s = kvm_state; KVMState *s = kvm_state;
if (s->coalesced_mmio) { if (s->coalesced_mmio) {
@ -430,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); ret = kvm_vm_ioctl(s, KVM_UNREGISTER_COALESCED_MMIO, &zone);
} }
#endif
return ret; return ret;
} }
@ -484,8 +483,19 @@ static int kvm_check_many_ioeventfds(void)
#endif #endif
} }
static void kvm_set_phys_mem(target_phys_addr_t start_addr, static const KVMCapabilityInfo *
ram_addr_t size, 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) ram_addr_t phys_offset)
{ {
KVMState *s = kvm_state; KVMState *s = kvm_state;
@ -593,13 +603,13 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr,
} }
/* in case the KVM bug workaround already "consumed" the new slot */ /* in case the KVM bug workaround already "consumed" the new slot */
if (!size) if (!size) {
return; return;
}
/* KVM does not need to know about this memory */ /* KVM does not need to know about this memory */
if (flags >= IO_MEM_UNASSIGNED) if (flags >= IO_MEM_UNASSIGNED) {
return; return;
}
mem = kvm_alloc_slot(s); mem = kvm_alloc_slot(s);
mem->memory_size = size; mem->memory_size = size;
mem->start_addr = start_addr; mem->start_addr = start_addr;
@ -616,8 +626,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr,
static void kvm_client_set_memory(struct CPUPhysMemoryClient *client, static void kvm_client_set_memory(struct CPUPhysMemoryClient *client,
target_phys_addr_t start_addr, target_phys_addr_t start_addr,
ram_addr_t size, ram_addr_t size, ram_addr_t phys_offset)
ram_addr_t phys_offset)
{ {
kvm_set_phys_mem(start_addr, size, phys_offset); kvm_set_phys_mem(start_addr, size, phys_offset);
} }
@ -641,12 +650,13 @@ static CPUPhysMemoryClient kvm_cpu_phys_memory_client = {
.migration_log = kvm_client_migration_log, .migration_log = kvm_client_migration_log,
}; };
int kvm_init(int smp_cpus) int kvm_init(void)
{ {
static const char upgrade_note[] = static const char upgrade_note[] =
"Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n" "Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
"(see http://sourceforge.net/projects/kvm).\n"; "(see http://sourceforge.net/projects/kvm).\n";
KVMState *s; KVMState *s;
const KVMCapabilityInfo *missing_cap;
int ret; int ret;
int i; int i;
@ -655,9 +665,9 @@ int kvm_init(int smp_cpus)
#ifdef KVM_CAP_SET_GUEST_DEBUG #ifdef KVM_CAP_SET_GUEST_DEBUG
QTAILQ_INIT(&s->kvm_sw_breakpoints); QTAILQ_INIT(&s->kvm_sw_breakpoints);
#endif #endif
for (i = 0; i < ARRAY_SIZE(s->slots); i++) for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
s->slots[i].slot = i; s->slots[i].slot = i;
}
s->vmfd = -1; s->vmfd = -1;
s->fd = qemu_open("/dev/kvm", O_RDWR); s->fd = qemu_open("/dev/kvm", O_RDWR);
if (s->fd == -1) { if (s->fd == -1) {
@ -668,8 +678,9 @@ int kvm_init(int smp_cpus)
ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0); ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);
if (ret < KVM_API_VERSION) { if (ret < KVM_API_VERSION) {
if (ret > 0) if (ret > 0) {
ret = -EINVAL; ret = -EINVAL;
}
fprintf(stderr, "kvm version too old\n"); fprintf(stderr, "kvm version too old\n");
goto err; goto err;
} }
@ -689,39 +700,23 @@ int kvm_init(int smp_cpus)
goto err; goto err;
} }
/* initially, KVM allocated its own memory and we had to jump through missing_cap = kvm_check_extension_list(s, kvm_required_capabilites);
* hooks to make phys_ram_base point to this. Modern versions of KVM if (!missing_cap) {
* just use a user allocated buffer so we can use regular pages missing_cap =
* unmodified. Make sure we have a sufficiently modern version of KVM. kvm_check_extension_list(s, kvm_arch_required_capabilities);
*/ }
if (!kvm_check_extension(s, KVM_CAP_USER_MEMORY)) { if (missing_cap) {
ret = -EINVAL; ret = -EINVAL;
fprintf(stderr, "kvm does not support KVM_CAP_USER_MEMORY\n%s", fprintf(stderr, "kvm does not support %s\n%s",
upgrade_note); missing_cap->name, upgrade_note);
goto err; 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 = kvm_check_extension(s, KVM_CAP_COALESCED_MMIO);
s->coalesced_mmio_ring = NULL;
#endif
s->broken_set_mem_region = 1; s->broken_set_mem_region = 1;
#ifdef KVM_CAP_JOIN_MEMORY_REGIONS_WORKS #ifdef KVM_CAP_JOIN_MEMORY_REGIONS_WORKS
ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS); ret = kvm_check_extension(s, KVM_CAP_JOIN_MEMORY_REGIONS_WORKS);
if (ret > 0) { if (ret > 0) {
s->broken_set_mem_region = 0; s->broken_set_mem_region = 0;
} }
@ -753,9 +748,10 @@ int kvm_init(int smp_cpus)
s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS); s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
#endif #endif
ret = kvm_arch_init(s, smp_cpus); ret = kvm_arch_init(s);
if (ret < 0) if (ret < 0) {
goto err; goto err;
}
kvm_state = s; kvm_state = s;
cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client); cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client);
@ -766,11 +762,13 @@ int kvm_init(int smp_cpus)
err: err:
if (s) { if (s) {
if (s->vmfd != -1) if (s->vmfd != -1) {
close(s->vmfd); close(s->vmfd);
if (s->fd != -1) }
if (s->fd != -1) {
close(s->fd); close(s->fd);
} }
}
qemu_free(s); qemu_free(s);
return ret; return ret;
@ -816,36 +814,36 @@ static int kvm_handle_io(uint16_t port, void *data, int direction, int size,
} }
#ifdef KVM_CAP_INTERNAL_ERROR_DATA #ifdef KVM_CAP_INTERNAL_ERROR_DATA
static void kvm_handle_internal_error(CPUState *env, struct kvm_run *run) static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
{ {
fprintf(stderr, "KVM internal error.");
if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) { if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
int i; int i;
fprintf(stderr, "KVM internal error. Suberror: %d\n", fprintf(stderr, " Suberror: %d\n", run->internal.suberror);
run->internal.suberror);
for (i = 0; i < run->internal.ndata; ++i) { for (i = 0; i < run->internal.ndata; ++i) {
fprintf(stderr, "extra data[%d]: %"PRIx64"\n", fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
i, (uint64_t)run->internal.data[i]); i, (uint64_t)run->internal.data[i]);
} }
} else {
fprintf(stderr, "\n");
} }
cpu_dump_state(env, stderr, fprintf, 0);
if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) { if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
fprintf(stderr, "emulation failure\n"); fprintf(stderr, "emulation failure\n");
if (!kvm_arch_stop_on_emulation_error(env)) if (!kvm_arch_stop_on_emulation_error(env)) {
return; cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
return 0;
}
} }
/* FIXME: Should trigger a qmp message to let management know /* FIXME: Should trigger a qmp message to let management know
* something went wrong. * something went wrong.
*/ */
vm_stop(0); return -1;
} }
#endif #endif
void kvm_flush_coalesced_mmio_buffer(void) void kvm_flush_coalesced_mmio_buffer(void)
{ {
#ifdef KVM_CAP_COALESCED_MMIO
KVMState *s = kvm_state; KVMState *s = kvm_state;
if (s->coalesced_mmio_ring) { if (s->coalesced_mmio_ring) {
struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring; struct kvm_coalesced_mmio_ring *ring = s->coalesced_mmio_ring;
@ -859,7 +857,6 @@ void kvm_flush_coalesced_mmio_buffer(void)
ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX; ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX;
} }
} }
#endif
} }
static void do_kvm_cpu_synchronize_state(void *_env) static void do_kvm_cpu_synchronize_state(void *_env)
@ -874,9 +871,10 @@ static void do_kvm_cpu_synchronize_state(void *_env)
void kvm_cpu_synchronize_state(CPUState *env) void kvm_cpu_synchronize_state(CPUState *env)
{ {
if (!env->kvm_vcpu_dirty) if (!env->kvm_vcpu_dirty) {
run_on_cpu(env, do_kvm_cpu_synchronize_state, env); run_on_cpu(env, do_kvm_cpu_synchronize_state, env);
} }
}
void kvm_cpu_synchronize_post_reset(CPUState *env) void kvm_cpu_synchronize_post_reset(CPUState *env)
{ {
@ -924,6 +922,8 @@ int kvm_cpu_exec(CPUState *env)
cpu_single_env = env; cpu_single_env = env;
kvm_arch_post_run(env, run); kvm_arch_post_run(env, run);
kvm_flush_coalesced_mmio_buffer();
if (ret == -EINTR || ret == -EAGAIN) { if (ret == -EINTR || ret == -EAGAIN) {
cpu_exit(env); cpu_exit(env);
DPRINTF("io window exit\n"); DPRINTF("io window exit\n");
@ -936,8 +936,6 @@ int kvm_cpu_exec(CPUState *env)
abort(); abort();
} }
kvm_flush_coalesced_mmio_buffer();
ret = 0; /* exit loop */ ret = 0; /* exit loop */
switch (run->exit_reason) { switch (run->exit_reason) {
case KVM_EXIT_IO: case KVM_EXIT_IO:
@ -965,17 +963,13 @@ int kvm_cpu_exec(CPUState *env)
ret = 1; ret = 1;
break; break;
case KVM_EXIT_UNKNOWN: case KVM_EXIT_UNKNOWN:
DPRINTF("kvm_exit_unknown\n"); fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n",
break; (uint64_t)run->hw.hardware_exit_reason);
case KVM_EXIT_FAIL_ENTRY: ret = -1;
DPRINTF("kvm_exit_fail_entry\n");
break;
case KVM_EXIT_EXCEPTION:
DPRINTF("kvm_exit_exception\n");
break; break;
#ifdef KVM_CAP_INTERNAL_ERROR_DATA #ifdef KVM_CAP_INTERNAL_ERROR_DATA
case KVM_EXIT_INTERNAL_ERROR: case KVM_EXIT_INTERNAL_ERROR:
kvm_handle_internal_error(env, run); ret = kvm_handle_internal_error(env, run);
break; break;
#endif #endif
case KVM_EXIT_DEBUG: case KVM_EXIT_DEBUG:
@ -996,6 +990,11 @@ int kvm_cpu_exec(CPUState *env)
} }
} while (ret > 0); } while (ret > 0);
if (ret < 0) {
cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
vm_stop(0);
env->exit_request = 1;
}
if (env->exit_request) { if (env->exit_request) {
env->exit_request = 0; env->exit_request = 0;
env->exception_index = EXCP_INTERRUPT; env->exception_index = EXCP_INTERRUPT;
@ -1015,9 +1014,9 @@ int kvm_ioctl(KVMState *s, int type, ...)
va_end(ap); va_end(ap);
ret = ioctl(s->fd, type, arg); ret = ioctl(s->fd, type, arg);
if (ret == -1) if (ret == -1) {
ret = -errno; ret = -errno;
}
return ret; return ret;
} }
@ -1032,9 +1031,9 @@ int kvm_vm_ioctl(KVMState *s, int type, ...)
va_end(ap); va_end(ap);
ret = ioctl(s->vmfd, type, arg); ret = ioctl(s->vmfd, type, arg);
if (ret == -1) if (ret == -1) {
ret = -errno; ret = -errno;
}
return ret; return ret;
} }
@ -1049,21 +1048,15 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...)
va_end(ap); va_end(ap);
ret = ioctl(env->kvm_fd, type, arg); ret = ioctl(env->kvm_fd, type, arg);
if (ret == -1) if (ret == -1) {
ret = -errno; ret = -errno;
}
return ret; return ret;
} }
int kvm_has_sync_mmu(void) int kvm_has_sync_mmu(void)
{ {
#ifdef KVM_CAP_SYNC_MMU return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
KVMState *s = kvm_state;
return kvm_check_extension(s, KVM_CAP_SYNC_MMU);
#else
return 0;
#endif
} }
int kvm_has_vcpu_events(void) int kvm_has_vcpu_events(void)
@ -1120,9 +1113,10 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
struct kvm_sw_breakpoint *bp; struct kvm_sw_breakpoint *bp;
QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) { QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) {
if (bp->pc == pc) if (bp->pc == pc) {
return bp; return bp;
} }
}
return NULL; return NULL;
} }
@ -1176,8 +1170,9 @@ int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
} }
bp = qemu_malloc(sizeof(struct kvm_sw_breakpoint)); bp = qemu_malloc(sizeof(struct kvm_sw_breakpoint));
if (!bp) if (!bp) {
return -ENOMEM; return -ENOMEM;
}
bp->pc = addr; bp->pc = addr;
bp->use_count = 1; bp->use_count = 1;
@ -1191,15 +1186,17 @@ int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
bp, entry); bp, entry);
} else { } else {
err = kvm_arch_insert_hw_breakpoint(addr, len, type); err = kvm_arch_insert_hw_breakpoint(addr, len, type);
if (err) if (err) {
return err; return err;
} }
}
for (env = first_cpu; env != NULL; env = env->next_cpu) { for (env = first_cpu; env != NULL; env = env->next_cpu) {
err = kvm_update_guest_debug(env, 0); err = kvm_update_guest_debug(env, 0);
if (err) if (err) {
return err; return err;
} }
}
return 0; return 0;
} }
@ -1212,8 +1209,9 @@ int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
if (type == GDB_BREAKPOINT_SW) { if (type == GDB_BREAKPOINT_SW) {
bp = kvm_find_sw_breakpoint(current_env, addr); bp = kvm_find_sw_breakpoint(current_env, addr);
if (!bp) if (!bp) {
return -ENOENT; return -ENOENT;
}
if (bp->use_count > 1) { if (bp->use_count > 1) {
bp->use_count--; bp->use_count--;
@ -1221,22 +1219,25 @@ int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
} }
err = kvm_arch_remove_sw_breakpoint(current_env, bp); err = kvm_arch_remove_sw_breakpoint(current_env, bp);
if (err) if (err) {
return err; return err;
}
QTAILQ_REMOVE(&current_env->kvm_state->kvm_sw_breakpoints, bp, entry); QTAILQ_REMOVE(&current_env->kvm_state->kvm_sw_breakpoints, bp, entry);
qemu_free(bp); qemu_free(bp);
} else { } else {
err = kvm_arch_remove_hw_breakpoint(addr, len, type); err = kvm_arch_remove_hw_breakpoint(addr, len, type);
if (err) if (err) {
return err; return err;
} }
}
for (env = first_cpu; env != NULL; env = env->next_cpu) { for (env = first_cpu; env != NULL; env = env->next_cpu) {
err = kvm_update_guest_debug(env, 0); err = kvm_update_guest_debug(env, 0);
if (err) if (err) {
return err; return err;
} }
}
return 0; return 0;
} }
@ -1250,16 +1251,18 @@ void kvm_remove_all_breakpoints(CPUState *current_env)
if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) { if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) {
/* Try harder to find a CPU that currently sees the breakpoint. */ /* Try harder to find a CPU that currently sees the breakpoint. */
for (env = first_cpu; env != NULL; env = env->next_cpu) { for (env = first_cpu; env != NULL; env = env->next_cpu) {
if (kvm_arch_remove_sw_breakpoint(env, bp) == 0) if (kvm_arch_remove_sw_breakpoint(env, bp) == 0) {
break; break;
} }
} }
} }
}
kvm_arch_remove_all_hw_breakpoints(); kvm_arch_remove_all_hw_breakpoints();
for (env = first_cpu; env != NULL; env = env->next_cpu) for (env = first_cpu; env != NULL; env = env->next_cpu) {
kvm_update_guest_debug(env, 0); kvm_update_guest_debug(env, 0);
} }
}
#else /* !KVM_CAP_SET_GUEST_DEBUG */ #else /* !KVM_CAP_SET_GUEST_DEBUG */
@ -1290,8 +1293,9 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset)
struct kvm_signal_mask *sigmask; struct kvm_signal_mask *sigmask;
int r; int r;
if (!sigset) if (!sigset) {
return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL); return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL);
}
sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset)); sigmask = qemu_malloc(sizeof(*sigmask) + sizeof(*sigset));
@ -1346,13 +1350,16 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
.fd = fd, .fd = fd,
}; };
int r; int r;
if (!kvm_enabled()) if (!kvm_enabled()) {
return -ENOSYS; return -ENOSYS;
if (!assign) }
if (!assign) {
kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN; kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
}
r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick); r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
if (r < 0) if (r < 0) {
return r; return r;
}
return 0; return 0;
#else #else
return -ENOSYS; return -ENOSYS;

View File

@ -58,7 +58,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension)
return 0; return 0;
} }
int kvm_init(int smp_cpus) int kvm_init(void)
{ {
return -ENOSYS; return -ENOSYS;
} }

14
kvm.h
View File

@ -32,9 +32,17 @@ extern int kvm_allowed;
struct kvm_run; 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 */ /* external API */
int kvm_init(int smp_cpus); int kvm_init(void);
int kvm_has_sync_mmu(void); int kvm_has_sync_mmu(void);
int kvm_has_vcpu_events(void); int kvm_has_vcpu_events(void);
@ -86,6 +94,8 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...);
/* Arch specific hooks */ /* Arch specific hooks */
extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
int kvm_arch_post_run(CPUState *env, struct kvm_run *run); int kvm_arch_post_run(CPUState *env, struct kvm_run *run);
int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run); int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
@ -105,7 +115,7 @@ int kvm_arch_get_registers(CPUState *env);
int kvm_arch_put_registers(CPUState *env, int level); int kvm_arch_put_registers(CPUState *env, int level);
int kvm_arch_init(KVMState *s, int smp_cpus); int kvm_arch_init(KVMState *s);
int kvm_arch_init_vcpu(CPUState *env); int kvm_arch_init_vcpu(CPUState *env);

View File

@ -2709,13 +2709,16 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
uint64_t mcg_status = qdict_get_int(qdict, "mcg_status"); uint64_t mcg_status = qdict_get_int(qdict, "mcg_status");
uint64_t addr = qdict_get_int(qdict, "addr"); uint64_t addr = qdict_get_int(qdict, "addr");
uint64_t misc = qdict_get_int(qdict, "misc"); uint64_t misc = qdict_get_int(qdict, "misc");
int broadcast = qdict_get_try_bool(qdict, "broadcast", 0);
for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
if (cenv->cpu_index == cpu_index && cenv->mcg_cap) { if (cenv->cpu_index == cpu_index && cenv->mcg_cap) {
cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc); cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc,
broadcast);
break; break;
} }
} }
}
#endif #endif
static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data) static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data)

View File

@ -699,6 +699,10 @@ typedef struct CPUX86State {
uint32_t smbase; uint32_t smbase;
int old_exception; /* exception in flight */ int old_exception; /* exception in flight */
/* KVM states, automatically cleared on reset */
uint8_t nmi_injected;
uint8_t nmi_pending;
CPU_COMMON CPU_COMMON
/* processor features (e.g. for CPUID insn) */ /* processor features (e.g. for CPUID insn) */
@ -726,8 +730,6 @@ typedef struct CPUX86State {
int32_t exception_injected; int32_t exception_injected;
int32_t interrupt_injected; int32_t interrupt_injected;
uint8_t soft_interrupt; uint8_t soft_interrupt;
uint8_t nmi_injected;
uint8_t nmi_pending;
uint8_t has_error_code; uint8_t has_error_code;
uint32_t sipi_vector; uint32_t sipi_vector;
uint32_t cpuid_kvm_features; uint32_t cpuid_kvm_features;
@ -760,6 +762,7 @@ int cpu_x86_exec(CPUX86State *s);
void cpu_x86_close(CPUX86State *s); void cpu_x86_close(CPUX86State *s);
void x86_cpu_list (FILE *f, fprintf_function cpu_fprintf, const char *optarg); void x86_cpu_list (FILE *f, fprintf_function cpu_fprintf, const char *optarg);
void x86_cpudef_setup(void); void x86_cpudef_setup(void);
int cpu_x86_support_mca_broadcast(CPUState *env);
int cpu_get_pic_interrupt(CPUX86State *s); int cpu_get_pic_interrupt(CPUX86State *s);
/* MSDOS compatibility mode FPU exception support */ /* MSDOS compatibility mode FPU exception support */
@ -873,6 +876,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
uint32_t *ecx, uint32_t *edx); uint32_t *ecx, uint32_t *edx);
int cpu_x86_register (CPUX86State *env, const char *cpu_model); int cpu_x86_register (CPUX86State *env, const char *cpu_model);
void cpu_clear_apic_feature(CPUX86State *env); void cpu_clear_apic_feature(CPUX86State *env);
void host_cpuid(uint32_t function, uint32_t count,
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
/* helper.c */ /* helper.c */
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,

View File

@ -103,9 +103,8 @@ typedef struct model_features_t {
int check_cpuid = 0; int check_cpuid = 0;
int enforce_cpuid = 0; int enforce_cpuid = 0;
static void host_cpuid(uint32_t function, uint32_t count, void host_cpuid(uint32_t function, uint32_t count,
uint32_t *eax, uint32_t *ebx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
uint32_t *ecx, uint32_t *edx)
{ {
#if defined(CONFIG_KVM) #if defined(CONFIG_KVM)
uint32_t vec[4]; uint32_t vec[4];

View File

@ -110,6 +110,32 @@ void cpu_x86_close(CPUX86State *env)
qemu_free(env); qemu_free(env);
} }
static void cpu_x86_version(CPUState *env, int *family, int *model)
{
int cpuver = env->cpuid_version;
if (family == NULL || model == NULL) {
return;
}
*family = (cpuver >> 8) & 0x0f;
*model = ((cpuver >> 12) & 0xf0) + ((cpuver >> 4) & 0x0f);
}
/* Broadcast MCA signal for processor version 06H_EH and above */
int cpu_x86_support_mca_broadcast(CPUState *env)
{
int family = 0;
int model = 0;
cpu_x86_version(env, &family, &model);
if ((family == 6 && model >= 14) || family > 6) {
return 1;
}
return 0;
}
/***********************************************************/ /***********************************************************/
/* x86 debug */ /* x86 debug */
@ -223,6 +249,9 @@ done:
cpu_fprintf(f, "\n"); cpu_fprintf(f, "\n");
} }
#define DUMP_CODE_BYTES_TOTAL 50
#define DUMP_CODE_BYTES_BACKWARD 20
void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
int flags) int flags)
{ {
@ -408,6 +437,24 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, " "); cpu_fprintf(f, " ");
} }
} }
if (flags & CPU_DUMP_CODE) {
target_ulong base = env->segs[R_CS].base + env->eip;
target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
uint8_t code;
char codestr[3];
cpu_fprintf(f, "Code=");
for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
if (cpu_memory_rw_debug(env, base - offs + i, &code, 1, 0) == 0) {
snprintf(codestr, sizeof(codestr), "%02x", code);
} else {
snprintf(codestr, sizeof(codestr), "??");
}
cpu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
i == offs ? "<" : "", codestr, i == offs ? ">" : "");
}
cpu_fprintf(f, "\n");
}
} }
/***********************************************************/ /***********************************************************/
@ -1021,21 +1068,12 @@ static void breakpoint_handler(CPUState *env)
/* This should come from sysemu.h - if we could include it here... */ /* This should come from sysemu.h - if we could include it here... */
void qemu_system_reset_request(void); void qemu_system_reset_request(void);
void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, static void qemu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
uint64_t mcg_status, uint64_t addr, uint64_t misc) uint64_t mcg_status, uint64_t addr, uint64_t misc)
{ {
uint64_t mcg_cap = cenv->mcg_cap; uint64_t mcg_cap = cenv->mcg_cap;
unsigned bank_num = mcg_cap & 0xff;
uint64_t *banks = cenv->mce_banks; uint64_t *banks = cenv->mce_banks;
if (bank >= bank_num || !(status & MCI_STATUS_VAL))
return;
if (kvm_enabled()) {
kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, 0);
return;
}
/* /*
* if MSR_MCG_CTL is not all 1s, the uncorrected error * if MSR_MCG_CTL is not all 1s, the uncorrected error
* reporting is disabled * reporting is disabled
@ -1076,6 +1114,45 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
} else } else
banks[1] |= MCI_STATUS_OVER; banks[1] |= MCI_STATUS_OVER;
} }
void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
uint64_t mcg_status, uint64_t addr, uint64_t misc,
int broadcast)
{
unsigned bank_num = cenv->mcg_cap & 0xff;
CPUState *env;
int flag = 0;
if (bank >= bank_num || !(status & MCI_STATUS_VAL)) {
return;
}
if (broadcast) {
if (!cpu_x86_support_mca_broadcast(cenv)) {
fprintf(stderr, "Current CPU does not support broadcast\n");
return;
}
}
if (kvm_enabled()) {
if (broadcast) {
flag |= MCE_BROADCAST;
}
kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag);
} else {
qemu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
if (broadcast) {
for (env = first_cpu; env != NULL; env = env->next_cpu) {
if (cenv == env) {
continue;
}
qemu_inject_x86_mce(env, 1, 0xa000000000000000, 0, 0, 0);
}
}
}
}
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
static void mce_init(CPUX86State *cenv) static void mce_init(CPUX86State *cenv)

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,11 @@
#ifndef __KVM_X86_H__ #ifndef __KVM_X86_H__
#define __KVM_X86_H__ #define __KVM_X86_H__
#define ABORT_ON_ERROR 0x01
#define MCE_BROADCAST 0x02
void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
uint64_t mcg_status, uint64_t addr, uint64_t misc, uint64_t mcg_status, uint64_t addr, uint64_t misc,
int abort_on_error); int flag);
#endif #endif

View File

@ -37,6 +37,10 @@
do { } while (0) do { } while (0)
#endif #endif
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
};
static int cap_interrupt_unset = false; static int cap_interrupt_unset = false;
static int cap_interrupt_level = false; static int cap_interrupt_level = false;
@ -56,7 +60,7 @@ static void kvm_kick_env(void *env)
qemu_cpu_kick(env); qemu_cpu_kick(env);
} }
int kvm_arch_init(KVMState *s, int smp_cpus) int kvm_arch_init(KVMState *s)
{ {
#ifdef KVM_CAP_PPC_UNSET_IRQ #ifdef KVM_CAP_PPC_UNSET_IRQ
cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ); cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ);
@ -307,6 +311,10 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
dprintf("handle halt\n"); dprintf("handle halt\n");
ret = kvmppc_handle_halt(env); ret = kvmppc_handle_halt(env);
break; break;
default:
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
ret = -1;
break;
} }
return ret; return ret;

View File

@ -70,7 +70,11 @@
#define SCLP_CMDW_READ_SCP_INFO 0x00020001 #define SCLP_CMDW_READ_SCP_INFO 0x00020001
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 #define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
int kvm_arch_init(KVMState *s, int smp_cpus) const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
};
int kvm_arch_init(KVMState *s)
{ {
return 0; return 0;
} }

2
vl.c
View File

@ -2860,7 +2860,7 @@ int main(int argc, char **argv, char **envp)
} }
if (kvm_allowed) { if (kvm_allowed) {
int ret = kvm_init(smp_cpus); int ret = kvm_init();
if (ret < 0) { if (ret < 0) {
if (!kvm_available()) { if (!kvm_available()) {
printf("KVM not supported for this target\n"); printf("KVM not supported for this target\n");