• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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