def from_csv(cls, csv_contents, partitionTableOffset = None, sectorSize = None, md5Sum = True): res = PartitionTable(md5Sum) lines = csv_contents.splitlines() def expand_vars(f): f = os.path.expandvars(f) m = re.match(r'(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)', f) if m: raise InputError("unknown variable '%s'" % m.group(1)) return f for line_no in range(len(lines)): line = expand_vars(lines[line_no]).strip() if line.startswith("#") or len(line) == 0: continue try: res.append(PartitionDefinition.from_csv(line, line_no + 1, sectorSize)) except InputError as e: raise InputError("Error at line %d: %s" % (line_no + 1, e)) except Exception: raise InputError("Unexpected error parsing CSV line %d: %s" % (line_no + 1, line)) # To fill automaticaly partition offset fields, partition table offset and sector size must be know. if (not (partitionTableOffset and sectorSize)): for e in res: if (e.offset is None): raise InputError("Flash offset of the `%s' partition is empty in the CSV input file.\n" "So that the gen_partition script automaticaly calculates this offset, you must specify partition table offset (--offset) " "and flash sector size (--flash-sector-size) from the command line." % e.name) return res # fix up missing offsets last_end = partitionTableOffset + res.tableSize() # first offset after partition table last_end = binary.align(last_end, sectorSize) for e in res: if e.offset is not None and e.offset < last_end: if e == res[0]: raise InputError("CSV Error: First partition offset 0x%x overlaps end of partition table 0x%x" % (e.offset, last_end)) else: raise InputError( "CSV Error: Partitions overlap. Partition at line %d sets offset 0x%x. Previous partition ends 0x%x" % (e.line_no, e.offset, last_end)) if e.offset is None: if last_end % sectorSize != 0: last_end = binary.align(last_end, sectorSize) e.offset = last_end last_end = e.offset + e.size return res
def operationFunc(args, flash_config=None): traces.info('Build flash image') flashImage = FlashImage(sectorSize = args.blockSize, flashType = args.flashType) # # Bootloader # endOfSSBLOffset = flashImage.appendBootloader(elf = args.boot_loader) traces.info("Partition boot loader size: 0x%X" % endOfSSBLOffset) # # Partition table # traces.info("\nGenerating partition table:") # Check if the partition table is lower than free space in current SSBL flash sector if (endOfSSBLOffset + partition.MAX_PARTITION_TABLE_SIZE) > binary.align(endOfSSBLOffset, args.blockSize): partitionTableOffset = binary.align(endOfSSBLOffset, args.blockSize) traces.info( "No free space to store partition table at the end of the SSBL partition, adding padding untill the next sector 0x%X" % partitionTableOffset) flashImage.image.padToOffset(partitionTableOffset) else: partitionTableOffset = endOfSSBLOffset traces.info("Partition table offset: 0x%X" % partitionTableOffset) if flash_config and flash_config.get('content/partitions') is not None: traces.info('Partition table was provided from configuration file.') config_partitions = {} table = gen_partition.PartitionTable(md5Sum = True) offset = partitionTableOffset + partition.MAX_PARTITION_TABLE_SIZE for name, partition_config in flash_config.get('content/partitions').get_items().items(): if partition_config.get_bool('enabled'): path = partition_config.get_str('image') type_name = partition_config.get_str('type') size = os.path.getsize(path) traces.info("Creating partition (name: %s, type: %s, path: %s, offset: 0x%x, size: 0x%x" % (name, type_name, path, offset, size)) part = partition.PartitionDefinition( name = name, type = partition.DATA_TYPE, subtype = partition.SUBTYPES[partition.DATA_TYPE][type_name], size = size, offset = binary.align(offset, args.blockSize), path = path) table.append(part) offset = part.offset + part.size else: if args.partitionTable: traces.infoWithoutNewLine('Open partition table: ') tableInput = args.partitionTable.read() if gen_partition.isBinaryPartitionTable(tableInput): # Binary format traces.info('Binary table format') table = gen_partition.PartitionTable.from_binary(tableInput) else: # CSV Format traces.info('CSV table format') try: tableInput = tableInput.decode() except UnicodeDecodeError: raise InputError( '"%s" input file must be a CSV text file or partition table binary.' % args.partitionTable.name) traces.info('Parsing CSV input...') table = gen_partition.PartitionTable.from_csv(tableInput, partitionTableOffset = partitionTableOffset, sectorSize = args.blockSize, md5Sum = True) else: # Auto partitioning traces.info('Partition table was not provided, generating generic table.') table = gen_partition.PartitionTable(md5Sum = True) offset = partitionTableOffset + partition.MAX_PARTITION_TABLE_SIZE if "readfs" in args.partition.keys(): traces.info("Creating ReadFS partition") readFSSize = os.path.getsize(args.partition['readfs'].name) traces.info("ReadFS image size: 0x%X" % readFSSize) readFSPartition = partition.PartitionDefinition( name = 'readfs', type = partition.DATA_TYPE, subtype = partition.READFS_SUBTYPE, size = readFSSize, offset = binary.align(offset, args.blockSize)) table.append(readFSPartition) offset = readFSPartition.offset + readFSPartition.size # # LittleFS partition # lfsOffset = binary.align(offset, args.blockSize) if "lfs" in args.partition.keys(): # LittleFS image from CLI traces.info("Creating LittleFS partition") lfsSize = os.path.getsize(args.partition['lfs'].name) traces.info("LittleFS image size: 0x%X" % lfsSize) else: # No LittleFS image, use of remaining free space lfsSize = args.flashSize - lfsOffset traces.info("Creating an empty LittleFS partition, using the rest of the flash space: 0x%X" % lfsSize) lfsPartition = partition.PartitionDefinition( name = 'lfs', type = partition.DATA_TYPE, subtype = partition.LFS_SUBTYPE, size = lfsSize, offset = binary.align(offset, args.blockSize)) table.append(lfsPartition) offset = lfsPartition.offset + lfsPartition.size traces.info('Verifying table...') traces.info(table.to_csv(simple_formatting = False)) table.verify(partitionTableOffset = partitionTableOffset, flashSectorSize = args.blockSize, flashSize = args.flashSize) flashImage.appendPartitionTable(table) # # Writting partition images # traces.info("Dumping partition image::") if flash_config and flash_config.get('content/partitions') is not None: for p in table: if p.path: flashImage.image.padToOffset(p.offset) with open(p.path, 'rb') as p_file: flashImage.image += p_file.read() else: for p in sorted(table, key = lambda x: x.offset): if p.name in args.partition.keys(): traces.info("%s partition [%s]" % (p.name, args.partition[p.name].name)) flashImage.image.padToOffset(p.offset) flashImage.image += args.partition[p.name].read() else: traces.info("%s partition [None]" % p.name) # add padding to finish on 4 bytes align flashImage.image.padToOffset(binary.align(flashImage.getCurrentSize(), 4)) # # Write output # traces.info("\nWritting output image to %s, size %uKB." % (args.output, flashImage.getCurrentSize() / 1024)) flashImage.writeRAWImage(args.output) if args.flashStimuliFormat is not None: file_name = args.flashStimuliFile traces.info("\nWritting output stimuli to %s" %( file_name)) flashImage.writeStimuli(file_name)