1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <random.h> 4 #include <types.h> 5 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 */ rdrand_32(uint32_t * rand)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 28 #if ENV_X86_64 29 /* 30 * Generate a 64-bit random number through RDRAND instruction. 31 * Carry flag is set on RDRAND success and 0 on failure. 32 */ rdrand_64(uint64_t * rand)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 } 42 #endif 43 get_random_number_32(uint32_t * rand)44enum cb_err get_random_number_32(uint32_t *rand) 45 { 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)) 51 return CB_SUCCESS; 52 } 53 return CB_ERR; 54 } 55 get_random_number_64(uint64_t * rand)56enum cb_err get_random_number_64(uint64_t *rand) 57 { 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++) { 63 #if ENV_X86_64 64 if (rdrand_64(rand)) 65 return CB_SUCCESS; 66 #endif 67 if (rdrand_32(&rand_high) && rdrand_32(&rand_low)) { 68 *rand = ((uint64_t)rand_high << 32) | 69 (uint64_t)rand_low; 70 return CB_SUCCESS; 71 } 72 } 73 return CB_ERR; 74 } 75