Skip to content

Commit 74222cd

Browse files
committed
[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>
1 parent d681794 commit 74222cd

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/arch/x86/include/bits/errfile.h

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
2323
#define ERRFILE_vesafb ( ERRFILE_ARCH | ERRFILE_CORE | 0x000c0000 )
2424
#define ERRFILE_int13con ( ERRFILE_ARCH | ERRFILE_CORE | 0x000d0000 )
2525
#define ERRFILE_gdbmach ( ERRFILE_ARCH | ERRFILE_CORE | 0x000e0000 )
26+
#define ERRFILE_rtc_entropy ( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
2627

2728
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
2829
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

src/arch/x86/interface/pcbios/rtc_entropy.c

+56
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,26 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
3131

3232
#include <stdint.h>
3333
#include <string.h>
34+
#include <errno.h>
35+
#include <unistd.h>
3436
#include <biosint.h>
3537
#include <pic8259.h>
3638
#include <rtc.h>
3739
#include <ipxe/entropy.h>
3840

41+
/** Maximum time to wait for an RTC interrupt, in milliseconds */
42+
#define RTC_MAX_WAIT_MS 100
43+
3944
/** RTC interrupt handler */
4045
extern void rtc_isr ( void );
4146

4247
/** Previous RTC interrupt handler */
4348
static struct segoff rtc_old_handler;
4449

50+
/** Flag set by RTC interrupt handler */
51+
extern volatile uint8_t __text16 ( rtc_flag );
52+
#define rtc_flag __use_text16 ( rtc_flag )
53+
4554
/**
4655
* Hook RTC interrupt handler
4756
*
@@ -96,6 +105,10 @@ static void rtc_unhook_isr ( void ) {
96105
static void rtc_enable_int ( void ) {
97106
uint8_t status_b;
98107

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+
99112
/* Set Periodic Interrupt Enable bit in status register B */
100113
outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
101114
status_b = inb ( CMOS_DATA );
@@ -125,18 +138,60 @@ static void rtc_disable_int ( void ) {
125138
inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
126139
}
127140

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+
128171
/**
129172
* Enable entropy gathering
130173
*
131174
* @ret rc Return status code
132175
*/
133176
static int rtc_entropy_enable ( void ) {
177+
int rc;
134178

179+
/* Hook ISR and enable RTC interrupts */
135180
rtc_hook_isr();
136181
enable_irq ( RTC_IRQ );
137182
rtc_enable_int();
138183

184+
/* Check that RTC interrupts are working */
185+
if ( ( rc = rtc_entropy_check() ) != 0 )
186+
goto err_check;
187+
139188
return 0;
189+
190+
err_check:
191+
rtc_disable_int();
192+
disable_irq ( RTC_IRQ );
193+
rtc_unhook_isr();
194+
return rc;
140195
}
141196

142197
/**
@@ -145,6 +200,7 @@ static int rtc_entropy_enable ( void ) {
145200
*/
146201
static void rtc_entropy_disable ( void ) {
147202

203+
/* Disable RTC interrupts and unhook ISR */
148204
rtc_disable_int();
149205
disable_irq ( RTC_IRQ );
150206
rtc_unhook_isr();

0 commit comments

Comments
 (0)