]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Add APIs to allow pausing guests
authorSasha Levin <levinsasha928@gmail.com>
Mon, 30 May 2011 17:27:52 +0000 (20:27 +0300)
committerPekka Enberg <penberg@kernel.org>
Thu, 2 Jun 2011 08:37:50 +0000 (11:37 +0300)
Allow pausing and unpausing guests running on the host.
Pausing a guest means that none of the VCPU threads are running
KVM_RUN until they are unpaused.

The following API functions are added:
 void kvm__pause(void);
 void kvm__continue(void);
 void kvm__notify_paused(void);

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
tools/kvm/include/kvm/kvm-cpu.h
tools/kvm/include/kvm/kvm.h
tools/kvm/kvm-cpu.c
tools/kvm/kvm-run.c
tools/kvm/kvm.c

index b2b6fceea3ed75abbd84ccc0777dfd9ba44b183b..4d99246c674722637254d2f460c655e7f89e6def 100644 (file)
@@ -23,6 +23,7 @@ struct kvm_cpu {
        struct kvm_msrs         *msrs;          /* dynamically allocated */
 
        u8                      is_running;
+       u8                      paused;
 };
 
 struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id);
index 6a17362fb5525bcf4c3397ed2c08459730af42e8..d22a849322df35d65232d79cebc8074c86a16fdf 100644 (file)
@@ -12,6 +12,7 @@
 #define KVM_32BIT_GAP_START    ((1ULL << 32) - KVM_32BIT_GAP_SIZE)
 
 #define SIGKVMEXIT             (SIGRTMIN + 0)
+#define SIGKVMPAUSE            (SIGRTMIN + 1)
 
 struct kvm {
        int                     sys_fd;         /* For system ioctls(), i.e. /dev/kvm */
@@ -50,6 +51,9 @@ bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int s
 bool kvm__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write);
 bool kvm__register_mmio(u64 phys_addr, u64 phys_addr_len, void (*kvm_mmio_callback_fn)(u64 addr, u8 *data, u32 len, u8 is_write));
 bool kvm__deregister_mmio(u64 phys_addr);
+void kvm__pause(void);
+void kvm__continue(void);
+void kvm__notify_paused(void);
 
 /*
  * Debugging
index de0591f88d1a60eb590d610ffd5844c5905dac2d..be0528b64ec5f6021fb9dfc5cf4e7a5835addab9 100644 (file)
@@ -383,11 +383,15 @@ void kvm_cpu__run(struct kvm_cpu *vcpu)
                die_perror("KVM_RUN failed");
 }
 
-static void kvm_cpu_exit_handler(int signum)
+static void kvm_cpu_signal_handler(int signum)
 {
-       if (current_kvm_cpu->is_running) {
-               current_kvm_cpu->is_running = false;
-               pthread_kill(pthread_self(), SIGKVMEXIT);
+       if (signum == SIGKVMEXIT) {
+               if (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;
        }
 }
 
@@ -400,12 +404,18 @@ int kvm_cpu__start(struct kvm_cpu *cpu)
 
        pthread_sigmask(SIG_BLOCK, &sigset, NULL);
 
-       signal(SIGKVMEXIT, kvm_cpu_exit_handler);
+       signal(SIGKVMEXIT, kvm_cpu_signal_handler);
+       signal(SIGKVMPAUSE, kvm_cpu_signal_handler);
 
        kvm_cpu__setup_cpuid(cpu);
        kvm_cpu__reset_vcpu(cpu);
 
        for (;;) {
+               if (cpu->paused) {
+                       kvm__notify_paused();
+                       cpu->paused = 0;
+               }
+
                kvm_cpu__run(cpu);
 
                switch (cpu->kvm_run->exit_reason) {
index 48b8e700ae5ee4cedb800e606db2d84fc7b0bede..761ac0d3548dcaaf34f997177461f44c5e0aab4e 100644 (file)
@@ -47,8 +47,8 @@
 #define MIN_RAM_SIZE_MB                (64ULL)
 #define MIN_RAM_SIZE_BYTE      (MIN_RAM_SIZE_MB << MB_SHIFT)
 
-static struct kvm *kvm;
-static struct kvm_cpu *kvm_cpus[KVM_NR_CPUS];
+struct kvm *kvm;
+struct kvm_cpu *kvm_cpus[KVM_NR_CPUS];
 __thread struct kvm_cpu *current_kvm_cpu;
 
 static u64 ram_size;
index 1d756e0ebbe36f36867f91afa74f8aab73e25f42..54e3203df0babb44177c18f86aed249d918f0522 100644 (file)
@@ -6,6 +6,8 @@
 #include "kvm/interrupt.h"
 #include "kvm/mptable.h"
 #include "kvm/util.h"
+#include "kvm/mutex.h"
+#include "kvm/kvm-cpu.h"
 
 #include <linux/kvm.h>
 
@@ -25,6 +27,7 @@
 #include <stdio.h>
 #include <fcntl.h>
 #include <time.h>
+#include <sys/eventfd.h>
 
 #define DEFINE_KVM_EXIT_REASON(reason) [reason] = #reason
 
@@ -68,6 +71,11 @@ struct {
        { DEFINE_KVM_EXT(KVM_CAP_EXT_CPUID) },
 };
 
+extern struct kvm *kvm;
+extern struct kvm_cpu *kvm_cpus[KVM_NR_CPUS];
+static int pause_event;
+static DEFINE_MUTEX(pause_lock);
+
 static bool kvm__supports_extension(struct kvm *kvm, unsigned int extension)
 {
        int ret;
@@ -575,3 +583,49 @@ void kvm__dump_mem(struct kvm *kvm, unsigned long addr, unsigned long size)
                                  p[n + 4], p[n + 5], p[n + 6], p[n + 7]);
        }
 }
+
+void kvm__pause(void)
+{
+       int i, paused_vcpus = 0;
+
+       /* Check if the guest is running */
+       if (!kvm_cpus[0] || kvm_cpus[0]->thread == 0)
+               return;
+
+       mutex_lock(&pause_lock);
+
+       pause_event = eventfd(0, 0);
+       if (pause_event < 0)
+               die("Failed creating pause notification event");
+       for (i = 0; i < kvm->nrcpus; i++)
+               pthread_kill(kvm_cpus[i]->thread, SIGKVMPAUSE);
+
+       while (paused_vcpus < kvm->nrcpus) {
+               u64 cur_read;
+
+               if (read(pause_event, &cur_read, sizeof(cur_read)) < 0)
+                       die("Failed reading pause event");
+               paused_vcpus += cur_read;
+       }
+       close(pause_event);
+}
+
+void kvm__continue(void)
+{
+       /* Check if the guest is running */
+       if (!kvm_cpus[0] || kvm_cpus[0]->thread == 0)
+               return;
+
+       mutex_unlock(&pause_lock);
+}
+
+void kvm__notify_paused(void)
+{
+       u64 p = 1;
+
+       if (write(pause_event, &p, sizeof(p)) < 0)
+               die("Failed notifying of paused VCPU.");
+
+       mutex_lock(&pause_lock);
+       mutex_unlock(&pause_lock);
+}