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  }