grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] kern/efi: Adding efi-watchdog command


From: Erwan Velu
Subject: [PATCH] kern/efi: Adding efi-watchdog command
Date: Mon, 30 Aug 2021 16:08:07 +0200

This patch got written by Arthur Mesh from Juniper (now at Apple Sec team).
It was extracted from 
https://lists.gnu.org/archive/html/grub-devel/2015-09/msg00065.html

Since this email, the this patch was :
- rebased against the current tree
- added a default timeout value

This commit adds a new command efi-watchdog to manage efi watchdogs.

On server platforms, this allow grub to reset the host automatically
if it wasn't able to succeed at booting in a given timeframe.
This usually covers the following issues :
- net boot is too slow and never ends
- grub is unable to find a proper configuration and fails

If EFI_WATCHDOG_MINUTES is set a compile time, this enable the watchdog
behavior at the early init of GRUB meaning that even if grub is not able
to load its configuration file, the watchdog will be triggered
automatically.

Please note that watchdog only covers GRUB itself.
Additional hardware watchdog are required if some want to protect the early
operating system loading phase.

By default grub disable the watchdog and so this patch.
Therefore, this commit have no impact on grub's behavior.

This patch is used in production for month on a 50K server platform with 
success.

Signed-off-by: Erwan Velu <e.velu@criteo.com>
---
 docs/grub.texi            | 15 ++++++++++
 grub-core/kern/efi/init.c | 63 ++++++++++++++++++++++++++++++++++++++-
 include/grub/efi/efi.h    |  2 ++
 3 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index f8b4b3b21a7f..b52161a19b3b 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,20 @@ 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 @option{enable}|@option{disable} code timeout
+Enable or disable the system's watchdog timer.
+Only available in EFI targeted GRUB.
+
+If @option{enable} is used, the @var{code} is logged upon
+watchdog timeout event. The UEFI BIOS reserves codes 0x0000 to 0xFFFF.
+The @var{timeout} represents number of seconds to set the watchdog timeout to.
+When the watchdog exceed the timeout, the system is reset.
+
+if @option{disable} is used, the EFI watchdog is disarmed.
+@end deffn
 
 @node eval
 @subsection eval
diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
index 7facacf09c7b..c8cda3854ce7 100644
--- a/grub-core/kern/efi/init.c
+++ b/grub-core/kern/efi/init.c
@@ -28,6 +28,8 @@
 #include <grub/mm.h>
 #include <grub/kernel.h>
 #include <grub/stack_protector.h>
+#include <grub/extcmd.h>
+#include <grub/command.h>
 
 #ifdef GRUB_STACK_PROTECTOR
 
@@ -82,6 +84,60 @@ 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) <code> <timeout>"));
+
+    if (grub_strcasecmp (args[0], "enable") == 0) {
+
+       if (argc != 3)
+           return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                              N_("usage: efi-watchdog enable <code> 
<timeout>"));
+
+       input = grub_strtol (args[1], 0, 0);
+
+       if (input >= 0) {
+           code = input;
+       } else {
+           return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                              N_("<code> 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) <code> <timeout>"));
+    }
+
+    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)
 {
@@ -105,10 +161,14 @@ grub_efi_init (void)
       grub_shim_lock_verifier_setup ();
     }
 
+  grub_printf("grub %s: Arming EFI watchdog at %d minutes\n", PACKAGE_VERSION, 
EFI_WATCHDOG_MINUTES);
   efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer,
-             0, 0, 0, NULL);
+              60*EFI_WATCHDOG_MINUTES, 0, sizeof(L"GRUB"), L"GRUB");
 
   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 +206,5 @@ grub_efi_fini (void)
 {
   grub_efidisk_fini ();
   grub_console_fini ();
+  grub_unregister_command (cmd_list);
 }
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 83d958f9945e..372f995b74f4 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -124,4 +124,6 @@ struct grub_net_card;
 grub_efi_handle_t
 grub_efinet_get_device_handle (struct grub_net_card *card);
 
+/* EFI Watchdog armed by grub, in minutes */
+#define EFI_WATCHDOG_MINUTES 0
 #endif /* ! GRUB_EFI_EFI_HEADER */
-- 
2.25.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]