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.")
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)
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))
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)
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()