How to jump to application from custom bootloader where both are XIP

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

How to jump to application from custom bootloader where both are XIP

Jump to solution
7,641 Views
greg_nowak
Contributor III

I have created an L2 bootloader (modified from an NXP provided "OTA Bootloader") that will look for various images in QSPI flash, validate them, and decide which one to boot based on an A/B/Factory partitioning scheme.

The bootloader is what is loaded by the BootROM and is XIP from flash.  The images I want to boot are also in QSPI and I want them to be XIP as well.

I have the following setup:  

RT-1052

L2 bootloader runs, can find the images in flash, validate them, and "jump" to their respective start addresses.

Vector table "seems" correct for image I'm attempting to jump to, the stack pointer is set to 0x20000000 (SRAM DTC), ResetISR "appears" to be at the correct memory location. 

Functions are below for jumping to application.

void jump_to_user_application(uint32_t app_start)
{
/* Invalidate caches */
SCB_DisableDCache();
SCB_DisableICache();
/* The main application will enable caches */
__DMB();

/* Relocate vector table */
SCB->VTOR = app_start;

jump(*(uint32_t *)(app_start), *((uint32_t *)(app_start+4)));
}

/* Jump to application */
static void jump(uint32_t user_sp, uint32_t user_startup)
{
static void (*farewell_bootloader)(void) = 0;
farewell_bootloader = (void (*)(void))user_startup;

// Set stack pointers to the application stack pointer.
__set_MSP(user_sp);
__set_PSP(user_sp);

// Jump to the application.
farewell_bootloader();
}

Issues:

I get an Imprecise Bus Error hard fault after the jump.  

Things I've tried:

* I've tried building the app without the XIP headers and DCD headers, loading the raw binary into flash as the expected location and jumping to it.  Same error.

 

* Disabling the cache was another suggestion ( as you can see in the functions above I'm doing that, still didn't help)

* Aligned the memory map for the bootloader and the memory map of the application to make sure we were all on the same page.

Questions: 

1.  Since my bootloader is what is being processed by the BootROM, do I need to build the bootloader differently to ensure memory is properly setup for the application I'm trying to jump to?

2.  Is there a "de-initialization" sequence I need to do before jumping to the application beyond what I'm doing above?  I'm wondering if the bus fault has something to do with the fact that the application assumes it is coming out of reset and is trying to run through its initialization sequence but the bootloader has already done that.

3.  How do I build my application such that it can get loaded at a different location?  I've modified the linker script and all the memory addresses appear to be correct, but I'm just loading the raw binary (not running it through any of the factory tools to create a "bootable" image, since I don't need it to be run from the BootRom)

My primary confusion here is that most forum answers for booting to SRAM have you run the binary output by MCUXpresso through the BootUtility tools, but since my image is linked at 0x60100000 the MCUBootUtility adds 1M of 0's to the image since it is trying to put the HDR and IVT at the base of flash to make it a bootable image.  I don't want that since my bootloader is going to live in the first 1M of flash.

Thanks,


Greg

Labels (1)
1 Solution
7,224 Views
greg_nowak
Contributor III

I figured out my issue.  My application required SRAM and a DCD but the bootloader did not.  

When loading an application that depends on a DCD I needed to change my bootloader to use that DCD, then change the bootloader to skip SYSCLK_INIT (since it is now using a DCD).  The bus fault was because I wasn't skipping the SYSCLK INIT in my bootloader.

This is resolved!

View solution in original post

15 Replies
7,224 Views
dansmithers
Contributor III

Hi, I've found this thread really useful as I am trying to achieve a similar objective. The difference is that I am using an iMxrt1062 processor.

I have compiled and tested my test application in QSPI flash from 0x6000_0000 and everything works fine.

I have now added a bootloader stage at that location and recompiled my application to be PIC and removed the XIP_BOOT_HEADER_ENABLE flag. I have downloaded my binary onto the QSPI flash at 0x6030_0000.

Looking at the binary that is on the flash the stack pointer is 0x0020_0000 presumably a relative address) and the application entry point is 0x6000_231D, which is back into the bootloader.

Is there another flag to make the compiler treat the entry point as relative?

thanks

for your help.

Dan

0 Kudos
7,224 Views
dansmithers
Contributor III

Thanks for such a quick response Greg.

My next challenge is finding out how to get MCUXpresso to generate the code offsets.

dan

0 Kudos
7,224 Views
dansmithers
Contributor III

As a quick fix, I moved the flash base for the application in the Eclipse settings, but I now find the debugger branching to 0xdeadbeee after calling the new function.

Where can I find more information of the required format of the binary image?

Also, how can I make my code properly position independent?

thanks

dan

0 Kudos
7,224 Views
mjbcswitzerland
Specialist V

Dan

You don't need to use PIC to locate an application to a different address that 0x60000000. PIC is needed when loading to RAM at undefined addresses - Could that be a part of the problem?

Regards

Mark

[uTasker project developer for Kinetis and i.MX RT]

Complete turn-key i.MX RT bootloading concept for all parts is available for professional work:
https://www.utasker.com/iMX/RT1060.html
https://www.youtube.com/watch?v=2XfgZq19XDw&list=PLWKlVb_MqDQEOCnsNOJO8gd3jDCwiyKKe&index=3
https://www.youtube.com/watch?v=C7DyE8RscHs&list=PLWKlVb_MqDQEOCnsNOJO8gd3jDCwiyKKe&index=4
AES256 code and clone protection with OTA and serial loaders (USB device, memory stick, SD card, Ethernet, UART) https://www.utasker.com/docs/uTasker/uTaskerSerialLoader.pdf
For operating in internal, SDRAM or XiP
https://www.utasker.com/docs/iMX/Loader.pdf

0 Kudos
7,224 Views
dansmithers
Contributor III

Thanks Mark,

I recompiled without fPIC and the bootloader now chooses between two applications to XIP from flash.

Currently I am linking the application twice for this. Can I just change the value of the entry point? The aim is to have the software on the processor determine where to store the code.

thanks

dan

0 Kudos
7,224 Views
mjbcswitzerland
Specialist V

Dan

I you have multiple locations in flash where a single application could be stored at PIC would be needed but I expect that you will still have problems with fixed addresses - such as the entry in the reset vector. If it is only the entry point causing problems the loader could work around that by reading the value and then adjusting it by an offset equal to the location the code is stored at and the location it was linked to be at before jumping there.

Regards

Mark

[uTasker project developer for Kinetis and i.MX RT]

0 Kudos
7,224 Views
greg_nowak
Contributor III

Dan,

The linker script for your application needs to move your HDR section to your new address.  For me, this is what I did.

pastedImage_2.png

Thanks,


Greg

0 Kudos
7,225 Views
greg_nowak
Contributor III

I figured out my issue.  My application required SRAM and a DCD but the bootloader did not.  

When loading an application that depends on a DCD I needed to change my bootloader to use that DCD, then change the bootloader to skip SYSCLK_INIT (since it is now using a DCD).  The bus fault was because I wasn't skipping the SYSCLK INIT in my bootloader.

This is resolved!

7,224 Views
mjbcswitzerland
Specialist V

Greg

I'll show you the XiP application jump used in the uTasker project (allowing XiP application code to be used with or without configuration - the configuration should however be linked to your address 0x60100000 and not just the reset vector otherwise you will get the huge fill between the two) which might give you some ideas:

extern void start_application(unsigned long app_link_location)
{
....

        switch (ptrFlashHeader->usMagicNumber & BOOT_LOADER_TYPE_MASK) {
        case BOOT_LOADER_TYPE_PLAIN_XiP_RESET_VECTOR:                    // the code is to be executed directly from QSPI flash and begins with the application's reset vector
            jump_to_application(app_link_location + sizeof(iMX_BOOT_HEADER)); // and finally jump to the new code (this will not return)
            break;
        case BOOT_LOADER_TYPE_PLAIN_XiP_CONFIG_TABLE:                    // the code is to be executed directly from QSPI flash and begins with a configuration table that needs to be interpreted in order to locate the reset vector
            app_link_location += (0x1000 + sizeof(iMX_BOOT_HEADER));     // move over the flash configuration to the image vector table
            if (*(unsigned char *)fnGetFlashAdd((unsigned char *)app_link_location) == (unsigned char)IVT_TAG_HEADER) { // check that it is has an IVT header
                if (*(unsigned char *)(fnGetFlashAdd((unsigned char *)app_link_location) + 1) == (unsigned char)(IVT_SIZE)) {
                    if (*(unsigned char *)(fnGetFlashAdd((unsigned char *)app_link_location) + 2) == (unsigned char)(IVT_SIZE >> 8)) {
                        app_link_location = *(unsigned long *)(fnGetFlashAdd((unsigned char *)app_link_location) + 4); // get the vector table location
                        jump_to_application(app_link_location);          // jump to the application in QSPI flash (this will not return)
                    }
                }
            }
            break;
....

and the jump takes place with


static void jump_to_application(volatile unsigned long app_link_location)
{                                     // cortex-M3/M4/M7 assembler code
    asm(" mov r1, #0");
    asm(" msr control, r1");          // disable potential FPU access flag so that subsequent exceptions do not save FPU registers
    asm(" ldr sp, [r0,#0]");          // load the stack pointer value from the program's reset vector
    asm(" ldr pc, [r0,#4]");          // load the program counter value from the program's reset vector to cause operation to continue from there
}

Ready made boot loader concept for professionals:
https://www.youtube.com/watch?v=2XfgZq19XDw&feature=youtu.be

Concept flow diagram: https://www.utasker.com/docs/iMX/Loader.pdf

Page 6 of https://www.utasker.com/docs/iMX/MCUXpresso.pdf gives some additional information about XiP with and without config header.

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]

7,224 Views
greg_nowak
Contributor III

Do you know if your  bootloader needed to take into account the DCD of the application you are booting?  I'm suspicious that my problem might be more around the application I'm booting and what it expects for memory configuration which is different that the DCD used by my bootloader (which is fairly minimal).

Greg

0 Kudos
7,224 Views
mjbcswitzerland
Specialist V

Greg


When I build an XiP application image I just remove the image vector table, ensure the reset vector is at the start and set its link address accordingly - and then it can be jumped to using the standard method (load the SP from the first long word and the PC from the second long word).

DCD is only needed if you want to immediately work from SDRAM, for example, and should not be critical. The application code can also do its own initialisation of most things in code if they don't match the loader's setup.
If the initial stack pointer matches with the RAM configuration it should be uncritical.

In the uTasker boot loader the loader dynamically configures the DTC/ITC configuration to match the application's requirements and adjust's the application's stack pointer to suit however, If you have fixed settings, the fixed SP value in code should be fine. What memory the loader used during its own work should be irrelevant.

Regards

Mark

[uTasker project developer for Kinetis and i.MX RT]

0 Kudos
7,224 Views
greg_nowak
Contributor III

From what I'm seeing my application has the hard fault as soon as it tries to copy the 'data' section to SRAM.  It's an imprecise bus fault so I'm not 100% sure this is where it is happening, but my program counter in my application is at the "data_init" function called within the startup routine of the application where it is copying the application's data section to BOARD SRAM (not the internal SRAM like ITC, DTC, or OC).

pastedImage_3.jpg

pastedImage_1.jpg

0 Kudos
7,224 Views
mjbcswitzerland
Specialist V

Hi

Set a break point at the line that you know will fail and switch to disassemble mode. Watch which register is used as a pointer and the value that it has before failing. It sounds as though it will point to the SDRAM area.

Try viewing this area in a memory window - if it can't be viewed it will presumably mean that the SDRAM interface hasn't been configured. Check SDRAM controller's registers to see whether they haven't been set up at all or whether they have been set up incorrectly.
If it can view it double check the range that the data is being initialised in to be sure that it matches the expected SDRAM range.

If you have no SDRAM setup in the loader's CDC you can add initialisation code in the application to do the same before it starts accessing the SDRAM.

Do you need to use SDRAM for variables? Accesses are a lot slower there than from DTC.

Regards

Mark
[uTasker project developer for Kinetis and i.MX RT]

0 Kudos
7,224 Views
greg_nowak
Contributor III

Mark,

Thanks!

Do you need to do anything special in your application code aside from linking it?  

I'm curious about all of the "normal" initialization that is done in my application when it runs on its own, do I need to gut any of that if the bootloader is going to jump to it?

Greg

0 Kudos
7,224 Views
greg_nowak
Contributor III

Currently it is "jumping" to the reset ISR in my Application but I get the hard fault somewhere in that function.  The hard fault occurs before the "main" of my jump to application is called.  I tested this by putting a while(1) loop at the top of my application main.

There are a couple things I'm struggling to understand.  

1.  My bootloader uses DTC and ITC sram for execution.  When I hand over control to my application does it do what it needs to do with those memory regions automatically?  

2.  I'm disabling D and I caches in my bootloader prior to making the jump, but it is still hard faulting.

Because it is an "imprecise bus error" I don't get a solid picture of what specific function is causing the issue.  

Greg

0 Kudos