1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2014, STMicroelectronics International N.V.
4 */
5 #include <kernel/tee_common.h>
6 #include <kernel/tee_l2cc_mutex.h>
7 #include <kernel/spinlock.h>
8 #include <mm/tee_mm.h>
9 #include <mm/core_memprot.h>
10 #include <mm/core_mmu.h>
11 #include <tee_api_defines.h>
12 #include <trace.h>
13
14 /*
15 * l2cc_mutex_va holds teecore virtual address of TZ L2CC mutex or NULL.
16 *
17 * l2cc_mutex_pa holds TZ L2CC mutex physical address. It is relevant only
18 * if 'l2cc_mutex_va' hold a non-NULL address.
19 */
20 #define MUTEX_SZ sizeof(uint32_t)
21
22 static uint32_t *l2cc_mutex_va;
23 static uint32_t l2cc_mutex_pa;
24 static uint32_t l2cc_mutex_boot_pa;
25 static unsigned int *l2cc_mutex;
26
tee_l2cc_store_mutex_boot_pa(uint32_t pa)27 void tee_l2cc_store_mutex_boot_pa(uint32_t pa)
28 {
29 l2cc_mutex_boot_pa = pa;
30 }
31
32 /*
33 * Allocate public RAM to get a L2CC mutex to shared with NSec.
34 * Return 0 on success.
35 */
l2cc_mutex_alloc(void)36 static int l2cc_mutex_alloc(void)
37 {
38 void *va;
39
40 if (l2cc_mutex_va != NULL)
41 return -1;
42
43 l2cc_mutex_pa = l2cc_mutex_boot_pa;
44
45 va = phys_to_virt(l2cc_mutex_pa, MEM_AREA_NSEC_SHM, MUTEX_SZ);
46 if (!va)
47 return -1;
48
49 *(uint32_t *)va = 0;
50 l2cc_mutex_va = va;
51 return 0;
52 }
53
l2cc_mutex_set(void * mutex)54 static void l2cc_mutex_set(void *mutex)
55 {
56 l2cc_mutex = (unsigned int *)mutex;
57 }
58
59 /*
60 * tee_xxx_l2cc_mutex(): Handle L2 mutex configuration requests from NSec
61 *
62 * Policy:
63 * - if NSec did not register a L2 mutex, default allocate it in public RAM.
64 * - if NSec disables L2 mutex, disable the current mutex and unregister it.
65 *
66 * Enable L2CC: NSec allows teecore to run safe outer maintance
67 * with shared mutex.
68 * Disable L2CC: NSec will run outer maintenance with locking
69 * shared mutex. teecore cannot run outer maintenance.
70 * Set L2CC: NSec proposes a Shared Memory locaiotn for the outer
71 * maintenance shared mutex.
72 * Get L2CC: NSec requests the outer maintenance shared mutex
73 * location. If NSec has successufully registered one,
74 * return its location, otherwise, allocated one in NSec
75 * and provided NSec the physical location.
76 */
tee_enable_l2cc_mutex(void)77 TEE_Result tee_enable_l2cc_mutex(void)
78 {
79 int ret;
80
81 if (!l2cc_mutex_va) {
82 ret = l2cc_mutex_alloc();
83 if (ret)
84 return TEE_ERROR_GENERIC;
85 }
86 l2cc_mutex_set(l2cc_mutex_va);
87 return TEE_SUCCESS;
88 }
89
tee_disable_l2cc_mutex(void)90 TEE_Result tee_disable_l2cc_mutex(void)
91 {
92 l2cc_mutex_va = NULL;
93 l2cc_mutex_set(NULL);
94 return TEE_SUCCESS;
95 }
96
tee_get_l2cc_mutex(paddr_t * mutex)97 TEE_Result tee_get_l2cc_mutex(paddr_t *mutex)
98 {
99 int ret;
100
101 if (!l2cc_mutex_va) {
102 ret = l2cc_mutex_alloc();
103 if (ret)
104 return TEE_ERROR_GENERIC;
105 }
106 *mutex = l2cc_mutex_pa;
107 return TEE_SUCCESS;
108 }
109
tee_set_l2cc_mutex(paddr_t * mutex)110 TEE_Result tee_set_l2cc_mutex(paddr_t *mutex)
111 {
112 uint32_t addr;
113 void *va;
114
115 if (l2cc_mutex_va != NULL)
116 return TEE_ERROR_BAD_PARAMETERS;
117 addr = *mutex;
118 va = phys_to_virt(addr, MEM_AREA_NSEC_SHM, MUTEX_SZ);
119 if (!va)
120 return TEE_ERROR_BAD_PARAMETERS;
121 l2cc_mutex_pa = addr;
122 l2cc_mutex_va = va;
123 return TEE_SUCCESS;
124 }
125
tee_l2cc_mutex_lock(void)126 void tee_l2cc_mutex_lock(void)
127 {
128 if (l2cc_mutex)
129 cpu_spin_lock(l2cc_mutex);
130 }
131
tee_l2cc_mutex_unlock(void)132 void tee_l2cc_mutex_unlock(void)
133 {
134 if (l2cc_mutex)
135 cpu_spin_unlock(l2cc_mutex);
136 }
137