Skip to content

Commit

Permalink
Add sanity check on chunks before writing to flash, critically to ens…
Browse files Browse the repository at this point in the history
…ure image file fits
  • Loading branch information
mikee47 committed Feb 7, 2021
1 parent e24c22c commit cf936d1
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 16 deletions.
24 changes: 22 additions & 2 deletions Sming/Components/Storage/Tools/hwconfig/hwconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ 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)

args = parser.parse_args()

common.quiet = args.quiet

output = None
input_is_binary = False
if os.path.exists(args.input):
Expand All @@ -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
Expand All @@ -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)
Expand Down
9 changes: 9 additions & 0 deletions Sming/Components/Storage/Tools/hwconfig/partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
"""
Expand Down Expand Up @@ -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)

Expand Down
36 changes: 22 additions & 14 deletions Sming/Components/Storage/component.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Sming/component.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit cf936d1

Please sign in to comment.