u-boot/lib/efi_loader/efi_watchdog.c
Masahisa Kojima 3fa9ed9ae3 efi_loader: update the timing of enabling and disabling EFI watchdog
UEFI specification requires that 5 minutes watchdog timer is
armed before the firmware's boot manager invokes an EFI boot option.
This watchdog timer is updated as follows, according to the
UEFI specification.

 1) The EFI Image may reset or disable the watchdog timer as needed.
 2) If control is returned to the firmware's boot manager,
    the watchdog timer must be disabled.
 3) On successful completion of EFI_BOOT_SERVICES.ExitBootServices()
    the watchdog timer is disabled.

1) is up to the EFI image, and 3) is already implemented in U-Boot.
This patch implements 2), the watchdog is disabled when control is
returned to U-Boot.

In addition, current implementation arms the EFI watchdog at only
the first "bootefi" invocation. The EFI watchdog must be armed
in every EFI boot option invocation.

Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
Reviewed-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
2022-02-26 07:37:01 +01:00

80 lines
1.7 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* EFI watchdog
*
* Copyright (c) 2017 Heinrich Schuchardt
*/
#include <common.h>
#include <efi_loader.h>
/* Conversion factor from seconds to multiples of 100ns */
#define EFI_SECONDS_TO_100NS 10000000ULL
static struct efi_event *watchdog_timer_event;
/**
* efi_watchdog_timer_notify() - resets system upon watchdog 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");
do_reset(NULL, 0, 0, NULL);
EFI_EXIT(EFI_UNSUPPORTED);
}
/**
* efi_set_watchdog() - resets 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,
EFI_SECONDS_TO_100NS * timeout);
else
/* Deactivate watchdog */
r = efi_set_timer(watchdog_timer_event, EFI_TIMER_STOP, 0);
return r;
}
/**
* efi_watchdog_register() - initializes the EFI watchdog
*
* This function is called by efi_init_obj_list().
*
* Return: status code
*/
efi_status_t 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, NULL,
&watchdog_timer_event);
if (r != EFI_SUCCESS) {
printf("ERROR: Failed to register watchdog event\n");
return r;
}
return EFI_SUCCESS;
}