github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/snvs/snvs.go (about)

     1  // NXP Secure Non-Volatile Storage (SNVS) support
     2  // https://github.com/usbarmory/tamago
     3  //
     4  // Copyright (c) WithSecure Corporation
     5  // https://foundry.withsecure.com
     6  //
     7  // Use of this source code is governed by the license
     8  // that can be found in the LICENSE file.
     9  
    10  // Package snvs implements a driver for NXP Secure Non-Volatile Storage (SNVS)
    11  // following reference specifications:
    12  //   - IMX6ULLRM  - i.MX 6ULL Applications Processor Reference Manual          - Rev 1 2017/11
    13  //   - IMX6ULLSRM - i.MX 6ULL Applications Processor Security Reference Manual - Rev 0 2016/09
    14  //
    15  // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as
    16  // supported by the TamaGo framework for bare metal Go on ARM SoCs, see
    17  // https://github.com/usbarmory/tamago.
    18  package snvs
    19  
    20  import (
    21  	"github.com/usbarmory/tamago/bits"
    22  	"github.com/usbarmory/tamago/internal/reg"
    23  
    24  	"sync"
    25  	"time"
    26  )
    27  
    28  // SNVS registers
    29  const (
    30  	SNVS_HPCOMR     = 0x04
    31  	HPCOMR_HAC_STOP = 19
    32  	HPCOMR_HAC_LOAD = 17
    33  	HPCOMR_HAC_EN   = 16
    34  
    35  	SNVS_HPSVCR     = 0x10
    36  	HPSVCR_LPSV_CFG = 30
    37  
    38  	SNVS_HPSR           = 0x14
    39  	HPSR_OTPMK_ZERO     = 27
    40  	HPSR_OTPMK_SYNDROME = 16
    41  
    42  	SNVS_HPHACIVR = 0x1c
    43  	SNVS_HPHACR   = 0x20
    44  
    45  	HPSR_SSM_STATE = 8
    46  
    47  	SNVS_LPTDCR  = 0x48
    48  	LPTDCR_VT_EN = 6
    49  	LPTDCR_TT_EN = 5
    50  	LPTDCR_CT_EN = 4
    51  
    52  	SNVS_LPSR = 0x4c
    53  	LPSR_VTD  = 6
    54  	LPSR_TTD  = 5
    55  	LPSR_CTD  = 4
    56  	LPSR_PGD  = 3
    57  
    58  	SNVS_LPPGDR = 0x64
    59  	// Power Glitch Detector Register hardwired value
    60  	LPPGDR_PGD_VAL = 0x41736166
    61  )
    62  
    63  // System Security Monitor (SSM) states
    64  const (
    65  	SSM_STATE_INIT      = 0b0000
    66  	SSM_STATE_HARD_FAIL = 0b0001
    67  	SSM_STATE_SOFT_FAIL = 0b0011
    68  	SSM_STATE_CHECK     = 0b1001
    69  	SSM_STATE_NONSECURE = 0b1011
    70  	SSM_STATE_TRUSTED   = 0b1101
    71  	SSM_STATE_SECURE    = 0b1111
    72  )
    73  
    74  // DryIce registers
    75  const (
    76  	DRYICE_DTOCR    = 0x00
    77  	DTOCR_DRYICE_EN = 0
    78  
    79  	DRYICE_DTMR        = 0x04
    80  	DTMR_TEMP_MON_TRIM = 22
    81  	DTMR_VOLT_MON_TRIM = 12
    82  	DTMR_BGR_TRIM      = 6
    83  	DTMR_PROG_TRIM     = 0
    84  
    85  	DRYICE_DTRR                  = 0x08
    86  	DTRR_SNVS_CLK_TAMP_DETECT    = 2
    87  	DTRR_DRYICE_TEMP_DETECT      = 1
    88  	DTRR_DRYICE_VOLT_TAMP_DETECT = 0
    89  
    90  	DRYICE_DMCR       = 0x0c
    91  	DMCR_CLOCK_DET_EN = 2
    92  	DMCR_VOLT_DET_EN  = 1
    93  	DMCR_TEMP_DET_EN  = 0
    94  )
    95  
    96  // SNVS represents the SNVS instance.
    97  type SNVS struct {
    98  	sync.Mutex
    99  
   100  	// Base register
   101  	Base uint32
   102  	// Clock gate register
   103  	CCGR uint32
   104  	// Clock gate
   105  	CG int
   106  	// auxiliary logic base register
   107  	DryIce uint32
   108  
   109  	// control registers
   110  	hpcomr   uint32
   111  	hpsvcr   uint32
   112  	hpsr     uint32
   113  	hphacivr uint32
   114  	hphacr   uint32
   115  	lptdcr   uint32
   116  	lpsr     uint32
   117  	lppgdr   uint32
   118  
   119  	// DryIce registers
   120  	dtocr uint32
   121  	dtmr  uint32
   122  	dtrr  uint32
   123  	dmcr  uint32
   124  
   125  	// active configuration
   126  	sp SecurityPolicy
   127  }
   128  
   129  // SecurityPolicy represents an SNVS configuration and is used to configure
   130  // tamper detection or return detected violations (see SetPolicy()).
   131  type SecurityPolicy struct {
   132  	// SRTC Clock Tampering
   133  	Clock bool
   134  	// Temperature Tamper
   135  	Temperature bool
   136  	// Voltage Tamper
   137  	Voltage bool
   138  	// Power Glitch Violation (used only when reporting, see Monitor())
   139  	Power bool
   140  
   141  	// SecurityViolation controls whether monitored conditions generate a
   142  	// violation which transitions the SNVS state to soft fail, preventing
   143  	// access to the OTPMK and SNVS availability (see Available()).
   144  	SecurityViolation bool
   145  
   146  	// HardFail controls whether a soft fail state (see SecurityViolation)
   147  	// transitions the system to a hard reset after a predefined system
   148  	// clock delay (see HAC).
   149  	HardFail bool
   150  
   151  	// HAC is used to stop and reset the initial value of the High
   152  	// Assurance Counter, a delay in system clocks between a soft fail and
   153  	// a hard fail, or return the current HAC value.
   154  	HAC uint32
   155  
   156  	// State represents the System Security Monitor (SSM) State (used only
   157  	// when reporting, see Monitor()).
   158  	State uint8
   159  }
   160  
   161  func (hw *SNVS) initDryIce(calibrationData uint32) {
   162  	hw.dtocr = hw.DryIce + DRYICE_DTOCR
   163  	hw.dtmr = hw.DryIce + DRYICE_DTMR
   164  	hw.dtrr = hw.DryIce + DRYICE_DTRR
   165  	hw.dmcr = hw.DryIce + DRYICE_DMCR
   166  
   167  	reg.SetN(hw.dtmr, DTMR_TEMP_MON_TRIM, 0x3ff, bits.Get(&calibrationData, 0, 0x3ff))
   168  	reg.SetN(hw.dtmr, DTMR_VOLT_MON_TRIM, 0x3ff, bits.Get(&calibrationData, 10, 0x3ff))
   169  	reg.SetN(hw.dtmr, DTMR_BGR_TRIM, 0x3f, bits.Get(&calibrationData, 20, 0x3f))
   170  	reg.SetN(hw.dtmr, DTMR_PROG_TRIM, 0x3f, bits.Get(&calibrationData, 26, 0x3f))
   171  }
   172  
   173  // Init initializes the SNVS controller, the calibration data is fused
   174  // individually for each part and is required for correct initialization of the
   175  // DryIce auxiliary logic (when available).
   176  func (hw *SNVS) Init(calibrationData uint32) {
   177  	if hw.Base == 0 || hw.CCGR == 0 {
   178  		panic("invalid SNVS instance")
   179  	}
   180  
   181  	// enable clock
   182  	reg.SetN(hw.CCGR, hw.CG, 0b11, 0b11)
   183  
   184  	hw.hpcomr = hw.Base + SNVS_HPCOMR
   185  	hw.hpsvcr = hw.Base + SNVS_HPSVCR
   186  	hw.hpsr = hw.Base + SNVS_HPSR
   187  	hw.hphacivr = hw.Base + SNVS_HPHACIVR
   188  	hw.hphacr = hw.Base + SNVS_HPHACR
   189  	hw.lptdcr = hw.Base + SNVS_LPTDCR
   190  	hw.lpsr = hw.Base + SNVS_LPSR
   191  	hw.lppgdr = hw.Base + SNVS_LPPGDR
   192  
   193  	if hw.DryIce > 0 {
   194  		hw.initDryIce(calibrationData)
   195  	}
   196  }
   197  
   198  func (hw *SNVS) setDryIcePolicy(sp SecurityPolicy) {
   199  	reg.Set(hw.dtocr, DTOCR_DRYICE_EN)
   200  	time.Sleep(1 * time.Millisecond)
   201  
   202  	reg.SetTo(hw.dmcr, DMCR_VOLT_DET_EN, sp.Voltage)
   203  	reg.SetTo(hw.dmcr, DMCR_TEMP_DET_EN, sp.Temperature)
   204  	reg.SetTo(hw.dmcr, DMCR_CLOCK_DET_EN, sp.Clock)
   205  	time.Sleep(1 * time.Millisecond)
   206  
   207  	// clear records
   208  	reg.Set(hw.dtrr, DTRR_DRYICE_TEMP_DETECT)
   209  	reg.Set(hw.dtrr, DTRR_DRYICE_VOLT_TAMP_DETECT)
   210  	reg.Set(hw.dtrr, DTRR_SNVS_CLK_TAMP_DETECT)
   211  }
   212  
   213  // SetPolicy configures the SNVS tamper detection and security violation
   214  // policy, It can be used to prevent a transition from soft fail to hard fail
   215  // if invoked within the expiration of a previously applied policy (see
   216  // SecurityPolicy.HAC).
   217  func (hw *SNVS) SetPolicy(sp SecurityPolicy) {
   218  	hw.Lock()
   219  	defer hw.Unlock()
   220  
   221  	// stop High Assurance Counter
   222  	reg.Set(hw.hpcomr, HPCOMR_HAC_STOP)
   223  	reg.Clear(hw.hpcomr, HPCOMR_HAC_EN)
   224  
   225  	// set Power Glitch Detector value and clear its record
   226  	reg.Write(hw.lppgdr, LPPGDR_PGD_VAL)
   227  	reg.Set(hw.lpsr, LPSR_PGD)
   228  
   229  	// set LP security violation configuration
   230  	reg.SetTo(hw.hpsvcr, HPSVCR_LPSV_CFG+1, sp.SecurityViolation)
   231  
   232  	if sp.HardFail {
   233  		reg.Clear(hw.hpcomr, HPCOMR_HAC_STOP)
   234  		reg.Write(hw.hphacivr, sp.HAC)
   235  		reg.Set(hw.hpcomr, HPCOMR_HAC_LOAD)
   236  		reg.Set(hw.hpcomr, HPCOMR_HAC_EN)
   237  	}
   238  
   239  	if hw.DryIce > 0 {
   240  		hw.setDryIcePolicy(sp)
   241  	}
   242  
   243  	// set tamper monitors
   244  	reg.SetTo(hw.lptdcr, LPTDCR_VT_EN, sp.Voltage)
   245  	reg.SetTo(hw.lptdcr, LPTDCR_TT_EN, sp.Temperature)
   246  	reg.SetTo(hw.lptdcr, LPTDCR_CT_EN, sp.Clock)
   247  
   248  	// clear records
   249  	reg.Set(hw.lpsr, LPSR_VTD)
   250  	reg.Set(hw.lpsr, LPSR_TTD)
   251  	reg.Set(hw.lpsr, LPSR_CTD)
   252  
   253  	hw.sp = sp
   254  }
   255  
   256  // Monitor returns the SNVS tamper System Security Monitor (SSM) state, its
   257  // configured violation policy and the current High Assurance Counter value.
   258  func (hw *SNVS) Monitor() (violations SecurityPolicy) {
   259  	clk := reg.IsSet(hw.lpsr, LPSR_CTD)
   260  	tmp := reg.IsSet(hw.lpsr, LPSR_TTD)
   261  	vcc := reg.IsSet(hw.lpsr, LPSR_VTD)
   262  
   263  	if hw.DryIce > 0 {
   264  		clk = clk || reg.IsSet(hw.dtrr, DTRR_SNVS_CLK_TAMP_DETECT)
   265  		tmp = tmp || reg.IsSet(hw.dtrr, DTRR_DRYICE_VOLT_TAMP_DETECT)
   266  		vcc = vcc || reg.IsSet(hw.dtrr, DTRR_DRYICE_TEMP_DETECT)
   267  	}
   268  
   269  	return SecurityPolicy{
   270  		Clock:             clk,
   271  		Temperature:       tmp,
   272  		Voltage:           vcc,
   273  		Power:             reg.IsSet(hw.lpsr, LPSR_PGD),
   274  		SecurityViolation: hw.sp.SecurityViolation,
   275  		HardFail:          hw.sp.HardFail,
   276  		HAC:               reg.Read(hw.hphacr),
   277  		State:             uint8(reg.Get(hw.hpsr, HPSR_SSM_STATE, 0b1111)),
   278  	}
   279  }
   280  
   281  // Available verifies whether the Secure Non Volatile Storage (SNVS) is
   282  // correctly programmed and in Trusted or Secure state (indicating that Secure
   283  // Boot is enabled and no security violations have been detected).
   284  //
   285  // The unique OTPMK internal key is available only when Secure Boot (HAB) is
   286  // enabled, otherwise a Non-volatile Test Key (NVTK), identical for each SoC,
   287  // is used.
   288  func (hw *SNVS) Available() bool {
   289  	hpsr := reg.Read(hw.hpsr)
   290  
   291  	// ensure that the OTPMK has been correctly programmed
   292  	if bits.Get(&hpsr, HPSR_OTPMK_ZERO, 1) != 0 || bits.Get(&hpsr, HPSR_OTPMK_SYNDROME, 0x1ff) != 0 {
   293  		return false
   294  	}
   295  
   296  	switch bits.Get(&hpsr, HPSR_SSM_STATE, 0b1111) {
   297  	case SSM_STATE_TRUSTED, SSM_STATE_SECURE:
   298  		return true
   299  	default:
   300  		return false
   301  	}
   302  }