Example #1
0
 def get_file_buf(self, filename):
     fil = open(filename, 'r')
     hexfile = IntelHex(fil)
     glog.info('Min addr >> ', hexfile.minaddr())
     assert hexfile.minaddr() == 0
     return hexfile.tobinstr()
Example #2
0
 def __init__(self, port, speed):
     port = port
     speed = speed
     self.hex = IntelHex()
     self.port = port
     self.speed = speed
Example #3
0
#see if we are preserving the mac
mac = None
if args.savemac:
    mac = jlink.make_mac_bin(None, device)
else:
    mac = jlink.make_mac_bin(args.mac, None)

if args.app:
    appStr = args.app

    #get size of app and create binary file
    filename, extension = os.path.splitext(args.app)
    appSize = 0
    if extension == '.hex':
        utils.deleteIfExists('temp.bin', None)
        ih = IntelHex(args.app)
        ih.tobinfile('temp.bin')
        appSize = os.path.getsize('temp.bin')
    else:
        appSize = os.path.getsize(args.app)
    jlink.make_bl_settings_bin(appSize)
    print(appSize)
    utils.deleteIfExists('temp.bin', None)
else:
    jlink.make_bl_settings_bin(0)

#validate existence of all necessary binary files; application validated earlier in script

if cfg.softdevice.compatible == 'True':
    if not os.path.exists(softdeviceStr):
        if args.softdevice != 'none':
Example #4
0
 def __init__(self, filename):
     """Opens a file by mmmap() for use within GoodHex."""
     from intelhex import IntelHex
     self.ihex = IntelHex(filename)
     self.ihex.padding = None
Example #5
0
 def save(self, path):
     h = IntelHex()
     h.frombytes(bytes=self.payload, offset=self.base_addr)
     h.tofile(path, 'hex')
Example #6
0
 def __init__(self, out):
     self.hex = IntelHex()
     self.out = out
def brp_otp():
    global brp_otp_state
    brp_otp_state = SHA256.new(brp_otp_state).digest()
    return brp_otp_state


for i in range(0, brp_seed_iterations):
    brp_otp()
BRP_APW_odd = brp_otp()
BRP_APW = bytearray()
for b in BRP_APW_odd:
    BRP_APW.append(0xF8)
    BRP_APW.append(b)
brp_otp_state = SHA256.new(BRP_APW).digest()

ih = IntelHex()
ih.loadhex(ihexf)
all_sections = ih.segments()
print("input hex file sections:")
for sec in all_sections:
    print("0x%08X 0x%08X" % (sec[0], sec[1] - 1))

#ensure we have a single section
assert (1 == len(all_sections))

#get BRP as raw bytes (boot_rom_patch shall be position independent code)
BRP = bytearray()
for sec in all_sections:
    for i in range(sec[0], sec[1]):
        BRP.append(ih[i])
Example #8
0
def tfm_sign_image(tfm_import_path, signing_key, signing_key_1, non_secure_bin):
    SECURE_ROOT = abspath(tfm_import_path)

    secure_bin = path_join(SECURE_ROOT, 'tfm_s.bin') 
    assert os.path.isfile(secure_bin)

    non_secure_bin = abspath(non_secure_bin)
    assert os.path.isfile(non_secure_bin)

    build_dir = dirname(non_secure_bin)
    tempdir = path_join(build_dir, 'temp')
    if not isdir(tempdir):
        os.makedirs(tempdir)

    flash_layout = path_join(SECURE_ROOT, 'partition', 'flash_layout.h')

    bl2_bin = path_join(SECURE_ROOT, 'bl2.bin')
    s_bin_basename = splitext(basename(secure_bin))[0]
    ns_bin_basename = splitext(basename(non_secure_bin))[0]

    signing_key = path_join(SECURE_ROOT, 'signing_key', signing_key)
    assert os.path.isfile(signing_key)

    # Find Python 3 command name across platforms
    python3_cmd = "python3" if shutil.which("python3") is not None else "python"

    # Specify image version
    #
    # MCUboot image version format: Major.Minor.Revision+Build
    #
    # Requirements for image version:
    # 1. Major.Minor.Revision must be non-decremental when used to derive security
    #    counter (-s 'auto').
    # 2. Make Major.Minor.Revision+Build incremental to identify the firmware
    #    itself uniquely through psa_fwu_query().
    # 3. Get around MCUboot failure with:
    #    [INF] Starting bootloader
    #    [INF] Swap type: none
    #    [ERR] Failed to add Image 0 data to shared memory area
    #    [ERR] Unable to find bootable image
    #    This is because TF-M underestimates MAX_BOOT_RECORD_SZ for boot record
    #    where Major.Minor.Revision will pack into during signing. The more digits
    #    of the Major.Minor.Revision, the larger the needed boot record size. And
    #    then MCUboot errors in boot_save_boot_status().
    #
    # To meet all the above requirements, we apply the following policy:
    # 1. To not change MAX_BOOT_RECORD_SZ in TF-M, specify Major.Minor.Revision
    #    with TF-M version instead of modified Unix timestamp. This needs less digits to
    #    fit into MAX_BOOT_RECORD_SZ.
    # 2. To make Major.Minor.Revision+Build incremental, specify the Build part with
    #    modified Unix timestamp.
    # 3. To make security counter non-decremental, we can derive it from
    #    Major.Minor.Revision (-s 'auto') or explicitly specify it with modified
    #    Unix timestamp, depending on security consideration.
    #
    # NOTE: To get around Y2038 problem, we modify Unix timestamp by setting new base
    #       point. Using 32-bit unsigned integer to hold the modified Unix timestamp,
    #       it will break (wrap around) after Y2156 (2106 + 2020 - 1970).
    #       https://en.wikipedia.org/wiki/Year_2038_problem
    #
    modified_timestamp = int(datetime.now().timestamp()) - int(datetime(2020, 1, 1).timestamp())
    img_ver_major = 1       # Instead of (modified_timestamp >> 24) & 0xFF
    img_ver_minor = 4       # Instead of (modified_timestamp >> 16) & 0xFF
    img_ver_revision = 0    # Instead of modified_timestamp & 0xFFFF
    img_ver_build = modified_timestamp

    # wrapper.py command template
    cmd_wrapper = [
        python3_cmd,
        path_join(MBED_OS_ROOT, "tools", "psa", "tfm", "bin_utils", "wrapper.py"),
        "-v",
        "{}.{}.{}+{}".format(img_ver_major, img_ver_minor, img_ver_revision, img_ver_build),
        "-k",
        "SIGNING_KEY_PATH",
        "--layout",
        "IMAGE_MACRO_PATH",
        "--public-key-format",
        'full',
        "--align",
        '1',
        # Reasons for removing padding and boot magic option "--pad":
        # 1. PSA FWU API psa_fwu_install() will be responsible for writing boot magic to enable upgradeable.
        # 2. The image size gets smaller instead of slot size.
        #"--pad",
        "--pad-header",
        "-H",
        '0x400',
        "--overwrite-only",
        "-s",
        'auto', # Or modified_timestamp
        "-d",
        '(IMAGE_ID,MAJOR.MINOR.REVISION+BUILD)',
        "RAW_BIN_PATH",
        "SIGNED_BIN_PATH",
    ]
    pos_wrapper_signing_key = cmd_wrapper.index("-k") + 1
    pos_wrapper_layout = cmd_wrapper.index("--layout") + 1
    pos_wrapper_dependency = cmd_wrapper.index("-d") + 1
    pos_wrapper_raw_bin = len(cmd_wrapper) - 2
    pos_wrapper_signed_bin = len(cmd_wrapper) - 1

    # assemble.py command template
    cmd_assemble = [
        python3_cmd,
        path_join(MBED_OS_ROOT, "tools", "psa", "tfm", "bin_utils", "assemble.py"),
        "--layout",
        "IMAGE_MACRO_PATH",
        "-s",
        "SECURE_BIN_PATH",
        "-n",
        "NONSECURE_BIN_PATH",
        "-o",
        "CONCATENATED_BIN_PATH",
    ]
    pos_assemble_layout = cmd_assemble.index("--layout") + 1
    pos_assemble_secure_bin = cmd_assemble.index("-s") + 1
    pos_assemble_nonsecure_bin = cmd_assemble.index("-n") + 1
    pos_assemble_concat_bin = cmd_assemble.index("-o") + 1

    # If second signing key is passed down, go signing separately; otherwise, go signing together.
    if signing_key_1 is not None:
        signing_key_1 = path_join(SECURE_ROOT, 'signing_key', signing_key_1)
        assert os.path.isfile(signing_key_1)

        image_macros_s = path_join(SECURE_ROOT, 'partition', 'signing_layout_s_preprocessed.h')
        image_macros_ns = path_join(SECURE_ROOT, 'partition', 'signing_layout_ns_preprocessed.h')
        assert os.path.isfile(image_macros_s)
        assert os.path.isfile(image_macros_ns)

        s_signed_bin = abspath(path_join(tempdir, 'tfm_s_signed' + '.bin'))
        ns_signed_bin = abspath(path_join(tempdir, 'tfm_' + ns_bin_basename + '_signed' + '.bin'))
        signed_concat_bin = abspath(path_join(tempdir, 'tfm_s_signed_' + ns_bin_basename + '_signed_concat' + '.bin'))
        s_update_bin = abspath(path_join(build_dir, s_bin_basename + '_update' + '.bin'))
        ns_update_bin = abspath(path_join(build_dir, ns_bin_basename + '_update' + '.bin'))
        
        #1. Run wrapper to sign the secure TF-M binary
        cmd_wrapper[pos_wrapper_signing_key] = signing_key
        cmd_wrapper[pos_wrapper_layout] = image_macros_s
        cmd_wrapper[pos_wrapper_dependency] = '(1,0.0.0+0)' # Minimum version of non-secure image required for upgrading to the secure image
        cmd_wrapper[pos_wrapper_raw_bin] = secure_bin
        cmd_wrapper[pos_wrapper_signed_bin] = s_signed_bin

        retcode = run_cmd(cmd_wrapper, MBED_OS_ROOT)
        if retcode:
            raise Exception("Unable to sign " + "TF-M Secure" +
                            " binary, Error code: " + str(retcode))
            return

        #2. Run wrapper to sign the non-secure mbed binary
        cmd_wrapper[pos_wrapper_signing_key] = signing_key_1
        cmd_wrapper[pos_wrapper_layout] = image_macros_ns
        cmd_wrapper[pos_wrapper_dependency] = '(0,0.0.0+0)' # Minimum version of secure image required for upgrading to the non-secure image
        cmd_wrapper[pos_wrapper_raw_bin] = non_secure_bin
        cmd_wrapper[pos_wrapper_signed_bin] = ns_signed_bin

        retcode = run_cmd(cmd_wrapper, MBED_OS_ROOT)
        if retcode:
            raise Exception("Unable to sign " + "TF-M Secure" +
                            " binary, Error code: " + str(retcode))
            return

         #3. Concatenate signed secure TF-M binary and signed non-secure mbed binary
        cmd_assemble[pos_assemble_layout] = image_macros_s
        cmd_assemble[pos_assemble_secure_bin] = s_signed_bin
        cmd_assemble[pos_assemble_nonsecure_bin] = ns_signed_bin
        cmd_assemble[pos_assemble_concat_bin] = signed_concat_bin

        retcode = run_cmd(cmd_assemble, MBED_OS_ROOT)
        if retcode:
            raise Exception("Unable to concatenate " + "Secure TF-M (signed)/Non-secure Mbed (signed)" +
                            " binaries, Error code: " + str(retcode))
            return

        #4. Concatenate MCUboot and concatenated signed secure TF-M binary/signed non-secure mbed binary
        flash_area_0_offset = find_flash_area_0_offset(flash_layout)
        out_ih = IntelHex()
        out_ih.loadbin(bl2_bin)
        out_ih.loadbin(signed_concat_bin, flash_area_0_offset)
        out_ih.tofile(splitext(non_secure_bin)[0] + ".hex", 'hex')
        out_ih.tobinfile(non_secure_bin)

        # Generate firmware update file for PSA Firmware Update
        shutil.copy(s_signed_bin, s_update_bin)
        shutil.copy(ns_signed_bin, ns_update_bin)
    else:
        image_macros_s_ns = path_join(SECURE_ROOT, 'partition', 'signing_layout_preprocessed.h')
        assert os.path.isfile(image_macros_s_ns)

        concat_bin = abspath(path_join(tempdir, 'tfm_s_' + ns_bin_basename + ".bin"))
        concat_signed_bin = abspath(path_join(tempdir, 'tfm_s_' + ns_bin_basename + '_signed' + ".bin"))
        update_bin = abspath(path_join(build_dir, ns_bin_basename + '_update' + '.bin'))

        #1. Concatenate secure TFM and non-secure mbed binaries
        cmd_assemble[pos_assemble_layout] = image_macros_s_ns
        cmd_assemble[pos_assemble_secure_bin] = secure_bin
        cmd_assemble[pos_assemble_nonsecure_bin] = non_secure_bin
        cmd_assemble[pos_assemble_concat_bin] = concat_bin

        retcode = run_cmd(cmd_assemble, MBED_OS_ROOT)
        if retcode:
            raise Exception("Unable to concatenate " + "Secure TF-M/Non-secure Mbed" +
                            " binaries, Error code: " + str(retcode))
            return

        #2. Run wrapper to sign the concatenated binary
        cmd_wrapper[pos_wrapper_signing_key] = signing_key
        cmd_wrapper[pos_wrapper_layout] = image_macros_s_ns
        cmd_wrapper[pos_wrapper_dependency] = '(1,0.0.0+0)' # No effect for single image boot
        cmd_wrapper[pos_wrapper_raw_bin] = concat_bin
        cmd_wrapper[pos_wrapper_signed_bin] = concat_signed_bin

        retcode = run_cmd(cmd_wrapper, MBED_OS_ROOT)
        if retcode:
            raise Exception("Unable to sign " + "concatenated" +
                            " binary, Error code: " + str(retcode))
            return

        #3. Concatenate MCUboot and signed binary
        flash_area_0_offset = find_flash_area_0_offset(flash_layout)
        out_ih = IntelHex()
        out_ih.loadbin(bl2_bin)
        out_ih.loadbin(concat_signed_bin, flash_area_0_offset)
        out_ih.tofile(splitext(non_secure_bin)[0] + ".hex", 'hex')
        out_ih.tobinfile(non_secure_bin)

        # Generate firmware update file for PSA Firmware Update
        shutil.copy(concat_signed_bin, update_bin)
Example #9
0
def dfu(serial, connect_attempts, detach, dry_run, firmware):
    """Program via STMicroelectronics DFU interface.


    Enter dfu mode using `solo program aux enter-dfu` first.
    """

    import time

    from intelhex import IntelHex
    import usb.core

    dfu = solo.dfu.find(serial, attempts=connect_attempts)

    if dfu is None:
        print("No STU DFU device found.")
        if serial is not None:
            print("Serial number used: ", serial)
        sys.exit(1)

    dfu.init()

    if not dry_run:
        # The actual programming
        # TODO: move to `operations.py` or elsewhere
        ih = IntelHex()
        ih.fromfile(firmware, format="hex")

        chunk = 2048
        # Why is this unused
        # seg = ih.segments()[0]
        size = sum([max(x[1] - x[0], chunk) for x in ih.segments()])
        total = 0
        t1 = time.time() * 1000

        print("erasing...")
        try:
            dfu.mass_erase()
        except usb.core.USBError:
            # garbage write, sometimes needed before mass_erase
            dfu.write_page(0x08000000 + 2048 * 10, "ZZFF" * (2048 // 4))
            dfu.mass_erase()

        page = 0
        for start, end in ih.segments():
            for i in range(start, end, chunk):
                page += 1
                data = ih.tobinarray(start=i, size=chunk)
                dfu.write_page(i, data)
                total += chunk
                # here and below, progress would overshoot 100% otherwise
                progress = min(100, total / float(size) * 100)

                sys.stdout.write(
                    "downloading %.2f%%  %08x - %08x ...         \r" %
                    (progress, i, i + page))
                # time.sleep(0.100)

            # print('done')
            # print(dfu.read_mem(i,16))

        t2 = time.time() * 1000
        print()
        print("time: %d ms" % (t2 - t1))
        print("verifying...")
        progress = 0
        for start, end in ih.segments():
            for i in range(start, end, chunk):
                data1 = dfu.read_mem(i, 2048)
                data2 = ih.tobinarray(start=i, size=chunk)
                total += chunk
                progress = min(100, total / float(size) * 100)
                sys.stdout.write("reading %.2f%%  %08x - %08x ...         \r" %
                                 (progress, i, i + page))
                if (end - start) == chunk:
                    assert data1 == data2
        print()
        print("firmware readback verified.")

    if detach:
        dfu.prepare_options_bytes_detach()
        dfu.detach()
        print("Please powercycle the device (pull out, plug in again)")

    hot_patch_windows_libusb()
Example #10
0
    print("ERROR: incorrect arguments")
    print(
        "phyihex.py: format an ihex to match exactly physical memory map (pad with 0xFF)"
    )
    print("Usage:")
    print("phyihex.py <ihex> <start> <end> [<start> <end>]*")
    exit()

ihexf = sys.argv[1]
sections = []
for i in range(2, len(sys.argv), 2):
    start = int(sys.argv[i], 0)
    end = int(sys.argv[i + 1], 0)
    sections.append([start, end + 1])

ih = IntelHex()
iho = IntelHex()
ih.loadhex(ihexf)
all_sections = ih.segments()
print("input hex file sections:")
for sec in all_sections:
    print("0x%08X 0x%08X" % (sec[0], sec[1] - 1))

#copy all regular sections
for sec in sections:
    for i in range(sec[0], sec[1]):
        iho[i] = ih[i]

#copy start address
#print("start address: ",ih.start_addr)
iho.start_addr = ih.start_addr
Example #11
0
 def __init__(self):
     self.hexinstance = IntelHex()
#use universal address, will program any node in bootloader mode on network. Will probably break if more than one :(
    CRIS = 0x00
    NNB = 0xFF
    if not selectNode(CRIS, NNB, connection, verbose): exit(1)

    #connected, now what?

    #first, verify that this is an AT90CAN128
    #    selectMemorySpace(SIGNATURE_SPACE, CRIS, connection, verbose)

    #first, select the Flash memory space
    #    selectMemorySpace(FLASH_SPACE, CRIS, connection, verbose)
    #    selectMemoryPage(0, CRIS, connection, verbose)

    #now, read the HEX file, and start writing
    ih = IntelHex(hexfile)
    address = ih.minaddr()
    max = ih.maxaddr()
    if (max > 0xFFFF):  #have to do this in two pages
        max = 0xFFFF

    #now, start programming
    eraseMemory(CRIS, connection, verbose)
    writeMemory(ih, ih.minaddr(), ih.minaddr(), max, CRIS, connection, verbose)
    #and now, verify
    verifyMemory(ih, CRIS, connection, verbose)

    #finally, set bootloader flag, and start application
    selectMemorySpace(EEPROM_SPACE, CRIS, connection, verbose)
    writeMemory([0x00, 0x00], 0x00, 0x0FF8, 0x0FF9, CRIS, connection, verbose)
    frame = makeframestring(CRIS, CAN_DISPLAY_DATA,
Example #13
0
 def __init__(self, filename):
     self.memory_map = IntelHex(filename)
Example #14
0
    def program_hex(self):
        # Get the nrfjprog command use to actually program self.hex_.
        self.logger.info('Flashing file: {}'.format(self.hex_))

        # What type of erase argument should we pass to nrfjprog?
        if self.erase:
            erase_arg = '--chiperase'
        else:
            if self.family == 'NRF52':
                erase_arg = '--sectoranduicrerase'
            else:
                erase_arg = '--sectorerase'

        program_commands = []

        if self.family == 'NRF53':
            # ************** HACK HACK HACK *********************
            # NCSDK-7327 workaround
            # ***************************************************

            # self.hex_ can contain code for both application core and network
            # core. Code being flashed to the network core needs to have a
            # specific argument provided to nrfjprog. If network code is found,
            # generate two new hex files, one for each core, and flash them
            # with the correct '--coprocessor' argument.
            ih = IntelHex(self.hex_)
            net_hex = IntelHex()
            app_hex = IntelHex()
            for s in ih.segments():
                if s[0] >= 0x01000000:
                    net_hex.merge(ih[s[0]:s[1]])
                else:
                    app_hex.merge(ih[s[0]:s[1]])

            wd = os.path.dirname(self.hex_)
            if len(net_hex) > 0:
                net_hex_file = os.path.join(
                    wd, 'GENERATED_CP_NETWORK_' + os.path.basename(self.hex_))
                self.logger.info(
                    "Generating CP_NETWORK hex file {}".format(net_hex_file))
                net_hex.write_hex_file(net_hex_file)

                program_net_cmd = [
                    'nrfjprog', '--program', net_hex_file, erase_arg, '-f',
                    'NRF53', '--coprocessor', 'CP_NETWORK', '--snr', self.snr
                ] + self.tool_opt
                program_commands.append(program_net_cmd)
            if len(app_hex) > 0:
                app_hex_file = os.path.join(
                    wd,
                    'GENERATED_CP_APPLICATION_' + os.path.basename(self.hex_))
                self.logger.info(
                    "Generating CP_APPLICATION hex file {}".format(
                        app_hex_file))
                app_hex.write_hex_file(app_hex_file)
                program_app_cmd = [
                    'nrfjprog', '--program', app_hex_file, erase_arg, '-f',
                    'NRF53', '--coprocessor', 'CP_APPLICATION', '--snr',
                    self.snr
                ] + self.tool_opt
                program_commands.append(program_app_cmd)
        else:
            # It's important for tool_opt to come last, so it can override
            # any options that we set here.
            program_commands.append([
                'nrfjprog', '--program', self.hex_, erase_arg, '-f',
                self.family, '--snr', self.snr
            ] + self.tool_opt)

        try:
            for command in program_commands:
                self.check_call(command)
        except subprocess.CalledProcessError as cpe:
            if cpe.returncode == UnavailableOperationBecauseProtectionError:
                if self.family == 'NRF53':
                    family_help = (
                        '  Note: your target is an nRF53; all flash memory '
                        'for both the network and application cores will be '
                        'erased prior to reflashing.')
                else:
                    family_help = (
                        '  Note: this will recover and erase all flash memory '
                        'prior to reflashing.')
                self.logger.error(
                    'Flashing failed because the target '
                    'must be recovered.\n'
                    '  To fix, run "west flash --recover" instead.\n' +
                    family_help)
            raise
def main():  # pylint: disable=too-many-locals

    # Set up a simple argument parser.
    parser = binhoArgumentParser(description="Utility for working with I2C EEPROMs")
    parser.add_argument(
        "-u", "--pullup", action="store_true", help="Enable 2.2k pullup resistors (3.3V)",
    )

    parser.add_argument(
        "-n",
        "--partnumber",
        default=None,
        help="Look up device parameters based on EEPROM manufacturer part number. These parameters can be provided \
              individually.",
    )

    parser.add_argument(
        "-f", "--frequency", default=400000, help="Max supported clock frequency of the EEPROM",
    )
    parser.add_argument(
        "-a",
        "--address",
        default=0,
        help="Offset from base address set on pins A0-A2, if present on package. Defaults to 0b000",
    )
    parser.add_argument("-c", "--capacity", default=None, type=int, help="EEPROM capacity in bytes")
    parser.add_argument("-t", "--writetime", default=0.005, type=float, help="EEPROM write cycle time")
    parser.add_argument(
        "-m",
        "--bitmask",
        default="AAA",
        help="Bitmask to determine how to use lowest three bits of EEPROM I2C Address",
    )
    parser.add_argument("-g", "--pagesize", default=None, type=int, help="EEPROM page size in bytes")

    parser.add_argument(
        "-b",
        "--blank",
        action="store_true",
        help="Check if the EEPROM is blank. No other operation will be performed.",
    )
    parser.add_argument("-e", "--erase", action="store_true", help="Erase the EEPROM before writing")
    parser.add_argument(
        "-y", "--verify", action="store_true", help="Verify the EEPROM contents after writing",
    )

    parser.add_argument(
        "-r", "--read", default=None, type=str, help="Read EEPROM data and save it to the provided file",
    )
    parser.add_argument(
        "-w", "--write", default=None, type=str, help="Write the data from the provided file to the EEPROM",
    )

    args = parser.parse_args()

    log_function = log_verbose if args.verbose else log_silent

    try:
        log_function("Trying to find a Binho host adapter...")
        device = parser.find_specified_device()

        if device.inBootloaderMode:
            print(
                "{} found on {}, but it cannot be used now because it's in DFU mode".format(
                    device.productName, device.commPort
                )
            )
            sys.exit(errno.ENODEV)

        elif device.inDAPLinkMode:
            print(
                "{} found on {}, but it cannot be used now because it's in DAPlink mode".format(
                    device.productName, device.commPort
                )
            )
            print("Tip: Exit DAPLink mode using 'binho daplink -q' command")
            sys.exit(errno.ENODEV)

        else:
            log_function("{} found on {}. (Device ID: {})".format(device.productName, device.commPort, device.deviceID))

    except DeviceNotFoundError:
        if args.serial:
            print(
                "No Binho host adapter found matching Device ID '{}'.".format(args.serial), file=sys.stderr,
            )
        else:
            print("No Binho host adapter found!", file=sys.stderr)
        sys.exit(errno.ENODEV)

    # if we fail before here, no connection to the device was opened yet.
    # however, if we fail after this point, we need to make sure we don't
    # leave the serial port open.

    try:

        t0 = time.time()  # pylint: disable=unused-variable

        ih = IntelHex()  # pylint: disable=unused-variable
        programmer = []  # pylint: disable=unused-variable
        device.operationMode = "I2C"

        if args.partnumber:
            # programmer = device.create_programmer('eeprom', device='24FC512')
            log_function("Using predefined parameters for EEPROM part number {}".format(args.partnumber.upper()))
            programmer = device.create_programmer("eeprom", device=args.partnumber.upper())

        elif args.frequency and args.capacity and args.writetime and args.bitmask and args.pagesize:
            log_function("EEPROM manually defined:")
            log_function(
                "Max Clock Frequency: {}, Base Address Offset: {}, Bitmask: {}".format(
                    args.frequency, args.address, args.bitmask
                )
            )
            log_function(
                "Capacity: {} bytes, Page Size: {} bytes, Write Cycle Time: {} s".format(
                    args.capacity, args.pagesize, args.writetime
                )
            )

            programmer = device.create_programmer(
                "eeprom",
                args.capacity,
                args.pagesize,
                bitmask=str(args.bitmask),
                slave_address=args.address,
                write_cycle_length=args.writetime,
            )

        else:
            log_function("EEPROM part number not provided, parameters must be manually supplied.")
            log_function("Flags -f, -a, -c, -t, -m, -g should be used to supply the device parameters")
            log_function("when the device part number cannot be used.")
            device.close()
            sys.exit(1)

        log_function("")

        if args.pullup:
            log_function(
                "Engaging the internal 2.2kOhm PullUp resistors. (Pulled to 3.3V). Remove the '-u' flag to rely on "
                "external resistors."
            )
            device.i2c.useInternalPullUps = True
        else:
            log_function(
                "Internal 2.2kOhm PullUp resistors are disengaged. Add the '-u' flag to engage the internal resistors."
            )
            device.i2c.useInternalPullUps = False

        log_function("")

        if args.read and args.write:
            log_function(
                "Cannot perform read and write in the same operation! Please perform these operations separately"
            )
            device.close()
            sys.exit(1)

        if args.verify and not args.write:
            log_function("Cannot perform verify without writing a file at this time.")
            device.close()
            sys.exit(1)

        if args.blank:
            log_function("Checking if the EEPROM is blank...")
            t_start = time.time()
            isBlank = programmer.blankCheck()
            t_stop = time.time()
            elapsedTime = "%.3f" % (t_stop - t_start)

            if isBlank:
                log_function("EEPROM is blank! Elapsed time: {} seconds".format(elapsedTime))
                device.close()
                sys.exit(0)
            else:
                log_function("EEPROM is NOT blank! Elapsed time: {} seconds".format(elapsedTime))
                device.close()
                sys.exit(1)

        if args.erase:
            log_function("Erasing the EEPROM...")
            te_start = time.time()
            programmer.erase()
            te_stop = time.time()
            elapsedTime = "%.3f" % (te_stop - te_start)
            log_function("EEPROM Erase completed! Elapsed time: {} seconds".format(elapsedTime))

        if args.read:
            filename, file_extension = os.path.splitext(args.read)  # pylint: disable=unused-variable

            fileFormat = "bin"
            if file_extension == ".hex":
                fileFormat = "hex"

            log_function("Reading from the EEPROM...")
            tr_start = time.time()
            programmer.readToFile(args.read, format=fileFormat)
            tr_stop = time.time()
            elapsedTime = "%.3f" % (tr_stop - tr_start)
            log_function("EEPROM Read completed! Elapsed time: {} seconds".format(elapsedTime))
            log_function("EEPROM Data saved as {} file to : {}".format(fileFormat, args.read))

        if args.write:

            filename, file_extension = os.path.splitext(args.write)

            fileFormat = "bin"
            if file_extension == ".hex":
                fileFormat = "hex"

            log_function("Writing Data to EEPROM from {} file: {}".format(fileFormat, args.write))
            tw_start = time.time()
            programmer.writeFromFile(args.write, format=fileFormat)
            tw_stop = time.time()
            elapsedTime = "%.3f" % (tw_stop - tw_start)
            log_function("EEPROM Write completed! Elapsed time: {} seconds".format(elapsedTime))

        if args.verify:

            log_function("Verifying Data written to EEPROM from {} file: {}".format(fileFormat, args.write))
            ty_start = time.time()
            programmer.verifyFile(args.write, format=fileFormat)
            ty_stop = time.time()
            elapsedTime = "%.3f" % (ty_stop - ty_start)
            log_function("EEPROM Verify completed! Elapsed time: {} seconds".format(elapsedTime))

        # close the connection to the host adapter
        device.close()

    except Exception:  # pylint: disable=broad-except
        # Catch any exception that was raised and display it
        binho_error_hander()

        # close the connection to the host adapter
        device.close()
Example #16
0
from intelhex import IntelHex

parser = argparse.ArgumentParser(
    description='Convert Intel hex file to human-readable hex dump')

parser.add_argument('input',
                    type=argparse.FileType('r'),
                    help='input file in Intel hex format')

parser.add_argument('-o',
                    '--output',
                    type=argparse.FileType('w'),
                    default=sys.stdout,
                    help='hex dump output file')

args = parser.parse_args()

data = IntelHex().read(args.input, max_size=256)
l = len(data)
bpl = 16
for la in range(0, l, bpl):
    if la > 0 and la % (4 * bpl) == 0:
        print(file=args.output)
    print('%04x:' % la, file=args.output, end='')
    for j in range(bpl):
        if la + j < l:
            if j > 0 and j % 4 == 0:
                print(' ', file=args.output, end='')
            print(' %02x' % data[la + j], file=args.output, end='')
    print(file=args.output)

def parse_args():
    parser = argparse.ArgumentParser(
        description="Hash data from file.",
        formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument(
        "--infile",
        "-i",
        "--in",
        "-in",
        required=True,
        help=
        "Hash the contents of the specified file. If a *.hex file is given, the contents will "
        "first be converted to binary, with all non-specified area being set to 0xff. "
        "For all other file types, no conversion is done.")
    return parser.parse_args()


if __name__ == "__main__":
    args = parse_args()

    if args.infile.endswith('.hex'):
        ih = IntelHex(args.infile)
        ih.padding = 0xff  # Allows hashing with empty regions
        to_hash = ih.tobinstr()
    else:
        to_hash = open(args.infile, 'rb').read()
    sys.stdout.buffer.write(hashlib.sha256(to_hash).digest())
Example #18
0
def update_device(device, firmware, logger, cancellation_token):
    """
    Updates the specified device with the specified firmware.
    The device passed to this function can either be in
    normal mode or in DFU mode.
    The firmware should be an instance of Firmware or None.
    If firmware is None, the newest firmware for the device is
    downloaded from GitHub releases.
    """

    if isinstance(device, usb.core.Device):
        serial_number = device.serial_number
        dfudev = DfuDevice(device)
        if (logger._verbose):
            logger.debug("OTP:")
            dump_otp(dfudev)

        # Read hardware version from one-time-programmable memory
        otp_sector = [s for s in dfudev.sectors if s['name'] == 'OTP Memory' and s['addr'] == 0x1fff7800][0]
        otp_data = dfudev.read_sector(otp_sector)
        if otp_data[0] == 0:
            otp_data = otp_data[16:]
        if otp_data[0] == 0xfe:
            hw_version = (otp_data[3], otp_data[4], otp_data[5])
        else:
            hw_version = (0, 0, 0)
    else:
        serial_number = device.__channel__.usb_device.serial_number
        dfudev = None

        # Read hardware version as reported from firmware
        hw_version_major = device.hw_version_major if hasattr(device, 'hw_version_major') else 0
        hw_version_minor = device.hw_version_minor if hasattr(device, 'hw_version_minor') else 0
        hw_version_variant = device.hw_version_variant if hasattr(device, 'hw_version_variant') else 0
        hw_version = (hw_version_major, hw_version_minor, hw_version_variant)

    if hw_version < (3, 5, 0):
        print("  DFU mode is not supported on board version 3.4 or earlier.")
        print("  This is because entering DFU mode on such a device would")
        print("  break the brake resistor FETs under some circumstances.")
        print("Warning: DFU mode is not supported on ODrives earlier than v3.5 unless you perform a hardware mod.")
        if not odrive.utils.yes_no_prompt("Do you still want to continue?", False):
            raise OperationAbortedException()

    fw_version_major = device.fw_version_major if hasattr(device, 'fw_version_major') else 0
    fw_version_minor = device.fw_version_minor if hasattr(device, 'fw_version_minor') else 0
    fw_version_revision = device.fw_version_revision if hasattr(device, 'fw_version_revision') else 0
    fw_version_prerelease = device.fw_version_prerelease if hasattr(device, 'fw_version_prerelease') else True
    fw_version = (fw_version_major, fw_version_minor, fw_version_revision, fw_version_prerelease)

    print("Found ODrive {} ({}) with firmware {}{}".format(
                serial_number,
                get_hw_version_string(hw_version),
                get_fw_version_string(fw_version),
                " in DFU mode" if dfudev is not None else ""))

    if firmware is None:
        if hw_version == (0, 0, 0):
            if dfudev is None:
                suggestion = 'You have to manually flash an up-to-date firmware to make automatic checks work. Run `odrivetool dfu --help` for more info.'
            else:
                suggestion = 'Run "make write_otp" to program the board version.'
            raise Exception('Cannot check online for new firmware because the board version is unknown. ' + suggestion)
        print("Checking online for newest firmware...", end='')
        firmware = get_newest_firmware(hw_version)
        if firmware is None:
            raise Exception("could not find any firmware release for this board version")
        print(" found {}".format(get_fw_version_string(firmware.fw_version)))

    if firmware.fw_version <= fw_version:
        print()
        if firmware.fw_version < fw_version:
            print("Warning: you are about to flash firmware {} which is older than the firmware on the device ({}).".format(
                    get_fw_version_string(firmware.fw_version),
                    get_fw_version_string(fw_version)))
        else:
            print("You are about to flash firmware {} which is the same version as the firmware on the device ({}).".format(
                    get_fw_version_string(firmware.fw_version),
                    get_fw_version_string(fw_version)))
        if not odrive.utils.yes_no_prompt("Do you want to flash this firmware anyway?", False):
            raise OperationAbortedException()

    # load hex file
    # TODO: Either use the elf format or pack a custom format with a manifest.
    # This way we can for instance verify the target board version and only
    # have to publish one file for every board (instead of elf AND hex files).
    hexfile = IntelHex(firmware.get_as_hex())

    logger.debug("Contiguous segments in hex file:")
    for start, end in hexfile.segments():
        logger.debug(" {:08X} to {:08X}".format(start, end - 1))

    # Back up configuration
    if dfudev is None:
        did_backup_config = device.user_config_loaded if hasattr(device, 'user_config_loaded') else False
        if did_backup_config:
            odrive.configuration.backup_config(device, None, logger)
    elif not odrive.utils.yes_no_prompt("The configuration cannot be backed up because the device is already in DFU mode. The configuration may be lost after updating. Do you want to continue anyway?", True):
        raise OperationAbortedException()

    # Put the device into DFU mode if it's not already in DFU mode
    if dfudev is None:
        find_odrive_cancellation_token = Event(cancellation_token)
        put_into_dfu_mode(device, find_odrive_cancellation_token)
        stm_device = find_device_in_dfu_mode(serial_number, cancellation_token)
        find_odrive_cancellation_token.set()
        dfudev = DfuDevice(stm_device)

    logger.debug("Sectors on device: ")
    for sector in dfudev.sectors:
        logger.debug(" {:08X} to {:08X} ({})".format(
            sector['addr'],
            sector['addr'] + sector['len'] - 1,
            sector['name']))

    # fill sectors with data
    touched_sectors = list(populate_sectors(dfudev.sectors, hexfile))

    logger.debug("The following sectors will be flashed: ")
    for sector,_ in touched_sectors:
        logger.debug(" {:08X} to {:08X}".format(sector['addr'], sector['addr'] + sector['len'] - 1))

    # Erase
    try:
        for i, (sector, data) in enumerate(touched_sectors):
            print("Erasing... (sector {}/{})  \r".format(i, len(touched_sectors)), end='', flush=True)
            dfudev.erase_sector(sector)
        print('Erasing... done            \r', end='', flush=True)
    finally:
        print('', flush=True)

    # Flash
    try:
        for i, (sector, data) in enumerate(touched_sectors):
            print("Flashing... (sector {}/{})  \r".format(i, len(touched_sectors)), end='', flush=True)
            dfudev.write_sector(sector, data)
        print('Flashing... done            \r', end='', flush=True)
    finally:
        print('', flush=True)

    # Verify
    try:
        for i, (sector, expected_data) in enumerate(touched_sectors):
            print("Verifying... (sector {}/{})  \r".format(i, len(touched_sectors)), end='', flush=True)
            observed_data = dfudev.read_sector(sector)
            mismatch_pos = get_first_mismatch_index(observed_data, expected_data)
            if not mismatch_pos is None:
                mismatch_pos -= mismatch_pos % 16
                observed_snippet = ' '.join('{:02X}'.format(x) for x in observed_data[mismatch_pos:mismatch_pos+16])
                expected_snippet = ' '.join('{:02X}'.format(x) for x in expected_data[mismatch_pos:mismatch_pos+16])
                raise RuntimeError("Verification failed around address 0x{:08X}:\n".format(sector['addr'] + mismatch_pos) +
                                   "  expected: " + expected_snippet + "\n"
                                   "  observed: " + observed_snippet)
        print('Verifying... done            \r', end='', flush=True)
    finally:
        print('', flush=True)


    # If the flash operation failed for some reason, your device is bricked now.
    # You can unbrick it as long as the device remains powered on.
    # (or always with an STLink)
    # So for debugging you should comment this last part out.

    # Jump to application
    dfudev.jump_to_application(0x08000000)

    logger.info("Waiting for the device to reappear...")
    device = odrive.find_any("usb", serial_number,
                    cancellation_token, cancellation_token, timeout=30)

    if did_backup_config:
        odrive.configuration.restore_config(device, None, logger)
        os.remove(odrive.configuration.get_temp_config_filename(device))

    logger.success("Device firmware update successful.")
Example #19
0
                    sys.exit(1)
                if not os.path.isfile(binfile):
                    print("Unreadable file '%s'." % binfile)
                    sys.exit(1)
                checkbin(binfile)
                target.append({
                    'address': address,
                    'data': open(binfile, 'rb').read()
                })

        if options.hexfiles:
            if not IntelHex:
                print("Error: IntelHex python module could not be found")
                sys.exit(1)
            for hex in options.hexfiles:
                ih = IntelHex(hex)
                for (address, end) in ih.segments():
                    try:
                        address = address & 0xFFFFFFFF
                    except ValueError:
                        print("Address %s invalid." % address)
                        sys.exit(1)
                    target.append({
                        'address':
                        address,
                        'data':
                        ih.tobinstr(start=address, end=end - 1)
                    })

        outfile = args[0]
        device = DEFAULT_DEVICE
Example #20
0
def main(argv):
    if (len(argv) != 2 and len(argv) != 3):
        print('Usage: otam_hex.py fw.hex [resource.hex]')
        return
    fname = argv[1]
    fname_res = None
    if (len(argv) == 3):
        fname_res = argv[2]

    try:
        ih = IntelHex(fname)
        ih = None
        ih_res = None

        if (fname_res is not None):
            ih_res = IntelHex(fname)
            ih_res = None
    except:
        print('Open hex file failed:', fname, 'or resouce file error:',
              fname_res)
        print('Usage: otam_hex.py fw.hex [resource.hex]')
        return

    ih = hexf(fname)
    ih_res = []
    if (fname_res is not None):
        ih_res = hexf(fname_res)

    is_res = True
    for ihp in ih:
        if (ihp[0] == 0x1fff4000 or ihp[0] == 0x1fff4800):
            is_res = False
            break

    fname_bin = fname + '.bin'
    fp = open(fname_bin, 'wb')
    try:

        tag = 'OTAF'.encode()
        if (is_res):
            tag = 'OTAR'.encode()
        fp.write(tag)
        lval = [0, 0, 0, 0]
        lval[0] = (len(ih) + len(ih_res)) & 0xff
        fp.write(bytes(lval))

        for ihp in ih:
            #run address
            param = ihp[0]
            lval = [0, 0, 0, 0]
            lval[0] = param & 0xff
            lval[1] = (param >> 8) & 0xff
            lval[2] = (param >> 16) & 0xff
            lval[3] = (param >> 24) & 0xff
            fp.write(bytes(lval))

            #partition size
            param = len(ihp[1])
            lval = [0, 0, 0, 0]
            lval[0] = param & 0xff
            lval[1] = (param >> 8) & 0xff
            lval[2] = (param >> 16) & 0xff
            lval[3] = (param >> 24) & 0xff
            fp.write(bytes(lval))
        for ihp in ih_res:
            #run address
            param = ihp[0]
            lval = [0, 0, 0, 0]
            lval[0] = param & 0xff
            lval[1] = (param >> 8) & 0xff
            lval[2] = (param >> 16) & 0xff
            lval[3] = (param >> 24) & 0xff
            fp.write(bytes(lval))

            #partition size
            param = len(ihp[1])
            lval = [0, 0, 0, 0]
            lval[0] = param & 0xff
            lval[1] = (param >> 8) & 0xff
            lval[2] = (param >> 16) & 0xff
            lval[3] = (param >> 24) & 0xff
            fp.write(bytes(lval))

        for ihp in ih:
            fp.write(bytes(ihp[1]))

        for ihp in ih_res:
            fp.write(bytes(ihp[1]))

        fp.close()
    except:
        print('Open hex file failed:', fname)
        print('Usage: otam_hex.py fw.hex')
Example #21
0
        opts, args = getopt.gnu_getopt(argv, 'hv', ['help', 'version'])

        for o,a in opts:
            if o in ('-h', '--help'):
                print(USAGE)
                return 0
            elif o in ('-v', '--version'):
                print(VERSION)
                return 0

    except getopt.GetoptError, e:
        sys.stderr.write(str(e)+"\n")
        sys.stderr.write(USAGE+"\n")
        return 1

    if len(args) != 2:
        sys.stderr.write("ERROR: You should specify 2 files to diff.\n")
        sys.stderr.write(USAGE+"\n")
        return 1

    fname1, fname2 = args

    from intelhex import IntelHex, diff_dumps
    ih1 = IntelHex(fname1)
    ih2 = IntelHex(fname2)
    diff_dumps(ih1, ih2, name1=fname1, name2=fname2)


if __name__ == '__main__':
    sys.exit(main())
Example #22
0
pic18f2_4xk22 = PIC18F2_4XK22()
AllCpuFamily = [pic12, pic18fxx2, pic18f2xxx, pic18fxxk80, pic18f2_4xk22]

#=============  main ==========

if __name__ == '__main__':
    if len(sys.argv) is 2:
        HexFile = sys.argv[1]
    elif len(sys.argv) is 1:
        HexFile = ''
    else:
        print 'Usage: %s file.hex' % sys.argv[0]
        quit()

## load hex file if it exist
FileData = IntelHex()
if len(HexFile) > 0:
    try:
        FileData.loadhex(HexFile)
    except IOError:
        print 'Error in file "', HexFile, '"'
        quit()

PicData = FileData.todict()
print 'File "', HexFile, '" loaded'

#try to figure out the CpuId by scanning all available Cpu family
IO.Setup_Interface()

CpuId = 0
print "Scan CPU "
Example #23
0
 def load(self, path):
     ih = IntelHex(path)
     return ih.tobinarray(), ih.minaddr()
Example #24
0
    def __init__(self, path):
        """
        Read a firmware file and store its data ready for device programming.

        This class will try to guess the file type if python-magic is available.

        If python-magic indicates a plain text file, and if IntelHex is
        available, then the file will be treated as one of Intel HEX format.

        In all other cases, the file will be treated as a raw binary file.

        In both cases, the file's contents are stored in bytes for subsequent
        usage to program a device or to perform a crc check.

        Parameters:
            path -- A str with the path to the firmware file.

        Attributes:
            bytes: A bytearray with firmware contents ready to send to the
            device
        """
        self._crc32 = None
        firmware_is_hex = False

        if have_magic:
            file_type = bytearray(magic.from_file(path, True))

            # from_file() returns bytes with PY3, str with PY2. This comparison
            # will be True in both cases"""
            if file_type == b'text/plain':
                firmware_is_hex = True
                mdebug(5, "Firmware file: Intel Hex")
            elif file_type == b'application/octet-stream':
                mdebug(5, "Firmware file: Raw Binary")
            else:
                error_str = "Could not determine firmware type. Magic " \
                            "indicates '%s'" % (file_type)
                raise CmdException(error_str)
        else:
            if os.path.splitext(path)[1][1:] in self.HEX_FILE_EXTENSIONS:
                firmware_is_hex = True
                mdebug(5, "Your firmware looks like an Intel Hex file")
            else:
                mdebug(5,
                       "Cannot auto-detect firmware filetype: Assuming .bin")

            mdebug(
                10, "For more solid firmware type auto-detection, install "
                "python-magic.")
            mdebug(10, "Please see the readme for more details.")

        if firmware_is_hex:
            if have_hex_support:
                self.bytes = bytearray(IntelHex(path).tobinarray())
                return
            else:
                error_str = "Firmware is Intel Hex, but the IntelHex library " \
                            "could not be imported.\n" \
                            "Install IntelHex in site-packages or program " \
                            "your device with a raw binary (.bin) file.\n" \
                            "Please see the readme for more details."
                raise CmdException(error_str)

        with open(path, 'rb') as f:
            self.bytes = bytearray(f.read())
Example #25
0
# Copyright (C) 2015 Herbert Poetzl

import sys
import serial
import struct

from intelhex import IntelHex
from smbus import SMBus
from time import sleep
from axiom_icsp import *

tty = "/dev/ttyPS1"
sel = sys.argv[1] if len(sys.argv) > 1 else "A"
ver = "0.36"

ih = IntelHex(sys.argv[2])
ih.padding = 0xFF


def ih_data(ih, addr, count=32):
    data = []
    mask = 0xFFFF
    for n in range(count):
        l, h = ih[(addr + n) * 2], ih[(addr + n) * 2 + 1]
        val = (h << 8) | l
        mask &= val
        data.append(val)
    return data, mask


ser = serial.Serial(
Example #26
0
    def binary_hook(t_self, resources, _, binf):
        """Hook that merges the soft device with the bin file"""
        # Scan to find the actual paths of soft device
        sdf = None
        for softdevice_and_offset_entry\
            in t_self.target.EXPECTED_SOFTDEVICES_WITH_OFFSETS:
            for hexf in resources.get_file_paths(FileType.HEX):
                if hexf.find(softdevice_and_offset_entry['name']) != -1:
                    t_self.notify.debug("SoftDevice file found %s." %
                                        softdevice_and_offset_entry['name'])
                    sdf = hexf

                if sdf is not None:
                    break
            if sdf is not None:
                break

        if sdf is None:
            t_self.notify.debug("Hex file not found. Aborting.")
            return

        # Look for bootloader file that matches this soft device or bootloader
        # override image
        blf = None
        if t_self.target.MERGE_BOOTLOADER is True:
            for hexf in resources.get_file_paths(FileType.HEX):
                if hexf.find(t_self.target.OVERRIDE_BOOTLOADER_FILENAME) != -1:
                    t_self.notify.debug(
                        "Bootloader file found %s." %
                        t_self.target.OVERRIDE_BOOTLOADER_FILENAME)
                    blf = hexf
                    break
                elif hexf.find(softdevice_and_offset_entry['boot']) != -1:
                    t_self.notify.debug("Bootloader file found %s." %
                                        softdevice_and_offset_entry['boot'])
                    blf = hexf
                    break

        # Merge user code with softdevice
        from intelhex import IntelHex
        binh = IntelHex()
        _, ext = os.path.splitext(binf)
        if ext == ".hex":
            binh.loadhex(binf)
        elif ext == ".bin":
            binh.loadbin(binf, softdevice_and_offset_entry['offset'])

        if t_self.target.MERGE_SOFT_DEVICE is True:
            t_self.notify.debug("Merge SoftDevice file %s" %
                                softdevice_and_offset_entry['name'])
            sdh = IntelHex(sdf)
            sdh.start_addr = None
            binh.merge(sdh)

        if t_self.target.MERGE_BOOTLOADER is True and blf is not None:
            t_self.notify.debug("Merge BootLoader file %s" % blf)
            blh = IntelHex(blf)
            blh.start_addr = None
            binh.merge(blh)

        with open(binf.replace(".bin", ".hex"), "w") as fileout:
            binh.write_hex_file(fileout, write_start_addr=False)
Example #27
0
def bundlePackAndSign(bundleName, firmwareName, oldAesKey, newAesKey,
                      updateFileName, verbose):
    # Rather than at the beginning of the files, constants are here
    HASH_LENGH = 128 / 8  # Hash length (128 bits)
    AES_KEY_LENGTH = 256 / 8  # AES key length (256 bits)
    FW_VERSION_LENGTH = 4  # Length of the firmware version in the bundle
    AES_KEY_UPDATE_FLAG_LGTH = 1  # Length of the tag which specifies a firmware udpate
    FW_MAX_LENGTH = 28672  # Maximum firmware length, depends on size allocated to bootloader
    FLASH_SECTOR_0_LENGTH = 264 * 8  # Length in bytes of sector 0a in external flash (to change for 16Mb & 32Mb flash!)
    STORAGE_SPACE = 65536 - FLASH_SECTOR_0_LENGTH  # Uint16_t addressing space - sector 0a length (dedicated to other storage...)
    BUNDLE_MAX_LENGTH = STORAGE_SPACE - FW_MAX_LENGTH - HASH_LENGH - AES_KEY_LENGTH - FW_VERSION_LENGTH - AES_KEY_UPDATE_FLAG_LGTH

    # Robust RNG
    rng = Random.new()

    # Extracted firmware version
    firmware_version = None

    # AES Key Update Bool
    aes_key_update_bool = True

    # Check that all required files are here
    if isfile(bundleName):
        if verbose == True:
            print "Bundle file found"
    else:
        print "Couldn't find bundle file"
        return False

    if isfile(firmwareName):
        if verbose == True:
            print "Firmware file found"
    else:
        print "Couldn't find firmware file"
        return False

    # Read bundle and firmware data
    firmware = IntelHex(firmwareName)
    firmware_bin = firmware.tobinarray()
    fd = open(bundleName, 'rb')
    bundle = fd.read()
    fd.close()

    # Check that the firmware data actually starts at address 0
    if firmware.minaddr() != 0:
        print "Firmware start address isn't correct"
        return False

    # Check that the bundle & firmware data aren't bigger than they should be
    if len(bundle) > BUNDLE_MAX_LENGTH:
        print "Bundle file too long:", len(bundle), "bytes long"
        return False
    else:
        if verbose == True:
            print "Bundle file is", len(bundle), "bytes long"

    if len(firmware) > FW_MAX_LENGTH:
        print "Firmware file too long:", len(firmware), "bytes long"
        return False
    else:
        if verbose == True:
            print "Firmware file is", len(firmware), "bytes long"

    if verbose == True:
        print "Remaining space in MCU flash:", FW_MAX_LENGTH - len(
            firmware), "bytes"

    if verbose == True:
        print "Remaining space in bundle:", STORAGE_SPACE - FW_MAX_LENGTH - HASH_LENGH - AES_KEY_LENGTH - FW_VERSION_LENGTH - AES_KEY_UPDATE_FLAG_LGTH - len(
            bundle), "bytes"

    # Beta testers devices have their aes key set to 00000... and the bootloader will always perform a key update
    if oldAesKey == "0000000000000000000000000000000000000000000000000000000000000000" and newAesKey == None:
        if verbose == True:
            print "Bundle update for beta testers unit, setting 00000... as new AES key"
        newAesKey = "0000000000000000000000000000000000000000000000000000000000000000"

    # If no new aes key is specified, don't set the aes key update flag
    if newAesKey == None:
        if verbose == True:
            print "No new AES key set"
        aes_key_update_bool = False
    else:
        if verbose == True:
            print "Encrypting new AES key"

    # If needed, check the new aes key
    if aes_key_update_bool == True:
        new_aes_key = array('B', newAesKey.decode("hex"))
        if len(new_aes_key) != AES_KEY_LENGTH:
            print "Wrong New AES Key Length:", len(new_aes_key)
            return False

    # Convert & check the old aes key
    old_aes_key = array('B', oldAesKey.decode("hex"))
    if len(old_aes_key) != AES_KEY_LENGTH:
        print "Wrong Old AES Key Length:", len(oldAesKey)
        return False

    # Get version number
    for i in range(len(firmware_bin) - 3):
        if chr(firmware_bin[i]) == 'v' and \
        chr(firmware_bin[i + 1]) >= '1' and chr(firmware_bin[i + 1]) <= '9' and \
        chr(firmware_bin[i + 2]) == '.' and \
        chr(firmware_bin[i + 3]) >= '0' and chr(firmware_bin[i + 3]) <= '9':
            firmware_version = firmware_bin[i:i + 4]
            if verbose == True:
                print "Extracted firmware version:", "".join(
                    chr(firmware_version[j]) for j in range(0, 4))
            break

    # Check if we extracted the firmware version and it has the correct length
    if firmware_version == None or len(firmware_version) != FW_VERSION_LENGTH:
        print "Problem while extracting firmware version"
        return False

    # If needed, encrypt the new AES key with the old one
    if aes_key_update_bool == True:
        cipher = AES.new(old_aes_key, AES.MODE_ECB,
                         array('B', [0] * AES.block_size))  # IV ignored in ECB
        enc_password = cipher.encrypt(new_aes_key)
        if len(enc_password) != AES_KEY_LENGTH:
            print "Encoded password is too long!"
            return False
    else:
        enc_password = [255] * AES_KEY_LENGTH

    # Generate beginning of update file data: bundle | padding | firmware version | new aes key bool | firmware | padding | new aes key encoded
    update_file_data = array('B')
    update_file_data.extend(bytearray(bundle))
    update_file_data.extend(
        array('B', [0] *
              (STORAGE_SPACE - HASH_LENGH - AES_KEY_LENGTH - FW_MAX_LENGTH -
               FW_VERSION_LENGTH - AES_KEY_UPDATE_FLAG_LGTH - len(bundle))))
    update_file_data.extend(firmware_version)
    if aes_key_update_bool == True:
        update_file_data.append(255)
    else:
        update_file_data.append(0)
    update_file_data.extend(firmware.tobinarray())
    update_file_data.extend(
        array('B', [0] * (STORAGE_SPACE - HASH_LENGH - AES_KEY_LENGTH -
                          len(update_file_data))))
    update_file_data.extend(bytearray(enc_password))

    # Check length
    if len(update_file_data) != (STORAGE_SPACE - HASH_LENGH):
        print "Problem with update file length!"
        return False

    # Generate CBCMAC, IV is ZEROS
    cipher = AES.new(old_aes_key, AES.MODE_CBC, array('B',
                                                      [0] * AES.block_size))
    cbc_mac = cipher.encrypt(update_file_data)[-AES.block_size:]

    # Append it to update file data: bundle | padding | firmware version | new aes key bool | firmware | padding | new aes key encoded | cbcmac
    update_file_data.extend(bytearray(cbc_mac))

    # Check length
    if len(update_file_data) != STORAGE_SPACE:
        print "Problem with update file length!"
        return False

    # Write our update image file
    data_fd = open(updateFileName, 'wb')
    data_fd.write(update_file_data)
    data_fd.close()
    if verbose == True:
        print "Update file written!"
    return True
Example #28
0
def generateFlashAndEepromHex(originalFlashHexName, bootloaderHexName,
                              serialNumber, AESKey1, AESKey2, UIDKey, UID,
                              newFlashHexName, newEeepromHex, verbose):
    FW_MAX_LENGTH = 28672
    BL_MAX_LENGTH = 4096
    AES_KEY_LENGTH = 256 / 8
    AES_BLOCK_LENGTH = 128 / 8
    UID_REQUEST_KEY_LENGTH = 16
    UID_KEY_LENGTH = 6

    # Merged bootloader and firmware sha1 hash
    merged_fw_bl_sha1_hash = ""

    # Check for original firmware file presence
    if not os.path.isfile(originalFlashHexName):
        print "Couldn't find firmware hex file", originalFlashHexName
        return [False, merged_fw_bl_sha1_hash]

    # Check for bootloader file presence
    if not os.path.isfile(bootloaderHexName):
        print "Couldn't find bootloader hex file", bootloaderHexName
        return [False, merged_fw_bl_sha1_hash]

    # Check AES Key Length
    if len(AESKey1) != AES_KEY_LENGTH:
        print "Wrong AES Key1 length!"
        return [False, merged_fw_bl_sha1_hash]

    # Check AES Key Length
    if len(AESKey2) != AES_KEY_LENGTH:
        print "Wrong AES Key2 length!"
        return [False, merged_fw_bl_sha1_hash]

    # Check UID Req Key Length
    if len(UIDKey) != UID_REQUEST_KEY_LENGTH:
        print "Wrong UID request key length!"
        return [False, merged_fw_bl_sha1_hash]

    # Check UID Key Length
    if len(UID) != UID_KEY_LENGTH:
        print "Wrong UID key length!"
        return [False, merged_fw_bl_sha1_hash]

    # Read firmware Hex
    flashHex = IntelHex(originalFlashHexName)
    if len(flashHex) > FW_MAX_LENGTH:
        print "Firmware file too long:", len(flashHex), "bytes long"
        return [False, merged_fw_bl_sha1_hash]
    else:
        if verbose == True:
            print "Firmware file is", len(flashHex), "bytes long"

    # Get fw version number
    firmware_bin = flashHex.tobinarray()
    for i in range(len(firmware_bin) - 3):
        if chr(firmware_bin[i]) == 'v' and \
        chr(firmware_bin[i + 1]) >= '1' and chr(firmware_bin[i + 1]) <= '9' and \
        chr(firmware_bin[i + 2]) == '.' and \
        chr(firmware_bin[i + 3]) >= '0' and chr(firmware_bin[i + 3]) <= '9':
            firmware_version = firmware_bin[i:i + 4]
            if verbose == True:
                print "Extracted firmware version:", "".join(
                    chr(firmware_version[j]) for j in range(0, 4))
            break

    # Check there's nothing where we want to put the fw version number
    if flashHex[FW_MAX_LENGTH - 4] != 0xFF:
        print "No space to write fw version number inside the firmware hex!"
        return [False, merged_fw_bl_sha1_hash]

    # Write the fw version number in the last 4 bytes of the firmware hex
    flashHex[FW_MAX_LENGTH - 4] = firmware_version[0]
    flashHex[FW_MAX_LENGTH - 3] = firmware_version[1]
    flashHex[FW_MAX_LENGTH - 2] = firmware_version[2]
    flashHex[FW_MAX_LENGTH - 1] = firmware_version[3]

    # Read bootloader hex
    bootloaderHex = IntelHex(bootloaderHexName)
    if len(bootloaderHex) > BL_MAX_LENGTH:
        print "Bootloader file too long:", len(bootloaderHex), "bytes long"
        return [False, merged_fw_bl_sha1_hash]
    else:
        if verbose == True:
            print "Bootloader file is", len(bootloaderHex), "bytes long"

    # Merge firmware with bootloader
    flashHex.merge(bootloaderHex)

    # Generate hash, print it if need
    merged_fw_bl_sha1_hash = hashlib.sha1(flashHex.tobinarray()).hexdigest()
    if verbose == True:
        print "Original Firmware/Bootloader Hash:", merged_fw_bl_sha1_hash

    # Check there's nothing where we want to put the serial number
    if flashHex[0x7F7C] != 0xFF:
        print "No space to write serial number inside the bootloader hex!"
        return [False, merged_fw_bl_sha1_hash]

    # Include serial number in the hex to be flashed
    flashHex[0x7F7C] = (serialNumber >> 24) & 0x000000FF
    flashHex[0x7F7D] = (serialNumber >> 16) & 0x000000FF
    flashHex[0x7F7E] = (serialNumber >> 8) & 0x000000FF
    flashHex[0x7F7F] = (serialNumber >> 0) & 0x000000FF

    # Write production firmware file
    flashHex.tofile(newFlashHexName, format="hex")

    # Generate blank eeprom file
    eepromHex = IntelHex()
    for i in range(0x400):
        eepromHex[i] = 0xFF

    # Modify the byte in eeprom to indicate normal boot
    # Address 0: 0xDEAD, little endian
    eepromHex[0] = 0xAD
    eepromHex[1] = 0xDE
    # Address 2: 0xAB (bootloader password set)
    eepromHex[2] = 0xAB
    # Address 98: mass production boolean
    eepromHex[98] = 0xCD
    # Address 999: boolean specifiying that uid key is set
    eepromHex[999] = 0xBB
    # Address 1000: UID request key
    eepromHex[1000:1000 + UID_REQUEST_KEY_LENGTH] = UIDKey
    # Address 1016: UID key
    eepromHex[1000 + UID_REQUEST_KEY_LENGTH:1000 + UID_REQUEST_KEY_LENGTH +
              UID_KEY_LENGTH] = UID
    # Address 0x03: 32 bytes of AES key 1 + 30 first bytes of AES key 2
    eepromHex[3:3 + AES_KEY_LENGTH] = AESKey1
    eepromHex[3 + AES_KEY_LENGTH:3 + AES_KEY_LENGTH + 30] = AESKey2[0:30]
    # Last 2 bytes in EEPROM: last 2 AESKey 2 bytes
    eepromHex[0x400 - 2] = AESKey2[30]
    eepromHex[0x400 - 1] = AESKey2[31]

    # Write new eeprom file
    eepromHex.tofile(newEeepromHex, format="hex")

    # Return success and hash
    return [True, merged_fw_bl_sha1_hash]
Example #29
0
            if device_info['flash_kb'] < 64:
                send_page_data(hid_device, addr, page_data)
            else:
                send_page_data(hid_device, addr >> 8, page_data)

        # Once programming is complete, start the application via a dummy page
        # program to the page address 0xFFFF
        print("Programming complete, starting application.")
        send_page_data(hid_device, 0xFFFF, [0] * device_info['page_size'])

    finally:
        hid_device.close()


if __name__ == '__main__':
    # Load the specified HEX file
    try:
        hex_data = IntelHex(sys.argv[2])
    except:
        print("Could not open the specified HEX file.")
        sys.exit(1)

    # Retrieve the device information entry for the specified device
    try:
        device_info = device_info_map[sys.argv[1]]
    except:
        print("Unknown device name specified.")
        sys.exit(1)

    program_device(hex_data, device_info)
Example #30
0
def cmd_update(args):
    if args.reset_tty:
        sys.stdout.write("resetting to bootloader via serial\n")
        serial = Tl866Driver(args.reset_tty)
        serial.cmd_reset_to_bootloader()

        # wait for the device to show up
        devs = None
        stop_time = time.time() + 5  # timeout 5s
        while not devs and time.time() < stop_time:
            time.sleep(0.100)
            devs = driver.list_devices()

    dev = find_dev()

    report = dev.report()
    if report.status != dev.STATUS_BOOTLOADER:
        sys.stdout.write("resetting to bootloader\n")
        dev.reset()

        report = dev.report()
        if report.status != dev.STATUS_BOOTLOADER:
            sys.stderr.write("device did not reset to booloader\n")
            sys.exit(2)

    model_a = (report.model == dev.MODEL_TL866A)

    # load the firmware image
    stock = None
    image = None
    if args.stock:
        with open(args.firmware, 'rb') as source:
            stock = firmware.UpdateFile(source.read())
            image = firmware.Firmware(
                stock.a_firmware if model_a else stock.cs_firmware,
                encrypted=True,
            )
    else:
        with open(args.firmware, 'r') as source:
            hexfile = IntelHex(source)
            image = firmware.Firmware(
                hexfile.tobinstr(start=0x1800, end=0x1FBFF),
                encrypted=False,
            )

    # load encryption and erase keys
    target_key = None
    target_erase = None
    if args.keys_from:
        with open(args.keys_from, 'rb') as source:
            keyfile = firmware.UpdateFile(source.read())
            keyfw = firmware.Firmware(
                keyfile.a_firmware if model_a else keyfile.cs_firmware,
                encrypted=True,
            )
            target_key = keyfw.key
            target_erase = keyfile.a_erase if model_a else keyfile.cs_erase
    elif stock:
        target_key = image.key
        target_erase = stock.a_erase if model_a else stock.cs_erase
    else:
        target_key = firmware.KEY_A if model_a else firmware.KEY_CS
        target_erase = firmware.ERASE_A if model_a else firmware.ERASE_CS

    if not image.valid:
        raise RuntimeError("firmware image invalid")

    sys.stdout.write("erasing\n")
    dev.erase(target_erase)

    sys.stdout.write("programming\n")
    addr = 0x1800
    cryptbuf = image.encrypt(target_key)
    for off in range(0, len(cryptbuf), 80):
        dev.write(addr, 80, cryptbuf[off:off + 80])
        addr += 64

    sys.stdout.write("success!\n")

    report = dev.report()
    if report.status != dev.STATUS_NORMAL:
        sys.stdout.write("resetting to firmware\n")
        dev.reset()