1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2017-2020 NXP
4  * All rights reserved.
5  *
6  * Peng Fan <peng.fan@nxp.com>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice,
12  * this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <assert.h>
32 #include <drivers/tzc380.h>
33 #include <io.h>
34 #include <kernel/panic.h>
35 #include <mm/core_memprot.h>
36 #include <mm/core_mmu.h>
37 #include <stddef.h>
38 #include <trace.h>
39 #include <util.h>
40 
41 /*
42  * Implementation defined values used to validate inputs later.
43  * Filters : max of 4 ; 0 to 3
44  * Regions : max of 9 ; 0 to 8
45  * Address width : Values between 32 to 64
46  */
47 struct tzc_instance {
48 	vaddr_t base;
49 	uint8_t addr_width;
50 	uint8_t num_regions;
51 };
52 
53 static struct tzc_instance tzc;
54 
tzc_read_build_config(vaddr_t base)55 static uint32_t tzc_read_build_config(vaddr_t base)
56 {
57 	return io_read32(base + BUILD_CONFIG_OFF);
58 }
59 
tzc_write_action(vaddr_t base,enum tzc_action action)60 static void tzc_write_action(vaddr_t base, enum tzc_action action)
61 {
62 	io_write32(base + ACTION_OFF, action);
63 }
64 
tzc_read_action(vaddr_t base)65 static uint32_t tzc_read_action(vaddr_t base)
66 {
67 	return io_read32(base + ACTION_OFF);
68 }
69 
tzc_write_region_base_low(vaddr_t base,uint32_t region,uint32_t val)70 static void tzc_write_region_base_low(vaddr_t base, uint32_t region,
71 				      uint32_t val)
72 {
73 	io_write32(base + REGION_SETUP_LOW_OFF(region), val);
74 }
75 
tzc_write_region_base_high(vaddr_t base,uint32_t region,uint32_t val)76 static void tzc_write_region_base_high(vaddr_t base, uint32_t region,
77 				       uint32_t val)
78 {
79 	io_write32(base + REGION_SETUP_HIGH_OFF(region), val);
80 }
81 
tzc_read_region_attributes(vaddr_t base,uint32_t region)82 static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region)
83 {
84 	return io_read32(base + REGION_ATTRIBUTES_OFF(region));
85 }
86 
tzc_write_region_attributes(vaddr_t base,uint32_t region,uint32_t val)87 static void tzc_write_region_attributes(vaddr_t base, uint32_t region,
88 					uint32_t val)
89 {
90 	io_write32(base + REGION_ATTRIBUTES_OFF(region), val);
91 }
92 
tzc_init(vaddr_t base)93 void tzc_init(vaddr_t base)
94 {
95 	uint32_t tzc_build;
96 
97 	assert(base);
98 	tzc.base = base;
99 
100 	/* Save values we will use later. */
101 	tzc_build = tzc_read_build_config(tzc.base);
102 	tzc.addr_width  = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) &
103 			   BUILD_CONFIG_AW_MASK) + 1;
104 	tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) &
105 			   BUILD_CONFIG_NR_MASK) + 1;
106 }
107 
108 /*
109  * There are two modes of operation for the region security
110  * permissions, with or without security inversion.
111  * Check TZC380 "2.2.5 Region security permissions" for
112  * more details.
113  */
tzc_security_inversion_en(vaddr_t base)114 void tzc_security_inversion_en(vaddr_t base)
115 {
116 	io_write32(base + SECURITY_INV_EN_OFF, 1);
117 }
118 
119 /*
120  * Enable a single region. Sometimes we could not use tzc_configure_region
121  * to enable the region, when security inversion is on.
122  * When need security inversion, we need to first configure
123  * region address and attribute, then configure security inversion,
124  * then enable the regions.
125  */
tzc_region_enable(uint8_t region)126 void tzc_region_enable(uint8_t region)
127 {
128 	uint32_t val;
129 
130 	val = tzc_read_region_attributes(tzc.base, region);
131 	val |= TZC_ATTR_REGION_EN_MASK;
132 	tzc_write_region_attributes(tzc.base, region, val);
133 }
134 
135 /*
136  * Dump info when TZC380 catchs an unallowed access with TZC
137  * interrupt enabled.
138  */
tzc_fail_dump(void)139 void tzc_fail_dump(void)
140 {
141 	vaddr_t base __maybe_unused = core_mmu_get_va(tzc.base,
142 						      MEM_AREA_IO_SEC,
143 						      TZC400_REG_SIZE);
144 
145 	EMSG("Fail address Low 0x%" PRIx32,
146 	     io_read32(base + FAIL_ADDRESS_LOW_OFF));
147 	EMSG("Fail address High 0x%" PRIx32,
148 	     io_read32(base + FAIL_ADDRESS_HIGH_OFF));
149 	EMSG("Fail Control 0x%" PRIx32, io_read32(base + FAIL_CONTROL_OFF));
150 	EMSG("Fail Id 0x%" PRIx32, io_read32(base + FAIL_ID));
151 }
152 
tzc_int_clear(void)153 void tzc_int_clear(void)
154 {
155 	vaddr_t base = core_mmu_get_va(tzc.base, MEM_AREA_IO_SEC,
156 				       TZC400_REG_SIZE);
157 
158 	io_write32(base + INT_CLEAR, 0);
159 }
160 
addr_low(vaddr_t addr)161 static uint32_t addr_low(vaddr_t addr)
162 {
163 	return (uint32_t)addr;
164 }
165 
addr_high(vaddr_t addr __maybe_unused)166 static uint32_t addr_high(vaddr_t addr __maybe_unused)
167 {
168 #if (UINTPTR_MAX == UINT64_MAX)
169 	return addr >> 32;
170 #else
171 	return 0;
172 #endif
173 }
174 
175 
176 /*
177  * `tzc_configure_region` is used to program regions into the TrustZone
178  * controller.
179  */
tzc_configure_region(uint8_t region,vaddr_t region_base,uint32_t attr)180 void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr)
181 {
182 	assert(tzc.base);
183 
184 	assert(region < tzc.num_regions);
185 
186 	/*
187 	 * For region 0, this high/low/size/en field is Read Only (RO).
188 	 * So should not configure those field for region 0.
189 	 */
190 	if (region) {
191 		tzc_write_region_base_low(tzc.base, region,
192 					  addr_low(region_base));
193 		tzc_write_region_base_high(tzc.base, region,
194 					   addr_high(region_base));
195 		tzc_write_region_attributes(tzc.base, region, attr);
196 	} else {
197 		tzc_write_region_attributes(tzc.base, region,
198 					    attr & TZC_ATTR_SP_MASK);
199 	}
200 }
201 
tzc_set_action(enum tzc_action action)202 void tzc_set_action(enum tzc_action action)
203 {
204 	assert(tzc.base);
205 
206 	/*
207 	 * - Currently no handler is provided to trap an error via interrupt
208 	 *   or exception.
209 	 * - The interrupt action has not been tested.
210 	 */
211 	tzc_write_action(tzc.base, action);
212 }
213 
tzc_get_action(void)214 uint32_t tzc_get_action(void)
215 {
216 	assert(tzc.base);
217 
218 	return tzc_read_action(tzc.base);
219 }
220 
tzc_auto_configure(vaddr_t addr,vaddr_t size,uint32_t attr,uint8_t region)221 int tzc_auto_configure(vaddr_t addr, vaddr_t size, uint32_t attr,
222 		       uint8_t region)
223 {
224 	uint64_t sub_region_size = 0;
225 	uint64_t area = 0;
226 	uint8_t lregion = region;
227 	uint64_t region_size = 0;
228 	vaddr_t sub_address = 0;
229 	vaddr_t address = addr;
230 	uint64_t lsize = size;
231 	uint32_t mask = 0;
232 	int i = 0;
233 	uint8_t pow = 0;
234 
235 	assert(tzc.base);
236 
237 	/*
238 	 * TZC380 RM
239 	 * For region_attributes_<n> registers, region_size:
240 	 * Note: The AXI address width, that is AXI_ADDRESS_MSB+1, controls the
241 	 * upper limit value of the field.
242 	 */
243 	pow = tzc.addr_width;
244 
245 	while (lsize != 0 && pow > 15) {
246 		region_size = 1ULL << pow;
247 
248 		/* Case region fits alignment and covers requested area */
249 		if ((address % region_size == 0) &&
250 		    ((address + lsize) % region_size == 0)) {
251 			tzc_configure_region(lregion, address,
252 					     TZC_ATTR_REGION_SIZE(pow - 1) |
253 					     TZC_ATTR_REGION_EN_MASK |
254 					     attr);
255 			lregion++;
256 			address += region_size;
257 			lsize -= region_size;
258 			pow = tzc.addr_width;
259 			continue;
260 		}
261 
262 		/* Cover area using several subregions */
263 		sub_region_size = region_size / 8;
264 		if (address % sub_region_size == 0 &&
265 		    lsize > 2 * sub_region_size) {
266 			sub_address = (address / region_size) * region_size;
267 			mask = 0;
268 			for (i = 0; i < 8; i++) {
269 				area = (i + 1) * sub_region_size;
270 				if (sub_address + area <= address ||
271 				    sub_address + area > address + lsize) {
272 					mask |= TZC_ATTR_SUBREGION_DIS(i);
273 				} else {
274 					address += sub_region_size;
275 					lsize -= sub_region_size;
276 				}
277 			}
278 			tzc_configure_region(lregion, sub_address,
279 					     TZC_ATTR_REGION_SIZE(pow - 1) |
280 					     TZC_ATTR_REGION_EN_MASK |
281 					     mask | attr);
282 			lregion++;
283 			pow = tzc.addr_width;
284 			continue;
285 		}
286 		pow--;
287 	}
288 	assert(lsize == 0);
289 	assert(address == addr + size);
290 	return lregion;
291 }
292 
293 /*
294  * `region_lockdown` is used to lockdown the TZC380 configuration to prevent
295  * unintended overwrites of the configuration. Returns TEE_ERROR_SECURITY in
296  * case the lockdown fails.
297  */
tzc_regions_lockdown(void)298 TEE_Result tzc_regions_lockdown(void)
299 {
300 	uint32_t val = 0;
301 	uint32_t check = 0;
302 
303 	val = LOCKDOWN_RANGE_ENABLE | tzc.num_regions;
304 	io_write32(tzc.base + LOCKDOWN_RANGE_OFF, val);
305 	check = io_read32(tzc.base + LOCKDOWN_RANGE_OFF);
306 	if (check != val)
307 		return TEE_ERROR_SECURITY;
308 
309 	val = LOCKDOWN_SELECT_RANGE_ENABLE;
310 	io_write32(tzc.base + LOCKDOWN_SELECT_OFF, val);
311 	check = io_read32(tzc.base + LOCKDOWN_SELECT_OFF);
312 	if (check != val)
313 		return TEE_ERROR_SECURITY;
314 
315 	return TEE_SUCCESS;
316 }
317 
318 #if TRACE_LEVEL >= TRACE_DEBUG
319 
tzc_read_region_base_low(vaddr_t base,uint32_t region)320 static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region)
321 {
322 	return io_read32(base + REGION_SETUP_LOW_OFF(region));
323 }
324 
tzc_read_region_base_high(vaddr_t base,uint32_t region)325 static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region)
326 {
327 	return io_read32(base + REGION_SETUP_HIGH_OFF(region));
328 }
329 
330 #define	REGION_MAX	16
tzc_dump_state(void)331 void tzc_dump_state(void)
332 {
333 	uint32_t n;
334 	uint32_t temp_32reg, temp_32reg_h;
335 
336 	DMSG("TZC380 configuration:");
337 	DMSG("security_inversion_en %x",
338 	     io_read32(tzc.base + SECURITY_INV_EN_OFF));
339 	for (n = 0; n <= REGION_MAX; n++) {
340 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
341 		if (!(temp_32reg & TZC_ATTR_REGION_EN_MASK))
342 			continue;
343 
344 		DMSG("");
345 		DMSG("region %d", n);
346 		temp_32reg = tzc_read_region_base_low(tzc.base, n);
347 		temp_32reg_h = tzc_read_region_base_high(tzc.base, n);
348 		DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg);
349 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
350 		DMSG("region sp: %x", temp_32reg >> TZC_ATTR_SP_SHIFT);
351 		DMSG("region size: %x", (temp_32reg & TZC_REGION_SIZE_MASK) >>
352 				TZC_REGION_SIZE_SHIFT);
353 	}
354 	DMSG("Lockdown select: %"PRIx32,
355 	     io_read32(tzc.base + LOCKDOWN_SELECT_OFF));
356 	DMSG("Lockdown range: %"PRIx32,
357 	     io_read32(tzc.base + LOCKDOWN_RANGE_OFF));
358 	DMSG("Action register: %"PRIx32, tzc_get_action());
359 	DMSG("exit");
360 }
361 
362 #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */
363