xref: /qemu/hw/watchdog/watchdog.c (revision e688df6bc4549f28534cdb001f168b8caae55b0c)
19dd986ccSRichard W.M. Jones /*
29dd986ccSRichard W.M. Jones  * Virtual hardware watchdog.
39dd986ccSRichard W.M. Jones  *
49dd986ccSRichard W.M. Jones  * Copyright (C) 2009 Red Hat Inc.
59dd986ccSRichard W.M. Jones  *
69dd986ccSRichard W.M. Jones  * This program is free software; you can redistribute it and/or
79dd986ccSRichard W.M. Jones  * modify it under the terms of the GNU General Public License
89dd986ccSRichard W.M. Jones  * as published by the Free Software Foundation; either version 2
99dd986ccSRichard W.M. Jones  * of the License, or (at your option) any later version.
109dd986ccSRichard W.M. Jones  *
119dd986ccSRichard W.M. Jones  * This program is distributed in the hope that it will be useful,
129dd986ccSRichard W.M. Jones  * but WITHOUT ANY WARRANTY; without even the implied warranty of
139dd986ccSRichard W.M. Jones  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149dd986ccSRichard W.M. Jones  * GNU General Public License for more details.
159dd986ccSRichard W.M. Jones  *
169dd986ccSRichard W.M. Jones  * You should have received a copy of the GNU General Public License
178167ee88SBlue Swirl  * along with this program; if not, see <http://www.gnu.org/licenses/>.
189dd986ccSRichard W.M. Jones  *
199dd986ccSRichard W.M. Jones  * By Richard W.M. Jones (rjones@redhat.com).
209dd986ccSRichard W.M. Jones  */
219dd986ccSRichard W.M. Jones 
220430891cSPeter Maydell #include "qemu/osdep.h"
231de7afc9SPaolo Bonzini #include "qemu/option.h"
241de7afc9SPaolo Bonzini #include "qemu/config-file.h"
251de7afc9SPaolo Bonzini #include "qemu/queue.h"
26*e688df6bSMarkus Armbruster #include "qapi/error.h"
277b1b5d19SPaolo Bonzini #include "qapi/qmp/types.h"
289c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
290d09e41aSPaolo Bonzini #include "sysemu/watchdog.h"
3099eaf09cSWenchao Xia #include "qapi-event.h"
31795dc6e4SMao Chuan Li #include "hw/nmi.h"
32f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
33f0df84c6SMichal Privoznik #include "qmp-commands.h"
349dd986ccSRichard W.M. Jones 
354c7f4426SMichal Privoznik static WatchdogAction watchdog_action = WATCHDOG_ACTION_RESET;
3672cf2d4fSBlue Swirl static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
379dd986ccSRichard W.M. Jones 
389dd986ccSRichard W.M. Jones void watchdog_add_model(WatchdogTimerModel *model)
399dd986ccSRichard W.M. Jones {
4072cf2d4fSBlue Swirl     QLIST_INSERT_HEAD(&watchdog_list, model, entry);
419dd986ccSRichard W.M. Jones }
429dd986ccSRichard W.M. Jones 
439dd986ccSRichard W.M. Jones /* Returns:
449dd986ccSRichard W.M. Jones  *   0 = continue
459dd986ccSRichard W.M. Jones  *   1 = exit program with error
469dd986ccSRichard W.M. Jones  *   2 = exit program without error
479dd986ccSRichard W.M. Jones  */
489dd986ccSRichard W.M. Jones int select_watchdog(const char *p)
499dd986ccSRichard W.M. Jones {
509dd986ccSRichard W.M. Jones     WatchdogTimerModel *model;
5109aaa160SMarkus Armbruster     QemuOpts *opts;
529dd986ccSRichard W.M. Jones 
539dd986ccSRichard W.M. Jones     /* -watchdog ? lists available devices and exits cleanly. */
54c8057f95SPeter Maydell     if (is_help_option(p)) {
5572cf2d4fSBlue Swirl         QLIST_FOREACH(model, &watchdog_list, entry) {
569dd986ccSRichard W.M. Jones             fprintf(stderr, "\t%s\t%s\n",
579dd986ccSRichard W.M. Jones                      model->wdt_name, model->wdt_description);
589dd986ccSRichard W.M. Jones         }
599dd986ccSRichard W.M. Jones         return 2;
609dd986ccSRichard W.M. Jones     }
619dd986ccSRichard W.M. Jones 
6272cf2d4fSBlue Swirl     QLIST_FOREACH(model, &watchdog_list, entry) {
639dd986ccSRichard W.M. Jones         if (strcasecmp(model->wdt_name, p) == 0) {
6409aaa160SMarkus Armbruster             /* add the device */
6587ea75d5SPeter Crosthwaite             opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
6687ea75d5SPeter Crosthwaite                                     &error_abort);
67f43e47dbSMarkus Armbruster             qemu_opt_set(opts, "driver", p, &error_abort);
689dd986ccSRichard W.M. Jones             return 0;
699dd986ccSRichard W.M. Jones         }
709dd986ccSRichard W.M. Jones     }
719dd986ccSRichard W.M. Jones 
729dd986ccSRichard W.M. Jones     fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
7372cf2d4fSBlue Swirl     QLIST_FOREACH(model, &watchdog_list, entry) {
749dd986ccSRichard W.M. Jones         fprintf(stderr, "\t%s\t%s\n",
759dd986ccSRichard W.M. Jones                  model->wdt_name, model->wdt_description);
769dd986ccSRichard W.M. Jones     }
779dd986ccSRichard W.M. Jones     return 1;
789dd986ccSRichard W.M. Jones }
799dd986ccSRichard W.M. Jones 
809dd986ccSRichard W.M. Jones int select_watchdog_action(const char *p)
819dd986ccSRichard W.M. Jones {
824c7f4426SMichal Privoznik     int action;
834c7f4426SMichal Privoznik     char *qapi_value;
849dd986ccSRichard W.M. Jones 
854c7f4426SMichal Privoznik     qapi_value = g_ascii_strdown(p, -1);
864c7f4426SMichal Privoznik     action = qapi_enum_parse(&WatchdogAction_lookup, qapi_value, -1, NULL);
874c7f4426SMichal Privoznik     g_free(qapi_value);
884c7f4426SMichal Privoznik     if (action < 0)
894c7f4426SMichal Privoznik         return -1;
90f0df84c6SMichal Privoznik     qmp_watchdog_set_action(action, &error_abort);
919dd986ccSRichard W.M. Jones     return 0;
929dd986ccSRichard W.M. Jones }
939dd986ccSRichard W.M. Jones 
944c7f4426SMichal Privoznik WatchdogAction get_watchdog_action(void)
950d035b6cSBo Tu {
960d035b6cSBo Tu     return watchdog_action;
970d035b6cSBo Tu }
980d035b6cSBo Tu 
999dd986ccSRichard W.M. Jones /* This actually performs the "action" once a watchdog has expired,
1009dd986ccSRichard W.M. Jones  * ie. reboot, shutdown, exit, etc.
1019dd986ccSRichard W.M. Jones  */
1029dd986ccSRichard W.M. Jones void watchdog_perform_action(void)
1039dd986ccSRichard W.M. Jones {
1049dd986ccSRichard W.M. Jones     switch (watchdog_action) {
1054c7f4426SMichal Privoznik     case WATCHDOG_ACTION_RESET:     /* same as 'system_reset' in monitor */
10614d53b4fSMichal Privoznik         qapi_event_send_watchdog(WATCHDOG_ACTION_RESET, &error_abort);
107cf83f140SEric Blake         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
1089dd986ccSRichard W.M. Jones         break;
1099dd986ccSRichard W.M. Jones 
1104c7f4426SMichal Privoznik     case WATCHDOG_ACTION_SHUTDOWN:  /* same as 'system_powerdown' in monitor */
11114d53b4fSMichal Privoznik         qapi_event_send_watchdog(WATCHDOG_ACTION_SHUTDOWN, &error_abort);
1129dd986ccSRichard W.M. Jones         qemu_system_powerdown_request();
1139dd986ccSRichard W.M. Jones         break;
1149dd986ccSRichard W.M. Jones 
1154c7f4426SMichal Privoznik     case WATCHDOG_ACTION_POWEROFF:  /* same as 'quit' command in monitor */
11614d53b4fSMichal Privoznik         qapi_event_send_watchdog(WATCHDOG_ACTION_POWEROFF, &error_abort);
1179dd986ccSRichard W.M. Jones         exit(0);
1189dd986ccSRichard W.M. Jones 
1194c7f4426SMichal Privoznik     case WATCHDOG_ACTION_PAUSE:     /* same as 'stop' command in monitor */
12030e5210aSPaolo Bonzini         /* In a timer callback, when vm_stop calls qemu_clock_enable
12130e5210aSPaolo Bonzini          * you would get a deadlock.  Bypass the problem.
12230e5210aSPaolo Bonzini          */
12330e5210aSPaolo Bonzini         qemu_system_vmstop_request_prepare();
12414d53b4fSMichal Privoznik         qapi_event_send_watchdog(WATCHDOG_ACTION_PAUSE, &error_abort);
12530e5210aSPaolo Bonzini         qemu_system_vmstop_request(RUN_STATE_WATCHDOG);
1269dd986ccSRichard W.M. Jones         break;
1279dd986ccSRichard W.M. Jones 
1284c7f4426SMichal Privoznik     case WATCHDOG_ACTION_DEBUG:
12914d53b4fSMichal Privoznik         qapi_event_send_watchdog(WATCHDOG_ACTION_DEBUG, &error_abort);
1309dd986ccSRichard W.M. Jones         fprintf(stderr, "watchdog: timer fired\n");
1319dd986ccSRichard W.M. Jones         break;
1329dd986ccSRichard W.M. Jones 
1334c7f4426SMichal Privoznik     case WATCHDOG_ACTION_NONE:
13414d53b4fSMichal Privoznik         qapi_event_send_watchdog(WATCHDOG_ACTION_NONE, &error_abort);
1359dd986ccSRichard W.M. Jones         break;
136795dc6e4SMao Chuan Li 
1374c7f4426SMichal Privoznik     case WATCHDOG_ACTION_INJECT_NMI:
13814d53b4fSMichal Privoznik         qapi_event_send_watchdog(WATCHDOG_ACTION_INJECT_NMI,
139795dc6e4SMao Chuan Li                                  &error_abort);
140f7e981f2SBandan Das         nmi_monitor_handle(0, NULL);
141795dc6e4SMao Chuan Li         break;
1424c7f4426SMichal Privoznik 
1434c7f4426SMichal Privoznik     default:
1444c7f4426SMichal Privoznik         assert(0);
1459dd986ccSRichard W.M. Jones     }
1469dd986ccSRichard W.M. Jones }
147f0df84c6SMichal Privoznik 
148f0df84c6SMichal Privoznik void qmp_watchdog_set_action(WatchdogAction action, Error **errp)
149f0df84c6SMichal Privoznik {
150f0df84c6SMichal Privoznik     watchdog_action = action;
151f0df84c6SMichal Privoznik }
152