1 /* 2 * Copyright 2017 NXP 3 * All rights reserved. 4 * 5 * Peng Fan <peng.fan@nxp.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <assert.h> 31 #include <drivers/tzc380.h> 32 #include <io.h> 33 #include <kernel/panic.h> 34 #include <stddef.h> 35 #include <trace.h> 36 #include <util.h> 37 38 /* 39 * Implementation defined values used to validate inputs later. 40 * Filters : max of 4 ; 0 to 3 41 * Regions : max of 9 ; 0 to 8 42 * Address width : Values between 32 to 64 43 */ 44 struct tzc_instance { 45 vaddr_t base; 46 uint8_t addr_width; 47 uint8_t num_regions; 48 }; 49 50 static struct tzc_instance tzc; 51 52 static uint32_t tzc_read_build_config(vaddr_t base) 53 { 54 return read32(base + BUILD_CONFIG_OFF); 55 } 56 57 static void tzc_write_action(vaddr_t base, enum tzc_action action) 58 { 59 write32(action, base + ACTION_OFF); 60 } 61 62 static void tzc_write_region_base_low(vaddr_t base, uint32_t region, 63 uint32_t val) 64 { 65 write32(val, base + REGION_SETUP_LOW_OFF(region)); 66 } 67 68 static void tzc_write_region_base_high(vaddr_t base, uint32_t region, 69 uint32_t val) 70 { 71 write32(val, base + REGION_SETUP_HIGH_OFF(region)); 72 } 73 74 static void tzc_write_region_attributes(vaddr_t base, uint32_t region, 75 uint32_t val) 76 { 77 write32(val, base + REGION_ATTRIBUTES_OFF(region)); 78 } 79 80 void tzc_init(vaddr_t base) 81 { 82 uint32_t tzc_build; 83 84 assert(base); 85 tzc.base = base; 86 87 /* Save values we will use later. */ 88 tzc_build = tzc_read_build_config(tzc.base); 89 tzc.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) & 90 BUILD_CONFIG_AW_MASK) + 1; 91 tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) & 92 BUILD_CONFIG_NR_MASK) + 1; 93 } 94 95 static uint32_t addr_low(vaddr_t addr) 96 { 97 return (uint32_t)addr; 98 } 99 100 static uint32_t addr_high(vaddr_t addr __maybe_unused) 101 { 102 #if (UINTPTR_MAX == UINT64_MAX) 103 return addr >> 32; 104 #else 105 return 0; 106 #endif 107 } 108 109 110 /* 111 * `tzc_configure_region` is used to program regions into the TrustZone 112 * controller. 113 */ 114 void tzc_configure_region(uint8_t region, vaddr_t region_base, uint32_t attr) 115 { 116 assert(tzc.base); 117 118 assert(region < tzc.num_regions); 119 120 tzc_write_region_base_low(tzc.base, region, addr_low(region_base)); 121 tzc_write_region_base_high(tzc.base, region, addr_high(region_base)); 122 tzc_write_region_attributes(tzc.base, region, attr); 123 } 124 125 void tzc_set_action(enum tzc_action action) 126 { 127 assert(tzc.base); 128 129 /* 130 * - Currently no handler is provided to trap an error via interrupt 131 * or exception. 132 * - The interrupt action has not been tested. 133 */ 134 tzc_write_action(tzc.base, action); 135 } 136 137 #if TRACE_LEVEL >= TRACE_DEBUG 138 139 static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region) 140 { 141 return read32(base + REGION_ATTRIBUTES_OFF(region)); 142 } 143 144 static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region) 145 { 146 return read32(base + REGION_SETUP_LOW_OFF(region)); 147 } 148 149 static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region) 150 { 151 return read32(base + REGION_SETUP_HIGH_OFF(region)); 152 } 153 154 #define REGION_MAX 16 155 void tzc_dump_state(void) 156 { 157 uint32_t n; 158 uint32_t temp_32reg, temp_32reg_h; 159 160 DMSG("enter"); 161 DMSG("security_inversion_en %x\n", 162 read32(tzc.base + SECURITY_INV_EN_OFF)); 163 for (n = 0; n <= REGION_MAX; n++) { 164 temp_32reg = tzc_read_region_attributes(tzc.base, n); 165 if (!(temp_32reg & TZC_ATTR_REGION_EN_MASK)) 166 continue; 167 168 DMSG("\n"); 169 DMSG("region %d", n); 170 temp_32reg = tzc_read_region_base_low(tzc.base, n); 171 temp_32reg_h = tzc_read_region_base_high(tzc.base, n); 172 DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg); 173 temp_32reg = tzc_read_region_attributes(tzc.base, n); 174 DMSG("region sp: %x", temp_32reg >> TZC_ATTR_SP_SHIFT); 175 DMSG("region size: %x\n", (temp_32reg & TZC_REGION_SIZE_MASK) >> 176 TZC_REGION_SIZE_SHIFT); 177 } 178 DMSG("exit"); 179 } 180 181 #endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */ 182