xref: /optee_os/core/drivers/tzc380.c (revision 77327d7a47019cf9f66972403d0de1c32fe4cdee)
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 void tzc_write_region_base_low(vaddr_t base, uint32_t region,
66 				      uint32_t val)
67 {
68 	io_write32(base + REGION_SETUP_LOW_OFF(region), val);
69 }
70 
71 static void tzc_write_region_base_high(vaddr_t base, uint32_t region,
72 				       uint32_t val)
73 {
74 	io_write32(base + REGION_SETUP_HIGH_OFF(region), val);
75 }
76 
77 static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region)
78 {
79 	return io_read32(base + REGION_ATTRIBUTES_OFF(region));
80 }
81 
82 static void tzc_write_region_attributes(vaddr_t base, uint32_t region,
83 					uint32_t val)
84 {
85 	io_write32(base + REGION_ATTRIBUTES_OFF(region), val);
86 }
87 
88 void tzc_init(vaddr_t base)
89 {
90 	uint32_t tzc_build;
91 
92 	assert(base);
93 	tzc.base = base;
94 
95 	/* Save values we will use later. */
96 	tzc_build = tzc_read_build_config(tzc.base);
97 	tzc.addr_width  = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) &
98 			   BUILD_CONFIG_AW_MASK) + 1;
99 	tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) &
100 			   BUILD_CONFIG_NR_MASK) + 1;
101 }
102 
103 /*
104  * There are two modes of operation for the region security
105  * permissions, with or without security inversion.
106  * Check TZC380 "2.2.5 Region security permissions" for
107  * more details.
108  */
109 void tzc_security_inversion_en(vaddr_t base)
110 {
111 	io_write32(base + SECURITY_INV_EN_OFF, 1);
112 }
113 
114 /*
115  * Enable a single region. Sometimes we could not use tzc_configure_region
116  * to enable the region, when security inversion is on.
117  * When need security inversion, we need to first configure
118  * region address and attribute, then configure security inversion,
119  * then enable the regions.
120  */
121 void tzc_region_enable(uint8_t region)
122 {
123 	uint32_t val;
124 
125 	val = tzc_read_region_attributes(tzc.base, region);
126 	val |= TZC_ATTR_REGION_EN_MASK;
127 	tzc_write_region_attributes(tzc.base, region, val);
128 }
129 
130 /*
131  * Dump info when TZC380 catchs an unallowed access with TZC
132  * interrupt enabled.
133  */
134 void tzc_fail_dump(void)
135 {
136 	vaddr_t base __maybe_unused = core_mmu_get_va(tzc.base,
137 						      MEM_AREA_IO_SEC);
138 
139 	EMSG("Fail address Low 0x%" PRIx32,
140 	     io_read32(base + FAIL_ADDRESS_LOW_OFF));
141 	EMSG("Fail address High 0x%" PRIx32,
142 	     io_read32(base + FAIL_ADDRESS_HIGH_OFF));
143 	EMSG("Fail Control 0x%" PRIx32, io_read32(base + FAIL_CONTROL_OFF));
144 	EMSG("Fail Id 0x%" PRIx32, io_read32(base + FAIL_ID));
145 }
146 
147 void tzc_int_clear(void)
148 {
149 	vaddr_t base = core_mmu_get_va(tzc.base, MEM_AREA_IO_SEC);
150 
151 	io_write32(base + INT_CLEAR, 0);
152 }
153 
154 static uint32_t addr_low(vaddr_t addr)
155 {
156 	return (uint32_t)addr;
157 }
158 
159 static uint32_t addr_high(vaddr_t addr __maybe_unused)
160 {
161 #if (UINTPTR_MAX == UINT64_MAX)
162 	return addr >> 32;
163 #else
164 	return 0;
165 #endif
166 }
167 
168 
169 /*
170  * `tzc_configure_region` is used to program regions into the TrustZone
171  * controller.
172  */
173 void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr)
174 {
175 	assert(tzc.base);
176 
177 	assert(region < tzc.num_regions);
178 
179 	/*
180 	 * For region 0, this high/low/size/en field is Read Only (RO).
181 	 * So should not configure those field for region 0.
182 	 */
183 	if (region) {
184 		tzc_write_region_base_low(tzc.base, region,
185 					  addr_low(region_base));
186 		tzc_write_region_base_high(tzc.base, region,
187 					   addr_high(region_base));
188 		tzc_write_region_attributes(tzc.base, region, attr);
189 	} else {
190 		tzc_write_region_attributes(tzc.base, region,
191 					    attr & TZC_ATTR_SP_MASK);
192 	}
193 }
194 
195 void tzc_set_action(enum tzc_action action)
196 {
197 	assert(tzc.base);
198 
199 	/*
200 	 * - Currently no handler is provided to trap an error via interrupt
201 	 *   or exception.
202 	 * - The interrupt action has not been tested.
203 	 */
204 	tzc_write_action(tzc.base, action);
205 }
206 
207 #if TRACE_LEVEL >= TRACE_DEBUG
208 
209 static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region)
210 {
211 	return io_read32(base + REGION_SETUP_LOW_OFF(region));
212 }
213 
214 static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region)
215 {
216 	return io_read32(base + REGION_SETUP_HIGH_OFF(region));
217 }
218 
219 #define	REGION_MAX	16
220 void tzc_dump_state(void)
221 {
222 	uint32_t n;
223 	uint32_t temp_32reg, temp_32reg_h;
224 
225 	DMSG("enter");
226 	DMSG("security_inversion_en %x",
227 	     io_read32(tzc.base + SECURITY_INV_EN_OFF));
228 	for (n = 0; n <= REGION_MAX; n++) {
229 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
230 		if (!(temp_32reg & TZC_ATTR_REGION_EN_MASK))
231 			continue;
232 
233 		DMSG("");
234 		DMSG("region %d", n);
235 		temp_32reg = tzc_read_region_base_low(tzc.base, n);
236 		temp_32reg_h = tzc_read_region_base_high(tzc.base, n);
237 		DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg);
238 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
239 		DMSG("region sp: %x", temp_32reg >> TZC_ATTR_SP_SHIFT);
240 		DMSG("region size: %x", (temp_32reg & TZC_REGION_SIZE_MASK) >>
241 				TZC_REGION_SIZE_SHIFT);
242 	}
243 	DMSG("exit");
244 }
245 
246 #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */
247