xref: /optee_os/core/drivers/tzc400.c (revision 5a913ee74d3c71af2a2860ce8a4e7aeab2916f9b)
1 // SPDX-License-Identifier: (BSD-2-Clause AND BSD-3-Clause)
2 /*
3  * Copyright (c) 2015, Linaro Limited
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  * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions are met:
33  *
34  * Redistributions of source code must retain the above copyright notice, this
35  * list of conditions and the following disclaimer.
36  *
37  * Redistributions in binary form must reproduce the above copyright notice,
38  * this list of conditions and the following disclaimer in the documentation
39  * and/or other materials provided with the distribution.
40  *
41  * Neither the name of ARM nor the names of its contributors may be used
42  * to endorse or promote products derived from this software without specific
43  * prior written permission.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
46  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
49  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55  * POSSIBILITY OF SUCH DAMAGE.
56  */
57 
58 #include <assert.h>
59 #include <drivers/tzc400.h>
60 #include <io.h>
61 #include <kernel/panic.h>
62 #include <stddef.h>
63 #include <trace.h>
64 #include <util.h>
65 
66 /*
67  * Implementation defined values used to validate inputs later.
68  * Filters : max of 4 ; 0 to 3
69  * Regions : max of 9 ; 0 to 8
70  * Address width : Values between 32 to 64
71  */
72 struct tzc_instance {
73 	vaddr_t base;
74 	uint8_t addr_width;
75 	uint8_t num_filters;
76 	uint8_t num_regions;
77 };
78 
79 static struct tzc_instance tzc;
80 
81 
82 static uint32_t tzc_read_build_config(vaddr_t base)
83 {
84 	return io_read32(base + BUILD_CONFIG_OFF);
85 }
86 
87 static uint32_t tzc_read_gate_keeper(vaddr_t base)
88 {
89 	return io_read32(base + GATE_KEEPER_OFF);
90 }
91 
92 static void tzc_write_gate_keeper(vaddr_t base, uint32_t val)
93 {
94 	io_write32(base + GATE_KEEPER_OFF, val);
95 }
96 
97 static void tzc_write_action(vaddr_t base, enum tzc_action action)
98 {
99 	io_write32(base + ACTION_OFF, action);
100 }
101 
102 static void tzc_write_region_base_low(vaddr_t base, uint32_t region,
103 				      uint32_t val)
104 {
105 	io_write32(base + REGION_BASE_LOW_OFF + REGION_NUM_OFF(region), val);
106 }
107 
108 static void tzc_write_region_base_high(vaddr_t base, uint32_t region,
109 				       uint32_t val)
110 {
111 	io_write32(base + REGION_BASE_HIGH_OFF + REGION_NUM_OFF(region), val);
112 }
113 
114 static void tzc_write_region_top_low(vaddr_t base, uint32_t region,
115 				     uint32_t val)
116 {
117 	io_write32(base + REGION_TOP_LOW_OFF + REGION_NUM_OFF(region), val);
118 }
119 
120 static void tzc_write_region_top_high(vaddr_t base, uint32_t region,
121 				      uint32_t val)
122 {
123 	io_write32(base + REGION_TOP_HIGH_OFF +	REGION_NUM_OFF(region), val);
124 }
125 
126 static void tzc_write_region_attributes(vaddr_t base, uint32_t region,
127 					uint32_t val)
128 {
129 	io_write32(base + REGION_ATTRIBUTES_OFF + REGION_NUM_OFF(region), val);
130 }
131 
132 static void tzc_write_region_id_access(vaddr_t base, uint32_t region,
133 				       uint32_t val)
134 {
135 	io_write32(base + REGION_ID_ACCESS_OFF + REGION_NUM_OFF(region), val);
136 }
137 
138 static uint32_t tzc_read_component_id(vaddr_t base)
139 {
140 	uint32_t id;
141 
142 	id = io_read8(base + CID0_OFF);
143 	id |= SHIFT_U32(io_read8(base + CID1_OFF), 8);
144 	id |= SHIFT_U32(io_read8(base + CID2_OFF), 16);
145 	id |= SHIFT_U32(io_read8(base + CID3_OFF), 24);
146 
147 	return id;
148 }
149 
150 static uint32_t tzc_get_gate_keeper(vaddr_t base, uint8_t filter)
151 {
152 	uint32_t tmp;
153 
154 	tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
155 		GATE_KEEPER_OS_MASK;
156 
157 	return (tmp >> filter) & GATE_KEEPER_FILTER_MASK;
158 }
159 
160 /* This function is not MP safe. */
161 static void tzc_set_gate_keeper(vaddr_t base, uint8_t filter, uint32_t val)
162 {
163 	uint32_t tmp;
164 
165 	/* Upper half is current state. Lower half is requested state. */
166 	tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
167 		GATE_KEEPER_OS_MASK;
168 
169 	if (val)
170 		tmp |=  (1 << filter);
171 	else
172 		tmp &= ~(1 << filter);
173 
174 	tzc_write_gate_keeper(base, (tmp & GATE_KEEPER_OR_MASK) <<
175 			      GATE_KEEPER_OR_SHIFT);
176 
177 	/* Wait here until we see the change reflected in the TZC status. */
178 	while (((tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
179 		GATE_KEEPER_OS_MASK) != tmp)
180 		;
181 }
182 
183 
184 void tzc_init(vaddr_t base)
185 {
186 	uint32_t tzc_id, tzc_build;
187 
188 	assert(base);
189 	tzc.base = base;
190 
191 	/*
192 	 * We expect to see a tzc400. Check component ID. The TZC-400 TRM shows
193 	 * component ID is expected to be "0xB105F00D".
194 	 */
195 	tzc_id = tzc_read_component_id(tzc.base);
196 	if (tzc_id != TZC400_COMPONENT_ID) {
197 		EMSG("TZC : Wrong device ID (0x%" PRIx32 ")", tzc_id);
198 		panic();
199 	}
200 
201 	/* Save values we will use later. */
202 	tzc_build = tzc_read_build_config(tzc.base);
203 	tzc.num_filters = ((tzc_build >> BUILD_CONFIG_NF_SHIFT) &
204 			   BUILD_CONFIG_NF_MASK) + 1;
205 	tzc.addr_width  = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) &
206 			   BUILD_CONFIG_AW_MASK) + 1;
207 	tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) &
208 			   BUILD_CONFIG_NR_MASK) + 1;
209 }
210 
211 static uint32_t addr_low(vaddr_t addr)
212 {
213 	return (uint32_t)addr;
214 }
215 
216 static uint32_t addr_high(vaddr_t addr __unused)
217 {
218 #if (UINTPTR_MAX == UINT64_MAX)
219 	return (addr >> 32);
220 #else
221 	return 0;
222 #endif
223 }
224 
225 
226 /*
227  * `tzc_configure_region` is used to program regions into the TrustZone
228  * controller. A region can be associated with more than one filter. The
229  * associated filters are passed in as a bitmap (bit0 = filter0).
230  * NOTE:
231  * The region 0 covers the whole address space and is enabled on all filters,
232  * this cannot be changed. It is, however, possible to change some region 0
233  * permissions.
234  */
235 void tzc_configure_region(uint32_t filters,
236 			  uint8_t  region,
237 			  vaddr_t  region_base,
238 			  vaddr_t  region_top,
239 			  enum tzc_region_attributes sec_attr,
240 			  uint32_t ns_device_access)
241 {
242 	assert(tzc.base);
243 
244 	/* Do range checks on filters and regions. */
245 	assert(((filters >> tzc.num_filters) == 0) &&
246 	       (region < tzc.num_regions));
247 
248 	/*
249 	 * Do address range check based on TZC configuration. A 64bit address is
250 	 * the max and expected case.
251 	 */
252 #if (UINTPTR_MAX == UINT64_MAX)
253 	assert(((region_top <= (UINT64_MAX >> (64 - tzc.addr_width))) &&
254 		(region_base < region_top)));
255 #endif
256 	/* region_base and (region_top + 1) must be 4KB aligned */
257 	assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0);
258 
259 	assert(sec_attr <= TZC_REGION_S_RDWR);
260 
261 	/*
262 	 * Inputs look ok, start programming registers.
263 	 * All the address registers are 32 bits wide and have a LOW and HIGH
264 	 * component used to construct a up to a 64bit address.
265 	 */
266 	tzc_write_region_base_low(tzc.base, region,
267 				  addr_low(region_base));
268 	tzc_write_region_base_high(tzc.base, region,
269 				   addr_high(region_base));
270 
271 	tzc_write_region_top_low(tzc.base, region,
272 				addr_low(region_top));
273 	tzc_write_region_top_high(tzc.base, region,
274 				addr_high(region_top));
275 
276 	/* Assign the region to a filter and set secure attributes */
277 	tzc_write_region_attributes(tzc.base, region,
278 		(sec_attr << REG_ATTR_SEC_SHIFT) | filters);
279 
280 	/*
281 	 * Specify which non-secure devices have permission to access this
282 	 * region.
283 	 */
284 	tzc_write_region_id_access(tzc.base, region, ns_device_access);
285 }
286 
287 
288 void tzc_set_action(enum tzc_action action)
289 {
290 	assert(tzc.base);
291 
292 	/*
293 	 * - Currently no handler is provided to trap an error via interrupt
294 	 *   or exception.
295 	 * - The interrupt action has not been tested.
296 	 */
297 	tzc_write_action(tzc.base, action);
298 }
299 
300 
301 void tzc_enable_filters(void)
302 {
303 	uint32_t state;
304 	uint32_t filter;
305 
306 	assert(tzc.base);
307 
308 	for (filter = 0; filter < tzc.num_filters; filter++) {
309 		state = tzc_get_gate_keeper(tzc.base, filter);
310 		if (state) {
311 			/*
312 			 * The TZC filter is already configured. Changing the
313 			 * programmer's view in an active system can cause
314 			 * unpredictable behavior therefore panic for now rather
315 			 * than try to determine whether this is safe in this
316 			 * instance. See:
317 			 * http://infocenter.arm.com/help/index.jsp?\
318 			 * topic=/com.arm.doc.ddi0504c/CJHHECBF.html
319 			 */
320 			EMSG("TZC : Filter %d Gatekeeper already enabled",
321 			     filter);
322 			panic();
323 		}
324 		tzc_set_gate_keeper(tzc.base, filter, 1);
325 	}
326 }
327 
328 
329 void tzc_disable_filters(void)
330 {
331 	uint32_t filter;
332 
333 	assert(tzc.base);
334 
335 	/*
336 	 * We don't do the same state check as above as the Gatekeepers are
337 	 * disabled after reset.
338 	 */
339 	for (filter = 0; filter < tzc.num_filters; filter++)
340 		tzc_set_gate_keeper(tzc.base, filter, 0);
341 }
342 
343 #if TRACE_LEVEL >= TRACE_DEBUG
344 
345 static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region)
346 {
347 	return io_read32(base + REGION_ATTRIBUTES_OFF + REGION_NUM_OFF(region));
348 }
349 
350 static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region)
351 {
352 	return io_read32(base + REGION_BASE_LOW_OFF + REGION_NUM_OFF(region));
353 }
354 
355 static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region)
356 {
357 	return io_read32(base + REGION_BASE_HIGH_OFF + REGION_NUM_OFF(region));
358 }
359 
360 static uint32_t tzc_read_region_top_low(vaddr_t base, uint32_t region)
361 {
362 	return io_read32(base + REGION_TOP_LOW_OFF + REGION_NUM_OFF(region));
363 }
364 
365 static uint32_t tzc_read_region_top_high(vaddr_t base, uint32_t region)
366 {
367 	return io_read32(base + REGION_TOP_HIGH_OFF + REGION_NUM_OFF(region));
368 }
369 
370 #define	REGION_MAX		8
371 static const __maybe_unused char * const tzc_attr_msg[] = {
372 	"TZC_REGION_S_NONE",
373 	"TZC_REGION_S_RD",
374 	"TZC_REGION_S_WR",
375 	"TZC_REGION_S_RDWR"
376 };
377 
378 void tzc_dump_state(void)
379 {
380 	uint32_t n;
381 	uint32_t temp_32reg, temp_32reg_h;
382 
383 	DMSG("enter");
384 	for (n = 0; n <= REGION_MAX; n++) {
385 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
386 		if (!(temp_32reg & REG_ATTR_F_EN_MASK))
387 			continue;
388 
389 		DMSG("\n");
390 		DMSG("region %d", n);
391 		temp_32reg = tzc_read_region_base_low(tzc.base, n);
392 		temp_32reg_h = tzc_read_region_base_high(tzc.base, n);
393 		DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg);
394 		temp_32reg = tzc_read_region_top_low(tzc.base, n);
395 		temp_32reg_h = tzc_read_region_top_high(tzc.base, n);
396 		DMSG("region_top: 0x%08x%08x", temp_32reg_h, temp_32reg);
397 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
398 		DMSG("secure rw: %s",
399 		     tzc_attr_msg[temp_32reg >> REG_ATTR_SEC_SHIFT]);
400 		if (temp_32reg & (1 << 0))
401 			DMSG("filter 0 enable");
402 		if (temp_32reg & (1 << 1))
403 			DMSG("filter 1 enable");
404 		if (temp_32reg & (1 << 2))
405 			DMSG("filter 2 enable");
406 		if (temp_32reg & (1 << 3))
407 			DMSG("filter 3 enable");
408 	}
409 	DMSG("exit");
410 }
411 
412 #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */
413