iPXE
efi_entropy.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 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 (at your option) 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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_SECBOOT ( PERMITTED );
26 
27 #include <errno.h>
28 #include <ipxe/entropy.h>
29 #include <ipxe/profile.h>
30 #include <ipxe/efi/efi.h>
31 
32 /** @file
33  *
34  * EFI entropy source
35  *
36  */
37 
38 struct entropy_source efitick_entropy __entropy_source ( ENTROPY_FALLBACK );
39 
40 /** Time (in 100ns units) to delay waiting for timer tick
41  *
42  * In theory, UEFI allows us to specify a trigger time of zero to
43  * simply wait for the next timer tick. In practice, specifying zero
44  * seems to often return immediately, which produces almost no
45  * entropy. Specify a delay of 1000ns to try to force an existent
46  * delay.
47  */
48 #define EFI_ENTROPY_TRIGGER_TIME 10
49 
50 /** Event used to wait for timer tick */
51 static EFI_EVENT tick;
52 
53 /**
54  * Enable entropy gathering
55  *
56  * @ret rc Return status code
57  */
58 static int efi_entropy_enable ( void ) {
60  EFI_STATUS efirc;
61  int rc;
62 
63  /* Drop to external TPL to allow timer tick event to take place */
65 
66  /* Create timer tick event */
67  if ( ( efirc = bs->CreateEvent ( EVT_TIMER, TPL_NOTIFY, NULL, NULL,
68  &tick ) ) != 0 ) {
69  rc = -EEFI ( efirc );
70  DBGC ( &tick, "ENTROPY could not create event: %s\n",
71  strerror ( rc ) );
72  return rc;
73  }
74 
75  /* We use essentially the same mechanism as for the BIOS
76  * RTC-based entropy source, and so assume the same
77  * min-entropy per sample.
78  */
79  entropy_init ( &efitick_entropy, MIN_ENTROPY ( 1.3 ) );
80 
81  return 0;
82 }
83 
84 /**
85  * Disable entropy gathering
86  *
87  */
88 static void efi_entropy_disable ( void ) {
90 
91  /* Close timer tick event */
92  bs->CloseEvent ( tick );
93 
94  /* Return to internal TPL */
95  bs->RaiseTPL ( efi_internal_tpl );
96 }
97 
98 /**
99  * Wait for a timer tick
100  *
101  * @ret low CPU profiling low-order bits, or negative error
102  */
103 static int efi_entropy_tick ( void ) {
105  UINTN index;
106  uint16_t low;
107  EFI_STATUS efirc;
108  int rc;
109 
110  /* Wait for next timer tick */
111  if ( ( efirc = bs->SetTimer ( tick, TimerRelative,
112  EFI_ENTROPY_TRIGGER_TIME ) ) != 0 ) {
113  rc = -EEFI ( efirc );
114  DBGC ( &tick, "ENTROPY could not set timer: %s\n",
115  strerror ( rc ) );
116  return rc;
117  }
118  if ( ( efirc = bs->WaitForEvent ( 1, &tick, &index ) ) != 0 ) {
119  rc = -EEFI ( efirc );
120  DBGC ( &tick, "ENTROPY could not wait for timer tick: %s\n",
121  strerror ( rc ) );
122  return rc;
123  }
124 
125  /* Get current CPU profiling timestamp low-order bits */
127 
128  return low;
129 }
130 
131 /**
132  * Get noise sample from timer ticks
133  *
134  * @ret noise Noise sample
135  * @ret rc Return status code
136  */
137 static int efi_get_noise ( noise_sample_t *noise ) {
138  int before;
139  int after;
140  int rc;
141 
142  /* Wait for a timer tick */
144  if ( before < 0 ) {
145  rc = before;
146  return rc;
147  }
148 
149  /* Wait for another timer tick */
151  if ( after < 0 ) {
152  rc = after;
153  return rc;
154  }
155 
156  /* Use TSC delta as noise sample */
157  *noise = ( after - before );
158 
159  return 0;
160 }
161 
162 /** EFI entropy source */
163 struct entropy_source efitick_entropy __entropy_source ( ENTROPY_FALLBACK ) = {
164  .name = "efitick",
165  .enable = efi_entropy_enable,
166  .disable = efi_entropy_disable,
167  .get_noise = efi_get_noise,
168 };
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned short uint16_t
Definition: stdint.h:11
static int efi_entropy_tick(void)
Wait for a timer tick.
Definition: efi_entropy.c:103
uint32_t low
Low 16 bits of address.
Definition: myson.h:19
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:175
EFI_RAISE_TPL RaiseTPL
Definition: UefiSpec.h:1940
An event is to be signaled once at a specified interval from the current time.
Definition: UefiSpec.h:552
Error codes.
Definition: efi.h:63
static EFI_EVENT tick
Event used to wait for timer tick.
Definition: efi_entropy.c:51
static int efi_get_noise(noise_sample_t *noise)
Get noise sample from timer ticks.
Definition: efi_entropy.c:137
#define DBGC(...)
Definition: compiler.h:505
int32_t before
Initial microcode version.
Definition: ucode.h:16
long index
Definition: bigint.h:65
EFI_CLOSE_EVENT CloseEvent
Definition: UefiSpec.h:1959
EFI_SET_TIMER SetTimer
Definition: UefiSpec.h:1956
#define EFI_ENTROPY_TRIGGER_TIME
Time (in 100ns units) to delay waiting for timer tick.
Definition: efi_entropy.c:48
struct entropy_source efitick_entropy __entropy_source(ENTROPY_FALLBACK)
EFI entropy source.
static void efi_entropy_disable(void)
Disable entropy gathering.
Definition: efi_entropy.c:88
EFI_TPL efi_internal_tpl
Internal task priority level.
Definition: efi_init.c:54
An entropy source.
Definition: entropy.h:117
#define TPL_NOTIFY
Definition: UefiSpec.h:650
const char * name
Name.
Definition: entropy.h:119
static int efi_entropy_enable(void)
Enable entropy gathering.
Definition: efi_entropy.c:58
EFI_CREATE_EVENT CreateEvent
Definition: UefiSpec.h:1955
Profiling.
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
EFI Boot Services Table.
Definition: UefiSpec.h:1931
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
UINT64 UINTN
Unsigned value of native width.
EFI_WAIT_FOR_EVENT WaitForEvent
Definition: UefiSpec.h:1957
#define MIN_ENTROPY(bits)
Construct a min-entropy fixed-point value.
Definition: entropy.h:43
EFI API.
#define ENTROPY_FALLBACK
Fallback entropy source.
Definition: entropy.h:182
FILE_SECBOOT(PERMITTED)
int32_t after
Final microcode version.
Definition: ucode.h:18
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
unsigned long profile_timestamp(void)
uint8_t noise_sample_t
A noise sample.
Definition: entropy.h:22
EFI_SYSTEM_TABLE * efi_systab
EFI_RESTORE_TPL RestoreTPL
Definition: UefiSpec.h:1941
static void entropy_init(struct entropy_source *source, min_entropy_t min_entropy_per_sample)
Initialise entropy source.
Definition: entropy.h:490
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
Entropy source.
#define EVT_TIMER
Definition: UefiSpec.h:451
EFI_TPL efi_external_tpl
External task priority level.
Definition: efi_init.c:57