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  }