1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 /*
16 * Simple virtio-rng driver.
17 * Any time, only one task can use it to get randoms.
18 */
19
20 #include "osal.h"
21 #include "osal_io.h"
22 #include "dmac_core.h"
23 #include "los_vm_iomap.h"
24 #include "los_random.h"
25 #include "virtmmio.h"
26
27 #define VIRTQ_REQUEST_QSZ 1
28 #define VIRTMMIO_RNG_NAME "virtrng"
29
30 struct Virtrng {
31 struct VirtmmioDev dev;
32
33 OSAL_DECLARE_MUTEX(mutex);
34 DmacEvent event;
35 };
36 static struct Virtrng *g_virtRng;
37
Feature0(uint32_t features,uint32_t * supported,void * dev)38 static bool Feature0(uint32_t features, uint32_t *supported, void *dev)
39 {
40 (void)features;
41 (void)supported;
42 (void)dev;
43
44 return true;
45 }
46
Feature1(uint32_t features,uint32_t * supported,void * dev)47 static bool Feature1(uint32_t features, uint32_t *supported, void *dev)
48 {
49 (void)dev;
50 if (features & VIRTIO_F_VERSION_1) {
51 *supported |= VIRTIO_F_VERSION_1;
52 } else {
53 HDF_LOGE("[%s]virtio-rng has no VERSION_1 feature", __func__);
54 return false;
55 }
56
57 return true;
58 }
59
VirtrngIO(char * buffer,size_t buflen)60 static int VirtrngIO(char *buffer, size_t buflen)
61 {
62 struct Virtq *q = &g_virtRng->dev.vq[0];
63 int32_t ret;
64
65 if ((ret = OsalMutexLock(&g_virtRng->mutex)) != HDF_SUCCESS) {
66 HDF_LOGE("[%s]acquire mutex failed: %#x", __func__, ret);
67 return -1;
68 }
69
70 q->desc[0].pAddr = VMM_TO_DMA_ADDR((VADDR_T)buffer);
71 q->desc[0].len = buflen;
72 q->desc[0].flag = VIRTQ_DESC_F_WRITE;
73 q->avail->ring[q->avail->index % q->qsz] = 0;
74 DSB;
75 q->avail->index++;
76 OSAL_WRITEL(0, g_virtRng->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
77
78 if ((ret = DmaEventWait(&g_virtRng->event, 1, HDF_WAIT_FOREVER)) != 1) {
79 HDF_LOGE("[%s]wait event failed: %#x", __func__, ret);
80 ret = -1;
81 } else {
82 ret = q->used->ring[0].len; /* actual randoms acquired */
83 }
84
85 (void)OsalMutexUnlock(&g_virtRng->mutex);
86 return ret;
87 }
88
VirtrngIRQhandle(uint32_t swIrq,void * dev)89 static uint32_t VirtrngIRQhandle(uint32_t swIrq, void *dev)
90 {
91 (void)swIrq;
92 (void)dev;
93 struct Virtq *q = &g_virtRng->dev.vq[0];
94
95 if (!(OSAL_READL(g_virtRng->dev.base + VIRTMMIO_REG_INTERRUPTSTATUS) & VIRTMMIO_IRQ_NOTIFY_USED)) {
96 return 1;
97 }
98
99 (void)DmaEventSignal(&g_virtRng->event, 1);
100 q->last++;
101
102 OSAL_WRITEL(VIRTMMIO_IRQ_NOTIFY_USED, g_virtRng->dev.base + VIRTMMIO_REG_INTERRUPTACK);
103 return 0;
104 }
105
VirtrngDeInit(struct Virtrng * rng)106 static void VirtrngDeInit(struct Virtrng *rng)
107 {
108 if (rng->dev.irq & ~_IRQ_MASK) {
109 OsalUnregisterIrq(rng->dev.irq & _IRQ_MASK, rng);
110 }
111 if (rng->mutex.realMutex) {
112 OsalMutexDestroy(&rng->mutex);
113 }
114 LOS_DmaMemFree(rng);
115 g_virtRng = NULL;
116 }
117
VirtrngInitDevAux(struct Virtrng * rng)118 static int VirtrngInitDevAux(struct Virtrng *rng)
119 {
120 int32_t ret;
121
122 if ((ret = OsalMutexInit(&rng->mutex)) != HDF_SUCCESS) {
123 HDF_LOGE("[%s]initialize mutex failed: %d", __func__, ret);
124 return ret;
125 }
126
127 if ((ret = DmaEventInit(&rng->event)) != HDF_SUCCESS) {
128 HDF_LOGE("[%s]initialize event control block failed: %u", __func__, ret);
129 return ret;
130 }
131
132 ret = OsalRegisterIrq(rng->dev.irq, OSAL_IRQF_TRIGGER_NONE,
133 (OsalIRQHandle)VirtrngIRQhandle, VIRTMMIO_RNG_NAME, rng);
134 if (ret != HDF_SUCCESS) {
135 HDF_LOGE("[%s]register IRQ failed: %d", __func__, ret);
136 return ret;
137 }
138 rng->dev.irq |= ~_IRQ_MASK;
139
140 return HDF_SUCCESS;
141 }
142
VirtrngInitDev(void)143 static struct Virtrng *VirtrngInitDev(void)
144 {
145 struct Virtrng *rng = NULL;
146 VADDR_T base;
147 uint16_t qsz;
148 int32_t len;
149
150 /* NOTE: For simplicity, alloc all these data from physical continuous memory. */
151 len = sizeof(struct Virtrng) + VirtqSize(VIRTQ_REQUEST_QSZ);
152 rng = LOS_DmaMemAlloc(NULL, len, sizeof(UINTPTR), DMA_CACHE);
153 if (rng == NULL) {
154 HDF_LOGE("[%s]alloc rng memory failed", __func__);
155 return NULL;
156 }
157 (void)memset_s(rng, len, 0, len);
158
159 if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_RNG, &rng->dev)) {
160 goto ERR_OUT;
161 }
162
163 VirtmmioInitBegin(&rng->dev);
164
165 if (!VirtmmioNegotiate(&rng->dev, Feature0, Feature1, rng)) {
166 goto ERR_OUT1;
167 }
168
169 base = ALIGN((VADDR_T)rng + sizeof(struct Virtrng), VIRTQ_ALIGN_DESC);
170 qsz = VIRTQ_REQUEST_QSZ;
171 if (VirtmmioConfigQueue(&rng->dev, base, &qsz, 1) == 0) {
172 goto ERR_OUT1;
173 }
174
175 if (VirtrngInitDevAux(rng) != HDF_SUCCESS) {
176 goto ERR_OUT1;
177 }
178
179 VritmmioInitEnd(&rng->dev);
180 return rng;
181
182 ERR_OUT1:
183 VirtmmioInitFailed(&rng->dev);
184 ERR_OUT:
185 VirtrngDeInit(rng);
186 return NULL;
187 }
188
189
190 /*
191 * random_hw code
192 */
193
VirtrngSupport(void)194 static int VirtrngSupport(void)
195 {
196 return 1;
197 }
198
VirtrngOpen(void)199 static void VirtrngOpen(void)
200 {
201 }
202
VirtrngClose(void)203 static void VirtrngClose(void)
204 {
205 }
206
VirtrngRead(char * buffer,size_t bytes)207 static int VirtrngRead(char *buffer, size_t bytes)
208 {
209 char *newbuf = buffer;
210 int len;
211
212 if (LOS_IsUserAddressRange((VADDR_T)buffer, bytes)) {
213 newbuf = OsalMemAlloc(bytes);
214 if (newbuf == NULL) {
215 HDF_LOGE("[%s]alloc memory failed", __func__);
216 return -1;
217 }
218 } else if ((VADDR_T)buffer + bytes < (VADDR_T)buffer) {
219 HDF_LOGE("[%s]invalid argument: buffer=%p, size=%#x\n", __func__, buffer, bytes);
220 return -1;
221 }
222
223 len = VirtrngIO(newbuf, bytes);
224
225 if (newbuf != buffer) {
226 if ((len > 0) && (LOS_ArchCopyToUser(buffer, newbuf, len)) != 0) {
227 HDF_LOGE("[%s]LOS_ArchCopyToUser error\n", __func__);
228 len = -1;
229 }
230
231 (void)OsalMemFree(newbuf);
232 }
233
234 return len;
235 }
236
VirtrngInit(void)237 void VirtrngInit(void)
238 {
239 if ((g_virtRng = VirtrngInitDev()) == NULL) {
240 return;
241 }
242
243 int ret;
244 RandomOperations r = {
245 .support = VirtrngSupport,
246 .init = VirtrngOpen,
247 .deinit = VirtrngClose,
248 .read = VirtrngRead,
249 };
250 RandomOperationsInit(&r);
251 if ((ret = DevUrandomRegister()) != 0) {
252 HDF_LOGE("[%s]register /dev/urandom failed: %#x", __func__, ret);
253 VirtrngDeInit(g_virtRng);
254 }
255 }
256
257
258 /*
259 * When kernel decoupled with specific devices,
260 * these code can be removed.
261 */
HiRandomHwInit(void)262 void HiRandomHwInit(void) {}
HiRandomHwDeinit(void)263 void HiRandomHwDeinit(void) {}
HiRandomHwGetInteger(unsigned * result)264 int HiRandomHwGetInteger(unsigned *result)
265 {
266 /* kernel call this too early in mount.c */
267 if (g_virtRng == NULL) {
268 *result = 1;
269 return sizeof(unsigned);
270 }
271
272 return VirtrngRead((char*)result, sizeof(unsigned));
273 }
HiRandomHwGetNumber(char * buffer,size_t buflen)274 int HiRandomHwGetNumber(char *buffer, size_t buflen)
275 {
276 return VirtrngRead(buffer, buflen);
277 }
278