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 <stddef.h> 36 #include <trace.h> 37 #include <util.h> 38 39 /* 40 * Implementation defined values used to validate inputs later. 41 * Filters : max of 4 ; 0 to 3 42 * Regions : max of 9 ; 0 to 8 43 * Address width : Values between 32 to 64 44 */ 45 struct tzc_instance { 46 vaddr_t base; 47 uint8_t addr_width; 48 uint8_t num_regions; 49 }; 50 51 static struct tzc_instance tzc; 52 53 static uint32_t tzc_read_build_config(vaddr_t base) 54 { 55 return read32(base + BUILD_CONFIG_OFF); 56 } 57 58 static void tzc_write_action(vaddr_t base, enum tzc_action action) 59 { 60 write32(action, base + ACTION_OFF); 61 } 62 63 static void tzc_write_region_base_low(vaddr_t base, uint32_t region, 64 uint32_t val) 65 { 66 write32(val, base + REGION_SETUP_LOW_OFF(region)); 67 } 68 69 static void tzc_write_region_base_high(vaddr_t base, uint32_t region, 70 uint32_t val) 71 { 72 write32(val, base + REGION_SETUP_HIGH_OFF(region)); 73 } 74 75 static void tzc_write_region_attributes(vaddr_t base, uint32_t region, 76 uint32_t val) 77 { 78 write32(val, base + REGION_ATTRIBUTES_OFF(region)); 79 } 80 81 void tzc_init(vaddr_t base) 82 { 83 uint32_t tzc_build; 84 85 assert(base); 86 tzc.base = base; 87 88 /* Save values we will use later. */ 89 tzc_build = tzc_read_build_config(tzc.base); 90 tzc.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) & 91 BUILD_CONFIG_AW_MASK) + 1; 92 tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) & 93 BUILD_CONFIG_NR_MASK) + 1; 94 } 95 96 static uint32_t addr_low(vaddr_t addr) 97 { 98 return (uint32_t)addr; 99 } 100 101 static uint32_t addr_high(vaddr_t addr __maybe_unused) 102 { 103 #if (UINTPTR_MAX == UINT64_MAX) 104 return addr >> 32; 105 #else 106 return 0; 107 #endif 108 } 109 110 111 /* 112 * `tzc_configure_region` is used to program regions into the TrustZone 113 * controller. 114 */ 115 void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr) 116 { 117 assert(tzc.base); 118 119 assert(region < tzc.num_regions); 120 121 /* 122 * For region 0, this high/low/size/en field is Read Only (RO). 123 * So should not configure those field for region 0. 124 */ 125 if (region) { 126 tzc_write_region_base_low(tzc.base, region, 127 addr_low(region_base)); 128 tzc_write_region_base_high(tzc.base, region, 129 addr_high(region_base)); 130 tzc_write_region_attributes(tzc.base, region, attr); 131 } else { 132 tzc_write_region_attributes(tzc.base, region, 133 attr & TZC_ATTR_SP_MASK); 134 } 135 } 136 137 void tzc_set_action(enum tzc_action action) 138 { 139 assert(tzc.base); 140 141 /* 142 * - Currently no handler is provided to trap an error via interrupt 143 * or exception. 144 * - The interrupt action has not been tested. 145 */ 146 tzc_write_action(tzc.base, action); 147 } 148 149 #if TRACE_LEVEL >= TRACE_DEBUG 150 151 static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region) 152 { 153 return read32(base + REGION_ATTRIBUTES_OFF(region)); 154 } 155 156 static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region) 157 { 158 return read32(base + REGION_SETUP_LOW_OFF(region)); 159 } 160 161 static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region) 162 { 163 return read32(base + REGION_SETUP_HIGH_OFF(region)); 164 } 165 166 #define REGION_MAX 16 167 void tzc_dump_state(void) 168 { 169 uint32_t n; 170 uint32_t temp_32reg, temp_32reg_h; 171 172 DMSG("enter"); 173 DMSG("security_inversion_en %x\n", 174 read32(tzc.base + SECURITY_INV_EN_OFF)); 175 for (n = 0; n <= REGION_MAX; n++) { 176 temp_32reg = tzc_read_region_attributes(tzc.base, n); 177 if (!(temp_32reg & TZC_ATTR_REGION_EN_MASK)) 178 continue; 179 180 DMSG("\n"); 181 DMSG("region %d", n); 182 temp_32reg = tzc_read_region_base_low(tzc.base, n); 183 temp_32reg_h = tzc_read_region_base_high(tzc.base, n); 184 DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg); 185 temp_32reg = tzc_read_region_attributes(tzc.base, n); 186 DMSG("region sp: %x", temp_32reg >> TZC_ATTR_SP_SHIFT); 187 DMSG("region size: %x\n", (temp_32reg & TZC_REGION_SIZE_MASK) >> 188 TZC_REGION_SIZE_SHIFT); 189 } 190 DMSG("exit"); 191 } 192 193 #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */ 194