• 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 "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