diff --git a/boards/common/qn908x/Makefile.include b/boards/common/qn908x/Makefile.include index e731a314a6e1a..2cb3ff4fa34d0 100644 --- a/boards/common/qn908x/Makefile.include +++ b/boards/common/qn908x/Makefile.include @@ -14,3 +14,17 @@ OPENOCD_CONFIG ?= $(RIOTBOARD)/common/qn908x/dist/openocd.cfg # verify the image, which needs to have the WDT disabled but it is normally # enabled after a 'reset halt' command. OPENOCD_PRE_FLASH_CMDS += "-c qn908x disable_wdog" + +# In order to boot, the CPU requires that the Vector table contain a valid +# checksum in one of the "reserved" fields. We don't generate this checksum when +# compiling and linking the code, instead this make target computes the checksum +# in another ELF file and we set it as the FLASHFILE. +ELFFILE ?= $(BINDIR)/$(APPLICATION).elf +ELFFILE_CHECKSUM ?= $(ELFFILE:.elf=-checksum.elf) + +$(ELFFILE_CHECKSUM): $(ELFFILE) + $(Q)$(OBJCOPY) --dump-section .vectors=$<.vectors $< + $(Q)$(RIOTBOARD)/common/qn908x/dist/nxp_checksum.py $(if $(Q),--quiet) \ + $<.vectors + $(Q)$(OBJCOPY) --update-section .vectors=$<.vectors $< $@ +FLASHFILE ?= $(ELFFILE_CHECKSUM) diff --git a/boards/common/qn908x/dist/nxp_checksum.py b/boards/common/qn908x/dist/nxp_checksum.py new file mode 100755 index 0000000000000..3f164f1808a56 --- /dev/null +++ b/boards/common/qn908x/dist/nxp_checksum.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2020 iosabi +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +""" +NXP Vector table checksum generator for RAW binary files. + +Computes and verifies the Vector table checksum entry for the NXP QN908x +family. These MCUs need a specific checksum value in the Vector table in order +to boot. +""" + +import argparse +import logging +import struct + + +class NXPChecksumError(Exception): + """Generic tool error.""" + + +# Number of uint32_t entries that the checksum covers in the QN908X family. +# The computed checksum is stored right after these values. +CHECKSUM_ENTRIES = 7 + + +def FixChecksum(binary_name, dry_run): + with open(binary_name, 'rb' if dry_run else 'rb+') as fobj: + + checksum_fmt = '<%dI' % (CHECKSUM_ENTRIES + 1) + checksum_data_size = struct.calcsize(checksum_fmt) + data = fobj.read(checksum_data_size) + + if len(data) < checksum_data_size: + raise NXPChecksumError( + 'File %s is too small, it should have at least %d bytes' % ( + binary_name, checksum_data_size)) + + values = list(struct.unpack(checksum_fmt, data)) + checksum = (-sum(values[:-1])) % (1 << 32) + if checksum != values[-1]: + logging.info( + 'Computed checksum 0x%.8x doesn\'t match the value in the file ' + '(0x%.8x), updating...', checksum, values[-1]) + if not dry_run: + fobj.seek(checksum_data_size - 4) + fobj.write(struct.pack('