aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Ellerman <mpe@ellerman.id.au>2016-04-03 20:37:59 +1000
committerWill Deacon <will.deacon@arm.com>2016-04-11 11:59:57 +0100
commite300a5eef43ed25dc415b47d67cdf8d8987a9bf8 (patch)
tree15758cd4717875a68c6b2d14748e87d7124f394a
parent62a15bd19897dd7cbcc35e74037bcba9dec39d02 (diff)
downloadkvmtool-e300a5eef43ed25dc415b47d67cdf8d8987a9bf8.tar.gz
Add basic infrastructure to run tasks on vCPUs
This patch adds kvm_cpu__run_on_all_cpus() to run a task on each vCPU. This infrastructure uses signals to signal the vCPU to allow a task to be added to each vCPU's task. The vCPU executes any pending tasks in the cpu run loop Signed-off-by: Balbir Singh <bsingharora@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arm/include/arm-common/kvm-cpu-arch.h1
-rw-r--r--include/kvm/kvm-cpu.h6
-rw-r--r--include/kvm/kvm.h1
-rw-r--r--kvm-cpu.c73
-rw-r--r--mips/include/kvm/kvm-cpu-arch.h1
-rw-r--r--powerpc/include/kvm/kvm-cpu-arch.h1
-rw-r--r--x86/include/kvm/kvm-cpu-arch.h1
7 files changed, 84 insertions, 0 deletions
diff --git a/arm/include/arm-common/kvm-cpu-arch.h b/arm/include/arm-common/kvm-cpu-arch.h
index 329979a0..8a6a6e7c 100644
--- a/arm/include/arm-common/kvm-cpu-arch.h
+++ b/arm/include/arm-common/kvm-cpu-arch.h
@@ -17,6 +17,7 @@ struct kvm_cpu {
struct kvm *kvm;
int vcpu_fd;
struct kvm_run *kvm_run;
+ struct kvm_cpu_task *task;
u8 is_running;
u8 paused;
diff --git a/include/kvm/kvm-cpu.h b/include/kvm/kvm-cpu.h
index c4c9cca4..0f16f8d6 100644
--- a/include/kvm/kvm-cpu.h
+++ b/include/kvm/kvm-cpu.h
@@ -4,6 +4,11 @@
#include "kvm/kvm-cpu-arch.h"
#include <stdbool.h>
+struct kvm_cpu_task {
+ void (*func)(struct kvm_cpu *vcpu, void *data);
+ void *data;
+};
+
int kvm_cpu__init(struct kvm *kvm);
int kvm_cpu__exit(struct kvm *kvm);
struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id);
@@ -22,5 +27,6 @@ void kvm_cpu__show_code(struct kvm_cpu *vcpu);
void kvm_cpu__show_registers(struct kvm_cpu *vcpu);
void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu);
void kvm_cpu__arch_nmi(struct kvm_cpu *cpu);
+void kvm_cpu__run_on_all_cpus(struct kvm *kvm, struct kvm_cpu_task *task);
#endif /* KVM__KVM_CPU_H */
diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
index 890ddc4a..4a76ec2f 100644
--- a/include/kvm/kvm.h
+++ b/include/kvm/kvm.h
@@ -15,6 +15,7 @@
#define SIGKVMEXIT (SIGRTMIN + 0)
#define SIGKVMPAUSE (SIGRTMIN + 1)
+#define SIGKVMTASK (SIGRTMIN + 2)
#define KVM_PID_FILE_PATH "/.lkvm/"
#define HOME_DIR getenv("HOME")
diff --git a/kvm-cpu.c b/kvm-cpu.c
index 3e2037e3..2af459b3 100644
--- a/kvm-cpu.c
+++ b/kvm-cpu.c
@@ -4,9 +4,12 @@
#include "kvm/util.h"
#include "kvm/kvm.h"
#include "kvm/virtio.h"
+#include "kvm/mutex.h"
+#include "kvm/barrier.h"
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <sys/eventfd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@@ -50,6 +53,8 @@ static void kvm_cpu_signal_handler(int signum)
} else if (signum == SIGKVMPAUSE) {
current_kvm_cpu->paused = 1;
}
+
+ /* For SIGKVMTASK cpu->task is already set */
}
static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu)
@@ -68,6 +73,62 @@ static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu)
}
}
+static DEFINE_MUTEX(task_lock);
+static int task_eventfd;
+
+static void kvm_cpu__run_task(struct kvm_cpu *cpu)
+{
+ u64 inc = 1;
+
+ pr_debug("Running task %p on cpu %lu", cpu->task, cpu->cpu_id);
+
+ /* Make sure we see the store to cpu->task */
+ rmb();
+ cpu->task->func(cpu, cpu->task->data);
+
+ /* Clear task before we signal completion */
+ cpu->task = NULL;
+ wmb();
+
+ if (write(task_eventfd, &inc, sizeof(inc)) < 0)
+ die("Failed notifying of completed task.");
+}
+
+void kvm_cpu__run_on_all_cpus(struct kvm *kvm, struct kvm_cpu_task *task)
+{
+ int i, done = 0;
+
+ pr_debug("Running task %p on all cpus", task);
+
+ mutex_lock(&task_lock);
+
+ for (i = 0; i < kvm->nrcpus; i++) {
+ if (kvm->cpus[i]->task) {
+ /* Should never happen */
+ die("CPU %d already has a task pending!", i);
+ }
+
+ kvm->cpus[i]->task = task;
+ wmb();
+
+ if (kvm->cpus[i] == current_kvm_cpu)
+ kvm_cpu__run_task(current_kvm_cpu);
+ else
+ pthread_kill(kvm->cpus[i]->thread, SIGKVMTASK);
+ }
+
+ while (done < kvm->nrcpus) {
+ u64 count;
+
+ if (read(task_eventfd, &count, sizeof(count)) < 0)
+ die("Failed reading task eventfd");
+
+ done += count;
+ }
+
+ mutex_unlock(&task_lock);
+}
+
int kvm_cpu__start(struct kvm_cpu *cpu)
{
sigset_t sigset;
@@ -79,6 +140,7 @@ int kvm_cpu__start(struct kvm_cpu *cpu)
signal(SIGKVMEXIT, kvm_cpu_signal_handler);
signal(SIGKVMPAUSE, kvm_cpu_signal_handler);
+ signal(SIGKVMTASK, kvm_cpu_signal_handler);
kvm_cpu__reset_vcpu(cpu);
@@ -96,6 +158,9 @@ int kvm_cpu__start(struct kvm_cpu *cpu)
cpu->needs_nmi = 0;
}
+ if (cpu->task)
+ kvm_cpu__run_task(cpu);
+
kvm_cpu__run(cpu);
switch (cpu->kvm_run->exit_reason) {
@@ -202,6 +267,12 @@ int kvm_cpu__init(struct kvm *kvm)
kvm->nrcpus = kvm->cfg.nrcpus;
+ task_eventfd = eventfd(0, 0);
+ if (task_eventfd < 0) {
+ pr_warning("Couldn't create task_eventfd");
+ return task_eventfd;
+ }
+
/* Alloc one pointer too many, so array ends up 0-terminated */
kvm->cpus = calloc(kvm->nrcpus + 1, sizeof(void *));
if (!kvm->cpus) {
@@ -249,6 +320,8 @@ int kvm_cpu__exit(struct kvm *kvm)
kvm->nrcpus = 0;
+ close(task_eventfd);
+
return r;
}
core_exit(kvm_cpu__exit);
diff --git a/mips/include/kvm/kvm-cpu-arch.h b/mips/include/kvm/kvm-cpu-arch.h
index 3db7f2b8..45e69f65 100644
--- a/mips/include/kvm/kvm-cpu-arch.h
+++ b/mips/include/kvm/kvm-cpu-arch.h
@@ -15,6 +15,7 @@ struct kvm_cpu {
struct kvm *kvm; /* parent KVM */
int vcpu_fd; /* For VCPU ioctls() */
struct kvm_run *kvm_run;
+ struct kvm_cpu_task *task;
struct kvm_regs regs;
diff --git a/powerpc/include/kvm/kvm-cpu-arch.h b/powerpc/include/kvm/kvm-cpu-arch.h
index 01eafdf0..f2bfbb5b 100644
--- a/powerpc/include/kvm/kvm-cpu-arch.h
+++ b/powerpc/include/kvm/kvm-cpu-arch.h
@@ -48,6 +48,7 @@ struct kvm_cpu {
struct kvm *kvm; /* parent KVM */
int vcpu_fd; /* For VCPU ioctls() */
struct kvm_run *kvm_run;
+ struct kvm_cpu_task *task;
struct kvm_regs regs;
struct kvm_sregs sregs;
diff --git a/x86/include/kvm/kvm-cpu-arch.h b/x86/include/kvm/kvm-cpu-arch.h
index 89c80595..05e5bb6c 100644
--- a/x86/include/kvm/kvm-cpu-arch.h
+++ b/x86/include/kvm/kvm-cpu-arch.h
@@ -18,6 +18,7 @@ struct kvm_cpu {
struct kvm *kvm; /* parent KVM */
int vcpu_fd; /* For VCPU ioctls() */
struct kvm_run *kvm_run;
+ struct kvm_cpu_task *task;
struct kvm_regs regs;
struct kvm_sregs sregs;