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 }