예제 #1
0
def program_qspi(image_file, cli_programmer, serial=None, prog_prod_header=False,
                 header_config_path=None, flash_config_path=None):
    qspi_config = handle_qspi_config(header_config_path, flash_config_path)

    if qspi_config.product_id == ProductId.DA1469x_00:
        if image_file is not None:
            ui.print_title("Programming image")

            if qspi_config.update_image_address < MIN_FW_ADDRESS:
                raise RuntimeError(
                    "FW cannot be written at address lower than 0x{:X} (0x{:X} given)".format(
                        MIN_FW_ADDRESS, qspi_config.update_image_address))

            try:
                version_file = tempfile.mktemp()
                make_sw_version_file(version_file)

                try:
                    output_image = tempfile.mktemp()
                    Mkimage().da1469x(image_file, version_file, output_image)
                    cli_programmer.write_qspi(qspi_config.update_image_address, output_image,
                                              serial_port=serial, silent=False)
                finally:
                    os.remove(output_image)
            finally:
                os.remove(version_file)

        if prog_prod_header:
            ui.print_title("Programming product header")
            ui.print_message("Using configuration:\n" + qspi_config.get_config_info())
            program_product_header(qspi_config, cli_programmer, serial)
    elif qspi_config.product_id == ProductId.DA14681_01 or \
            qspi_config.product_id == ProductId.DA14683_00:
        if prog_prod_header:
            ui.print_message("Product header can be programmed only on DA1469x-00 boards. Skipped.")

        if image_file is not None:
            ui.print_title("Programming image")
            cli_programmer.write_qspi_exec(image_file=image_file, serial_port=serial, silent=False)

    else:
        raise RuntimeError("No supported device selected ({})".format(qspi_config.product_id))

    if image_file is None and prog_prod_header is False:
        ui.print_message("No image, no header selected. Nothing to do.")
예제 #2
0
def secure_keys_prog(secure_cfg_file, keys_file, cli_programmer, serial=None):
    # Report contains all steps in the order of their execution
    report = OrderedDict([(STEP_CONFIG_FILE_CHECK, STATUS_NOT_RUN),
                          (STEP_CHECK_PROD_ID, STATUS_NOT_RUN),
                          (STEP_KEY_VERIFICATION, STATUS_NOT_RUN),
                          (STEP_OTP_CHECK, STATUS_NOT_RUN),
                          (STEP_KEY_MATCHING, STATUS_NOT_RUN),
                          (STEP_KEY_WRITING, STATUS_NOT_RUN),
                          (STEP_READ_REV_KEYS, STATUS_NOT_RUN),
                          (STEP_CS_WRITE, STATUS_NOT_RUN)])

    if secure_cfg_file is None:
        secure_cfg_file = DEFAULT_SECURE_CFG_FILE

    if keys_file is None:
        keys_file = DEFAULT_PRODUCT_KEYS_FILE

    if not os.path.exists(secure_cfg_file) or not os.path.exists(keys_file):
        secure_keys_cfg(configuration_file=secure_cfg_file,
                        keys_file=keys_file,
                        prod_id=ProductId.DA1469x_00)

    secure_cfg = SecurityConfig(secure_cfg_file)
    product_keys = ProductKeys(keys_file)

    if not secure_cfg.is_valid():
        msg = 'Secure configuration is not valid.'
        report[STEP_CONFIG_FILE_CHECK] = [STATUS_FAIL, msg]
        __print_report(report)
        raise RuntimeError(msg)

    if not product_keys.is_valid(secure_cfg.product_id):
        msg = 'Product keys file is not valid.'
        report[STEP_CONFIG_FILE_CHECK] = [STATUS_FAIL, msg]
        __print_report(report)
        raise RuntimeError(msg)

    report[STEP_CONFIG_FILE_CHECK] = STATUS_PASS
    ui.print_message('Using product keys file: {}'.format(
        os.path.normpath(keys_file)))
    ui.print_message('Using secure configuration file: {}'.format(
        os.path.normpath(secure_cfg_file)))

    if secure_cfg.product_id != ProductId.DA1469x_00:
        report[STEP_CHECK_PROD_ID] = [
            STATUS_FAIL, 'Passed ID: {}'.format(secure_cfg.product_id)
        ]
        __print_report(report)
        raise RuntimeError(
            'This script could be run only for {} ({} selected)'.format(
                ProductId.DA1469x_00.value, secure_cfg.product_id))

    report[STEP_CHECK_PROD_ID] = STATUS_PASS
    ui.print_title('Programming product keys')
    write_product_keys(cli_programmer, serial, product_keys, report)

    ui.print_title('Checking key revocation status')
    status = __read_keys_revocation_status(cli_programmer, serial)
    report[STEP_READ_REV_KEYS] = \
        [STATUS_PASS,
         'Revoked signature keys: {}'.format(status[AREA_ADDRESS_SIGNATURE_KEYS_INDEX]),
         'Revoked user data keys: {}'.format(status[AREA_ADDRESS_USER_DATA_ENCRYPTION_KEYS_INDEX]),
         'Revoked FW decryption keys: {}'.format(status[AREA_ADDRESS_FW_DECRYPTION_KEYS_INDEX])]

    if secure_cfg.cs_enable_secure_boot is True:
        ui.print_title('Programming SECURE_BOOT_REG in configuration script')
        if report[STEP_KEY_VERIFICATION] != STATUS_PASS:
            report[STEP_CS_WRITE] = [
                STATUS_NOT_RUN, 'Product keys are not valid.'
            ]
        elif report[STEP_KEY_MATCHING] == STATUS_FAIL:
            report[STEP_CS_WRITE] = [
                STATUS_NOT_RUN, 'Product keys from file do not match to the '
                'keys read from OTP.'
            ]
        elif report[STEP_KEY_WRITING] == STATUS_FAIL:
            report[STEP_CS_WRITE] = [
                STATUS_NOT_RUN, 'Product keys writing failed.'
            ]
        else:
            report[STEP_CS_WRITE] = write_configuration_script(
                cli_programmer, serial)
    else:
        report[STEP_CS_WRITE] = [
            STATUS_NOT_RUN, 'Feature not enabled in configuration'
        ]

    __print_report(report)
예제 #3
0
def initial_flash(binary,
                  bootloader=None,
                  nobootloader=None,
                  cfg=None,
                  device_id=None,
                  jlink_path=None,
                  secure_config=None,
                  keys=None,
                  prod_id=None):

    config = ProgramQspiConfig()
    if prod_id is None:
        if config.is_valid():
            prod_id = config.product_id
        else:
            raise RuntimeError(
                'Product ID was not passed and the configuration file is not valid.'
            )

    if not device_id:
        device_id = select_jlink_serial(jlink_path)

    cli = CliProgrammer(cfg_path=cfg, prod_id=prod_id)

    if not cfg:
        prepare_local_ini_file(cfg=cli.get_cfg(),
                               prod_id=prod_id,
                               device_id=device_id,
                               jlink_path=jlink_path)

    if not os.path.exists(binary):
        raise RuntimeError('Binary file {} does not exist'.format(binary))

    if secure_config is not None and not os.path.exists(secure_config):
        raise RuntimeError(
            'Configuration file {} does not exist.\n'
            'Run secure_keys_cfg.py to create one'.format(secure_config))

    if secure_config and not keys:
        raise RuntimeError(
            'Product keys file not passed - secure image cannot be created.')

    ui.print_message('Using SDK from {}'.format(SDK_ROOT))
    ui.print_message('cli_programmer from {}'.format(cli.get_path()))
    ui.print_message('image file {}'.format(binary))

    if prod_id == ProductId.DA1469x_00:
        ui.print_title('Erasing product header area')
        cli.erase_qspi(0, 4096)

        ui.print_title('Erasing partition table')
        cli.erase_qspi(NVMS_PARTITION_TABLE, 4096)

        program_qspi(binary, cli, prog_prod_header=True)

    elif prod_id == ProductId.DA14683_00 or prod_id == ProductId.DA14681_01:
        if not (bootloader or nobootloader):
            bootloader_bin = 'ble_suota_loader.bin'
            suota_build_config = \
                prod_id.value + '-Release_' + ('OTP_Secure' if secure_config else 'QSPI')
            bootloader = os.path.join(SUOTA_LOADER_PATH, suota_build_config,
                                      bootloader_bin)
            ui.print_message('boot loader {}'.format(bootloader))

        ui.print_title('Preparing image file {}'.format(IMAGE_FILE))

        if secure_config:
            mkimage(binary,
                    IMAGE_FILE,
                    prod_id,
                    VERSION_FILE,
                    security_config=secure_config,
                    product_keys=keys)
        else:
            mkimage(binary, IMAGE_FILE, prod_id)

        if not nobootloader:
            ui.print_title('Erasing bootloader area')
            cli.erase_qspi(0, 4096)

        ui.print_title('Erasing partition table')
        cli.erase_qspi(NVMS_PARTITION_TABLE, 4096)

        ui.print_title('Writing application image {}'.format(binary))
        cli.write_qspi(NVMS_FW_EXEC_PART, binary)

        ui.print_title('Writing image header {}'.format(IMAGE_FILE))
        cli.write_qspi(NVMS_IMAGE_HEADER_PART, IMAGE_FILE, 1024)
        os.remove(IMAGE_FILE)

        if not nobootloader:
            ui.print_title('Writing bootloader')
            if secure_config:
                cli.write_otp_exec(bootloader)
            else:
                program_qspi(bootloader, cli)

        if secure_config:
            if keys:
                prod_keys = ProductKeys(keys)

                if not prod_keys.is_valid(ProductId.DA14683_00):
                    raise RuntimeError('Product key file is not valid.')

                ui.print_title("Writing symmetric keys")
                for index, key in enumerate(prod_keys.symmetric_keys):
                    cli.write_key_sym(index, key)

                ui.print_title("Writing asymmetric keys")
                for index, key in enumerate(prod_keys.asymmetric_keys):
                    cli.write_key_asym(index, key.public)

            # Write 0xAA to the product ready and the secure device field in OTP header
            cli.write_otp(PRODUCT_READY_ADDR, 1, 0xAA)
            cli.write_otp(SECURE_DEVICE_ADDR, 1, 0xAA)

        reboot_device(jlink_number=device_id, jlink_path=jlink_path)
    else:
        raise RuntimeError('Unsupported device selected ({}).'.format(prod_id))
예제 #4
0
def secure_img_prog(image_file,
                    secure_cfg_file,
                    keys_file,
                    cli_programmer,
                    serial=None,
                    header_config_path=None,
                    flash_config_path=None):
    if image_file is None or not os.path.exists(image_file):
        raise RuntimeError("Application binary file not passed or not exist")

    qspi_config = handle_qspi_config(header_config_path, flash_config_path)

    if qspi_config.product_id != ProductId.DA1469x_00:
        raise RuntimeError(
            "This script could be run only for {} ({} selected)".format(
                ProductId.DA1469x_00.value, qspi_config.product_id))

    if secure_cfg_file is None:
        secure_cfg_file = DEFAULT_SECURE_CFG_FILE

    if keys_file is None:
        keys_file = DEFAULT_PRODUCT_KEYS_FILE

    if not os.path.exists(secure_cfg_file) or not os.path.exists(keys_file):
        secure_keys_cfg(configuration_file=secure_cfg_file,
                        keys_file=keys_file,
                        prod_id=qspi_config.product_id)

    secure_cfg = SecurityConfig(secure_cfg_file)
    product_keys = ProductKeys(keys_file)

    if not secure_cfg.is_valid():
        raise RuntimeError("Secure configuration is not valid.")

    if not product_keys.is_valid(secure_cfg.product_id):
        raise RuntimeError('Product keys file is not valid.')

    ui.print_message('Using product keys file: {}'.format(
        os.path.normpath(keys_file)))
    ui.print_message('Using secure configuration file: {}'.format(
        os.path.normpath(secure_cfg_file)))

    ui.print_title("Erasing product header area")
    cli_programmer.erase_qspi(FLASH_BASE_ADDRESS,
                              PRODUCT_HEADER_SIZE,
                              serial_port=serial)

    ui.print_title("Programming image")

    try:
        version_file = tempfile.mktemp()
        make_sw_version_file(version_file)

        try:
            output_image = tempfile.mktemp()
            asym_key = product_keys.asymmetric_keys[
                secure_cfg.security_pub_key_idx]
            sym_key = product_keys.symmetric_fw_dec_keys[
                secure_cfg.security_sym_key_idx]

            Mkimage().da1469x_secure(image_file, version_file, output_image,
                                     asym_key.private,
                                     secure_cfg.security_pub_key_idx, sym_key,
                                     secure_cfg.security_sym_key_idx,
                                     secure_cfg.security_nonce,
                                     secure_cfg.make_revocation_string())

            cli_programmer.write_qspi(qspi_config.update_image_address,
                                      output_image,
                                      serial_port=serial,
                                      silent=False)
        finally:
            os.remove(output_image)
    finally:
        os.remove(version_file)

    ui.print_title("Programming product header")
    ui.print_message("Using configuration:\n" + qspi_config.get_config_info())
    program_product_header(qspi_config, cli_programmer, serial)
예제 #5
0
def program_qspi_config(product_id=None,
                        flash_config_path=None,
                        header_config_path=None,
                        flash_configuration=None,
                        default_img_addr=False):
    config = ProgramQspiConfig(header_config_path)

    if not product_id:
        if config.product_id and not confirm_configuration_change(config):
            if header_config_path:
                config.save()
                return
            else:
                raise ExecutionCanceled()

        product_id = ui.select_item(text='Select Product ID',
                                    item_list=list(PRODUCT_IDS_DICT.keys()))
        if not product_id:
            ui.print_message(
                "No valid Product ID selected.\nExecution aborted.\n")
            raise ExecutionCanceled()

        config.product_id = PRODUCT_IDS_DICT[product_id]
    else:
        config.product_id = ProductId(product_id)

    if config.product_id == ProductId.DA1469x_00:
        if not flash_config_path:
            configurations = get_flash_configurations()

        else:
            ui.print_message(
                "\nUsing flash config from {}.\n".format(flash_config_path))
            configurations = get_flash_configurations(flash_config_path)

        if not flash_configuration:
            flash_configuration = ui.select_item(
                item_list=list(configurations.keys()),
                text='Please select flash configuration')
        else:
            ui.print_message(
                "Selected flash: {}\n".format(flash_configuration))

        if not flash_configuration:
            ui.print_message(
                "No valid flash config selected.\nExecution aborted.\n")
            raise ExecutionCanceled()

        try:
            configuration = configurations[flash_configuration]
        except:
            ui.print_message(
                "Unsupported flash config selected.\nExecution aborted.\n")
            raise ExecutionCanceled()

        config.flash_name = flash_configuration
        config.flash_size = int(
            configuration[ProgramQspiConfig.FLASH_SIZE_TAG], 16)
        config.flash_burstcmda_reg_value = \
            int(configuration[ProgramQspiConfig.FLASH_BURSTCMDA_REG_VALUE_TAG], 16)
        config.flash_burstcmdb_reg_value = \
            int(configuration[ProgramQspiConfig.FLASH_BURSTCMDB_REG_VALUE_TAG], 16)
        config.flash_write_config_command = config.parse_config_command(
            configuration[ProgramQspiConfig.FLASH_WRITE_CONFIG_COMMAND_TAG])

        if default_img_addr:
            config.active_image_address = 0x2000
            config.update_image_address = 0x2000
        else:
            ui.print_title('Active FW Image Address\n')
            config.active_image_address = \
                _setup_address(ProgramQspiConfig.ACTIVE_FW_IMAGE_ADDRESS_TAG,
                               'Insert Active FW image address (hex)')

            ui.print_title('Update FW Image Address\n')
            config.update_image_address = \
                _setup_address(ProgramQspiConfig.UPDATE_FW_IMAGE_ADDRESS_TAG,
                               'Insert Update FW image address (hex)')

    config.save()