cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}