mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-12-19 16:31:27 +01:00
u-boot internals were being corrupted following an EFI callback to get_rng(). One of the many footprints was a corruption of the EFI protocols linked list. A request for >16 bytes of random data is broken into smaller requests. Those requests are fed in a loop to the CAAM RNG, which uses a job queue ring for interaction. However, the job queue descriptor is created only at probe time. That descriptor may end up needing an endian swap (LS1046A) before being fed to the CAAM RNG. This corrupts the descriptor for the next iteration, since it will be blindly endian swapped yet again. Two issues arise. The number of words to endian swap is taken from the input descriptor itself. So on the second iteration, the length has been corrupted. This results in a corruption past the end of the descriptor: whatever is after in memory is endian swapped too. Second, some of the entries in the descriptor are DMA addresses. If the descriptor is still somehow considered valid after swapping, the data at the corrupted DMA address is now trampled. Linux properly initializes the descriptor for each iteration. This is what is now done with this commit. Signed-off-by: Anthony Pighin <anthony.pighin@nokia.com> Signed-off-by: Peng Fan <peng.fan@nxp.com>
99 lines
2.0 KiB
C
99 lines
2.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) 2020 Michael Walle <michael@walle.cc>
|
|
*
|
|
* Driver for Freescale Cryptographic Accelerator and Assurance
|
|
* Module (CAAM) hardware random number generator.
|
|
*/
|
|
|
|
#include <asm/cache.h>
|
|
#include <cpu_func.h>
|
|
#include <dm.h>
|
|
#include <rng.h>
|
|
#include <linux/kernel.h>
|
|
#include "desc_constr.h"
|
|
#include "jobdesc.h"
|
|
#include "jr.h"
|
|
|
|
#define CAAM_RNG_MAX_FIFO_STORE_SIZE 16
|
|
#define CAAM_RNG_DESC_LEN (3 * CAAM_CMD_SZ + CAAM_PTR_SZ)
|
|
|
|
struct caam_rng_priv {
|
|
u32 desc[CAAM_RNG_DESC_LEN / 4];
|
|
u8 data[CAAM_RNG_MAX_FIFO_STORE_SIZE] __aligned(ARCH_DMA_MINALIGN);
|
|
};
|
|
|
|
static int caam_init_desc(struct caam_rng_priv *priv)
|
|
{
|
|
ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN);
|
|
|
|
inline_cnstr_jobdesc_rng(priv->desc, priv->data,
|
|
CAAM_RNG_MAX_FIFO_STORE_SIZE);
|
|
|
|
flush_dcache_range((unsigned long)priv->desc,
|
|
(unsigned long)priv->desc + size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int caam_rng_read_one(struct caam_rng_priv *priv)
|
|
{
|
|
int size = ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE, ARCH_DMA_MINALIGN);
|
|
int ret;
|
|
|
|
caam_init_desc(priv);
|
|
|
|
ret = run_descriptor_jr(priv->desc);
|
|
if (ret < 0)
|
|
return -EIO;
|
|
|
|
invalidate_dcache_range((unsigned long)priv->data,
|
|
(unsigned long)priv->data + size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int caam_rng_read(struct udevice *dev, void *data, size_t len)
|
|
{
|
|
struct caam_rng_priv *priv = dev_get_priv(dev);
|
|
u8 *buffer = data;
|
|
size_t size;
|
|
int ret;
|
|
|
|
while (len) {
|
|
ret = caam_rng_read_one(priv);
|
|
if (ret)
|
|
return ret;
|
|
|
|
size = min(len, (size_t)CAAM_RNG_MAX_FIFO_STORE_SIZE);
|
|
|
|
memcpy(buffer, priv->data, size);
|
|
buffer += size;
|
|
len -= size;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int caam_rng_probe(struct udevice *dev)
|
|
{
|
|
struct caam_rng_priv *priv = dev_get_priv(dev);
|
|
|
|
caam_init_desc(priv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct dm_rng_ops caam_rng_ops = {
|
|
.read = caam_rng_read,
|
|
};
|
|
|
|
U_BOOT_DRIVER(caam_rng) = {
|
|
.name = "caam-rng",
|
|
.id = UCLASS_RNG,
|
|
.ops = &caam_rng_ops,
|
|
.probe = caam_rng_probe,
|
|
.priv_auto = sizeof(struct caam_rng_priv),
|
|
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
|
};
|