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