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