github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/dcp/dcp.go (about)

     1  // NXP Data Co-Processor (DCP) driver
     2  // https://github.com/f-secure-foundry/tamago
     3  //
     4  // Copyright (c) F-Secure Corporation
     5  // https://foundry.f-secure.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 dcp implements a driver for the NXP Data Co-Processor (DCP), a
    11  // cryptographic hardware accelerator included in i.MX6ULL/i.MX6ULZ SoCs.
    12  //
    13  // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as
    14  // supported by the TamaGo framework for bare metal Go on ARM SoCs, see
    15  // https://github.com/f-secure-foundry/tamago.
    16  package dcp
    17  
    18  import (
    19  	"bytes"
    20  	"encoding/binary"
    21  	"errors"
    22  	"fmt"
    23  	"sync"
    24  
    25  	"github.com/f-secure-foundry/tamago/bits"
    26  	"github.com/f-secure-foundry/tamago/internal/reg"
    27  )
    28  
    29  // DCP registers
    30  const (
    31  	DCP_BASE = 0x02280000
    32  
    33  	DCP_CTRL     = DCP_BASE
    34  	CTRL_SFTRST  = 31
    35  	CTRL_CLKGATE = 30
    36  
    37  	DCP_STAT     = DCP_BASE + 0x10
    38  	DCP_STAT_CLR = DCP_BASE + 0x18
    39  	DCP_STAT_IRQ = 0
    40  
    41  	DCP_CHANNELCTRL = DCP_BASE + 0x0020
    42  
    43  	DCP_KEY     = DCP_BASE + 0x0060
    44  	KEY_INDEX   = 4
    45  	KEY_SUBWORD = 0
    46  
    47  	DCP_KEYDATA   = DCP_BASE + 0x0070
    48  	DCP_CH0CMDPTR = DCP_BASE + 0x0100
    49  	DCP_CH0SEMA   = DCP_BASE + 0x0110
    50  
    51  	DCP_CH0STAT        = DCP_BASE + 0x0120
    52  	CHxSTAT_ERROR_CODE = 16
    53  	CHxSTAT_ERROR_MASK = 0b1111110
    54  
    55  	DCP_CH0STAT_CLR = DCP_BASE + 0x0128
    56  )
    57  
    58  // DCP channels
    59  const (
    60  	DCP_CHANNEL_0 = iota + 1
    61  	DCP_CHANNEL_1
    62  	DCP_CHANNEL_2
    63  	DCP_CHANNEL_3
    64  )
    65  
    66  // DCP control packet settings
    67  const (
    68  	// p1068, 13.2.6.4.2 Control0 Field, MCIMX28RM
    69  
    70  	DCP_CTRL0_HASH_TERM       = 13
    71  	DCP_CTRL0_HASH_INIT       = 12
    72  	DCP_CTRL0_OTP_KEY         = 10
    73  	DCP_CTRL0_CIPHER_INIT     = 9
    74  	DCP_CTRL0_CIPHER_ENCRYPT  = 8
    75  	DCP_CTRL0_ENABLE_HASH     = 6
    76  	DCP_CTRL0_ENABLE_CIPHER   = 5
    77  	DCP_CTRL0_CHAIN           = 2
    78  	DCP_CTRL0_DECR_SEMAPHORE  = 1
    79  	DCP_CTRL0_INTERRUPT_ENABL = 0
    80  
    81  	// p1070, 13.2.6.4.3 Control1 Field, MCIMX28RM
    82  	// p1098, 13.3.11 DCP_PACKET2 field descriptions, MCIMX28RM
    83  
    84  	DCP_CTRL1_HASH_SELECT = 16
    85  	HASH_SELECT_SHA1      = 0x00
    86  	HASH_SELECT_CRC32     = 0x01
    87  	HASH_SELECT_SHA256    = 0x02
    88  
    89  	DCP_CTRL1_KEY_SELECT  = 8
    90  	KEY_SELECT_UNIQUE_KEY = 0xfe
    91  
    92  	DCP_CTRL1_CIPHER_MODE = 4
    93  	CIPHER_MODE_CBC       = 0x01
    94  
    95  	DCP_CTRL1_CIPHER_SELECT = 0
    96  	CIPHER_SELECT_AES128    = 0x00
    97  )
    98  
    99  const WorkPacketLength = 32
   100  
   101  // WorkPacket represents a DCP work packet
   102  // (p1067, 13.2.6.4 Work Packet Structure, MCIMX28RM).
   103  type WorkPacket struct {
   104  	NextCmdAddr              uint32
   105  	Control0                 uint32
   106  	Control1                 uint32
   107  	SourceBufferAddress      uint32
   108  	DestinationBufferAddress uint32
   109  	BufferSize               uint32
   110  	PayloadPointer           uint32
   111  	Status                   uint32
   112  }
   113  
   114  // Bytes converts the DCP work packet structure to byte array format.
   115  func (pkt *WorkPacket) Bytes() []byte {
   116  	buf := new(bytes.Buffer)
   117  	binary.Write(buf, binary.LittleEndian, pkt)
   118  	return buf.Bytes()
   119  }
   120  
   121  var mux sync.Mutex
   122  
   123  // Init initializes the DCP module.
   124  func Init() {
   125  	mux.Lock()
   126  	defer mux.Unlock()
   127  
   128  	// soft reset DCP
   129  	reg.Set(DCP_CTRL, CTRL_SFTRST)
   130  	reg.Clear(DCP_CTRL, CTRL_SFTRST)
   131  
   132  	// enable clocks
   133  	reg.Clear(DCP_CTRL, CTRL_CLKGATE)
   134  
   135  	// enable channel 0
   136  	reg.Write(DCP_CHANNELCTRL, DCP_CHANNEL_0)
   137  }
   138  
   139  func cmd(ptr uint32, count int) (err error) {
   140  	mux.Lock()
   141  	defer mux.Unlock()
   142  
   143  	if reg.Read(DCP_CHANNELCTRL) != DCP_CHANNEL_0 {
   144  		return errors.New("co-processor is not initialized")
   145  	}
   146  
   147  	// clear channel status
   148  	reg.Write(DCP_CH0STAT_CLR, 0xffffffff)
   149  
   150  	// set command address
   151  	reg.Write(DCP_CH0CMDPTR, ptr)
   152  	// activate channel
   153  	reg.SetN(DCP_CH0SEMA, 0, 0xff, uint32(count))
   154  	// wait for completion
   155  	reg.Wait(DCP_STAT, DCP_STAT_IRQ, DCP_CHANNEL_0, 1)
   156  	// clear interrupt register
   157  	reg.Set(DCP_STAT_CLR, DCP_CHANNEL_0)
   158  
   159  	chstatus := reg.Read(DCP_CH0STAT)
   160  
   161  	// check for errors
   162  	if bits.Get(&chstatus, 0, CHxSTAT_ERROR_MASK) != 0 {
   163  		code := bits.Get(&chstatus, CHxSTAT_ERROR_CODE, 0xff)
   164  		sema := reg.Read(DCP_CH0SEMA)
   165  		return fmt.Errorf("DCP channel 0 error, status:%#x error_code:%#x sema:%#x", chstatus, code, sema)
   166  	}
   167  
   168  	return
   169  }