11bb92983SJerome Forissier // SPDX-License-Identifier: (BSD-2-Clause AND BSD-3-Clause) 25d1638f3SJens Wiklander /* 35d1638f3SJens Wiklander * Copyright (c) 2015, Linaro Limited 45d1638f3SJens Wiklander * All rights reserved. 55d1638f3SJens Wiklander * 65d1638f3SJens Wiklander * Redistribution and use in source and binary forms, with or without 75d1638f3SJens Wiklander * modification, are permitted provided that the following conditions are met: 85d1638f3SJens Wiklander * 95d1638f3SJens Wiklander * 1. Redistributions of source code must retain the above copyright notice, 105d1638f3SJens Wiklander * this list of conditions and the following disclaimer. 115d1638f3SJens Wiklander * 125d1638f3SJens Wiklander * 2. Redistributions in binary form must reproduce the above copyright notice, 135d1638f3SJens Wiklander * this list of conditions and the following disclaimer in the documentation 145d1638f3SJens Wiklander * and/or other materials provided with the distribution. 155d1638f3SJens Wiklander * 165d1638f3SJens Wiklander * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 175d1638f3SJens Wiklander * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 185d1638f3SJens Wiklander * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 195d1638f3SJens Wiklander * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 205d1638f3SJens Wiklander * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 215d1638f3SJens Wiklander * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 225d1638f3SJens Wiklander * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 235d1638f3SJens Wiklander * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 245d1638f3SJens Wiklander * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 255d1638f3SJens Wiklander * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 265d1638f3SJens Wiklander * POSSIBILITY OF SUCH DAMAGE. 275d1638f3SJens Wiklander */ 285d1638f3SJens Wiklander /* 295d1638f3SJens Wiklander * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. 305d1638f3SJens Wiklander * 315d1638f3SJens Wiklander * Redistribution and use in source and binary forms, with or without 325d1638f3SJens Wiklander * modification, are permitted provided that the following conditions are met: 335d1638f3SJens Wiklander * 345d1638f3SJens Wiklander * Redistributions of source code must retain the above copyright notice, this 355d1638f3SJens Wiklander * list of conditions and the following disclaimer. 365d1638f3SJens Wiklander * 375d1638f3SJens Wiklander * Redistributions in binary form must reproduce the above copyright notice, 385d1638f3SJens Wiklander * this list of conditions and the following disclaimer in the documentation 395d1638f3SJens Wiklander * and/or other materials provided with the distribution. 405d1638f3SJens Wiklander * 415d1638f3SJens Wiklander * Neither the name of ARM nor the names of its contributors may be used 425d1638f3SJens Wiklander * to endorse or promote products derived from this software without specific 435d1638f3SJens Wiklander * prior written permission. 445d1638f3SJens Wiklander * 455d1638f3SJens Wiklander * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 465d1638f3SJens Wiklander * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 475d1638f3SJens Wiklander * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 485d1638f3SJens Wiklander * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 495d1638f3SJens Wiklander * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 505d1638f3SJens Wiklander * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 515d1638f3SJens Wiklander * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 525d1638f3SJens Wiklander * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 535d1638f3SJens Wiklander * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 545d1638f3SJens Wiklander * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 555d1638f3SJens Wiklander * POSSIBILITY OF SUCH DAMAGE. 565d1638f3SJens Wiklander */ 575d1638f3SJens Wiklander 585d1638f3SJens Wiklander #include <assert.h> 595d1638f3SJens Wiklander #include <drivers/tzc400.h> 605d1638f3SJens Wiklander #include <io.h> 615d1638f3SJens Wiklander #include <kernel/panic.h> 625d1638f3SJens Wiklander #include <stddef.h> 635d1638f3SJens Wiklander #include <trace.h> 645d1638f3SJens Wiklander #include <util.h> 655d1638f3SJens Wiklander 665d1638f3SJens Wiklander /* 675d1638f3SJens Wiklander * Implementation defined values used to validate inputs later. 685d1638f3SJens Wiklander * Filters : max of 4 ; 0 to 3 695d1638f3SJens Wiklander * Regions : max of 9 ; 0 to 8 705d1638f3SJens Wiklander * Address width : Values between 32 to 64 715d1638f3SJens Wiklander */ 725d1638f3SJens Wiklander struct tzc_instance { 735d1638f3SJens Wiklander vaddr_t base; 745d1638f3SJens Wiklander uint8_t addr_width; 755d1638f3SJens Wiklander uint8_t num_filters; 765d1638f3SJens Wiklander uint8_t num_regions; 775d1638f3SJens Wiklander }; 785d1638f3SJens Wiklander 795d1638f3SJens Wiklander static struct tzc_instance tzc; 805d1638f3SJens Wiklander 815d1638f3SJens Wiklander 825d1638f3SJens Wiklander static uint32_t tzc_read_build_config(vaddr_t base) 835d1638f3SJens Wiklander { 84918bb3a5SEtienne Carriere return io_read32(base + BUILD_CONFIG_OFF); 855d1638f3SJens Wiklander } 865d1638f3SJens Wiklander 875d1638f3SJens Wiklander static uint32_t tzc_read_gate_keeper(vaddr_t base) 885d1638f3SJens Wiklander { 89918bb3a5SEtienne Carriere return io_read32(base + GATE_KEEPER_OFF); 905d1638f3SJens Wiklander } 915d1638f3SJens Wiklander 925d1638f3SJens Wiklander static void tzc_write_gate_keeper(vaddr_t base, uint32_t val) 935d1638f3SJens Wiklander { 94918bb3a5SEtienne Carriere io_write32(base + GATE_KEEPER_OFF, val); 955d1638f3SJens Wiklander } 965d1638f3SJens Wiklander 975d1638f3SJens Wiklander static void tzc_write_action(vaddr_t base, enum tzc_action action) 985d1638f3SJens Wiklander { 99918bb3a5SEtienne Carriere io_write32(base + ACTION_OFF, action); 1005d1638f3SJens Wiklander } 1015d1638f3SJens Wiklander 102ce7cb5fdSEtienne Carriere static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region) 103ce7cb5fdSEtienne Carriere { 104ce7cb5fdSEtienne Carriere return io_read32(base + REGION_BASE_LOW_OFF + REGION_NUM_OFF(region)); 105ce7cb5fdSEtienne Carriere } 106ce7cb5fdSEtienne Carriere 1075d1638f3SJens Wiklander static void tzc_write_region_base_low(vaddr_t base, uint32_t region, 1085d1638f3SJens Wiklander uint32_t val) 1095d1638f3SJens Wiklander { 110918bb3a5SEtienne Carriere io_write32(base + REGION_BASE_LOW_OFF + REGION_NUM_OFF(region), val); 1115d1638f3SJens Wiklander } 1125d1638f3SJens Wiklander 113ce7cb5fdSEtienne Carriere static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region) 114ce7cb5fdSEtienne Carriere { 115ce7cb5fdSEtienne Carriere return io_read32(base + REGION_BASE_HIGH_OFF + REGION_NUM_OFF(region)); 116ce7cb5fdSEtienne Carriere } 117ce7cb5fdSEtienne Carriere 1185d1638f3SJens Wiklander static void tzc_write_region_base_high(vaddr_t base, uint32_t region, 1195d1638f3SJens Wiklander uint32_t val) 1205d1638f3SJens Wiklander { 121918bb3a5SEtienne Carriere io_write32(base + REGION_BASE_HIGH_OFF + REGION_NUM_OFF(region), val); 1225d1638f3SJens Wiklander } 1235d1638f3SJens Wiklander 124ce7cb5fdSEtienne Carriere static uint32_t tzc_read_region_top_low(vaddr_t base, uint32_t region) 125ce7cb5fdSEtienne Carriere { 126ce7cb5fdSEtienne Carriere return io_read32(base + REGION_TOP_LOW_OFF + REGION_NUM_OFF(region)); 127ce7cb5fdSEtienne Carriere } 128ce7cb5fdSEtienne Carriere 1295d1638f3SJens Wiklander static void tzc_write_region_top_low(vaddr_t base, uint32_t region, 1305d1638f3SJens Wiklander uint32_t val) 1315d1638f3SJens Wiklander { 132918bb3a5SEtienne Carriere io_write32(base + REGION_TOP_LOW_OFF + REGION_NUM_OFF(region), val); 1335d1638f3SJens Wiklander } 1345d1638f3SJens Wiklander 135ce7cb5fdSEtienne Carriere static uint32_t tzc_read_region_top_high(vaddr_t base, uint32_t region) 136ce7cb5fdSEtienne Carriere { 137ce7cb5fdSEtienne Carriere return io_read32(base + REGION_TOP_HIGH_OFF + REGION_NUM_OFF(region)); 138ce7cb5fdSEtienne Carriere } 139ce7cb5fdSEtienne Carriere 1405d1638f3SJens Wiklander static void tzc_write_region_top_high(vaddr_t base, uint32_t region, 1415d1638f3SJens Wiklander uint32_t val) 1425d1638f3SJens Wiklander { 143918bb3a5SEtienne Carriere io_write32(base + REGION_TOP_HIGH_OFF + REGION_NUM_OFF(region), val); 1445d1638f3SJens Wiklander } 1455d1638f3SJens Wiklander 146ce7cb5fdSEtienne Carriere static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region) 147ce7cb5fdSEtienne Carriere { 148ce7cb5fdSEtienne Carriere return io_read32(base + REGION_ATTRIBUTES_OFF + REGION_NUM_OFF(region)); 149ce7cb5fdSEtienne Carriere } 150ce7cb5fdSEtienne Carriere 1515d1638f3SJens Wiklander static void tzc_write_region_attributes(vaddr_t base, uint32_t region, 1525d1638f3SJens Wiklander uint32_t val) 1535d1638f3SJens Wiklander { 154918bb3a5SEtienne Carriere io_write32(base + REGION_ATTRIBUTES_OFF + REGION_NUM_OFF(region), val); 1555d1638f3SJens Wiklander } 1565d1638f3SJens Wiklander 157ce7cb5fdSEtienne Carriere static uint32_t tzc_read_region_id_access(vaddr_t base, uint32_t region) 158ce7cb5fdSEtienne Carriere { 159ce7cb5fdSEtienne Carriere return io_read32(base + REGION_ID_ACCESS_OFF + REGION_NUM_OFF(region)); 160ce7cb5fdSEtienne Carriere } 161ce7cb5fdSEtienne Carriere 1625d1638f3SJens Wiklander static void tzc_write_region_id_access(vaddr_t base, uint32_t region, 1635d1638f3SJens Wiklander uint32_t val) 1645d1638f3SJens Wiklander { 165918bb3a5SEtienne Carriere io_write32(base + REGION_ID_ACCESS_OFF + REGION_NUM_OFF(region), val); 1665d1638f3SJens Wiklander } 1675d1638f3SJens Wiklander 1685d1638f3SJens Wiklander static uint32_t tzc_read_component_id(vaddr_t base) 1695d1638f3SJens Wiklander { 1705d1638f3SJens Wiklander uint32_t id; 1715d1638f3SJens Wiklander 172918bb3a5SEtienne Carriere id = io_read8(base + CID0_OFF); 173918bb3a5SEtienne Carriere id |= SHIFT_U32(io_read8(base + CID1_OFF), 8); 174918bb3a5SEtienne Carriere id |= SHIFT_U32(io_read8(base + CID2_OFF), 16); 175918bb3a5SEtienne Carriere id |= SHIFT_U32(io_read8(base + CID3_OFF), 24); 1765d1638f3SJens Wiklander 1775d1638f3SJens Wiklander return id; 1785d1638f3SJens Wiklander } 1795d1638f3SJens Wiklander 1805d1638f3SJens Wiklander static uint32_t tzc_get_gate_keeper(vaddr_t base, uint8_t filter) 1815d1638f3SJens Wiklander { 1825d1638f3SJens Wiklander uint32_t tmp; 1835d1638f3SJens Wiklander 1845d1638f3SJens Wiklander tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) & 1855d1638f3SJens Wiklander GATE_KEEPER_OS_MASK; 1865d1638f3SJens Wiklander 1875d1638f3SJens Wiklander return (tmp >> filter) & GATE_KEEPER_FILTER_MASK; 1885d1638f3SJens Wiklander } 1895d1638f3SJens Wiklander 1905d1638f3SJens Wiklander /* This function is not MP safe. */ 1915d1638f3SJens Wiklander static void tzc_set_gate_keeper(vaddr_t base, uint8_t filter, uint32_t val) 1925d1638f3SJens Wiklander { 1935d1638f3SJens Wiklander uint32_t tmp; 1945d1638f3SJens Wiklander 1955d1638f3SJens Wiklander /* Upper half is current state. Lower half is requested state. */ 1965d1638f3SJens Wiklander tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) & 1975d1638f3SJens Wiklander GATE_KEEPER_OS_MASK; 1985d1638f3SJens Wiklander 1995d1638f3SJens Wiklander if (val) 2005d1638f3SJens Wiklander tmp |= (1 << filter); 2015d1638f3SJens Wiklander else 2025d1638f3SJens Wiklander tmp &= ~(1 << filter); 2035d1638f3SJens Wiklander 2045d1638f3SJens Wiklander tzc_write_gate_keeper(base, (tmp & GATE_KEEPER_OR_MASK) << 2055d1638f3SJens Wiklander GATE_KEEPER_OR_SHIFT); 2065d1638f3SJens Wiklander 2075d1638f3SJens Wiklander /* Wait here until we see the change reflected in the TZC status. */ 2085d1638f3SJens Wiklander while (((tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) & 2095d1638f3SJens Wiklander GATE_KEEPER_OS_MASK) != tmp) 2105d1638f3SJens Wiklander ; 2115d1638f3SJens Wiklander } 2125d1638f3SJens Wiklander 2135d1638f3SJens Wiklander 2145d1638f3SJens Wiklander void tzc_init(vaddr_t base) 2155d1638f3SJens Wiklander { 2165d1638f3SJens Wiklander uint32_t tzc_id, tzc_build; 2175d1638f3SJens Wiklander 2185d1638f3SJens Wiklander assert(base); 2195d1638f3SJens Wiklander tzc.base = base; 2205d1638f3SJens Wiklander 2215d1638f3SJens Wiklander /* 2225d1638f3SJens Wiklander * We expect to see a tzc400. Check component ID. The TZC-400 TRM shows 2235d1638f3SJens Wiklander * component ID is expected to be "0xB105F00D". 2245d1638f3SJens Wiklander */ 2255d1638f3SJens Wiklander tzc_id = tzc_read_component_id(tzc.base); 2265d1638f3SJens Wiklander if (tzc_id != TZC400_COMPONENT_ID) { 22765fe41dbSEtienne Carriere EMSG("TZC : Wrong device ID (0x%" PRIx32 ")", tzc_id); 2285d1638f3SJens Wiklander panic(); 2295d1638f3SJens Wiklander } 2305d1638f3SJens Wiklander 2315d1638f3SJens Wiklander /* Save values we will use later. */ 2325d1638f3SJens Wiklander tzc_build = tzc_read_build_config(tzc.base); 2335d1638f3SJens Wiklander tzc.num_filters = ((tzc_build >> BUILD_CONFIG_NF_SHIFT) & 2345d1638f3SJens Wiklander BUILD_CONFIG_NF_MASK) + 1; 2355d1638f3SJens Wiklander tzc.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) & 2365d1638f3SJens Wiklander BUILD_CONFIG_AW_MASK) + 1; 2375d1638f3SJens Wiklander tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) & 2385d1638f3SJens Wiklander BUILD_CONFIG_NR_MASK) + 1; 2395d1638f3SJens Wiklander } 2405d1638f3SJens Wiklander 2415d1638f3SJens Wiklander static uint32_t addr_low(vaddr_t addr) 2425d1638f3SJens Wiklander { 2435d1638f3SJens Wiklander return (uint32_t)addr; 2445d1638f3SJens Wiklander } 2455d1638f3SJens Wiklander 2465d1638f3SJens Wiklander static uint32_t addr_high(vaddr_t addr __unused) 2475d1638f3SJens Wiklander { 2485d1638f3SJens Wiklander #if (UINTPTR_MAX == UINT64_MAX) 2495d1638f3SJens Wiklander return (addr >> 32); 2505d1638f3SJens Wiklander #else 2515d1638f3SJens Wiklander return 0; 2525d1638f3SJens Wiklander #endif 2535d1638f3SJens Wiklander } 2545d1638f3SJens Wiklander 2555d1638f3SJens Wiklander 2565d1638f3SJens Wiklander /* 2575d1638f3SJens Wiklander * `tzc_configure_region` is used to program regions into the TrustZone 2585d1638f3SJens Wiklander * controller. A region can be associated with more than one filter. The 2595d1638f3SJens Wiklander * associated filters are passed in as a bitmap (bit0 = filter0). 2605d1638f3SJens Wiklander * NOTE: 2615d1638f3SJens Wiklander * The region 0 covers the whole address space and is enabled on all filters, 2625d1638f3SJens Wiklander * this cannot be changed. It is, however, possible to change some region 0 2635d1638f3SJens Wiklander * permissions. 2645d1638f3SJens Wiklander */ 2655d1638f3SJens Wiklander void tzc_configure_region(uint32_t filters, 2665d1638f3SJens Wiklander uint8_t region, 2675d1638f3SJens Wiklander vaddr_t region_base, 2685d1638f3SJens Wiklander vaddr_t region_top, 2695d1638f3SJens Wiklander enum tzc_region_attributes sec_attr, 2705d1638f3SJens Wiklander uint32_t ns_device_access) 2715d1638f3SJens Wiklander { 2725d1638f3SJens Wiklander assert(tzc.base); 2735d1638f3SJens Wiklander 2745d1638f3SJens Wiklander /* Do range checks on filters and regions. */ 2755d1638f3SJens Wiklander assert(((filters >> tzc.num_filters) == 0) && 2765d1638f3SJens Wiklander (region < tzc.num_regions)); 2775d1638f3SJens Wiklander 2785d1638f3SJens Wiklander /* 2795d1638f3SJens Wiklander * Do address range check based on TZC configuration. A 64bit address is 2805d1638f3SJens Wiklander * the max and expected case. 2815d1638f3SJens Wiklander */ 2825d1638f3SJens Wiklander #if (UINTPTR_MAX == UINT64_MAX) 2835d1638f3SJens Wiklander assert(((region_top <= (UINT64_MAX >> (64 - tzc.addr_width))) && 2845d1638f3SJens Wiklander (region_base < region_top))); 2855d1638f3SJens Wiklander #endif 2865d1638f3SJens Wiklander /* region_base and (region_top + 1) must be 4KB aligned */ 2875d1638f3SJens Wiklander assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0); 2885d1638f3SJens Wiklander 2895d1638f3SJens Wiklander assert(sec_attr <= TZC_REGION_S_RDWR); 2905d1638f3SJens Wiklander 2915d1638f3SJens Wiklander /* 2925d1638f3SJens Wiklander * Inputs look ok, start programming registers. 2935d1638f3SJens Wiklander * All the address registers are 32 bits wide and have a LOW and HIGH 2945d1638f3SJens Wiklander * component used to construct a up to a 64bit address. 2955d1638f3SJens Wiklander */ 2965d1638f3SJens Wiklander tzc_write_region_base_low(tzc.base, region, 2975d1638f3SJens Wiklander addr_low(region_base)); 2985d1638f3SJens Wiklander tzc_write_region_base_high(tzc.base, region, 2995d1638f3SJens Wiklander addr_high(region_base)); 3005d1638f3SJens Wiklander 3015d1638f3SJens Wiklander tzc_write_region_top_low(tzc.base, region, 3025d1638f3SJens Wiklander addr_low(region_top)); 3035d1638f3SJens Wiklander tzc_write_region_top_high(tzc.base, region, 3045d1638f3SJens Wiklander addr_high(region_top)); 3055d1638f3SJens Wiklander 3065d1638f3SJens Wiklander /* Assign the region to a filter and set secure attributes */ 3075d1638f3SJens Wiklander tzc_write_region_attributes(tzc.base, region, 3085d1638f3SJens Wiklander (sec_attr << REG_ATTR_SEC_SHIFT) | filters); 3095d1638f3SJens Wiklander 3105d1638f3SJens Wiklander /* 3115d1638f3SJens Wiklander * Specify which non-secure devices have permission to access this 3125d1638f3SJens Wiklander * region. 3135d1638f3SJens Wiklander */ 3145d1638f3SJens Wiklander tzc_write_region_id_access(tzc.base, region, ns_device_access); 3155d1638f3SJens Wiklander } 3165d1638f3SJens Wiklander 317ce7cb5fdSEtienne Carriere TEE_Result tzc_get_region_config(uint8_t region, struct tzc_region_config *cfg) 318ce7cb5fdSEtienne Carriere { 319ce7cb5fdSEtienne Carriere uint32_t val32 = 0; 320ce7cb5fdSEtienne Carriere 321ce7cb5fdSEtienne Carriere if (region >= tzc.num_regions) 322ce7cb5fdSEtienne Carriere return TEE_ERROR_GENERIC; 323ce7cb5fdSEtienne Carriere 324ce7cb5fdSEtienne Carriere cfg->base = reg_pair_to_64(tzc_read_region_base_high(tzc.base, region), 325ce7cb5fdSEtienne Carriere tzc_read_region_base_low(tzc.base, region)); 326ce7cb5fdSEtienne Carriere cfg->top = reg_pair_to_64(tzc_read_region_top_high(tzc.base, region), 327ce7cb5fdSEtienne Carriere tzc_read_region_top_low(tzc.base, region)); 328ce7cb5fdSEtienne Carriere 329ce7cb5fdSEtienne Carriere cfg->ns_device_access = tzc_read_region_id_access(tzc.base, region); 330ce7cb5fdSEtienne Carriere 331ce7cb5fdSEtienne Carriere val32 = tzc_read_region_attributes(tzc.base, region); 332ce7cb5fdSEtienne Carriere cfg->sec_attr = val32 >> REG_ATTR_SEC_SHIFT; 333ce7cb5fdSEtienne Carriere cfg->filters = val32 & REG_ATTR_F_EN_MASK; 334ce7cb5fdSEtienne Carriere 335ce7cb5fdSEtienne Carriere return TEE_SUCCESS; 336ce7cb5fdSEtienne Carriere } 3375d1638f3SJens Wiklander 3385d1638f3SJens Wiklander void tzc_set_action(enum tzc_action action) 3395d1638f3SJens Wiklander { 3405d1638f3SJens Wiklander assert(tzc.base); 3415d1638f3SJens Wiklander 3425d1638f3SJens Wiklander /* 3435d1638f3SJens Wiklander * - Currently no handler is provided to trap an error via interrupt 3445d1638f3SJens Wiklander * or exception. 3455d1638f3SJens Wiklander * - The interrupt action has not been tested. 3465d1638f3SJens Wiklander */ 3475d1638f3SJens Wiklander tzc_write_action(tzc.base, action); 3485d1638f3SJens Wiklander } 3495d1638f3SJens Wiklander 3505d1638f3SJens Wiklander 3515d1638f3SJens Wiklander void tzc_enable_filters(void) 3525d1638f3SJens Wiklander { 3535d1638f3SJens Wiklander uint32_t state; 3545d1638f3SJens Wiklander uint32_t filter; 3555d1638f3SJens Wiklander 3565d1638f3SJens Wiklander assert(tzc.base); 3575d1638f3SJens Wiklander 3585d1638f3SJens Wiklander for (filter = 0; filter < tzc.num_filters; filter++) { 3595d1638f3SJens Wiklander state = tzc_get_gate_keeper(tzc.base, filter); 3605d1638f3SJens Wiklander if (state) { 3615d1638f3SJens Wiklander /* 3625d1638f3SJens Wiklander * The TZC filter is already configured. Changing the 3635d1638f3SJens Wiklander * programmer's view in an active system can cause 3645d1638f3SJens Wiklander * unpredictable behavior therefore panic for now rather 3655d1638f3SJens Wiklander * than try to determine whether this is safe in this 3665d1638f3SJens Wiklander * instance. See: 3675d1638f3SJens Wiklander * http://infocenter.arm.com/help/index.jsp?\ 3685d1638f3SJens Wiklander * topic=/com.arm.doc.ddi0504c/CJHHECBF.html 3695d1638f3SJens Wiklander */ 37065fe41dbSEtienne Carriere EMSG("TZC : Filter %d Gatekeeper already enabled", 3715d1638f3SJens Wiklander filter); 3725d1638f3SJens Wiklander panic(); 3735d1638f3SJens Wiklander } 3745d1638f3SJens Wiklander tzc_set_gate_keeper(tzc.base, filter, 1); 3755d1638f3SJens Wiklander } 3765d1638f3SJens Wiklander } 3775d1638f3SJens Wiklander 3785d1638f3SJens Wiklander 3795d1638f3SJens Wiklander void tzc_disable_filters(void) 3805d1638f3SJens Wiklander { 3815d1638f3SJens Wiklander uint32_t filter; 3825d1638f3SJens Wiklander 3835d1638f3SJens Wiklander assert(tzc.base); 3845d1638f3SJens Wiklander 3855d1638f3SJens Wiklander /* 3865d1638f3SJens Wiklander * We don't do the same state check as above as the Gatekeepers are 3875d1638f3SJens Wiklander * disabled after reset. 3885d1638f3SJens Wiklander */ 3895d1638f3SJens Wiklander for (filter = 0; filter < tzc.num_filters; filter++) 3905d1638f3SJens Wiklander tzc_set_gate_keeper(tzc.base, filter, 0); 3915d1638f3SJens Wiklander } 3925d1638f3SJens Wiklander 393*f45362f0SEtienne Carriere static bool __maybe_unused write_not_read(unsigned int filter) 394*f45362f0SEtienne Carriere { 395*f45362f0SEtienne Carriere return io_read32(tzc.base + FAIL_CONTROL(filter)) & 396*f45362f0SEtienne Carriere FAIL_CONTROL_DIRECTION_WRITE; 397*f45362f0SEtienne Carriere } 398*f45362f0SEtienne Carriere 399*f45362f0SEtienne Carriere static bool __maybe_unused nonsecure_not_secure(unsigned int filter) 400*f45362f0SEtienne Carriere { 401*f45362f0SEtienne Carriere return io_read32(tzc.base + FAIL_CONTROL(filter)) & 402*f45362f0SEtienne Carriere FAIL_CONTROL_NONSECURE; 403*f45362f0SEtienne Carriere } 404*f45362f0SEtienne Carriere 405*f45362f0SEtienne Carriere static bool __maybe_unused priv_not_unpriv(unsigned int filter) 406*f45362f0SEtienne Carriere { 407*f45362f0SEtienne Carriere return io_read32(tzc.base + FAIL_CONTROL(filter)) & 408*f45362f0SEtienne Carriere FAIL_CONTROL_PRIVILEGED; 409*f45362f0SEtienne Carriere } 410*f45362f0SEtienne Carriere 411*f45362f0SEtienne Carriere static void dump_fail_filter(unsigned int filter) 412*f45362f0SEtienne Carriere { 413*f45362f0SEtienne Carriere uint64_t __maybe_unused addr = 0; 414*f45362f0SEtienne Carriere uint32_t status = io_read32(tzc.base + INT_STATUS); 415*f45362f0SEtienne Carriere 416*f45362f0SEtienne Carriere if (!(status & BIT(filter + INT_STATUS_OVERLAP_SHIFT)) && 417*f45362f0SEtienne Carriere !(status & BIT(filter + INT_STATUS_OVERRUN_SHIFT)) && 418*f45362f0SEtienne Carriere !(status & BIT(filter + INT_STATUS_STATUS_SHIFT))) 419*f45362f0SEtienne Carriere return; 420*f45362f0SEtienne Carriere 421*f45362f0SEtienne Carriere if (status & BIT(filter + INT_STATUS_OVERLAP_SHIFT)) 422*f45362f0SEtienne Carriere EMSG("Overlap violation on filter %u", filter); 423*f45362f0SEtienne Carriere 424*f45362f0SEtienne Carriere if (status & BIT(filter + INT_STATUS_OVERRUN_SHIFT)) 425*f45362f0SEtienne Carriere EMSG("Overrun violation on filter %u", filter); 426*f45362f0SEtienne Carriere 427*f45362f0SEtienne Carriere if (status & BIT(filter + INT_STATUS_STATUS_SHIFT)) 428*f45362f0SEtienne Carriere EMSG("Permission violation on filter %u", filter); 429*f45362f0SEtienne Carriere 430*f45362f0SEtienne Carriere addr = reg_pair_to_64(io_read32(tzc.base + FAIL_ADDRESS_HIGH(filter)), 431*f45362f0SEtienne Carriere io_read32(tzc.base + FAIL_ADDRESS_LOW(filter))); 432*f45362f0SEtienne Carriere 433*f45362f0SEtienne Carriere EMSG("Violation @0x%"PRIx64", %ssecure %sprivileged %s, AXI ID %"PRIx32, 434*f45362f0SEtienne Carriere addr, 435*f45362f0SEtienne Carriere nonsecure_not_secure(filter) ? "non-" : "", 436*f45362f0SEtienne Carriere priv_not_unpriv(filter) ? "" : "un", 437*f45362f0SEtienne Carriere write_not_read(filter) ? "write" : "read", 438*f45362f0SEtienne Carriere io_read32(tzc.base + FAIL_ID(filter))); 439*f45362f0SEtienne Carriere } 440*f45362f0SEtienne Carriere 441*f45362f0SEtienne Carriere /* 442*f45362f0SEtienne Carriere * Dump info when TZC400 catches an unallowed access with TZC 443*f45362f0SEtienne Carriere * interrupt enabled. 444*f45362f0SEtienne Carriere */ 445*f45362f0SEtienne Carriere void tzc_fail_dump(void) 446*f45362f0SEtienne Carriere { 447*f45362f0SEtienne Carriere unsigned int filter = 0; 448*f45362f0SEtienne Carriere 449*f45362f0SEtienne Carriere for (filter = 0; filter < tzc.num_filters; filter++) 450*f45362f0SEtienne Carriere dump_fail_filter(filter); 451*f45362f0SEtienne Carriere } 452*f45362f0SEtienne Carriere 453*f45362f0SEtienne Carriere void tzc_int_clear(void) 454*f45362f0SEtienne Carriere { 455*f45362f0SEtienne Carriere assert(tzc.base); 456*f45362f0SEtienne Carriere 457*f45362f0SEtienne Carriere io_setbits32(tzc.base + INT_CLEAR, GENMASK_32(tzc.num_filters - 1, 0)); 458*f45362f0SEtienne Carriere } 459*f45362f0SEtienne Carriere 4605d1638f3SJens Wiklander #if TRACE_LEVEL >= TRACE_DEBUG 4615d1638f3SJens Wiklander 4625d1638f3SJens Wiklander #define REGION_MAX 8 4635d1638f3SJens Wiklander static const __maybe_unused char * const tzc_attr_msg[] = { 4645d1638f3SJens Wiklander "TZC_REGION_S_NONE", 4655d1638f3SJens Wiklander "TZC_REGION_S_RD", 4665d1638f3SJens Wiklander "TZC_REGION_S_WR", 4675d1638f3SJens Wiklander "TZC_REGION_S_RDWR" 4685d1638f3SJens Wiklander }; 4695d1638f3SJens Wiklander 4705d1638f3SJens Wiklander void tzc_dump_state(void) 4715d1638f3SJens Wiklander { 4725d1638f3SJens Wiklander uint32_t n; 4735d1638f3SJens Wiklander uint32_t temp_32reg, temp_32reg_h; 47464044ef4SEtienne Carriere unsigned int filter = 0; 4755d1638f3SJens Wiklander 4765d1638f3SJens Wiklander for (n = 0; n <= REGION_MAX; n++) { 4775d1638f3SJens Wiklander temp_32reg = tzc_read_region_attributes(tzc.base, n); 4785d1638f3SJens Wiklander if (!(temp_32reg & REG_ATTR_F_EN_MASK)) 4795d1638f3SJens Wiklander continue; 4805d1638f3SJens Wiklander 4815d1638f3SJens Wiklander DMSG("region %d", n); 4825d1638f3SJens Wiklander temp_32reg = tzc_read_region_base_low(tzc.base, n); 4835d1638f3SJens Wiklander temp_32reg_h = tzc_read_region_base_high(tzc.base, n); 4845d1638f3SJens Wiklander DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg); 4855d1638f3SJens Wiklander temp_32reg = tzc_read_region_top_low(tzc.base, n); 4865d1638f3SJens Wiklander temp_32reg_h = tzc_read_region_top_high(tzc.base, n); 4875d1638f3SJens Wiklander DMSG("region_top: 0x%08x%08x", temp_32reg_h, temp_32reg); 4885d1638f3SJens Wiklander temp_32reg = tzc_read_region_attributes(tzc.base, n); 4895d1638f3SJens Wiklander DMSG("secure rw: %s", 4905d1638f3SJens Wiklander tzc_attr_msg[temp_32reg >> REG_ATTR_SEC_SHIFT]); 49164044ef4SEtienne Carriere 49264044ef4SEtienne Carriere for (filter = 0; filter < tzc.num_filters; filter++) 49364044ef4SEtienne Carriere if (temp_32reg & BIT(filter)) 49464044ef4SEtienne Carriere DMSG("filter %u enable", filter); 4955d1638f3SJens Wiklander } 4965d1638f3SJens Wiklander } 4975d1638f3SJens Wiklander 4985d1638f3SJens Wiklander #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */ 499