From d8d9c3ce2441be42fc65d2bde5d0fb299de39ad0 Mon Sep 17 00:00:00 2001 From: Jiang Lu Date: Thu, 31 Jan 2019 15:27:03 +0800 Subject: [PATCH] Make UEFI watchdog behaviour configurable Starting with d9a0c9413e81d3c0affc6383693bdd28dc863a5c, GRUB unconditionally disables watchdog on EFI platforms. This opens up a window (starting at GRUB's grub_efi_init(), until OS re-enables it) when EFI system operates w/o watchdog. If an EFI system gets stuck in that window, the chipset will never reset the system. Create a command line interface to enable/disable watchdog: efi-watchdog (enable|disable) Signed-off-by: Jiang Lu Rebase for grub 2.06 Signed-off-by: Yi Zhao --- docs/grub.texi | 11 +++++++ grub-core/kern/efi/init.c | 68 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/docs/grub.texi b/docs/grub.texi index f8b4b3b..95e8367 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -3991,6 +3991,7 @@ you forget a command, you can run the command @command{help} * distrust:: Remove a pubkey from trusted keys * drivemap:: Map a drive to another * echo:: Display a line of text +* efi-watchdog:: Manipulate EFI watchdog * eval:: Evaluate agruments as GRUB commands * export:: Export an environment variable * false:: Do nothing, unsuccessfully @@ -4442,6 +4443,16 @@ When interpreting backslash escapes, backslash followed by any other character will print that character. @end deffn +@node efi-watchdog +@subsection efi-watchdog + +@deffn Command efi-watchdog enable|disable +Enable or disable the system's watchdog timer. Only available in EFI targeted +GRUB. +The is logged upon watchdog timeout event. The UEFI BIOS reserves codes +0x0000 to 0xFFFF. +The represents number of seconds to set the watchdog timeout to. +@end deffn @node eval @subsection eval diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c index 7facacf..4a88397 100644 --- a/grub-core/kern/efi/init.c +++ b/grub-core/kern/efi/init.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #ifdef GRUB_STACK_PROTECTOR @@ -82,6 +84,68 @@ stack_protector_init (void) grub_addr_t grub_modbase; +static grub_command_t cmd_list; + +static grub_err_t +grub_cmd_efi_watchdog (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + long input; + grub_efi_status_t status; + grub_efi_uintn_t timeout; + grub_efi_uint64_t code; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("usage: efi-watchdog (enable|disable) ")); + + if (grub_strcasecmp (args[0], "enable") == 0) { + + if (argc != 3) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("usage: efi-watchdog enable ")); + + input = grub_strtol (args[1], 0, 0); + + if (input >= 0) { + code = input; + } else { + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_(" must be non-negative")); + } + + input = grub_strtol (args[2], 0, 0); + + if (input >= 0) { + timeout = (grub_efi_uintn_t) input; + } else { + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_(" must be non-negative")); + } + + } else if (grub_strcasecmp (args[0], "disable") == 0) { + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("usage: efi-watchdog disable")); + timeout = 0; + code = 0; + + } else { + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("usage: efi-watchdog (enable|disable) ")); + } + + status = efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer, + timeout, code, sizeof(L"GRUB"), L"GRUB"); + + if (status != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_BUG, + N_("Unexpected UEFI SetWatchdogTimer() error")); + else + return GRUB_ERR_NONE; +} + void grub_efi_init (void) { @@ -109,6 +173,9 @@ grub_efi_init (void) 0, 0, 0, NULL); grub_efidisk_init (); + + cmd_list = grub_register_command ("efi-watchdog", grub_cmd_efi_watchdog, 0, + N_("Enable/Disable system's watchdog timer.")); } void (*grub_efi_net_config) (grub_efi_handle_t hnd, @@ -146,4 +213,5 @@ grub_efi_fini (void) { grub_efidisk_fini (); grub_console_fini (); + grub_unregister_command (cmd_list); } -- 2.17.1