iPXE
rtc_entropy.c File Reference

RTC-based entropy source. More...

#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <biosint.h>
#include <pic8259.h>
#include <rtc.h>
#include <ipxe/cpuid.h>
#include <ipxe/entropy.h>

Go to the source code of this file.

Macros

#define RTC_MAX_WAIT_MS   100
 Maximum time to wait for an RTC interrupt, in milliseconds.
#define RTC_CHECK_COUNT   3
 Number of RTC interrupts to check for.
#define rtc_flag   __use_text16 ( rtc_flag )

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
struct entropy_source rtc_entropy __entropy_source (ENTROPY_NORMAL)
 RTC entropy source.
void rtc_isr (void)
 RTC interrupt handler.
volatile uint8_t __text16 (rtc_flag)
 Flag set by RTC interrupt handler.
static void rtc_hook_isr (void)
 Hook RTC interrupt handler.
static void rtc_unhook_isr (void)
 Unhook RTC interrupt handler.
static int rtc_enable_int (void)
 Enable RTC interrupts.
static void rtc_disable_int (void)
 Disable RTC interrupts.
static int rtc_entropy_check (void)
 Check that entropy gathering is functional.
static int rtc_entropy_enable (void)
 Enable entropy gathering.
static void rtc_entropy_disable (void)
 Disable entropy gathering.
static int rtc_get_noise (noise_sample_t *noise)
 Get noise sample.

Variables

static struct segoff rtc_old_handler
 Previous RTC interrupt handler.
static uint8_t rtc_irq_enabled
 Previous RTC interrupt enabled state.
static uint8_t rtc_int_enabled
 Previous RTC periodic interrupt enabled state.

Detailed Description

RTC-based entropy source.

Definition in file rtc_entropy.c.

Macro Definition Documentation

◆ RTC_MAX_WAIT_MS

#define RTC_MAX_WAIT_MS   100

Maximum time to wait for an RTC interrupt, in milliseconds.

Definition at line 45 of file rtc_entropy.c.

Referenced by rtc_entropy_check().

◆ RTC_CHECK_COUNT

#define RTC_CHECK_COUNT   3

Number of RTC interrupts to check for.

Definition at line 48 of file rtc_entropy.c.

Referenced by rtc_entropy_check().

◆ rtc_flag

#define rtc_flag   __use_text16 ( rtc_flag )

Definition at line 64 of file rtc_entropy.c.

Referenced by __text16(), rtc_entropy_check(), and rtc_entropy_enable().

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ __entropy_source()

struct entropy_source rtc_entropy __entropy_source ( ENTROPY_NORMAL )

RTC entropy source.

References __entropy_source, and ENTROPY_NORMAL.

◆ rtc_isr()

void rtc_isr ( void )
extern

RTC interrupt handler.

Referenced by rtc_hook_isr(), and rtc_unhook_isr().

◆ __text16()

volatile uint8_t __text16 ( rtc_flag )
extern

Flag set by RTC interrupt handler.

References rtc_flag.

◆ rtc_hook_isr()

void rtc_hook_isr ( void )
static

Hook RTC interrupt handler.

Definition at line 70 of file rtc_entropy.c.

70 {
71
72 /* RTC interrupt handler */
74 TEXT16_CODE ( "\nrtc_isr:\n\t"
75 /* Preserve registers */
76 "pushw %%ax\n\t"
77 /* Set "interrupt triggered" flag */
78 "movb $0x01, %%cs:rtc_flag\n\t"
79 /* Read RTC status register C to
80 * acknowledge interrupt
81 */
82 "movb %2, %%al\n\t"
83 "outb %%al, %0\n\t"
84 "inb %1\n\t"
85 /* Send EOI */
86 "movb $0x20, %%al\n\t"
87 "outb %%al, $0xa0\n\t"
88 "outb %%al, $0x20\n\t"
89 /* Restore registers and return */
90 "popw %%ax\n\t"
91 "iret\n\t"
92 "\nrtc_flag:\n\t"
93 ".byte 0\n\t" )
94 :
95 : "i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ),
96 "i" ( RTC_STATUS_C ) );
97
99}
__asm__ __volatile__("call *%9" :"=a"(result), "=c"(discard_ecx), "=d"(discard_edx) :"d"(0), "a"(code), "b"(0), "c"(in_phys), "D"(0), "S"(out_phys), "m"(hypercall))
unsigned long intptr_t
Definition stdint.h:21
void hook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Hook INT vector.
Definition biosint.c:25
#define TEXT16_CODE(asm_code_str)
Definition libkir.h:217
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
#define RTC_STATUS_C
RTC status register C.
Definition rtc.h:75
#define CMOS_DATA
CMOS/RTC data register.
Definition rtc.h:33
#define RTC_INT
RTC interrupt vector.
Definition rtc.h:24
#define CMOS_ADDRESS
CMOS/RTC address (and NMI) register.
Definition rtc.h:27
static struct segoff rtc_old_handler
Previous RTC interrupt handler.
Definition rtc_entropy.c:54
void rtc_isr(void)
RTC interrupt handler.

References __asm__(), __volatile__(), CMOS_ADDRESS, CMOS_DATA, hook_bios_interrupt(), RTC_INT, rtc_isr(), rtc_old_handler, RTC_STATUS_C, and TEXT16_CODE.

Referenced by rtc_entropy_enable().

◆ rtc_unhook_isr()

void rtc_unhook_isr ( void )
static

Unhook RTC interrupt handler.

Definition at line 105 of file rtc_entropy.c.

105 {
106 int rc;
107
110 assert ( rc == 0 ); /* Should always be able to unhook */
111}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
Definition biosint.c:70

References assert, rc, RTC_INT, rtc_isr(), rtc_old_handler, and unhook_bios_interrupt().

Referenced by rtc_entropy_disable(), and rtc_entropy_enable().

◆ rtc_enable_int()

int rtc_enable_int ( void )
static

Enable RTC interrupts.

Return values
enabledPeriodic interrupt was previously enabled

Definition at line 118 of file rtc_entropy.c.

118 {
119 uint8_t status_b;
120
121 /* Clear any stale pending interrupts via status register C */
123 inb ( CMOS_DATA );
124
125 /* Set Periodic Interrupt Enable bit in status register B */
127 status_b = inb ( CMOS_DATA );
129 outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA );
130
131 /* Re-enable NMI and reset to default address */
133 inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
134
135 /* Return previous state */
136 return ( status_b & RTC_STATUS_B_PIE );
137}
unsigned char uint8_t
Definition stdint.h:10
#define outb(data, io_addr)
Definition io.h:310
#define inb(io_addr)
Definition io.h:283
#define CMOS_DISABLE_NMI
NMI disable bit.
Definition rtc.h:30
#define RTC_STATUS_B
RTC status register B.
Definition rtc.h:63
#define CMOS_DEFAULT_ADDRESS
CMOS default address.
Definition rtc.h:81
#define RTC_STATUS_B_PIE
RTC Periodic Interrupt Enabled bit.
Definition rtc.h:72

References CMOS_ADDRESS, CMOS_DATA, CMOS_DEFAULT_ADDRESS, CMOS_DISABLE_NMI, inb, outb, RTC_STATUS_B, RTC_STATUS_B_PIE, and RTC_STATUS_C.

Referenced by rtc_entropy_enable().

◆ rtc_disable_int()

void rtc_disable_int ( void )
static

Disable RTC interrupts.

Definition at line 143 of file rtc_entropy.c.

143 {
144 uint8_t status_b;
145
146 /* Clear Periodic Interrupt Enable bit in status register B */
148 status_b = inb ( CMOS_DATA );
150 outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA );
151
152 /* Re-enable NMI and reset to default address */
154 inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
155}

References CMOS_ADDRESS, CMOS_DATA, CMOS_DEFAULT_ADDRESS, CMOS_DISABLE_NMI, inb, outb, RTC_STATUS_B, and RTC_STATUS_B_PIE.

Referenced by rtc_entropy_disable(), and rtc_entropy_enable().

◆ rtc_entropy_check()

int rtc_entropy_check ( void )
static

Check that entropy gathering is functional.

Return values
rcReturn status code

Definition at line 162 of file rtc_entropy.c.

162 {
163 unsigned int count = 0;
164 unsigned int i;
165
166 /* Check that RTC interrupts are working */
167 rtc_flag = 0;
168 for ( i = 0 ; i < RTC_MAX_WAIT_MS ; i++ ) {
169
170 /* Allow interrupts to occur */
171 __asm__ __volatile__ ( "sti\n\t"
172 "nop\n\t"
173 "nop\n\t"
174 "cli\n\t" );
175
176 /* Check for RTC interrupt flag */
177 if ( rtc_flag ) {
178 rtc_flag = 0;
179 if ( ++count >= RTC_CHECK_COUNT )
180 return 0;
181 }
182
183 /* Delay */
184 mdelay ( 1 );
185 }
186
187 DBGC ( &rtc_flag, "RTC timed out waiting for interrupt %d/%d\n",
188 ( count + 1 ), RTC_CHECK_COUNT );
189 return -ETIMEDOUT;
190}
#define DBGC(...)
Definition compiler.h:505
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define RTC_CHECK_COUNT
Number of RTC interrupts to check for.
Definition rtc_entropy.c:48
#define RTC_MAX_WAIT_MS
Maximum time to wait for an RTC interrupt, in milliseconds.
Definition rtc_entropy.c:45
#define rtc_flag
Definition rtc_entropy.c:64
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79

References __asm__(), __volatile__(), count, DBGC, ETIMEDOUT, mdelay(), RTC_CHECK_COUNT, rtc_flag, and RTC_MAX_WAIT_MS.

Referenced by rtc_entropy_enable().

◆ rtc_entropy_enable()

int rtc_entropy_enable ( void )
static

Enable entropy gathering.

Return values
rcReturn status code

Definition at line 197 of file rtc_entropy.c.

197 {
198 struct x86_features features;
199 int rc;
200
201 /* Check that TSC is supported */
203 if ( ! ( features.intel.edx & CPUID_FEATURES_INTEL_EDX_TSC ) ) {
204 DBGC ( &rtc_flag, "RTC has no TSC\n" );
205 rc = -ENOTSUP;
206 goto err_no_tsc;
207 }
208
209 /* Hook ISR and enable RTC interrupts */
210 rtc_hook_isr();
211 rtc_irq_enabled = enable_irq ( RTC_IRQ );
213 DBGC ( &rtc_flag, "RTC had IRQ%d %sabled, interrupt %sabled\n",
214 RTC_IRQ, ( rtc_irq_enabled ? "en" : "dis" ),
215 ( rtc_int_enabled ? "en" : "dis" ) );
216
217 /* Check that RTC interrupts are working */
218 if ( ( rc = rtc_entropy_check() ) != 0 )
219 goto err_check;
220
221 /* The min-entropy has been measured on several platforms
222 * using the entropy_sample test code. Modelling the samples
223 * as independent, and using a confidence level of 99.99%, the
224 * measurements were as follows:
225 *
226 * qemu-kvm : 7.38 bits
227 * VMware : 7.46 bits
228 * Physical hardware : 2.67 bits
229 *
230 * We choose the lowest of these (2.67 bits) and apply a 50%
231 * safety margin to allow for some potential non-independence
232 * of samples.
233 */
234 entropy_init ( &rtc_entropy, MIN_ENTROPY ( 1.3 ) );
235
236 return 0;
237
238 err_check:
239 if ( ! rtc_int_enabled )
241 if ( ! rtc_irq_enabled )
242 disable_irq ( RTC_IRQ );
244 err_no_tsc:
245 return rc;
246}
void x86_features(struct x86_features *features)
Get x86 CPU features.
Definition cpuid.c:164
#define CPUID_FEATURES_INTEL_EDX_TSC
TSC is present.
Definition cpuid.h:53
uint32_t features
Supported features.
Definition ena.h:5
#define ENOTSUP
Operation not supported.
Definition errno.h:590
static void entropy_init(struct entropy_source *source, min_entropy_t min_entropy_per_sample)
Initialise entropy source.
Definition entropy.h:490
#define MIN_ENTROPY(bits)
Construct a min-entropy fixed-point value.
Definition entropy.h:43
#define RTC_IRQ
RTC IRQ.
Definition rtc.h:21
static int rtc_entropy_check(void)
Check that entropy gathering is functional.
static void rtc_hook_isr(void)
Hook RTC interrupt handler.
Definition rtc_entropy.c:70
static void rtc_unhook_isr(void)
Unhook RTC interrupt handler.
static uint8_t rtc_int_enabled
Previous RTC periodic interrupt enabled state.
Definition rtc_entropy.c:60
static void rtc_disable_int(void)
Disable RTC interrupts.
static uint8_t rtc_irq_enabled
Previous RTC interrupt enabled state.
Definition rtc_entropy.c:57
static int rtc_enable_int(void)
Enable RTC interrupts.
x86 CPU features
Definition cpuid.h:24

References CPUID_FEATURES_INTEL_EDX_TSC, DBGC, ENOTSUP, entropy_init(), features, MIN_ENTROPY, rc, rtc_disable_int(), rtc_enable_int(), rtc_entropy_check(), rtc_flag, rtc_hook_isr(), rtc_int_enabled, RTC_IRQ, rtc_irq_enabled, rtc_unhook_isr(), and x86_features().

◆ rtc_entropy_disable()

void rtc_entropy_disable ( void )
static

Disable entropy gathering.

Definition at line 252 of file rtc_entropy.c.

252 {
253
254 /* Restore RTC interrupt state and unhook ISR */
255 if ( ! rtc_int_enabled )
257 if ( ! rtc_irq_enabled )
258 disable_irq ( RTC_IRQ );
260}

References rtc_disable_int(), rtc_int_enabled, RTC_IRQ, rtc_irq_enabled, and rtc_unhook_isr().

◆ rtc_get_noise()

int rtc_get_noise ( noise_sample_t * noise)
static

Get noise sample.

Return values
noiseNoise sample
rcReturn status code

Definition at line 268 of file rtc_entropy.c.

268 {
271 uint32_t temp;
272
274 REAL_CODE ( /* Enable interrupts */
275 "sti\n\t"
276 /* Wait for RTC interrupt */
277 "movb %b2, %%cs:rtc_flag\n\t"
278 "\n1:\n\t"
279 "xchgb %b2, %%cs:rtc_flag\n\t" /* Serialize */
280 "testb %b2, %b2\n\t"
281 "jz 1b\n\t"
282 /* Read "before" TSC */
283 "rdtsc\n\t"
284 /* Store "before" TSC on stack */
285 "pushl %0\n\t"
286 /* Wait for another RTC interrupt */
287 "xorb %b2, %b2\n\t"
288 "movb %b2, %%cs:rtc_flag\n\t"
289 "\n1:\n\t"
290 "xchgb %b2, %%cs:rtc_flag\n\t" /* Serialize */
291 "testb %b2, %b2\n\t"
292 "jz 1b\n\t"
293 /* Read "after" TSC */
294 "rdtsc\n\t"
295 /* Retrieve "before" TSC on stack */
296 "popl %1\n\t"
297 /* Disable interrupts */
298 "cli\n\t"
299 )
300 : "=a" ( after ), "=d" ( before ), "=Q" ( temp )
301 : "2" ( 0 ) );
302
303 *noise = ( after - before );
304 return 0;
305}
unsigned int uint32_t
Definition stdint.h:12
#define REAL_CODE(asm_code_str)
Definition libkir.h:226
int32_t after
Final microcode version.
Definition ucode.h:7
int32_t before
Initial microcode version.
Definition ucode.h:5

References __asm__(), __volatile__(), after, before, and REAL_CODE.

Variable Documentation

◆ rtc_old_handler

struct segoff rtc_old_handler
static

Previous RTC interrupt handler.

Definition at line 54 of file rtc_entropy.c.

Referenced by rtc_hook_isr(), and rtc_unhook_isr().

◆ rtc_irq_enabled

uint8_t rtc_irq_enabled
static

Previous RTC interrupt enabled state.

Definition at line 57 of file rtc_entropy.c.

Referenced by rtc_entropy_disable(), and rtc_entropy_enable().

◆ rtc_int_enabled

uint8_t rtc_int_enabled
static

Previous RTC periodic interrupt enabled state.

Definition at line 60 of file rtc_entropy.c.

Referenced by rtc_entropy_disable(), and rtc_entropy_enable().