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
MmzOpen(struct file * filep)44 static int MmzOpen(struct file *filep)
45 {
46 return 0;
47 }
48
MmzClose(struct file * filep)49 static int MmzClose(struct file *filep)
50 {
51 return 0;
52 }
53
MmzAlloc(int cmd,unsigned long arg)54 static 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
MmzMap(int cmd,unsigned long arg)120 static 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
MmzUnMap(unsigned long arg)179 static 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
MmzFree(unsigned long arg)186 static 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
213 DONE:
214 (VOID)LOS_MuxRelease(&curVmSpace->regionMux);
215 return ret;
216 }
217
MmzFlush(unsigned long arg)218 static 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
MmzInvalidate(unsigned long arg)225 static 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
MmzIoctl(struct file * filep,int cmd,unsigned long arg)232 static 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
257 static const struct file_operations_vfs g_mmzDevOps = {
258 .open = MmzOpen, /* open */
259 .close = MmzClose, /* close */
260 .ioctl = MmzIoctl, /* ioctl */
261 };
262
DevMmzRegister(void)263 int DevMmzRegister(void)
264 {
265 return register_driver(MMZ_NODE, &g_mmzDevOps, 0666, 0); /* 0666: file mode */
266 }
267