Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2016 Linaro Ltd;  <ard.biesheuvel@linaro.org>
0004  */
0005 
0006 #include <linux/efi.h>
0007 #include <asm/efi.h>
0008 
0009 #include "efistub.h"
0010 
0011 typedef union efi_rng_protocol efi_rng_protocol_t;
0012 
0013 union efi_rng_protocol {
0014     struct {
0015         efi_status_t (__efiapi *get_info)(efi_rng_protocol_t *,
0016                           unsigned long *,
0017                           efi_guid_t *);
0018         efi_status_t (__efiapi *get_rng)(efi_rng_protocol_t *,
0019                          efi_guid_t *, unsigned long,
0020                          u8 *out);
0021     };
0022     struct {
0023         u32 get_info;
0024         u32 get_rng;
0025     } mixed_mode;
0026 };
0027 
0028 /**
0029  * efi_get_random_bytes() - fill a buffer with random bytes
0030  * @size:   size of the buffer
0031  * @out:    caller allocated buffer to receive the random bytes
0032  *
0033  * The call will fail if either the firmware does not implement the
0034  * EFI_RNG_PROTOCOL or there are not enough random bytes available to fill
0035  * the buffer.
0036  *
0037  * Return:  status code
0038  */
0039 efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
0040 {
0041     efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
0042     efi_status_t status;
0043     efi_rng_protocol_t *rng = NULL;
0044 
0045     status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng);
0046     if (status != EFI_SUCCESS)
0047         return status;
0048 
0049     return efi_call_proto(rng, get_rng, NULL, size, out);
0050 }
0051 
0052 /**
0053  * efi_random_get_seed() - provide random seed as configuration table
0054  *
0055  * The EFI_RNG_PROTOCOL is used to read random bytes. These random bytes are
0056  * saved as a configuration table which can be used as entropy by the kernel
0057  * for the initialization of its pseudo random number generator.
0058  *
0059  * If the EFI_RNG_PROTOCOL is not available or there are not enough random bytes
0060  * available, the configuration table will not be installed and an error code
0061  * will be returned.
0062  *
0063  * Return:  status code
0064  */
0065 efi_status_t efi_random_get_seed(void)
0066 {
0067     efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
0068     efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW;
0069     efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID;
0070     efi_rng_protocol_t *rng = NULL;
0071     struct linux_efi_random_seed *seed = NULL;
0072     efi_status_t status;
0073 
0074     status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng);
0075     if (status != EFI_SUCCESS)
0076         return status;
0077 
0078     status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA,
0079                  sizeof(*seed) + EFI_RANDOM_SEED_SIZE,
0080                  (void **)&seed);
0081     if (status != EFI_SUCCESS)
0082         return status;
0083 
0084     status = efi_call_proto(rng, get_rng, &rng_algo_raw,
0085                  EFI_RANDOM_SEED_SIZE, seed->bits);
0086 
0087     if (status == EFI_UNSUPPORTED)
0088         /*
0089          * Use whatever algorithm we have available if the raw algorithm
0090          * is not implemented.
0091          */
0092         status = efi_call_proto(rng, get_rng, NULL,
0093                     EFI_RANDOM_SEED_SIZE, seed->bits);
0094 
0095     if (status != EFI_SUCCESS)
0096         goto err_freepool;
0097 
0098     seed->size = EFI_RANDOM_SEED_SIZE;
0099     status = efi_bs_call(install_configuration_table, &rng_table_guid, seed);
0100     if (status != EFI_SUCCESS)
0101         goto err_freepool;
0102 
0103     return EFI_SUCCESS;
0104 
0105 err_freepool:
0106     efi_bs_call(free_pool, seed);
0107     return status;
0108 }