|
@@ -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();
|