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