Browse Source

[rng] Add RTC-based entropy source

The RTC-based entropy source uses the nanosecond-scale CPU TSC to
measure the time between two 1kHz interrupts generated by the CMOS
RTC.  In a physical machine these clocks are driven from independent
crystals, resulting in some observable clock drift.  In a virtual
machine, the CMOS RTC is typically emulated using host-OS
constructions such as SIGALRM.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
05719804b9

+ 2
- 0
src/arch/i386/include/bits/entropy.h View File

@@ -9,4 +9,6 @@
9 9
 
10 10
 FILE_LICENCE ( GPL2_OR_LATER );
11 11
 
12
+#include <ipxe/rtc_entropy.h>
13
+
12 14
 #endif /* _BITS_ENTROPY_H */

+ 62
- 0
src/arch/i386/include/ipxe/rtc_entropy.h View File

@@ -0,0 +1,62 @@
1
+#ifndef _IPXE_RTC_ENTROPY_H
2
+#define _IPXE_RTC_ENTROPY_H
3
+
4
+/** @file
5
+ *
6
+ * RTC-based entropy source
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <stdint.h>
13
+
14
+#ifdef ENTROPY_RTC
15
+#define ENTROPY_PREFIX_rtc
16
+#else
17
+#define ENTROPY_PREFIX_rtc __rtc_
18
+#endif
19
+
20
+/**
21
+ * min-entropy per sample
22
+ *
23
+ * @ret min_entropy	min-entropy of each sample
24
+ */
25
+static inline __always_inline double
26
+ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
27
+
28
+	/* The min-entropy has been measured on several platforms
29
+	 * using the entropy_sample test code.  Modelling the samples
30
+	 * as independent, and using a confidence level of 99.99%, the
31
+	 * measurements were as follows:
32
+	 *
33
+	 *    qemu-kvm		: 7.38 bits
34
+	 *    VMware		: 7.46 bits
35
+	 *    Physical hardware	: 2.67 bits
36
+	 *
37
+	 * We choose the lowest of these (2.67 bits) and apply a 50%
38
+	 * safety margin to allow for some potential non-independence
39
+	 * of samples.
40
+	 */
41
+	return 1.3;
42
+}
43
+
44
+extern uint8_t rtc_sample ( void );
45
+
46
+/**
47
+ * Get noise sample
48
+ *
49
+ * @ret noise		Noise sample
50
+ * @ret rc		Return status code
51
+ */
52
+static inline __always_inline int
53
+ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) {
54
+
55
+	/* Get sample */
56
+	*noise = rtc_sample();
57
+
58
+	/* Always successful */
59
+	return 0;
60
+}
61
+
62
+#endif /* _IPXE_RTC_ENTROPY_H */

+ 233
- 0
src/arch/i386/interface/pcbios/rtc_entropy.c View File

@@ -0,0 +1,233 @@
1
+/*
2
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+/** @file
22
+ *
23
+ * RTC-based entropy source
24
+ *
25
+ * The CMOS/RTC registers are documented (with varying degrees of
26
+ * accuracy and consistency) at
27
+ *
28
+ *    http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt
29
+ *    http://wiki.osdev.org/RTC
30
+ *    http://wiki.osdev.org/CMOS
31
+ */
32
+
33
+#include <stdint.h>
34
+#include <string.h>
35
+#include <biosint.h>
36
+#include <pic8259.h>
37
+#include <ipxe/entropy.h>
38
+
39
+/** RTC IRQ */
40
+#define RTC_IRQ 8
41
+
42
+/** RTC interrupt vector */
43
+#define RTC_INT IRQ_INT ( RTC_IRQ )
44
+
45
+/** CMOS/RTC address (and NMI) register */
46
+#define CMOS_ADDRESS 0x70
47
+
48
+/** NMI disable bit */
49
+#define CMOS_DISABLE_NMI 0x80
50
+
51
+/** CMOS/RTC data register */
52
+#define CMOS_DATA 0x71
53
+
54
+/** RTC status register A */
55
+#define RTC_STATUS_A 0x0a
56
+
57
+/** RTC status register B */
58
+#define RTC_STATUS_B 0x0b
59
+
60
+/** RTC Periodic Interrupt Enabled bit */
61
+#define RTC_STATUS_B_PIE 0x40
62
+
63
+/** RTC status register C */
64
+#define RTC_STATUS_C 0x0c
65
+
66
+/** RTC status register D */
67
+#define RTC_STATUS_D 0x0d
68
+
69
+/** CMOS default address */
70
+#define CMOS_DEFAULT_ADDRESS RTC_STATUS_D
71
+
72
+/** RTC "interrupt triggered" flag */
73
+static uint8_t __text16 ( rtc_flag );
74
+#define rtc_flag __use_text16 ( rtc_flag )
75
+
76
+/** RTC interrupt handler */
77
+extern void rtc_isr ( void );
78
+
79
+/** Previous RTC interrupt handler */
80
+static struct segoff rtc_old_handler;
81
+
82
+/**
83
+ * Hook RTC interrupt handler
84
+ *
85
+ */
86
+static void rtc_hook_isr ( void ) {
87
+
88
+	/* RTC interrupt handler */
89
+	__asm__ __volatile__ (
90
+		TEXT16_CODE ( "\nrtc_isr:\n\t"
91
+			      /* Preserve registers */
92
+			      "pushw %%ax\n\t"
93
+			      /* Set "interrupt triggered" flag */
94
+			      "cs movb $0x01, %c0\n\t"
95
+			      /* Read RTC status register C to
96
+			       * acknowledge interrupt
97
+			       */
98
+			      "movb %3, %%al\n\t"
99
+			      "outb %%al, %1\n\t"
100
+			      "inb %2\n\t"
101
+			      /* Send EOI */
102
+			      "movb $0x20, %%al\n\t"
103
+			      "outb %%al, $0xa0\n\t"
104
+			      "outb %%al, $0x20\n\t"
105
+			      /* Restore registers and return */
106
+			      "popw %%ax\n\t"
107
+			      "iret\n\t" )
108
+		:
109
+		: "p" ( __from_text16 ( &rtc_flag ) ),
110
+		  "i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ),
111
+		  "i" ( RTC_STATUS_C ) );
112
+
113
+	hook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
114
+			      &rtc_old_handler );
115
+}
116
+
117
+/**
118
+ * Unhook RTC interrupt handler
119
+ *
120
+ */
121
+static void rtc_unhook_isr ( void ) {
122
+	int rc;
123
+
124
+	rc = unhook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
125
+				     &rtc_old_handler );
126
+	assert ( rc == 0 ); /* Should always be able to unhook */
127
+}
128
+
129
+/**
130
+ * Enable RTC interrupts
131
+ *
132
+ */
133
+static void rtc_enable_int ( void ) {
134
+	uint8_t status_b;
135
+
136
+	/* Set Periodic Interrupt Enable bit in status register B */
137
+	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
138
+	status_b = inb ( CMOS_DATA );
139
+	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
140
+	outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA );
141
+
142
+	/* Re-enable NMI and reset to default address */
143
+	outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
144
+	inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
145
+}
146
+
147
+/**
148
+ * Disable RTC interrupts
149
+ *
150
+ */
151
+static void rtc_disable_int ( void ) {
152
+	uint8_t status_b;
153
+
154
+	/* Clear Periodic Interrupt Enable bit in status register B */
155
+	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
156
+	status_b = inb ( CMOS_DATA );
157
+	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
158
+	outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA );
159
+
160
+	/* Re-enable NMI and reset to default address */
161
+	outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
162
+	inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
163
+}
164
+
165
+/**
166
+ * Enable entropy gathering
167
+ *
168
+ */
169
+static void rtc_entropy_enable ( void ) {
170
+
171
+	rtc_hook_isr();
172
+	enable_irq ( RTC_IRQ );
173
+	rtc_enable_int();
174
+}
175
+
176
+/**
177
+ * Disable entropy gathering
178
+ *
179
+ */
180
+static void rtc_entropy_disable ( void ) {
181
+
182
+	rtc_disable_int();
183
+	disable_irq ( RTC_IRQ );
184
+	rtc_unhook_isr();
185
+}
186
+
187
+/**
188
+ * Measure a single RTC tick
189
+ *
190
+ * @ret delta		Length of RTC tick (in TSC units)
191
+ */
192
+uint8_t rtc_sample ( void ) {
193
+	uint32_t before;
194
+	uint32_t after;
195
+	uint32_t temp;
196
+
197
+	__asm__ __volatile__ (
198
+		REAL_CODE ( /* Enable interrupts */
199
+			    "sti\n\t"
200
+			    /* Wait for RTC interrupt */
201
+			    "cs movb %b2, %c4\n\t"
202
+			    "\n1:\n\t"
203
+			    "cs xchgb %b2, %c4\n\t" /* Serialize */
204
+			    "testb %b2, %b2\n\t"
205
+			    "jz 1b\n\t"
206
+			    /* Read "before" TSC */
207
+			    "rdtsc\n\t"
208
+			    /* Store "before" TSC on stack */
209
+			    "pushl %0\n\t"
210
+			    /* Wait for another RTC interrupt */
211
+			    "xorb %b2, %b2\n\t"
212
+			    "cs movb %b2, %c4\n\t"
213
+			    "\n1:\n\t"
214
+			    "cs xchgb %b2, %c4\n\t" /* Serialize */
215
+			    "testb %b2, %b2\n\t"
216
+			    "jz 1b\n\t"
217
+			    /* Read "after" TSC */
218
+			    "rdtsc\n\t"
219
+			    /* Retrieve "before" TSC on stack */
220
+			    "popl %1\n\t"
221
+			    /* Disable interrupts */
222
+			    "cli\n\t"
223
+			    )
224
+		: "=a" ( after ), "=d" ( before ), "=q" ( temp )
225
+		: "2" ( 0 ), "p" ( __from_text16 ( &rtc_flag ) ) );
226
+
227
+	return ( after - before );
228
+}
229
+
230
+PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
231
+PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
232
+PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
233
+PROVIDE_ENTROPY_INLINE ( rtc, get_noise );

+ 1
- 1
src/config/defaults/pcbios.h View File

@@ -18,7 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
18 18
 #define UMALLOC_MEMTOP
19 19
 #define SMBIOS_PCBIOS
20 20
 #define SANBOOT_PCBIOS
21
-#define ENTROPY_NULL
21
+#define ENTROPY_RTC
22 22
 
23 23
 #define	IMAGE_ELF		/* ELF image support */
24 24
 #define	IMAGE_MULTIBOOT		/* MultiBoot image support */

Loading…
Cancel
Save