blob: 5374933b5e0c4c8f051982139d449473bf99f7c6 [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Robbie Zhang18792312017-02-13 13:44:14 -08002
3#include <random.h>
Robbie Zhang18792312017-02-13 13:44:14 -08004
5/*
6 * Intel recommends that applications attempt 10 retries in a tight loop
7 * in the unlikely event that the RDRAND instruction does not successfully
8 * return a random number. The odds of ten failures in a row would in fact
9 * be an indication of a larger CPU issue.
10 */
11#define RDRAND_RETRY_LOOPS 10
12
13/*
14 * Generate a 32-bit random number through RDRAND instruction.
15 * Carry flag is set on RDRAND success and 0 on failure.
16 */
17static inline uint8_t rdrand_32(uint32_t *rand)
18{
19 uint8_t carry;
20
21 __asm__ __volatile__(
22 ".byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1"
23 : "=a" (*rand), "=qm" (carry));
24 return carry;
25}
26
Stefan Reinauer0380e0a2017-06-21 12:40:15 -070027#if ENV_X86_64
Robbie Zhang18792312017-02-13 13:44:14 -080028/*
29 * Generate a 64-bit random number through RDRAND instruction.
30 * Carry flag is set on RDRAND success and 0 on failure.
31 */
32static inline uint8_t rdrand_64(uint64_t *rand)
33{
34 uint8_t carry;
35
36 __asm__ __volatile__(
37 ".byte 0x48; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1"
38 : "=a" (*rand), "=qm" (carry));
39 return carry;
40}
Stefan Reinauer0380e0a2017-06-21 12:40:15 -070041#endif
Robbie Zhang18792312017-02-13 13:44:14 -080042
43int get_random_number_32(uint32_t *rand)
44{
45 int i;
46
47 /* Perform a loop call until RDRAND succeeds or returns failure. */
48 for (i = 0; i < RDRAND_RETRY_LOOPS; i++) {
49 if (rdrand_32(rand))
50 return 0;
51 }
52 return -1;
53}
54
55int get_random_number_64(uint64_t *rand)
56{
57 int i;
58 uint32_t rand_high, rand_low;
59
60 /* Perform a loop call until RDRAND succeeds or returns failure. */
61 for (i = 0; i < RDRAND_RETRY_LOOPS; i++) {
Stefan Reinauer0380e0a2017-06-21 12:40:15 -070062#if ENV_X86_64
63 if (rdrand_64(rand))
Robbie Zhang18792312017-02-13 13:44:14 -080064 return 0;
Stefan Reinauer0380e0a2017-06-21 12:40:15 -070065#endif
66 if (rdrand_32(&rand_high) && rdrand_32(&rand_low)) {
Robbie Zhang18792312017-02-13 13:44:14 -080067 *rand = ((uint64_t)rand_high << 32) |
68 (uint64_t)rand_low;
69 return 0;
70 }
71 }
72 return -1;
73}