Jumping to user application from custom bootloader

cancel
Showing results for 
Search instead for 
Did you mean: 

Jumping to user application from custom bootloader

Jump to solution
2,627 Views
alexferreirós
Contributor II

Hello,

I'm coding a bootloader and a MQX user application using KSDK and KDS on a KL27 custom board. I've followed this awesome guide to properly change the linker files (.ld) so the bootloader was placed at 0x00000000 and the main application at 0x00004000.

After looking up in the .map file, I saw the "Reset_Handler" symbol was placed at address 0x0000442D. This way, my bootloader is able to successfully jump to the user application with this piece of code:

__asm("bl 0x0000442D");

So far so good. The issue is that I wouldn't like to hardcode that address in bootloader's code Smiley Sad

I've seen in other threads a common approach to do that, but I couldn't make it work and I don't know why (wouldn't be a valid approach for my specific MCU?). The thing is that this snippet fails in my case:

#define USER_APP_ADDRESS   0x00004000

void JumpToUserApplication(uint32_t userSP, uint32_t userStartup) {

  __asm("msr msp, r0");

  __asm("msr psp, r0");

  __asm("mov pc,  r1");

}

JumpToUserApplication(*((unsigned long*)USER_APP_ADDRESS), *((unsigned long*)(USER_APP_ADDRESS+4)));

Does anybody know what could be wrong or knows other ways to jump to the user application without hardcoding its entry point address?

Best regards,

Alex

Labels (2)
Tags (3)
1 Solution
686 Views
mjbcswitzerland
Specialist V

Alex

The jump code is pretty standard so if it doesn't work for your application it may be that the application doesn't have its reset vector located at 0x4000.

Look in the binary (or SREC) etc. that you want to load and check that the first long word is the expected stack pointer address and the second is the entry point that you expect.

I use this code for KL parts:

extern void start_application(unsigned long app_link_location)
{
    asm(" ldr r1, [r0,#0]");            // get the stack pointer value from the program's reset vector
    asm(" mov sp, r1");                 // copy the value to the stack pointer
    asm(" ldr r0, [r0,#4]");            // get the program counter value from the program's reset vector
    asm(" blx r0");                     // jump to the start address }

So you would call it with

start_application(USER_APP_ADDRESS);

Regards

Mark

Kinetis: http://www.utasker.com/kinetis.html

Bare-Minimum Loader: http://www.utasker.com/docs/uTasker/uTasker_BM_Loader.pdf

Serial Bootloader (Ethernet, USB, MSD, KBOOT, AN2295, SREC, SD-card): http://www.utasker.com/forum/index.php?topic=1873.msg6796#msg6796 / http://www.utasker.com/docs/uTasker/uTaskerSerialLoader.PDF

For the complete "out-of-the-box" Kinetis experience and faster time to market

:smileyinfo: Out-of-the-box boot loader support for 46 Kinetis boards, 8 modes and 10 IDEs (over 15'000 combinations from a single code source with no porting required)

View solution in original post

14 Replies
686 Views
utsavkumar
Contributor II

I am working on LPC2648(ARM7). Facing the same issue as Alex got. Using reset vector address(Here 0x00030058), able to jump to app(starting address: 0x00030000) from my user defined boot(Starting address: 0x00000000). 

But following codes didn't work.

__asm void boot_jump(){
/* Load main stack pointer with application stack pointer initial value,
stored at first location of application area */
ldr r0, =0x30000
ldr r0, [r0]
mov sp, r0
/* Load program counter with application reset vector address, located at
second word of application area. */
ldr r0, = 0x30004
ldr r0, [r0]
mov pc, r0
}

OR

__asm void start_application(unsigned long location)
{
ldr r1, [r0,#0] // get the stack pointer value from the program's reset vector
mov sp, r1 // copy the value to the stack pointer
ldr r0, [r0,#4] // get the program counter value from the program's reset vector
bx r0 // jump to the start address
}

Using keil compiler with which hex file is getting generated. I have used hex to bin converter and opened the generated bin in HxD Hex editor to verify the stack and program counter address as part of the file. But didn't observe the addresses in the file.

What can be wrong and how to correct it?

0 Kudos
686 Views
mjbcswitzerland
Specialist V

Hi

You jump code looks OK, although the following is more efficient for the M4.

__asm void start_application(unsigned long location)

{

ldr sp, [r0,#0]

ldr pc, [r0,#4]

}

I think that you need to post the HEX and BIN files so that they can be checked.

Regards

Mark

0 Kudos
686 Views
utsavkumar
Contributor II

Thank you for the quick reply Mark. I have already tried the mentioned piece of code. It didn't work.

Sorry to say I am new to this forum and  I am not getting how to post the hex and bin files here.

0 Kudos
686 Views
mjbcswitzerland
Specialist V

Hi

Select "Use advanced editor"

pastedImage_1.png

and then there will be an attachment method.

pastedImage_1.png

Regards

Mark

0 Kudos
686 Views
utsavkumar
Contributor II

Thank you so much for helping out in adding the attachment.

I have already tried the piece of code that you have mentioned. It didn't work.

I have attached the Hex and bin files. I am using Keil IDE, which generated HEX files. Bin files, I have generated using online Hex to Bin converter(Hex to file (binary) converter ). Controller is LPC2648.

Boot.Hex & Boot.bin - Images for the user defined boot with starting address 0x00000000. Reset vector at 0x00000058(Refered map file)

App.Hex & App.bin -  Images for the application where jump have to be made with starting address 0x00030000. Reset vector at 0x00030058(Refered map file).

0 Kudos
686 Views
mjbcswitzerland
Specialist V

Hi

I checked the files and only then realised that you are working with an old ARM7 processor. This has nothing to do with Kinetis or Cortex M cores and the above code will certainly not work.... it is wise to consider moving to a more modern processor since they are so much better.

However, if you want to jump from a boot loader to an application it is in fact very simple.

start_application(_APP_START_); // jump to the application located at the address defined by _APP_START_

where

#define start_application(call_address)   ((void (*)(void))call_address)(); // call specified address

The ARM7 just needs code at the start location which 'manually' sets up the stack pointer. I doesn't work at all like the Cortex M (which in fact copies the Motorola 68000 and Coldfire method).

In fact you could get all the methods needed from the uTasker LPC2XXX project [including boot loaders] (which allows applications written for the LPC2xxx family to also run on Kinetis parts with almost no porting effort). This project is however legacy since it seems that it is a few years since anyone used these chips...

Regards

Mark

http://www.utasker.com/

686 Views
utsavkumar
Contributor II

Thank you for the clarification Mark. It is working.

But one thing raised my  curiosity, how come from Hex or binary file, you found the processor?

0 Kudos
686 Views
mjbcswitzerland
Specialist V

Hi

The files that you attached are clearly not Cortex M code since the first two long words are not valid RAM and Flash address, there then follows immediately code, rather than interrupt vectors addresses (which will also be Flash addresses if fixed and present) and there is no valid Flash config data at 0x400..0x40f. Furthermore, the first long word in the binary file is 0xe5f09fe5, which is a typical pattern for the ARM7 ldr pc,[pc, #xx] [branch to a cost address value].

Regards

Mark

686 Views
utsavkumar
Contributor II

Thank you for the information.

0 Kudos
686 Views
ndavies
Contributor V

Alex,

You need to or a 0x01 onto to your jump address. On the cortex-m4 cores the least significant bit of the requested jump to address must be set. This tells the processor to remain in Thumb instruction mode. Since these cores only supports the thumb instruction set, jumping to to an even address causes a hard fault.

Notice the __asm("bl 0x0000442D"); instruction is a jump to an odd address, even though the code actually exists starting on the even address.

Norm

0 Kudos
687 Views
mjbcswitzerland
Specialist V

Alex

The jump code is pretty standard so if it doesn't work for your application it may be that the application doesn't have its reset vector located at 0x4000.

Look in the binary (or SREC) etc. that you want to load and check that the first long word is the expected stack pointer address and the second is the entry point that you expect.

I use this code for KL parts:

extern void start_application(unsigned long app_link_location)
{
    asm(" ldr r1, [r0,#0]");            // get the stack pointer value from the program's reset vector
    asm(" mov sp, r1");                 // copy the value to the stack pointer
    asm(" ldr r0, [r0,#4]");            // get the program counter value from the program's reset vector
    asm(" blx r0");                     // jump to the start address }

So you would call it with

start_application(USER_APP_ADDRESS);

Regards

Mark

Kinetis: http://www.utasker.com/kinetis.html

Bare-Minimum Loader: http://www.utasker.com/docs/uTasker/uTasker_BM_Loader.pdf

Serial Bootloader (Ethernet, USB, MSD, KBOOT, AN2295, SREC, SD-card): http://www.utasker.com/forum/index.php?topic=1873.msg6796#msg6796 / http://www.utasker.com/docs/uTasker/uTaskerSerialLoader.PDF

For the complete "out-of-the-box" Kinetis experience and faster time to market

:smileyinfo: Out-of-the-box boot loader support for 46 Kinetis boards, 8 modes and 10 IDEs (over 15'000 combinations from a single code source with no porting required)

View solution in original post

686 Views
alexferreirós
Contributor II

It works like a charm! Thank you

0 Kudos
686 Views
ndavies
Contributor V

Sorry, didn't realize it was picking up the jump address from somewhere else

0 Kudos
686 Views
alexferreirós
Contributor II

Good to know anyway.

BR

0 Kudos