1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2016 Linaro Ltd; <ard.biesheuvel@linaro.org> 4 */ 5 6 #include <linux/efi.h> 7 #include <asm/efi.h> 8 9 #include "efistub.h" 10 11 typedef union efi_rng_protocol efi_rng_protocol_t; 12 13 union efi_rng_protocol { 14 struct { 15 efi_status_t (__efiapi *get_info)(efi_rng_protocol_t *, 16 unsigned long *, 17 efi_guid_t *); 18 efi_status_t (__efiapi *get_rng)(efi_rng_protocol_t *, 19 efi_guid_t *, unsigned long, 20 u8 *out); 21 }; 22 struct { 23 u32 get_info; 24 u32 get_rng; 25 } mixed_mode; 26 }; 27 28 /** 29 * efi_get_random_bytes() - fill a buffer with random bytes 30 * @size: size of the buffer 31 * @out: caller allocated buffer to receive the random bytes 32 * 33 * The call will fail if either the firmware does not implement the 34 * EFI_RNG_PROTOCOL or there are not enough random bytes available to fill 35 * the buffer. 36 * 37 * Return: status code 38 */ 39 efi_status_t efi_get_random_bytes(unsigned long size, u8 *out) 40 { 41 efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID; 42 efi_status_t status; 43 efi_rng_protocol_t *rng = NULL; 44 45 status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng); 46 if (status != EFI_SUCCESS) 47 return status; 48 49 return efi_call_proto(rng, get_rng, NULL, size, out); 50 } 51 52 /** 53 * efi_random_get_seed() - provide random seed as configuration table 54 * 55 * The EFI_RNG_PROTOCOL is used to read random bytes. These random bytes are 56 * saved as a configuration table which can be used as entropy by the kernel 57 * for the initialization of its pseudo random number generator. 58 * 59 * If the EFI_RNG_PROTOCOL is not available or there are not enough random bytes 60 * available, the configuration table will not be installed and an error code 61 * will be returned. 62 * 63 * Return: status code 64 */ 65 efi_status_t efi_random_get_seed(void) 66 { 67 efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID; 68 efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW; 69 efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID; 70 efi_rng_protocol_t *rng = NULL; 71 struct linux_efi_random_seed *seed = NULL; 72 efi_status_t status; 73 74 status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng); 75 if (status != EFI_SUCCESS) 76 return status; 77 78 /* 79 * Use EFI_ACPI_RECLAIM_MEMORY here so that it is guaranteed that the 80 * allocation will survive a kexec reboot (although we refresh the seed 81 * beforehand) 82 */ 83 status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, 84 sizeof(*seed) + EFI_RANDOM_SEED_SIZE, 85 (void **)&seed); 86 if (status != EFI_SUCCESS) 87 return status; 88 89 status = efi_call_proto(rng, get_rng, &rng_algo_raw, 90 EFI_RANDOM_SEED_SIZE, seed->bits); 91 92 if (status == EFI_UNSUPPORTED) 93 /* 94 * Use whatever algorithm we have available if the raw algorithm 95 * is not implemented. 96 */ 97 status = efi_call_proto(rng, get_rng, NULL, 98 EFI_RANDOM_SEED_SIZE, seed->bits); 99 100 if (status != EFI_SUCCESS) 101 goto err_freepool; 102 103 seed->size = EFI_RANDOM_SEED_SIZE; 104 status = efi_bs_call(install_configuration_table, &rng_table_guid, seed); 105 if (status != EFI_SUCCESS) 106 goto err_freepool; 107 108 return EFI_SUCCESS; 109 110 err_freepool: 111 efi_bs_call(free_pool, seed); 112 return status; 113 } 114