diff options
author | Michael Ellerman <mpe@ellerman.id.au> | 2016-04-03 20:37:59 +1000 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2016-04-11 11:59:57 +0100 |
commit | e300a5eef43ed25dc415b47d67cdf8d8987a9bf8 (patch) | |
tree | 15758cd4717875a68c6b2d14748e87d7124f394a | |
parent | 62a15bd19897dd7cbcc35e74037bcba9dec39d02 (diff) | |
download | kvmtool-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.h | 1 | ||||
-rw-r--r-- | include/kvm/kvm-cpu.h | 6 | ||||
-rw-r--r-- | include/kvm/kvm.h | 1 | ||||
-rw-r--r-- | kvm-cpu.c | 73 | ||||
-rw-r--r-- | mips/include/kvm/kvm-cpu-arch.h | 1 | ||||
-rw-r--r-- | powerpc/include/kvm/kvm-cpu-arch.h | 1 | ||||
-rw-r--r-- | x86/include/kvm/kvm-cpu-arch.h | 1 |
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") @@ -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; |