1 /*
2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifdef LOSCFG_KERNEL_PLIMITS
32 #include "los_base.h"
33 #include "los_process_pri.h"
34 #include "hal_timer.h"
35 #include "los_plimits.h"
36
37 typedef struct PlimiteOperations {
38 VOID (*LimiterInit)(UINTPTR);
39 VOID *(*LimiterAlloc)(VOID);
40 VOID (*LimiterFree)(UINTPTR);
41 VOID (*LimiterCopy)(UINTPTR, UINTPTR);
42 BOOL (*LimiterAddProcessCheck)(UINTPTR, UINTPTR);
43 VOID (*LimiterAddProcess)(UINTPTR, UINTPTR);
44 VOID (*LimiterDelProcess)(UINTPTR, UINTPTR);
45 BOOL (*LimiterMigrateCheck)(UINTPTR, UINTPTR);
46 VOID (*LimiterMigrate)(UINTPTR, UINTPTR, UINTPTR);
47 } PlimiteOperations;
48
49 static PlimiteOperations g_limiteOps[PROCESS_LIMITER_COUNT] = {
50 [PROCESS_LIMITER_ID_PIDS] = {
51 .LimiterInit = PidLimiterInit,
52 .LimiterAlloc = PidLimiterAlloc,
53 .LimiterFree = PidLimterFree,
54 .LimiterCopy = PidLimiterCopy,
55 .LimiterAddProcessCheck = OsPidLimitAddProcessCheck,
56 .LimiterAddProcess = OsPidLimitAddProcess,
57 .LimiterDelProcess = OsPidLimitDelProcess,
58 .LimiterMigrateCheck = PidLimitMigrateCheck,
59 .LimiterMigrate = NULL,
60 },
61 #ifdef LOSCFG_KERNEL_MEM_PLIMIT
62 [PROCESS_LIMITER_ID_MEM] = {
63 .LimiterInit = OsMemLimiterInit,
64 .LimiterAlloc = OsMemLimiterAlloc,
65 .LimiterFree = OsMemLimiterFree,
66 .LimiterCopy = OsMemLimiterCopy,
67 .LimiterAddProcessCheck = OsMemLimitAddProcessCheck,
68 .LimiterAddProcess = OsMemLimitAddProcess,
69 .LimiterDelProcess = OsMemLimitDelProcess,
70 .LimiterMigrateCheck = MemLimiteMigrateCheck,
71 .LimiterMigrate = OsMemLimiterMigrate,
72 },
73 #endif
74 #ifdef LOSCFG_KERNEL_SCHED_PLIMIT
75 [PROCESS_LIMITER_ID_SCHED] = {
76 .LimiterInit = OsSchedLimitInit,
77 .LimiterAlloc = OsSchedLimitAlloc,
78 .LimiterFree = OsSchedLimitFree,
79 .LimiterCopy = OsSchedLimitCopy,
80 .LimiterAddProcessCheck = NULL,
81 .LimiterAddProcess = NULL,
82 .LimiterDelProcess = NULL,
83 .LimiterMigrateCheck = NULL,
84 .LimiterMigrate = NULL,
85 },
86 #endif
87 #ifdef LOSCFG_KERNEL_DEV_PLIMIT
88 [PROCESS_LIMITER_ID_DEV] = {
89 .LimiterInit = OsDevLimitInit,
90 .LimiterAlloc = OsDevLimitAlloc,
91 .LimiterFree = OsDevLimitFree,
92 .LimiterCopy = OsDevLimitCopy,
93 .LimiterAddProcessCheck = NULL,
94 .LimiterAddProcess = NULL,
95 .LimiterDelProcess = NULL,
96 .LimiterMigrateCheck = NULL,
97 .LimiterMigrate = NULL,
98 },
99 #endif
100 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
101 [PROCESS_LIMITER_ID_IPC] = {
102 .LimiterInit = OsIPCLimitInit,
103 .LimiterAlloc = OsIPCLimitAlloc,
104 .LimiterFree = OsIPCLimitFree,
105 .LimiterCopy = OsIPCLimitCopy,
106 .LimiterAddProcessCheck = OsIPCLimitAddProcessCheck,
107 .LimiterAddProcess = OsIPCLimitAddProcess,
108 .LimiterDelProcess = OsIPCLimitDelProcess,
109 .LimiterMigrateCheck = OsIPCLimiteMigrateCheck,
110 .LimiterMigrate = OsIPCLimitMigrate,
111 },
112 #endif
113 };
114
115 STATIC ProcLimiterSet *g_rootPLimite = NULL;
116
OsRootPLimitsGet(VOID)117 ProcLimiterSet *OsRootPLimitsGet(VOID)
118 {
119 return g_rootPLimite;
120 }
121
OsProcLimiterSetInit(VOID)122 UINT32 OsProcLimiterSetInit(VOID)
123 {
124 g_rootPLimite = (ProcLimiterSet *)LOS_MemAlloc(m_aucSysMem1, sizeof(ProcLimiterSet));
125 if (g_rootPLimite == NULL) {
126 return ENOMEM;
127 }
128 (VOID)memset_s(g_rootPLimite, sizeof(ProcLimiterSet), 0, sizeof(ProcLimiterSet));
129
130 LOS_ListInit(&g_rootPLimite->childList);
131 LOS_ListInit(&g_rootPLimite->processList);
132
133 ProcLimiterSet *procLimiterSet = g_rootPLimite;
134 for (INT32 plimiteID = 0; plimiteID < PROCESS_LIMITER_COUNT; ++plimiteID) {
135 procLimiterSet->limitsList[plimiteID] = (UINTPTR)g_limiteOps[plimiteID].LimiterAlloc();
136 if (procLimiterSet->limitsList[plimiteID] == (UINTPTR)NULL) {
137 OsPLimitsFree(procLimiterSet);
138 return ENOMEM;
139 }
140
141 if (g_limiteOps[plimiteID].LimiterInit != NULL) {
142 g_limiteOps[plimiteID].LimiterInit(procLimiterSet->limitsList[plimiteID]);
143 }
144 }
145 return LOS_OK;
146 }
147
PLimitsDeleteProcess(LosProcessCB * processCB)148 STATIC VOID PLimitsDeleteProcess(LosProcessCB *processCB)
149 {
150 if ((processCB == NULL) || (processCB->plimits == NULL)) {
151 return;
152 }
153
154 ProcLimiterSet *plimits = processCB->plimits;
155 for (UINT32 limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) {
156 if (g_limiteOps[limitsID].LimiterDelProcess == NULL) {
157 continue;
158 }
159 g_limiteOps[limitsID].LimiterDelProcess(plimits->limitsList[limitsID], (UINTPTR)processCB);
160 }
161 plimits->pidCount--;
162 LOS_ListDelete(&processCB->plimitsList);
163 processCB->plimits = NULL;
164 return;
165 }
166
PLimitsAddProcess(ProcLimiterSet * plimits,LosProcessCB * processCB)167 STATIC UINT32 PLimitsAddProcess(ProcLimiterSet *plimits, LosProcessCB *processCB)
168 {
169 UINT32 limitsID;
170 if (plimits == NULL) {
171 plimits = g_rootPLimite;
172 }
173
174 if (processCB->plimits == g_rootPLimite) {
175 return EPERM;
176 }
177
178 if (processCB->plimits == plimits) {
179 return LOS_OK;
180 }
181
182 for (limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) {
183 if (g_limiteOps[limitsID].LimiterAddProcessCheck == NULL) {
184 continue;
185 }
186
187 if (!g_limiteOps[limitsID].LimiterAddProcessCheck(plimits->limitsList[limitsID], (UINTPTR)processCB)) {
188 return EACCES;
189 }
190 }
191
192 PLimitsDeleteProcess(processCB);
193
194 for (limitsID = 0; limitsID < PROCESS_LIMITER_COUNT; limitsID++) {
195 if (g_limiteOps[limitsID].LimiterAddProcess == NULL) {
196 continue;
197 }
198 g_limiteOps[limitsID].LimiterAddProcess(plimits->limitsList[limitsID], (UINTPTR)processCB);
199 }
200
201 LOS_ListTailInsert(&plimits->processList, &processCB->plimitsList);
202 plimits->pidCount++;
203 processCB->plimits = plimits;
204 return LOS_OK;
205 }
206
OsPLimitsAddProcess(ProcLimiterSet * plimits,LosProcessCB * processCB)207 UINT32 OsPLimitsAddProcess(ProcLimiterSet *plimits, LosProcessCB *processCB)
208 {
209 UINT32 intSave;
210 SCHEDULER_LOCK(intSave);
211 UINT32 ret = PLimitsAddProcess(plimits, processCB);
212 SCHEDULER_UNLOCK(intSave);
213 return ret;
214 }
215
OsPLimitsAddPid(ProcLimiterSet * plimits,UINT32 pid)216 UINT32 OsPLimitsAddPid(ProcLimiterSet *plimits, UINT32 pid)
217 {
218 UINT32 intSave, ret;
219 if ((plimits == NULL) || OS_PID_CHECK_INVALID(pid) || (pid == 0)) {
220 return EINVAL;
221 }
222
223 if (plimits == g_rootPLimite) {
224 return EPERM;
225 }
226
227 SCHEDULER_LOCK(intSave);
228 LosProcessCB *processCB = OS_PCB_FROM_PID((unsigned int)pid);
229 if (OsProcessIsInactive(processCB)) {
230 SCHEDULER_UNLOCK(intSave);
231 return EINVAL;
232 }
233
234 ret = PLimitsAddProcess(plimits, processCB);
235 SCHEDULER_UNLOCK(intSave);
236 return ret;
237 }
238
OsPLimitsDeleteProcess(LosProcessCB * processCB)239 VOID OsPLimitsDeleteProcess(LosProcessCB *processCB)
240 {
241 UINT32 intSave;
242 SCHEDULER_LOCK(intSave);
243 PLimitsDeleteProcess(processCB);
244 SCHEDULER_UNLOCK(intSave);
245 }
246
OsPLimitsPidsGet(const ProcLimiterSet * plimits,UINT32 * pids,UINT32 size)247 UINT32 OsPLimitsPidsGet(const ProcLimiterSet *plimits, UINT32 *pids, UINT32 size)
248 {
249 UINT32 intSave;
250 LosProcessCB *processCB = NULL;
251 UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT32);
252 if ((plimits == NULL) || (pids == NULL) || (size < minSize)) {
253 return EINVAL;
254 }
255
256 SCHEDULER_LOCK(intSave);
257 LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList;
258 if (LOS_ListEmpty(listHead)) {
259 SCHEDULER_UNLOCK(intSave);
260 return EINVAL;
261 }
262
263 LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) {
264 pids[OsGetPid(processCB)] = 1;
265 }
266 SCHEDULER_UNLOCK(intSave);
267 return LOS_OK;
268 }
269
PLimitsProcessMerge(ProcLimiterSet * currPLimits,ProcLimiterSet * parentPLimits)270 STATIC VOID PLimitsProcessMerge(ProcLimiterSet *currPLimits, ProcLimiterSet *parentPLimits)
271 {
272 LOS_DL_LIST *head = &currPLimits->processList;
273 while (!LOS_ListEmpty(head)) {
274 LosProcessCB *processCB = LOS_DL_LIST_ENTRY(head->pstNext, LosProcessCB, plimitsList);
275 PLimitsDeleteProcess(processCB);
276 PLimitsAddProcess(parentPLimits, processCB);
277 }
278 LOS_ListDelete(&currPLimits->childList);
279 currPLimits->parent = NULL;
280 return;
281 }
282
PLimitsMigrateCheck(ProcLimiterSet * currPLimits,ProcLimiterSet * parentPLimits)283 STATIC UINT32 PLimitsMigrateCheck(ProcLimiterSet *currPLimits, ProcLimiterSet *parentPLimits)
284 {
285 for (UINT32 limiteID = 0; limiteID < PROCESS_LIMITER_COUNT; limiteID++) {
286 UINTPTR currLimit = currPLimits->limitsList[limiteID];
287 UINTPTR parentLimit = parentPLimits->limitsList[limiteID];
288 if (g_limiteOps[limiteID].LimiterMigrateCheck == NULL) {
289 continue;
290 }
291
292 if (!g_limiteOps[limiteID].LimiterMigrateCheck(currLimit, parentLimit)) {
293 return EPERM;
294 }
295 }
296 return LOS_OK;
297 }
298
OsPLimitsFree(ProcLimiterSet * currPLimits)299 UINT32 OsPLimitsFree(ProcLimiterSet *currPLimits)
300 {
301 UINT32 intSave, ret;
302 if (currPLimits == NULL) {
303 return EINVAL;
304 }
305
306 SCHEDULER_LOCK(intSave);
307 ProcLimiterSet *parentPLimits = currPLimits->parent;
308 ret = PLimitsMigrateCheck(currPLimits, parentPLimits);
309 if (ret != LOS_OK) {
310 SCHEDULER_UNLOCK(intSave);
311 return ret;
312 }
313
314 PLimitsProcessMerge(currPLimits, parentPLimits);
315 SCHEDULER_UNLOCK(intSave);
316
317 for (INT32 limiteID = 0; limiteID < PROCESS_LIMITER_COUNT; ++limiteID) {
318 UINTPTR procLimiter = currPLimits->limitsList[limiteID];
319 if (g_limiteOps[limiteID].LimiterFree != NULL) {
320 g_limiteOps[limiteID].LimiterFree(procLimiter);
321 }
322 }
323 (VOID)LOS_MemFree(m_aucSysMem1, currPLimits);
324 return LOS_OK;
325 }
326
OsPLimitsCreate(ProcLimiterSet * parentPLimits)327 ProcLimiterSet *OsPLimitsCreate(ProcLimiterSet *parentPLimits)
328 {
329 UINT32 intSave;
330
331 ProcLimiterSet *newPLimits = (ProcLimiterSet *)LOS_MemAlloc(m_aucSysMem1, sizeof(ProcLimiterSet));
332 if (newPLimits == NULL) {
333 return NULL;
334 }
335 (VOID)memset_s(newPLimits, sizeof(ProcLimiterSet), 0, sizeof(ProcLimiterSet));
336 LOS_ListInit(&newPLimits->childList);
337 LOS_ListInit(&newPLimits->processList);
338
339 SCHEDULER_LOCK(intSave);
340 newPLimits->parent = parentPLimits;
341 newPLimits->level = parentPLimits->level + 1;
342 newPLimits->mask = parentPLimits->mask;
343
344 for (INT32 plimiteID = 0; plimiteID < PROCESS_LIMITER_COUNT; ++plimiteID) {
345 newPLimits->limitsList[plimiteID] = (UINTPTR)g_limiteOps[plimiteID].LimiterAlloc();
346 if (newPLimits->limitsList[plimiteID] == (UINTPTR)NULL) {
347 SCHEDULER_UNLOCK(intSave);
348 OsPLimitsFree(newPLimits);
349 return NULL;
350 }
351
352 if (g_limiteOps[plimiteID].LimiterCopy != NULL) {
353 g_limiteOps[plimiteID].LimiterCopy(newPLimits->limitsList[plimiteID],
354 parentPLimits->limitsList[plimiteID]);
355 }
356 }
357 LOS_ListTailInsert(&g_rootPLimite->childList, &newPLimits->childList);
358
359 (VOID)PLimitsDeleteProcess(OsCurrProcessGet());
360 (VOID)PLimitsAddProcess(newPLimits, OsCurrProcessGet());
361 SCHEDULER_UNLOCK(intSave);
362 return newPLimits;
363 }
364
365 #ifdef LOSCFG_KERNEL_MEM_PLIMIT
OsPLimitsMemUsageGet(ProcLimiterSet * plimits,UINT64 * usage,UINT32 size)366 UINT32 OsPLimitsMemUsageGet(ProcLimiterSet *plimits, UINT64 *usage, UINT32 size)
367 {
368 UINT32 intSave;
369 LosProcessCB *processCB = NULL;
370 UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT64) + sizeof(ProcMemLimiter);
371 ProcMemLimiter *memLimit = (ProcMemLimiter *)usage;
372 UINT64 *memSuage = (UINT64 *)((UINTPTR)usage + sizeof(ProcMemLimiter));
373 if ((plimits == NULL) || (usage == NULL) || (size < minSize)) {
374 return EINVAL;
375 }
376
377 SCHEDULER_LOCK(intSave);
378 (VOID)memcpy_s(memLimit, sizeof(ProcMemLimiter),
379 (VOID *)plimits->limitsList[PROCESS_LIMITER_ID_MEM], sizeof(ProcMemLimiter));
380 LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList;
381 if (LOS_ListEmpty(listHead)) {
382 SCHEDULER_UNLOCK(intSave);
383 return EINVAL;
384 }
385
386 LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) {
387 memSuage[OsGetPid(processCB)] = processCB->limitStat.memUsed;
388 }
389 SCHEDULER_UNLOCK(intSave);
390 return LOS_OK;
391 }
392 #endif
393
394 #ifdef LOSCFG_KERNEL_IPC_PLIMIT
OsPLimitsIPCStatGet(ProcLimiterSet * plimits,ProcIPCLimit * ipc,UINT32 size)395 UINT32 OsPLimitsIPCStatGet(ProcLimiterSet *plimits, ProcIPCLimit *ipc, UINT32 size)
396 {
397 UINT32 intSave;
398 if ((plimits == NULL) || (ipc == NULL) || (size != sizeof(ProcIPCLimit))) {
399 return EINVAL;
400 }
401
402 SCHEDULER_LOCK(intSave);
403 (VOID)memcpy_s(ipc, sizeof(ProcIPCLimit),
404 (VOID *)plimits->limitsList[PROCESS_LIMITER_ID_IPC], sizeof(ProcIPCLimit));
405 SCHEDULER_UNLOCK(intSave);
406 return LOS_OK;
407 }
408 #endif
409
410 #ifdef LOSCFG_KERNEL_SCHED_PLIMIT
OsPLimitsSchedUsageGet(ProcLimiterSet * plimits,UINT64 * usage,UINT32 size)411 UINT32 OsPLimitsSchedUsageGet(ProcLimiterSet *plimits, UINT64 *usage, UINT32 size)
412 {
413 UINT32 intSave;
414 LosProcessCB *processCB = NULL;
415 UINT32 minSize = LOS_GetSystemProcessMaximum() * sizeof(UINT64);
416 if ((plimits == NULL) || (usage == NULL) || (size < minSize)) {
417 return EINVAL;
418 }
419
420 SCHEDULER_LOCK(intSave);
421 LOS_DL_LIST *listHead = (LOS_DL_LIST *)&plimits->processList;
422 if (LOS_ListEmpty(listHead)) {
423 SCHEDULER_UNLOCK(intSave);
424 return EINVAL;
425 }
426
427 LOS_DL_LIST_FOR_EACH_ENTRY(processCB, listHead, LosProcessCB, plimitsList) {
428 usage[OsGetPid(processCB)] = processCB->limitStat.allRuntime;
429 }
430 SCHEDULER_UNLOCK(intSave);
431 return LOS_OK;
432 }
433 #endif
434 #endif
435