def gen_prog_image_without_scratchpad(config, bootloader, scratchpad_data, in_files): '''Create a Flash memory image, ready for programming to a device.''' # Create a Memory object to store the Flash memory image. memory = hextool.Memory() # Add bootloader to memory image memory += gen_bootloader(config, bootloader) # Add other files to memory image. for in_file in in_files: for area in config.areas.values(): # Add file only if bootloader knows this area. if area.id == in_file.area_id: memory.cursor = area.address # Sanity check. if area.length < len(in_file.raw_data): raise ValueError("error generating programming image: \ file too big for area.") memory += in_file.raw_data # If flag is set need to add bl_info_header. if area.has_bl_info_header(): header = make_bl_info_header(config, scratchpad_data, in_file) memory.cursor = area.address + BL_INFO_HEADER_OFFSET memory.overlap_ok = True memory += header memory.overlap_ok = False return memory
def get_bootloader_hex(self): '''Create a Bootloader memory image, with its config.''' # Create a Memory object to store the Flash memory image. memory = hextool.Memory() # Add bootloader to memory image memory += self.bootloader return memory
def gen_bootloader(self, bootloader): '''Create the bootloader image with its configuration (areas and keys).''' bl_area = self.config.get_bootloader_area() bl_start = bl_area.address bl_max_num_bytes = bl_area.length bl_end = bl_start + bl_max_num_bytes set_start = bl_area.get_settings_start_address() set_key_start = bl_area.get_key_start_address() set_end = bl_area.get_settings_end_address() memory = hextool.Memory() if bootloader.min_address < bl_start: # DEBUG: or bootloader.max_address > bl_end: raise ValueError("bootloader overflows outside its area: " "0x%04x .. 0x%04x, should be 0x%04x .. 0x%04x" % (bootloader.min_address, bootloader.max_address, bl_start, bl_end)) # Add bootloader to the Flash memory image. memory.cursor = bl_start memory += bootloader # Erase keys and memory area information Flash memory image. del memory[set_start:set_end] # Set Memory cursor to point at the bootloader area settings. memory.cursor = set_start # Add memory area information in Flash memory image. for area in self.config.areas.values(): data = struct.pack("<4L", area.address, area.length, area.id, area.flags | (area.type << 2)) memory += data # Sanity check. if memory.cursor > set_key_start: raise ValueError( "error generating programming image: bootloader areas") # Set Memory cursor to point at the bootloader key settings. memory.cursor = set_key_start # Add keys in Flash memory image. for key in self.config.keys.values(): memory += key.authentication memory += key.encryption # Sanity check. if memory.cursor > set_end: raise ValueError( "error generating programming image: bootloader keys") return memory
def main(): '''Main program''' # Determine program name, for error messages. pgmname = os.path.split(sys.argv[0])[-1] # Determine help text width. try: help_width = int(os.environ['COLUMNS']) except (KeyError, ValueError): help_width = 80 help_width -= 2 parser = argparse.ArgumentParser( prog = pgmname, formatter_class = argparse.RawDescriptionHelpFormatter, description = textwrap.fill( "A tool to prepare EFR32 stack hex file for v4.0 to v5.0 upgrade.")) parser.add_argument("infilespec", metavar = "INFILESPEC", help = "stack hex file") parser.add_argument("--output", "-o", metavar = "OUTFILESPEC", help = "output file") try: args = parser.parse_args() memory = hextool.Memory() hextool.load_intel_hex(memory, filename = args.infilespec) # Move first page off stack just before the v3 bootloader data. first_page = memory[memory.min_address:memory.min_address + PAGE_SIZE] memory.cursor = FIRST_PAGE_ADDRESS memory += first_page del memory[memory.min_address:memory.min_address + PAGE_SIZE] if args.output is not None: # Save output file. hextool.save_intel_hex(memory, filename=args.output) else: hextool.save_intel_hex(memory, filename=args.infilespec) except (ValueError, IOError, OSError) as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return 0
def gen_prog_image(config, bootloader, scratchpad_header, scratchpad_data): '''Create a Flash memory image, ready for programming to a device.''' sp_area = config.get_scratchpad_area() sp_max_num_bytes = sp_area.length # scratchpad is written by the end sp_end = sp_area.address + sp_area.length # Create a Memory object to store the Flash memory image. memory = hextool.Memory() # Calculate total scratchpad length in bytes. sp_num_bytes = sum(map(len, scratchpad_data)) if sp_num_bytes > sp_max_num_bytes: raise ValueError("scratchpad too big by %d bytes" % (sp_num_bytes - sp_max_num_bytes)) # Add bootloader to memory image memory += gen_bootloader(config, bootloader) # Set Memory cursor to point at the first byte # of scratchpad in the Flash memory image. memory.cursor = (sp_end - len(SCRATCHPAD_V1_TAG) - len(scratchpad_header) - sp_num_bytes) # Add scratchpad to the Flash memory image. for data in scratchpad_data: memory += data # Add a scratchpad header at the end, followed by a 16-byte tag # for finding the scratchpad in Flash, to the Flash memory image. memory += scratchpad_header memory += SCRATCHPAD_V1_TAG # Sanity check. if memory.cursor != sp_end: raise ValueError("error generating programming image: scratchpad") return memory
def __init__(self, file_spec = None, data = None, version = (0, 0, 0, 0)): if file_spec == None and data == None: raise ValueError("no data given") elif file_spec != None and data != None: raise ValueError("file_spec and data are mutually exclusive") # Set default values. self.area_id = 0x00000000 self.version = version self.compressed = False self.encrypted = False if data: # Data given, make a copy of it. self.data = bytearray(data) self.raw_data = bytearray(data) else: # File specification given, parse it. version, self.area_id, filename = self.parse_file_spec(file_spec) self.version = self.parse_version(version) # Read data from file. memory = hextool.Memory() hextool.load_intel_hex(memory, filename = filename) if memory.num_ranges == 0: # No data found in file. raise ValueError("file contains no data: '%s'" % filename) elif (memory.max_address - memory.min_address > self.MAX_NUM_BYTES_PER_FILE): raise ValueError("file too big: '%s'" % filename) # Convert Memory object to a flat bytearray. self.data = memory[memory.min_address:memory.max_address] self.raw_data = memory[memory.min_address:memory.max_address] # Create a file header for uncompressed, unencrypted data. self.header = self.make_file_header(self.area_id, len(self.data), *self.version)
def main(): '''Main program''' # Determine program name, for error messages. pgmname = os.path.split(sys.argv[0])[-1] # Create a parser for parsing the command line and printing error messages. parser = create_argument_parser(pgmname) try: # Parse command line arguments. args = parse_arguments(parser) # Parse configuration file. config = BootloaderConfig.from_ini_files(args.configfile, args.symbols) # Check that config is valid # ValueError exception will be raised in case of invalid config config.check_config() # Check the key chosen is declared try: chosenkey = config.keys[args.keyname] except KeyError: raise ValueError("key not found: '%s'" % args.keyname) except (ValueError, IOError, OSError, configparser.Error) as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return 1 if False: # DEBUG: Show config. for key in config.keys.items(): print(key) # Create a Memory object for storing the bootloader. bootloader = hextool.Memory() if args.bootloader: # Read bootloader. hextool.load_intel_hex(bootloader, filename=args.bootloader) in_files = [] # List of InFile objects # (header, area_id, version, data) scratchpad_data = [] # List of scratchpad data blocks ver_major, ver_minor, ver_maint, ver_devel = (0, 0, 0, 0) if AES_TEST: # Run AES test. See aes_test1() in utils/aes.c for details. in_files.append(InFile(data=test_data)) scratchpad_data.append(test_icb) elif CMAC_TEST: # Run CMAC / OMAC1 test. See aes_omac1_test1() # in utils/aes.c for details. scratchpad_data.append(test_data) else: # Read input files. try: for file_spec in args.infilespec: # Create an InFile object. in_file = InFile(file_spec=file_spec, version=(0, 0, 0, args.otapseq)) # Compress data in-place. in_file.compress() in_files.append(in_file) except (ValueError, IOError, OSError) as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return 1 # Create secure header, which is also the initial counter block (ICB). secure_header = get_random_bytes(16) scratchpad_data.append(secure_header) if not CMAC_TEST: try: # Create an AES Counter (CTR) mode cipher using secure # header as the 16-byte initial counter block (ICB). cipher = create_cipher(secure_header, chosenkey.encryption) # Encrypt each input file. for in_file in in_files: # Encrypt data in-place. in_file.encrypt(cipher) # Add file header to scratchpad data. scratchpad_data.append(in_file.header) # Add compressed, encrypted file data to scratchpad data. scratchpad_data.append(in_file.data) except ValueError as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return 1 # Calculate and add CMAC / OMAC1 tag. try: cmac = calculate_cmac(scratchpad_data, chosenkey.authentication) scratchpad_data.insert(0, cmac) except ValueError as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return 1 if not AES_TEST and not CMAC_TEST: # Create a scratchpad header. try: scratchpad_header = make_scratchpad_header(args.otapseq, scratchpad_data) except ValueError as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return 1 else: scratchpad_header = bytes() # Write output file and optionally the programming image file. try: with open(args.outfile, "wb") as f: # A combi scratchpad file starts with a 16-byte tag. f.write(SCRATCHPAD_V1_TAG) # Combi scratchpad files have the scratchpad header in front of # the scratchpad contents. The firmware rearranges the data in # Flash memory while storing the scratchpad. f.write(scratchpad_header) # Write scratchpad contents. for data in scratchpad_data: f.write(data) if args.genprog == None: return 0 # Combine bootloader, memory area specification, keys and scratchpad. file_without_scr = args.genprog.rsplit('.',1)[0] + \ "_without_scratchpad.hex" if config.is_scratchpad_internal(): # Generate a programming image (bootloader + scratchpad file) # and save it as Intel HEX. memory = gen_prog_image(config, bootloader, scratchpad_header, scratchpad_data) hextool.save_intel_hex(memory, filename=args.genprog) # Also generate a programming image without scratchpad # (bl+stack+app) for debug purposes and save it as Intel HEX. memory = gen_prog_image_without_scratchpad(config, bootloader, scratchpad_data, in_files) hextool.save_intel_hex(memory, filename=file_without_scr) else: # config.is_scratchpad_internal(): # Generate a programming image without scratchpad (bl+stack+app). # and save it as Intel HEX. memory = gen_prog_image_without_scratchpad(config, bootloader, scratchpad_data, in_files) hextool.save_intel_hex(memory, filename=file_without_scr) except (ValueError, IOError, OSError) as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return 1 return 0
def main(): '''Main program''' # Determine program name, for error messages. pgmname = os.path.split(sys.argv[0])[-1] # Determine help text width. try: help_width = int(os.environ['COLUMNS']) except (KeyError, ValueError): help_width = 80 help_width -= 2 parser = argparse.ArgumentParser( prog=pgmname, formatter_class=argparse.RawTextHelpFormatter, description=textwrap.fill( "A tool to generate a hex file to customize node for \ provisioning.")) parser.add_argument("infilespec", metavar="INFILESPEC", help="yml personalization file") parser.add_argument("--output", "-o", metavar="OUTFILESPEC", help="The output file") parser.add_argument( "--address", "-a", type=parse_address, metavar="VALUE", required=True, help="Address of the storage area ([area:app_persistent]) " "defined in mcu/<mcu>/ini_files/<mcu>_app.ini file\n" "Default values per mcu are :\n" " - NRF52832 : 499712 (0x7A000)\n" " - NRF52833 : 499712 (0x7A000)\n" " - NRF52840 : 1024000 (0xFA000)\n" " - EFR32xg1x (512k) : 503808 (0x7B000)\n" " - EFR32xg1x (1024k): 1028096 (0xFB000)\n" " - EFR32xg22 (512k) : 491520 (0x78000)\n" " - EFR32xg21 (768k) : 753664 (0xB8000)\n" " - EFR32xg21 (1024k): 1015808 (0xF8000)") try: args = parser.parse_args() except (ValueError, IOError, OSError) as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return -1 try: with open(args.infilespec, 'r') as ymlfile: cfg = yaml.load(ymlfile, Loader=yaml.FullLoader) except yaml.YAMLError as exc: sys.stdout.write("%s: Error opening %s (%s)\n" % (pgmname, args.infilespec, exc)) return -1 try: uid = to_bytes(cfg['provisioning']['uid']) method = to_bytes(cfg['provisioning']['method']) except KeyError: sys.stdout.write("%s: UID and Method are mandatory\n" % (pgmname)) return -1 try: key = to_bytes(cfg['provisioning']['factory_key']) except KeyError: key = b'' sys.stdout.write("%s - UID: %s (len: %d)\n" % (pgmname, uid, len(uid))) sys.stdout.write("%s - KEY: %s (len: %d)\n" % (pgmname, "".join("{:02X}".format(to_int(x)) for x in key), len(key))) sys.stdout.write("%s - Method: %d\n" % (pgmname, method)) data = struct.pack("<I", STORAGE_MAGIC) + \ struct.pack("B", method) + \ struct.pack("B", len(uid)) + \ uid + \ struct.pack("B", len(key)) + \ key memory = hextool.Memory() memory.cursor = args.address memory += data # Save output file. if args.output is not None: hextool.save_intel_hex(memory, filename=args.output) sys.stdout.write("%s - Output file: %s\n" % (pgmname, args.output)) else: hextool.save_intel_hex(memory, filename=os.path.splitext(args.infilespec)[0] + ".hex") sys.stdout.write( "%s - Output file: %s\n" % (pgmname, os.path.splitext(args.infilespec)[0] + ".hex"))
def __init__(self, config, bootloader): self.config = config bl_without_config = hextool.Memory() hextool.load_intel_hex(bl_without_config, filename=bootloader) self.bootloader = self.gen_bootloader(bl_without_config) self.infiles = [] # List of data blocks
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # hextoarray32.py - A tool to convert an hex file to an array of 32-bit numbers import sys import os import struct import hextool LINE_INDENT = " " LINE_LENGTH = 72 # Open hex file and convert it to byte array memory = hextool.Memory() hextool.load_intel_hex(memory, filename=sys.argv[1]) # For EFR32 delete range in special registers [0xfe04000-0xfe04200] del memory[0xfe04000:0xfe04200] data = memory[memory.min_address:memory.max_address] # Open outfile and write uint32 array with open(sys.argv[2], "w") as f: line = LINE_INDENT for pos in range(0, len(data), 4): if pos != 0: line += ", " if len(line) >= LINE_LENGTH: f.write(line) f.write("\n")
def main(): '''Main program''' # Determine program name, for error messages. pgmname = os.path.split(sys.argv[0])[-1] # Determine help text width. try: help_width = int(os.environ['COLUMNS']) except (KeyError, ValueError): help_width = 80 help_width -= 2 parser = argparse.ArgumentParser( prog=pgmname, formatter_class=argparse.RawDescriptionHelpFormatter, description=textwrap.fill( "A tool to generate a hex file to customize node for \ provisioning.")) parser.add_argument("infilespec", metavar="INFILESPEC", help="yml personalization file") parser.add_argument("--output", "-o", metavar="OUTFILESPEC", help="output file") parser.add_argument("--address", "-a", type=parse_address, metavar="VALUE", required=True, help="Storage area address") try: args = parser.parse_args() except (ValueError, IOError, OSError) as exc: sys.stdout.write("%s: %s\n" % (pgmname, exc)) return -1 try: with open(args.infilespec, 'r') as ymlfile: cfg = yaml.load(ymlfile, Loader=yaml.FullLoader) except yaml.YAMLError as exc: sys.stdout.write("%s: Error opening %s (%s)\n" % (pgmname, args.infilespec, exc)) return -1 try: uid = to_bytes(cfg['provisioning']['uid']) method = to_bytes(cfg['provisioning']['method']) except KeyError: sys.stdout.write("%s: UID and Method are mandatory\n" % (pgmname)) return -1 try: key = to_bytes(cfg['provisioning']['factory_key']) except KeyError: key = b'' sys.stdout.write("%s - UID: %s (len: %d)\n" % (pgmname, uid, len(uid))) sys.stdout.write("%s - KEY: %s (len: %d)\n" % (pgmname, "".join("{:02X}".format(to_int(x)) for x in key), len(key))) sys.stdout.write("%s - Method: %d\n" % (pgmname, method)) data = struct.pack("<I", STORAGE_MAGIC) + \ struct.pack("B", method) + \ struct.pack("B", len(uid)) + \ uid + \ struct.pack("B", len(key)) + \ key memory = hextool.Memory() memory.cursor = args.address memory += data # Save output file. if args.output is not None: hextool.save_intel_hex(memory, filename=args.output) sys.stdout.write("%s - Output file: %s\n" % (pgmname, args.output)) else: hextool.save_intel_hex(memory, filename=os.path.splitext(args.infilespec)[0] + ".hex") sys.stdout.write( "%s - Output file: %s\n" % (pgmname, os.path.splitext(args.infilespec)[0] + ".hex"))
def main(): '''Main program''' # Determine program name, for error messages. pgmname = os.path.split(sys.argv[0])[-1] # Verify python version is 3.7 or newer. if sys.version_info.major < 3 or (sys.version_info.major == 3 and sys.version_info.minor < 7): print( f"{pgmname} ERROR: Python version {sys.version_info.major}.{sys.version_info.minor} not supported" ) return -1 # Determine help text width. try: help_width = int(os.environ['COLUMNS']) except (KeyError, ValueError): help_width = 80 help_width -= 2 parser = argparse.ArgumentParser( prog=pgmname, formatter_class=argparse.RawTextHelpFormatter, description=textwrap.fill( "A tool to generate a hex file to customize node for \ positioning application.")) parser.add_argument("infilespec", metavar="INFILESPEC", help="yml personalization file") parser.add_argument("--output", "-o", metavar="OUTFILESPEC", help="The output file") parser.add_argument("--layout", "-l", metavar="LAYOUTFILESPEC", help="The layout file") parser.add_argument( "--address", "-a", type=parse_address, metavar="VALUE", required=True, help="Address of the storage area ([area:app_persistent])\n" "defined in scratchpad_ini/scratchpad_<mcu>.ini file\n" "Default values per mcu are :\n" " - NRF52832 : 512000 (0x7D000)\n" " - NRF52833 : 512000 (0x7D000)\n" " - NRF52840 : 1036288 (0xFD000)\n" " - EFR32xg1x (512k) : 518144 (0x7E800)\n" " - EFR32xg1x (1024k): 1042432 (0xFE800)\n" " - EFR32xg22 (512k) : 499712 (0x7A000)\n" " - EFR32xg21 (1024k): 1024000 (0xFA000)") try: args = parser.parse_args() except (ValueError, IOError, OSError) as exc: sys.stdout.write(f"{pgmname}: {exc}\n") return -1 try: with open(args.layout, 'r') as ymllayoutfile: layout = yaml.load(ymllayoutfile, Loader=yaml.FullLoader) except yaml.YAMLError as exc: sys.stdout.write(f"{pgmname}: Error opening {args.layout} ({exc})\n") return -1 try: with open(args.infilespec, 'r') as ymlfile: cfg = yaml.load(ymlfile, Loader=yaml.FullLoader) except yaml.YAMLError as exc: sys.stdout.write( f"{pgmname}: Error opening {args.infilespec} ({exc})\n") return -1 if not check_config_against_layout(args, layout, cfg): return -1 status, data = process_layout_and_config(args, layout, cfg) if not status: return -1 memory = hextool.Memory() memory.cursor = args.address memory += data # Determine name for output file. if args.output is not None: outfilename = args.output else: outfilename = os.path.splitext(args.infilespec)[0] + ".hex" # Save output file. hextool.save_intel_hex(memory, filename=outfilename) sys.stdout.write(f"{pgmname} - Output file: {outfilename}\n")