uTasker bootloader with iMXRT1064

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

uTasker bootloader with iMXRT1064

Jump to solution
3,116 Views
Davidino
Contributor IV

Goodmorning to all, and especially @mjbcswitzerland 

I've been using the iMXRT1064-evk board with SDK version 2.9.1.

I've recently tested the uTasker bootloader project with USB-MSD device mode. I followed the guide https://www.utasker.com/docs/iMX/MCUXpresso.pdf, built the bootloaders and modified my application to make it suitable for uTasker (chapter 5).

The application plain code version (*_XiP.bin) works perfectly with the bootloader, but the BEE encrypted version (*_XiP_BEE.bin) doesn't. As a test I've download the encrypted application uTaskerV1.4.14_i.MX-RT1064_SD-USB-MSD_AES256.bin found at the bottom of this page https://www.utasker.com/iMX/RT1064.html. I tried to upload it with uTasker bootloader that I compiled and it works!

Hence I think that the problem is not the bootloader but something concerning the encrypted application file.

I've modified the generate.bat as follow:

 

 

 

 

SET PATH=%PATH%;C:\myNxp\totalProjectWorkspace\uTasker-GIT-Kinetis\Tools

rem - select the target being built for in order to automate combining production file

set SECRET_KEY="aes256 secret key"
set VECTOR="initial vector"
set MAGIC=234
set AUTHENTICATION=a748b6531124

rem - generate uploadable version (plain code)
uTaskerConvert.exe %1.bin %1_XiP.bin +../boot_header.txt -0x0%MAGIC% -%AUTHENTICATION%

rem - encrypt for OTF XiP operation
rem - used by OTFAD
uTaskerConvert.exe %1.bin %1_OTFAD.bin E=128-70020400 $%SECRET_KEY% $%VECTOR%)
uTaskerConvert.exe %1_OTFAD.bin %1_XiP_OTFAD.bin +../boot_header.txt -0x5%MAGIC% -%AUTHENTICATION%
del %1_OTFAD.bin

rem - used by BEE
uTaskerConvert.exe %1.bin %1_BEE.bin E=128B-70020400 $%SECRET_KEY% $%VECTOR%)
uTaskerConvert.exe %1_BEE.bin %1_XiP_BEE.bin +../boot_header.txt -0x5%MAGIC% -%AUTHENTICATION%
del %1_BEE.bin

 

 

 

 

The boot_header.txt file is the following:

 

 

 

 

// We add 760 bytes of padding between the header and the start of code in order to
// align the code on a 1k (0x400) byte boundary (ensures on-the-fly decryption compatibility,
// library compatibility and also allows interrupt vectors to remain in code)

02f8
ffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

ffffffffffffffff
ffffffffffffffff
ffffffffffffffff
ffffffffffffffff

 

 

 

 

The MCU settings is as follow:

 

 

 

 

 <chip>
  <memory id='Flash' type='Flash' is_ro='true' can_program='true'></memory>
  <memory id='RAM' type='RAM'></memory>
   <memoryInstance id='PROGRAM_FLASH' derived_from='Flash' location='0x70020400' size='0x3dfc00' driver='MIMXRT1064.cfx'  edited='true'  />
   <memoryInstance id='SRAM_DTC' derived_from='RAM' location='0x20000000' size='0x40000'   edited='true'  />
   <memoryInstance id='SRAM_ITC' derived_from='RAM' location='0x0' size='0x20000'   edited='true'  />
   <memoryInstance id='SRAM_OC' derived_from='RAM' location='0x20200000' size='0xa0000'   edited='true'  />
 </chip>

 

 

 

 

 

Have you got any advices?

Thank you in advance.

 

Best Regards,

Davidino

 

0 Kudos
1 Solution
3,017 Views
Davidino
Contributor IV

Hello @mjbcswitzerland ,

thank you for your message. I think I sorted out the problem: basically in generate.bat there was an extraneous ')' following the authentication code for BEE file generation. Once that I had removed it, it worked like a charm. I have one last question:

As far as I know, in uTasker among the several boot magic numbers, there isn't the option where the code to be loaded via MSD Device is encrypted but it's stored in Flash memory as plain code for XIP.
In this way there wouldn't be any performance reduction since it's already decrypted and, only in case of iMXRT1064, it would be safe (closing JTAG and ISP access) because it has an inner Flash memory.

Are there any plan to add it in the future?

Thank you for your support.

Best Regards,

Davidino

View solution in original post

0 Kudos
13 Replies
2,957 Views
Davidino
Contributor IV

Hello Mark,

thank you for your message, yes probably I have an older version. Thank you for your patience.

Best Regards,

Davide Brunelli

0 Kudos
3,107 Views
mjbcswitzerland
Specialist V

Hi Davidino

It may be better to post in the i.MX RT forum that in the i.MX forum.

Did you also see the video guide at https://www.youtube.com/watch?v=5iT7KP691ls&list=PLWKlVb_MqDQEOCnsNOJO8gd3jDCwiyKKe&index=10 ?

 

When you say it doesn't work is it that the loading fails (incorrect coding would be ignored) or is it that it loads but the loaded code fails?

There will be an XiP and an encrypted XiP for BEE on-the-fly operation generated with each build that will 'theoretically" both operate (since the boot loader handles all the details of setting up decrypted operation on the fly without needing any fixed configuration or special keys to be loaded). The magic number beginning with 0x0xxx informs the boot loader that the image is built for XiP unencrypted mode (without flash configuration block) and 0x5xxx the same - but encrypted - so the same actual XiP image is used in both cases.

If the code fails you can still debug it with the debugger [as long as not permanently disabled via eFUSE setting] (where the decrypted content is visible as decrypted - plain-text - content by the debugger) and see where it fails. There may be an operation that is not allowed when using BEE decryption (there are a few restrictions on the 1011 in OTFAD mode, for example) even if I am not aware of such at the moment.

I don't see any set up issues since, as noted, the only actual difference between XiP and encrypted XiP is just the encryption step of the exact same firmware image.

Regards

Mark

 

0 Kudos
3,097 Views
mjbcswitzerland
Specialist V

Davidino

On a practical point - is on-the-fly decryption from the internal QSPI flash in the 1064 really of practical significance? The flash is not accessible as it is on-chip and so code protection is less important as it can't be read out (unless the chips were to be opened in some way). Since on-the-fly decryption has a performance hit (not sure how much, but I heard of 30% or so) it seems that in many cases the 1064 has an advantage in that on-the-fly decryption may not be needed to ensure IP protection (in most standard instances) - compared to designs with off-chip QSPI flash where it would easily be extracted when not in encrypted from.

Note also that if you have code that fits in the internal RAM (enough space for code and variables) you can also use AES256 encryption in the flash and the uTasker boot loader will dynamically configure the FlexRAM to suit and ensure optimal performance, which can be 10x faster than XiP operation and also with much better deterministic performance [optimal for deep embedded control] as (core / FlexSPI) caching is never needed.

Regards

Mark

0 Kudos
3,085 Views
Davidino
Contributor IV

Hello @mjbcswitzerland , thank you for your answer.

Below some questions and answer.

  1. Yes, I saw both the video and pdf, thank you.
  2. The code size doesn't fit in ITCM as it's more than 300kB and I cannot reduce DTCM, so I simply moved some crucial functions in ITCM with _RAMFUNC() attribute (including cr_section_macros.h file).
  3. Regarding the fact that the code contained inside the processor itself is protected, isn't it possible to read the flash memory content via USB using MCU NXP Boot Utility or with JTAG? Do I have to burn some eFuses so that flash memory content cannot be read?
  4. Regarding the error that I get: The application is accepted (as the folder UPLOAD_DISK doesn't remain open) but the program doesn't work properly. I tested the bootloader with the simple hello_world SDK example, modified as explained in previous post, and the situation is the same (with _XIP version, it prints hello world with _XIP_BEE, it doesn't). You can find the project in attachment together with uTasker compiled bootloaders (writing on eFuses is disabled).
  5. I tried to "attach to a running target using LinkServer" as explained here https://www.utasker.com/docs/iMX/MCUXpresso.pdf chapter 7 but it goes in "Read Timeout" both with XIP and XIP_BEE executable.

Thank you for your support.

Best Regards,

Davidino

0 Kudos
3,073 Views
mjbcswitzerland
Specialist V

Hi Davidino

I posted in your other thread about protecting Flash here: https://community.nxp.com/t5/i-MX-RT/Prevent-internal-ROM-code-from-being-read-in-imxRT1064/m-p/1348...

Note that the 1064 has 1MByte RAM so 300kByte code could operate in ITC, depending on the variable size and where they are located (512k RAM and 196k DTC, for example).

As noted in the other thread JTAG and ISP are sources of easy access to code, even when On-the-Fly encoded. So these interfaces have to be disabled or protected to an adequate degree.

Regards

Mark

0 Kudos
3,056 Views
Davidino
Contributor IV

Hello @mjbcswitzerland ,

thank you for your answers, both in this thread and in the other. Regarding the memory occupancy the situation is the following (consider that the project is going to expand further in the next future):

Memory region Used Size Region Size %age Used
PROGRAM_FLASH: 309384 B 4 MB 7.38%
SRAM_DTC: 132312 B 256 KB 50.47%
SRAM_ITC: 9352 B 128 KB 7.14%
SRAM_OC: 0 GB 640 KB 0.00%

Even if I move the remaing partitionable 128k OCRAM slot to ITCM, it's not enough yet. Maybe the only solution would be to move global data from DTCM to OCRAM, but it could affect program performances as well ("cachable or not cachable, this is the dilemma"). What do you think?

I thought about the code protection and I missed a point. If we need to provide to customer an updated release of the program (after all, it's the reason why a bootloader exists), they can easely obtain the source code from the executable!
I think that the only solution is to encrypt the code, and I don't understand why my code hello_world (the encryped form) posted before, doesn't work.

Thank you.

Best Regards,

Davide Brunelli

 

0 Kudos
3,039 Views
mjbcswitzerland
Specialist V

Hi Davide

I expect that OCRAM with caching would be a good solution since running code in ITC can be 10x faster than when running from QSPI flash. The OCRAM is about 1/4 the speed of DTC but with the cache it will tend to be more efficient much of the time.

You can (and should) still encode your application since you can then distribute it in a safe form. When the boot loader knows that it should be decrypted at reception and saved in plain XiP form it will then do this and the plain code is in the QSPI flash but never visible externally (or in the distributed files).

Regards

Mark

0 Kudos
3,018 Views
Davidino
Contributor IV

Hello @mjbcswitzerland ,

thank you for your message. I think I sorted out the problem: basically in generate.bat there was an extraneous ')' following the authentication code for BEE file generation. Once that I had removed it, it worked like a charm. I have one last question:

As far as I know, in uTasker among the several boot magic numbers, there isn't the option where the code to be loaded via MSD Device is encrypted but it's stored in Flash memory as plain code for XIP.
In this way there wouldn't be any performance reduction since it's already decrypted and, only in case of iMXRT1064, it would be safe (closing JTAG and ISP access) because it has an inner Flash memory.

Are there any plan to add it in the future?

Thank you for your support.

Best Regards,

Davidino

0 Kudos
3,010 Views
mjbcswitzerland
Specialist V

Hi Davidino

Could you tell me whether that extraneous ')' was in an original bat file or was the result of a manipulation? I checked through the ones in the repository and didn't identify this.

 

You are right that there is not presently a code for encrypted content to be saved in unencrypted form but it is quite easy to add. The existing codes are

#define BOOT_LOADER_TYPE_MASK                    0xf000
#define BOOT_LOADER_TYPE_PLAIN_XiP_RESET_VECTOR  0x0000                  // execute in QSPi flash (execute in place) starting with reset vector
#define BOOT_LOADER_TYPE_PLAIN_RAM_EXECUTION     0x1000                  // copy plain code to ITC and execute there
#define BOOT_LOADER_TYPE_PLAIN_XiP_CONFIG_TABLE  0x2000                  // execute in QSPi flash (execute in place) starting with configuration table
#define BOOT_LOADER_TYPE_PLAIN_SDRAM_EXECUTION   0x3000                  // copy plain code to SDRAM and execute there
#define BOOT_LOADER_TYPE_AES256_SDRAM_EXECUTION  0x4000                  // decrypt AES256 encrypted code to SDRAM and execute there
#define BOOT_LOADER_TYPE_AES128_XiP_RESET_VECTOR 0x5000                  // execute in QSPI flash (execute in place) starting with reset vector using on-the-fly decryption
#define BOOT_LOADER_TYPE_AES128_XiP_CONFIG_TABLE 0x6000                  // execute in QSPI flash (execute in place) starting with configuration table using on-the-fly decryption
#define BOOT_LOADER_TYPE_AES256_RAM_EXECUTION    0x9000                  // decrypt AES256 encrypted code to ITC and execute there

So two new ones for "AES to plain code reset" and/or "AES to plain code with config table" could be added. The USB usb_device_loader.c file which handles USB MSD class and loading checks the new file as it arrives and decrypts it on-the-fly (it can decrypt in AES128 or AES256 but I would suggest using AES256 when it doesn't need to be compatible with BEE, which (only) supports AES128 (although I understand there is no real difference in strength)) but usually it only decrypts the start so that it can verify that the content matches that which is advertised. The same file is also used for the Kinetis AES256 encrypted method which decrypts the full content on the fly and saves it to internal flash.
See https://www.youtube.com/watch?v=MXsJvTdCcH4&list=PLWKlVb_MqDQFZAulrUywU30v869JBYi9Q&index=25
which means that the technique is already include in the actual code.
It will be necessary - at a couple of locations - to check the type code in order to choose the decryption algorithm setting to use and to continue decrypting before saving (as the Kinetis configuration will always does) when the code signals that it should be used.

Also the primary loader will need to understand the new code so that it understands that it should start the application as plain-code (effectively equivalent to BOOT_LOADER_TYPE_PLAIN_XiP_RESET_VECTOR and BOOT_LOADER_TYPE_PLAIN_XiP_CONFIG_TABLE).

Good luck

Regards

Mark

 

 

3,004 Views
Davidino
Contributor IV

Hello Mark,

thank you for your useful information.We are going to decide if we need to create this "new" bootloader mode (save file decrypted in flash) according to the performance that we can reach.

The problem was caused by me manipulating the file, but I can underline some bugs (at least as far as I can say):

In generate.bat for uTaskerV1.4_BM_XiP:

 

...

if %1==MIMXRT1010 (set CODE=E=128-60020200) else (if %1==MIMXRT1050 (set CODE=E=128B-60080200) else (set CODE=E=128B-60020200))
if %iMX_RT%==MIMXRT1050 (set OFFSET=0x80000) else (set OFFSET=0x20000)

....

 

Changed to (just to suit my need):

 

if %1==MIMXRT1010 (set CODE=E=128-60020200) else (if %1==MIMXRT1050 (set CODE=E=128B-60080200) else (set CODE=E=128B-70020400))
if %1==MIMXRT1050 (set OFFSET=0x80000) else (set OFFSET=0x20000)

 

 

Aside that if I comment out "#define USE_HTTP" from config.h in uTaskerSerialBoot, I get error:

 

c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: ./Hardware/iMX/iMX.o:(.rodata.ctTaskTable+0x34): undefined reference to `fnNetworkIndicator'
c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: ./uTasker/Driver.o: in function `fnWrite':
C:\myNxp\uTasker\uTasker-GIT-Kinetis\uTaskerSerialBoot/../uTasker/Driver.c:355: undefined reference to `fnNetworkTx'
c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: ./stack/Ethernet.o: in function `fnTaskEthernet':
C:\myNxp\uTasker\uTasker-GIT-Kinetis\uTaskerSerialBoot/../stack/Ethernet.c:299: undefined reference to `fnGetEthernetPars'
c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: ./stack/Ethernet.o: in function `fnEthernetMuxEvent':
C:\myNxp\uTasker\uTasker-GIT-Kinetis\uTaskerSerialBoot/../stack/Ethernet.c:1107: undefined reference to `network'
c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: ./stack/arp.o: in function `is_subnet':
C:\myNxp\uTasker\uTasker-GIT-Kinetis\uTaskerSerialBoot/../stack/arp.c:366: undefined reference to `network'
c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: ./stack/arp.o: in function `fnBuildSendARP':
C:\myNxp\uTasker\uTasker-GIT-Kinetis\uTaskerSerialBoot/../stack/arp.c:545: undefined reference to `network'
c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: C:\myNxp\uTasker\uTasker-GIT-Kinetis\uTaskerSerialBoot/../stack/arp.c:545: undefined reference to `network'
c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: ./stack/arp.o: in function `fnTimeoutValue':
C:\myNxp\uTasker\uTasker-GIT-Kinetis\uTaskerSerialBoot/../stack/arp.c:413: undefined reference to `network'
c:/nxp/mcuxpressoide_11.3.0_5222/ide/plugins/com.nxp.mcuxpresso.tools.win32_11.3.0.202008311133/tools/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: ./stack/arp.o:C:\myNxp\uTasker\uTasker-GIT-Kinetis\uTaskerSerialBoot/../stack/arp.c:752: more undefined references to `network' follow

 

The reason is that without USE_HTTP in webinterface.c functions fnGetEthernetPars() and fnNetworkTx() and struct network are comment out, but they are still in use.

Hope it can help you.Thank you.

 

Best Regards,

Davidino

0 Kudos
2,986 Views
mjbcswitzerland
Specialist V

Hi Davidino

I think the bat file can be extended to automatically recognise the 1064 case with:

if %1==MIMXRT1010 (set CODE=E=128-60020400) else if %1==MIMXRT1050 (set CODE=E=128B-60080400) else if %1==MIMXRT1064 (set CODE=E=128B-70020400) else (set CODE=E=128B-60020400)


The serial loader is usually used with HTTP,  MODBUS/TCP, FTP or TFTP and if these are all disabled (or TCP disabled) it is correct that you get those linker errors.
However, if you want to build a (test) version with just basic Ethernet support (eg. to test that it can ping without needing a TCP protocol) this can be solved as follows:
1. In webInterface.c make
NETWORK_PARAMETERS network[IP_NETWORK_COUNT] = ...
conditional on USE_IP (rather than it being conditional on HTTP, FTP, etc.

2. In the same file do the same with the dummy functions fnNetworkTx() and fnGetEthernetPars().

This will now build.

Regards

Mark

0 Kudos
2,982 Views
Davidino
Contributor IV

Hello Mark,

if I'm not wrong this is an error, right?

if %iMX_RT%==MIMXRT1050 (set OFFSET=0x80000) else (set OFFSET=0x20000)

and should be changed to:

if %1==MIMXRT1050 (set OFFSET=0x80000) else (set OFFSET=0x20000)

 

regarding the USE_HTTP the error happens, for example, even if USE_FTP is enabled.

Can you confirm? Thank you.

0 Kudos
2,961 Views
mjbcswitzerland
Specialist V

Hi Davidino

There are a number of bat files that are used in different environment:
The MCUXpresso version uses
if %1==MIMXRT1010
since the parameters are passed by the MCUXpresso post-build step as parameters:
and the GCC make file version uses
if %iMX_RT%==MIMXRT1010
since iMX_RT is manually set in the file.
Therefore both are correct but it depends which environment you are building in (and which of the bat files is actually being used).

If I build with USE_FTP only I don't have any problems since those missing functions and struct are conditional on
#if defined USE_HTTP || defined USE_FTP || defined USE_TFTP

Possibly you are using an older version where there is a difference but if you check these conditions it should be clear what is missing.

Regards

Mark

0 Kudos