Exemple #1
0
def gen_prog_image_without_scratchpad(config, bootloader, scratchpad_data,
                                      in_files):
    '''Create a Flash memory image, ready for programming to a device.'''

    # Create a Memory object to store the Flash memory image.
    memory = hextool.Memory()

    # Add bootloader to memory image
    memory += gen_bootloader(config, bootloader)

    # Add other files to memory image.
    for in_file in in_files:
        for area in config.areas.values():
            # Add file only if bootloader knows this area.
            if area.id == in_file.area_id:
                memory.cursor = area.address

                # Sanity check.
                if area.length < len(in_file.raw_data):
                    raise ValueError("error generating programming image: \
                        file too big for area.")

                memory += in_file.raw_data

                # If flag is set need to add bl_info_header.
                if area.has_bl_info_header():
                    header = make_bl_info_header(config, scratchpad_data,
                                                 in_file)
                    memory.cursor = area.address + BL_INFO_HEADER_OFFSET
                    memory.overlap_ok = True
                    memory += header
                    memory.overlap_ok = False

    return memory
Exemple #2
0
    def get_bootloader_hex(self):
        '''Create a Bootloader memory image, with its config.'''

        # Create a Memory object to store the Flash memory image.
        memory = hextool.Memory()

        # Add bootloader to memory image
        memory += self.bootloader

        return memory
Exemple #3
0
    def gen_bootloader(self, bootloader):
        '''Create the bootloader image with its configuration (areas and keys).'''

        bl_area = self.config.get_bootloader_area()

        bl_start = bl_area.address
        bl_max_num_bytes = bl_area.length
        bl_end = bl_start + bl_max_num_bytes
        set_start = bl_area.get_settings_start_address()
        set_key_start = bl_area.get_key_start_address()
        set_end = bl_area.get_settings_end_address()

        memory = hextool.Memory()

        if bootloader.min_address < bl_start:  # DEBUG: or bootloader.max_address > bl_end:
            raise ValueError("bootloader overflows outside its area: "
                             "0x%04x .. 0x%04x, should be 0x%04x .. 0x%04x" %
                             (bootloader.min_address, bootloader.max_address,
                              bl_start, bl_end))

        # Add bootloader to the Flash memory image.
        memory.cursor = bl_start
        memory += bootloader

        # Erase keys and memory area information Flash memory image.
        del memory[set_start:set_end]

        # Set Memory cursor to point at the bootloader area settings.
        memory.cursor = set_start

        # Add memory area information in Flash memory image.
        for area in self.config.areas.values():
            data = struct.pack("<4L", area.address, area.length, area.id,
                               area.flags | (area.type << 2))
            memory += data

        # Sanity check.
        if memory.cursor > set_key_start:
            raise ValueError(
                "error generating programming image: bootloader areas")

        # Set Memory cursor to point at the bootloader key settings.
        memory.cursor = set_key_start

        # Add keys in Flash memory image.
        for key in self.config.keys.values():
            memory += key.authentication
            memory += key.encryption

        # Sanity check.
        if memory.cursor > set_end:
            raise ValueError(
                "error generating programming image: bootloader keys")

        return memory
Exemple #4
0
def main():
    '''Main program'''

    # Determine program name, for error messages.
    pgmname = os.path.split(sys.argv[0])[-1]

    # Determine help text width.
    try:
        help_width = int(os.environ['COLUMNS'])
    except (KeyError, ValueError):
        help_width = 80
    help_width -= 2

    parser = argparse.ArgumentParser(
        prog = pgmname,
        formatter_class = argparse.RawDescriptionHelpFormatter,
        description = textwrap.fill(
        "A tool to prepare EFR32 stack hex file for v4.0 to v5.0 upgrade."))

    parser.add_argument("infilespec",
        metavar = "INFILESPEC", help = "stack hex file")
    parser.add_argument("--output", "-o",
        metavar = "OUTFILESPEC",
        help = "output file")

    try:
        args = parser.parse_args()

        memory = hextool.Memory()

        hextool.load_intel_hex(memory, filename = args.infilespec)

        # Move first page off stack just before the v3 bootloader data.
        first_page = memory[memory.min_address:memory.min_address + PAGE_SIZE]
        memory.cursor = FIRST_PAGE_ADDRESS
        memory += first_page
        del memory[memory.min_address:memory.min_address + PAGE_SIZE]

        if args.output is not None:
            # Save output file.
            hextool.save_intel_hex(memory, filename=args.output)
        else:
            hextool.save_intel_hex(memory, filename=args.infilespec)

    except (ValueError, IOError, OSError) as exc:
        sys.stdout.write("%s: %s\n" % (pgmname, exc))

    return 0
Exemple #5
0
def gen_prog_image(config, bootloader, scratchpad_header, scratchpad_data):
    '''Create a Flash memory image, ready for programming to a device.'''

    sp_area = config.get_scratchpad_area()
    sp_max_num_bytes = sp_area.length
    # scratchpad is written by the end
    sp_end = sp_area.address + sp_area.length

    # Create a Memory object to store the Flash memory image.
    memory = hextool.Memory()

    # Calculate total scratchpad length in bytes.
    sp_num_bytes = sum(map(len, scratchpad_data))

    if sp_num_bytes > sp_max_num_bytes:
        raise ValueError("scratchpad too big by %d bytes" %
                         (sp_num_bytes - sp_max_num_bytes))

    # Add bootloader to memory image
    memory += gen_bootloader(config, bootloader)

    # Set Memory cursor to point at the first byte
    # of scratchpad in the Flash memory image.
    memory.cursor = (sp_end - len(SCRATCHPAD_V1_TAG) - len(scratchpad_header) -
                     sp_num_bytes)

    # Add scratchpad to the Flash memory image.
    for data in scratchpad_data:
        memory += data

    # Add a scratchpad header at the end, followed by a 16-byte tag
    # for finding the scratchpad in Flash, to the Flash memory image.
    memory += scratchpad_header
    memory += SCRATCHPAD_V1_TAG

    # Sanity check.
    if memory.cursor != sp_end:
        raise ValueError("error generating programming image: scratchpad")

    return memory
Exemple #6
0
    def __init__(self, file_spec = None, data = None,
                 version = (0, 0, 0, 0)):
        if file_spec == None and data == None:
            raise ValueError("no data given")
        elif file_spec != None and data != None:
            raise ValueError("file_spec and data are mutually exclusive")

        # Set default values.
        self.area_id = 0x00000000
        self.version = version
        self.compressed = False
        self.encrypted = False

        if data:
            # Data given, make a copy of it.
            self.data = bytearray(data)
            self.raw_data = bytearray(data)
        else:
            # File specification given, parse it.
            version, self.area_id, filename = self.parse_file_spec(file_spec)
            self.version = self.parse_version(version)

            # Read data from file.
            memory = hextool.Memory()
            hextool.load_intel_hex(memory, filename = filename)

            if memory.num_ranges == 0:
                # No data found in file.
                raise ValueError("file contains no data: '%s'" % filename)
            elif (memory.max_address -
                  memory.min_address > self.MAX_NUM_BYTES_PER_FILE):
                raise ValueError("file too big: '%s'" % filename)

            # Convert Memory object to a flat bytearray.
            self.data = memory[memory.min_address:memory.max_address]
            self.raw_data = memory[memory.min_address:memory.max_address]

        # Create a file header for uncompressed, unencrypted data.
        self.header = self.make_file_header(self.area_id, len(self.data),
                                            *self.version)
Exemple #7
0
def main():
    '''Main program'''

    # Determine program name, for error messages.
    pgmname = os.path.split(sys.argv[0])[-1]

    # Create a parser for parsing the command line and printing error messages.
    parser = create_argument_parser(pgmname)

    try:
        # Parse command line arguments.
        args = parse_arguments(parser)

        # Parse configuration file.
        config = BootloaderConfig.from_ini_files(args.configfile, args.symbols)

        # Check that config is valid
        # ValueError exception will be raised in case of invalid config
        config.check_config()

        # Check the key chosen is declared
        try:
            chosenkey = config.keys[args.keyname]
        except KeyError:
            raise ValueError("key not found: '%s'" % args.keyname)

    except (ValueError, IOError, OSError, configparser.Error) as exc:
        sys.stdout.write("%s: %s\n" % (pgmname, exc))
        return 1

    if False:
        # DEBUG: Show config.
        for key in config.keys.items():
            print(key)

    # Create a Memory object for storing the bootloader.
    bootloader = hextool.Memory()

    if args.bootloader:
        # Read bootloader.
        hextool.load_intel_hex(bootloader, filename=args.bootloader)

    in_files = []  # List of InFile objects
    # (header, area_id, version, data)
    scratchpad_data = []  # List of scratchpad data blocks
    ver_major, ver_minor, ver_maint, ver_devel = (0, 0, 0, 0)

    if AES_TEST:
        # Run AES test. See aes_test1() in utils/aes.c for details.
        in_files.append(InFile(data=test_data))
        scratchpad_data.append(test_icb)
    elif CMAC_TEST:
        # Run CMAC / OMAC1 test. See aes_omac1_test1()
        # in utils/aes.c for details.
        scratchpad_data.append(test_data)
    else:
        # Read input files.
        try:
            for file_spec in args.infilespec:
                # Create an InFile object.
                in_file = InFile(file_spec=file_spec,
                                 version=(0, 0, 0, args.otapseq))

                # Compress data in-place.
                in_file.compress()

                in_files.append(in_file)
        except (ValueError, IOError, OSError) as exc:
            sys.stdout.write("%s: %s\n" % (pgmname, exc))
            return 1

        # Create secure header, which is also the initial counter block (ICB).
        secure_header = get_random_bytes(16)
        scratchpad_data.append(secure_header)

    if not CMAC_TEST:
        try:
            # Create an AES Counter (CTR) mode cipher using secure
            # header as the 16-byte initial counter block (ICB).
            cipher = create_cipher(secure_header, chosenkey.encryption)

            # Encrypt each input file.
            for in_file in in_files:
                # Encrypt data in-place.
                in_file.encrypt(cipher)

                # Add file header to scratchpad data.
                scratchpad_data.append(in_file.header)

                # Add compressed, encrypted file data to scratchpad data.
                scratchpad_data.append(in_file.data)
        except ValueError as exc:
            sys.stdout.write("%s: %s\n" % (pgmname, exc))
            return 1

    # Calculate and add CMAC / OMAC1 tag.
    try:
        cmac = calculate_cmac(scratchpad_data, chosenkey.authentication)
        scratchpad_data.insert(0, cmac)
    except ValueError as exc:
        sys.stdout.write("%s: %s\n" % (pgmname, exc))
        return 1

    if not AES_TEST and not CMAC_TEST:
        # Create a scratchpad header.
        try:
            scratchpad_header = make_scratchpad_header(args.otapseq,
                                                       scratchpad_data)
        except ValueError as exc:
            sys.stdout.write("%s: %s\n" % (pgmname, exc))
            return 1
    else:
        scratchpad_header = bytes()

    # Write output file and optionally the programming image file.
    try:
        with open(args.outfile, "wb") as f:
            # A combi scratchpad file starts with a 16-byte tag.
            f.write(SCRATCHPAD_V1_TAG)

            # Combi scratchpad files have the scratchpad header in front of
            # the scratchpad contents. The firmware rearranges the data in
            # Flash memory while storing the scratchpad.
            f.write(scratchpad_header)

            # Write scratchpad contents.
            for data in scratchpad_data:
                f.write(data)

        if args.genprog == None:
            return 0

        # Combine bootloader, memory area specification, keys and scratchpad.
        file_without_scr = args.genprog.rsplit('.',1)[0] + \
                           "_without_scratchpad.hex"

        if config.is_scratchpad_internal():
            # Generate a programming image (bootloader + scratchpad file)
            # and save it as Intel HEX.
            memory = gen_prog_image(config, bootloader, scratchpad_header,
                                    scratchpad_data)
            hextool.save_intel_hex(memory, filename=args.genprog)

            # Also generate a programming image without scratchpad
            # (bl+stack+app) for debug purposes and save it as Intel HEX.
            memory = gen_prog_image_without_scratchpad(config, bootloader,
                                                       scratchpad_data,
                                                       in_files)
            hextool.save_intel_hex(memory, filename=file_without_scr)

        else:  # config.is_scratchpad_internal():
            # Generate a programming image without scratchpad (bl+stack+app).
            # and save it as Intel HEX.
            memory = gen_prog_image_without_scratchpad(config, bootloader,
                                                       scratchpad_data,
                                                       in_files)
            hextool.save_intel_hex(memory, filename=file_without_scr)

    except (ValueError, IOError, OSError) as exc:
        sys.stdout.write("%s: %s\n" % (pgmname, exc))
        return 1

    return 0
Exemple #8
0
def main():
    '''Main program'''
    # Determine program name, for error messages.
    pgmname = os.path.split(sys.argv[0])[-1]

    # Determine help text width.
    try:
        help_width = int(os.environ['COLUMNS'])
    except (KeyError, ValueError):
        help_width = 80
    help_width -= 2

    parser = argparse.ArgumentParser(
        prog=pgmname,
        formatter_class=argparse.RawTextHelpFormatter,
        description=textwrap.fill(
            "A tool to generate a hex file to customize node for \
                provisioning."))

    parser.add_argument("infilespec",
                        metavar="INFILESPEC",
                        help="yml personalization file")
    parser.add_argument("--output",
                        "-o",
                        metavar="OUTFILESPEC",
                        help="The output file")
    parser.add_argument(
        "--address",
        "-a",
        type=parse_address,
        metavar="VALUE",
        required=True,
        help="Address of the storage area ([area:app_persistent]) "
        "defined in mcu/<mcu>/ini_files/<mcu>_app.ini file\n"
        "Default values per mcu are :\n"
        " - NRF52832         :  499712  (0x7A000)\n"
        " - NRF52833         :  499712  (0x7A000)\n"
        " - NRF52840         :  1024000 (0xFA000)\n"
        " - EFR32xg1x (512k) :  503808  (0x7B000)\n"
        " - EFR32xg1x (1024k):  1028096 (0xFB000)\n"
        " - EFR32xg22 (512k) :  491520  (0x78000)\n"
        " - EFR32xg21 (768k) :  753664  (0xB8000)\n"
        " - EFR32xg21 (1024k):  1015808 (0xF8000)")

    try:
        args = parser.parse_args()

    except (ValueError, IOError, OSError) as exc:
        sys.stdout.write("%s: %s\n" % (pgmname, exc))
        return -1

    try:
        with open(args.infilespec, 'r') as ymlfile:
            cfg = yaml.load(ymlfile, Loader=yaml.FullLoader)
    except yaml.YAMLError as exc:
        sys.stdout.write("%s: Error opening %s (%s)\n" %
                         (pgmname, args.infilespec, exc))
        return -1

    try:
        uid = to_bytes(cfg['provisioning']['uid'])
        method = to_bytes(cfg['provisioning']['method'])
    except KeyError:
        sys.stdout.write("%s: UID and Method are mandatory\n" % (pgmname))
        return -1
    try:
        key = to_bytes(cfg['provisioning']['factory_key'])
    except KeyError:
        key = b''

    sys.stdout.write("%s - UID: %s (len: %d)\n" % (pgmname, uid, len(uid)))
    sys.stdout.write("%s - KEY: %s (len: %d)\n" %
                     (pgmname, "".join("{:02X}".format(to_int(x))
                                       for x in key), len(key)))
    sys.stdout.write("%s - Method: %d\n" % (pgmname, method))

    data = struct.pack("<I", STORAGE_MAGIC) + \
        struct.pack("B", method) + \
        struct.pack("B", len(uid)) + \
        uid + \
        struct.pack("B", len(key)) + \
        key

    memory = hextool.Memory()
    memory.cursor = args.address
    memory += data

    # Save output file.
    if args.output is not None:
        hextool.save_intel_hex(memory, filename=args.output)
        sys.stdout.write("%s - Output file: %s\n" % (pgmname, args.output))
    else:
        hextool.save_intel_hex(memory,
                               filename=os.path.splitext(args.infilespec)[0] +
                               ".hex")
        sys.stdout.write(
            "%s - Output file: %s\n" %
            (pgmname, os.path.splitext(args.infilespec)[0] + ".hex"))
Exemple #9
0
 def __init__(self, config, bootloader):
     self.config = config
     bl_without_config = hextool.Memory()
     hextool.load_intel_hex(bl_without_config, filename=bootloader)
     self.bootloader = self.gen_bootloader(bl_without_config)
     self.infiles = []  # List of data blocks
Exemple #10
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# hextoarray32.py - A tool to convert an hex file to an array of 32-bit numbers

import sys
import os
import struct
import hextool

LINE_INDENT = "    "
LINE_LENGTH = 72

# Open hex file and convert it to byte array
memory = hextool.Memory()
hextool.load_intel_hex(memory, filename=sys.argv[1])
# For EFR32 delete range in special registers [0xfe04000-0xfe04200]
del memory[0xfe04000:0xfe04200]
data = memory[memory.min_address:memory.max_address]

# Open outfile and write uint32 array
with open(sys.argv[2], "w") as f:
    line = LINE_INDENT

    for pos in range(0, len(data), 4):
        if pos != 0:
            line += ", "

        if len(line) >= LINE_LENGTH:
            f.write(line)
            f.write("\n")
Exemple #11
0
def main():
    '''Main program'''
    # Determine program name, for error messages.
    pgmname = os.path.split(sys.argv[0])[-1]

    # Determine help text width.
    try:
        help_width = int(os.environ['COLUMNS'])
    except (KeyError, ValueError):
        help_width = 80
    help_width -= 2

    parser = argparse.ArgumentParser(
        prog=pgmname,
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description=textwrap.fill(
            "A tool to generate a hex file to customize node for \
                provisioning."))

    parser.add_argument("infilespec",
                        metavar="INFILESPEC",
                        help="yml personalization file")
    parser.add_argument("--output",
                        "-o",
                        metavar="OUTFILESPEC",
                        help="output file")
    parser.add_argument("--address",
                        "-a",
                        type=parse_address,
                        metavar="VALUE",
                        required=True,
                        help="Storage area address")

    try:
        args = parser.parse_args()

    except (ValueError, IOError, OSError) as exc:
        sys.stdout.write("%s: %s\n" % (pgmname, exc))
        return -1

    try:
        with open(args.infilespec, 'r') as ymlfile:
            cfg = yaml.load(ymlfile, Loader=yaml.FullLoader)
    except yaml.YAMLError as exc:
        sys.stdout.write("%s: Error opening %s (%s)\n" %
                         (pgmname, args.infilespec, exc))
        return -1

    try:
        uid = to_bytes(cfg['provisioning']['uid'])
        method = to_bytes(cfg['provisioning']['method'])
    except KeyError:
        sys.stdout.write("%s: UID and Method are mandatory\n" % (pgmname))
        return -1
    try:
        key = to_bytes(cfg['provisioning']['factory_key'])
    except KeyError:
        key = b''

    sys.stdout.write("%s - UID: %s (len: %d)\n" % (pgmname, uid, len(uid)))
    sys.stdout.write("%s - KEY: %s (len: %d)\n" %
                     (pgmname, "".join("{:02X}".format(to_int(x))
                                       for x in key), len(key)))
    sys.stdout.write("%s - Method: %d\n" % (pgmname, method))

    data = struct.pack("<I", STORAGE_MAGIC) + \
        struct.pack("B", method) + \
        struct.pack("B", len(uid)) + \
        uid + \
        struct.pack("B", len(key)) + \
        key

    memory = hextool.Memory()
    memory.cursor = args.address
    memory += data

    # Save output file.
    if args.output is not None:
        hextool.save_intel_hex(memory, filename=args.output)
        sys.stdout.write("%s - Output file: %s\n" % (pgmname, args.output))
    else:
        hextool.save_intel_hex(memory,
                               filename=os.path.splitext(args.infilespec)[0] +
                               ".hex")
        sys.stdout.write(
            "%s - Output file: %s\n" %
            (pgmname, os.path.splitext(args.infilespec)[0] + ".hex"))
Exemple #12
0
def main():
    '''Main program'''

    # Determine program name, for error messages.
    pgmname = os.path.split(sys.argv[0])[-1]

    # Verify python version is 3.7 or newer.
    if sys.version_info.major < 3 or (sys.version_info.major == 3
                                      and sys.version_info.minor < 7):
        print(
            f"{pgmname} ERROR: Python version {sys.version_info.major}.{sys.version_info.minor} not supported"
        )
        return -1

    # Determine help text width.
    try:
        help_width = int(os.environ['COLUMNS'])
    except (KeyError, ValueError):
        help_width = 80
    help_width -= 2

    parser = argparse.ArgumentParser(
        prog=pgmname,
        formatter_class=argparse.RawTextHelpFormatter,
        description=textwrap.fill(
            "A tool to generate a hex file to customize node for \
                positioning application."))

    parser.add_argument("infilespec",
                        metavar="INFILESPEC",
                        help="yml personalization file")
    parser.add_argument("--output",
                        "-o",
                        metavar="OUTFILESPEC",
                        help="The output file")
    parser.add_argument("--layout",
                        "-l",
                        metavar="LAYOUTFILESPEC",
                        help="The layout file")
    parser.add_argument(
        "--address",
        "-a",
        type=parse_address,
        metavar="VALUE",
        required=True,
        help="Address of the storage area ([area:app_persistent])\n"
        "defined in scratchpad_ini/scratchpad_<mcu>.ini file\n"
        "Default values per mcu are :\n"
        " - NRF52832         : 512000  (0x7D000)\n"
        " - NRF52833         : 512000  (0x7D000)\n"
        " - NRF52840         : 1036288 (0xFD000)\n"
        " - EFR32xg1x (512k) : 518144  (0x7E800)\n"
        " - EFR32xg1x (1024k): 1042432 (0xFE800)\n"
        " - EFR32xg22 (512k) : 499712  (0x7A000)\n"
        " - EFR32xg21 (1024k): 1024000 (0xFA000)")

    try:
        args = parser.parse_args()
    except (ValueError, IOError, OSError) as exc:
        sys.stdout.write(f"{pgmname}: {exc}\n")
        return -1

    try:
        with open(args.layout, 'r') as ymllayoutfile:
            layout = yaml.load(ymllayoutfile, Loader=yaml.FullLoader)
    except yaml.YAMLError as exc:
        sys.stdout.write(f"{pgmname}: Error opening {args.layout} ({exc})\n")
        return -1

    try:
        with open(args.infilespec, 'r') as ymlfile:
            cfg = yaml.load(ymlfile, Loader=yaml.FullLoader)
    except yaml.YAMLError as exc:
        sys.stdout.write(
            f"{pgmname}: Error opening {args.infilespec} ({exc})\n")
        return -1

    if not check_config_against_layout(args, layout, cfg):
        return -1

    status, data = process_layout_and_config(args, layout, cfg)
    if not status:
        return -1

    memory = hextool.Memory()
    memory.cursor = args.address
    memory += data

    # Determine name for output file.
    if args.output is not None:
        outfilename = args.output
    else:
        outfilename = os.path.splitext(args.infilespec)[0] + ".hex"
    # Save output file.
    hextool.save_intel_hex(memory, filename=outfilename)
    sys.stdout.write(f"{pgmname} - Output file: {outfilename}\n")