iPXE
Macros | Functions | Variables
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. More...
 
#define RTC_CHECK_COUNT   3
 Number of RTC interrupts to check for. More...
 
#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. More...
 
void rtc_isr (void)
 RTC interrupt handler. More...
 
volatile uint8_t __text16 (rtc_flag)
 Flag set by RTC interrupt handler. More...
 
static void rtc_hook_isr (void)
 Hook RTC interrupt handler. More...
 
static void rtc_unhook_isr (void)
 Unhook RTC interrupt handler. More...
 
static int rtc_enable_int (void)
 Enable RTC interrupts. More...
 
static void rtc_disable_int (void)
 Disable RTC interrupts. More...
 
static int rtc_entropy_check (void)
 Check that entropy gathering is functional. More...
 
static int rtc_entropy_enable (void)
 Enable entropy gathering. More...
 
static void rtc_entropy_disable (void)
 Disable entropy gathering. More...
 
static int rtc_get_noise (noise_sample_t *noise)
 Get noise sample. More...
 

Variables

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

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.

◆ RTC_CHECK_COUNT

#define RTC_CHECK_COUNT   3

Number of RTC interrupts to check for.

Definition at line 48 of file rtc_entropy.c.

◆ rtc_flag

#define rtc_flag   __use_text16 ( rtc_flag )

Definition at line 64 of file rtc_entropy.c.

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.

◆ rtc_isr()

void rtc_isr ( void  )

RTC interrupt handler.

Referenced by rtc_hook_isr(), and rtc_unhook_isr().

◆ __text16()

volatile uint8_t __text16 ( rtc_flag  )

Flag set by RTC interrupt handler.

◆ rtc_hook_isr()

static 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 }
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
void rtc_isr(void)
RTC interrupt handler.
static struct segoff rtc_old_handler
Previous RTC interrupt handler.
Definition: rtc_entropy.c:54
#define CMOS_DATA
CMOS/RTC data register.
Definition: rtc.h:33
__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))
#define RTC_INT
RTC interrupt vector.
Definition: rtc.h:24
__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_ADDRESS
CMOS/RTC address (and NMI) register.
Definition: rtc.h:27
#define TEXT16_CODE(asm_code_str)
Definition: libkir.h:217

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

static void rtc_unhook_isr ( void  )
static

Unhook RTC interrupt handler.

Definition at line 105 of file rtc_entropy.c.

105  {
106  int rc;
107 
109  &rtc_old_handler );
110  assert ( rc == 0 ); /* Should always be able to unhook */
111 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned long intptr_t
Definition: stdint.h:21
void rtc_isr(void)
RTC interrupt handler.
static struct segoff rtc_old_handler
Previous RTC interrupt handler.
Definition: rtc_entropy.c:54
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
Definition: biosint.c:70
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
#define RTC_INT
RTC interrupt vector.
Definition: rtc.h:24

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

static 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 }
#define CMOS_DEFAULT_ADDRESS
CMOS default address.
Definition: rtc.h:81
#define RTC_STATUS_B
RTC status register B.
Definition: rtc.h:63
#define CMOS_DATA
CMOS/RTC data register.
Definition: rtc.h:33
unsigned char uint8_t
Definition: stdint.h:10
uint8_t inb(volatile uint8_t *io_addr)
Read byte from I/O-mapped device.
#define outb(data, io_addr)
Definition: io.h:309
#define RTC_STATUS_C
RTC status register C.
Definition: rtc.h:75
#define CMOS_ADDRESS
CMOS/RTC address (and NMI) register.
Definition: rtc.h:27
#define CMOS_DISABLE_NMI
NMI disable bit.
Definition: rtc.h:30
#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()

static 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 }
#define CMOS_DEFAULT_ADDRESS
CMOS default address.
Definition: rtc.h:81
#define RTC_STATUS_B
RTC status register B.
Definition: rtc.h:63
#define CMOS_DATA
CMOS/RTC data register.
Definition: rtc.h:33
unsigned char uint8_t
Definition: stdint.h:10
uint8_t inb(volatile uint8_t *io_addr)
Read byte from I/O-mapped device.
#define outb(data, io_addr)
Definition: io.h:309
#define CMOS_ADDRESS
CMOS/RTC address (and NMI) register.
Definition: rtc.h:27
#define CMOS_DISABLE_NMI
NMI disable bit.
Definition: rtc.h:30
#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, and RTC_STATUS_B_PIE.

Referenced by rtc_entropy_disable(), and rtc_entropy_enable().

◆ rtc_entropy_check()

static 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:225
#define RTC_CHECK_COUNT
Number of RTC interrupts to check for.
Definition: rtc_entropy.c:48
#define rtc_flag
Definition: rtc_entropy.c:64
__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))
#define RTC_MAX_WAIT_MS
Maximum time to wait for an RTC interrupt, in milliseconds.
Definition: rtc_entropy.c:45
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
__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 ETIMEDOUT
Connection timed out.
Definition: errno.h:669

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

static 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 */
202  x86_features ( &features );
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 )
240  rtc_disable_int();
241  if ( ! rtc_irq_enabled )
242  disable_irq ( RTC_IRQ );
243  rtc_unhook_isr();
244  err_no_tsc:
245  return rc;
246 }
static uint8_t rtc_irq_enabled
Previous RTC interrupt enabled state.
Definition: rtc_entropy.c:57
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define RTC_IRQ
RTC IRQ.
Definition: rtc.h:21
#define DBGC(...)
Definition: compiler.h:505
void x86_features(struct x86_features *features)
Get x86 CPU features.
Definition: cpuid.c:163
x86 CPU features
Definition: cpuid.h:23
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
#define rtc_flag
Definition: rtc_entropy.c:64
uint32_t features
Supported features.
Definition: ena.h:16
static void rtc_hook_isr(void)
Hook RTC interrupt handler.
Definition: rtc_entropy.c:70
#define MIN_ENTROPY(bits)
Construct a min-entropy fixed-point value.
Definition: entropy.h:42
static int rtc_entropy_check(void)
Check that entropy gathering is functional.
Definition: rtc_entropy.c:162
static uint8_t rtc_int_enabled
Previous RTC periodic interrupt enabled state.
Definition: rtc_entropy.c:60
static int rtc_enable_int(void)
Enable RTC interrupts.
Definition: rtc_entropy.c:118
static void rtc_disable_int(void)
Disable RTC interrupts.
Definition: rtc_entropy.c:143
static void rtc_unhook_isr(void)
Unhook RTC interrupt handler.
Definition: rtc_entropy.c:105
#define CPUID_FEATURES_INTEL_EDX_TSC
TSC is present.
Definition: cpuid.h:52
static void entropy_init(struct entropy_source *source, min_entropy_t min_entropy_per_sample)
Initialise entropy source.
Definition: entropy.h:489

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

static 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 )
256  rtc_disable_int();
257  if ( ! rtc_irq_enabled )
258  disable_irq ( RTC_IRQ );
259  rtc_unhook_isr();
260 }
static uint8_t rtc_irq_enabled
Previous RTC interrupt enabled state.
Definition: rtc_entropy.c:57
#define RTC_IRQ
RTC IRQ.
Definition: rtc.h:21
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.
Definition: rtc_entropy.c:143
static void rtc_unhook_isr(void)
Unhook RTC interrupt handler.
Definition: rtc_entropy.c:105

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

◆ rtc_get_noise()

static 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  {
270  uint32_t after;
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 }
int32_t before
Initial microcode version.
Definition: ucode.h:16
__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 int uint32_t
Definition: stdint.h:12
__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")
int32_t after
Final microcode version.
Definition: ucode.h:18
#define REAL_CODE(asm_code_str)
Definition: libkir.h:226

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().