@@ -3,11 +3,16 @@
#include <linux/kvm.h> /* for struct kvm_regs */
+#include <pthread.h>
#include <stdint.h>
struct kvm;
struct kvm_cpu {
+ pthread_t thread; /* VCPU thread */
+
+ unsigned long cpu_id;
+
struct kvm *kvm; /* parent KVM */
int vcpu_fd; /* For VCPU ioctls() */
struct kvm_run *kvm_run;
@@ -19,7 +24,7 @@ struct kvm_cpu {
struct kvm_msrs *msrs; /* dynamically allocated */
};
-struct kvm_cpu *kvm_cpu__init(struct kvm *kvm);
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id);
void kvm_cpu__delete(struct kvm_cpu *self);
void kvm_cpu__reset_vcpu(struct kvm_cpu *self);
void kvm_cpu__setup_cpuid(struct kvm_cpu *self);
@@ -1,12 +1,11 @@
#include "kvm/kvm-cpu.h"
-#include "kvm/virtio-console.h"
-#include "kvm/8250-serial.h"
#include "kvm/util.h"
#include "kvm/kvm.h"
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
@@ -61,7 +60,7 @@ void kvm_cpu__delete(struct kvm_cpu *self)
free(self);
}
-struct kvm_cpu *kvm_cpu__init(struct kvm *kvm)
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id)
{
struct kvm_cpu *self;
int mmap_size;
@@ -70,7 +69,9 @@ struct kvm_cpu *kvm_cpu__init(struct kvm *kvm)
if (!self)
return NULL;
- self->vcpu_fd = ioctl(self->kvm->vm_fd, KVM_CREATE_VCPU, 0);
+ self->cpu_id = cpu_id;
+
+ self->vcpu_fd = ioctl(self->kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
if (self->vcpu_fd < 0)
die_perror("KVM_CREATE_VCPU ioctl");
@@ -373,6 +374,13 @@ void kvm_cpu__run(struct kvm_cpu *self)
int kvm_cpu__start(struct kvm_cpu *cpu)
{
+ sigset_t sigset;
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+
+ pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+
kvm_cpu__setup_cpuid(cpu);
kvm_cpu__reset_vcpu(cpu);
@@ -412,11 +420,8 @@ int kvm_cpu__start(struct kvm_cpu *cpu)
goto panic_kvm;
break;
}
- case KVM_EXIT_INTR: {
- serial8250__inject_interrupt(cpu->kvm);
- virtio_console__inject_interrupt(cpu->kvm);
+ case KVM_EXIT_INTR:
break;
- }
case KVM_EXIT_SHUTDOWN:
goto exit_kvm;
default:
@@ -29,8 +29,11 @@
#define MIN_RAM_SIZE_MB (64ULL)
#define MIN_RAM_SIZE_BYTE (MIN_RAM_SIZE_MB << MB_SHIFT)
+#define NUM_KVM_CPUS 1
+
static struct kvm *kvm;
-static struct kvm_cpu *cpu;
+static struct kvm_cpu *cpus[NUM_KVM_CPUS];
+static __thread struct kvm_cpu *current_cpu;
static void handle_sigint(int sig)
{
@@ -39,16 +42,22 @@ static void handle_sigint(int sig)
static void handle_sigquit(int sig)
{
- kvm_cpu__show_registers(cpu);
- kvm_cpu__show_code(cpu);
- kvm_cpu__show_page_tables(cpu);
+ kvm_cpu__show_registers(current_cpu);
+ kvm_cpu__show_code(current_cpu);
+ kvm_cpu__show_page_tables(current_cpu);
- kvm_cpu__delete(cpu);
+ kvm_cpu__delete(current_cpu);
kvm__delete(kvm);
exit(1);
}
+static void handle_sigalrm(int sig)
+{
+ serial8250__inject_interrupt(kvm);
+ virtio_console__inject_interrupt(kvm);
+}
+
static u64 ram_size = MIN_RAM_SIZE_MB;
static const char *kernel_cmdline;
static const char *kernel_filename;
@@ -84,10 +93,41 @@ static const struct option options[] = {
OPT_END()
};
+static void *kvm_cpu_thread(void *arg)
+{
+ current_cpu = arg;
+
+ if (kvm_cpu__start(current_cpu))
+ goto panic_kvm;
+
+ kvm_cpu__delete(current_cpu);
+
+ return (void *) (intptr_t) 0;
+
+panic_kvm:
+ fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
+ current_cpu->kvm_run->exit_reason,
+ kvm_exit_reasons[current_cpu->kvm_run->exit_reason]);
+ if (current_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
+ fprintf(stderr, "KVM exit code: 0x%Lu\n",
+ current_cpu->kvm_run->hw.hardware_exit_reason);
+ disk_image__close(kvm->disk_image);
+ kvm_cpu__show_registers(current_cpu);
+ kvm_cpu__show_code(current_cpu);
+ kvm_cpu__show_page_tables(current_cpu);
+
+ kvm_cpu__delete(current_cpu);
+
+ return (void *) (intptr_t) 1;
+}
+
int kvm_cmd_run(int argc, const char **argv, const char *prefix)
{
static char real_cmdline[2048];
+ int exit_code = 0;
+ int i;
+ signal(SIGALRM, handle_sigalrm);
signal(SIGQUIT, handle_sigquit);
signal(SIGINT, handle_sigint);
@@ -132,10 +172,6 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
kvm = kvm__init(kvm_dev, ram_size);
- cpu = kvm_cpu__init(kvm);
- if (!cpu)
- die("unable to initialize KVM VCPU");
-
if (image_filename) {
kvm->disk_image = disk_image__open(image_filename);
if (!kvm->disk_image)
@@ -169,32 +205,33 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
kvm__start_timer(kvm);
- if (single_step)
- kvm_cpu__enable_singlestep(cpu);
+ for (i = 0; i < NUM_KVM_CPUS; i++) {
+ cpus[i] = kvm_cpu__init(kvm, i);
+ if (!cpus[i])
+ die("unable to initialize KVM VCPU");
- if (kvm_cpu__start(cpu))
- goto panic_kvm;
+ if (single_step)
+ kvm_cpu__enable_singlestep(cpus[i]);
- disk_image__close(kvm->disk_image);
- kvm__delete(kvm);
+ if (pthread_create(&cpus[i]->thread, NULL, kvm_cpu_thread, cpus[i]) != 0)
+ die("unable to create KVM VCPU thread");
+ }
- printf("\n # KVM session ended normally.\n");
+ for (i = 0; i < NUM_KVM_CPUS; i++) {
+ void *ret;
- return 0;
+ if (pthread_join(cpus[i]->thread, &ret) != 0)
+ die("pthread_join");
+
+ if (ret != NULL)
+ exit_code = 1;
+ }
-panic_kvm:
- fprintf(stderr, "KVM exit reason: %" PRIu32 " (\"%s\")\n",
- cpu->kvm_run->exit_reason,
- kvm_exit_reasons[cpu->kvm_run->exit_reason]);
- if (cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
- fprintf(stderr, "KVM exit code: 0x%Lu\n",
- cpu->kvm_run->hw.hardware_exit_reason);
disk_image__close(kvm->disk_image);
- kvm_cpu__show_registers(cpu);
- kvm_cpu__show_code(cpu);
- kvm_cpu__show_page_tables(cpu);
- kvm_cpu__delete(cpu);
kvm__delete(kvm);
- return 1;
+ if (!exit_code)
+ printf("\n # KVM session ended normally.\n");
+
+ return exit_code;
}
@@ -412,10 +412,6 @@ void kvm__setup_bios(struct kvm *self)
#define TIMER_INTERVAL_NS 1000000 /* 1 msec */
-static void alarm_handler(int sig)
-{
-}
-
/*
* This function sets up a timer that's used to inject interrupts from the
* userspace hypervisor into the guest at periodical intervals. Please note
@@ -424,15 +420,8 @@ static void alarm_handler(int sig)
void kvm__start_timer(struct kvm *self)
{
struct itimerspec its;
- struct sigaction sa;
struct sigevent sev;
- sigfillset(&sa.sa_mask);
- sa.sa_flags = 0;
- sa.sa_handler = alarm_handler;
-
- sigaction(SIGALRM, &sa, NULL);
-
memset(&sev, 0, sizeof(struct sigevent));
sev.sigev_value.sival_int = 0;
sev.sigev_notify = SIGEV_SIGNAL;
This patch makes the core hypervisor to use per-VCPU threads for execution. NOTE: We only start one thread right now because we're unable to let the guest kernel know about more cores at the moment. Cc: Asias He <asias.hejun@gmail.com> Cc: Cyrill Gorcunov <gorcunov@gmail.com> Tested-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Pekka Enberg <penberg@kernel.org> --- tools/kvm/include/kvm/kvm-cpu.h | 7 +++- tools/kvm/kvm-cpu.c | 21 +++++--- tools/kvm/kvm-run.c | 95 +++++++++++++++++++++++++++------------ tools/kvm/kvm.c | 11 ----- 4 files changed, 85 insertions(+), 49 deletions(-)