diff --git a/hmp.c b/hmp.c index 43ae9ec61a..80aa5ab504 100644 --- a/hmp.c +++ b/hmp.c @@ -1220,7 +1220,10 @@ void hmp_cont(Monitor *mon, const QDict *qdict) void hmp_system_wakeup(Monitor *mon, const QDict *qdict) { - qmp_system_wakeup(NULL); + Error *err = NULL; + + qmp_system_wakeup(&err); + hmp_handle_error(mon, &err); } void hmp_nmi(Monitor *mon, const QDict *qdict) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index 52e18d7810..d6f0709691 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -514,7 +514,8 @@ static uint32_t acpi_pm_tmr_get(ACPIREGS *ar) static void acpi_pm_tmr_timer(void *opaque) { ACPIREGS *ar = opaque; - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER); + + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL); ar->tmr.update_sci(ar); } diff --git a/hw/char/serial.c b/hw/char/serial.c index 02463e3388..7c42a2abfc 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -611,7 +611,7 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size) SerialState *s = opaque; if (s->wakeup) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); } if(s->fcr & UART_FCR_FE) { int i; diff --git a/hw/input/ps2.c b/hw/input/ps2.c index eb33ee9b6f..d3161f1e7c 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -255,7 +255,7 @@ static void ps2_put_keycode(void *opaque, int keycode) PS2KbdState *s = opaque; trace_ps2_put_keycode(opaque, keycode); - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); if (s->translate) { if (keycode == 0xf0) { @@ -285,7 +285,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, return; } - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); assert(evt->type == INPUT_EVENT_KIND_KEY); qcode = qemu_input_key_value_to_qcode(key->key); @@ -748,7 +748,7 @@ static void ps2_mouse_sync(DeviceState *dev) } if (s->mouse_buttons) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); } if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { /* if not remote, send event. Multiple events are sent if diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index e4e4de8b8a..69483152c3 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -455,7 +455,7 @@ static void rtc_update_timer(void *opaque) if (qemu_clock_get_ns(rtc_clock) >= s->next_alarm_time) { irqs |= REG_C_AF; if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC, NULL); } } diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index d9cabb34bd..c8efdeb376 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -54,7 +54,8 @@ void qemu_exit_preconfig_request(void); void qemu_system_reset_request(ShutdownCause reason); void qemu_system_suspend_request(void); void qemu_register_suspend_notifier(Notifier *notifier); -void qemu_system_wakeup_request(WakeupReason reason); +bool qemu_wakeup_suspend_enabled(void); +void qemu_system_wakeup_request(WakeupReason reason, Error **errp); void qemu_system_wakeup_enable(WakeupReason reason, bool enabled); void qemu_register_wakeup_notifier(Notifier *notifier); void qemu_register_wakeup_support(void); diff --git a/migration/migration.c b/migration/migration.c index 49ffb9997a..ffc4d9e556 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2408,7 +2408,7 @@ static int postcopy_start(MigrationState *ms) qemu_mutex_lock_iothread(); trace_postcopy_start_set_run(); - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); global_state_store(); ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); if (ret < 0) { @@ -2612,7 +2612,7 @@ static void migration_completion(MigrationState *s) if (s->state == MIGRATION_STATUS_ACTIVE) { qemu_mutex_lock_iothread(); s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); s->vm_was_running = runstate_is_running(); ret = global_state_store(); diff --git a/qapi/misc.json b/qapi/misc.json index c4696ef150..24d20a880a 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -1239,12 +1239,18 @@ ## # @system_wakeup: # -# Wakeup guest from suspend. Does nothing in case the guest isn't suspended. +# Wake up guest from suspend. If the guest has wake-up from suspend +# support enabled (wakeup-suspend-support flag from +# query-current-machine), wake-up guest from suspend if the guest is +# in SUSPENDED state. Return an error otherwise. # # Since: 1.1 # # Returns: nothing. # +# Note: prior to 4.0, this command does nothing in case the guest +# isn't suspended. +# # Example: # # -> { "execute": "system_wakeup" } diff --git a/qmp.c b/qmp.c index 82298f6cb0..4c819dd8cf 100644 --- a/qmp.c +++ b/qmp.c @@ -183,7 +183,13 @@ void qmp_cont(Error **errp) void qmp_system_wakeup(Error **errp) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + if (!qemu_wakeup_suspend_enabled()) { + error_setg(errp, + "wake-up from suspend is not supported by this guest"); + return; + } + + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp); } ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp) diff --git a/vl.c b/vl.c index 2bd869580f..9dbba36ad3 100644 --- a/vl.c +++ b/vl.c @@ -1752,11 +1752,13 @@ void qemu_register_suspend_notifier(Notifier *notifier) notifier_list_add(&suspend_notifiers, notifier); } -void qemu_system_wakeup_request(WakeupReason reason) +void qemu_system_wakeup_request(WakeupReason reason, Error **errp) { trace_system_wakeup_request(reason); if (!runstate_check(RUN_STATE_SUSPENDED)) { + error_setg(errp, + "Unable to wake up: guest is not in suspended state"); return; } if (!(wakeup_reason_mask & (1 << reason))) { @@ -1786,7 +1788,7 @@ void qemu_register_wakeup_support(void) wakeup_suspend_enabled = true; } -static bool qemu_wakeup_suspend_enabled(void) +bool qemu_wakeup_suspend_enabled(void) { return wakeup_suspend_enabled; }