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