Files
kvmtool/kvm-cpu.c
T
Matt Evans af7b086859 kvm tools: Split x86 arch-specific bits into x86/
Create a new arch-specific subdirectory to contain architecture-specific code
and includes.

The Makefile now adds various arch-specific objects based on detected
architecture.  That aside, this patch should only contain code moves.  These
include:

- x86-specific kvm_cpu setup, kernel loading, memory setup etc. now in
  x86/kvm{-cpu}.c
- BIOS now lives in x86/bios/
- ioport setup
- KVM extensions are asserted in arch-specific kvm.c now, so each architecture
  can manage its own dependencies.
- Various architecture-specific #defines are moved into $(ARCH)/include/kvm{-cpu}.h
  such as struct kvm_cpu, KVM_NR_CPUS, KVM_32BIT_GAP_SIZE.

Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
2015-06-01 16:39:49 +01:00

152 lines
3.0 KiB
C

#include "kvm/kvm-cpu.h"
#include "kvm/symbol.h"
#include "kvm/util.h"
#include "kvm/kvm.h"
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
extern struct kvm_cpu *kvm_cpus[KVM_NR_CPUS];
extern __thread struct kvm_cpu *current_kvm_cpu;
void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu)
{
struct kvm_guest_debug debug = {
.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP,
};
if (ioctl(vcpu->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0)
pr_warning("KVM_SET_GUEST_DEBUG failed");
}
void kvm_cpu__run(struct kvm_cpu *vcpu)
{
int err;
err = ioctl(vcpu->vcpu_fd, KVM_RUN, 0);
if (err && (errno != EINTR && errno != EAGAIN))
die_perror("KVM_RUN failed");
}
static void kvm_cpu_signal_handler(int signum)
{
if (signum == SIGKVMEXIT) {
if (current_kvm_cpu && current_kvm_cpu->is_running) {
current_kvm_cpu->is_running = false;
pthread_kill(pthread_self(), SIGKVMEXIT);
}
} else if (signum == SIGKVMPAUSE) {
current_kvm_cpu->paused = 1;
}
}
static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu)
{
if (cpu->ring) {
while (cpu->ring->first != cpu->ring->last) {
struct kvm_coalesced_mmio *m;
m = &cpu->ring->coalesced_mmio[cpu->ring->first];
kvm__emulate_mmio(cpu->kvm,
m->phys_addr,
m->data,
m->len,
1);
cpu->ring->first = (cpu->ring->first + 1) % KVM_COALESCED_MMIO_MAX;
}
}
}
void kvm_cpu__reboot(void)
{
int i;
for (i = 0; i < KVM_NR_CPUS; i++)
if (kvm_cpus[i])
pthread_kill(kvm_cpus[i]->thread, SIGKVMEXIT);
}
int kvm_cpu__start(struct kvm_cpu *cpu)
{
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
signal(SIGKVMEXIT, kvm_cpu_signal_handler);
signal(SIGKVMPAUSE, kvm_cpu_signal_handler);
kvm_cpu__reset_vcpu(cpu);
if (cpu->kvm->single_step)
kvm_cpu__enable_singlestep(cpu);
while (cpu->is_running) {
if (cpu->paused) {
kvm__notify_paused();
cpu->paused = 0;
}
kvm_cpu__run(cpu);
switch (cpu->kvm_run->exit_reason) {
case KVM_EXIT_UNKNOWN:
break;
case KVM_EXIT_DEBUG:
kvm_cpu__show_registers(cpu);
kvm_cpu__show_code(cpu);
break;
case KVM_EXIT_IO: {
bool ret;
ret = kvm__emulate_io(cpu->kvm,
cpu->kvm_run->io.port,
(u8 *)cpu->kvm_run +
cpu->kvm_run->io.data_offset,
cpu->kvm_run->io.direction,
cpu->kvm_run->io.size,
cpu->kvm_run->io.count);
if (!ret)
goto panic_kvm;
break;
}
case KVM_EXIT_MMIO: {
bool ret;
ret = kvm__emulate_mmio(cpu->kvm,
cpu->kvm_run->mmio.phys_addr,
cpu->kvm_run->mmio.data,
cpu->kvm_run->mmio.len,
cpu->kvm_run->mmio.is_write);
if (!ret)
goto panic_kvm;
break;
}
case KVM_EXIT_INTR:
if (cpu->is_running)
break;
goto exit_kvm;
case KVM_EXIT_SHUTDOWN:
goto exit_kvm;
default:
goto panic_kvm;
}
kvm_cpu__handle_coalesced_mmio(cpu);
}
exit_kvm:
return 0;
panic_kvm:
return 1;
}