xref: /optee_os/core/drivers/tzc380.c (revision 7eedcd151e9c7b5eb56ab2f6379ee9c3de77e8c4)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2017 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 
55 static uint32_t tzc_read_build_config(vaddr_t base)
56 {
57 	return io_read32(base + BUILD_CONFIG_OFF);
58 }
59 
60 static void tzc_write_action(vaddr_t base, enum tzc_action action)
61 {
62 	io_write32(base + ACTION_OFF, action);
63 }
64 
65 static uint32_t tzc_read_action(vaddr_t base)
66 {
67 	return io_read32(base + ACTION_OFF);
68 }
69 
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 
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 
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 
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 
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  */
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  */
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  */
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 
144 	EMSG("Fail address Low 0x%" PRIx32,
145 	     io_read32(base + FAIL_ADDRESS_LOW_OFF));
146 	EMSG("Fail address High 0x%" PRIx32,
147 	     io_read32(base + FAIL_ADDRESS_HIGH_OFF));
148 	EMSG("Fail Control 0x%" PRIx32, io_read32(base + FAIL_CONTROL_OFF));
149 	EMSG("Fail Id 0x%" PRIx32, io_read32(base + FAIL_ID));
150 }
151 
152 void tzc_int_clear(void)
153 {
154 	vaddr_t base = core_mmu_get_va(tzc.base, MEM_AREA_IO_SEC);
155 
156 	io_write32(base + INT_CLEAR, 0);
157 }
158 
159 static uint32_t addr_low(vaddr_t addr)
160 {
161 	return (uint32_t)addr;
162 }
163 
164 static uint32_t addr_high(vaddr_t addr __maybe_unused)
165 {
166 #if (UINTPTR_MAX == UINT64_MAX)
167 	return addr >> 32;
168 #else
169 	return 0;
170 #endif
171 }
172 
173 
174 /*
175  * `tzc_configure_region` is used to program regions into the TrustZone
176  * controller.
177  */
178 void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr)
179 {
180 	assert(tzc.base);
181 
182 	assert(region < tzc.num_regions);
183 
184 	/*
185 	 * For region 0, this high/low/size/en field is Read Only (RO).
186 	 * So should not configure those field for region 0.
187 	 */
188 	if (region) {
189 		tzc_write_region_base_low(tzc.base, region,
190 					  addr_low(region_base));
191 		tzc_write_region_base_high(tzc.base, region,
192 					   addr_high(region_base));
193 		tzc_write_region_attributes(tzc.base, region, attr);
194 	} else {
195 		tzc_write_region_attributes(tzc.base, region,
196 					    attr & TZC_ATTR_SP_MASK);
197 	}
198 }
199 
200 void tzc_set_action(enum tzc_action action)
201 {
202 	assert(tzc.base);
203 
204 	/*
205 	 * - Currently no handler is provided to trap an error via interrupt
206 	 *   or exception.
207 	 * - The interrupt action has not been tested.
208 	 */
209 	tzc_write_action(tzc.base, action);
210 }
211 
212 uint32_t tzc_get_action(void)
213 {
214 	assert(tzc.base);
215 
216 	return tzc_read_action(tzc.base);
217 }
218 
219 #if TRACE_LEVEL >= TRACE_DEBUG
220 
221 static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region)
222 {
223 	return io_read32(base + REGION_SETUP_LOW_OFF(region));
224 }
225 
226 static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region)
227 {
228 	return io_read32(base + REGION_SETUP_HIGH_OFF(region));
229 }
230 
231 #define	REGION_MAX	16
232 void tzc_dump_state(void)
233 {
234 	uint32_t n;
235 	uint32_t temp_32reg, temp_32reg_h;
236 
237 	DMSG("enter");
238 	DMSG("security_inversion_en %x",
239 	     io_read32(tzc.base + SECURITY_INV_EN_OFF));
240 	for (n = 0; n <= REGION_MAX; n++) {
241 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
242 		if (!(temp_32reg & TZC_ATTR_REGION_EN_MASK))
243 			continue;
244 
245 		DMSG("");
246 		DMSG("region %d", n);
247 		temp_32reg = tzc_read_region_base_low(tzc.base, n);
248 		temp_32reg_h = tzc_read_region_base_high(tzc.base, n);
249 		DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg);
250 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
251 		DMSG("region sp: %x", temp_32reg >> TZC_ATTR_SP_SHIFT);
252 		DMSG("region size: %x", (temp_32reg & TZC_REGION_SIZE_MASK) >>
253 				TZC_REGION_SIZE_SHIFT);
254 	}
255 	DMSG("exit");
256 }
257 
258 #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */
259