1 // SPDX-License-Identifier: BSD-2-Clause
2 /* Copyright (c) 2023 HiSilicon Limited. */
3
4 #include <initcall.h>
5 #include <io.h>
6 #include <kernel/spinlock.h>
7 #include <malloc.h>
8 #include <mm/core_memprot.h>
9 #include <platform_config.h>
10 #include <rng_support.h>
11 #include <string.h>
12
13 #define HTRNG_RANDATA_REG 0xF0
14 #define HTRNG_BYTES 4U
15
16 #define POLL_PERIOD 10
17 #define POLL_TIMEOUT 1000
18
19 struct hisi_trng {
20 vaddr_t base;
21 };
22
23 static unsigned int trng_lock = SPINLOCK_UNLOCK;
24 static struct hisi_trng *trng_dev;
25
trng_read(uint32_t * val)26 static TEE_Result trng_read(uint32_t *val)
27 {
28 TEE_Result ret = TEE_SUCCESS;
29 uint32_t exceptions = 0;
30
31 exceptions = cpu_spin_lock_xsave(&trng_lock);
32 if (IO_READ32_POLL_TIMEOUT(trng_dev->base + HTRNG_RANDATA_REG,
33 *val, *val, POLL_PERIOD, POLL_TIMEOUT)) {
34 EMSG("Hardware busy");
35 ret = TEE_ERROR_BUSY;
36 }
37 cpu_spin_unlock_xrestore(&trng_lock, exceptions);
38
39 return ret;
40 }
41
hw_get_random_bytes(void * buf,size_t len)42 TEE_Result hw_get_random_bytes(void *buf, size_t len)
43 {
44 TEE_Result ret = TEE_ERROR_GENERIC;
45 size_t current_len = 0;
46 uint32_t val = 0;
47 size_t size = 0;
48
49 if (!trng_dev) {
50 EMSG("No valid TRNG device");
51 return TEE_ERROR_NOT_SUPPORTED;
52 }
53
54 if (!buf || !len) {
55 EMSG("Invalid input parameter");
56 return TEE_ERROR_BAD_PARAMETERS;
57 }
58
59 while (current_len < len) {
60 ret = trng_read(&val);
61 if (ret)
62 return TEE_ERROR_BUSY;
63
64 size = MIN(HTRNG_BYTES, len - current_len);
65 memcpy((uint8_t *)buf + current_len, &val, size);
66 current_len += size;
67 }
68
69 return TEE_SUCCESS;
70 }
71
trng_init(void)72 static TEE_Result trng_init(void)
73 {
74 DMSG("TRNG driver init start");
75 trng_dev = calloc(1, sizeof(struct hisi_trng));
76 if (!trng_dev) {
77 EMSG("Fail to calloc trng device");
78 return TEE_ERROR_OUT_OF_MEMORY;
79 }
80
81 trng_dev->base = (vaddr_t)phys_to_virt_io(HISI_TRNG_BASE,
82 HISI_TRNG_SIZE);
83 if (!trng_dev->base) {
84 EMSG("Fail to get trng io_base");
85 free(trng_dev);
86 trng_dev = NULL;
87 return TEE_ERROR_ACCESS_DENIED;
88 }
89
90 DMSG("TRNG driver init done");
91
92 return TEE_SUCCESS;
93 }
94
95 early_init(trng_init);
96