1 /*
2  *  EFI watchdog
3  *
4  *  Copyright (c) 2017 Heinrich Schuchardt
5  *
6  *  SPDX-License-Identifier:     GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <efi_loader.h>
11 
12 /* Conversion factor from seconds to multiples of 100ns */
13 #define EFI_SECONDS_TO_100NS 10000000ULL
14 
15 static struct efi_event *watchdog_timer_event;
16 
17 /*
18  * Reset the system when the watchdog event is notified.
19  *
20  * @event:	the watchdog event
21  * @context:	not used
22  */
23 static void EFIAPI efi_watchdog_timer_notify(struct efi_event *event,
24 					     void *context)
25 {
26 	EFI_ENTRY("%p, %p", event, context);
27 
28 	printf("\nEFI: Watchdog timeout\n");
29 	EFI_CALL_VOID(efi_runtime_services.reset_system(EFI_RESET_COLD,
30 							EFI_SUCCESS, 0, NULL));
31 
32 	EFI_EXIT(EFI_UNSUPPORTED);
33 }
34 
35 /*
36  * Reset the watchdog timer.
37  *
38  * This function is used by the SetWatchdogTimer service.
39  *
40  * @timeout:		seconds before reset by watchdog
41  * @return:		status code
42  */
43 efi_status_t efi_set_watchdog(unsigned long timeout)
44 {
45 	efi_status_t r;
46 
47 	if (timeout)
48 		/* Reset watchdog */
49 		r = efi_set_timer(watchdog_timer_event, EFI_TIMER_RELATIVE,
50 				  EFI_SECONDS_TO_100NS * timeout);
51 	else
52 		/* Deactivate watchdog */
53 		r = efi_set_timer(watchdog_timer_event, EFI_TIMER_STOP, 0);
54 	return r;
55 }
56 
57 /*
58  * Initialize the EFI watchdog.
59  *
60  * This function is called by efi_init_obj_list()
61  */
62 int efi_watchdog_register(void)
63 {
64 	efi_status_t r;
65 
66 	/*
67 	 * Create a timer event.
68 	 */
69 	r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
70 			     efi_watchdog_timer_notify, NULL,
71 			     &watchdog_timer_event);
72 	if (r != EFI_SUCCESS) {
73 		printf("ERROR: Failed to register watchdog event\n");
74 		return r;
75 	}
76 	/*
77 	 * The UEFI standard requires that the watchdog timer is set to five
78 	 * minutes when invoking an EFI boot option.
79 	 *
80 	 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
81 	 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
82 	 */
83 	r = efi_set_watchdog(300);
84 	if (r != EFI_SUCCESS) {
85 		printf("ERROR: Failed to set watchdog timer\n");
86 		return r;
87 	}
88 	return 0;
89 }
90