|  | @@ -31,17 +31,26 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 31 | 31 |  
 | 
		
	
		
			
			| 32 | 32 |  #include <stdint.h>
 | 
		
	
		
			
			| 33 | 33 |  #include <string.h>
 | 
		
	
		
			
			|  | 34 | +#include <errno.h>
 | 
		
	
		
			
			|  | 35 | +#include <unistd.h>
 | 
		
	
		
			
			| 34 | 36 |  #include <biosint.h>
 | 
		
	
		
			
			| 35 | 37 |  #include <pic8259.h>
 | 
		
	
		
			
			| 36 | 38 |  #include <rtc.h>
 | 
		
	
		
			
			| 37 | 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 | 44 |  /** RTC interrupt handler */
 | 
		
	
		
			
			| 40 | 45 |  extern void rtc_isr ( void );
 | 
		
	
		
			
			| 41 | 46 |  
 | 
		
	
		
			
			| 42 | 47 |  /** Previous RTC interrupt handler */
 | 
		
	
		
			
			| 43 | 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 | 55 |   * Hook RTC interrupt handler
 | 
		
	
		
			
			| 47 | 56 |   *
 | 
		
	
	
		
			
			|  | @@ -96,6 +105,10 @@ static void rtc_unhook_isr ( void ) {
 | 
		
	
		
			
			| 96 | 105 |  static void rtc_enable_int ( void ) {
 | 
		
	
		
			
			| 97 | 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 | 112 |  	/* Set Periodic Interrupt Enable bit in status register B */
 | 
		
	
		
			
			| 100 | 113 |  	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
 | 
		
	
		
			
			| 101 | 114 |  	status_b = inb ( CMOS_DATA );
 | 
		
	
	
		
			
			|  | @@ -125,18 +138,60 @@ static void rtc_disable_int ( void ) {
 | 
		
	
		
			
			| 125 | 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 | 172 |   * Enable entropy gathering
 | 
		
	
		
			
			| 130 | 173 |   *
 | 
		
	
		
			
			| 131 | 174 |   * @ret rc		Return status code
 | 
		
	
		
			
			| 132 | 175 |   */
 | 
		
	
		
			
			| 133 | 176 |  static int rtc_entropy_enable ( void ) {
 | 
		
	
		
			
			|  | 177 | +	int rc;
 | 
		
	
		
			
			| 134 | 178 |  
 | 
		
	
		
			
			|  | 179 | +	/* Hook ISR and enable RTC interrupts */
 | 
		
	
		
			
			| 135 | 180 |  	rtc_hook_isr();
 | 
		
	
		
			
			| 136 | 181 |  	enable_irq ( RTC_IRQ );
 | 
		
	
		
			
			| 137 | 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 | 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,6 +200,7 @@ static int rtc_entropy_enable ( void ) {
 | 
		
	
		
			
			| 145 | 200 |   */
 | 
		
	
		
			
			| 146 | 201 |  static void rtc_entropy_disable ( void ) {
 | 
		
	
		
			
			| 147 | 202 |  
 | 
		
	
		
			
			|  | 203 | +	/* Disable RTC interrupts and unhook ISR */
 | 
		
	
		
			
			| 148 | 204 |  	rtc_disable_int();
 | 
		
	
		
			
			| 149 | 205 |  	disable_irq ( RTC_IRQ );
 | 
		
	
		
			
			| 150 | 206 |  	rtc_unhook_isr();
 |