xref: /optee_os/core/arch/arm/plat-marvell/armada7k8k/hal_sec_perf.c (revision 6d777f268ade9a73ad56e68bd1c418dc905ecf52)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2017 Marvell International Ltd.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <initcall.h>
30 #include <io.h>
31 #include <kernel/panic.h>
32 #include <mm/core_memprot.h>
33 #include <util.h>
34 
35 #define PHY_2_VIR(addr)	((vaddr_t)phys_to_virt((addr), MEM_AREA_IO_SEC, 1))
36 
37 #define MCU_MC_CONTROL_0_REG	PHY_2_VIR(MCU_BASE + 0x044)
38 #define TRUSTZONE_LOCK			BIT(31)
39 
40 #define MCU_TZ_RANGE_HIGH_REG(x)	PHY_2_VIR(MCU_BASE + 0x84 + ((x) << 3))
41 #define MCU_TZ_RANGE_LOW_REG(x)		PHY_2_VIR(MCU_BASE + 0x80 + ((x) << 3))
42 
43 #define RW_PERM	0x0
44 #define RO_PERM	0x1
45 #define WO_PERM	0x2
46 #define ABORT_PERM	0x3
47 
48 #define MAX_RANGE_NUM   16
49 #define INVALID_SIZE_CODE   0xff
50 
51 #ifdef TEE_RES_CFG_16M
52 #define RSVD_SEC_MEM    (SIZE_8M + SIZE_8M)
53 #elif defined(TEE_RES_CFG_24M)
54 #define RSVD_SEC_MEM    (SIZE_8M + SIZE_8M + SIZE_8M)
55 #elif defined(TEE_RES_CFG_8M)
56 #define RSVD_SEC_MEM    SIZE_8M
57 #else
58 #error "no reserved secure memory defined."
59 #endif
60 
61 #define RA_ADDR	TZDRAM_BASE
62 #define RA_SIZE	TZDRAM_SIZE
63 #define RA_PERM	ABORT_PERM
64 
65 #define TZ_IS_VALID(data)		((data) & (0x1))
66 #define TZ_SET_VALID(data)		((data) |= (0x1))
67 
68 #define TZ_GET_PERM(data, ret)		((ret) = (((data) & (0x3 << 1)) >> 1))
69 #define TZ_SET_PERM(data, val)		\
70 	do {	\
71 		(data) &= (~(0x3 << 1)); \
72 		(data) |= (((val) & 0x3) << 1);	\
73 	} while (0)
74 
75 #define TZ_GET_RZ_EN(data, ret)		((ret) = (((data) & (0x1 << 3)) >> 3))
76 #define TZ_SET_RZ_EN(data, val)		\
77 	do {	\
78 		(data) &= (~(0x1 << 3)); \
79 		(data) |= (((val) & 0x1) << 3);	\
80 	} while (0)
81 
82 #define TZ_GET_AREA_LEN_CODE(data, ret)	((ret) = (((data) & (0x1F << 7)) >> 7))
83 
84 #define TZ_SET_AREA_LEN_CODE(data, val)	\
85 	do {	\
86 		(data) &= (~(0x1F << 7));	\
87 		(data) |= (((val) & 0x1F) << 7);		\
88 	} while (0)
89 
90 #define TZ_GET_START_ADDR_L(data, ret)	\
91 	((ret) = (((data) & 0xFFFFF000)))
92 
93 #define TZ_SET_START_ADDR_L(data, val)		\
94 	do {	\
95 		(data) &= (~0xFFFFF000);		\
96 		(data) |= (((val) & 0xFFFFF000));	\
97 	} while (0)
98 
99 #define TZ_GET_UR_PERM(data, val)	((ret) = (((data) & (0x3 << 4)) >> 4))
100 #define TZ_SET_UR_PERM(data, val)	\
101 	do {	\
102 		(data) &= (~(0x3 << 4)); \
103 		(data) |= (((val) & 0x3) << 4);	\
104 	} while (0)
105 
106 #define TZ_GET_UR_RZ_EN(data, val)		\
107 	((ret) = (((data) & (0x1 << 6)) >> 6))
108 
109 #define TZ_SET_UR_RZ_EN(data, val)		\
110 	do {	\
111 		(data) &= (~(0x1 << 6)); \
112 		(data) |= (((val) & 0x1) << 6);	\
113 	} while (0)
114 
115  /* armada mini region size is 1M */
116 #define RANGE_SIZE_TO_CODE(size, code, i)	\
117 	do {	\
118 		(code) = INVALID_SIZE_CODE;	\
119 		for ((i) = 8; (i) <= 0x1f; (i)++) {	   \
120 			if (((uint32_t)0x1 << (i)) == ((size) >> 12)) { \
121 				(code) = (i);	\
122 				break;	\
123 			}	\
124 		}	\
125 	} while (0)
126 
127 #define RANGE_CODE_TO_SIZE_K(code, sizek)	((sizek) = ((4) << (code)))
128 
129 #define TZ_LOCK_MC(x)		\
130 	do {	\
131 		(x) = io_read32(MCU_MC_CONTROL_0_REG);	\
132 		(x) |= (TRUSTZONE_LOCK);	\
133 		 io_write32(MCU_MC_CONTROL_0_REG, (x));	\
134 	} while (0)
135 
136 register_phys_mem_pgdir(MEM_AREA_IO_SEC, MCU_BASE, CORE_MMU_PGDIR_SIZE);
137 register_phys_mem_pgdir(MEM_AREA_IO_SEC, MC_SCR_REGISTER, CORE_MMU_PGDIR_SIZE);
138 
_find_valid_range(void)139 static int32_t _find_valid_range(void)
140 {
141 	uint32_t i;
142 	uint32_t tmp;
143 
144 	for (i = 0; i < MAX_RANGE_NUM; i++) {
145 		tmp = io_read32(MCU_TZ_RANGE_LOW_REG(i));
146 		if (!TZ_IS_VALID(tmp))
147 			return i;
148 	}
149 	return -1;
150 }
151 
set_range(uint32_t addr,uint32_t size,uint32_t perm)152 static int32_t set_range(uint32_t addr, uint32_t size, uint32_t perm)
153 {
154 	uint32_t data;
155 	uint32_t sizecode;
156 	int32_t valid_range;
157 	uint32_t i;
158 
159 	if (!IS_ALIGNED(addr, SIZE_1M)) {
160 		EMSG("region addr(0x%" PRIx32 ") is not aligned with 1M!",
161 			addr);
162 		return -1;
163 	}
164 
165 	if (!IS_ALIGNED(size, SIZE_1M)) {
166 		EMSG("region size(0x%" PRIx32 ") is not aligned with 1M!",
167 			size);
168 		return -1;
169 	}
170 
171 	if (!IS_ALIGNED(addr, size)) {
172 		EMSG("region size(0x%" PRIx32
173 			") not align with addr(0x%" PRIx32 ")",
174 			size, addr);
175 		return -1;
176 	}
177 
178 	RANGE_SIZE_TO_CODE(size, sizecode, i);
179 	if (sizecode == INVALID_SIZE_CODE) {
180 		EMSG("not valid region size(2^n)! size:0x%" PRIx32, size);
181 		return -1;
182 	}
183 
184 	valid_range = _find_valid_range();
185 	if (valid_range == -1) {
186 		EMSG("ERR: can't find valid range!");
187 		return -1;
188 	}
189 
190 	data = io_read32(MCU_TZ_RANGE_LOW_REG(valid_range));
191 
192 	TZ_SET_VALID(data);
193 	TZ_SET_PERM(data, perm);
194 	TZ_SET_AREA_LEN_CODE(data, sizecode);
195 	TZ_SET_START_ADDR_L(data, addr);
196 
197 	if (!valid_range) {
198 		/* Set Undefine Range RW */
199 		TZ_SET_UR_PERM(data, RW_PERM);
200 		TZ_SET_UR_RZ_EN(data, 0);
201 	}
202 
203 	io_write32(MCU_TZ_RANGE_LOW_REG(valid_range), data);
204 
205 	return 0;
206 }
207 
_dump_range(void)208 static void  _dump_range(void)
209 {
210 	uint32_t i;
211 	uint32_t tmp;
212 	uint32_t sizek;
213 	uint32_t sizecode_read;
214 	uint32_t __maybe_unused sizem;
215 	uint32_t __maybe_unused addr_read;
216 	uint32_t __maybe_unused perm_read;
217 
218 	for (i = 0; i < MAX_RANGE_NUM; i++) {
219 		tmp = io_read32(MCU_TZ_RANGE_LOW_REG(i));
220 
221 		if (TZ_IS_VALID(tmp)) {
222 			TZ_GET_PERM(tmp, perm_read);
223 			TZ_GET_AREA_LEN_CODE(tmp, sizecode_read);
224 			TZ_GET_START_ADDR_L(tmp, addr_read);
225 
226 			DMSG("Range Num%" PRIu32
227 				": Reg 0x%" PRIx64 " = 0x%" PRIx32,
228 				i, MCU_TZ_RANGE_LOW_REG(i), tmp);
229 			DMSG("AddrL: 0x%08" PRIx32, addr_read);
230 			RANGE_CODE_TO_SIZE_K(sizecode_read, sizek);
231 			sizem = sizek >> 10;
232 			DMSG("Size: %" PRIu32 "K, %" PRIu32 "M", sizek, sizem);
233 			DMSG("Perm: %" PRIu32, perm_read);
234 		}
235 	}
236 }
237 
_find_granule(uint32_t addr,uint32_t size)238 static uint32_t _find_granule(uint32_t addr, uint32_t size)
239 {
240 	/* max supported granule for armada is 8TB
241 	 * but 2GB is far enough here
242 	 */
243 	uint32_t max_granule = SIZE_2G;
244 
245 	while (max_granule >= SIZE_4K) {	/* min granule is 4kB */
246 		if (max_granule <= size && IS_ALIGNED(addr, max_granule))
247 			return max_granule;
248 
249 		max_granule >>= 1;
250 	}
251 
252 	return 0;	/* cannot find a valid granule */
253 }
254 
_set_range(uint32_t addr,uint32_t size,uint32_t perm)255 static void _set_range(uint32_t addr, uint32_t size, uint32_t perm)
256 {
257 	uint32_t rgn_addr = addr;
258 	uint32_t rgn_size = size;
259 	uint32_t p;
260 
261 	while (rgn_size) {
262 		p = _find_granule(rgn_addr, rgn_size);
263 		if (!p)
264 			panic("cannot find a suitable granule!");
265 		if (set_range(rgn_addr, p, perm))
266 			panic("set_range failed!");
267 
268 		rgn_addr += p;
269 		rgn_size -= p;
270 	}
271 }
272 
init_sec_perf(void)273 static TEE_Result init_sec_perf(void)
274 {
275 	uint32_t tmp;
276 
277 	/* MC_SCR config: deny NS access to MC registers */
278 	tmp = io_read32(PHY_2_VIR(MC_SCR_REGISTER));
279 	tmp |= 0x1;
280 	io_write32(PHY_2_VIR(MC_SCR_REGISTER), tmp);
281 
282 	/* Set Secure Memory Region */
283 	DMSG("sec-rgn size: ra = 0x%08" PRIx32 ", size = 0x%" PRIx32,
284 		RA_ADDR, RA_SIZE);
285 	_set_range(RA_ADDR, RA_SIZE, RA_PERM);
286 
287 	/* Close TZ register modification */
288 	TZ_LOCK_MC(tmp);
289 
290 	_dump_range();
291 
292 	return TEE_SUCCESS;
293 }
294 
295 service_init(init_sec_perf);
296