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 "mailbox_mempool.h"
33 #include <securec.h>
34 #include "smc.h"
35 #include "tc_ns_log.h"
36 #include "teek_client_constants.h"
37 #include "tzdriver_compat.h"
38
39 #define MAILBOX_PAGE_MAX (MAILBOX_POOL_SIZE >> PAGE_SHIFT)
40 #define MAILBOX_ORDER_MAX GET_ORDER(MAILBOX_POOL_SIZE)
41 static unsigned int g_mailboxMaxOrder = MAILBOX_ORDER_MAX;
42
43 struct MbPageT {
44 struct list_head node;
45 LosVmPage *page;
46 int order; // block size
47 unsigned int count; // whether be used
48 };
49
50 struct MbFreeAreaT {
51 struct list_head pageList;
52 int order;
53 };
54
55 struct MbZoneT {
56 LosVmPage *allPages;
57 struct MbPageT pages[MAILBOX_PAGE_MAX];
58 struct MbFreeAreaT freeAreas[MAILBOX_ORDER_MAX + 1];
59 };
60
61 static struct MbZoneT g_mZone;
62 static mutex_t g_mbLock;
63
64 #ifdef DEF_ENG
MailboxShowStatus(void)65 static void MailboxShowStatus(void)
66 {
67 unsigned int i;
68 struct MbPageT *pos = NULL;
69 struct list_head *head = NULL;
70 unsigned int used = 0;
71
72 pr_info("########################################\n");
73 mutex_lock(&g_mbLock);
74 for (i = 0; i < MAILBOX_PAGE_MAX; i++) {
75 if (g_mZone.pages[i].count) {
76 pr_info("page[%02d], order=%02u, count=%u\n", i, g_mZone.pages[i].order, g_mZone.pages[i].count);
77 used += (1UL << (uint32_t)g_mZone.pages[i].order);
78 }
79 }
80 pr_info("total usage:%u/%u\n", used, MAILBOX_PAGE_MAX);
81 pr_info("----------------------------------------\n");
82
83 for (i = 0; i < g_mailboxMaxOrder; i++) {
84 head = &g_mZone.freeAreas[i].pageList;
85 if (list_empty(head)) {
86 pr_info("order[%02d] is empty\n", i);
87 } else {
88 list_for_each_entry(pos, head, node)
89 pr_info("order[%02d]\n", i);
90 }
91 }
92 mutex_unlock(&g_mbLock);
93
94 pr_info("########################################\n");
95 }
96
97 #define MB_SHOW_LINE 64
98 #define BITS_OF_BYTE 8
MailboxShowDetails(void)99 static void MailboxShowDetails(void)
100 {
101 unsigned int i;
102 unsigned int used = 0;
103 unsigned int left = 0;
104 unsigned int order = 0;
105
106 pr_info("----- show mailbox details -----");
107 mutex_lock(&g_mbLock);
108 for (i = 0; i < MAILBOX_PAGE_MAX; i++) {
109 if ((i % MB_SHOW_LINE) == 0) {
110 PRINTK("\n");
111 PRINTK("%04d-%04d:", i, i + MB_SHOW_LINE);
112 }
113
114 if (g_mZone.pages[i].count) {
115 left = 1 << (uint32_t)g_mZone.pages[i].order;
116 order = g_mZone.pages[i].order;
117 used += (1UL << (uint32_t)g_mZone.pages[i].order);
118 }
119
120 if (left) {
121 left--;
122 PRINTK("%01d", order);
123 } else {
124 PRINTK("X");
125 }
126
127 if (i > 1 && (i + 1) % (MB_SHOW_LINE / BITS_OF_BYTE) == 0) {
128 PRINTK(" ");
129 }
130 }
131 pr_info("\ntotal usage:%u/%u\n", used, MAILBOX_PAGE_MAX);
132 mutex_unlock(&g_mbLock);
133 }
134 #endif
135
MailboxAlloc(size_t size,unsigned int flag)136 void *MailboxAlloc(size_t size, unsigned int flag)
137 {
138 unsigned int i;
139 struct MbPageT *pos = (struct MbPageT *)NULL;
140 struct list_head *head = NULL;
141 unsigned int order = GET_ORDER(ALIGN(size, SZ_4K));
142 void *addr = NULL;
143
144 if (size == 0) {
145 tlogw("alloc 0 size mailbox\n");
146 return NULL;
147 }
148
149 if (order > g_mailboxMaxOrder) {
150 tloge("invalid order %d\n", order);
151 return NULL;
152 }
153
154 mutex_lock(&g_mbLock);
155 for (i = order; i <= g_mailboxMaxOrder; i++) {
156 unsigned int j;
157
158 head = &g_mZone.freeAreas[i].pageList;
159 if (list_empty(head)) {
160 continue;
161 }
162
163 pos = list_first_entry(head, struct MbPageT, node);
164
165 pos->count = 1;
166 pos->order = order;
167
168 /* split and add free list */
169 for (j = order; j < i; j++) {
170 struct MbPageT *newPage = NULL;
171
172 newPage = pos + (1UL << j);
173 newPage->count = 0;
174 newPage->order = j;
175 list_add_tail(&newPage->node, &g_mZone.freeAreas[j].pageList);
176 }
177 list_del(&pos->node);
178 addr = OsVmPageToVaddr(pos->page);
179 break;
180 }
181 mutex_unlock(&g_mbLock);
182
183 if (addr != NULL && (flag & MB_FLAG_ZERO)) {
184 if (memset_s(addr, ALIGN(size, SZ_4K), 0,
185 ALIGN(size, SZ_4K)) != EOK) {
186 tloge("clean mailbox failed\n");
187 MailboxFree(addr);
188 return NULL;
189 }
190 }
191 return addr;
192 }
193
MailboxFree(const void * ptr)194 void MailboxFree(const void *ptr)
195 {
196 unsigned int i;
197 LosVmPage *page = NULL;
198 struct MbPageT *self = NULL;
199 struct MbPageT *buddy = NULL;
200 unsigned int selfIdx;
201 unsigned int buddyIdx;
202
203 if (ptr == NULL) {
204 tloge("invalid ptr\n");
205 return;
206 }
207
208 page = OsVmVaddrToPage((void *)ptr);
209 if (page < g_mZone.allPages ||
210 page >= (g_mZone.allPages + MAILBOX_PAGE_MAX)) {
211 tloge("invalid ptr to free in mailbox\n");
212 return;
213 }
214
215 mutex_lock(&g_mbLock);
216 selfIdx = page - g_mZone.allPages;
217 self = &g_mZone.pages[selfIdx];
218 if (!self->count) {
219 tloge("already freed in mailbox\n");
220 mutex_unlock(&g_mbLock);
221 return;
222 }
223
224 for (i = (unsigned int)self->order; i <=
225 g_mailboxMaxOrder; i++) {
226 selfIdx = page - g_mZone.allPages;
227 buddyIdx = selfIdx ^ (1UL << i);
228 self = &g_mZone.pages[selfIdx];
229 buddy = &g_mZone.pages[buddyIdx];
230 self->count = 0;
231 /* is buddy free */
232 if ((unsigned int)buddy->order == i && buddy->count == 0) {
233 /* release buddy */
234 list_del(&buddy->node);
235 /* combine self and buddy */
236 if (selfIdx > buddyIdx) {
237 page = buddy->page;
238 buddy->order = (int)i + 1;
239 self->order = -1;
240 } else {
241 self->order = (int)i + 1;
242 buddy->order = -1;
243 }
244 } else {
245 /* release self */
246 list_add_tail(&self->node, &g_mZone.freeAreas[i].pageList);
247 mutex_unlock(&g_mbLock);
248 return;
249 }
250 }
251 mutex_unlock(&g_mbLock);
252 }
253
MailboxAllocCmdPack(void)254 struct MbCmdPack *MailboxAllocCmdPack(void)
255 {
256 void *pack = MailboxAlloc(SZ_4K, MB_FLAG_ZERO);
257
258 if (pack == NULL) {
259 tloge("alloc mb cmd pack failed\n");
260 }
261 return (struct MbCmdPack *)pack;
262 }
263
MailboxCopyAlloc(const void * src,size_t size)264 void *MailboxCopyAlloc(const void *src, size_t size)
265 {
266 void *mbPtr = NULL;
267
268 if ((src == NULL) || (size == 0)) {
269 tloge("invali src to alloc mailbox copy\n");
270 return NULL;
271 }
272
273 mbPtr = MailboxAlloc(size, 0);
274 if (mbPtr == NULL) {
275 tloge("alloc size(%zu) mailbox failed\n", size);
276 return NULL;
277 }
278
279 if (memcpy_s(mbPtr, size, src, size)) {
280 tloge("memcpy to mailbox failed\n");
281 MailboxFree(mbPtr);
282 return NULL;
283 }
284
285 return mbPtr;
286 }
287
288 #ifdef DEF_ENG
289 struct MbDbgEntry {
290 struct list_head node;
291 unsigned int idx;
292 void *ptr;
293 };
294
295 static LINUX_LIST_HEAD(g_mbDbgList);
296 static DEFINE_MUTEX(g_mbDbgLock);
297 static unsigned int g_mbDbgEntryCount = 1;
298 static unsigned int g_mbDbgLastRes; /* only cache 1 opt result */
299
MbDbgAddEntry(void * ptr)300 static unsigned int MbDbgAddEntry(void *ptr)
301 {
302 struct MbDbgEntry *newEntry = NULL;
303
304 newEntry = malloc(sizeof(*newEntry));
305 if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)newEntry)) {
306 tloge("alloc entry failed\n");
307 return 0;
308 }
309 INIT_LIST_HEAD(&newEntry->node);
310 newEntry->ptr = ptr;
311 mutex_lock(&g_mbDbgLock);
312 newEntry->idx = g_mbDbgEntryCount;
313 /* to make sure g_mbDbgEntryCount==0 is invalid */
314 if ((g_mbDbgEntryCount++) == 0) {
315 g_mbDbgEntryCount++;
316 }
317 list_add_tail(&newEntry->node, &g_mbDbgList);
318 mutex_unlock(&g_mbDbgLock);
319
320 return newEntry->idx;
321 }
322
MbDbgRemoveEntry(unsigned int idx)323 static void MbDbgRemoveEntry(unsigned int idx)
324 {
325 struct MbDbgEntry *pos = NULL;
326
327 mutex_lock(&g_mbDbgLock);
328 list_for_each_entry(pos, &g_mbDbgList, node) {
329 if (pos->idx == idx) {
330 MailboxFree(pos->ptr);
331 list_del(&pos->node);
332 free(pos);
333 mutex_unlock(&g_mbDbgLock);
334 return;
335 }
336 }
337 mutex_unlock(&g_mbDbgLock);
338
339 tloge("entry %u invalid\n", idx);
340 }
341
MbDbgReset(void)342 static void MbDbgReset(void)
343 {
344 struct MbDbgEntry *pos = NULL;
345 struct MbDbgEntry *tmp = NULL;
346
347 mutex_lock(&g_mbDbgLock);
348 list_for_each_entry_safe(pos, tmp, &g_mbDbgList, node) {
349 MailboxFree(pos->ptr);
350 list_del(&pos->node);
351 free(pos);
352 }
353 g_mbDbgEntryCount = 0;
354 mutex_unlock(&g_mbDbgLock);
355 }
356
357 #define MB_WRITE_SIZE 64
358
CheckDbgOptWrite(struct file * filp,const char __user * ubuf,char * obuf,size_t cnt)359 static int CheckDbgOptWrite(struct file *filp, const char __user *ubuf, char *obuf, size_t cnt)
360 {
361 bool checkValue = (filp == NULL);
362 if (checkValue || ubuf == NULL) {
363 return -EINVAL;
364 }
365 if (cnt >= MB_WRITE_SIZE || cnt == 0) {
366 return -EINVAL;
367 }
368 if (copy_from_user(obuf, ubuf, cnt)) {
369 return -EFAULT;
370 }
371 return 0;
372 }
373
MbDbgOptWrite(struct file * filp,const char __user * ubuf,size_t cnt)374 static ssize_t MbDbgOptWrite(struct file *filp, const char __user *ubuf, size_t cnt)
375 {
376 char buf[MB_WRITE_SIZE] = {0};
377 char *cmd = NULL;
378 char *value = NULL;
379 char *endPtr = NULL;
380 int ret = CheckDbgOptWrite(filp, ubuf, buf, cnt);
381 if (ret) {
382 return ret;
383 }
384
385 buf[cnt] = 0;
386 value = buf;
387 if (!strncmp(value, "reset", strlen("reset"))) {
388 tlogi("mb dbg reset\n");
389 MbDbgReset();
390 return cnt;
391 }
392
393 cmd = strsep(&value, ":");
394 if (cmd == NULL || value == NULL) {
395 tloge("no valid cmd or value for mb dbg\n");
396 return -EFAULT;
397 }
398
399 if (!strncmp(cmd, "alloc", strlen("alloc"))) {
400 unsigned int allocSize = strtoul(value, &endPtr, 0);
401 if ((endPtr == NULL) || (*endPtr != 0)) {
402 tloge("invalid value format for mb dbg\n");
403 return cnt;
404 }
405
406 unsigned int idx;
407 void *ptr = MailboxAlloc(allocSize, 0);
408 if (ptr != NULL) {
409 idx = MbDbgAddEntry(ptr);
410 if (idx == 0) {
411 MailboxFree(ptr);
412 }
413 g_mbDbgLastRes = idx;
414 } else {
415 tloge("alloc order=%u in mailbox failed\n", allocSize);
416 }
417 } else if (!strncmp(cmd, "free", strlen("free"))) {
418 unsigned int freeIdx = strtoul(value, &endPtr, 0);
419 if ((endPtr == NULL) || (*endPtr != 0)) {
420 tloge("invalid value format for mb dbg\n");
421 return cnt;
422 }
423
424 MbDbgRemoveEntry(freeIdx);
425 } else {
426 tloge("invalid format for mb dbg\n");
427 }
428
429 return cnt;
430 }
431
432 #define DBG_READ_BUFSIZE 16
MbDbgOptRead(struct file * filp,char __user * ubuf,size_t cnt)433 static ssize_t MbDbgOptRead(struct file *filp, char __user *ubuf,
434 size_t cnt)
435 {
436 char buf[DBG_READ_BUFSIZE] = {0};
437 ssize_t ret;
438
439 (void)(filp);
440
441 ret = snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "%u\n", g_mbDbgLastRes);
442 if (ret < 0) {
443 tloge("snprintf idx failed\n");
444 return -EINVAL;
445 }
446
447 return SimpleReadFromBuffer(ubuf, cnt, buf, ret);
448 }
449
450 static const struct file_operations_vfs g_mbDbgOptFops = {
451 .read = MbDbgOptRead,
452 .write = MbDbgOptWrite,
453 };
454
MbDbgStateRead(struct file * filp,char __user * ubuf,size_t cnt)455 static ssize_t MbDbgStateRead(struct file *filp, char __user *ubuf,
456 size_t cnt)
457 {
458 (void)(filp);
459 (void)(ubuf);
460 MailboxShowStatus();
461 MailboxShowDetails();
462 return 0;
463 }
464
465 static const struct file_operations_vfs mb_dbg_state_fops = {
466 .read = MbDbgStateRead,
467 };
468 #endif
469
MailboxRegister(const void * mbPool,unsigned int size)470 static int MailboxRegister(const void *mbPool, unsigned int size)
471 {
472 TcNsOperation *operation = NULL;
473 TcNsSmcCmd *smcCmd = NULL;
474 int ret = 0;
475
476 smcCmd = calloc(1, sizeof(*smcCmd));
477 if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)smcCmd)) {
478 tloge("alloc smcCmd failed\n");
479 return -EIO;
480 }
481 operation = calloc(1, sizeof(*operation));
482 if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)operation)) {
483 tloge("alloc operation failed\n");
484 ret = -EIO;
485 goto FREE_SMC_CMD;
486 }
487
488 operation->paramTypes = TEE_PARAM_TYPE_VALUE_INPUT |
489 (TEE_PARAM_TYPE_VALUE_INPUT << TEE_PARAM_NUM);
490 operation->params[TEE_PARAM_ONE].value.a = LOS_PaddrQuery((void *)mbPool);
491 operation->params[TEE_PARAM_ONE].value.b = 0;
492 operation->params[TEE_PARAM_TWO].value.a = size;
493
494 smcCmd->globalCmd = true;
495 smcCmd->cmdId = GLOBAL_CMD_ID_REGISTER_MAILBOX;
496 smcCmd->operationPhys = LOS_PaddrQuery(operation);
497 smcCmd->operationHphys = 0;
498
499 ret = TcNsSmc(smcCmd);
500 if (ret != TEEC_SUCCESS) {
501 tloge("resigter mailbox failed\n");
502 ret = -EIO;
503 }
504
505 free(operation);
506 operation = NULL;
507 FREE_SMC_CMD:
508 free(smcCmd);
509 smcCmd = NULL;
510 return ret;
511 }
512
513 #define TC_NS_CLIENT_MEILBOX_OPT_NAME "/dev/tz_mailbox_opt"
514 #define TC_NS_CLIENT_MEILBOX_STATE_NAME "/dev/tz_mailbox_state"
515
MailboxMempoolInit(void)516 int MailboxMempoolInit(void)
517 {
518 int i;
519 struct MbPageT *mbPage = NULL;
520 struct MbFreeAreaT *area = NULL;
521 LosVmPage *allPages = NULL;
522
523 allPages = MailboxPoolAllocPages(g_mailboxMaxOrder);
524 if (allPages == NULL) {
525 tloge("fail to alloc mailbox mempool\n");
526 return -ENOMEM;
527 }
528 if (MailboxRegister(OsVmPageToVaddr(allPages), MAILBOX_POOL_SIZE)) {
529 tloge("register mailbox failed\n");
530 MailboxPoolFreePages(allPages, g_mailboxMaxOrder);
531 return -EIO;
532 }
533 for (i = 0; i < MAILBOX_PAGE_MAX; i++) {
534 g_mZone.pages[i].order = -1;
535 g_mZone.pages[i].count = 0;
536 g_mZone.pages[i].page = &allPages[i];
537 }
538 g_mZone.pages[0].order = g_mailboxMaxOrder;
539 for (i = 0; i <= g_mailboxMaxOrder; i++) {
540 area = &g_mZone.freeAreas[i];
541 INIT_LIST_HEAD(&area->pageList);
542 area->order = i;
543 }
544
545 mbPage = &g_mZone.pages[0];
546 list_add_tail(&mbPage->node, &area->pageList);
547 g_mZone.allPages = allPages;
548 mutex_init(&g_mbLock);
549
550 #ifdef DEF_ENG
551 int ret = CreateTcClientDevice(TC_NS_CLIENT_MEILBOX_OPT_NAME, &g_mbDbgOptFops);
552 if (ret != EOK) {
553 return ret;
554 }
555
556 ret = CreateTcClientDevice(TC_NS_CLIENT_MEILBOX_STATE_NAME, &mb_dbg_state_fops);
557 if (ret != EOK) {
558 return ret;
559 }
560 #endif
561 return 0;
562 }
563
MailboxMempoolDestroy(void)564 void MailboxMempoolDestroy(void)
565 {
566 MailboxPoolFreePages(g_mZone.allPages, g_mailboxMaxOrder);
567 g_mZone.allPages = NULL;
568 }
569