github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/tzasc/tzasc.go (about) 1 // TrustZone Address Space Controller (TZASC) driver 2 // https://github.com/f-secure-foundry/tamago 3 // 4 // IP: ARM CoreLinkā¢ TrustZone Address Space Controller TZC-380 5 // 6 // Copyright (c) F-Secure Corporation 7 // https://foundry.f-secure.com 8 // 9 // Use of this source code is governed by the license 10 // that can be found in the LICENSE file. 11 12 // Package tzasc implements a driver for the TrustZone Address Space Controller 13 // (TZASC) included in NXP i.MX6ULL/i.MX6ULZ SoCs. 14 // 15 // Note that the TZASC must be initialized early in the boot process, see 16 // TZASC_BYPASS for information. 17 // 18 // The driver is based on the following reference specifications: 19 // * TZC-380 TRM - CoreLinkā¢ TrustZone Address Space Controller TZC-380 - Revision: r0p1 20 // 21 // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as 22 // supported by the TamaGo framework for bare metal Go on ARM SoCs, see 23 // https://github.com/f-secure-foundry/tamago. 24 package tzasc 25 26 import ( 27 "errors" 28 29 "github.com/f-secure-foundry/tamago/bits" 30 "github.com/f-secure-foundry/tamago/internal/reg" 31 ) 32 33 // TZASC imx6 specific registers 34 const ( 35 IOMUXC_GPR_GPR1 = 0x020e4004 36 GPR1_TZASC1_BOOT_LOCK = 23 37 38 // TZASC_BYPASS represents the register that allows to enable the TZASC 39 // monitoring of DDR transactions. 40 // 41 // To use the TZASC the bypass must be disabled early in the boot 42 // process, before DDR use. 43 // 44 // To do so the register can be written in the board DCD file (e.g. 45 // imximage.cfg in usbarmory package): 46 // `DATA 4 0x020e4024 0x00000001` 47 // 48 // This is a one time operation, until the next power-up cycle. 49 TZASC_BYPASS = 0x020e4024 50 51 TZASC_BASE = 0x021d0000 52 ) 53 54 // TZASC registers 55 // (p37, Table 3-1 Register summary, TZC-380 TRM). 56 const ( 57 TZASC_CONF = TZASC_BASE + 0x000 58 CONF_REGIONS = 0 59 60 TZASC_ACTION = TZASC_BASE + 0x004 61 TZASC_LOCKDOWN_RANGE = TZASC_BASE + 0x008 62 TZASC_LOCKDOWN_SELECT = TZASC_BASE + 0x00c 63 TZASC_SEC_INV_EN = TZASC_BASE + 0x034 64 65 TZASC_REGION_SETUP_LOW_0 = TZASC_BASE + 0x100 66 TZASC_REGION_SETUP_HIGH_0 = TZASC_BASE + 0x104 67 68 TZASC_REGION_ATTRS_0 = TZASC_BASE + 0x108 69 REGION_ATTRS_SP = 28 70 REGION_ATTRS_SIZE = 1 71 REGION_ATTRS_EN = 0 72 73 SIZE_MIN = 0b001110 74 SIZE_MAX = 0b111111 75 ) 76 77 // TZASC security permissions, 78 // (p28, Table 2-4, TZC-380 TRM). 79 const ( 80 // Secure Read Access bit 81 SP_SW_RD = 3 82 // Secure Write Access bit 83 SP_SW_WR = 2 84 // NonSecure Read Access bit 85 SP_NW_RD = 1 86 // NonSecure Write Access bit 87 SP_NW_WR = 0 88 ) 89 90 // Regions returns the number of regions that the TZASC provides. 91 func Regions() int { 92 return int(reg.Get(TZASC_CONF, CONF_REGIONS, 0xf)) + 1 93 } 94 95 // EnableSecurityInversion allows configuration of arbitrary security 96 // permissions, disabling automatic enabling of secure access on non-secure 97 // only permissions 98 // (p49, 3.2.12 Security Inversion Enable Register, TZC-380 TRM). 99 func EnableSecurityInversion() { 100 reg.Set(TZASC_SEC_INV_EN, 0) 101 } 102 103 // EnableRegion configures a TZASC region with the argument start address, size 104 // and security permissions, for region 0 only security permissions are 105 // relevant. 106 func EnableRegion(n int, start uint32, size int, sp int) (err error) { 107 var attrs uint32 108 var s uint32 109 110 if n < 0 || n+1 > Regions() { 111 return errors.New("invalid region index") 112 } 113 114 if reg.Read(TZASC_BYPASS) != 1 { 115 return errors.New("TZASC inactive (bypass detected)") 116 } 117 118 if n == 0 { 119 reg.SetN(TZASC_REGION_ATTRS_0, REGION_ATTRS_SP, 0b1111, uint32(sp)) 120 return 121 } 122 123 if start%(1<<15) != 0 { 124 return errors.New("incompatible start address") 125 } 126 127 if start != 0 && (start%uint32(size)) != 0 { 128 return errors.New("start address must be a multiple of its region size") 129 } 130 131 if sp > 0b1111 { 132 return errors.New("invalid security permissions") 133 } 134 135 // size = 2^(s+1) 136 for i := uint32(SIZE_MIN); i <= SIZE_MAX; i++ { 137 if size == (1 << (i + 1)) { 138 s = i 139 break 140 } 141 } 142 143 if s == 0 { 144 return errors.New("incompatible region size") 145 } 146 147 bits.SetN(&attrs, REGION_ATTRS_SP, 0b1111, uint32(sp)) 148 bits.SetN(&attrs, REGION_ATTRS_SIZE, 0b111111, s) 149 bits.Set(&attrs, REGION_ATTRS_EN) 150 151 off := uint32(0x10 * n) 152 153 reg.Write(TZASC_REGION_SETUP_LOW_0+off, start&0xffff8000) 154 reg.Write(TZASC_REGION_SETUP_HIGH_0+off, 0) 155 reg.Write(TZASC_REGION_ATTRS_0+off, attrs) 156 157 return 158 } 159 160 // DisableRegion disables a TZASC region. 161 func DisableRegion(n int) (err error) { 162 if n < 0 || n+1 > Regions() { 163 return errors.New("invalid region index") 164 } 165 166 if reg.Read(TZASC_BYPASS) != 1 { 167 return errors.New("TZASC inactive (bypass detected)") 168 } 169 170 reg.Clear(TZASC_REGION_ATTRS_0+uint32(0x10*n), REGION_ATTRS_EN) 171 172 return 173 } 174 175 // Lock enables TZASC secure boot lock register writing restrictions 176 // (p30, 2.2.8 Preventing writes to registers and using secure_boot_lock, TZC-380 TRM). 177 func Lock() { 178 reg.Write(TZASC_LOCKDOWN_RANGE, 0xffffffff) 179 reg.Write(TZASC_LOCKDOWN_SELECT, 0xffffffff) 180 reg.Set(GPR1_TZASC1_BOOT_LOCK, 23) 181 }