Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

boards/common/qn908x: Compute the image checksum #15546

Merged
merged 1 commit into from Dec 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions boards/common/qn908x/Makefile.include
Expand Up @@ -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)
76 changes: 76 additions & 0 deletions 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 fix_checksum(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('<I', checksum))
else:
logging.info('Checksum not updated [DRY-RUN].')
logging.info('Checksum updated. Done.')
else:
logging.info('Checksum in file is already valid. Done.')


def main_func():
parser = argparse.ArgumentParser(description=__doc__)

parser.add_argument('--dry-run', action='store_true', default=False)
parser.add_argument('--quiet', action='store_true', default=False)
parser.add_argument(
'bin', help='Path to RAW binary to check/update', type=str)

args = parser.parse_args()
logging.basicConfig(
format='%(filename)s: %(message)s',
level=logging.ERROR if args.quiet else logging.INFO)

fix_checksum(args.bin, args.dry_run)


if __name__ == '__main__':
main_func()