From cf936d173ede270b1dc423536c4ab3c20c6d4f2e Mon Sep 17 00:00:00 2001 From: mikee47 Date: Sun, 7 Feb 2021 11:46:44 +0000 Subject: [PATCH] Add sanity check on chunks before writing to flash, critically to ensure image file fits --- .../Storage/Tools/hwconfig/hwconfig.py | 24 +++++++++++-- .../Storage/Tools/hwconfig/partition.py | 9 +++++ Sming/Components/Storage/component.mk | 36 +++++++++++-------- Sming/component.mk | 2 ++ 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/Sming/Components/Storage/Tools/hwconfig/hwconfig.py b/Sming/Components/Storage/Tools/hwconfig/hwconfig.py index 64b2c366b1..5167855c24 100644 --- a/Sming/Components/Storage/Tools/hwconfig/hwconfig.py +++ b/Sming/Components/Storage/Tools/hwconfig/hwconfig.py @@ -27,7 +27,7 @@ def main(): parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') parser.add_argument('--secure', help="Require app partitions to be suitable for secure boot", action='store_true') parser.add_argument('--part', help="Name of partition to operate on") - parser.add_argument('command', help='Action to perform', choices=['partgen', 'expr', 'validate']) + parser.add_argument('command', help='Action to perform', choices=['partgen', 'expr', 'validate', 'flashcheck']) parser.add_argument('input', help='Name of hardware configuration or path to binary partition table') parser.add_argument('output', help='Path to output file. Will use stdout if omitted.', nargs='?', default='-') parser.add_argument('expr', help='Expression to evaluate', nargs='?', default=None) @@ -35,7 +35,7 @@ def main(): args = parser.parse_args() common.quiet = args.quiet - + output = None input_is_binary = False if os.path.exists(args.input): @@ -56,6 +56,7 @@ def main(): return if args.command == 'validate': + # Validate resulting hardware configuration against schema try: from jsonschema import Draft7Validator from jsonschema.exceptions import ValidationError @@ -70,12 +71,31 @@ def main(): for e in errors: critical("%s @ %s" % (e.message, e.path)) sys.exit(3) + elif args.command == 'flashcheck': + # Expect list of chunks, such as "0x100000=/out/Esp8266/debug/firmware/spiff_rom.bin 0x200000=custom.bin" + error_count = 0 + list = args.expr.split() + if len(list) == 0: + raise InputError("No chunks to flash!") + for e in list: + addr, filename = e.split('=') + addr = int(addr, 0) + part = config.partitions.find_by_address(addr) + if part is None: + raise InputError("No partition contains address 0x%08x" % addr) + if part.address != addr: + raise InputError("Address 0x%08x is within partition '%s', not at start (0x%08x)" % (addr, part.name, part.address)) + filesize = os.path.getsize(filename) + if filesize > part.size: + raise InputError("File '%s' is 0x%08x bytes, too big for partition '%s' (0x%08x bytes)" % (os.path.basename(filename), filesize, part.name, part.size)) elif args.command == 'partgen': + # Generate partition table binary if not args.no_verify: status("Verifying partition table...") config.verify(args.secure) output = config.partitions.to_binary(config.devices) elif args.command == 'expr': + # Evaluate expression against configuration data output = str(eval(args.expr)).encode() else: raise InputError('Unknown command: %s' % args.command) diff --git a/Sming/Components/Storage/Tools/hwconfig/partition.py b/Sming/Components/Storage/Tools/hwconfig/partition.py index 1ba64daea9..018167d60a 100644 --- a/Sming/Components/Storage/Tools/hwconfig/partition.py +++ b/Sming/Components/Storage/Tools/hwconfig/partition.py @@ -198,6 +198,12 @@ def find_by_name(self, name): return p return None + def find_by_address(self, addr): + for p in self: + if p.contains(addr): + return p + return None + def verify(self, arch, secure): """Verify partition layout """ @@ -404,6 +410,9 @@ def address_str(self): def size_str(self): return size_format(self.size) + def contains(self, addr): + return addr >= self.address and addr <= self.end() + def type_str(self): return "" if self.type == 0xff else lookup_keyword(self.type, TYPES) diff --git a/Sming/Components/Storage/component.mk b/Sming/Components/Storage/component.mk index 6398fca7d6..ea241d4399 100644 --- a/Sming/Components/Storage/component.mk +++ b/Sming/Components/Storage/component.mk @@ -41,7 +41,7 @@ HWCONFIG_MK := $(PROJECT_DIR)/$(OUT_BASE)/hwconfig.mk $(shell $(HWCONFIG_TOOL) --quiet expr $(HWCONFIG) $(HWCONFIG_MK) "config.buildVars()") include $(HWCONFIG_MK) -HWEXPR := $(HWCONFIG_TOOL) $(if $(PART),--part $(PART)) expr $(HWCONFIG) - +HWEXPR := $(HWCONFIG_TOOL) $(if $(PART),--part "$(PART)") expr $(HWCONFIG) - define HwExpr $(shell $(HWEXPR) "$1") @@ -122,31 +122,32 @@ endef ##@Flashing -# $1 -> Partition name -define PartChunk -$(if $(PARTITION_$1_FILENAME),$(PARTITION_$1_ADDRESS)=$(PARTITION_$1_FILENAME)) +# Get chunks for a list of partitions, ignore any without filenames +# $1 -> List of partition names +define PartChunks +$(foreach p,$1,$(if $(PARTITION_$p_FILENAME),$(PARTITION_$p_ADDRESS)=$(PARTITION_$p_FILENAME))) endef -# $1 -> Partition name -define PartRegion -$(PARTITION_$1_ADDRESS),$(PARTITION_$1_SIZE) +# Get regions for list of partitions +# $1 -> List of partition names +define PartRegions +$(foreach p,$1,$(PARTITION_$p_ADDRESS),$(PARTITION_$p_SIZE_BYTES)) endef # One flash sector of 0xFF BLANK_BIN := $(PARTITION_PATH)/blank.bin # Just the application chunks -FLASH_APP_CHUNKS = $(foreach p,$(SPIFLASH_PARTITION_NAMES),$(if $(filter app,$(PARTITION_$p_TYPE)),$(call PartChunk,$p))) +SPIFLASH_APP_PARTITION_NAMES := $(foreach p,$(SPIFLASH_PARTITION_NAMES),$(if $(filter app,$(PARTITION_$p_TYPE)),$p)) +FLASH_APP_CHUNKS = $(call PartChunks,$(SPIFLASH_APP_PARTITION_NAMES)) # Partition map chunk FLASH_MAP_CHUNK := $(PARTITION_TABLE_OFFSET)=$(PARTITIONS_BIN) # All partitions with image files -FLASH_PARTITION_CHUNKS = $(foreach p,$(SPIFLASH_PARTITION_NAMES),$(call PartChunk,$p)) +FLASH_PARTITION_CHUNKS = $(call PartChunks,$(SPIFLASH_PARTITION_NAMES)) -ifdef PART -DEBUG_VARS += FLASH_PART_CHUNKS FLASH_PART_REGION -FLASH_PART_CHUNKS := $(call PartChunk,$(PART)) -FLASH_PART_REGION := $(call PartRegion,$(PART)) -endif +# User-selected partition(s) +FLASH_PART_CHUNKS = $(call PartChunks,$(PART)) +FLASH_PART_REGION = $(call PartRegions,$(PART)) # Where to store read partition map file READMAP_BIN := $(OUT_BASE)/partition-table.read.bin @@ -160,8 +161,15 @@ readmap:##Read partition map from device $(Q) $(HWCONFIG_TOOL) expr $(READMAP_BIN) - "config.map().to_csv()" @echo +# Run sanity checks against a list of partitions before flashing commences +# $1 -> List of partition names +define CheckPartitionChunks +$(HWCONFIG_TOOL) flashcheck $(HWCONFIG) - "$1" +endef + .PHONY: flashpart flashpart: all kill_term ##Flash a specific partition, set PART=name + $(Q) $(call CheckPartitionChunks,$(FLASH_PART_CHUNKS)) $(call WriteFlash,$(FLASH_PART_CHUNKS)) .PHONY: erasepart diff --git a/Sming/component.mk b/Sming/component.mk index 17feb9bb08..9685debd3a 100644 --- a/Sming/component.mk +++ b/Sming/component.mk @@ -159,10 +159,12 @@ flashboot: $(FLASH_BOOT_LOADER) kill_term ##Write just the Bootloader .PHONY: flashapp flashapp: all kill_term ##Write just the application image(s) + $(Q) $(call CheckPartitionChunks,$(FLASH_APP_CHUNKS)) $(call WriteFlash,$(FLASH_APP_CHUNKS)) .PHONY: flash flash: all kill_term ##Write the boot loader and all defined partition images + $(Q) $(call CheckPartitionChunks,$(FLASH_PARTITION_CHUNKS)) $(call WriteFlash,$(FLASH_BOOT_CHUNKS) $(FLASH_MAP_CHUNK) $(FLASH_PARTITION_CHUNKS)) ifeq ($(ENABLE_GDB), 1) $(GDB_CMDLINE)