xref: /optee_os/core/drivers/tzc380.c (revision 343c157192ad693db1736d02d6dc549b1b6de4a3)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
24c56bf5fSPeng Fan /*
34c56bf5fSPeng Fan  * Copyright 2017 NXP
44c56bf5fSPeng Fan  * All rights reserved.
54c56bf5fSPeng Fan  *
64c56bf5fSPeng Fan  * Peng Fan <peng.fan@nxp.com>
74c56bf5fSPeng Fan  *
84c56bf5fSPeng Fan  * Redistribution and use in source and binary forms, with or without
94c56bf5fSPeng Fan  * modification, are permitted provided that the following conditions are met:
104c56bf5fSPeng Fan  *
114c56bf5fSPeng Fan  * 1. Redistributions of source code must retain the above copyright notice,
124c56bf5fSPeng Fan  * this list of conditions and the following disclaimer.
134c56bf5fSPeng Fan  *
144c56bf5fSPeng Fan  * 2. Redistributions in binary form must reproduce the above copyright notice,
154c56bf5fSPeng Fan  * this list of conditions and the following disclaimer in the documentation
164c56bf5fSPeng Fan  * and/or other materials provided with the distribution.
174c56bf5fSPeng Fan  *
184c56bf5fSPeng Fan  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
194c56bf5fSPeng Fan  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
204c56bf5fSPeng Fan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
214c56bf5fSPeng Fan  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
224c56bf5fSPeng Fan  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
234c56bf5fSPeng Fan  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
244c56bf5fSPeng Fan  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
254c56bf5fSPeng Fan  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
264c56bf5fSPeng Fan  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
274c56bf5fSPeng Fan  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
284c56bf5fSPeng Fan  * POSSIBILITY OF SUCH DAMAGE.
294c56bf5fSPeng Fan  */
304c56bf5fSPeng Fan 
314c56bf5fSPeng Fan #include <assert.h>
324c56bf5fSPeng Fan #include <drivers/tzc380.h>
334c56bf5fSPeng Fan #include <io.h>
344c56bf5fSPeng Fan #include <kernel/panic.h>
35*343c1571SPeng Fan #include <mm/core_memprot.h>
36*343c1571SPeng Fan #include <mm/core_mmu.h>
374c56bf5fSPeng Fan #include <stddef.h>
384c56bf5fSPeng Fan #include <trace.h>
394c56bf5fSPeng Fan #include <util.h>
404c56bf5fSPeng Fan 
414c56bf5fSPeng Fan /*
424c56bf5fSPeng Fan  * Implementation defined values used to validate inputs later.
434c56bf5fSPeng Fan  * Filters : max of 4 ; 0 to 3
444c56bf5fSPeng Fan  * Regions : max of 9 ; 0 to 8
454c56bf5fSPeng Fan  * Address width : Values between 32 to 64
464c56bf5fSPeng Fan  */
474c56bf5fSPeng Fan struct tzc_instance {
484c56bf5fSPeng Fan 	vaddr_t base;
494c56bf5fSPeng Fan 	uint8_t addr_width;
504c56bf5fSPeng Fan 	uint8_t num_regions;
514c56bf5fSPeng Fan };
524c56bf5fSPeng Fan 
534c56bf5fSPeng Fan static struct tzc_instance tzc;
544c56bf5fSPeng Fan 
554c56bf5fSPeng Fan static uint32_t tzc_read_build_config(vaddr_t base)
564c56bf5fSPeng Fan {
574c56bf5fSPeng Fan 	return read32(base + BUILD_CONFIG_OFF);
584c56bf5fSPeng Fan }
594c56bf5fSPeng Fan 
604c56bf5fSPeng Fan static void tzc_write_action(vaddr_t base, enum tzc_action action)
614c56bf5fSPeng Fan {
624c56bf5fSPeng Fan 	write32(action, base + ACTION_OFF);
634c56bf5fSPeng Fan }
644c56bf5fSPeng Fan 
654c56bf5fSPeng Fan static void tzc_write_region_base_low(vaddr_t base, uint32_t region,
664c56bf5fSPeng Fan 				      uint32_t val)
674c56bf5fSPeng Fan {
684c56bf5fSPeng Fan 	write32(val, base + REGION_SETUP_LOW_OFF(region));
694c56bf5fSPeng Fan }
704c56bf5fSPeng Fan 
714c56bf5fSPeng Fan static void tzc_write_region_base_high(vaddr_t base, uint32_t region,
724c56bf5fSPeng Fan 				       uint32_t val)
734c56bf5fSPeng Fan {
744c56bf5fSPeng Fan 	write32(val, base + REGION_SETUP_HIGH_OFF(region));
754c56bf5fSPeng Fan }
764c56bf5fSPeng Fan 
77*343c1571SPeng Fan static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region)
78*343c1571SPeng Fan {
79*343c1571SPeng Fan 	return read32(base + REGION_ATTRIBUTES_OFF(region));
80*343c1571SPeng Fan }
81*343c1571SPeng Fan 
824c56bf5fSPeng Fan static void tzc_write_region_attributes(vaddr_t base, uint32_t region,
834c56bf5fSPeng Fan 					uint32_t val)
844c56bf5fSPeng Fan {
854c56bf5fSPeng Fan 	write32(val, base + REGION_ATTRIBUTES_OFF(region));
864c56bf5fSPeng Fan }
874c56bf5fSPeng Fan 
884c56bf5fSPeng Fan void tzc_init(vaddr_t base)
894c56bf5fSPeng Fan {
904c56bf5fSPeng Fan 	uint32_t tzc_build;
914c56bf5fSPeng Fan 
924c56bf5fSPeng Fan 	assert(base);
934c56bf5fSPeng Fan 	tzc.base = base;
944c56bf5fSPeng Fan 
954c56bf5fSPeng Fan 	/* Save values we will use later. */
964c56bf5fSPeng Fan 	tzc_build = tzc_read_build_config(tzc.base);
974c56bf5fSPeng Fan 	tzc.addr_width  = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) &
984c56bf5fSPeng Fan 			   BUILD_CONFIG_AW_MASK) + 1;
994c56bf5fSPeng Fan 	tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) &
1004c56bf5fSPeng Fan 			   BUILD_CONFIG_NR_MASK) + 1;
1014c56bf5fSPeng Fan }
1024c56bf5fSPeng Fan 
103*343c1571SPeng Fan /*
104*343c1571SPeng Fan  * There are two modes of operation for the region security
105*343c1571SPeng Fan  * permissions, with or without security inversion.
106*343c1571SPeng Fan  * Check TZC380 "2.2.5 Region security permissions" for
107*343c1571SPeng Fan  * more details.
108*343c1571SPeng Fan  */
109*343c1571SPeng Fan void tzc_security_inversion_en(vaddr_t base)
110*343c1571SPeng Fan {
111*343c1571SPeng Fan 	write32(1, base + SECURITY_INV_EN_OFF);
112*343c1571SPeng Fan }
113*343c1571SPeng Fan 
114*343c1571SPeng Fan /*
115*343c1571SPeng Fan  * Enable a single region. Sometimes we could not use tzc_configure_region
116*343c1571SPeng Fan  * to enable the region, when security inversion is on.
117*343c1571SPeng Fan  * When need security inversion, we need to first configure
118*343c1571SPeng Fan  * region address and attribute, then configure security inversion,
119*343c1571SPeng Fan  * then enable the regions.
120*343c1571SPeng Fan  */
121*343c1571SPeng Fan void tzc_region_enable(uint8_t region)
122*343c1571SPeng Fan {
123*343c1571SPeng Fan 	uint32_t val;
124*343c1571SPeng Fan 
125*343c1571SPeng Fan 	val = tzc_read_region_attributes(tzc.base, region);
126*343c1571SPeng Fan 	val |= TZC_ATTR_REGION_EN_MASK;
127*343c1571SPeng Fan 	tzc_write_region_attributes(tzc.base, region, val);
128*343c1571SPeng Fan }
129*343c1571SPeng Fan 
130*343c1571SPeng Fan /*
131*343c1571SPeng Fan  * Dump info when TZC380 catchs an unallowed access with TZC
132*343c1571SPeng Fan  * interrupt enabled.
133*343c1571SPeng Fan  */
134*343c1571SPeng Fan void tzc_fail_dump(void)
135*343c1571SPeng Fan {
136*343c1571SPeng Fan 	vaddr_t base __maybe_unused = core_mmu_get_va(tzc.base,
137*343c1571SPeng Fan 						      MEM_AREA_IO_SEC);
138*343c1571SPeng Fan 
139*343c1571SPeng Fan 	EMSG("Fail address Low 0x%" PRIx32,
140*343c1571SPeng Fan 	     read32(base + FAIL_ADDRESS_LOW_OFF));
141*343c1571SPeng Fan 	EMSG("Fail address High 0x%" PRIx32,
142*343c1571SPeng Fan 	     read32(base + FAIL_ADDRESS_HIGH_OFF));
143*343c1571SPeng Fan 	EMSG("Fail Control 0x%" PRIx32, read32(base + FAIL_CONTROL_OFF));
144*343c1571SPeng Fan 	EMSG("Fail Id 0x%" PRIx32, read32(base + FAIL_ID));
145*343c1571SPeng Fan }
146*343c1571SPeng Fan 
147*343c1571SPeng Fan void tzc_int_clear(void)
148*343c1571SPeng Fan {
149*343c1571SPeng Fan 	vaddr_t base = core_mmu_get_va(tzc.base, MEM_AREA_IO_SEC);
150*343c1571SPeng Fan 
151*343c1571SPeng Fan 	write32(0, base + INT_CLEAR);
152*343c1571SPeng Fan }
153*343c1571SPeng Fan 
1544c56bf5fSPeng Fan static uint32_t addr_low(vaddr_t addr)
1554c56bf5fSPeng Fan {
1564c56bf5fSPeng Fan 	return (uint32_t)addr;
1574c56bf5fSPeng Fan }
1584c56bf5fSPeng Fan 
1594c56bf5fSPeng Fan static uint32_t addr_high(vaddr_t addr __maybe_unused)
1604c56bf5fSPeng Fan {
1614c56bf5fSPeng Fan #if (UINTPTR_MAX == UINT64_MAX)
1624c56bf5fSPeng Fan 	return addr >> 32;
1634c56bf5fSPeng Fan #else
1644c56bf5fSPeng Fan 	return 0;
1654c56bf5fSPeng Fan #endif
1664c56bf5fSPeng Fan }
1674c56bf5fSPeng Fan 
1684c56bf5fSPeng Fan 
1694c56bf5fSPeng Fan /*
1704c56bf5fSPeng Fan  * `tzc_configure_region` is used to program regions into the TrustZone
1714c56bf5fSPeng Fan  * controller.
1724c56bf5fSPeng Fan  */
1734c56bf5fSPeng Fan void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr)
1744c56bf5fSPeng Fan {
1754c56bf5fSPeng Fan 	assert(tzc.base);
1764c56bf5fSPeng Fan 
1774c56bf5fSPeng Fan 	assert(region < tzc.num_regions);
1784c56bf5fSPeng Fan 
179fe1404daSPeng Fan 	/*
180fe1404daSPeng Fan 	 * For region 0, this high/low/size/en field is Read Only (RO).
181fe1404daSPeng Fan 	 * So should not configure those field for region 0.
182fe1404daSPeng Fan 	 */
183fe1404daSPeng Fan 	if (region) {
184fe1404daSPeng Fan 		tzc_write_region_base_low(tzc.base, region,
185fe1404daSPeng Fan 					  addr_low(region_base));
186fe1404daSPeng Fan 		tzc_write_region_base_high(tzc.base, region,
187fe1404daSPeng Fan 					   addr_high(region_base));
1884c56bf5fSPeng Fan 		tzc_write_region_attributes(tzc.base, region, attr);
189fe1404daSPeng Fan 	} else {
190fe1404daSPeng Fan 		tzc_write_region_attributes(tzc.base, region,
191fe1404daSPeng Fan 					    attr & TZC_ATTR_SP_MASK);
192fe1404daSPeng Fan 	}
1934c56bf5fSPeng Fan }
1944c56bf5fSPeng Fan 
1954c56bf5fSPeng Fan void tzc_set_action(enum tzc_action action)
1964c56bf5fSPeng Fan {
1974c56bf5fSPeng Fan 	assert(tzc.base);
1984c56bf5fSPeng Fan 
1994c56bf5fSPeng Fan 	/*
2004c56bf5fSPeng Fan 	 * - Currently no handler is provided to trap an error via interrupt
2014c56bf5fSPeng Fan 	 *   or exception.
2024c56bf5fSPeng Fan 	 * - The interrupt action has not been tested.
2034c56bf5fSPeng Fan 	 */
2044c56bf5fSPeng Fan 	tzc_write_action(tzc.base, action);
2054c56bf5fSPeng Fan }
2064c56bf5fSPeng Fan 
2074c56bf5fSPeng Fan #if TRACE_LEVEL >= TRACE_DEBUG
2084c56bf5fSPeng Fan 
2094c56bf5fSPeng Fan static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region)
2104c56bf5fSPeng Fan {
2114c56bf5fSPeng Fan 	return read32(base + REGION_SETUP_LOW_OFF(region));
2124c56bf5fSPeng Fan }
2134c56bf5fSPeng Fan 
2144c56bf5fSPeng Fan static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region)
2154c56bf5fSPeng Fan {
2164c56bf5fSPeng Fan 	return read32(base + REGION_SETUP_HIGH_OFF(region));
2174c56bf5fSPeng Fan }
2184c56bf5fSPeng Fan 
2194c56bf5fSPeng Fan #define	REGION_MAX	16
2204c56bf5fSPeng Fan void tzc_dump_state(void)
2214c56bf5fSPeng Fan {
2224c56bf5fSPeng Fan 	uint32_t n;
2234c56bf5fSPeng Fan 	uint32_t temp_32reg, temp_32reg_h;
2244c56bf5fSPeng Fan 
2254c56bf5fSPeng Fan 	DMSG("enter");
2264c56bf5fSPeng Fan 	DMSG("security_inversion_en %x\n",
2274c56bf5fSPeng Fan 	     read32(tzc.base + SECURITY_INV_EN_OFF));
2284c56bf5fSPeng Fan 	for (n = 0; n <= REGION_MAX; n++) {
2294c56bf5fSPeng Fan 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
2304c56bf5fSPeng Fan 		if (!(temp_32reg & TZC_ATTR_REGION_EN_MASK))
2314c56bf5fSPeng Fan 			continue;
2324c56bf5fSPeng Fan 
2334c56bf5fSPeng Fan 		DMSG("\n");
2344c56bf5fSPeng Fan 		DMSG("region %d", n);
2354c56bf5fSPeng Fan 		temp_32reg = tzc_read_region_base_low(tzc.base, n);
2364c56bf5fSPeng Fan 		temp_32reg_h = tzc_read_region_base_high(tzc.base, n);
2374c56bf5fSPeng Fan 		DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg);
2384c56bf5fSPeng Fan 		temp_32reg = tzc_read_region_attributes(tzc.base, n);
2394c56bf5fSPeng Fan 		DMSG("region sp: %x", temp_32reg >> TZC_ATTR_SP_SHIFT);
2404c56bf5fSPeng Fan 		DMSG("region size: %x\n", (temp_32reg & TZC_REGION_SIZE_MASK) >>
2414c56bf5fSPeng Fan 				TZC_REGION_SIZE_SHIFT);
2424c56bf5fSPeng Fan 	}
2434c56bf5fSPeng Fan 	DMSG("exit");
2444c56bf5fSPeng Fan }
2454c56bf5fSPeng Fan 
2464c56bf5fSPeng Fan #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */
247