1 /* 2 * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <debug.h> 9 #include <mmio.h> 10 #include <stddef.h> 11 #include <tzc400.h> 12 #include "tzc_common_private.h" 13 14 /* 15 * Macros which will be used by common core functions. 16 */ 17 #define TZC_400_REGION_BASE_LOW_0_OFFSET 0x100 18 #define TZC_400_REGION_BASE_HIGH_0_OFFSET 0x104 19 #define TZC_400_REGION_TOP_LOW_0_OFFSET 0x108 20 #define TZC_400_REGION_TOP_HIGH_0_OFFSET 0x10c 21 #define TZC_400_REGION_ATTR_0_OFFSET 0x110 22 #define TZC_400_REGION_ID_ACCESS_0_OFFSET 0x114 23 24 /* 25 * Implementation defined values used to validate inputs later. 26 * Filters : max of 4 ; 0 to 3 27 * Regions : max of 9 ; 0 to 8 28 * Address width : Values between 32 to 64 29 */ 30 typedef struct tzc400_instance { 31 uintptr_t base; 32 uint8_t addr_width; 33 uint8_t num_filters; 34 uint8_t num_regions; 35 } tzc400_instance_t; 36 37 tzc400_instance_t tzc400; 38 39 static inline unsigned int _tzc400_read_build_config(uintptr_t base) 40 { 41 return mmio_read_32(base + BUILD_CONFIG_OFF); 42 } 43 44 static inline unsigned int _tzc400_read_gate_keeper(uintptr_t base) 45 { 46 return mmio_read_32(base + GATE_KEEPER_OFF); 47 } 48 49 static inline void _tzc400_write_gate_keeper(uintptr_t base, unsigned int val) 50 { 51 mmio_write_32(base + GATE_KEEPER_OFF, val); 52 } 53 54 /* 55 * Get the open status information for all filter units. 56 */ 57 #define get_gate_keeper_os(base) ((_tzc400_read_gate_keeper(base) >> \ 58 GATE_KEEPER_OS_SHIFT) & \ 59 GATE_KEEPER_OS_MASK) 60 61 62 /* Define common core functions used across different TZC peripherals. */ 63 DEFINE_TZC_COMMON_WRITE_ACTION(400, 400) 64 DEFINE_TZC_COMMON_WRITE_REGION_BASE(400, 400) 65 DEFINE_TZC_COMMON_WRITE_REGION_TOP(400, 400) 66 DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(400, 400) 67 DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400) 68 DEFINE_TZC_COMMON_CONFIGURE_REGION0(400) 69 DEFINE_TZC_COMMON_CONFIGURE_REGION(400) 70 71 static unsigned int _tzc400_get_gate_keeper(uintptr_t base, 72 unsigned int filter) 73 { 74 unsigned int open_status; 75 76 open_status = get_gate_keeper_os(base); 77 78 return (open_status >> filter) & GATE_KEEPER_FILTER_MASK; 79 } 80 81 /* This function is not MP safe. */ 82 static void _tzc400_set_gate_keeper(uintptr_t base, 83 unsigned int filter, 84 int val) 85 { 86 unsigned int open_status; 87 88 /* Upper half is current state. Lower half is requested state. */ 89 open_status = get_gate_keeper_os(base); 90 91 if (val) 92 open_status |= (1 << filter); 93 else 94 open_status &= ~(1 << filter); 95 96 _tzc400_write_gate_keeper(base, (open_status & GATE_KEEPER_OR_MASK) << 97 GATE_KEEPER_OR_SHIFT); 98 99 /* Wait here until we see the change reflected in the TZC status. */ 100 while ((get_gate_keeper_os(base)) != open_status) 101 ; 102 } 103 104 void tzc400_set_action(tzc_action_t action) 105 { 106 assert(tzc400.base); 107 assert(action <= TZC_ACTION_ERR_INT); 108 109 /* 110 * - Currently no handler is provided to trap an error via interrupt 111 * or exception. 112 * - The interrupt action has not been tested. 113 */ 114 _tzc400_write_action(tzc400.base, action); 115 } 116 117 void tzc400_init(uintptr_t base) 118 { 119 #if DEBUG 120 unsigned int tzc400_id; 121 #endif 122 unsigned int tzc400_build; 123 124 assert(base); 125 tzc400.base = base; 126 127 #if DEBUG 128 tzc400_id = _tzc_read_peripheral_id(base); 129 if (tzc400_id != TZC_400_PERIPHERAL_ID) { 130 ERROR("TZC-400 : Wrong device ID (0x%x).\n", tzc400_id); 131 panic(); 132 } 133 #endif 134 135 /* Save values we will use later. */ 136 tzc400_build = _tzc400_read_build_config(tzc400.base); 137 tzc400.num_filters = ((tzc400_build >> BUILD_CONFIG_NF_SHIFT) & 138 BUILD_CONFIG_NF_MASK) + 1; 139 tzc400.addr_width = ((tzc400_build >> BUILD_CONFIG_AW_SHIFT) & 140 BUILD_CONFIG_AW_MASK) + 1; 141 tzc400.num_regions = ((tzc400_build >> BUILD_CONFIG_NR_SHIFT) & 142 BUILD_CONFIG_NR_MASK) + 1; 143 } 144 145 /* 146 * `tzc400_configure_region0` is used to program region 0 into the TrustZone 147 * controller. Region 0 covers the whole address space that is not mapped 148 * to any other region, and is enabled on all filters; this cannot be 149 * changed. This function only changes the access permissions. 150 */ 151 void tzc400_configure_region0(tzc_region_attributes_t sec_attr, 152 unsigned int ns_device_access) 153 { 154 assert(tzc400.base); 155 assert(sec_attr <= TZC_REGION_S_RDWR); 156 157 _tzc400_configure_region0(tzc400.base, sec_attr, ns_device_access); 158 } 159 160 /* 161 * `tzc400_configure_region` is used to program regions into the TrustZone 162 * controller. A region can be associated with more than one filter. The 163 * associated filters are passed in as a bitmap (bit0 = filter0). 164 * NOTE: 165 * Region 0 is special; it is preferable to use tzc400_configure_region0 166 * for this region (see comment for that function). 167 */ 168 void tzc400_configure_region(unsigned int filters, 169 int region, 170 unsigned long long region_base, 171 unsigned long long region_top, 172 tzc_region_attributes_t sec_attr, 173 unsigned int nsaid_permissions) 174 { 175 assert(tzc400.base); 176 177 /* Do range checks on filters and regions. */ 178 assert(((filters >> tzc400.num_filters) == 0) && 179 (region >= 0) && (region < tzc400.num_regions)); 180 181 /* 182 * Do address range check based on TZC configuration. A 64bit address is 183 * the max and expected case. 184 */ 185 assert(((region_top <= _tzc_get_max_top_addr(tzc400.addr_width)) && 186 (region_base < region_top))); 187 188 /* region_base and (region_top + 1) must be 4KB aligned */ 189 assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0); 190 191 assert(sec_attr <= TZC_REGION_S_RDWR); 192 193 _tzc400_configure_region(tzc400.base, filters, region, region_base, 194 region_top, 195 sec_attr, nsaid_permissions); 196 } 197 198 void tzc400_enable_filters(void) 199 { 200 unsigned int state; 201 unsigned int filter; 202 203 assert(tzc400.base); 204 205 for (filter = 0; filter < tzc400.num_filters; filter++) { 206 state = _tzc400_get_gate_keeper(tzc400.base, filter); 207 if (state) { 208 /* The TZC filter is already configured. Changing the 209 * programmer's view in an active system can cause 210 * unpredictable behavior therefore panic for now rather 211 * than try to determine whether this is safe in this 212 * instance. See: 213 * http://infocenter.arm.com/help/index.jsp?\ 214 * topic=/com.arm.doc.ddi0504c/CJHHECBF.html */ 215 ERROR("TZC-400 : Filter %d Gatekeeper already" 216 " enabled.\n", filter); 217 panic(); 218 } 219 _tzc400_set_gate_keeper(tzc400.base, filter, 1); 220 } 221 } 222 223 void tzc400_disable_filters(void) 224 { 225 unsigned int filter; 226 227 assert(tzc400.base); 228 229 /* 230 * We don't do the same state check as above as the Gatekeepers are 231 * disabled after reset. 232 */ 233 for (filter = 0; filter < tzc400.num_filters; filter++) 234 _tzc400_set_gate_keeper(tzc400.base, filter, 0); 235 } 236