Переглянути джерело

[efi] Hold off watchdog timer while running

UEFI platforms may provide a watchdog timer, which will reboot the
machine if an operating system takes more than five minutes to load.
This can cause long-lived iPXE downloads (or interactive shell
sessions) to unexpectedly reboot.

Fix by resetting the watchdog timer every ten seconds while the iPXE
main processing loop continues to run.

Reported-by: Bradley B Williams <bradleybwilliams@swbell.net>
Reported-by: John Clark <john.r.clark.3@gmail.com>
Reported-by: wdriever@gmail.com
Reported-by: Charlie Beima <cbeima@indiana.edu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 роки тому
джерело
коміт
c6b299df20

+ 5
- 0
src/arch/x86/prefix/efiprefix.c Переглянути файл

@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
26 26
 #include <ipxe/efi/efi_driver.h>
27 27
 #include <ipxe/efi/efi_snp.h>
28 28
 #include <ipxe/efi/efi_autoboot.h>
29
+#include <ipxe/efi/efi_watchdog.h>
29 30
 
30 31
 /**
31 32
  * EFI entry point
@@ -49,6 +50,9 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
49 50
 	/* Claim SNP devices for use by iPXE */
50 51
 	efi_snp_claim();
51 52
 
53
+	/* Start watchdog holdoff timer */
54
+	efi_watchdog_start();
55
+
52 56
 	/* Call to main() */
53 57
 	if ( ( rc = main() ) != 0 ) {
54 58
 		efirc = EFIRC ( rc );
@@ -56,6 +60,7 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
56 60
 	}
57 61
 
58 62
  err_main:
63
+	efi_watchdog_stop();
59 64
 	efi_snp_release();
60 65
 	efi_loaded_image->Unload ( image_handle );
61 66
 	efi_driver_reconnect_all();

+ 31
- 0
src/include/ipxe/efi/efi_watchdog.h Переглянути файл

@@ -0,0 +1,31 @@
1
+#ifndef _IPXE_EFI_WATCHDOG_H
2
+#define _IPXE_EFI_WATCHDOG_H
3
+
4
+/** @file
5
+ *
6
+ * EFI watchdog holdoff timer
7
+ */
8
+
9
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
10
+
11
+extern struct retry_timer efi_watchdog;
12
+
13
+/**
14
+ * Start EFI watchdog holdoff timer
15
+ *
16
+ */
17
+static inline void efi_watchdog_start ( void ) {
18
+
19
+	start_timer_nodelay ( &efi_watchdog );
20
+}
21
+
22
+/**
23
+ * Stop EFI watchdog holdoff timer
24
+ *
25
+ */
26
+static inline void efi_watchdog_stop ( void ) {
27
+
28
+	stop_timer ( &efi_watchdog );
29
+}
30
+
31
+#endif /* _IPXE_EFI_WATCHDOG_H */

+ 1
- 0
src/include/ipxe/errfile.h Переглянути файл

@@ -330,6 +330,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
330 330
 #define ERRFILE_efi_wrap	      ( ERRFILE_OTHER | 0x00460000 )
331 331
 #define ERRFILE_vmbus		      ( ERRFILE_OTHER | 0x00470000 )
332 332
 #define ERRFILE_efi_time	      ( ERRFILE_OTHER | 0x00480000 )
333
+#define ERRFILE_efi_watchdog	      ( ERRFILE_OTHER | 0x00490000 )
333 334
 
334 335
 /** @} */
335 336
 

+ 7
- 0
src/interface/efi/efi_snp.c Переглянути файл

@@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
32 32
 #include <ipxe/efi/efi_driver.h>
33 33
 #include <ipxe/efi/efi_strings.h>
34 34
 #include <ipxe/efi/efi_utils.h>
35
+#include <ipxe/efi/efi_watchdog.h>
35 36
 #include <ipxe/efi/efi_snp.h>
36 37
 #include <usr/autoboot.h>
37 38
 #include <config/general.h>
@@ -881,9 +882,15 @@ efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file,
881 882
 	/* Claim network devices for use by iPXE */
882 883
 	efi_snp_claim();
883 884
 
885
+	/* Start watchdog holdoff timer */
886
+	efi_watchdog_start();
887
+
884 888
 	/* Boot from network device */
885 889
 	ipxe ( netdev );
886 890
 
891
+	/* Stop watchdog holdoff timer */
892
+	efi_watchdog_stop();
893
+
887 894
 	/* Release network devices for use via SNP */
888 895
 	efi_snp_release();
889 896
 

+ 82
- 0
src/interface/efi/efi_watchdog.c Переглянути файл

@@ -0,0 +1,82 @@
1
+/*
2
+ * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/**
27
+ * @file
28
+ *
29
+ * EFI watchdog holdoff timer
30
+ *
31
+ */
32
+
33
+#include <errno.h>
34
+#include <string.h>
35
+#include <ipxe/retry.h>
36
+#include <ipxe/timer.h>
37
+#include <ipxe/efi/efi.h>
38
+#include <ipxe/efi/efi_watchdog.h>
39
+
40
+/** Watchdog holdoff interval (in seconds) */
41
+#define WATCHDOG_HOLDOFF_SECS 10
42
+
43
+/** Watchdog timeout (in seconds) */
44
+#define WATCHDOG_TIMEOUT_SECS ( 5 * 60 )
45
+
46
+/** Watchdog code (to be logged on watchdog timeout) */
47
+#define WATCHDOG_CODE 0x6950584544454144
48
+
49
+/** Watchdog data (to be logged on watchdog timeout) */
50
+#define WATCHDOG_DATA L"iPXE";
51
+
52
+/**
53
+ * Hold off watchdog timer
54
+ *
55
+ * @v retry		Retry timer
56
+ * @v over		Failure indicator
57
+ */
58
+static void efi_watchdog_expired ( struct retry_timer *timer,
59
+				   int over __unused ) {
60
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
61
+	static CHAR16 data[] = WATCHDOG_DATA;
62
+	EFI_STATUS efirc;
63
+	int rc;
64
+
65
+	DBGC2 ( timer, "EFI holding off watchdog timer\n" );
66
+
67
+	/* Restart this holdoff timer */
68
+	start_timer_fixed ( timer, ( WATCHDOG_HOLDOFF_SECS * TICKS_PER_SEC ) );
69
+
70
+	/* Reset watchdog timer */
71
+	if ( ( efirc = bs->SetWatchdogTimer ( WATCHDOG_TIMEOUT_SECS,
72
+					      WATCHDOG_CODE, sizeof ( data ),
73
+					      data ) ) != 0 ) {
74
+		rc = -EEFI ( efirc );
75
+		DBGC ( timer, "EFI could not set watchdog timer: %s\n",
76
+		       strerror ( rc ) );
77
+		return;
78
+	}
79
+}
80
+
81
+/** Watchdog holdoff timer */
82
+struct retry_timer efi_watchdog = TIMER_INIT ( efi_watchdog_expired );

Завантаження…
Відмінити
Зберегти