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 "los_vm_map.h"
33 #include "los_vm_page.h"
34 #include "los_vm_phys.h"
35 #include "los_vm_dump.h"
36 #include "los_vm_lock.h"
37 #include "los_vm_zone.h"
38 #include "los_vm_common.h"
39 #include "los_vm_filemap.h"
40 #include "los_vm_shm_pri.h"
41 #include "los_arch_mmu.h"
42 #include "los_process_pri.h"
43 #ifdef LOSCFG_FS_VFS
44 #include "fs/file.h"
45 #include "vnode.h"
46 #endif
47 #include "los_task.h"
48 #include "los_memory_pri.h"
49 #include "los_vm_boot.h"
50
51
52 #ifdef LOSCFG_KERNEL_VM
53
54 #define VM_MAP_WASTE_MEM_LEVEL (PAGE_SIZE >> 2)
55 LosMux g_vmSpaceListMux;
56 LOS_DL_LIST_HEAD(g_vmSpaceList);
57 LosVmSpace g_kVmSpace;
58 LosVmSpace g_vMallocSpace;
59
LOS_CurrSpaceGet(VOID)60 LosVmSpace *LOS_CurrSpaceGet(VOID)
61 {
62 return OsCurrProcessGet()->vmSpace;
63 }
64
LOS_SpaceGet(VADDR_T vaddr)65 LosVmSpace *LOS_SpaceGet(VADDR_T vaddr)
66 {
67 if (LOS_IsKernelAddress(vaddr)) {
68 return LOS_GetKVmSpace();
69 } else if (LOS_IsUserAddress(vaddr)) {
70 return LOS_CurrSpaceGet();
71 } else if (LOS_IsVmallocAddress(vaddr)) {
72 return LOS_GetVmallocSpace();
73 } else {
74 return NULL;
75 }
76 }
77
LOS_GetKVmSpace(VOID)78 LosVmSpace *LOS_GetKVmSpace(VOID)
79 {
80 return &g_kVmSpace;
81 }
82
LOS_GetVmSpaceList(VOID)83 LOS_DL_LIST *LOS_GetVmSpaceList(VOID)
84 {
85 return &g_vmSpaceList;
86 }
87
LOS_GetVmallocSpace(VOID)88 LosVmSpace *LOS_GetVmallocSpace(VOID)
89 {
90 return &g_vMallocSpace;
91 }
92
OsRegionRbFreeFn(LosRbNode * pstNode)93 ULONG_T OsRegionRbFreeFn(LosRbNode *pstNode)
94 {
95 LOS_MemFree(m_aucSysMem0, pstNode);
96 return LOS_OK;
97 }
98
OsRegionRbGetKeyFn(LosRbNode * pstNode)99 VOID *OsRegionRbGetKeyFn(LosRbNode *pstNode)
100 {
101 LosVmMapRegion *region = (LosVmMapRegion *)LOS_DL_LIST_ENTRY(pstNode, LosVmMapRegion, rbNode);
102 return (VOID *)®ion->range;
103 }
104
OsRegionRbCmpKeyFn(const VOID * pNodeKeyA,const VOID * pNodeKeyB)105 ULONG_T OsRegionRbCmpKeyFn(const VOID *pNodeKeyA, const VOID *pNodeKeyB)
106 {
107 LosVmMapRange rangeA = *(LosVmMapRange *)pNodeKeyA;
108 LosVmMapRange rangeB = *(LosVmMapRange *)pNodeKeyB;
109 UINT32 startA = rangeA.base;
110 UINT32 endA = rangeA.base + rangeA.size - 1;
111 UINT32 startB = rangeB.base;
112 UINT32 endB = rangeB.base + rangeB.size - 1;
113
114 if (startA > endB) {
115 return RB_BIGGER;
116 } else if (startA >= startB) {
117 if (endA <= endB) {
118 return RB_EQUAL;
119 } else {
120 return RB_BIGGER;
121 }
122 } else if (startA <= startB) {
123 if (endA >= endB) {
124 return RB_EQUAL;
125 } else {
126 return RB_SMALLER;
127 }
128 } else if (endA < startB) {
129 return RB_SMALLER;
130 }
131 return RB_EQUAL;
132 }
133
OsVmSpaceInitCommon(LosVmSpace * vmSpace,VADDR_T * virtTtb)134 STATIC BOOL OsVmSpaceInitCommon(LosVmSpace *vmSpace, VADDR_T *virtTtb)
135 {
136 LOS_RbInitTree(&vmSpace->regionRbTree, OsRegionRbCmpKeyFn, OsRegionRbFreeFn, OsRegionRbGetKeyFn);
137
138 status_t retval = LOS_MuxInit(&vmSpace->regionMux, NULL);
139 if (retval != LOS_OK) {
140 VM_ERR("Create mutex for vm space failed, status: %d", retval);
141 return FALSE;
142 }
143
144 (VOID)LOS_MuxAcquire(&g_vmSpaceListMux);
145 LOS_ListAdd(&g_vmSpaceList, &vmSpace->node);
146 (VOID)LOS_MuxRelease(&g_vmSpaceListMux);
147
148 return OsArchMmuInit(&vmSpace->archMmu, virtTtb);
149 }
150
OsVmMapInit(VOID)151 VOID OsVmMapInit(VOID)
152 {
153 status_t retval = LOS_MuxInit(&g_vmSpaceListMux, NULL);
154 if (retval != LOS_OK) {
155 VM_ERR("Create mutex for g_vmSpaceList failed, status: %d", retval);
156 }
157 }
158
OsKernVmSpaceInit(LosVmSpace * vmSpace,VADDR_T * virtTtb)159 BOOL OsKernVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)
160 {
161 vmSpace->base = KERNEL_ASPACE_BASE;
162 vmSpace->size = KERNEL_ASPACE_SIZE;
163 vmSpace->mapBase = KERNEL_VMM_BASE;
164 vmSpace->mapSize = KERNEL_VMM_SIZE;
165 #ifdef LOSCFG_DRIVERS_TZDRIVER
166 vmSpace->codeStart = 0;
167 vmSpace->codeEnd = 0;
168 #endif
169 return OsVmSpaceInitCommon(vmSpace, virtTtb);
170 }
171
OsVMallocSpaceInit(LosVmSpace * vmSpace,VADDR_T * virtTtb)172 BOOL OsVMallocSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)
173 {
174 vmSpace->base = VMALLOC_START;
175 vmSpace->size = VMALLOC_SIZE;
176 vmSpace->mapBase = VMALLOC_START;
177 vmSpace->mapSize = VMALLOC_SIZE;
178 #ifdef LOSCFG_DRIVERS_TZDRIVER
179 vmSpace->codeStart = 0;
180 vmSpace->codeEnd = 0;
181 #endif
182 return OsVmSpaceInitCommon(vmSpace, virtTtb);
183 }
184
OsKSpaceInit(VOID)185 VOID OsKSpaceInit(VOID)
186 {
187 OsVmMapInit();
188 OsKernVmSpaceInit(&g_kVmSpace, OsGFirstTableGet());
189 OsVMallocSpaceInit(&g_vMallocSpace, OsGFirstTableGet());
190 }
191
OsUserVmSpaceInit(LosVmSpace * vmSpace,VADDR_T * virtTtb)192 BOOL OsUserVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)
193 {
194 vmSpace->base = USER_ASPACE_BASE;
195 vmSpace->size = USER_ASPACE_SIZE;
196 vmSpace->mapBase = USER_MAP_BASE;
197 vmSpace->mapSize = USER_MAP_SIZE;
198 vmSpace->heapBase = USER_HEAP_BASE;
199 vmSpace->heapNow = USER_HEAP_BASE;
200 vmSpace->heap = NULL;
201 #ifdef LOSCFG_DRIVERS_TZDRIVER
202 vmSpace->codeStart = 0;
203 vmSpace->codeEnd = 0;
204 #endif
205 return OsVmSpaceInitCommon(vmSpace, virtTtb);
206 }
207
OsCreateUserVmSpace(VOID)208 LosVmSpace *OsCreateUserVmSpace(VOID)
209 {
210 BOOL retVal = FALSE;
211
212 LosVmSpace *space = LOS_MemAlloc(m_aucSysMem0, sizeof(LosVmSpace));
213 if (space == NULL) {
214 return NULL;
215 }
216
217 VADDR_T *ttb = LOS_PhysPagesAllocContiguous(1);
218 if (ttb == NULL) {
219 (VOID)LOS_MemFree(m_aucSysMem0, space);
220 return NULL;
221 }
222
223 (VOID)memset_s(ttb, PAGE_SIZE, 0, PAGE_SIZE);
224 retVal = OsUserVmSpaceInit(space, ttb);
225 LosVmPage *vmPage = OsVmVaddrToPage(ttb);
226 if ((retVal == FALSE) || (vmPage == NULL)) {
227 (VOID)LOS_MemFree(m_aucSysMem0, space);
228 LOS_PhysPagesFreeContiguous(ttb, 1);
229 return NULL;
230 }
231 LOS_ListAdd(&space->archMmu.ptList, &(vmPage->node));
232
233 return space;
234 }
235
OsVmSpaceParamCheck(const LosVmSpace * vmSpace)236 STATIC BOOL OsVmSpaceParamCheck(const LosVmSpace *vmSpace)
237 {
238 if (vmSpace == NULL) {
239 return FALSE;
240 }
241 return TRUE;
242 }
243
LOS_VmSpaceClone(LosVmSpace * oldVmSpace,LosVmSpace * newVmSpace)244 STATUS_T LOS_VmSpaceClone(LosVmSpace *oldVmSpace, LosVmSpace *newVmSpace)
245 {
246 LosVmMapRegion *oldRegion = NULL;
247 LosVmMapRegion *newRegion = NULL;
248 LosRbNode *pstRbNode = NULL;
249 LosRbNode *pstRbNodeNext = NULL;
250 STATUS_T ret = LOS_OK;
251 UINT32 numPages;
252 PADDR_T paddr;
253 VADDR_T vaddr;
254 UINT32 intSave;
255 LosVmPage *page = NULL;
256 UINT32 flags;
257 UINT32 i;
258
259 if ((OsVmSpaceParamCheck(oldVmSpace) == FALSE) || (OsVmSpaceParamCheck(newVmSpace) == FALSE)) {
260 return LOS_ERRNO_VM_INVALID_ARGS;
261 }
262
263 if ((OsIsVmRegionEmpty(oldVmSpace) == TRUE) || (oldVmSpace == &g_kVmSpace)) {
264 return LOS_ERRNO_VM_INVALID_ARGS;
265 }
266
267 /* search the region list */
268 newVmSpace->mapBase = oldVmSpace->mapBase;
269 newVmSpace->heapBase = oldVmSpace->heapBase;
270 newVmSpace->heapNow = oldVmSpace->heapNow;
271 (VOID)LOS_MuxAcquire(&oldVmSpace->regionMux);
272 RB_SCAN_SAFE(&oldVmSpace->regionRbTree, pstRbNode, pstRbNodeNext)
273 oldRegion = (LosVmMapRegion *)pstRbNode;
274 newRegion = OsVmRegionDup(newVmSpace, oldRegion, oldRegion->range.base, oldRegion->range.size);
275 if (newRegion == NULL) {
276 VM_ERR("dup new region failed");
277 ret = LOS_ERRNO_VM_NO_MEMORY;
278 break;
279 }
280
281 #ifdef LOSCFG_KERNEL_SHM
282 if (oldRegion->regionFlags & VM_MAP_REGION_FLAG_SHM) {
283 OsShmFork(newVmSpace, oldRegion, newRegion);
284 continue;
285 }
286 #endif
287
288 if (oldRegion == oldVmSpace->heap) {
289 newVmSpace->heap = newRegion;
290 }
291
292 numPages = newRegion->range.size >> PAGE_SHIFT;
293 for (i = 0; i < numPages; i++) {
294 vaddr = newRegion->range.base + (i << PAGE_SHIFT);
295 if (LOS_ArchMmuQuery(&oldVmSpace->archMmu, vaddr, &paddr, &flags) != LOS_OK) {
296 continue;
297 }
298
299 page = LOS_VmPageGet(paddr);
300 if (page != NULL) {
301 LOS_AtomicInc(&page->refCounts);
302 }
303 if (flags & VM_MAP_REGION_FLAG_PERM_WRITE) {
304 LOS_ArchMmuUnmap(&oldVmSpace->archMmu, vaddr, 1);
305 LOS_ArchMmuMap(&oldVmSpace->archMmu, vaddr, paddr, 1, flags & ~VM_MAP_REGION_FLAG_PERM_WRITE);
306 }
307 LOS_ArchMmuMap(&newVmSpace->archMmu, vaddr, paddr, 1, flags & ~VM_MAP_REGION_FLAG_PERM_WRITE);
308
309 #ifdef LOSCFG_FS_VFS
310 if (LOS_IsRegionFileValid(oldRegion)) {
311 LosFilePage *fpage = NULL;
312 LOS_SpinLockSave(&oldRegion->unTypeData.rf.vnode->mapping.list_lock, &intSave);
313 fpage = OsFindGetEntry(&oldRegion->unTypeData.rf.vnode->mapping, newRegion->pgOff + i);
314 if ((fpage != NULL) && (fpage->vmPage == page)) { /* cow page no need map */
315 OsAddMapInfo(fpage, &newVmSpace->archMmu, vaddr);
316 }
317 LOS_SpinUnlockRestore(&oldRegion->unTypeData.rf.vnode->mapping.list_lock, intSave);
318 }
319 #endif
320 }
321 RB_SCAN_SAFE_END(&oldVmSpace->regionRbTree, pstRbNode, pstRbNodeNext)
322 (VOID)LOS_MuxRelease(&oldVmSpace->regionMux);
323 return ret;
324 }
325
OsFindRegion(LosRbTree * regionRbTree,VADDR_T vaddr,size_t len)326 LosVmMapRegion *OsFindRegion(LosRbTree *regionRbTree, VADDR_T vaddr, size_t len)
327 {
328 LosVmMapRegion *regionRst = NULL;
329 LosRbNode *pstRbNode = NULL;
330 LosVmMapRange rangeKey;
331 rangeKey.base = vaddr;
332 rangeKey.size = len;
333
334 if (LOS_RbGetNode(regionRbTree, (VOID *)&rangeKey, &pstRbNode)) {
335 regionRst = (LosVmMapRegion *)LOS_DL_LIST_ENTRY(pstRbNode, LosVmMapRegion, rbNode);
336 }
337 return regionRst;
338 }
339
LOS_RegionFind(LosVmSpace * vmSpace,VADDR_T addr)340 LosVmMapRegion *LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
341 {
342 LosVmMapRegion *region = NULL;
343
344 (VOID)LOS_MuxAcquire(&vmSpace->regionMux);
345 region = OsFindRegion(&vmSpace->regionRbTree, addr, 1);
346 (VOID)LOS_MuxRelease(&vmSpace->regionMux);
347
348 return region;
349 }
350
LOS_RegionRangeFind(LosVmSpace * vmSpace,VADDR_T addr,size_t len)351 LosVmMapRegion *LOS_RegionRangeFind(LosVmSpace *vmSpace, VADDR_T addr, size_t len)
352 {
353 LosVmMapRegion *region = NULL;
354
355 (VOID)LOS_MuxAcquire(&vmSpace->regionMux);
356 region = OsFindRegion(&vmSpace->regionRbTree, addr, len);
357 (VOID)LOS_MuxRelease(&vmSpace->regionMux);
358
359 return region;
360 }
361
OsAllocRange(LosVmSpace * vmSpace,size_t len)362 VADDR_T OsAllocRange(LosVmSpace *vmSpace, size_t len)
363 {
364 LosVmMapRegion *curRegion = NULL;
365 LosRbNode *pstRbNode = NULL;
366 LosRbNode *pstRbNodeTmp = NULL;
367 LosRbTree *regionRbTree = &vmSpace->regionRbTree;
368 VADDR_T curEnd = vmSpace->mapBase;
369 VADDR_T nextStart;
370
371 curRegion = LOS_RegionFind(vmSpace, vmSpace->mapBase);
372 if (curRegion != NULL) {
373 pstRbNode = &curRegion->rbNode;
374 curEnd = curRegion->range.base + curRegion->range.size;
375 RB_MID_SCAN(regionRbTree, pstRbNode)
376 curRegion = (LosVmMapRegion *)pstRbNode;
377 nextStart = curRegion->range.base;
378 if (nextStart < curEnd) {
379 continue;
380 }
381 if ((nextStart - curEnd) >= len) {
382 return curEnd;
383 } else {
384 curEnd = curRegion->range.base + curRegion->range.size;
385 }
386 RB_MID_SCAN_END(regionRbTree, pstRbNode)
387 } else {
388 /* rbtree scan is sorted, from small to big */
389 RB_SCAN_SAFE(regionRbTree, pstRbNode, pstRbNodeTmp)
390 curRegion = (LosVmMapRegion *)pstRbNode;
391 nextStart = curRegion->range.base;
392 if (nextStart < curEnd) {
393 continue;
394 }
395 if ((nextStart - curEnd) >= len) {
396 return curEnd;
397 } else {
398 curEnd = curRegion->range.base + curRegion->range.size;
399 }
400 RB_SCAN_SAFE_END(regionRbTree, pstRbNode, pstRbNodeTmp)
401 }
402
403 nextStart = vmSpace->mapBase + vmSpace->mapSize;
404 if ((nextStart >= curEnd) && ((nextStart - curEnd) >= len)) {
405 return curEnd;
406 }
407
408 return 0;
409 }
410
OsAllocSpecificRange(LosVmSpace * vmSpace,VADDR_T vaddr,size_t len,UINT32 regionFlags)411 VADDR_T OsAllocSpecificRange(LosVmSpace *vmSpace, VADDR_T vaddr, size_t len, UINT32 regionFlags)
412 {
413 STATUS_T status;
414
415 if (LOS_IsRangeInSpace(vmSpace, vaddr, len) == FALSE) {
416 return 0;
417 }
418
419 if ((LOS_RegionFind(vmSpace, vaddr) != NULL) ||
420 (LOS_RegionFind(vmSpace, vaddr + len - 1) != NULL) ||
421 (LOS_RegionRangeFind(vmSpace, vaddr, len - 1) != NULL)) {
422 if ((regionFlags & VM_MAP_REGION_FLAG_FIXED_NOREPLACE) != 0) {
423 return 0;
424 } else if ((regionFlags & VM_MAP_REGION_FLAG_FIXED) != 0) {
425 status = LOS_UnMMap(vaddr, len);
426 if (status != LOS_OK) {
427 VM_ERR("unmap specific range va: %#x, len: %#x failed, status: %d", vaddr, len, status);
428 return 0;
429 }
430 } else {
431 return OsAllocRange(vmSpace, len);
432 }
433 }
434
435 return vaddr;
436 }
437
LOS_IsRegionFileValid(LosVmMapRegion * region)438 BOOL LOS_IsRegionFileValid(LosVmMapRegion *region)
439 {
440 if ((region != NULL) && (LOS_IsRegionTypeFile(region)) &&
441 (region->unTypeData.rf.vnode != NULL)) {
442 return TRUE;
443 }
444 return FALSE;
445 }
446
OsInsertRegion(LosRbTree * regionRbTree,LosVmMapRegion * region)447 BOOL OsInsertRegion(LosRbTree *regionRbTree, LosVmMapRegion *region)
448 {
449 if (LOS_RbAddNode(regionRbTree, (LosRbNode *)region) == FALSE) {
450 VM_ERR("insert region failed, base: %#x, size: %#x", region->range.base, region->range.size);
451 OsDumpAspace(region->space);
452 return FALSE;
453 }
454 return TRUE;
455 }
456
OsCreateRegion(VADDR_T vaddr,size_t len,UINT32 regionFlags,unsigned long offset)457 LosVmMapRegion *OsCreateRegion(VADDR_T vaddr, size_t len, UINT32 regionFlags, unsigned long offset)
458 {
459 LosVmMapRegion *region = LOS_MemAlloc(m_aucSysMem0, sizeof(LosVmMapRegion));
460 if (region == NULL) {
461 VM_ERR("memory allocate for LosVmMapRegion failed");
462 return region;
463 }
464
465 (void)memset_s(region, sizeof(LosVmMapRegion), 0, sizeof(LosVmMapRegion));
466 region->range.base = vaddr;
467 region->range.size = len;
468 region->pgOff = offset;
469 region->regionFlags = regionFlags;
470 region->regionType = VM_MAP_REGION_TYPE_NONE;
471 region->forkFlags = 0;
472 region->shmid = -1;
473 return region;
474 }
475
LOS_PaddrQuery(VOID * vaddr)476 PADDR_T LOS_PaddrQuery(VOID *vaddr)
477 {
478 PADDR_T paddr = 0;
479 STATUS_T status;
480 LosVmSpace *space = NULL;
481 LosArchMmu *archMmu = NULL;
482
483 if (LOS_IsKernelAddress((VADDR_T)(UINTPTR)vaddr)) {
484 archMmu = &g_kVmSpace.archMmu;
485 } else if (LOS_IsUserAddress((VADDR_T)(UINTPTR)vaddr)) {
486 space = OsCurrProcessGet()->vmSpace;
487 archMmu = &space->archMmu;
488 } else if (LOS_IsVmallocAddress((VADDR_T)(UINTPTR)vaddr)) {
489 archMmu = &g_vMallocSpace.archMmu;
490 } else {
491 VM_ERR("vaddr is beyond range");
492 return 0;
493 }
494
495 status = LOS_ArchMmuQuery(archMmu, (VADDR_T)(UINTPTR)vaddr, &paddr, 0);
496 if (status == LOS_OK) {
497 return paddr;
498 } else {
499 return 0;
500 }
501 }
502
LOS_RegionAlloc(LosVmSpace * vmSpace,VADDR_T vaddr,size_t len,UINT32 regionFlags,VM_OFFSET_T pgoff)503 LosVmMapRegion *LOS_RegionAlloc(LosVmSpace *vmSpace, VADDR_T vaddr, size_t len, UINT32 regionFlags, VM_OFFSET_T pgoff)
504 {
505 VADDR_T rstVaddr;
506 LosVmMapRegion *newRegion = NULL;
507 BOOL isInsertSucceed = FALSE;
508 /**
509 * If addr is NULL, then the kernel chooses the address at which to create the mapping;
510 * this is the most portable method of creating a new mapping. If addr is not NULL,
511 * then the kernel takes it as where to place the mapping;
512 */
513 (VOID)LOS_MuxAcquire(&vmSpace->regionMux);
514 if (vaddr == 0) {
515 rstVaddr = OsAllocRange(vmSpace, len);
516 } else {
517 /* if it is already mmapped here, we unmmap it */
518 rstVaddr = OsAllocSpecificRange(vmSpace, vaddr, len, regionFlags);
519 if (rstVaddr == 0) {
520 VM_ERR("alloc specific range va: %#x, len: %#x failed", vaddr, len);
521 goto OUT;
522 }
523 }
524 if (rstVaddr == 0) {
525 goto OUT;
526 }
527
528 newRegion = OsCreateRegion(rstVaddr, len, regionFlags, pgoff);
529 if (newRegion == NULL) {
530 goto OUT;
531 }
532 newRegion->space = vmSpace;
533 isInsertSucceed = OsInsertRegion(&vmSpace->regionRbTree, newRegion);
534 if (isInsertSucceed == FALSE) {
535 (VOID)LOS_MemFree(m_aucSysMem0, newRegion);
536 newRegion = NULL;
537 }
538
539 OUT:
540 (VOID)LOS_MuxRelease(&vmSpace->regionMux);
541 return newRegion;
542 }
543
OsAnonPagesRemove(LosArchMmu * archMmu,VADDR_T vaddr,UINT32 count)544 STATIC VOID OsAnonPagesRemove(LosArchMmu *archMmu, VADDR_T vaddr, UINT32 count)
545 {
546 status_t status;
547 paddr_t paddr;
548 LosVmPage *page = NULL;
549
550 if ((archMmu == NULL) || (vaddr == 0) || (count == 0)) {
551 VM_ERR("OsAnonPagesRemove invalid args, archMmu %p, vaddr %p, count %d", archMmu, vaddr, count);
552 return;
553 }
554
555 while (count > 0) {
556 count--;
557 status = LOS_ArchMmuQuery(archMmu, vaddr, &paddr, NULL);
558 if (status != LOS_OK) {
559 vaddr += PAGE_SIZE;
560 continue;
561 }
562
563 LOS_ArchMmuUnmap(archMmu, vaddr, 1);
564
565 page = LOS_VmPageGet(paddr);
566 if (page != NULL) {
567 if (!OsIsPageShared(page)) {
568 LOS_PhysPageFree(page);
569 }
570 }
571 vaddr += PAGE_SIZE;
572 }
573 }
574
OsDevPagesRemove(LosArchMmu * archMmu,VADDR_T vaddr,UINT32 count)575 STATIC VOID OsDevPagesRemove(LosArchMmu *archMmu, VADDR_T vaddr, UINT32 count)
576 {
577 status_t status;
578
579 if ((archMmu == NULL) || (vaddr == 0) || (count == 0)) {
580 VM_ERR("OsDevPagesRemove invalid args, archMmu %p, vaddr %p, count %d", archMmu, vaddr, count);
581 return;
582 }
583
584 status = LOS_ArchMmuQuery(archMmu, vaddr, NULL, NULL);
585 if (status != LOS_OK) {
586 return;
587 }
588
589 /* in order to unmap section */
590 LOS_ArchMmuUnmap(archMmu, vaddr, count);
591 }
592
593 #ifdef LOSCFG_FS_VFS
OsFilePagesRemove(LosVmSpace * space,LosVmMapRegion * region)594 STATIC VOID OsFilePagesRemove(LosVmSpace *space, LosVmMapRegion *region)
595 {
596 VM_OFFSET_T offset;
597 size_t size;
598
599 if ((space == NULL) || (region == NULL) || (region->unTypeData.rf.vmFOps == NULL)) {
600 return;
601 }
602
603 offset = region->pgOff;
604 size = region->range.size;
605 while (size >= PAGE_SIZE) {
606 region->unTypeData.rf.vmFOps->remove(region, &space->archMmu, offset);
607 offset++;
608 size -= PAGE_SIZE;
609 }
610 }
611 #endif
612
LOS_RegionFree(LosVmSpace * space,LosVmMapRegion * region)613 STATUS_T LOS_RegionFree(LosVmSpace *space, LosVmMapRegion *region)
614 {
615 if ((space == NULL) || (region == NULL)) {
616 VM_ERR("args error, aspace %p, region %p", space, region);
617 return LOS_ERRNO_VM_INVALID_ARGS;
618 }
619
620 (VOID)LOS_MuxAcquire(&space->regionMux);
621
622 #ifdef LOSCFG_FS_VFS
623 if (LOS_IsRegionFileValid(region)) {
624 OsFilePagesRemove(space, region);
625 VnodeHold();
626 region->unTypeData.rf.vnode->useCount--;
627 VnodeDrop();
628 } else
629 #endif
630
631 #ifdef LOSCFG_KERNEL_SHM
632 if (OsIsShmRegion(region)) {
633 OsShmRegionFree(space, region);
634 } else if (LOS_IsRegionTypeDev(region)) {
635 #else
636 if (LOS_IsRegionTypeDev(region)) {
637 #endif
638 OsDevPagesRemove(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);
639 } else {
640 OsAnonPagesRemove(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);
641 }
642
643 /* remove it from space */
644 LOS_RbDelNode(&space->regionRbTree, ®ion->rbNode);
645 /* free it */
646 LOS_MemFree(m_aucSysMem0, region);
647 (VOID)LOS_MuxRelease(&space->regionMux);
648 return LOS_OK;
649 }
650
651 LosVmMapRegion *OsVmRegionDup(LosVmSpace *space, LosVmMapRegion *oldRegion, VADDR_T vaddr, size_t size)
652 {
653 LosVmMapRegion *newRegion = NULL;
654 UINT32 regionFlags;
655
656 (VOID)LOS_MuxAcquire(&space->regionMux);
657 regionFlags = oldRegion->regionFlags;
658 if (vaddr == 0) {
659 regionFlags &= ~(VM_MAP_REGION_FLAG_FIXED | VM_MAP_REGION_FLAG_FIXED_NOREPLACE);
660 } else {
661 regionFlags |= VM_MAP_REGION_FLAG_FIXED;
662 }
663 newRegion = LOS_RegionAlloc(space, vaddr, size, regionFlags, oldRegion->pgOff);
664 if (newRegion == NULL) {
665 VM_ERR("LOS_RegionAlloc failed");
666 goto REGIONDUPOUT;
667 }
668 newRegion->regionType = oldRegion->regionType;
669
670 #ifdef LOSCFG_KERNEL_SHM
671 if (OsIsShmRegion(oldRegion)) {
672 newRegion->shmid = oldRegion->shmid;
673 }
674 #endif
675
676 #ifdef LOSCFG_FS_VFS
677 if (LOS_IsRegionTypeFile(oldRegion)) {
678 newRegion->unTypeData.rf.vmFOps = oldRegion->unTypeData.rf.vmFOps;
679 newRegion->unTypeData.rf.vnode = oldRegion->unTypeData.rf.vnode;
680 newRegion->unTypeData.rf.f_oflags = oldRegion->unTypeData.rf.f_oflags;
681 VnodeHold();
682 newRegion->unTypeData.rf.vnode->useCount++;
683 VnodeDrop();
684 }
685 #endif
686
687 REGIONDUPOUT:
688 (VOID)LOS_MuxRelease(&space->regionMux);
689 return newRegion;
690 }
691
692 STATIC LosVmMapRegion *OsVmRegionSplit(LosVmMapRegion *oldRegion, VADDR_T newRegionStart)
693 {
694 LosVmMapRegion *newRegion = NULL;
695 LosVmSpace *space = oldRegion->space;
696 size_t size = LOS_RegionSize(newRegionStart, LOS_RegionEndAddr(oldRegion));
697
698 oldRegion->range.size = LOS_RegionSize(oldRegion->range.base, newRegionStart - 1);
699 if (oldRegion->range.size == 0) {
700 LOS_RbDelNode(&space->regionRbTree, &oldRegion->rbNode);
701 }
702
703 newRegion = OsVmRegionDup(oldRegion->space, oldRegion, newRegionStart, size);
704 if (newRegion == NULL) {
705 VM_ERR("OsVmRegionDup fail");
706 return NULL;
707 }
708 #ifdef LOSCFG_FS_VFS
709 newRegion->pgOff = oldRegion->pgOff + ((newRegionStart - oldRegion->range.base) >> PAGE_SHIFT);
710 #endif
711 return newRegion;
712 }
713
714 STATUS_T OsVmRegionAdjust(LosVmSpace *space, VADDR_T newRegionStart, size_t size)
715 {
716 LosVmMapRegion *region = NULL;
717 VADDR_T nextRegionBase = newRegionStart + size;
718 LosVmMapRegion *newRegion = NULL;
719
720 region = LOS_RegionFind(space, newRegionStart);
721 if ((region != NULL) && (newRegionStart > region->range.base)) {
722 newRegion = OsVmRegionSplit(region, newRegionStart);
723 if (newRegion == NULL) {
724 VM_ERR("region split fail");
725 return LOS_ERRNO_VM_NO_MEMORY;
726 }
727 }
728
729 region = LOS_RegionFind(space, nextRegionBase - 1);
730 if ((region != NULL) && (nextRegionBase < LOS_RegionEndAddr(region))) {
731 newRegion = OsVmRegionSplit(region, nextRegionBase);
732 if (newRegion == NULL) {
733 VM_ERR("region split fail");
734 return LOS_ERRNO_VM_NO_MEMORY;
735 }
736 }
737
738 return LOS_OK;
739 }
740
741 STATUS_T OsRegionsRemove(LosVmSpace *space, VADDR_T regionBase, size_t size)
742 {
743 STATUS_T status;
744 VADDR_T regionEnd = regionBase + size - 1;
745 LosVmMapRegion *regionTemp = NULL;
746 LosRbNode *pstRbNodeTemp = NULL;
747 LosRbNode *pstRbNodeNext = NULL;
748
749 (VOID)LOS_MuxAcquire(&space->regionMux);
750
751 status = OsVmRegionAdjust(space, regionBase, size);
752 if (status != LOS_OK) {
753 goto ERR_REGION_SPLIT;
754 }
755
756 RB_SCAN_SAFE(&space->regionRbTree, pstRbNodeTemp, pstRbNodeNext)
757 regionTemp = (LosVmMapRegion *)pstRbNodeTemp;
758 if (regionTemp->range.base > regionEnd) {
759 break;
760 }
761 if (regionBase <= regionTemp->range.base && regionEnd >= LOS_RegionEndAddr(regionTemp)) {
762 status = LOS_RegionFree(space, regionTemp);
763 if (status != LOS_OK) {
764 VM_ERR("fail to free region, status=%d", status);
765 goto ERR_REGION_SPLIT;
766 }
767 }
768
769 RB_SCAN_SAFE_END(&space->regionRbTree, pstRbNodeTemp, pstRbNodeNext)
770
771 ERR_REGION_SPLIT:
772 (VOID)LOS_MuxRelease(&space->regionMux);
773 return status;
774 }
775
776 INT32 OsUserHeapFree(LosVmSpace *vmSpace, VADDR_T addr, size_t len)
777 {
778 LosVmMapRegion *vmRegion = NULL;
779 LosVmPage *vmPage = NULL;
780 PADDR_T paddr = 0;
781 VADDR_T vaddr;
782 STATUS_T ret;
783
784 if (vmSpace == LOS_GetKVmSpace() || vmSpace->heap == NULL) {
785 return -1;
786 }
787
788 vmRegion = LOS_RegionFind(vmSpace, addr);
789 if (vmRegion == NULL) {
790 return -1;
791 }
792
793 if (vmRegion == vmSpace->heap) {
794 vaddr = addr;
795 while (len > 0) {
796 if (LOS_ArchMmuQuery(&vmSpace->archMmu, vaddr, &paddr, 0) == LOS_OK) {
797 ret = LOS_ArchMmuUnmap(&vmSpace->archMmu, vaddr, 1);
798 if (ret <= 0) {
799 VM_ERR("unmap failed, ret = %d", ret);
800 }
801 vmPage = LOS_VmPageGet(paddr);
802 LOS_PhysPageFree(vmPage);
803 }
804 vaddr += PAGE_SIZE;
805 len -= PAGE_SIZE;
806 }
807 return 0;
808 }
809
810 return -1;
811 }
812
813 STATUS_T OsIsRegionCanExpand(LosVmSpace *space, LosVmMapRegion *region, size_t size)
814 {
815 LosVmMapRegion *nextRegion = NULL;
816
817 if ((space == NULL) || (region == NULL)) {
818 return LOS_NOK;
819 }
820
821 nextRegion = (LosVmMapRegion *)LOS_RbSuccessorNode(&space->regionRbTree, ®ion->rbNode);
822 /* if the gap is larger than size, then we can expand */
823 if ((nextRegion != NULL) && ((nextRegion->range.base - region->range.base) >= size)) {
824 return LOS_OK;
825 }
826
827 return LOS_NOK;
828 }
829
830 STATUS_T OsUnMMap(LosVmSpace *space, VADDR_T addr, size_t size)
831 {
832 size = LOS_Align(size, PAGE_SIZE);
833 addr = LOS_Align(addr, PAGE_SIZE);
834 (VOID)LOS_MuxAcquire(&space->regionMux);
835 STATUS_T status = OsRegionsRemove(space, addr, size);
836 if (status != LOS_OK) {
837 status = -EINVAL;
838 VM_ERR("region_split failed");
839 goto ERR_REGION_SPLIT;
840 }
841
842 ERR_REGION_SPLIT:
843 (VOID)LOS_MuxRelease(&space->regionMux);
844 return status;
845 }
846
847 STATIC VOID OsVmSpaceAllRegionFree(LosVmSpace *space)
848 {
849 LosRbNode *pstRbNode = NULL;
850 LosRbNode *pstRbNodeNext = NULL;
851
852 /* free all of the regions */
853 RB_SCAN_SAFE(&space->regionRbTree, pstRbNode, pstRbNodeNext)
854 LosVmMapRegion *region = (LosVmMapRegion *)pstRbNode;
855 if (region->range.size == 0) {
856 VM_ERR("space free, region: %#x flags: %#x, base:%#x, size: %#x",
857 region, region->regionFlags, region->range.base, region->range.size);
858 }
859 STATUS_T ret = LOS_RegionFree(space, region);
860 if (ret != LOS_OK) {
861 VM_ERR("free region error, space %p, region %p", space, region);
862 }
863 RB_SCAN_SAFE_END(&space->regionRbTree, pstRbNode, pstRbNodeNext)
864
865 return;
866 }
867
868 STATUS_T OsVmSpaceRegionFree(LosVmSpace *space)
869 {
870 if (space == NULL) {
871 return LOS_ERRNO_VM_INVALID_ARGS;
872 }
873
874 if (space == &g_kVmSpace) {
875 VM_ERR("try to free kernel aspace, not allowed");
876 return LOS_OK;
877 }
878
879 (VOID)LOS_MuxAcquire(&space->regionMux);
880 OsVmSpaceAllRegionFree(space);
881 (VOID)LOS_MuxRelease(&space->regionMux);
882
883 return LOS_OK;
884 }
885
886 STATUS_T LOS_VmSpaceFree(LosVmSpace *space)
887 {
888 if (space == NULL) {
889 return LOS_ERRNO_VM_INVALID_ARGS;
890 }
891
892 if (space == &g_kVmSpace) {
893 VM_ERR("try to free kernel aspace, not allowed");
894 return LOS_OK;
895 }
896
897 /* pop it out of the global aspace list */
898 (VOID)LOS_MuxAcquire(&space->regionMux);
899
900 LOS_ListDelete(&space->node);
901
902 OsVmSpaceAllRegionFree(space);
903
904 /* make sure the current thread does not map the aspace */
905 LosProcessCB *currentProcess = OsCurrProcessGet();
906 if (currentProcess->vmSpace == space) {
907 LOS_TaskLock();
908 currentProcess->vmSpace = NULL;
909 LOS_ArchMmuContextSwitch(&space->archMmu);
910 LOS_TaskUnlock();
911 }
912
913 /* destroy the arch portion of the space */
914 LOS_ArchMmuDestroy(&space->archMmu);
915
916 (VOID)LOS_MuxRelease(&space->regionMux);
917 (VOID)LOS_MuxDestroy(&space->regionMux);
918
919 /* free the aspace */
920 LOS_MemFree(m_aucSysMem0, space);
921 return LOS_OK;
922 }
923
924 BOOL LOS_IsRangeInSpace(const LosVmSpace *space, VADDR_T vaddr, size_t size)
925 {
926 /* is the starting address within the address space */
927 if (vaddr < space->base || vaddr > space->base + space->size - 1) {
928 return FALSE;
929 }
930 if (size == 0) {
931 return TRUE;
932 }
933 /* see if the size is enough to wrap the integer */
934 if (vaddr + size - 1 < vaddr) {
935 return FALSE;
936 }
937 /* see if the end address is within the address space's */
938 if (vaddr + size - 1 > space->base + space->size - 1) {
939 return FALSE;
940 }
941 return TRUE;
942 }
943
944 STATUS_T LOS_VmSpaceReserve(LosVmSpace *space, size_t size, VADDR_T vaddr)
945 {
946 UINT32 regionFlags = 0;
947
948 if ((space == NULL) || (size == 0) || (!IS_PAGE_ALIGNED(vaddr) || !IS_PAGE_ALIGNED(size))) {
949 return LOS_ERRNO_VM_INVALID_ARGS;
950 }
951
952 if (!LOS_IsRangeInSpace(space, vaddr, size)) {
953 return LOS_ERRNO_VM_OUT_OF_RANGE;
954 }
955
956 /* lookup how it's already mapped */
957 (VOID)LOS_ArchMmuQuery(&space->archMmu, vaddr, NULL, ®ionFlags);
958
959 /* build a new region structure */
960 LosVmMapRegion *region = LOS_RegionAlloc(space, vaddr, size, regionFlags | VM_MAP_REGION_FLAG_FIXED, 0);
961
962 return region ? LOS_OK : LOS_ERRNO_VM_NO_MEMORY;
963 }
964
965 STATUS_T LOS_VaddrToPaddrMmap(LosVmSpace *space, VADDR_T vaddr, PADDR_T paddr, size_t len, UINT32 flags)
966 {
967 STATUS_T ret;
968 LosVmMapRegion *region = NULL;
969 LosVmPage *vmPage = NULL;
970
971 if ((vaddr != ROUNDUP(vaddr, PAGE_SIZE)) ||
972 (paddr != ROUNDUP(paddr, PAGE_SIZE)) ||
973 (len != ROUNDUP(len, PAGE_SIZE))) {
974 VM_ERR("vaddr :0x%x paddr:0x%x len: 0x%x not page size align", vaddr, paddr, len);
975 return LOS_ERRNO_VM_NOT_VALID;
976 }
977
978 if (space == NULL) {
979 space = OsCurrProcessGet()->vmSpace;
980 }
981
982 region = LOS_RegionFind(space, vaddr);
983 if (region != NULL) {
984 VM_ERR("vaddr : 0x%x already used!", vaddr);
985 return LOS_ERRNO_VM_BUSY;
986 }
987
988 region = LOS_RegionAlloc(space, vaddr, len, flags, 0);
989 if (region == NULL) {
990 VM_ERR("failed");
991 return LOS_ERRNO_VM_NO_MEMORY;
992 }
993
994 while (len > 0) {
995 vmPage = LOS_VmPageGet(paddr);
996 if (vmPage == NULL) {
997 LOS_RegionFree(space, region);
998 VM_ERR("Page is NULL");
999 return LOS_ERRNO_VM_NOT_VALID;
1000 }
1001 LOS_AtomicInc(&vmPage->refCounts);
1002
1003 ret = LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, 1, region->regionFlags);
1004 if (ret <= 0) {
1005 VM_ERR("LOS_ArchMmuMap failed: %d", ret);
1006 LOS_RegionFree(space, region);
1007 return ret;
1008 }
1009
1010 paddr += PAGE_SIZE;
1011 vaddr += PAGE_SIZE;
1012 len -= PAGE_SIZE;
1013 }
1014 return LOS_OK;
1015 }
1016
1017 VOID *LOS_VMalloc(size_t size)
1018 {
1019 LosVmSpace *space = &g_vMallocSpace;
1020 LosVmMapRegion *region = NULL;
1021 size_t sizeCount;
1022 size_t count;
1023 LosVmPage *vmPage = NULL;
1024 VADDR_T va;
1025 PADDR_T pa;
1026 STATUS_T ret;
1027
1028 size = LOS_Align(size, PAGE_SIZE);
1029 if ((size == 0) || (size > space->size)) {
1030 return NULL;
1031 }
1032 sizeCount = size >> PAGE_SHIFT;
1033
1034 LOS_DL_LIST_HEAD(pageList);
1035 (VOID)LOS_MuxAcquire(&space->regionMux);
1036
1037 count = LOS_PhysPagesAlloc(sizeCount, &pageList);
1038 if (count < sizeCount) {
1039 VM_ERR("failed to allocate enough pages (ask %zu, got %zu)", sizeCount, count);
1040 goto ERROR;
1041 }
1042
1043 /* allocate a region and put it in the aspace list */
1044 region = LOS_RegionAlloc(space, 0, size, VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE, 0);
1045 if (region == NULL) {
1046 VM_ERR("alloc region failed, size = %x", size);
1047 goto ERROR;
1048 }
1049
1050 va = region->range.base;
1051 while ((vmPage = LOS_ListRemoveHeadType(&pageList, LosVmPage, node))) {
1052 pa = vmPage->physAddr;
1053 LOS_AtomicInc(&vmPage->refCounts);
1054 ret = LOS_ArchMmuMap(&space->archMmu, va, pa, 1, region->regionFlags);
1055 if (ret != 1) {
1056 VM_ERR("LOS_ArchMmuMap failed!, err;%d", ret);
1057 }
1058 va += PAGE_SIZE;
1059 }
1060
1061 (VOID)LOS_MuxRelease(&space->regionMux);
1062 return (VOID *)(UINTPTR)region->range.base;
1063
1064 ERROR:
1065 (VOID)LOS_PhysPagesFree(&pageList);
1066 (VOID)LOS_MuxRelease(&space->regionMux);
1067 return NULL;
1068 }
1069
1070 VOID LOS_VFree(const VOID *addr)
1071 {
1072 LosVmSpace *space = &g_vMallocSpace;
1073 LosVmMapRegion *region = NULL;
1074 STATUS_T ret;
1075
1076 if (addr == NULL) {
1077 VM_ERR("addr is NULL!");
1078 return;
1079 }
1080
1081 (VOID)LOS_MuxAcquire(&space->regionMux);
1082
1083 region = LOS_RegionFind(space, (VADDR_T)(UINTPTR)addr);
1084 if (region == NULL) {
1085 VM_ERR("find region failed");
1086 goto DONE;
1087 }
1088
1089 ret = LOS_RegionFree(space, region);
1090 if (ret) {
1091 VM_ERR("free region failed, ret = %d", ret);
1092 }
1093
1094 DONE:
1095 (VOID)LOS_MuxRelease(&space->regionMux);
1096 }
1097
1098 LosMux *OsGVmSpaceMuxGet(VOID)
1099 {
1100 return &g_vmSpaceListMux;
1101 }
1102
1103 STATIC INLINE BOOL OsMemLargeAlloc(UINT32 size)
1104 {
1105 if (g_kHeapInited == FALSE) {
1106 return FALSE;
1107 }
1108
1109 if (size < KMALLOC_LARGE_SIZE) {
1110 return FALSE;
1111 }
1112
1113 return TRUE;
1114 }
1115 #else
1116 PADDR_T LOS_PaddrQuery(VOID *vaddr)
1117 {
1118 if (!LOS_IsKernelAddress((VADDR_T)vaddr)) {
1119 return 0;
1120 }
1121
1122 return (PADDR_T)VMM_TO_DMA_ADDR((VADDR_T)vaddr);
1123 }
1124 #endif
1125
1126 VOID *LOS_KernelMalloc(UINT32 size)
1127 {
1128 VOID *ptr = NULL;
1129
1130 #ifdef LOSCFG_KERNEL_VM
1131 if (OsMemLargeAlloc(size)) {
1132 ptr = LOS_PhysPagesAllocContiguous(ROUNDUP(size, PAGE_SIZE) >> PAGE_SHIFT);
1133 } else
1134 #endif
1135 {
1136 ptr = LOS_MemAlloc(OS_SYS_MEM_ADDR, size);
1137 }
1138
1139 return ptr;
1140 }
1141
1142 VOID *LOS_KernelMallocAlign(UINT32 size, UINT32 boundary)
1143 {
1144 VOID *ptr = NULL;
1145
1146 #ifdef LOSCFG_KERNEL_VM
1147 if (OsMemLargeAlloc(size) && IS_ALIGNED(PAGE_SIZE, boundary)) {
1148 ptr = LOS_PhysPagesAllocContiguous(ROUNDUP(size, PAGE_SIZE) >> PAGE_SHIFT);
1149 } else
1150 #endif
1151 {
1152 ptr = LOS_MemAllocAlign(OS_SYS_MEM_ADDR, size, boundary);
1153 }
1154
1155 return ptr;
1156 }
1157
1158 VOID *LOS_KernelRealloc(VOID *ptr, UINT32 size)
1159 {
1160 VOID *tmpPtr = NULL;
1161
1162 #ifdef LOSCFG_KERNEL_VM
1163 LosVmPage *page = NULL;
1164 errno_t ret;
1165 if (ptr == NULL) {
1166 tmpPtr = LOS_KernelMalloc(size);
1167 } else {
1168 if (OsMemIsHeapNode(ptr) == FALSE) {
1169 page = OsVmVaddrToPage(ptr);
1170 if (page == NULL) {
1171 VM_ERR("page of ptr(%#x) is null", ptr);
1172 return NULL;
1173 }
1174 tmpPtr = LOS_KernelMalloc(size);
1175 if (tmpPtr == NULL) {
1176 VM_ERR("alloc memory failed");
1177 return NULL;
1178 }
1179 ret = memcpy_s(tmpPtr, size, ptr, page->nPages << PAGE_SHIFT);
1180 if (ret != EOK) {
1181 LOS_KernelFree(tmpPtr);
1182 VM_ERR("KernelRealloc memcpy error");
1183 return NULL;
1184 }
1185 OsMemLargeNodeFree(ptr);
1186 } else {
1187 tmpPtr = LOS_MemRealloc(OS_SYS_MEM_ADDR, ptr, size);
1188 }
1189 }
1190 #else
1191 tmpPtr = LOS_MemRealloc(OS_SYS_MEM_ADDR, ptr, size);
1192 #endif
1193
1194 return tmpPtr;
1195 }
1196
1197 VOID LOS_KernelFree(VOID *ptr)
1198 {
1199 #ifdef LOSCFG_KERNEL_VM
1200 UINT32 ret;
1201 if (OsMemIsHeapNode(ptr) == FALSE) {
1202 ret = OsMemLargeNodeFree(ptr);
1203 if (ret != LOS_OK) {
1204 VM_ERR("KernelFree %p failed", ptr);
1205 return;
1206 }
1207 } else
1208 #endif
1209 {
1210 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, ptr);
1211 }
1212 }
1213