All of lore.kernel.org
 help / color / mirror / Atom feed
From: Erwan Velu <erwanaliasr1@gmail.com>
To: grub-devel@gnu.org
Cc: dkiper@net-space.pl, daniel.kiper@oracle.com,
	alexander.burmashev@oracle.com, phcoder@gmail.com,
	Erwan Velu <e.velu@criteo.com>
Subject: [PATCH] kern/efi: Adding efi-watchdog command
Date: Mon, 30 Aug 2021 16:08:07 +0200	[thread overview]
Message-ID: <20210830140807.1328406-1-e.velu@criteo.com> (raw)

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	other threads:[~2021-08-30 14:08 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-30 14:08 Erwan Velu [this message]
2021-09-01 16:24 ` [PATCH] kern/efi: Adding efi-watchdog command 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210830140807.1328406-1-e.velu@criteo.com \
    --to=erwanaliasr1@gmail.com \
    --cc=alexander.burmashev@oracle.com \
    --cc=daniel.kiper@oracle.com \
    --cc=dkiper@net-space.pl \
    --cc=e.velu@criteo.com \
    --cc=grub-devel@gnu.org \
    --cc=phcoder@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.