Browse Source

[rng] Check for functioning RTC interrupt

On some platforms (observed in a small subset of Microsoft Azure
(Hyper-V) virtual machines), the RTC appears to be incapable of
generating an interrupt via the legacy PIC.  The RTC status registers
show that a periodic interrupt has been asserted, but the PIC IRR
shows that IRQ8 remains inactive.

On such systems, iPXE will currently freeze during the "iPXE
initialising devices..." message.

Work around this problem by checking that RTC interrupts are being
raised before returning from rtc_entropy_enable().  If no interrupt is
seen within 100ms, then we assume that the RTC interrupt mechanism is
broken.  In these circumstances, iPXE will continue to initialise but
any subsequent attempt to generate entropy will fail.  In particular,
HTTPS connections will fail with an error indicating that no entropy
is available.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
74222cd2c1
2 changed files with 57 additions and 0 deletions
  1. 1
    0
      src/arch/x86/include/bits/errfile.h
  2. 56
    0
      src/arch/x86/interface/pcbios/rtc_entropy.c

+ 1
- 0
src/arch/x86/include/bits/errfile.h View File

23
 #define ERRFILE_vesafb		( ERRFILE_ARCH | ERRFILE_CORE | 0x000c0000 )
23
 #define ERRFILE_vesafb		( ERRFILE_ARCH | ERRFILE_CORE | 0x000c0000 )
24
 #define ERRFILE_int13con	( ERRFILE_ARCH | ERRFILE_CORE | 0x000d0000 )
24
 #define ERRFILE_int13con	( ERRFILE_ARCH | ERRFILE_CORE | 0x000d0000 )
25
 #define ERRFILE_gdbmach		( ERRFILE_ARCH | ERRFILE_CORE | 0x000e0000 )
25
 #define ERRFILE_gdbmach		( ERRFILE_ARCH | ERRFILE_CORE | 0x000e0000 )
26
+#define ERRFILE_rtc_entropy	( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
26
 
27
 
27
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
28
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
28
 #define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
29
 #define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

+ 56
- 0
src/arch/x86/interface/pcbios/rtc_entropy.c View File

31
 
31
 
32
 #include <stdint.h>
32
 #include <stdint.h>
33
 #include <string.h>
33
 #include <string.h>
34
+#include <errno.h>
35
+#include <unistd.h>
34
 #include <biosint.h>
36
 #include <biosint.h>
35
 #include <pic8259.h>
37
 #include <pic8259.h>
36
 #include <rtc.h>
38
 #include <rtc.h>
37
 #include <ipxe/entropy.h>
39
 #include <ipxe/entropy.h>
38
 
40
 
41
+/** Maximum time to wait for an RTC interrupt, in milliseconds */
42
+#define RTC_MAX_WAIT_MS 100
43
+
39
 /** RTC interrupt handler */
44
 /** RTC interrupt handler */
40
 extern void rtc_isr ( void );
45
 extern void rtc_isr ( void );
41
 
46
 
42
 /** Previous RTC interrupt handler */
47
 /** Previous RTC interrupt handler */
43
 static struct segoff rtc_old_handler;
48
 static struct segoff rtc_old_handler;
44
 
49
 
50
+/** Flag set by RTC interrupt handler */
51
+extern volatile uint8_t __text16 ( rtc_flag );
52
+#define rtc_flag __use_text16 ( rtc_flag )
53
+
45
 /**
54
 /**
46
  * Hook RTC interrupt handler
55
  * Hook RTC interrupt handler
47
  *
56
  *
96
 static void rtc_enable_int ( void ) {
105
 static void rtc_enable_int ( void ) {
97
 	uint8_t status_b;
106
 	uint8_t status_b;
98
 
107
 
108
+	/* Clear any stale pending interrupts via status register C */
109
+	outb ( ( RTC_STATUS_C | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
110
+	inb ( CMOS_DATA );
111
+
99
 	/* Set Periodic Interrupt Enable bit in status register B */
112
 	/* Set Periodic Interrupt Enable bit in status register B */
100
 	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
113
 	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
101
 	status_b = inb ( CMOS_DATA );
114
 	status_b = inb ( CMOS_DATA );
125
 	inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
138
 	inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
126
 }
139
 }
127
 
140
 
141
+/**
142
+ * Check that entropy gathering is functional
143
+ *
144
+ * @ret rc		Return status code
145
+ */
146
+static int rtc_entropy_check ( void ) {
147
+	unsigned int i;
148
+
149
+	/* Check that RTC interrupts are working */
150
+	rtc_flag = 0;
151
+	for ( i = 0 ; i < RTC_MAX_WAIT_MS ; i++ ) {
152
+
153
+		/* Allow interrupts to occur */
154
+		__asm__ __volatile__ ( "sti\n\t"
155
+				       "nop\n\t"
156
+				       "nop\n\t"
157
+				       "cli\n\t" );
158
+
159
+		/* Check for RTC interrupt flag */
160
+		if ( rtc_flag )
161
+			return 0;
162
+
163
+		/* Delay */
164
+		mdelay ( 1 );
165
+	}
166
+
167
+	DBGC ( &rtc_flag, "RTC timed out waiting for interrupt\n" );
168
+	return -ETIMEDOUT;
169
+}
170
+
128
 /**
171
 /**
129
  * Enable entropy gathering
172
  * Enable entropy gathering
130
  *
173
  *
131
  * @ret rc		Return status code
174
  * @ret rc		Return status code
132
  */
175
  */
133
 static int rtc_entropy_enable ( void ) {
176
 static int rtc_entropy_enable ( void ) {
177
+	int rc;
134
 
178
 
179
+	/* Hook ISR and enable RTC interrupts */
135
 	rtc_hook_isr();
180
 	rtc_hook_isr();
136
 	enable_irq ( RTC_IRQ );
181
 	enable_irq ( RTC_IRQ );
137
 	rtc_enable_int();
182
 	rtc_enable_int();
138
 
183
 
184
+	/* Check that RTC interrupts are working */
185
+	if ( ( rc = rtc_entropy_check() ) != 0 )
186
+		goto err_check;
187
+
139
 	return 0;
188
 	return 0;
189
+
190
+ err_check:
191
+	rtc_disable_int();
192
+	disable_irq ( RTC_IRQ );
193
+	rtc_unhook_isr();
194
+	return rc;
140
 }
195
 }
141
 
196
 
142
 /**
197
 /**
145
  */
200
  */
146
 static void rtc_entropy_disable ( void ) {
201
 static void rtc_entropy_disable ( void ) {
147
 
202
 
203
+	/* Disable RTC interrupts and unhook ISR */
148
 	rtc_disable_int();
204
 	rtc_disable_int();
149
 	disable_irq ( RTC_IRQ );
205
 	disable_irq ( RTC_IRQ );
150
 	rtc_unhook_isr();
206
 	rtc_unhook_isr();

Loading…
Cancel
Save