• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2023 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 "stdio.h"
33 #include "string.h"
34 #include "time.h"
35 #include "sys/types.h"
36 #include "sys/stat.h"
37 #include "los_config.h"
38 #include "los_init.h"
39 #include "los_vm_map.h"
40 #include "los_vm_filemap.h"
41 #include "los_vm_phys.h"
42 #include "los_arch_mmu.h"
43 #include "los_vm_page.h"
44 #include "los_vm_lock.h"
45 #include "los_process.h"
46 #include "los_process_pri.h"
47 #include "user_copy.h"
48 #include "los_vm_shm_pri.h"
49 #include "sys/shm.h"
50 #ifdef LOSCFG_SHELL
51 #include "shcmd.h"
52 #include "shell.h"
53 #endif
54 
55 
56 #ifdef LOSCFG_KERNEL_SHM
57 
58 #define SHM_SEG_FREE    0x2000
59 #define SHM_SEG_USED    0x4000
60 #define SHM_SEG_REMOVE  0x8000
61 
62 #ifndef SHM_M
63 #define SHM_M   010000
64 #endif
65 
66 #ifndef SHM_X
67 #define SHM_X   0100
68 #endif
69 
70 #ifndef ACCESSPERMS
71 #define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO)
72 #endif
73 
74 #define SHM_S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
75 #define SHM_S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
76 #define SHM_S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
77 
78 #define SHM_GROUPE_TO_USER  3
79 #define SHM_OTHER_TO_USER   6
80 
81 #ifndef LOSCFG_IPC_CONTAINER
82 STATIC LosMux g_sysvShmMux;
83 
84 /* private data */
85 STATIC struct shminfo g_shmInfo;
86 STATIC struct shmIDSource *g_shmSegs = NULL;
87 STATIC UINT32 g_shmUsedPageCount;
88 
89 #define IPC_SHM_INFO            g_shmInfo
90 #define IPC_SHM_SYS_VSHM_MUTEX  g_sysvShmMux
91 #define IPC_SHM_SEGS            g_shmSegs
92 #define IPC_SHM_USED_PAGE_COUNT g_shmUsedPageCount
93 #endif
94 
95 /* private macro */
96 #define SYSV_SHM_LOCK()     (VOID)LOS_MuxLock(&IPC_SHM_SYS_VSHM_MUTEX, LOS_WAIT_FOREVER)
97 #define SYSV_SHM_UNLOCK()   (VOID)LOS_MuxUnlock(&IPC_SHM_SYS_VSHM_MUTEX)
98 
OsShmCBInit(LosMux * sysvShmMux,struct shminfo * shmInfo,UINT32 * shmUsedPageCount)99 struct shmIDSource *OsShmCBInit(LosMux *sysvShmMux, struct shminfo *shmInfo, UINT32 *shmUsedPageCount)
100 {
101     UINT32 ret;
102     UINT32 i;
103 
104     if ((sysvShmMux == NULL) || (shmInfo == NULL) || (shmUsedPageCount == NULL)) {
105         return NULL;
106     }
107 
108     ret = LOS_MuxInit(sysvShmMux, NULL);
109     if (ret != LOS_OK) {
110         goto ERROR;
111     }
112 
113     shmInfo->shmmax = SHM_MAX;
114     shmInfo->shmmin = SHM_MIN;
115     shmInfo->shmmni = SHM_MNI;
116     shmInfo->shmseg = SHM_SEG;
117     shmInfo->shmall = SHM_ALL;
118 
119     struct shmIDSource *shmSegs = LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, sizeof(struct shmIDSource) * shmInfo->shmmni);
120     if (shmSegs == NULL) {
121         (VOID)LOS_MuxDestroy(sysvShmMux);
122         goto ERROR;
123     }
124     (VOID)memset_s(shmSegs, (sizeof(struct shmIDSource) * shmInfo->shmmni),
125                    0, (sizeof(struct shmIDSource) * shmInfo->shmmni));
126 
127     for (i = 0; i < shmInfo->shmmni; i++) {
128         shmSegs[i].status = SHM_SEG_FREE;
129         shmSegs[i].ds.shm_perm.seq = i + 1;
130         LOS_ListInit(&shmSegs[i].node);
131     }
132     *shmUsedPageCount = 0;
133 
134     return shmSegs;
135 
136 ERROR:
137     VM_ERR("ShmInit fail\n");
138     return NULL;
139 }
140 
ShmInit(VOID)141 UINT32 ShmInit(VOID)
142 {
143 #ifndef LOSCFG_IPC_CONTAINER
144     g_shmSegs = OsShmCBInit(&IPC_SHM_SYS_VSHM_MUTEX, &IPC_SHM_INFO, &IPC_SHM_USED_PAGE_COUNT);
145     if (g_shmSegs == NULL) {
146         return LOS_NOK;
147     }
148 #endif
149     return LOS_OK;
150 }
151 
152 LOS_MODULE_INIT(ShmInit, LOS_INIT_LEVEL_VM_COMPLETE);
153 
ShmDeinit(VOID)154 UINT32 ShmDeinit(VOID)
155 {
156     UINT32 ret;
157 
158     (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, IPC_SHM_SEGS);
159     IPC_SHM_SEGS = NULL;
160 
161     ret = LOS_MuxDestroy(&IPC_SHM_SYS_VSHM_MUTEX);
162     if (ret != LOS_OK) {
163         return -1;
164     }
165 
166     return 0;
167 }
168 
ShmSetSharedFlag(struct shmIDSource * seg)169 STATIC inline VOID ShmSetSharedFlag(struct shmIDSource *seg)
170 {
171     LosVmPage *page = NULL;
172 
173     LOS_DL_LIST_FOR_EACH_ENTRY(page, &seg->node, LosVmPage, node) {
174         OsSetPageShared(page);
175     }
176 }
177 
ShmClearSharedFlag(struct shmIDSource * seg)178 STATIC inline VOID ShmClearSharedFlag(struct shmIDSource *seg)
179 {
180     LosVmPage *page = NULL;
181 
182     LOS_DL_LIST_FOR_EACH_ENTRY(page, &seg->node, LosVmPage, node) {
183         OsCleanPageShared(page);
184     }
185 }
186 
ShmPagesRefDec(struct shmIDSource * seg)187 STATIC VOID ShmPagesRefDec(struct shmIDSource *seg)
188 {
189     LosVmPage *page = NULL;
190 
191     LOS_DL_LIST_FOR_EACH_ENTRY(page, &seg->node, LosVmPage, node) {
192         LOS_AtomicDec(&page->refCounts);
193     }
194 }
195 
ShmAllocSegCheck(key_t key,size_t * size,INT32 * segNum)196 STATIC INT32 ShmAllocSegCheck(key_t key, size_t *size, INT32 *segNum)
197 {
198     INT32 i;
199     if ((*size == 0) || (*size < IPC_SHM_INFO.shmmin) ||
200         (*size > IPC_SHM_INFO.shmmax)) {
201         return -EINVAL;
202     }
203 
204     *size = LOS_Align(*size, PAGE_SIZE);
205     if ((IPC_SHM_USED_PAGE_COUNT + (*size >> PAGE_SHIFT)) > IPC_SHM_INFO.shmall) {
206         return -ENOMEM;
207     }
208 
209 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
210     if (OsIPCLimitShmAlloc(*size) != LOS_OK) {
211         return -ENOMEM;
212     }
213 #endif
214 
215     for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {
216         if (IPC_SHM_SEGS[i].status & SHM_SEG_FREE) {
217             IPC_SHM_SEGS[i].status &= ~SHM_SEG_FREE;
218             *segNum = i;
219             break;
220         }
221     }
222 
223     if (*segNum < 0) {
224         return -ENOSPC;
225     }
226     return 0;
227 }
228 
ShmAllocSeg(key_t key,size_t size,INT32 shmflg)229 STATIC INT32 ShmAllocSeg(key_t key, size_t size, INT32 shmflg)
230 {
231     INT32 segNum = -1;
232     struct shmIDSource *seg = NULL;
233     size_t count;
234 
235     INT32 ret = ShmAllocSegCheck(key, &size, &segNum);
236     if (ret < 0) {
237         return ret;
238     }
239 
240     seg = &IPC_SHM_SEGS[segNum];
241     count = LOS_PhysPagesAlloc(size >> PAGE_SHIFT, &seg->node);
242     if (count != (size >> PAGE_SHIFT)) {
243         (VOID)LOS_PhysPagesFree(&seg->node);
244         seg->status = SHM_SEG_FREE;
245 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
246         OsIPCLimitShmFree(size);
247 #endif
248         return -ENOMEM;
249     }
250 
251     ShmSetSharedFlag(seg);
252     IPC_SHM_USED_PAGE_COUNT += size >> PAGE_SHIFT;
253 
254     seg->status |= SHM_SEG_USED;
255     seg->ds.shm_perm.mode = (UINT32)shmflg & ACCESSPERMS;
256     seg->ds.shm_perm.key = key;
257     seg->ds.shm_segsz = size;
258     seg->ds.shm_perm.cuid = LOS_GetUserID();
259     seg->ds.shm_perm.uid = LOS_GetUserID();
260     seg->ds.shm_perm.cgid = LOS_GetGroupID();
261     seg->ds.shm_perm.gid = LOS_GetGroupID();
262     seg->ds.shm_lpid = 0;
263     seg->ds.shm_nattch = 0;
264     seg->ds.shm_cpid = LOS_GetCurrProcessID();
265     seg->ds.shm_atime = 0;
266     seg->ds.shm_dtime = 0;
267     seg->ds.shm_ctime = time(NULL);
268 #ifdef LOSCFG_SHELL
269     (VOID)memcpy_s(seg->ownerName, OS_PCB_NAME_LEN, OsCurrProcessGet()->processName, OS_PCB_NAME_LEN);
270 #endif
271 
272     return segNum;
273 }
274 
ShmFreeSeg(struct shmIDSource * seg,UINT32 * shmUsedPageCount)275 STATIC INLINE VOID ShmFreeSeg(struct shmIDSource *seg, UINT32 *shmUsedPageCount)
276 {
277     UINT32 count;
278 
279     ShmClearSharedFlag(seg);
280     count = LOS_PhysPagesFree(&seg->node);
281     if (count != (seg->ds.shm_segsz >> PAGE_SHIFT)) {
282         VM_ERR("free physical pages failed, count = %d, size = %d", count, seg->ds.shm_segsz >> PAGE_SHIFT);
283         return;
284     }
285 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
286     OsIPCLimitShmFree(seg->ds.shm_segsz);
287 #endif
288     if (shmUsedPageCount != NULL) {
289         (*shmUsedPageCount) -= seg->ds.shm_segsz >> PAGE_SHIFT;
290     }
291     seg->status = SHM_SEG_FREE;
292     LOS_ListInit(&seg->node);
293 }
294 
ShmFindSegByKey(key_t key)295 STATIC INT32 ShmFindSegByKey(key_t key)
296 {
297     INT32 i;
298     struct shmIDSource *seg = NULL;
299 
300     for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {
301         seg = &IPC_SHM_SEGS[i];
302         if ((seg->status & SHM_SEG_USED) &&
303             (seg->ds.shm_perm.key == key)) {
304             return i;
305         }
306     }
307 
308     return -1;
309 }
310 
ShmSegValidCheck(INT32 segNum,size_t size,INT32 shmFlg)311 STATIC INT32 ShmSegValidCheck(INT32 segNum, size_t size, INT32 shmFlg)
312 {
313     struct shmIDSource *seg = &IPC_SHM_SEGS[segNum];
314 
315     if (size > seg->ds.shm_segsz) {
316         return -EINVAL;
317     }
318 
319     if (((UINT32)shmFlg & (IPC_CREAT | IPC_EXCL)) ==
320         (IPC_CREAT | IPC_EXCL)) {
321         return -EEXIST;
322     }
323 
324     return segNum;
325 }
326 
ShmFindSeg(int shmid)327 STATIC struct shmIDSource *ShmFindSeg(int shmid)
328 {
329     struct shmIDSource *seg = NULL;
330 
331     if ((shmid < 0) || (shmid >= IPC_SHM_INFO.shmmni)) {
332         set_errno(EINVAL);
333         return NULL;
334     }
335 
336     seg = &IPC_SHM_SEGS[shmid];
337     if ((seg->status & SHM_SEG_FREE) || ((seg->ds.shm_nattch == 0) && (seg->status & SHM_SEG_REMOVE))) {
338         set_errno(EIDRM);
339         return NULL;
340     }
341 
342     return seg;
343 }
344 
ShmVmmMapping(LosVmSpace * space,LOS_DL_LIST * pageList,VADDR_T vaddr,UINT32 regionFlags)345 STATIC VOID ShmVmmMapping(LosVmSpace *space, LOS_DL_LIST *pageList, VADDR_T vaddr, UINT32 regionFlags)
346 {
347     LosVmPage *vmPage = NULL;
348     VADDR_T va = vaddr;
349     PADDR_T pa;
350     STATUS_T ret;
351 
352     LOS_DL_LIST_FOR_EACH_ENTRY(vmPage, pageList, LosVmPage, node) {
353         pa = VM_PAGE_TO_PHYS(vmPage);
354         LOS_AtomicInc(&vmPage->refCounts);
355         ret = LOS_ArchMmuMap(&space->archMmu, va, pa, 1, regionFlags);
356         if (ret != 1) {
357             VM_ERR("LOS_ArchMmuMap failed, ret = %d", ret);
358         }
359         va += PAGE_SIZE;
360     }
361 }
362 
OsShmFork(LosVmSpace * space,LosVmMapRegion * oldRegion,LosVmMapRegion * newRegion)363 VOID OsShmFork(LosVmSpace *space, LosVmMapRegion *oldRegion, LosVmMapRegion *newRegion)
364 {
365     struct shmIDSource *seg = NULL;
366 
367     SYSV_SHM_LOCK();
368     seg = ShmFindSeg(oldRegion->shmid);
369     if (seg == NULL) {
370         SYSV_SHM_UNLOCK();
371         VM_ERR("shm fork failed!");
372         return;
373     }
374 
375     newRegion->shmid = oldRegion->shmid;
376     newRegion->forkFlags = oldRegion->forkFlags;
377     ShmVmmMapping(space, &seg->node, newRegion->range.base, newRegion->regionFlags);
378     seg->ds.shm_nattch++;
379     SYSV_SHM_UNLOCK();
380 }
381 
OsShmRegionFree(LosVmSpace * space,LosVmMapRegion * region)382 VOID OsShmRegionFree(LosVmSpace *space, LosVmMapRegion *region)
383 {
384     struct shmIDSource *seg = NULL;
385 
386     SYSV_SHM_LOCK();
387     seg = ShmFindSeg(region->shmid);
388     if (seg == NULL) {
389         SYSV_SHM_UNLOCK();
390         return;
391     }
392 
393     LOS_ArchMmuUnmap(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);
394     ShmPagesRefDec(seg);
395     seg->ds.shm_nattch--;
396     if (seg->ds.shm_nattch <= 0 && (seg->status & SHM_SEG_REMOVE)) {
397         ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);
398     } else {
399         seg->ds.shm_dtime = time(NULL);
400         seg->ds.shm_lpid = LOS_GetCurrProcessID(); /* may not be the space's PID. */
401     }
402     SYSV_SHM_UNLOCK();
403 }
404 
OsIsShmRegion(LosVmMapRegion * region)405 BOOL OsIsShmRegion(LosVmMapRegion *region)
406 {
407     return (region->regionFlags & VM_MAP_REGION_FLAG_SHM) ? TRUE : FALSE;
408 }
409 
ShmSegUsedCount(VOID)410 STATIC INT32 ShmSegUsedCount(VOID)
411 {
412     INT32 i;
413     INT32 count = 0;
414     struct shmIDSource *seg = NULL;
415 
416     for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {
417         seg = &IPC_SHM_SEGS[i];
418         if (seg->status & SHM_SEG_USED) {
419             count++;
420         }
421     }
422     return count;
423 }
424 
ShmPermCheck(struct shmIDSource * seg,mode_t mode)425 STATIC INT32 ShmPermCheck(struct shmIDSource *seg, mode_t mode)
426 {
427     INT32 uid = LOS_GetUserID();
428     UINT32 tmpMode = 0;
429     mode_t privMode = seg->ds.shm_perm.mode;
430     mode_t accMode;
431 
432     if ((uid == seg->ds.shm_perm.uid) || (uid == seg->ds.shm_perm.cuid)) {
433         tmpMode |= SHM_M;
434         accMode = mode & S_IRWXU;
435     } else if (LOS_CheckInGroups(seg->ds.shm_perm.gid) ||
436                LOS_CheckInGroups(seg->ds.shm_perm.cgid)) {
437         privMode <<= SHM_GROUPE_TO_USER;
438         accMode = (mode & S_IRWXG) << SHM_GROUPE_TO_USER;
439     } else {
440         privMode <<= SHM_OTHER_TO_USER;
441         accMode = (mode & S_IRWXO) << SHM_OTHER_TO_USER;
442     }
443 
444     if (privMode & SHM_R) {
445         tmpMode |= SHM_R;
446     }
447 
448     if (privMode & SHM_W) {
449         tmpMode |= SHM_W;
450     }
451 
452     if (privMode & SHM_X) {
453         tmpMode |= SHM_X;
454     }
455 
456     if ((mode == SHM_M) && (tmpMode & SHM_M)) {
457         return 0;
458     } else if (mode == SHM_M) {
459         return EACCES;
460     }
461 
462     if ((tmpMode & accMode) == accMode) {
463         return 0;
464     } else {
465         return EACCES;
466     }
467 }
468 
ShmGet(key_t key,size_t size,INT32 shmflg)469 INT32 ShmGet(key_t key, size_t size, INT32 shmflg)
470 {
471     INT32 ret;
472     INT32 shmid;
473 
474     SYSV_SHM_LOCK();
475 
476     if (key == IPC_PRIVATE) {
477         ret = ShmAllocSeg(key, size, shmflg);
478     } else {
479         ret = ShmFindSegByKey(key);
480         if (ret < 0) {
481             if (((UINT32)shmflg & IPC_CREAT) == 0) {
482                 ret = -ENOENT;
483                 goto ERROR;
484             } else {
485                 ret = ShmAllocSeg(key, size, shmflg);
486             }
487         } else {
488             shmid = ret;
489             if (((UINT32)shmflg & IPC_CREAT) &&
490                 ((UINT32)shmflg & IPC_EXCL)) {
491                 ret = -EEXIST;
492                 goto ERROR;
493             }
494             ret = ShmPermCheck(ShmFindSeg(shmid), (UINT32)shmflg & ACCESSPERMS);
495             if (ret != 0) {
496                 ret = -ret;
497                 goto ERROR;
498             }
499             ret = ShmSegValidCheck(shmid, size, shmflg);
500         }
501     }
502     if (ret < 0) {
503         goto ERROR;
504     }
505 
506     SYSV_SHM_UNLOCK();
507 
508     return ret;
509 ERROR:
510     set_errno(-ret);
511     SYSV_SHM_UNLOCK();
512     PRINT_DEBUG("%s %d, ret = %d\n", __FUNCTION__, __LINE__, ret);
513     return -1;
514 }
515 
ShmatParamCheck(const VOID * shmaddr,INT32 shmflg)516 INT32 ShmatParamCheck(const VOID *shmaddr, INT32 shmflg)
517 {
518     if (((UINT32)shmflg & SHM_REMAP) && (shmaddr == NULL)) {
519         return EINVAL;
520     }
521 
522     if ((shmaddr != NULL) && !IS_PAGE_ALIGNED(shmaddr) &&
523         (((UINT32)shmflg & SHM_RND) == 0)) {
524         return EINVAL;
525     }
526 
527     return 0;
528 }
529 
ShmatVmmAlloc(struct shmIDSource * seg,const VOID * shmaddr,INT32 shmflg,UINT32 prot)530 LosVmMapRegion *ShmatVmmAlloc(struct shmIDSource *seg, const VOID *shmaddr,
531                               INT32 shmflg, UINT32 prot)
532 {
533     LosVmSpace *space = OsCurrProcessGet()->vmSpace;
534     LosVmMapRegion *region = NULL;
535     UINT32 flags = MAP_ANONYMOUS | MAP_SHARED;
536     UINT32 mapFlags = flags | MAP_FIXED;
537     VADDR_T vaddr;
538     UINT32 regionFlags;
539     INT32 ret;
540 
541     if (shmaddr != NULL) {
542         flags |= MAP_FIXED_NOREPLACE;
543     }
544     regionFlags = OsCvtProtFlagsToRegionFlags(prot, flags);
545     (VOID)LOS_MuxAcquire(&space->regionMux);
546     if (shmaddr == NULL) {
547         region = LOS_RegionAlloc(space, 0, seg->ds.shm_segsz, regionFlags, 0);
548     } else {
549         if ((UINT32)shmflg & SHM_RND) {
550             vaddr = ROUNDDOWN((VADDR_T)(UINTPTR)shmaddr, SHMLBA);
551         } else {
552             vaddr = (VADDR_T)(UINTPTR)shmaddr;
553         }
554         if (!((UINT32)shmflg & SHM_REMAP) && (LOS_RegionFind(space, vaddr) ||
555             LOS_RegionFind(space, vaddr + seg->ds.shm_segsz - 1) ||
556             LOS_RegionRangeFind(space, vaddr, seg->ds.shm_segsz - 1))) {
557             ret = EINVAL;
558             goto ERROR;
559         }
560         vaddr = (VADDR_T)LOS_MMap(vaddr, seg->ds.shm_segsz, prot, mapFlags, -1, 0);
561         region = LOS_RegionFind(space, vaddr);
562     }
563 
564     if (region == NULL) {
565         ret = ENOMEM;
566         goto ERROR;
567     }
568     ShmVmmMapping(space, &seg->node, region->range.base, regionFlags);
569     (VOID)LOS_MuxRelease(&space->regionMux);
570     return region;
571 ERROR:
572     set_errno(ret);
573     (VOID)LOS_MuxRelease(&space->regionMux);
574     return NULL;
575 }
576 
ShmAt(INT32 shmid,const VOID * shmaddr,INT32 shmflg)577 VOID *ShmAt(INT32 shmid, const VOID *shmaddr, INT32 shmflg)
578 {
579     INT32 ret;
580     UINT32 prot = PROT_READ;
581     mode_t acc_mode = SHM_S_IRUGO;
582     struct shmIDSource *seg = NULL;
583     LosVmMapRegion *r = NULL;
584 
585     ret = ShmatParamCheck(shmaddr, shmflg);
586     if (ret != 0) {
587         set_errno(ret);
588         return (VOID *)-1;
589     }
590 
591     if ((UINT32)shmflg & SHM_EXEC) {
592         prot |= PROT_EXEC;
593         acc_mode |= SHM_S_IXUGO;
594     } else if (((UINT32)shmflg & SHM_RDONLY) == 0) {
595         prot |= PROT_WRITE;
596         acc_mode |= SHM_S_IWUGO;
597     }
598 
599     SYSV_SHM_LOCK();
600     seg = ShmFindSeg(shmid);
601     if (seg == NULL) {
602         SYSV_SHM_UNLOCK();
603         return (VOID *)-1;
604     }
605 
606     ret = ShmPermCheck(seg, acc_mode);
607     if (ret != 0) {
608         goto ERROR;
609     }
610 
611     seg->ds.shm_nattch++;
612     r = ShmatVmmAlloc(seg, shmaddr, shmflg, prot);
613     if (r == NULL) {
614         seg->ds.shm_nattch--;
615         SYSV_SHM_UNLOCK();
616         return (VOID *)-1;
617     }
618 
619     r->shmid = shmid;
620     r->regionFlags |= VM_MAP_REGION_FLAG_SHM;
621     seg->ds.shm_atime = time(NULL);
622     seg->ds.shm_lpid = LOS_GetCurrProcessID();
623     SYSV_SHM_UNLOCK();
624 
625     return (VOID *)(UINTPTR)r->range.base;
626 ERROR:
627     set_errno(ret);
628     SYSV_SHM_UNLOCK();
629     PRINT_DEBUG("%s %d, ret = %d\n", __FUNCTION__, __LINE__, ret);
630     return (VOID *)-1;
631 }
632 
ShmCtl(INT32 shmid,INT32 cmd,struct shmid_ds * buf)633 INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
634 {
635     struct shmIDSource *seg = NULL;
636     INT32 ret = 0;
637     struct shm_info shmInfo = { 0 };
638     struct ipc_perm shm_perm;
639 
640     cmd = ((UINT32)cmd & ~IPC_64);
641 
642     SYSV_SHM_LOCK();
643 
644     if ((cmd != IPC_INFO) && (cmd != SHM_INFO)) {
645         seg = ShmFindSeg(shmid);
646         if (seg == NULL) {
647             SYSV_SHM_UNLOCK();
648             return -1;
649         }
650     }
651 
652     if ((buf == NULL) && (cmd != IPC_RMID)) {
653         ret = EINVAL;
654         goto ERROR;
655     }
656 
657     switch (cmd) {
658         case IPC_STAT:
659         case SHM_STAT:
660             ret = ShmPermCheck(seg, SHM_S_IRUGO);
661             if (ret != 0) {
662                 goto ERROR;
663             }
664 
665             ret = LOS_ArchCopyToUser(buf, &seg->ds, sizeof(struct shmid_ds));
666             if (ret != 0) {
667                 ret = EFAULT;
668                 goto ERROR;
669             }
670             if (cmd == SHM_STAT) {
671                 ret = (unsigned int)((unsigned int)seg->ds.shm_perm.seq << 16) | (unsigned int)((unsigned int)shmid & 0xffff); /* 16: use the seq as the upper 16 bits */
672             }
673             break;
674         case IPC_SET:
675             ret = ShmPermCheck(seg, SHM_M);
676             if (ret != 0) {
677                 ret = EPERM;
678                 goto ERROR;
679             }
680 
681             ret = LOS_ArchCopyFromUser(&shm_perm, &buf->shm_perm, sizeof(struct ipc_perm));
682             if (ret != 0) {
683                 ret = EFAULT;
684                 goto ERROR;
685             }
686             seg->ds.shm_perm.uid = shm_perm.uid;
687             seg->ds.shm_perm.gid = shm_perm.gid;
688             seg->ds.shm_perm.mode = (seg->ds.shm_perm.mode & ~ACCESSPERMS) |
689                                     (shm_perm.mode & ACCESSPERMS);
690             seg->ds.shm_ctime = time(NULL);
691 #ifdef LOSCFG_SHELL
692             (VOID)memcpy_s(seg->ownerName, OS_PCB_NAME_LEN, OS_PCB_FROM_PID(shm_perm.uid)->processName,
693                            OS_PCB_NAME_LEN);
694 #endif
695             break;
696         case IPC_RMID:
697             ret = ShmPermCheck(seg, SHM_M);
698             if (ret != 0) {
699                 ret = EPERM;
700                 goto ERROR;
701             }
702 
703             seg->status |= SHM_SEG_REMOVE;
704             if (seg->ds.shm_nattch <= 0) {
705                 ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);
706             }
707             break;
708         case IPC_INFO:
709             ret = LOS_ArchCopyToUser(buf, &IPC_SHM_INFO, sizeof(struct shminfo));
710             if (ret != 0) {
711                 ret = EFAULT;
712                 goto ERROR;
713             }
714             ret = IPC_SHM_INFO.shmmni;
715             break;
716         case SHM_INFO:
717             shmInfo.shm_rss = 0;
718             shmInfo.shm_swp = 0;
719             shmInfo.shm_tot = 0;
720             shmInfo.swap_attempts = 0;
721             shmInfo.swap_successes = 0;
722             shmInfo.used_ids = ShmSegUsedCount();
723             ret = LOS_ArchCopyToUser(buf, &shmInfo, sizeof(struct shm_info));
724             if (ret != 0) {
725                 ret = EFAULT;
726                 goto ERROR;
727             }
728             ret = IPC_SHM_INFO.shmmni;
729             break;
730         default:
731             VM_ERR("the cmd(%d) is not supported!", cmd);
732             ret = EINVAL;
733             goto ERROR;
734     }
735 
736     SYSV_SHM_UNLOCK();
737     return ret;
738 
739 ERROR:
740     set_errno(ret);
741     SYSV_SHM_UNLOCK();
742     PRINT_DEBUG("%s %d, ret = %d\n", __FUNCTION__, __LINE__, ret);
743     return -1;
744 }
745 
ShmDt(const VOID * shmaddr)746 INT32 ShmDt(const VOID *shmaddr)
747 {
748     LosVmSpace *space = OsCurrProcessGet()->vmSpace;
749     struct shmIDSource *seg = NULL;
750     LosVmMapRegion *region = NULL;
751     INT32 shmid;
752     INT32 ret;
753 
754     if (IS_PAGE_ALIGNED(shmaddr) == 0) {
755         ret = EINVAL;
756         goto ERROR;
757     }
758 
759     (VOID)LOS_MuxAcquire(&space->regionMux);
760     region = LOS_RegionFind(space, (VADDR_T)(UINTPTR)shmaddr);
761     if (region == NULL) {
762         ret = EINVAL;
763         goto ERROR_WITH_LOCK;
764     }
765     shmid = region->shmid;
766 
767     if (region->range.base != (VADDR_T)(UINTPTR)shmaddr) {
768         ret = EINVAL;
769         goto ERROR_WITH_LOCK;
770     }
771 
772     /* remove it from aspace */
773     LOS_RbDelNode(&space->regionRbTree, &region->rbNode);
774     LOS_ArchMmuUnmap(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);
775     (VOID)LOS_MuxRelease(&space->regionMux);
776     /* free it */
777     free(region);
778 
779     SYSV_SHM_LOCK();
780     seg = ShmFindSeg(shmid);
781     if (seg == NULL) {
782         ret = EINVAL;
783         SYSV_SHM_UNLOCK();
784         goto ERROR;
785     }
786 
787     ShmPagesRefDec(seg);
788     seg->ds.shm_nattch--;
789     if ((seg->ds.shm_nattch <= 0) &&
790         (seg->status & SHM_SEG_REMOVE)) {
791         ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);
792     } else {
793         seg->ds.shm_dtime = time(NULL);
794         seg->ds.shm_lpid = LOS_GetCurrProcessID();
795     }
796     SYSV_SHM_UNLOCK();
797 
798     return 0;
799 
800 ERROR_WITH_LOCK:
801     (VOID)LOS_MuxRelease(&space->regionMux);
802 ERROR:
803     set_errno(ret);
804     PRINT_DEBUG("%s %d, ret = %d\n", __FUNCTION__, __LINE__, ret);
805     return -1;
806 }
807 
OsShmCBDestroy(struct shmIDSource * shmSegs,struct shminfo * shmInfo,LosMux * sysvShmMux)808 VOID OsShmCBDestroy(struct shmIDSource *shmSegs, struct shminfo *shmInfo, LosMux *sysvShmMux)
809 {
810     if ((shmSegs == NULL) || (shmInfo == NULL) || (sysvShmMux == NULL)) {
811         return;
812     }
813 
814     for (UINT32 index = 0; index < shmInfo->shmmni; index++) {
815         struct shmIDSource *seg = &shmSegs[index];
816         if (seg->status == SHM_SEG_FREE) {
817             continue;
818         }
819 
820         (VOID)LOS_MuxLock(sysvShmMux, LOS_WAIT_FOREVER);
821         ShmFreeSeg(seg, NULL);
822         (VOID)LOS_MuxUnlock(sysvShmMux);
823     }
824 
825     (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, shmSegs);
826     (VOID)LOS_MuxDestroy(sysvShmMux);
827 }
828 
829 #ifdef LOSCFG_SHELL
OsShmInfoCmd(VOID)830 STATIC VOID OsShmInfoCmd(VOID)
831 {
832     INT32 i;
833     struct shmIDSource *seg = NULL;
834 
835     PRINTK("\r\n------- Shared Memory Segments -------\n");
836     PRINTK("key      shmid    perms      bytes      nattch     status     owner\n");
837     SYSV_SHM_LOCK();
838     for (i = 0; i < IPC_SHM_INFO.shmmni; i++) {
839         seg = &IPC_SHM_SEGS[i];
840         if (!(seg->status & SHM_SEG_USED)) {
841             continue;
842         }
843         PRINTK("%08x %-8d %-10o %-10u %-10u %-10x %s\n", seg->ds.shm_perm.key,
844                i, seg->ds.shm_perm.mode, seg->ds.shm_segsz, seg->ds.shm_nattch,
845                seg->status, seg->ownerName);
846 
847     }
848     SYSV_SHM_UNLOCK();
849 }
850 
OsShmDeleteCmd(INT32 shmid)851 STATIC VOID OsShmDeleteCmd(INT32 shmid)
852 {
853     struct shmIDSource *seg = NULL;
854 
855     if ((shmid < 0) || (shmid >= IPC_SHM_INFO.shmmni)) {
856         PRINT_ERR("shmid is invalid: %d\n", shmid);
857         return;
858     }
859 
860     SYSV_SHM_LOCK();
861     seg = ShmFindSeg(shmid);
862     if (seg == NULL) {
863         SYSV_SHM_UNLOCK();
864         return;
865     }
866 
867     if (seg->ds.shm_nattch <= 0) {
868         ShmFreeSeg(seg, &IPC_SHM_USED_PAGE_COUNT);
869     }
870     SYSV_SHM_UNLOCK();
871 }
872 
OsShmCmdUsage(VOID)873 STATIC VOID OsShmCmdUsage(VOID)
874 {
875     PRINTK("\tnone option,   print shm usage info\n"
876            "\t-r [shmid],    Recycle the specified shared memory about shmid\n"
877            "\t-h | --help,   print shm command usage\n");
878 }
879 
OsShellCmdShm(INT32 argc,const CHAR * argv[])880 UINT32 OsShellCmdShm(INT32 argc, const CHAR *argv[])
881 {
882     INT32 shmid;
883     CHAR *endPtr = NULL;
884 
885     if (argc == 0) {
886         OsShmInfoCmd();
887     } else if (argc == 1) {
888         if ((strcmp(argv[0], "-h") != 0) && (strcmp(argv[0], "--help") != 0)) {
889             PRINTK("Invalid option: %s\n", argv[0]);
890         }
891         OsShmCmdUsage();
892     } else if (argc == 2) { /* 2: two parameter */
893         if (strcmp(argv[0], "-r") != 0) {
894             PRINTK("Invalid option: %s\n", argv[0]);
895             goto DONE;
896         }
897         shmid = strtoul((CHAR *)argv[1], &endPtr, 0);
898         if ((endPtr == NULL) || (*endPtr != 0)) {
899             PRINTK("check shmid %s(us) invalid\n", argv[1]);
900             goto DONE;
901         }
902         /* try to delete shm about shmid */
903         OsShmDeleteCmd(shmid);
904     }
905     return 0;
906 DONE:
907     OsShmCmdUsage();
908     return -1;
909 }
910 
911 SHELLCMD_ENTRY(shm_shellcmd, CMD_TYPE_SHOW, "shm", 2, (CmdCallBackFunc)OsShellCmdShm);
912 #endif
913 #endif
914 
915