def init_flashloader(cpu_params: CpuParams) -> McuBoot: """Load an execute flash-loader binary in i.MX-RT The function signs the flashloader if needed (if HAB enabled) :param cpu_params: processor specific parameters of the test :return: McuBoot instance to communicate with flash-loader :raises ConnectionError: if connection cannot be established """ devs = mboot_scan_usb(cpu_params.com_processor_name ) # check whether flashloader is already running if len(devs) == 0: # if flash-loader not running yet, it must be downloaded to RAM and launched flshldr_img = BootImgRT.parse( load_binary(cpu_params.data_dir, 'ivt_flashloader.bin')) devs = sdp_scan_usb(cpu_params.com_processor_name) if len(devs) != 1: raise ConnectionError('Cannot connect to ROM bootloader') with SDP(devs[0], cmd_exception=True) as sd: assert sd.is_opened try: sd.read(INT_RAM_ADDR_CODE, 4) # dummy read to receive response except SdpCommandError: # there is an exception if HAB is locked, cause read not supported pass if (sd.status_code == StatusCode.HAB_IS_LOCKED) and (sd.response_value == ResponseValue.LOCKED): auth_flshldr_img = BootImgRT(flshldr_img.address, BootImgRT.IVT_OFFSET_OTHER) _to_authenticated_image( cpu_params, auth_flshldr_img, flshldr_img.app.data, 0, flshldr_img.ivt.app_address ) # entry addr cannot be detected from img else: auth_flshldr_img = flshldr_img assert sd.write_file(auth_flshldr_img.address, auth_flshldr_img.export()) try: assert sd.jump_and_run(auth_flshldr_img.address + auth_flshldr_img.ivt_offset) except SdpCommandError: pass # SDP may return an exception if HAB locked for _ in range(10): # wait 10 sec until flash-loader is inited sleep(1) # Scan for MCU-BOOT device devs = mboot_scan_usb(cpu_params.com_processor_name) if len(devs) == 1: break if len(devs) != 1: raise ConnectionError('Cannot connect to Flash-Loader') result = McuBoot(devs[0], cmd_exception=True) result.open() assert result.is_opened result.reopen = False # reopen not supported for RT1050??? return result
def test_sb(cpu_params: CpuParams) -> None: """Test creation of SB file. :param cpu_params: processor specific parameters of the test """ # timestamp is fixed for the test, do not not for production timestamp = datetime(year=2020, month=4, day=24, hour=16, minute=33, second=32) # load application to add into SB img_name = f'{cpu_params.board}_iled_blinky_ext_FLASH_unsigned_nofcb' app_data = load_binary(cpu_params.data_dir, OUTPUT_IMAGES_SUBDIR, img_name + '.bin') boot_img = BootImgRT.parse(app_data) # parse to retrieve IVT offset sb = SecureBootV1(version=SB_FILE_VERSION, timestamp=timestamp) sect = BootSectionV1(0, SecureBootFlagsV1.ROM_SECTION_BOOTABLE) # load 0xc0233007 > 0x2000; sect.append(CmdFill(INT_RAM_ADDR_DATA, pack("<I", cpu_params.ext_flash_cfg_word0))) # enable flexspinor 0x2000; sect.append(CmdMemEnable(INT_RAM_ADDR_DATA, 4, ExtMemId.FLEX_SPI_NOR)) # erase 0x60000000..0x60100000; sect.append(CmdErase(EXT_FLASH_ADDR, align(boot_img.ivt_offset + boot_img.size, 0x1000))) # load 0xf000000f > 0x3000; sect.append(CmdFill(INT_RAM_ADDR_DATA, pack("<I", FCB_FLASH_NOR_CFG_WORD))) # enable flexspinor 0x3000; sect.append(CmdMemEnable(INT_RAM_ADDR_DATA, 4, ExtMemId.FLEX_SPI_NOR)) # load myBinFile > kAbsAddr_Ivt; app_data += b'\x49\x20\x93\x8e\x89\x8F\x43\x88' # this is random padding fixed for the test, not use for production sect.append(CmdLoad(EXT_FLASH_ADDR + boot_img.ivt_offset, app_data)) # sb.append(sect) # write_sb(cpu_params, img_name + '.sb', sb)
def write_image( cpu_params: CpuParams, image_file_name: str, img: BootImgRT, otpmk_bee_regions: Tuple[BeeFacRegion, ...] = tuple(), ) -> None: """Write image to the external flash The method behaviour depends on TEST_IMG_CONTENT: - if True (TEST MODE), the method generates the image and compare with previous version - if False (PRODUCTION), the method generates the image and burn into FLASH :param cpu_params: processor specific parameters of the test :param image_file_name: of the image to be written (including file extension) :param img: image instance to be written :param otpmk_bee_regions: optional list of BEE regions for BEE OTPMK encryption """ path = os.path.join(cpu_params.data_dir, OUTPUT_IMAGES_SUBDIR, image_file_name) debug_info = DebugInfo() # use zulu datetime for test purposes only, to produce stable output; remove the parameter for production zulu = datetime(year=2020, month=4, day=8, hour=5, minute=54, second=33, tzinfo=timezone.utc) img_data = img.export(dbg_info=debug_info, zulu=zulu) assert len(img_data) == img.size write_dbg_log(cpu_params.data_dir, image_file_name, debug_info.lines, TEST_IMG_CONTENT) if TEST_IMG_CONTENT: assert img.info() # quick check info prints non-empty output compare_bin_files(path, img_data) # compare no-padding if (NO_PADDING and img.fcb.enabled and isinstance(img.fcb, PaddingFCB) and not img.bee_encrypted): img.fcb.enabled = False compare_bin_files(path.replace(".bin", "_nopadding.bin"), img.export(zulu=zulu)) img.fcb.enabled = False # test that parse image will return same content if img.fcb.enabled and not img.bee_encrypted: compare_bin_files(path, BootImgRT.parse(img_data).export()) # test that size matches len of exported data assert img.size == len(img_data) else: with open(path, "wb") as f: f.write(img_data) if (NO_PADDING and img.fcb.enabled and isinstance(img.fcb, PaddingFCB) and not img.bee_encrypted): with open(path.replace(".bin", "_nopadding.bin"), "wb") as f: f.write(img_data[img.ivt_offset:]) if img.ivt_offset == BootImgRT.IVT_OFFSET_NOR_FLASH: _burn_image_to_flash(cpu_params, img, img_data, otpmk_bee_regions) else: assert len(otpmk_bee_regions) == 0 _burn_image_to_sd(cpu_params, img, img_data)
def test_sb_multiple_sections(cpu_params: CpuParams) -> None: """Test creation of SB file with multiple sections. :param cpu_params: processor specific parameters of the test """ if (cpu_params.id != ID_RT1050) and (cpu_params.id != ID_RT1060): return # this test case is supported only for RT1050 and RT1060 # timestamp is fixed for the test, do not not for production timestamp = datetime(year=2020, month=4, day=24, hour=15, minute=33, second=32, tzinfo=timezone.utc) # load application to add into SB img_name = f"{cpu_params.board}_iled_blinky_ext_FLASH_unsigned_nofcb" app_data = load_binary(cpu_params.data_dir, OUTPUT_IMAGES_SUBDIR, img_name + ".bin") boot_img = BootImgRT.parse(app_data) # parse to retrieve IVT offset sb = SecureBootV1(version=SB_FILE_VERSION, timestamp=timestamp) sect = BootSectionV1(0, SecureBootFlagsV1.ROM_SECTION_BOOTABLE) # load 0xc0233007 > 0x2000; sect.append( CmdFill( INT_RAM_ADDR_DATA, int.from_bytes(pack("<I", cpu_params.ext_flash_cfg_word0), "little"))) # enable flexspinor 0x2000; sect.append(CmdMemEnable(INT_RAM_ADDR_DATA, 4, ExtMemId.FLEX_SPI_NOR)) # erase 0x60000000..0x60010000; # Note: erasing of long flash region may fail on timeout # For example this fails on EVK-RT1060: sect.append(CmdErase(EXT_FLASH_ADDR, 0x100000)) sect.append(CmdErase(EXT_FLASH_ADDR, 0x10000)) # load 0xf000000f > 0x3000; sect.append( CmdFill(INT_RAM_ADDR_DATA, int.from_bytes(pack("<I", FCB_FLASH_NOR_CFG_WORD), "little"))) # enable flexspinor 0x3000; sect.append(CmdMemEnable(INT_RAM_ADDR_DATA, 4, ExtMemId.FLEX_SPI_NOR)) # load myBinFile > kAbsAddr_Ivt; app_data += b"\xdc\xe8\x6d\x5d\xe9\x8c\xf5\x7c" # this is random padding fixed for the test, not use for production sect.append(CmdLoad(EXT_FLASH_ADDR + boot_img.ivt_offset, app_data)) # sb.append(sect) # add second section, just for the test sect2 = BootSectionV1(1, SecureBootFlagsV1.ROM_SECTION_BOOTABLE) sect2.append( CmdLoad(0x6000F000, load_binary(cpu_params.srk_data_dir, "SRK_hash_table.bin"))) sb.append(sect2) # write_sb(cpu_params, "sb_file_2_sections" + ".sb", sb)
def test_bootimage_rt10xx_basic(): """Simple test for BootImgRT""" img = BootImgRT(0x60000000) assert img.info() dbg_info = DebugInfo() img_data = img.export(dbg_info=dbg_info) # test parser returns same result dbg_info2 = DebugInfo() img_data2 = BootImgRT.parse(img_data).export(dbg_info=dbg_info2) assert dbg_info.lines == dbg_info2.lines assert img_data == img_data2
def test_signed_flashloader(cpu_params: CpuParams) -> None: """Test creation of signed FLASHLOADER image :param cpu_params: processor specific parameters of the test """ assert TEST_IMG_CONTENT # this should be used in test mode only to verify the flashloader image creation process image_name = 'ivt_flashloader' tgt_address = INT_RAM_ADDR_CODE flashloader_unsigned_img = BootImgRT.parse(load_binary(cpu_params.data_dir, image_name + '.bin')) app_data = flashloader_unsigned_img.app.data assert app_data boot_img = BootImgRT(tgt_address, BootImgRT.IVT_OFFSET_OTHER) _to_authenticated_image(cpu_params, boot_img, app_data, 0, flashloader_unsigned_img.ivt.app_address) write_image(cpu_params, image_name + '_signed.bin', boot_img)
def test_invalid_parse(): with pytest.raises(SPSDKError): BootImgRT.parse(stream=5)
def test_bootimage_rt10xx_missing_ivt(): # IVT header not found with pytest.raises(SPSDKError): BootImgRT.parse(b"00000000")
def test_bootimage_rt10xx_missing_ivt(): # IVT header not found with pytest.raises(ValueError): BootImgRT.parse(b'00000000')