162 lines
5.7 KiB
Python
162 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
#******************************************************************************
|
|
#
|
|
# This scripts creates a single Blob, which can be programmed at OTA_POINTER
|
|
# The first 4 bytes contain address to OTA Descriptor, which immediately follows
|
|
#
|
|
#******************************************************************************
|
|
|
|
|
|
import argparse
|
|
import sys
|
|
|
|
magicnum = 0xDEADCAFE
|
|
|
|
#******************************************************************************
|
|
#
|
|
# Main function
|
|
#
|
|
#******************************************************************************
|
|
def main():
|
|
|
|
# Read the binary file from the command line.
|
|
with open(args.binfile, mode='rb') as binfile:
|
|
application = binfile.read()
|
|
|
|
if len(args.trailerfile) > 0:
|
|
with open(args.trailerfile, mode='rb') as binfile:
|
|
trailer= binfile.read()
|
|
else:
|
|
trailer = []
|
|
|
|
applen = len(application)
|
|
crc = crc32(application)
|
|
|
|
ota_desc = []
|
|
|
|
# OTA Descriptor immediately follows the OTA_POINTER
|
|
ota_desc.extend(int_to_bytes(magicnum))
|
|
ota_desc.extend(int_to_bytes(int(args.linkaddr, 0)))
|
|
ota_desc.extend(int_to_bytes(applen))
|
|
ota_desc.extend(int_to_bytes(crc))
|
|
|
|
trailerlen = len(trailer)
|
|
ota_desc.extend(int_to_bytes(trailerlen))
|
|
ota_desc.extend(int_to_bytes(int(args.options, 0)))
|
|
ota_desc.extend(int_to_bytes(int(args.flashaddr , 0)+ 40)) # pui32SecInfoPtr
|
|
if (args.otaimageaddr != 0):
|
|
# Image has been flashed seprately. Just code the address in descriptor
|
|
ota_desc.extend(int_to_bytes(int(args.otaimageaddr, 0))) # pui32ImageAddr
|
|
else:
|
|
# Image is written immediately following the OTA descriptor
|
|
# Need to determine if there is a padding needed in between to ensure proper alignment
|
|
image_addr = int(args.flashaddr , 0) + 40 + trailerlen
|
|
if (image_addr % int(args.alignment) != 0):
|
|
pad_size = int(args.alignment) - (image_addr % int(args.alignment))
|
|
else:
|
|
pad_size = 0
|
|
image_addr = image_addr + pad_size
|
|
ota_desc.extend(int_to_bytes(image_addr)) # pui32ImageAddr
|
|
ota_desc_crc = crc32(ota_desc)
|
|
# OTA_POINTER contents
|
|
new_image = []
|
|
new_image.extend(int_to_bytes(int(args.flashaddr , 0)+ 4)) # OTA Descriptor address
|
|
new_image.extend(ota_desc) # OTA Descriptor
|
|
new_image.extend(int_to_bytes(ota_desc_crc))
|
|
|
|
if trailerlen > 0:
|
|
print('Adding Security Trailer')
|
|
new_image.extend(trailer)
|
|
if (pad_size != 0):
|
|
print('Adding padding of {} bytes...'.format(pad_size), flush=True)
|
|
pad_binarray = bytearray([0]*pad_size);
|
|
new_image.extend(pad_binarray)
|
|
if (args.otaimageaddr == 0):
|
|
# Image
|
|
new_image.extend(application)
|
|
print('Saving OTA descriptor image {} bytes to {}...'.format(len(new_image), args.outfile), flush=True)
|
|
with open(args.outfile, mode='wb') as imagefile:
|
|
imagebytearray = bytearray(new_image)
|
|
imagefile.write(imagebytearray)
|
|
|
|
print('Done.')
|
|
|
|
#******************************************************************************
|
|
#
|
|
# Turn a 32-bit number into a series of bytes for transmission.
|
|
#
|
|
# This command will split a 32-bit integer into an array of bytes, ordered
|
|
# LSB-first for transmission over the UART.
|
|
#
|
|
#******************************************************************************
|
|
def int_to_bytes(n):
|
|
A = [n & 0xFF,
|
|
(n >> 8) & 0xFF,
|
|
(n >> 16) & 0xFF,
|
|
(n >> 24) & 0xFF]
|
|
|
|
return A
|
|
|
|
#******************************************************************************
|
|
#
|
|
# Extract a word from a byte array
|
|
#
|
|
#******************************************************************************
|
|
def word_from_bytes(B, n):
|
|
return (B[n] + (B[n + 1] << 8) + (B[n + 2] << 16) + (B[n + 3] << 24))
|
|
|
|
#******************************************************************************
|
|
#
|
|
# CRC function that matches the CRC used by the Apollo bootloader.
|
|
#
|
|
#******************************************************************************
|
|
poly32 = 0x1EDC6F41
|
|
def crc32(L):
|
|
rem = 0
|
|
for b in L:
|
|
rem = rem ^ (b << 24)
|
|
for i in range(8):
|
|
if rem & 0x80000000:
|
|
rem = ((rem << 1) ^ poly32)
|
|
else:
|
|
rem = (rem << 1)
|
|
|
|
rem = rem & 0xFFFFFFFF
|
|
return rem
|
|
|
|
#******************************************************************************
|
|
#
|
|
# Main program flow
|
|
#
|
|
#******************************************************************************
|
|
if __name__ == '__main__':
|
|
|
|
parser = argparse.ArgumentParser(description =
|
|
'Utility to generate OTA blob for multi boot test app')
|
|
parser.add_argument('binfile',
|
|
help = 'Binary file to program into the target device')
|
|
|
|
parser.add_argument('flashaddr', help = 'Flash address (hex) where blob will be flashed to')
|
|
|
|
parser.add_argument('linkaddr', help = 'Link address (hex) of the program file')
|
|
|
|
parser.add_argument('-a', dest = 'alignment', default=4,
|
|
help = 'Desired alignment for application in image')
|
|
|
|
parser.add_argument('options',
|
|
help = 'OTA options parameter')
|
|
|
|
parser.add_argument('-s', dest = 'trailerfile', default='',
|
|
help = 'Binary file for (optional) security trailer')
|
|
|
|
parser.add_argument('-i', dest='otaimageaddr', default=0,
|
|
help = '(optional) Flash address (hex) where the OTA image is flashed to - if not specified, the image is included in outfile immediately following the descriptor')
|
|
|
|
|
|
parser.add_argument('-o', dest = 'outfile',
|
|
help = 'output filename for the ota descriptor')
|
|
|
|
args = parser.parse_args()
|
|
|
|
main()
|