random.c (2954B)
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 11typedef union efi_rng_protocol efi_rng_protocol_t; 12 13union 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 */ 39efi_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 */ 65efi_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 status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA, 79 sizeof(*seed) + EFI_RANDOM_SEED_SIZE, 80 (void **)&seed); 81 if (status != EFI_SUCCESS) 82 return status; 83 84 status = efi_call_proto(rng, get_rng, &rng_algo_raw, 85 EFI_RANDOM_SEED_SIZE, seed->bits); 86 87 if (status == EFI_UNSUPPORTED) 88 /* 89 * Use whatever algorithm we have available if the raw algorithm 90 * is not implemented. 91 */ 92 status = efi_call_proto(rng, get_rng, NULL, 93 EFI_RANDOM_SEED_SIZE, seed->bits); 94 95 if (status != EFI_SUCCESS) 96 goto err_freepool; 97 98 seed->size = EFI_RANDOM_SEED_SIZE; 99 status = efi_bs_call(install_configuration_table, &rng_table_guid, seed); 100 if (status != EFI_SUCCESS) 101 goto err_freepool; 102 103 return EFI_SUCCESS; 104 105err_freepool: 106 efi_bs_call(free_pool, seed); 107 return status; 108}