From 8990e1d2fbca42578b7257bfdd73b34fdad0eee6 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 7 Mar 2012 08:00:16 +0100 Subject: [PATCH 02/12] suspend: add infrastructure RH-Author: Gerd Hoffmann Message-id: <1331107226-21901-3-git-send-email-kraxel@redhat.com> Patchwork-id: 38354 O-Subject: [RHEL-6.3 qemu-kvm PATCH v3 02/12] suspend: add infrastructure Bugzilla: 766303 RH-Acked-by: Paolo Bonzini RH-Acked-by: Gleb Natapov RH-Acked-by: Alex Williamson This patch adds some infrastructure to handle suspend and resume to qemu. First there are two functions to switch state and second there is a suspend notifier: * qemu_system_suspend_request is supposed to be called when the guest asks for being be suspended, for example via ACPI. * qemu_system_wakeup_request is supposed to be called on events which should wake up the guest. * qemu_register_suspend_notifier can be used to register a notifier which will be called when the guest is suspended. Machine types and device models can hook in there to modify state if needed. * qemu_register_wakeup_notifier can be used to register a notifier which will be called when the guest is woken up. Machine types and device models can hook in there to modify state if needed. * qemu_system_wakeup_enable can be used to enable/disable wakeup events. Signed-off-by: Gerd Hoffmann [ rhel6: hook into both main_loop and kvm_main_loop ] upstream: 95b363b5c643d8ad81c5377726e753b84c909037 --- qemu-kvm.c | 4 ++- sysemu.h | 11 +++++++++ vl.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletions(-) Signed-off-by: Michal Novotny --- qemu-kvm.c | 4 ++- sysemu.h | 11 +++++++++ vl.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletions(-) diff --git a/qemu-kvm.c b/qemu-kvm.c index 6edb5f8..bd3b4a5 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -2242,7 +2242,9 @@ int kvm_main_loop(void) while (1) { main_loop_wait(1000); - if (qemu_shutdown_requested()) { + if (qemu_suspend_requested()) { + qemu_system_suspend(); + } else if (qemu_shutdown_requested()) { qemu_kill_report(); monitor_protocol_event(QEVENT_SHUTDOWN, NULL); if (qemu_no_shutdown()) { diff --git a/sysemu.h b/sysemu.h index 45fd915..e968915 100644 --- a/sysemu.h +++ b/sysemu.h @@ -67,17 +67,28 @@ int64_t cpu_get_ticks(void); void cpu_enable_ticks(void); void cpu_disable_ticks(void); +typedef enum WakeupReason { + QEMU_WAKEUP_REASON_OTHER = 0, +} WakeupReason; + void qemu_system_reset_request(void); +void qemu_system_suspend_request(void); +void qemu_register_suspend_notifier(Notifier *notifier); +void qemu_system_wakeup_request(WakeupReason reason); +void qemu_system_wakeup_enable(WakeupReason reason, bool enabled); +void qemu_register_wakeup_notifier(Notifier *notifier); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); int qemu_no_shutdown(void); int qemu_shutdown_requested(void); int qemu_reset_requested(void); +int qemu_suspend_requested(void); int qemu_powerdown_requested(void); void qemu_system_killed(int signal, pid_t pid); void qemu_kill_report(void); extern qemu_irq qemu_system_powerdown; void qemu_system_reset(void); +void qemu_system_suspend(void); void qemu_add_machine_init_done_notifier(Notifier *notify); void qemu_add_exit_notifier(Notifier *notify); diff --git a/vl.c b/vl.c index 38fb0a5..51cff6e 100644 --- a/vl.c +++ b/vl.c @@ -3283,6 +3283,13 @@ static int shutdown_requested, shutdown_signal = -1; static pid_t shutdown_pid; static int powerdown_requested; static int debug_requested; +static int suspend_requested; +static bool is_suspended; +static NotifierList suspend_notifiers = + NOTIFIER_LIST_INITIALIZER(suspend_notifiers); +static NotifierList wakeup_notifiers = + NOTIFIER_LIST_INITIALIZER(wakeup_notifiers); +static uint32_t wakeup_reason_mask = ~0; static int vmstop_requested = RUN_STATE_NO_STATE; int qemu_no_shutdown(void) @@ -3321,6 +3328,13 @@ int qemu_reset_requested(void) return r; } +int qemu_suspend_requested(void) +{ + int r = suspend_requested; + suspend_requested = 0; + return r; +} + int qemu_powerdown_requested(void) { int r = powerdown_requested; @@ -3400,6 +3414,59 @@ void qemu_system_reset_request(void) qemu_notify_event(); } +void qemu_system_suspend(void) +{ + pause_all_vcpus(); + notifier_list_notify(&suspend_notifiers, NULL); + is_suspended = true; +} + +void qemu_system_suspend_request(void) +{ + if (is_suspended) { + return; + } + suspend_requested = 1; + if (cpu_single_env) { + cpu_single_env->stopped = 1; + cpu_exit(cpu_single_env); + } + qemu_notify_event(); +} + +void qemu_register_suspend_notifier(Notifier *notifier) +{ + notifier_list_add(&suspend_notifiers, notifier); +} + +void qemu_system_wakeup_request(WakeupReason reason) +{ + if (!is_suspended) { + return; + } + if (!(wakeup_reason_mask & (1 << reason))) { + return; + } + notifier_list_notify(&wakeup_notifiers, &reason); + reset_requested = 1; + qemu_notify_event(); + is_suspended = false; +} + +void qemu_system_wakeup_enable(WakeupReason reason, bool enabled) +{ + if (enabled) { + wakeup_reason_mask |= (1 << reason); + } else { + wakeup_reason_mask &= ~(1 << reason); + } +} + +void qemu_register_wakeup_notifier(Notifier *notifier) +{ + notifier_list_add(&wakeup_notifiers, notifier); +} + void qemu_system_killed(int signal, pid_t pid) { shutdown_signal = signal; @@ -4218,6 +4285,8 @@ static int vm_can_run(void) return 0; if (debug_requested) return 0; + if (suspend_requested) + return 0; return 1; } @@ -4258,6 +4327,9 @@ static void main_loop(void) if (qemu_debug_requested()) { vm_stop(RUN_STATE_DEBUG); } + if (qemu_suspend_requested()) { + qemu_system_suspend(); + } if (qemu_shutdown_requested()) { monitor_protocol_event(QEVENT_SHUTDOWN, NULL); if (no_shutdown) { -- 1.7.7.6