[U-Boot] [PATCH v2 2/9] efi_loader: implement SetWatchdogTimer

Alexander Graf agraf at suse.de
Tue Oct 17 07:12:38 UTC 2017



On 13.10.17 19:33, Heinrich Schuchardt wrote:
> 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 at gmx.de>
> ---
> v2
> 	code comments updated
> ---
>  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
> 
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 478bc116e2..18176a1266 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 1b92edbd77..af64b11cee 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -163,6 +163,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);
>  
> @@ -171,6 +173,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 ddb978f650..83d879b686 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -17,7 +17,7 @@ endif
>  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_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 30577f717e..fd8d15655b 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -155,18 +155,6 @@ void efi_signal_event(struct efi_event *event)
>  	event->is_queued = false;
>  }
>  
> -/*
> - * 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.
>   *
> @@ -1454,6 +1442,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);
> @@ -1497,7 +1486,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.
>   *
> @@ -1514,7 +1503,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);

Can we get a define for this number?

Also, wouldn't it make sense to make the constant ULL? That way we
extend the multiplication result to 64bit on 32bit hosts.

Otherwise we can only fit ~430 seconds (~7 minutes) into the resulting
number before we get an overflow. So if an application sets the timeout
to "in 60 minutes", we'll overflow and maybe trigger when the
application doesn't expect us to.


Alex

> +	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;
> +}
> 


More information about the U-Boot mailing list