github.com/usbarmory/armory-boot@v0.0.0-20240307133412-208c66a380b9/sdp/sdp.go (about) 1 // https://github.com/usbarmory/armory-boot 2 // 3 // Copyright (c) WithSecure Corporation 4 // https://foundry.withsecure.com 5 // 6 // Use of this source code is governed by the license 7 // that can be found in the LICENSE file. 8 9 // Package sdp provide helpers for implementing the Serial Download Protocol 10 // (SDP), used on NXP i.MX System-on-Chip (SoC) application processors. 11 package sdp 12 13 import ( 14 "bytes" 15 "encoding/binary" 16 ) 17 18 const HIDReportSize = 1024 19 20 // SDP command types 21 // (p322, 8.9.3 Serial Download Protocol (SDP), IMX6ULLRM). 22 const ( 23 ReadRegister = 0x0101 24 WriteFile = 0x0404 25 DCDWrite = 0x0a0a 26 JumpAddress = 0x0b0b 27 SkipDCDHeader = 0x0c0c 28 ) 29 30 // SDP represents an SDP command 31 // (p322, 8.9.3 Serial Download Protocol (SDP), IMX6ULLRM). 32 type SDP struct { 33 CommandType uint16 34 Address uint32 35 Format uint8 36 DataCount uint32 37 Data uint32 38 _ byte 39 } 40 41 // Bytes converts the SDP command structure to byte array format. 42 func (s *SDP) Bytes() []byte { 43 buf := new(bytes.Buffer) 44 binary.Write(buf, binary.BigEndian, s) 45 return buf.Bytes() 46 } 47 48 // BuildReadRegisterReport generates USB HID reports (ID 1) that implement the 49 // SDP READ_REGISTER command for reading a single 32-bit device register value 50 // (p323, 8.9.3.1.1 READ_REGISTER, IMX6ULLRM). 51 func BuildReadRegisterReport(addr uint32, size uint32) (r1 []byte) { 52 sdp := &SDP{ 53 CommandType: ReadRegister, 54 Address: addr, 55 Format: 0x20, // 32-bit access 56 DataCount: size, 57 } 58 59 return sdp.Bytes() 60 } 61 62 // BuildDCDWriteReport generates USB HID reports (IDs 1 and 2) that implement 63 // the SDP DCD_WRITE command sequence, used to load a DCD binary payload 64 // (p327, 8.9.3.1.5 DCD_WRITE, IMX6ULLRM). 65 func BuildDCDWriteReport(dcd []byte, addr uint32) (r1 []byte, r2 []byte) { 66 sdp := &SDP{ 67 CommandType: DCDWrite, 68 Address: addr, 69 DataCount: uint32(len(dcd)), 70 } 71 72 return sdp.Bytes(), dcd 73 } 74 75 // BuildFileWriteReport generates USB HID reports (IDs1 and 2) that implement 76 // the SDP FILE_WRITE command sequence, used to load an imx binary payload 77 // (p325, 8.9.3.1.3 FILE_WRITE, IMX6ULLRM). 78 func BuildFileWriteReport(imx []byte, addr uint32) (r1 []byte, r2 [][]byte) { 79 sdp := &SDP{ 80 CommandType: WriteFile, 81 Address: addr, 82 DataCount: uint32(len(imx)), 83 } 84 85 // make a copy to leave input slice untouched 86 imx = append(imx[:0:0], imx...) 87 88 // DCD pointer must be cleared 89 binary.LittleEndian.PutUint32(imx[DCDOffset:], 0) 90 91 for j := 0; j < len(imx); j += HIDReportSize { 92 k := j + HIDReportSize 93 94 if k > len(imx) { 95 k = len(imx) 96 } 97 98 r2 = append(r2, imx[j:k]) 99 } 100 101 return sdp.Bytes(), r2 102 } 103 104 // BuildJumpAddressReport generates the USB HID report (ID 1) that implements 105 // the SDP JUMP_ADDRESS command, used to execute an imx binary payload 106 // (p328, 8.9.3.1.7 JUMP_ADDRESS, IMX6ULLRM). 107 func BuildJumpAddressReport(addr uint32) (r1 []byte) { 108 sdp := &SDP{ 109 CommandType: JumpAddress, 110 Address: addr, 111 } 112 113 return sdp.Bytes() 114 }