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, ®ion->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