All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] kern/efi: Adding efi-watchdog command
@ 2021-08-30 14:08 Erwan Velu
  2021-09-01 16:24 ` Daniel Kiper
  0 siblings, 1 reply; 7+ messages in thread
From: Erwan Velu @ 2021-08-30 14:08 UTC (permalink / raw)
  To: grub-devel; +Cc: dkiper, daniel.kiper, alexander.burmashev, phcoder, Erwan Velu

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



^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-09-02 16:59 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-30 14:08 [PATCH] kern/efi: Adding efi-watchdog command Erwan Velu
2021-09-01 16:24 ` Daniel Kiper
2021-09-02  9:08   ` Erwan Velu
2021-09-02 11:42     ` Daniel Kiper
2021-09-02 12:32       ` Erwan Velu
2021-09-02 12:48         ` Daniel Kiper
2021-09-02 16:58     ` Erwan Velu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.