blob: 31958dba7ffa5c38b01d0afbbce90e501ad7282d [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>
Elyes Haouas9523e3b2022-11-08 14:38:41 +01004#include <types.h>
Robbie Zhang18792312017-02-13 13:44:14 -08005
6/*
7 * Intel recommends that applications attempt 10 retries in a tight loop
8 * in the unlikely event that the RDRAND instruction does not successfully
9 * return a random number. The odds of ten failures in a row would in fact
10 * be an indication of a larger CPU issue.
11 */
12#define RDRAND_RETRY_LOOPS 10
13
14/*
15 * Generate a 32-bit random number through RDRAND instruction.
16 * Carry flag is set on RDRAND success and 0 on failure.
17 */
18static inline uint8_t rdrand_32(uint32_t *rand)
19{
20 uint8_t carry;
21
22 __asm__ __volatile__(
23 ".byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1"
24 : "=a" (*rand), "=qm" (carry));
25 return carry;
26}
27
Stefan Reinauer0380e0a2017-06-21 12:40:15 -070028#if ENV_X86_64
Robbie Zhang18792312017-02-13 13:44:14 -080029/*
30 * Generate a 64-bit random number through RDRAND instruction.
31 * Carry flag is set on RDRAND success and 0 on failure.
32 */
33static inline uint8_t rdrand_64(uint64_t *rand)
34{
35 uint8_t carry;
36
37 __asm__ __volatile__(
38 ".byte 0x48; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1"
39 : "=a" (*rand), "=qm" (carry));
40 return carry;
41}
Stefan Reinauer0380e0a2017-06-21 12:40:15 -070042#endif
Robbie Zhang18792312017-02-13 13:44:14 -080043
Elyes Haouas9523e3b2022-11-08 14:38:41 +010044enum cb_err get_random_number_32(uint32_t *rand)
Robbie Zhang18792312017-02-13 13:44:14 -080045{
46 int i;
47
48 /* Perform a loop call until RDRAND succeeds or returns failure. */
49 for (i = 0; i < RDRAND_RETRY_LOOPS; i++) {
50 if (rdrand_32(rand))
Elyes Haouas9523e3b2022-11-08 14:38:41 +010051 return CB_SUCCESS;
Robbie Zhang18792312017-02-13 13:44:14 -080052 }
Elyes Haouas9523e3b2022-11-08 14:38:41 +010053 return CB_ERR;
Robbie Zhang18792312017-02-13 13:44:14 -080054}
55
Elyes Haouas9523e3b2022-11-08 14:38:41 +010056enum cb_err get_random_number_64(uint64_t *rand)
Robbie Zhang18792312017-02-13 13:44:14 -080057{
58 int i;
59 uint32_t rand_high, rand_low;
60
61 /* Perform a loop call until RDRAND succeeds or returns failure. */
62 for (i = 0; i < RDRAND_RETRY_LOOPS; i++) {
Stefan Reinauer0380e0a2017-06-21 12:40:15 -070063#if ENV_X86_64
64 if (rdrand_64(rand))
Elyes Haouas9523e3b2022-11-08 14:38:41 +010065 return CB_SUCCESS;
Stefan Reinauer0380e0a2017-06-21 12:40:15 -070066#endif
67 if (rdrand_32(&rand_high) && rdrand_32(&rand_low)) {
Robbie Zhang18792312017-02-13 13:44:14 -080068 *rand = ((uint64_t)rand_high << 32) |
69 (uint64_t)rand_low;
Elyes Haouas9523e3b2022-11-08 14:38:41 +010070 return CB_SUCCESS;
Robbie Zhang18792312017-02-13 13:44:14 -080071 }
72 }
Elyes Haouas9523e3b2022-11-08 14:38:41 +010073 return CB_ERR;
Robbie Zhang18792312017-02-13 13:44:14 -080074}