[U-Boot,08/11] efi_loader: implement SetWatchdogTimer

Message ID 20171010122309.25313-9-robdclark@gmail.com
State New
Delegated to: Alexander Graf
Headers show
Series
  • efi_loader: patches for Shell.efi
Related show

Commit Message

Rob Clark Oct. 10, 2017, 12:23 p.m.
From: Heinrich Schuchardt <xypron.glpk@gmx.de>

The watchdog is initialized with a 5 minute timeout period.
It can be reset by SetWatchdogTimer.
It is stopped by ExitBoottimeServices.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
---
 cmd/bootefi.c                 |  1 +
 include/efi_loader.h          |  4 ++
 lib/efi_loader/Makefile       |  2 +-
 lib/efi_loader/efi_boottime.c | 17 ++-------
 lib/efi_loader/efi_watchdog.c | 86 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 95 insertions(+), 15 deletions(-)
 create mode 100644 lib/efi_loader/efi_watchdog.c

Comments

Alexander Graf Oct. 11, 2017, 2:55 p.m. | #1
On 10.10.17 14:23, Rob Clark wrote:
> From: Heinrich Schuchardt <xypron.glpk@gmx.de>
> 
> The watchdog is initialized with a 5 minute timeout period.
> It can be reset by SetWatchdogTimer.
> It is stopped by ExitBoottimeServices.
> 
> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>

This is missing an SoB line from Rob.

Reviewed-by: Alexander Graf <agraf@suse.de>


Alex

Patch

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index b7087e3da8..24958ada46 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -43,6 +43,7 @@  static void efi_init_obj_list(void)
 #ifdef CONFIG_GENERATE_SMBIOS_TABLE
 	efi_smbios_register();
 #endif
+	efi_watchdog_register();
 
 	/* Initialize EFI runtime services */
 	efi_reset_system_init();
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 2232caca44..fa4e1cdb1c 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -169,6 +169,8 @@  int efi_disk_register(void);
 int efi_gop_register(void);
 /* Called by bootefi to make the network interface available */
 int efi_net_register(void);
+/* Called by bootefi to make the watchdog available */
+int efi_watchdog_register(void);
 /* Called by bootefi to make SMBIOS tables available */
 void efi_smbios_register(void);
 
@@ -177,6 +179,8 @@  efi_fs_from_path(struct efi_device_path *fp);
 
 /* Called by networking code to memorize the dhcp ack package */
 void efi_net_set_dhcp_ack(void *pkt, int len);
+/* Called by efi_set_watchdog_timer to reset the timer */
+efi_status_t efi_set_watchdog(unsigned long timeout);
 
 /* Called from places to check whether a timer expired */
 void efi_timer_check(void);
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 7ea96a4f1c..4238cf9f9b 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -18,7 +18,7 @@  obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
 obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
 obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
 obj-y += efi_device_path_utilities.o efi_hii.o efi_unicode.o
-obj-y += efi_file.o efi_variable.o efi_bootmgr.o
+obj-y += efi_file.o efi_variable.o efi_bootmgr.o efi_watchdog.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
 obj-$(CONFIG_PARTITIONS) += efi_disk.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 19fafe546c..310f0a3b62 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -156,18 +156,6 @@  void efi_signal_event(struct efi_event *event)
 }
 
 /*
- * Write a debug message for an EPI API service that is not implemented yet.
- *
- * @funcname	function that is not yet implemented
- * @return	EFI_UNSUPPORTED
- */
-static efi_status_t efi_unsupported(const char *funcname)
-{
-	debug("EFI: App called into unimplemented function %s\n", funcname);
-	return EFI_EXIT(EFI_UNSUPPORTED);
-}
-
-/*
  * Raise the task priority level.
  *
  * This function implements the RaiseTpl service.
@@ -1470,6 +1458,7 @@  static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
 	bootm_disable_interrupts();
 
 	/* Give the payload some time to boot */
+	efi_set_watchdog(0);
 	WATCHDOG_RESET();
 
 	return EFI_EXIT(EFI_SUCCESS);
@@ -1513,7 +1502,7 @@  static efi_status_t EFIAPI efi_stall(unsigned long microseconds)
 /*
  * Reset the watchdog timer.
  *
- * This function implements the WatchdogTimer service.
+ * This function implements the SetWatchdogTimer service.
  * See the Unified Extensible Firmware Interface (UEFI) specification
  * for details.
  *
@@ -1529,7 +1518,7 @@  static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout,
 {
 	EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code,
 		  data_size, watchdog_data);
-	return efi_unsupported(__func__);
+	return EFI_EXIT(efi_set_watchdog(timeout));
 }
 
 /*
diff --git a/lib/efi_loader/efi_watchdog.c b/lib/efi_loader/efi_watchdog.c
new file mode 100644
index 0000000000..eb437faf4b
--- /dev/null
+++ b/lib/efi_loader/efi_watchdog.c
@@ -0,0 +1,86 @@ 
+/*
+ *  EFI watchdog
+ *
+ *  Copyright (c) 2017 Heinrich Schuchardt
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+
+static struct efi_event *watchdog_timer_event;
+
+/*
+ * Reset the system when the watchdog event is notified.
+ *
+ * @event:	the watchdog event
+ * @context:	not used
+ */
+static void EFIAPI efi_watchdog_timer_notify(struct efi_event *event,
+					     void *context)
+{
+	EFI_ENTRY("%p, %p", event, context);
+
+	printf("\nEFI: Watchdog timeout\n");
+	EFI_CALL_VOID(efi_runtime_services.reset_system(EFI_RESET_COLD,
+							EFI_SUCCESS, 0, NULL));
+
+	EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/*
+ * Reset the watchdog timer.
+ *
+ * This function is used by the SetWatchdogTimer service.
+ *
+ * @timeout:		seconds before reset by watchdog
+ * @return:		status code
+ */
+efi_status_t efi_set_watchdog(unsigned long timeout)
+{
+	efi_status_t r;
+
+	if (timeout)
+		/* Reset watchdog */
+		r = efi_set_timer(watchdog_timer_event, EFI_TIMER_RELATIVE,
+				  10000000 * timeout);
+	else
+		/* Deactivate watchdog */
+		r = efi_set_timer(watchdog_timer_event, EFI_TIMER_STOP, 0);
+	return r;
+}
+
+/*
+ * Initialize the EFI watchdog.
+ *
+ * This function is called by efi_init_obj_list()
+ */
+int efi_watchdog_register(void)
+{
+	efi_status_t r;
+
+	/*
+	 * Create a timer event.
+	 */
+	r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+			     efi_watchdog_timer_notify, NULL,
+			     &watchdog_timer_event);
+	if (r != EFI_SUCCESS) {
+		printf("ERROR: Failed to register watchdog event\n");
+		return r;
+	}
+	/*
+	 * The UEFI standard requires that the watchdog timer is set to five
+	 * minutes when invoking an EFI boot option.
+	 *
+	 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
+	 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
+	 */
+	r = efi_set_watchdog(300);
+	if (r != EFI_SUCCESS) {
+		printf("ERROR: Failed to set watchdog timer\n");
+		return r;
+	}
+	return 0;
+}