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:
commit
b3a98367ee
36
configure
vendored
36
configure
vendored
@ -1663,15 +1663,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
|
||||
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
|
||||
@ -1706,8 +1722,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"
|
||||
|
@ -765,6 +765,8 @@ int page_check_range(target_ulong start, target_ulong len, int flags);
|
||||
CPUState *cpu_copy(CPUState *env);
|
||||
CPUState *qemu_get_cpu(int cpu);
|
||||
|
||||
#define CPU_DUMP_CODE 0x00010000
|
||||
|
||||
void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
|
||||
int flags);
|
||||
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);
|
||||
|
||||
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 */
|
||||
|
2
cpus.c
2
cpus.c
@ -735,9 +735,7 @@ static sigset_t block_io_signals(void)
|
||||
void qemu_mutex_lock_iothread(void)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
qemu_mutex_lock(&qemu_fair_mutex);
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
qemu_mutex_unlock(&qemu_fair_mutex);
|
||||
} else {
|
||||
qemu_mutex_lock(&qemu_fair_mutex);
|
||||
if (qemu_mutex_trylock(&qemu_global_mutex)) {
|
||||
|
@ -1152,9 +1152,9 @@ ETEXI
|
||||
|
||||
{
|
||||
.name = "mce",
|
||||
.args_type = "cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l",
|
||||
.params = "cpu bank status mcgstatus addr misc",
|
||||
.help = "inject a MCE on the given CPU",
|
||||
.args_type = "broadcast:-b,cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l",
|
||||
.params = "[-b] cpu bank status mcgstatus addr misc",
|
||||
.help = "inject a MCE on the given CPU [and broadcast to other CPUs with -b option]",
|
||||
.mhandler.cmd = do_inject_mce,
|
||||
},
|
||||
|
||||
|
249
kvm-all.c
249
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,16 +80,24 @@ 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;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
|
||||
/* KVM private memory slots */
|
||||
if (i >= 8 && i < 12)
|
||||
if (i >= 8 && i < 12) {
|
||||
continue;
|
||||
if (s->slots[i].memory_size == 0)
|
||||
}
|
||||
if (s->slots[i].memory_size == 0) {
|
||||
return &s->slots[i];
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: no free slot available\n", __func__);
|
||||
@ -225,11 +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
|
||||
if (s->coalesced_mmio && !s->coalesced_mmio_ring) {
|
||||
s->coalesced_mmio_ring =
|
||||
(void *)env->kvm_run + s->coalesced_mmio * PAGE_SIZE;
|
||||
}
|
||||
|
||||
ret = kvm_arch_init_vcpu(env);
|
||||
if (ret == 0) {
|
||||
@ -275,16 +280,14 @@ 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)
|
||||
{
|
||||
return kvm_dirty_pages_log_change(phys_addr, size,
|
||||
KVM_MEM_LOG_DIRTY_PAGES,
|
||||
KVM_MEM_LOG_DIRTY_PAGES);
|
||||
return kvm_dirty_pages_log_change(phys_addr, size, KVM_MEM_LOG_DIRTY_PAGES,
|
||||
KVM_MEM_LOG_DIRTY_PAGES);
|
||||
}
|
||||
|
||||
int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size)
|
||||
{
|
||||
return kvm_dirty_pages_log_change(phys_addr, size,
|
||||
0,
|
||||
KVM_MEM_LOG_DIRTY_PAGES);
|
||||
return kvm_dirty_pages_log_change(phys_addr, size, 0,
|
||||
KVM_MEM_LOG_DIRTY_PAGES);
|
||||
}
|
||||
|
||||
static int kvm_set_migration_log(int enable)
|
||||
@ -356,7 +359,7 @@ static int kvm_get_dirty_pages_log_range(unsigned long start_addr,
|
||||
* @end_addr: end of logged region.
|
||||
*/
|
||||
static int kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
|
||||
target_phys_addr_t end_addr)
|
||||
target_phys_addr_t end_addr)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
unsigned long size, allocated_size = 0;
|
||||
@ -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 ret = -ENOSYS;
|
||||
#ifdef KVM_CAP_COALESCED_MMIO
|
||||
KVMState *s = kvm_state;
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
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 ret = -ENOSYS;
|
||||
#ifdef KVM_CAP_COALESCED_MMIO
|
||||
KVMState *s = kvm_state;
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -484,9 +483,20 @@ static int kvm_check_many_ioeventfds(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void kvm_set_phys_mem(target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset)
|
||||
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)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
|
||||
@ -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 */
|
||||
if (!size)
|
||||
if (!size) {
|
||||
return;
|
||||
|
||||
}
|
||||
/* KVM does not need to know about this memory */
|
||||
if (flags >= IO_MEM_UNASSIGNED)
|
||||
if (flags >= IO_MEM_UNASSIGNED) {
|
||||
return;
|
||||
|
||||
}
|
||||
mem = kvm_alloc_slot(s);
|
||||
mem->memory_size = size;
|
||||
mem->start_addr = start_addr;
|
||||
@ -615,38 +625,38 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr,
|
||||
}
|
||||
|
||||
static void kvm_client_set_memory(struct CPUPhysMemoryClient *client,
|
||||
target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset)
|
||||
target_phys_addr_t start_addr,
|
||||
ram_addr_t size, ram_addr_t phys_offset)
|
||||
{
|
||||
kvm_set_phys_mem(start_addr, size, phys_offset);
|
||||
kvm_set_phys_mem(start_addr, size, phys_offset);
|
||||
}
|
||||
|
||||
static int kvm_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
|
||||
target_phys_addr_t start_addr,
|
||||
target_phys_addr_t end_addr)
|
||||
target_phys_addr_t start_addr,
|
||||
target_phys_addr_t end_addr)
|
||||
{
|
||||
return kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
|
||||
return kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
|
||||
}
|
||||
|
||||
static int kvm_client_migration_log(struct CPUPhysMemoryClient *client,
|
||||
int enable)
|
||||
int enable)
|
||||
{
|
||||
return kvm_set_migration_log(enable);
|
||||
return kvm_set_migration_log(enable);
|
||||
}
|
||||
|
||||
static CPUPhysMemoryClient kvm_cpu_phys_memory_client = {
|
||||
.set_memory = kvm_client_set_memory,
|
||||
.sync_dirty_bitmap = kvm_client_sync_dirty_bitmap,
|
||||
.migration_log = kvm_client_migration_log,
|
||||
.set_memory = kvm_client_set_memory,
|
||||
.sync_dirty_bitmap = kvm_client_sync_dirty_bitmap,
|
||||
.migration_log = kvm_client_migration_log,
|
||||
};
|
||||
|
||||
int kvm_init(int smp_cpus)
|
||||
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";
|
||||
KVMState *s;
|
||||
const KVMCapabilityInfo *missing_cap;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
@ -655,9 +665,9 @@ int kvm_init(int smp_cpus)
|
||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
||||
QTAILQ_INIT(&s->kvm_sw_breakpoints);
|
||||
#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->vmfd = -1;
|
||||
s->fd = qemu_open("/dev/kvm", O_RDWR);
|
||||
if (s->fd == -1) {
|
||||
@ -668,8 +678,9 @@ int kvm_init(int smp_cpus)
|
||||
|
||||
ret = kvm_ioctl(s, KVM_GET_API_VERSION, 0);
|
||||
if (ret < KVM_API_VERSION) {
|
||||
if (ret > 0)
|
||||
if (ret > 0) {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
fprintf(stderr, "kvm version too old\n");
|
||||
goto err;
|
||||
}
|
||||
@ -689,39 +700,23 @@ int kvm_init(int smp_cpus)
|
||||
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
|
||||
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) {
|
||||
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);
|
||||
#endif
|
||||
|
||||
ret = kvm_arch_init(s, smp_cpus);
|
||||
if (ret < 0)
|
||||
ret = kvm_arch_init(s);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
kvm_state = s;
|
||||
cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client);
|
||||
@ -766,10 +762,12 @@ int kvm_init(int smp_cpus)
|
||||
|
||||
err:
|
||||
if (s) {
|
||||
if (s->vmfd != -1)
|
||||
if (s->vmfd != -1) {
|
||||
close(s->vmfd);
|
||||
if (s->fd != -1)
|
||||
}
|
||||
if (s->fd != -1) {
|
||||
close(s->fd);
|
||||
}
|
||||
}
|
||||
qemu_free(s);
|
||||
|
||||
@ -816,36 +814,36 @@ static int kvm_handle_io(uint16_t port, void *data, int direction, int size,
|
||||
}
|
||||
|
||||
#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)) {
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "KVM internal error. Suberror: %d\n",
|
||||
run->internal.suberror);
|
||||
|
||||
fprintf(stderr, " Suberror: %d\n", run->internal.suberror);
|
||||
for (i = 0; i < run->internal.ndata; ++i) {
|
||||
fprintf(stderr, "extra data[%d]: %"PRIx64"\n",
|
||||
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) {
|
||||
fprintf(stderr, "emulation failure\n");
|
||||
if (!kvm_arch_stop_on_emulation_error(env))
|
||||
return;
|
||||
if (!kvm_arch_stop_on_emulation_error(env)) {
|
||||
cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* FIXME: Should trigger a qmp message to let management know
|
||||
* something went wrong.
|
||||
*/
|
||||
vm_stop(0);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 +857,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)
|
||||
@ -874,8 +871,9 @@ static void do_kvm_cpu_synchronize_state(void *_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);
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_cpu_synchronize_post_reset(CPUState *env)
|
||||
@ -924,6 +922,8 @@ int kvm_cpu_exec(CPUState *env)
|
||||
cpu_single_env = env;
|
||||
kvm_arch_post_run(env, run);
|
||||
|
||||
kvm_flush_coalesced_mmio_buffer();
|
||||
|
||||
if (ret == -EINTR || ret == -EAGAIN) {
|
||||
cpu_exit(env);
|
||||
DPRINTF("io window exit\n");
|
||||
@ -936,8 +936,6 @@ int kvm_cpu_exec(CPUState *env)
|
||||
abort();
|
||||
}
|
||||
|
||||
kvm_flush_coalesced_mmio_buffer();
|
||||
|
||||
ret = 0; /* exit loop */
|
||||
switch (run->exit_reason) {
|
||||
case KVM_EXIT_IO:
|
||||
@ -965,17 +963,13 @@ int kvm_cpu_exec(CPUState *env)
|
||||
ret = 1;
|
||||
break;
|
||||
case KVM_EXIT_UNKNOWN:
|
||||
DPRINTF("kvm_exit_unknown\n");
|
||||
break;
|
||||
case KVM_EXIT_FAIL_ENTRY:
|
||||
DPRINTF("kvm_exit_fail_entry\n");
|
||||
break;
|
||||
case KVM_EXIT_EXCEPTION:
|
||||
DPRINTF("kvm_exit_exception\n");
|
||||
fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n",
|
||||
(uint64_t)run->hw.hardware_exit_reason);
|
||||
ret = -1;
|
||||
break;
|
||||
#ifdef KVM_CAP_INTERNAL_ERROR_DATA
|
||||
case KVM_EXIT_INTERNAL_ERROR:
|
||||
kvm_handle_internal_error(env, run);
|
||||
ret = kvm_handle_internal_error(env, run);
|
||||
break;
|
||||
#endif
|
||||
case KVM_EXIT_DEBUG:
|
||||
@ -996,6 +990,11 @@ int kvm_cpu_exec(CPUState *env)
|
||||
}
|
||||
} 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) {
|
||||
env->exit_request = 0;
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
@ -1015,9 +1014,9 @@ int kvm_ioctl(KVMState *s, int type, ...)
|
||||
va_end(ap);
|
||||
|
||||
ret = ioctl(s->fd, type, arg);
|
||||
if (ret == -1)
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1032,9 +1031,9 @@ int kvm_vm_ioctl(KVMState *s, int type, ...)
|
||||
va_end(ap);
|
||||
|
||||
ret = ioctl(s->vmfd, type, arg);
|
||||
if (ret == -1)
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1049,21 +1048,15 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...)
|
||||
va_end(ap);
|
||||
|
||||
ret = ioctl(env->kvm_fd, type, arg);
|
||||
if (ret == -1)
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -1120,8 +1113,9 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
|
||||
struct kvm_sw_breakpoint *bp;
|
||||
|
||||
QTAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) {
|
||||
if (bp->pc == pc)
|
||||
if (bp->pc == pc) {
|
||||
return bp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -1176,8 +1170,9 @@ int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
|
||||
}
|
||||
|
||||
bp = qemu_malloc(sizeof(struct kvm_sw_breakpoint));
|
||||
if (!bp)
|
||||
if (!bp) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bp->pc = addr;
|
||||
bp->use_count = 1;
|
||||
@ -1191,14 +1186,16 @@ int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr,
|
||||
bp, entry);
|
||||
} else {
|
||||
err = kvm_arch_insert_hw_breakpoint(addr, len, type);
|
||||
if (err)
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
err = kvm_update_guest_debug(env, 0);
|
||||
if (err)
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1212,8 +1209,9 @@ int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
|
||||
|
||||
if (type == GDB_BREAKPOINT_SW) {
|
||||
bp = kvm_find_sw_breakpoint(current_env, addr);
|
||||
if (!bp)
|
||||
if (!bp) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (bp->use_count > 1) {
|
||||
bp->use_count--;
|
||||
@ -1221,21 +1219,24 @@ int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr,
|
||||
}
|
||||
|
||||
err = kvm_arch_remove_sw_breakpoint(current_env, bp);
|
||||
if (err)
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
QTAILQ_REMOVE(¤t_env->kvm_state->kvm_sw_breakpoints, bp, entry);
|
||||
qemu_free(bp);
|
||||
} else {
|
||||
err = kvm_arch_remove_hw_breakpoint(addr, len, type);
|
||||
if (err)
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
err = kvm_update_guest_debug(env, 0);
|
||||
if (err)
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1250,15 +1251,17 @@ void kvm_remove_all_breakpoints(CPUState *current_env)
|
||||
if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) {
|
||||
/* Try harder to find a CPU that currently sees the breakpoint. */
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
int r;
|
||||
|
||||
if (!sigset)
|
||||
if (!sigset) {
|
||||
return kvm_vcpu_ioctl(env, KVM_SET_SIGNAL_MASK, NULL);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
int r;
|
||||
if (!kvm_enabled())
|
||||
if (!kvm_enabled()) {
|
||||
return -ENOSYS;
|
||||
if (!assign)
|
||||
}
|
||||
if (!assign) {
|
||||
kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
|
||||
}
|
||||
r = kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return -ENOSYS;
|
||||
|
@ -58,7 +58,7 @@ int kvm_check_extension(KVMState *s, unsigned int extension)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_init(int smp_cpus)
|
||||
int kvm_init(void)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
14
kvm.h
14
kvm.h
@ -32,9 +32,17 @@ 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(int smp_cpus);
|
||||
int kvm_init(void);
|
||||
|
||||
int kvm_has_sync_mmu(void);
|
||||
int kvm_has_vcpu_events(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);
|
||||
@ -105,7 +115,7 @@ int kvm_arch_get_registers(CPUState *env);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -2709,12 +2709,15 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
|
||||
uint64_t mcg_status = qdict_get_int(qdict, "mcg_status");
|
||||
uint64_t addr = qdict_get_int(qdict, "addr");
|
||||
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) {
|
||||
cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
|
||||
cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc,
|
||||
broadcast);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -699,6 +699,10 @@ typedef struct CPUX86State {
|
||||
uint32_t smbase;
|
||||
int old_exception; /* exception in flight */
|
||||
|
||||
/* KVM states, automatically cleared on reset */
|
||||
uint8_t nmi_injected;
|
||||
uint8_t nmi_pending;
|
||||
|
||||
CPU_COMMON
|
||||
|
||||
/* processor features (e.g. for CPUID insn) */
|
||||
@ -726,8 +730,6 @@ typedef struct CPUX86State {
|
||||
int32_t exception_injected;
|
||||
int32_t interrupt_injected;
|
||||
uint8_t soft_interrupt;
|
||||
uint8_t nmi_injected;
|
||||
uint8_t nmi_pending;
|
||||
uint8_t has_error_code;
|
||||
uint32_t sipi_vector;
|
||||
uint32_t cpuid_kvm_features;
|
||||
@ -760,6 +762,7 @@ int cpu_x86_exec(CPUX86State *s);
|
||||
void cpu_x86_close(CPUX86State *s);
|
||||
void x86_cpu_list (FILE *f, fprintf_function cpu_fprintf, const char *optarg);
|
||||
void x86_cpudef_setup(void);
|
||||
int cpu_x86_support_mca_broadcast(CPUState *env);
|
||||
|
||||
int cpu_get_pic_interrupt(CPUX86State *s);
|
||||
/* 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);
|
||||
int cpu_x86_register (CPUX86State *env, const char *cpu_model);
|
||||
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 */
|
||||
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
|
||||
|
@ -103,9 +103,8 @@ typedef struct model_features_t {
|
||||
int check_cpuid = 0;
|
||||
int enforce_cpuid = 0;
|
||||
|
||||
static void host_cpuid(uint32_t function, uint32_t count,
|
||||
uint32_t *eax, uint32_t *ebx,
|
||||
uint32_t *ecx, uint32_t *edx)
|
||||
void host_cpuid(uint32_t function, uint32_t count,
|
||||
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
|
||||
{
|
||||
#if defined(CONFIG_KVM)
|
||||
uint32_t vec[4];
|
||||
|
@ -110,6 +110,32 @@ void cpu_x86_close(CPUX86State *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 */
|
||||
|
||||
@ -223,6 +249,9 @@ done:
|
||||
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,
|
||||
int flags)
|
||||
{
|
||||
@ -408,6 +437,24 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
|
||||
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... */
|
||||
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_cap = cenv->mcg_cap;
|
||||
unsigned bank_num = mcg_cap & 0xff;
|
||||
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
|
||||
* reporting is disabled
|
||||
@ -1076,6 +1114,45 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
|
||||
} else
|
||||
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 */
|
||||
|
||||
static void mce_init(CPUX86State *cenv)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,8 +15,11 @@
|
||||
#ifndef __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,
|
||||
uint64_t mcg_status, uint64_t addr, uint64_t misc,
|
||||
int abort_on_error);
|
||||
int flag);
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
|
||||
@ -56,7 +60,7 @@ static void kvm_kick_env(void *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
|
||||
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");
|
||||
ret = kvmppc_handle_halt(env);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -70,7 +70,11 @@
|
||||
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
|
||||
#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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user