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