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
Solved! Go to Solution.
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
Hello Mark,
thank you for your message, yes probably I have an older version. Thank you for your patience.
Best Regards,
Davide Brunelli
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
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
Hello @mjbcswitzerland , thank you for your answer.
Below some questions and answer.
Thank you for your support.
Best Regards,
Davidino
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
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
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
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
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
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
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
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.
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