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