xref: /optee_os/core/drivers/riscv_zkr_rng.c (revision 47fd72092aa569f9da13393ed5387af5945e7ef5)
1fb605d4bSYu Chien Peter Lin // SPDX-License-Identifier: BSD-2-Clause
2fb605d4bSYu Chien Peter Lin /*
3fb605d4bSYu Chien Peter Lin  * Copyright (c) 2024 Andes Technology Corporation
4fb605d4bSYu Chien Peter Lin  */
5fb605d4bSYu Chien Peter Lin 
6fb605d4bSYu Chien Peter Lin #include <crypto/crypto.h>
7*47fd7209SYu Chien Peter Lin #include <encoding.h>
8*47fd7209SYu Chien Peter Lin #include <kernel/delay.h>
9fb605d4bSYu Chien Peter Lin #include <kernel/panic.h>
10fb605d4bSYu Chien Peter Lin #include <riscv.h>
11fb605d4bSYu Chien Peter Lin #include <rng_support.h>
12fb605d4bSYu Chien Peter Lin #include <tee/tee_cryp_utl.h>
13fb605d4bSYu Chien Peter Lin 
14*47fd7209SYu Chien Peter Lin #define RNG_TIMEOUT_US	1000000
15*47fd7209SYu Chien Peter Lin 
seed_get_random_u16(uint16_t * val)16*47fd7209SYu Chien Peter Lin static bool __must_check seed_get_random_u16(uint16_t *val)
17*47fd7209SYu Chien Peter Lin {
18*47fd7209SYu Chien Peter Lin 	uint64_t timeout = timeout_init_us(RNG_TIMEOUT_US);
19*47fd7209SYu Chien Peter Lin 	uint32_t seed = 0;
20*47fd7209SYu Chien Peter Lin 	uint32_t opst = 0;
21*47fd7209SYu Chien Peter Lin 
22*47fd7209SYu Chien Peter Lin 	do {
23*47fd7209SYu Chien Peter Lin 		/*
24*47fd7209SYu Chien Peter Lin 		 * The seed register must be accessed using CSR
25*47fd7209SYu Chien Peter Lin 		 * read-write instructions. The write operation
26*47fd7209SYu Chien Peter Lin 		 * is ignored and serves to indicate polling and
27*47fd7209SYu Chien Peter Lin 		 * flushing.
28*47fd7209SYu Chien Peter Lin 		 */
29*47fd7209SYu Chien Peter Lin 		seed = swap_csr(CSR_SEED, 0);
30*47fd7209SYu Chien Peter Lin 		opst = seed & SEED_OPST;
31*47fd7209SYu Chien Peter Lin 
32*47fd7209SYu Chien Peter Lin 		switch (opst) {
33*47fd7209SYu Chien Peter Lin 		case SEED_OPST_ES16:
34*47fd7209SYu Chien Peter Lin 			*val = seed & SEED_ENTROPY;
35*47fd7209SYu Chien Peter Lin 			return true;
36*47fd7209SYu Chien Peter Lin 		case SEED_OPST_DEAD:
37*47fd7209SYu Chien Peter Lin 			/* Unrecoverable self-test error */
38*47fd7209SYu Chien Peter Lin 			return false;
39*47fd7209SYu Chien Peter Lin 		case SEED_OPST_BIST:
40*47fd7209SYu Chien Peter Lin 		case SEED_OPST_WAIT:
41*47fd7209SYu Chien Peter Lin 		default:
42*47fd7209SYu Chien Peter Lin 			riscv_cpu_pause();
43*47fd7209SYu Chien Peter Lin 		}
44*47fd7209SYu Chien Peter Lin 	} while (!timeout_elapsed(timeout));
45*47fd7209SYu Chien Peter Lin 
46*47fd7209SYu Chien Peter Lin 	/* Consider timeout case due to normal world scheduler */
47*47fd7209SYu Chien Peter Lin 	seed = swap_csr(CSR_SEED, 0);
48*47fd7209SYu Chien Peter Lin 	if ((seed & SEED_OPST) == SEED_OPST_ES16) {
49*47fd7209SYu Chien Peter Lin 		*val = seed & SEED_ENTROPY;
50*47fd7209SYu Chien Peter Lin 		return true;
51*47fd7209SYu Chien Peter Lin 	}
52*47fd7209SYu Chien Peter Lin 
53*47fd7209SYu Chien Peter Lin 	EMSG("Failed to produce a sufficient amount of entropy");
54*47fd7209SYu Chien Peter Lin 
55*47fd7209SYu Chien Peter Lin 	return false;
56*47fd7209SYu Chien Peter Lin }
57fb605d4bSYu Chien Peter Lin 
hw_get_random_bytes(void * buf,size_t len)58fb605d4bSYu Chien Peter Lin TEE_Result hw_get_random_bytes(void *buf, size_t len)
59fb605d4bSYu Chien Peter Lin {
60fb605d4bSYu Chien Peter Lin 	uint8_t *ptr = buf;
61*47fd7209SYu Chien Peter Lin 	uint16_t seed = 0;
62fb605d4bSYu Chien Peter Lin 
63fb605d4bSYu Chien Peter Lin 	while (len > 0) {
64*47fd7209SYu Chien Peter Lin 		if (!seed_get_random_u16(&seed))
65*47fd7209SYu Chien Peter Lin 			return TEE_ERROR_ACCESS_DENIED;
66*47fd7209SYu Chien Peter Lin 		*ptr++ = seed & 0xff;
67fb605d4bSYu Chien Peter Lin 		len--;
68fb605d4bSYu Chien Peter Lin 		if (len > 0) {
69*47fd7209SYu Chien Peter Lin 			*ptr++ = seed >> 8;
70fb605d4bSYu Chien Peter Lin 			len--;
71fb605d4bSYu Chien Peter Lin 		}
72fb605d4bSYu Chien Peter Lin 	}
73fb605d4bSYu Chien Peter Lin 
74fb605d4bSYu Chien Peter Lin 	return TEE_SUCCESS;
75fb605d4bSYu Chien Peter Lin }
76fb605d4bSYu Chien Peter Lin 
plat_rng_init(void)77fb605d4bSYu Chien Peter Lin void plat_rng_init(void)
78fb605d4bSYu Chien Peter Lin {
79fb605d4bSYu Chien Peter Lin 	if (!riscv_detect_csr_seed())
80fb605d4bSYu Chien Peter Lin 		panic("RISC-V Zkr is not supported or unavailable in S-mode");
81fb605d4bSYu Chien Peter Lin }
82