2 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
27 #include <ipxe/entropy.h>
28 #include <ipxe/efi/efi.h>
36 /** Time (in 100ns units) to delay waiting for timer tick
38 * In theory, UEFI allows us to specify a trigger time of zero to
39 * simply wait for the next timer tick. In practice, specifying zero
40 * seems to often return immediately, which produces almost no
41 * entropy. Specify a delay of 1000ns to try to force an existent
44 #define EFI_ENTROPY_TRIGGER_TIME 10
46 /** Event used to wait for timer tick */
47 static EFI_EVENT tick
;
50 * Enable entropy gathering
52 * @ret rc Return status code
54 static int efi_entropy_enable ( void ) {
55 EFI_BOOT_SERVICES
*bs
= efi_systab
->BootServices
;
59 /* Create timer tick event */
60 if ( ( efirc
= bs
->CreateEvent ( EVT_TIMER
, TPL_NOTIFY
, NULL
, NULL
,
63 DBGC ( &tick
, "ENTROPY could not create event: %s\n",
72 * Disable entropy gathering
75 static void efi_entropy_disable ( void ) {
76 EFI_BOOT_SERVICES
*bs
= efi_systab
->BootServices
;
78 /* Close timer tick event */
79 bs
->CloseEvent ( tick
);
83 * Wait for an RTC tick
85 * @ret low TSC low-order bits, or negative error
87 static int efi_entropy_tick ( void ) {
88 EFI_BOOT_SERVICES
*bs
= efi_systab
->BootServices
;
95 /* Wait for next timer tick */
96 if ( ( efirc
= bs
->SetTimer ( tick
, TimerRelative
,
97 EFI_ENTROPY_TRIGGER_TIME
) ) != 0 ) {
99 DBGC ( &tick
, "ENTROPY could not set timer: %s\n",
103 if ( ( efirc
= bs
->WaitForEvent ( 1, &tick
, &index
) ) != 0 ) {
104 rc
= -EEFI ( efirc
);
105 DBGC ( &tick
, "ENTROPY could not wait for timer tick: %s\n",
110 /* Get current TSC low-order bits */
111 __asm__
__volatile__ ( "rdtsc" : "=a" ( low
), "=d" ( discard_d
) );
119 * @ret noise Noise sample
120 * @ret rc Return status code
122 static int efi_get_noise ( noise_sample_t
*noise
) {
127 /* Wait for a timer tick */
128 before
= efi_entropy_tick();
134 /* Wait for another timer tick */
135 after
= efi_entropy_tick();
141 /* Use TSC delta as noise sample */
142 *noise
= ( after
- before
);
147 PROVIDE_ENTROPY_INLINE ( efi
, min_entropy_per_sample
);
148 PROVIDE_ENTROPY ( efi
, entropy_enable
, efi_entropy_enable
);
149 PROVIDE_ENTROPY ( efi
, entropy_disable
, efi_entropy_disable
);
150 PROVIDE_ENTROPY ( efi
, get_noise
, efi_get_noise
);