github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/arm/tzc380/tzc380.go (about) 1 // ARM TrustZone Address Space Controller TZC-380 driver 2 // https://github.com/usbarmory/tamago 3 // 4 // IP: ARM CoreLinkā¢ TrustZone Address Space Controller TZC-380 5 // 6 // Copyright (c) WithSecure Corporation 7 // https://foundry.withsecure.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 tzc380 implements a driver for the ARM TrustZone Address Space 13 // Controller TZC-380. 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/usbarmory/tamago. 24 package tzc380 25 26 import ( 27 "errors" 28 29 "github.com/usbarmory/tamago/bits" 30 "github.com/usbarmory/tamago/internal/reg" 31 ) 32 33 // TZASC registers 34 // (p37, Table 3-1 Register summary, TZC-380 TRM). 35 const ( 36 TZASC_CONF = 0x000 37 CONF_REGIONS = 0 38 39 TZASC_LOCKDOWN_RANGE = 0x008 40 TZASC_LOCKDOWN_SELECT = 0x00c 41 TZASC_SEC_INV_EN = 0x034 42 43 TZASC_REGION_SETUP_LOW_0 = 0x100 44 TZASC_REGION_SETUP_HIGH_0 = 0x104 45 46 TZASC_REGION_ATTRS_0 = 0x108 47 REGION_ATTRS_SP = 28 48 REGION_ATTRS_SIZE = 1 49 REGION_ATTRS_EN = 0 50 51 SIZE_MIN = 0b001110 52 SIZE_MAX = 0b111111 53 ) 54 55 // TZASC security permissions, 56 // (p28, Table 2-4, TZC-380 TRM). 57 const ( 58 // Secure Read Access bit 59 SP_SW_RD = 3 60 // Secure Write Access bit 61 SP_SW_WR = 2 62 // NonSecure Read Access bit 63 SP_NW_RD = 1 64 // NonSecure Write Access bit 65 SP_NW_WR = 0 66 ) 67 68 // TZASC represents the TrustZone Address Space Controller instance. 69 type TZASC struct { 70 // Base register 71 Base uint32 72 73 // The bypass register controls the TZASC monitoring of DDR 74 // transactions. 75 // 76 // To use the TZASC, the bypass must be disabled early in the boot 77 // process, before DDR use. This is a one time operation, until the 78 // next power-up cycle. 79 // 80 // To do so the register can be written in the board DCD file (e.g. 81 // imximage.cfg in usbarmory package): 82 // `DATA 4 0x020e4024 0x00000001` 83 // 84 // The register must be specified in the TZASC instance for 85 // verification purposes. 86 Bypass uint32 87 88 // Secure Boot Lock signal (see 2.2.8 TZC-380 TRM) 89 SecureBootLockReg uint32 90 SecureBootLockPos int 91 92 // control registers 93 conf uint32 94 lockdown_range uint32 95 lockdown_select uint32 96 sec_inv_en uint32 97 region_setup_low_0 uint32 98 region_setup_high_0 uint32 99 region_attrs_0 uint32 100 } 101 102 // Init initializes the TrustZone Address Space Controller (TZASC). 103 func (hw *TZASC) Init() { 104 if hw.Base == 0 || hw.Bypass == 0 || hw.SecureBootLockReg == 0 { 105 panic("invalid TZASC instance") 106 } 107 108 hw.conf = hw.Base + TZASC_CONF 109 hw.lockdown_range = hw.Base + TZASC_LOCKDOWN_RANGE 110 hw.lockdown_select = hw.Base + TZASC_LOCKDOWN_SELECT 111 hw.sec_inv_en = hw.Base + TZASC_SEC_INV_EN 112 hw.region_setup_low_0 = hw.Base + TZASC_REGION_SETUP_LOW_0 113 hw.region_setup_high_0 = hw.Base + TZASC_REGION_SETUP_HIGH_0 114 hw.region_attrs_0 = hw.Base + TZASC_REGION_ATTRS_0 115 } 116 117 // Regions returns the number of regions that the TZASC provides. 118 func (hw *TZASC) Regions() int { 119 return int(reg.Get(hw.conf, CONF_REGIONS, 0xf)) + 1 120 } 121 122 // EnableSecurityInversion allows configuration of arbitrary security 123 // permissions, disabling automatic enabling of secure access on non-secure 124 // only permissions 125 // (p49, 3.2.12 Security Inversion Enable Register, TZC-380 TRM). 126 func (hw *TZASC) EnableSecurityInversion() { 127 reg.Set(hw.sec_inv_en, 0) 128 } 129 130 // EnableRegion configures a TZASC region with the argument start address, size 131 // and security permissions, for region 0 only security permissions are 132 // relevant. 133 func (hw *TZASC) EnableRegion(n int, start uint32, size uint32, sp int) (err error) { 134 var attrs uint32 135 var s uint32 136 137 if n < 0 || n+1 > hw.Regions() { 138 return errors.New("invalid region index") 139 } 140 141 if reg.Read(hw.Bypass) != 1 { 142 return errors.New("TZASC inactive (bypass detected)") 143 } 144 145 if n == 0 { 146 reg.SetN(hw.region_attrs_0, REGION_ATTRS_SP, 0b1111, uint32(sp)) 147 return 148 } 149 150 if start%(1<<15) != 0 { 151 return errors.New("incompatible start address") 152 } 153 154 if start != 0 && (start%size) != 0 { 155 return errors.New("start address must be a multiple of its region size") 156 } 157 158 if sp > 0b1111 { 159 return errors.New("invalid security permissions") 160 } 161 162 // size = 2^(s+1) 163 for i := uint32(SIZE_MIN); i <= SIZE_MAX; i++ { 164 if size == (1 << (i + 1)) { 165 s = i 166 break 167 } 168 } 169 170 if s == 0 { 171 return errors.New("incompatible region size") 172 } 173 174 bits.SetN(&attrs, REGION_ATTRS_SP, 0b1111, uint32(sp)) 175 bits.SetN(&attrs, REGION_ATTRS_SIZE, 0b111111, s) 176 bits.Set(&attrs, REGION_ATTRS_EN) 177 178 off := uint32(0x10 * n) 179 180 reg.Write(hw.region_setup_low_0+off, start&0xffff8000) 181 reg.Write(hw.region_setup_high_0+off, 0) 182 reg.Write(hw.region_attrs_0+off, attrs) 183 184 return 185 } 186 187 // DisableRegion disables a TZASC region. 188 func (hw *TZASC) DisableRegion(n int) (err error) { 189 if n < 0 || n+1 > hw.Regions() { 190 return errors.New("invalid region index") 191 } 192 193 if reg.Read(hw.Bypass) != 1 { 194 return errors.New("TZASC inactive (bypass detected)") 195 } 196 197 reg.Clear(hw.region_attrs_0+uint32(0x10*n), REGION_ATTRS_EN) 198 199 return 200 } 201 202 // Lock enables TZASC secure boot lock register writing restrictions 203 // (p30, 2.2.8 Preventing writes to registers and using secure_boot_lock, TZC-380 TRM). 204 func (hw *TZASC) Lock() { 205 reg.Write(hw.lockdown_range, 0xffffffff) 206 reg.Write(hw.lockdown_select, 0xffffffff) 207 reg.Set(hw.SecureBootLockReg, hw.SecureBootLockPos) 208 }