1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <stddef.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <common/debug.h> 11*91f16700Schasinglulu #include <drivers/arm/tzc400.h> 12*91f16700Schasinglulu #include <lib/mmio.h> 13*91f16700Schasinglulu #include <lib/utils_def.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include "tzc_common_private.h" 16*91f16700Schasinglulu 17*91f16700Schasinglulu /* 18*91f16700Schasinglulu * Macros which will be used by common core functions. 19*91f16700Schasinglulu */ 20*91f16700Schasinglulu #define TZC_400_REGION_BASE_LOW_0_OFFSET U(0x100) 21*91f16700Schasinglulu #define TZC_400_REGION_BASE_HIGH_0_OFFSET U(0x104) 22*91f16700Schasinglulu #define TZC_400_REGION_TOP_LOW_0_OFFSET U(0x108) 23*91f16700Schasinglulu #define TZC_400_REGION_TOP_HIGH_0_OFFSET U(0x10c) 24*91f16700Schasinglulu #define TZC_400_REGION_ATTR_0_OFFSET U(0x110) 25*91f16700Schasinglulu #define TZC_400_REGION_ID_ACCESS_0_OFFSET U(0x114) 26*91f16700Schasinglulu 27*91f16700Schasinglulu /* 28*91f16700Schasinglulu * Implementation defined values used to validate inputs later. 29*91f16700Schasinglulu * Filters : max of 4 ; 0 to 3 30*91f16700Schasinglulu * Regions : max of 9 ; 0 to 8 31*91f16700Schasinglulu * Address width : Values between 32 to 64 32*91f16700Schasinglulu */ 33*91f16700Schasinglulu typedef struct tzc400_instance { 34*91f16700Schasinglulu uintptr_t base; 35*91f16700Schasinglulu uint8_t addr_width; 36*91f16700Schasinglulu uint8_t num_filters; 37*91f16700Schasinglulu uint8_t num_regions; 38*91f16700Schasinglulu } tzc400_instance_t; 39*91f16700Schasinglulu 40*91f16700Schasinglulu static tzc400_instance_t tzc400; 41*91f16700Schasinglulu 42*91f16700Schasinglulu static inline unsigned int _tzc400_read_build_config(uintptr_t base) 43*91f16700Schasinglulu { 44*91f16700Schasinglulu return mmio_read_32(base + BUILD_CONFIG_OFF); 45*91f16700Schasinglulu } 46*91f16700Schasinglulu 47*91f16700Schasinglulu static inline unsigned int _tzc400_read_gate_keeper(uintptr_t base) 48*91f16700Schasinglulu { 49*91f16700Schasinglulu return mmio_read_32(base + GATE_KEEPER_OFF); 50*91f16700Schasinglulu } 51*91f16700Schasinglulu 52*91f16700Schasinglulu static inline void _tzc400_write_gate_keeper(uintptr_t base, unsigned int val) 53*91f16700Schasinglulu { 54*91f16700Schasinglulu mmio_write_32(base + GATE_KEEPER_OFF, val); 55*91f16700Schasinglulu } 56*91f16700Schasinglulu 57*91f16700Schasinglulu /* 58*91f16700Schasinglulu * Get the open status information for all filter units. 59*91f16700Schasinglulu */ 60*91f16700Schasinglulu #define get_gate_keeper_os(_base) ((_tzc400_read_gate_keeper(_base) >> \ 61*91f16700Schasinglulu GATE_KEEPER_OS_SHIFT) & \ 62*91f16700Schasinglulu GATE_KEEPER_OS_MASK) 63*91f16700Schasinglulu 64*91f16700Schasinglulu 65*91f16700Schasinglulu /* Define common core functions used across different TZC peripherals. */ 66*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_ACTION(400, 400) 67*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_REGION_BASE(400, 400) 68*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_REGION_TOP(400, 400) 69*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(400, 400) 70*91f16700Schasinglulu DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400) 71*91f16700Schasinglulu DEFINE_TZC_COMMON_UPDATE_FILTERS(400, 400) 72*91f16700Schasinglulu DEFINE_TZC_COMMON_CONFIGURE_REGION0(400) 73*91f16700Schasinglulu DEFINE_TZC_COMMON_CONFIGURE_REGION(400) 74*91f16700Schasinglulu 75*91f16700Schasinglulu static void _tzc400_clear_it(uintptr_t base, uint32_t filter) 76*91f16700Schasinglulu { 77*91f16700Schasinglulu mmio_write_32(base + INT_CLEAR, BIT_32(filter)); 78*91f16700Schasinglulu } 79*91f16700Schasinglulu 80*91f16700Schasinglulu static uint32_t _tzc400_get_int_by_filter(uintptr_t base, uint32_t filter) 81*91f16700Schasinglulu { 82*91f16700Schasinglulu return mmio_read_32(base + INT_STATUS) & BIT_32(filter); 83*91f16700Schasinglulu } 84*91f16700Schasinglulu 85*91f16700Schasinglulu #if DEBUG 86*91f16700Schasinglulu static unsigned long _tzc400_get_fail_address(uintptr_t base, uint32_t filter) 87*91f16700Schasinglulu { 88*91f16700Schasinglulu unsigned long fail_address; 89*91f16700Schasinglulu 90*91f16700Schasinglulu fail_address = mmio_read_32(base + FAIL_ADDRESS_LOW_OFF + 91*91f16700Schasinglulu (filter * FILTER_OFFSET)); 92*91f16700Schasinglulu #ifdef __aarch64__ 93*91f16700Schasinglulu fail_address += (unsigned long)mmio_read_32(base + FAIL_ADDRESS_HIGH_OFF + 94*91f16700Schasinglulu (filter * FILTER_OFFSET)) << 32; 95*91f16700Schasinglulu #endif 96*91f16700Schasinglulu 97*91f16700Schasinglulu return fail_address; 98*91f16700Schasinglulu } 99*91f16700Schasinglulu 100*91f16700Schasinglulu static uint32_t _tzc400_get_fail_id(uintptr_t base, uint32_t filter) 101*91f16700Schasinglulu { 102*91f16700Schasinglulu return mmio_read_32(base + FAIL_ID + (filter * FILTER_OFFSET)); 103*91f16700Schasinglulu } 104*91f16700Schasinglulu 105*91f16700Schasinglulu static uint32_t _tzc400_get_fail_control(uintptr_t base, uint32_t filter) 106*91f16700Schasinglulu { 107*91f16700Schasinglulu return mmio_read_32(base + FAIL_CONTROL_OFF + (filter * FILTER_OFFSET)); 108*91f16700Schasinglulu } 109*91f16700Schasinglulu 110*91f16700Schasinglulu static void _tzc400_dump_fail_filter(uintptr_t base, uint32_t filter) 111*91f16700Schasinglulu { 112*91f16700Schasinglulu uint32_t control_fail; 113*91f16700Schasinglulu uint32_t fail_id; 114*91f16700Schasinglulu unsigned long address_fail; 115*91f16700Schasinglulu 116*91f16700Schasinglulu address_fail = _tzc400_get_fail_address(base, filter); 117*91f16700Schasinglulu ERROR("Illegal access to 0x%lx:\n", address_fail); 118*91f16700Schasinglulu 119*91f16700Schasinglulu fail_id = _tzc400_get_fail_id(base, filter); 120*91f16700Schasinglulu ERROR("\tFAIL_ID = 0x%x\n", fail_id); 121*91f16700Schasinglulu 122*91f16700Schasinglulu control_fail = _tzc400_get_fail_control(base, filter); 123*91f16700Schasinglulu if (((control_fail & BIT_32(FAIL_CONTROL_NS_SHIFT)) >> FAIL_CONTROL_NS_SHIFT) == 124*91f16700Schasinglulu FAIL_CONTROL_NS_NONSECURE) { 125*91f16700Schasinglulu ERROR("\tNon-Secure\n"); 126*91f16700Schasinglulu } else { 127*91f16700Schasinglulu ERROR("\tSecure\n"); 128*91f16700Schasinglulu } 129*91f16700Schasinglulu 130*91f16700Schasinglulu if (((control_fail & BIT_32(FAIL_CONTROL_PRIV_SHIFT)) >> FAIL_CONTROL_PRIV_SHIFT) == 131*91f16700Schasinglulu FAIL_CONTROL_PRIV_PRIV) { 132*91f16700Schasinglulu ERROR("\tPrivilege\n"); 133*91f16700Schasinglulu } else { 134*91f16700Schasinglulu ERROR("\tUnprivilege\n"); 135*91f16700Schasinglulu } 136*91f16700Schasinglulu 137*91f16700Schasinglulu if (((control_fail & BIT_32(FAIL_CONTROL_DIR_SHIFT)) >> FAIL_CONTROL_DIR_SHIFT) == 138*91f16700Schasinglulu FAIL_CONTROL_DIR_WRITE) { 139*91f16700Schasinglulu ERROR("\tWrite\n"); 140*91f16700Schasinglulu } else { 141*91f16700Schasinglulu ERROR("\tRead\n"); 142*91f16700Schasinglulu } 143*91f16700Schasinglulu } 144*91f16700Schasinglulu #endif /* DEBUG */ 145*91f16700Schasinglulu 146*91f16700Schasinglulu static unsigned int _tzc400_get_gate_keeper(uintptr_t base, 147*91f16700Schasinglulu unsigned int filter) 148*91f16700Schasinglulu { 149*91f16700Schasinglulu unsigned int open_status; 150*91f16700Schasinglulu 151*91f16700Schasinglulu open_status = get_gate_keeper_os(base); 152*91f16700Schasinglulu 153*91f16700Schasinglulu return (open_status >> filter) & GATE_KEEPER_FILTER_MASK; 154*91f16700Schasinglulu } 155*91f16700Schasinglulu 156*91f16700Schasinglulu /* This function is not MP safe. */ 157*91f16700Schasinglulu static void _tzc400_set_gate_keeper(uintptr_t base, 158*91f16700Schasinglulu unsigned int filter, 159*91f16700Schasinglulu int val) 160*91f16700Schasinglulu { 161*91f16700Schasinglulu unsigned int open_status; 162*91f16700Schasinglulu 163*91f16700Schasinglulu /* Upper half is current state. Lower half is requested state. */ 164*91f16700Schasinglulu open_status = get_gate_keeper_os(base); 165*91f16700Schasinglulu 166*91f16700Schasinglulu if (val != 0) 167*91f16700Schasinglulu open_status |= (1UL << filter); 168*91f16700Schasinglulu else 169*91f16700Schasinglulu open_status &= ~(1UL << filter); 170*91f16700Schasinglulu 171*91f16700Schasinglulu _tzc400_write_gate_keeper(base, (open_status & GATE_KEEPER_OR_MASK) << 172*91f16700Schasinglulu GATE_KEEPER_OR_SHIFT); 173*91f16700Schasinglulu 174*91f16700Schasinglulu /* Wait here until we see the change reflected in the TZC status. */ 175*91f16700Schasinglulu while ((get_gate_keeper_os(base)) != open_status) 176*91f16700Schasinglulu ; 177*91f16700Schasinglulu } 178*91f16700Schasinglulu 179*91f16700Schasinglulu void tzc400_set_action(unsigned int action) 180*91f16700Schasinglulu { 181*91f16700Schasinglulu assert(tzc400.base != 0U); 182*91f16700Schasinglulu assert(action <= TZC_ACTION_ERR_INT); 183*91f16700Schasinglulu 184*91f16700Schasinglulu _tzc400_write_action(tzc400.base, action); 185*91f16700Schasinglulu } 186*91f16700Schasinglulu 187*91f16700Schasinglulu void tzc400_init(uintptr_t base) 188*91f16700Schasinglulu { 189*91f16700Schasinglulu #if DEBUG 190*91f16700Schasinglulu unsigned int tzc400_id; 191*91f16700Schasinglulu #endif 192*91f16700Schasinglulu unsigned int tzc400_build; 193*91f16700Schasinglulu 194*91f16700Schasinglulu assert(base != 0U); 195*91f16700Schasinglulu tzc400.base = base; 196*91f16700Schasinglulu 197*91f16700Schasinglulu #if DEBUG 198*91f16700Schasinglulu tzc400_id = _tzc_read_peripheral_id(base); 199*91f16700Schasinglulu if (tzc400_id != TZC_400_PERIPHERAL_ID) { 200*91f16700Schasinglulu ERROR("TZC-400 : Wrong device ID (0x%x).\n", tzc400_id); 201*91f16700Schasinglulu panic(); 202*91f16700Schasinglulu } 203*91f16700Schasinglulu #endif 204*91f16700Schasinglulu 205*91f16700Schasinglulu /* Save values we will use later. */ 206*91f16700Schasinglulu tzc400_build = _tzc400_read_build_config(tzc400.base); 207*91f16700Schasinglulu tzc400.num_filters = (uint8_t)((tzc400_build >> BUILD_CONFIG_NF_SHIFT) & 208*91f16700Schasinglulu BUILD_CONFIG_NF_MASK) + 1U; 209*91f16700Schasinglulu tzc400.addr_width = (uint8_t)((tzc400_build >> BUILD_CONFIG_AW_SHIFT) & 210*91f16700Schasinglulu BUILD_CONFIG_AW_MASK) + 1U; 211*91f16700Schasinglulu tzc400.num_regions = (uint8_t)((tzc400_build >> BUILD_CONFIG_NR_SHIFT) & 212*91f16700Schasinglulu BUILD_CONFIG_NR_MASK) + 1U; 213*91f16700Schasinglulu } 214*91f16700Schasinglulu 215*91f16700Schasinglulu /* 216*91f16700Schasinglulu * `tzc400_configure_region0` is used to program region 0 into the TrustZone 217*91f16700Schasinglulu * controller. Region 0 covers the whole address space that is not mapped 218*91f16700Schasinglulu * to any other region, and is enabled on all filters; this cannot be 219*91f16700Schasinglulu * changed. This function only changes the access permissions. 220*91f16700Schasinglulu */ 221*91f16700Schasinglulu void tzc400_configure_region0(unsigned int sec_attr, 222*91f16700Schasinglulu unsigned int ns_device_access) 223*91f16700Schasinglulu { 224*91f16700Schasinglulu assert(tzc400.base != 0U); 225*91f16700Schasinglulu assert(sec_attr <= TZC_REGION_S_RDWR); 226*91f16700Schasinglulu 227*91f16700Schasinglulu _tzc400_configure_region0(tzc400.base, sec_attr, ns_device_access); 228*91f16700Schasinglulu } 229*91f16700Schasinglulu 230*91f16700Schasinglulu /* 231*91f16700Schasinglulu * `tzc400_configure_region` is used to program regions into the TrustZone 232*91f16700Schasinglulu * controller. A region can be associated with more than one filter. The 233*91f16700Schasinglulu * associated filters are passed in as a bitmap (bit0 = filter0), except that 234*91f16700Schasinglulu * the value TZC_400_REGION_ATTR_FILTER_BIT_ALL selects all filters, based on 235*91f16700Schasinglulu * the value of tzc400.num_filters. 236*91f16700Schasinglulu * NOTE: 237*91f16700Schasinglulu * Region 0 is special; it is preferable to use tzc400_configure_region0 238*91f16700Schasinglulu * for this region (see comment for that function). 239*91f16700Schasinglulu */ 240*91f16700Schasinglulu void tzc400_configure_region(unsigned int filters, 241*91f16700Schasinglulu unsigned int region, 242*91f16700Schasinglulu unsigned long long region_base, 243*91f16700Schasinglulu unsigned long long region_top, 244*91f16700Schasinglulu unsigned int sec_attr, 245*91f16700Schasinglulu unsigned int nsaid_permissions) 246*91f16700Schasinglulu { 247*91f16700Schasinglulu assert(tzc400.base != 0U); 248*91f16700Schasinglulu 249*91f16700Schasinglulu /* Adjust filter mask by real filter number */ 250*91f16700Schasinglulu if (filters == TZC_400_REGION_ATTR_FILTER_BIT_ALL) { 251*91f16700Schasinglulu filters = (1U << tzc400.num_filters) - 1U; 252*91f16700Schasinglulu } 253*91f16700Schasinglulu 254*91f16700Schasinglulu /* Do range checks on filters and regions. */ 255*91f16700Schasinglulu assert(((filters >> tzc400.num_filters) == 0U) && 256*91f16700Schasinglulu (region < tzc400.num_regions)); 257*91f16700Schasinglulu 258*91f16700Schasinglulu /* 259*91f16700Schasinglulu * Do address range check based on TZC configuration. A 64bit address is 260*91f16700Schasinglulu * the max and expected case. 261*91f16700Schasinglulu */ 262*91f16700Schasinglulu assert((region_top <= (UINT64_MAX >> (64U - tzc400.addr_width))) && 263*91f16700Schasinglulu (region_base < region_top)); 264*91f16700Schasinglulu 265*91f16700Schasinglulu /* region_base and (region_top + 1) must be 4KB aligned */ 266*91f16700Schasinglulu assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); 267*91f16700Schasinglulu 268*91f16700Schasinglulu assert(sec_attr <= TZC_REGION_S_RDWR); 269*91f16700Schasinglulu 270*91f16700Schasinglulu _tzc400_configure_region(tzc400.base, filters, region, region_base, 271*91f16700Schasinglulu region_top, 272*91f16700Schasinglulu sec_attr, nsaid_permissions); 273*91f16700Schasinglulu } 274*91f16700Schasinglulu 275*91f16700Schasinglulu void tzc400_update_filters(unsigned int region, unsigned int filters) 276*91f16700Schasinglulu { 277*91f16700Schasinglulu /* Do range checks on filters and regions. */ 278*91f16700Schasinglulu assert(((filters >> tzc400.num_filters) == 0U) && 279*91f16700Schasinglulu (region < tzc400.num_regions)); 280*91f16700Schasinglulu 281*91f16700Schasinglulu _tzc400_update_filters(tzc400.base, region, tzc400.num_filters, filters); 282*91f16700Schasinglulu } 283*91f16700Schasinglulu 284*91f16700Schasinglulu void tzc400_enable_filters(void) 285*91f16700Schasinglulu { 286*91f16700Schasinglulu unsigned int state; 287*91f16700Schasinglulu unsigned int filter; 288*91f16700Schasinglulu 289*91f16700Schasinglulu assert(tzc400.base != 0U); 290*91f16700Schasinglulu 291*91f16700Schasinglulu for (filter = 0U; filter < tzc400.num_filters; filter++) { 292*91f16700Schasinglulu state = _tzc400_get_gate_keeper(tzc400.base, filter); 293*91f16700Schasinglulu if (state != 0U) { 294*91f16700Schasinglulu /* Filter 0 is special and cannot be disabled. 295*91f16700Schasinglulu * So here we allow it being already enabled. */ 296*91f16700Schasinglulu if (filter == 0U) { 297*91f16700Schasinglulu continue; 298*91f16700Schasinglulu } 299*91f16700Schasinglulu /* 300*91f16700Schasinglulu * The TZC filter is already configured. Changing the 301*91f16700Schasinglulu * programmer's view in an active system can cause 302*91f16700Schasinglulu * unpredictable behavior therefore panic for now rather 303*91f16700Schasinglulu * than try to determine whether this is safe in this 304*91f16700Schasinglulu * instance. 305*91f16700Schasinglulu * 306*91f16700Schasinglulu * See the 'ARM (R) CoreLink TM TZC-400 TrustZone (R) 307*91f16700Schasinglulu * Address Space Controller' Technical Reference Manual. 308*91f16700Schasinglulu */ 309*91f16700Schasinglulu ERROR("TZC-400 : Filter %u Gatekeeper already enabled.\n", 310*91f16700Schasinglulu filter); 311*91f16700Schasinglulu panic(); 312*91f16700Schasinglulu } 313*91f16700Schasinglulu _tzc400_set_gate_keeper(tzc400.base, filter, 1); 314*91f16700Schasinglulu } 315*91f16700Schasinglulu } 316*91f16700Schasinglulu 317*91f16700Schasinglulu void tzc400_disable_filters(void) 318*91f16700Schasinglulu { 319*91f16700Schasinglulu unsigned int filter; 320*91f16700Schasinglulu unsigned int state; 321*91f16700Schasinglulu unsigned int start = 0U; 322*91f16700Schasinglulu 323*91f16700Schasinglulu assert(tzc400.base != 0U); 324*91f16700Schasinglulu 325*91f16700Schasinglulu /* Filter 0 is special and cannot be disabled. */ 326*91f16700Schasinglulu state = _tzc400_get_gate_keeper(tzc400.base, 0); 327*91f16700Schasinglulu if (state != 0U) { 328*91f16700Schasinglulu start++; 329*91f16700Schasinglulu } 330*91f16700Schasinglulu for (filter = start; filter < tzc400.num_filters; filter++) 331*91f16700Schasinglulu _tzc400_set_gate_keeper(tzc400.base, filter, 0); 332*91f16700Schasinglulu } 333*91f16700Schasinglulu 334*91f16700Schasinglulu int tzc400_it_handler(void) 335*91f16700Schasinglulu { 336*91f16700Schasinglulu uint32_t filter; 337*91f16700Schasinglulu uint32_t filter_it_pending = tzc400.num_filters; 338*91f16700Schasinglulu 339*91f16700Schasinglulu assert(tzc400.base != 0U); 340*91f16700Schasinglulu 341*91f16700Schasinglulu for (filter = 0U; filter < tzc400.num_filters; filter++) { 342*91f16700Schasinglulu if (_tzc400_get_int_by_filter(tzc400.base, filter) != 0U) { 343*91f16700Schasinglulu filter_it_pending = filter; 344*91f16700Schasinglulu break; 345*91f16700Schasinglulu } 346*91f16700Schasinglulu } 347*91f16700Schasinglulu 348*91f16700Schasinglulu if (filter_it_pending == tzc400.num_filters) { 349*91f16700Schasinglulu ERROR("TZC-400: No interrupt pending!\n"); 350*91f16700Schasinglulu return -1; 351*91f16700Schasinglulu } 352*91f16700Schasinglulu 353*91f16700Schasinglulu #if DEBUG 354*91f16700Schasinglulu _tzc400_dump_fail_filter(tzc400.base, filter_it_pending); 355*91f16700Schasinglulu #endif 356*91f16700Schasinglulu 357*91f16700Schasinglulu _tzc400_clear_it(tzc400.base, filter_it_pending); 358*91f16700Schasinglulu 359*91f16700Schasinglulu return 0; 360*91f16700Schasinglulu } 361