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() |