1/* 2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. 3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this list of 9 * conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 12 * of conditions and the following disclaimer in the documentation and/or other materials 13 * provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used 16 * to endorse or promote products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "mmz.h" 33#include "fcntl.h" 34#include "fs/driver.h" 35#include "los_vm_map.h" 36#include "los_vm_phys.h" 37#include "los_vm_lock.h" 38#include "los_hw.h" 39#include "los_atomic.h" 40#include "los_vm_common.h" 41#include "los_process_pri.h" 42#include "target_config.h" 43 44static int MmzOpen(struct file *filep) 45{ 46 return 0; 47} 48 49static int MmzClose(struct file *filep) 50{ 51 return 0; 52} 53 54static ssize_t MmzAlloc(int cmd, unsigned long arg) 55{ 56 UINT32 vmFlags = VM_MAP_REGION_FLAG_PERM_USER | 57 VM_MAP_REGION_FLAG_PERM_READ | 58 VM_MAP_REGION_FLAG_PERM_WRITE; 59 STATUS_T status; 60 MmzMemory *mmzm = (MmzMemory *)arg; 61 LosVmSpace *curVmSpace = OsCurrProcessGet()->vmSpace; 62 LosVmMapRegion *vmRegion; 63 VOID *kvaddr; 64 PADDR_T paddr; 65 VADDR_T vaddr; 66 UINT32 size = ROUNDUP(mmzm->size, PAGE_SIZE); 67 LosVmPage *vmPage = NULL; 68 69 switch (cmd) { 70 case MMZ_CACHE_TYPE: 71 vmFlags |= VM_MAP_REGION_FLAG_CACHED; 72 break; 73 case MMZ_NOCACHE_TYPE: 74 vmFlags |= VM_MAP_REGION_FLAG_UNCACHED; 75 break; 76 default: 77 PRINT_ERR("%s %d: %d\n", __func__, __LINE__, cmd); 78 return -EINVAL; 79 } 80 vmRegion = LOS_RegionAlloc(curVmSpace, 0, size, vmFlags, 0); 81 if (vmRegion == NULL) { 82 PRINT_ERR("cmd: %d, size: %#x vaddr alloc failed\n", cmd, size); 83 return -ENOMEM; 84 } 85 86 kvaddr = (void *)LOS_PhysPagesAllocContiguous(size >> PAGE_SHIFT); 87 if (kvaddr == NULL) { 88 LOS_RegionFree(curVmSpace, vmRegion); 89 PRINT_ERR("size: %#x paddr alloc failed\n", size); 90 return -ENOMEM; 91 } 92 93 paddr = LOS_PaddrQuery(kvaddr); 94 mmzm->paddr = paddr; 95 vaddr = vmRegion->range.base; 96 while (size > 0) { 97 vmPage = LOS_VmPageGet(paddr); 98 if (vmPage == NULL) { 99 LOS_RegionFree(curVmSpace, vmRegion); 100 VM_ERR("Page is NULL"); 101 return -EINVAL; 102 } 103 LOS_AtomicInc(&vmPage->refCounts); 104 105 status = LOS_ArchMmuMap(&curVmSpace->archMmu, vaddr, paddr, 1, vmFlags); 106 if (status <= 0) { 107 VM_ERR("LOS_ArchMmuMap failed: %d", status); 108 LOS_RegionFree(curVmSpace, vmRegion); 109 return status; 110 } 111 112 paddr += PAGE_SIZE; 113 vaddr += PAGE_SIZE; 114 size -= PAGE_SIZE; 115 } 116 mmzm->vaddr = (void *)vmRegion->range.base; 117 return LOS_OK; 118} 119 120static ssize_t MmzMap(int cmd, unsigned long arg) 121{ 122 UINT32 vmFlags = VM_MAP_REGION_FLAG_PERM_USER | 123 VM_MAP_REGION_FLAG_PERM_READ | 124 VM_MAP_REGION_FLAG_PERM_WRITE; 125 MmzMemory *mmzm = (MmzMemory *)arg; 126 LosVmSpace *curVmSpace = OsCurrProcessGet()->vmSpace; 127 LosVmMapRegion *vmRegion = NULL; 128 STATUS_T status = LOS_OK; 129 PADDR_T paddr = (PADDR_T)mmzm->paddr; 130 UINT32 size = ROUNDUP(mmzm->size, PAGE_SIZE); 131 VADDR_T vaddr; 132 LosVmPage *vmPage = NULL; 133 134 switch (cmd) { 135 case MMZ_MAP_CACHE_TYPE: 136 vmFlags |= VM_MAP_REGION_FLAG_CACHED; 137 break; 138 case MMZ_MAP_NOCACHE_TYPE: 139 vmFlags |= VM_MAP_REGION_FLAG_UNCACHED; 140 break; 141 default: 142 PRINT_ERR("%s %d: %d\n", __func__, __LINE__, cmd); 143 return -EINVAL; 144 } 145 146 vmRegion = LOS_RegionAlloc(curVmSpace, 0, size, vmFlags, 0); 147 if (vmRegion == NULL) { 148 PRINT_ERR("cmd: %d, size: %#x vaddr alloc failed\n", cmd, size); 149 return -ENOMEM; 150 } 151 152 mmzm->vaddr = (void *)vmRegion->range.base; 153 vaddr = vmRegion->range.base; 154 while (size > 0) { 155 vmPage = LOS_VmPageGet(paddr); 156 if (vmPage == NULL) { 157 LOS_RegionFree(curVmSpace, vmRegion); 158 VM_ERR("Page is NULL"); 159 return -EINVAL; 160 } 161 LOS_AtomicInc(&vmPage->refCounts); 162 163 status = LOS_ArchMmuMap(&curVmSpace->archMmu, vaddr, paddr, 1, 164 vmRegion->regionFlags); 165 if (status <= 0) { 166 VM_ERR("LOS_ArchMmuMap failed: %d", status); 167 LOS_RegionFree(curVmSpace, vmRegion); 168 return status; 169 } 170 171 paddr += PAGE_SIZE; 172 vaddr += PAGE_SIZE; 173 size -= PAGE_SIZE; 174 } 175 176 return status; 177} 178 179static ssize_t MmzUnMap(unsigned long arg) 180{ 181 LosVmSpace *curVmSpace = OsCurrProcessGet()->vmSpace; 182 MmzMemory *mmzm = (MmzMemory *)arg; 183 return OsUnMMap(curVmSpace, (VADDR_T)mmzm->vaddr, mmzm->size); 184} 185 186static ssize_t MmzFree(unsigned long arg) 187{ 188 MmzMemory *mmzm = (MmzMemory *)arg; 189 LosVmSpace *curVmSpace = OsCurrProcessGet()->vmSpace; 190 LosVmMapRegion *region = NULL; 191 STATUS_T ret = LOS_OK; 192 193 (VOID)LOS_MuxAcquire(&curVmSpace->regionMux); 194 if ((PADDR_T)mmzm->paddr != LOS_PaddrQuery(mmzm->vaddr)) { 195 PRINT_ERR("vaddr is not equal to paddr"); 196 ret = -EINVAL; 197 goto DONE; 198 } 199 200 region = LOS_RegionFind(curVmSpace, (VADDR_T)(unsigned int)mmzm->vaddr); 201 if (region == NULL) { 202 PRINT_ERR("find region failed"); 203 ret = -EINVAL; 204 goto DONE; 205 } 206 207 ret = LOS_RegionFree(curVmSpace, region); 208 if (ret) { 209 PRINT_ERR("free region failed, ret = %d", ret); 210 ret = -EINVAL; 211 } 212 213DONE: 214 (VOID)LOS_MuxRelease(&curVmSpace->regionMux); 215 return ret; 216} 217 218static ssize_t MmzFlush(unsigned long arg) 219{ 220 MmzMemory *mmzm = (MmzMemory *)arg; 221 DCacheFlushRange((unsigned int)mmzm->vaddr, (UINT32)mmzm->vaddr + mmzm->size); 222 return LOS_OK; 223} 224 225static ssize_t MmzInvalidate(unsigned long arg) 226{ 227 MmzMemory *mmzm = (MmzMemory *)arg; 228 DCacheInvRange((unsigned int)mmzm->vaddr, (UINT32)mmzm->vaddr + mmzm->size); 229 return LOS_OK; 230} 231 232static ssize_t MmzIoctl(struct file *filep, int cmd, unsigned long arg) 233{ 234 switch (cmd) { 235 case MMZ_CACHE_TYPE: 236 case MMZ_NOCACHE_TYPE: 237 return MmzAlloc(cmd, arg); 238 case MMZ_FREE_TYPE: 239 return MmzFree(arg); 240 case MMZ_MAP_CACHE_TYPE: 241 case MMZ_MAP_NOCACHE_TYPE: 242 return MmzMap(cmd, arg); 243 case MMZ_UNMAP_TYPE: 244 return MmzUnMap(arg); 245 case MMZ_FLUSH_CACHE_TYPE: 246 case MMZ_FLUSH_NOCACHE_TYPE: 247 return MmzFlush(arg); 248 case MMZ_INVALIDATE_TYPE: 249 return MmzInvalidate(arg); 250 default: 251 PRINT_ERR("%s %d: %d\n", __func__, __LINE__, cmd); 252 return -EINVAL; 253 } 254 return LOS_OK; 255} 256 257static const struct file_operations_vfs g_mmzDevOps = { 258 .open = MmzOpen, /* open */ 259 .close = MmzClose, /* close */ 260 .ioctl = MmzIoctl, /* ioctl */ 261}; 262 263int DevMmzRegister(void) 264{ 265 return register_driver(MMZ_NODE, &g_mmzDevOps, 0666, 0); /* 0666: file mode */ 266} 267