mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-03 21:48:15 +00:00 
			
		
		
		
	The existence of devices should be checked in the bind method and not in
the probe method. Adjust the RISC-V Zkr RNG driver accordingly.
Use ENOENT (and not ENODEV) to signal that the device is not available.
Fixes: ceec977ba1a9 ("rng: Provide a RNG based on the RISC-V Zkr ISA extension")
Reported-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
		
	
			
		
			
				
	
	
		
			135 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
/*
 | 
						|
 * The RISC-V Zkr extension provides CSR seed which provides access to a
 | 
						|
 * random number generator.
 | 
						|
 */
 | 
						|
 | 
						|
#define LOG_CATEGORY UCLASS_RNG
 | 
						|
 | 
						|
#include <dm.h>
 | 
						|
#include <interrupt.h>
 | 
						|
#include <log.h>
 | 
						|
#include <rng.h>
 | 
						|
 | 
						|
#define DRIVER_NAME "riscv_zkr"
 | 
						|
 | 
						|
enum opst {
 | 
						|
	/** @BIST: built in self test running */
 | 
						|
	BIST = 0b00,
 | 
						|
	/** @WAIT: sufficient amount of entropy is not yet available */
 | 
						|
	WAIT = 0b01,
 | 
						|
	/** @ES16: 16bits of entropy available */
 | 
						|
	ES16 = 0b10,
 | 
						|
	/** @DEAD: unrecoverable self-test error */
 | 
						|
	DEAD = 0b11,
 | 
						|
};
 | 
						|
 | 
						|
static unsigned long read_seed(void)
 | 
						|
{
 | 
						|
	unsigned long ret;
 | 
						|
 | 
						|
	__asm__ __volatile__("csrrw %0, seed, x0" : "=r" (ret) : : "memory");
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int riscv_zkr_read(struct udevice *dev, void *data, size_t len)
 | 
						|
{
 | 
						|
	u8 *ptr = data;
 | 
						|
 | 
						|
	while (len) {
 | 
						|
		u32 val;
 | 
						|
 | 
						|
		val = read_seed();
 | 
						|
 | 
						|
		switch (val >> 30) {
 | 
						|
		case BIST:
 | 
						|
			continue;
 | 
						|
		case WAIT:
 | 
						|
			continue;
 | 
						|
		case ES16:
 | 
						|
			*ptr++ = val & 0xff;
 | 
						|
			if (--len) {
 | 
						|
				*ptr++ = val >> 8;
 | 
						|
				--len;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case DEAD:
 | 
						|
			return -ENOENT;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * riscv_zkr_bind() - check if the seed register is available
 | 
						|
 *
 | 
						|
 * If the SBI software has not set mseccfg.sseed=1 or the Zkr extension is not
 | 
						|
 * available, reading the seed register will result in an exception from which
 | 
						|
 * this function safely resumes.
 | 
						|
 *
 | 
						|
 * @dev:	RNG device
 | 
						|
 * Return:	0 if successfully probed
 | 
						|
 */
 | 
						|
static int riscv_zkr_bind(struct udevice *dev)
 | 
						|
{
 | 
						|
	struct resume_data resume;
 | 
						|
	int ret;
 | 
						|
	u32 val;
 | 
						|
 | 
						|
	/* Check if reading seed leads to interrupt */
 | 
						|
	set_resume(&resume);
 | 
						|
	ret = setjmp(resume.jump);
 | 
						|
	if (ret)
 | 
						|
		log_debug("Exception %ld reading seed CSR\n", resume.code);
 | 
						|
	else
 | 
						|
		val = read_seed();
 | 
						|
	set_resume(NULL);
 | 
						|
	if (ret)
 | 
						|
		return -ENOENT;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * riscv_zkr_probe() - check if entropy is available
 | 
						|
 *
 | 
						|
 * The bind method already checked that the seed register can be read without
 | 
						|
 * excpetiong. Here we wait for the self test to finish and entropy becoming
 | 
						|
 * available.
 | 
						|
 *
 | 
						|
 * @dev:	RNG device
 | 
						|
 * Return:	0 if successfully probed
 | 
						|
 */
 | 
						|
static int riscv_zkr_probe(struct udevice *dev)
 | 
						|
{
 | 
						|
	u32 val;
 | 
						|
 | 
						|
	do {
 | 
						|
		val = read_seed();
 | 
						|
		val >>= 30;
 | 
						|
	} while (val == BIST || val == WAIT);
 | 
						|
 | 
						|
	if (val == DEAD)
 | 
						|
		return -ENOENT;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static const struct dm_rng_ops riscv_zkr_ops = {
 | 
						|
	.read = riscv_zkr_read,
 | 
						|
};
 | 
						|
 | 
						|
U_BOOT_DRIVER(riscv_zkr) = {
 | 
						|
	.name = DRIVER_NAME,
 | 
						|
	.id = UCLASS_RNG,
 | 
						|
	.ops = &riscv_zkr_ops,
 | 
						|
	.bind = riscv_zkr_bind,
 | 
						|
	.probe = riscv_zkr_probe,
 | 
						|
};
 | 
						|
 | 
						|
U_BOOT_DRVINFO(cpu_riscv_zkr) = {
 | 
						|
	.name = DRIVER_NAME,
 | 
						|
};
 |