Jumping from bootloader to user application

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

Jumping from bootloader to user application

Jump to solution
4,748 Views
kevinlfw
Contributor III

I'm using KBOOT v2.0 and a MK22F512VLH12 chip.

 

I currently have my user application placed at 0xA000 and it is running MQX.  Direct boot is currently enabled, so at power-up, it skips the bootloader and goes straight into user application.  

 

Now, I want to be able to go from my user application into the bootloader.  I've tried using the code found in the bootloader manual however that seems to be unsuccessful:

// Variables
uint32_t runBootloaderAddress;
void (*runBootloader)(void * arg);

void run_bootloader(void * arg)
{
 // Read the function address from the ROM API tree.
 runBootloaderAddress = **(uint32_t **)(0x0000001CUL);
 runBootloader = (void (*)(void * arg))runBootloaderAddress;
 runBootloader(NULL);
}

And then I eventually call:
run_bootloader(NULL);

What am I doing wrong?  How can I jump back into bootloader successfully?

Labels (1)
1 Solution
2,346 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Kevin Luty,

All of the comments by Bob are valid for the ROM Bootloader implementation and it is correct that things are slightly different for the flash-resident bootloader in your device (MK22F512VLH12).

In your case to jump to the bootloader from the application you can read the values for reset vector (entry point) and initial stack pointer from the bootloader's vector table. This corresponds to approach (2) of the Reference Manual. The next code can be used:

void (*runBootloader)(void);

void run_bootloader(void)
{
uint32_t runBootloaderAddress;

// Read the entry point from bootloader's vector table
runBootloaderAddress = *(uint32_t*)(0x00000004);
runBootloader = (void (*) (void))runBootloaderAddress;
runBootloader();
}

Then call run_bootloader() at the required point in the application's code.

Hope this helps. Let me know if you have questions.

Regards!

Jorge Gonzalez

View solution in original post

0 Kudos
10 Replies
2,346 Views
bobpaddock
Senior Contributor III

Is 0x0000001CUL the correct address for that part?  That address indicates ROM at address zero.

0 Kudos
2,346 Views
kevinlfw
Contributor III

Here is another chunk of code that I tried, which I took from the bootloader project.  This jumps to the bootloader, however I have to disable the direct enable boot in the BCA, which also means it doesn't boot directly into the user application at startup like I want it to:  

static uint32_t s_stackPointer = 0;
s_stackPointer = 0;
static void (*enterBootloader)(void) = 0;
enterBootloader = (void (*)(void))0;

// Set the VTOR to the application vector table address.
SCB->VTOR = (uint32_t)0x1FFF0000;

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

// Jump to the application.
enterBootloader();

0 Kudos
2,346 Views
bobpaddock
Senior Contributor III

I've only worked with the KL series.  On the assumption it works the same as your part it is FOPT is what controls boot to flash or boot to ROM bootloader (Does your part have the bootloader in ROM?).  BCA only needs changed if want to do something like a custom USB VID/PID or custom bootloader.

What the above C code is doing is moving the vector table to address 0x1FFF0000; , setting the Stack Pointer to Zero which makes no sense unless the _set_XSP() are doing something odd, then jumping to address 0x1FFF0000 which is also odd.  I can't say any of this is wrong without knowing what "bootloader Project" code does, however to me it is highly suspicious code.

0 Kudos
2,347 Views
kevinlfw
Contributor III

I thought I'd want to jump to address 0x0 or 0x1C, what I perceive as the start of the bootloader code.  I added some of the hopefully relevant information below.  I'm curious if I'm jumping to the code, its reading the Direct Enable as true, and just continuing to jump straight to the user application

This comes from the map file after building my freedom_bootloader project (found in bootloader.eww)

"A0":  place at 0x00000000 { ro section .intvec, ro section .noinit };

...

Section           Kind      Address     Size   Object
-------           ----      -------     ----   ------
"A0":                                   0x470
  .intvec                    0x00000000 0x410  <Block>
    .intvec       ro code    0x00000000 0x410  startup_MK22F51212.o [1]
  .noinit         ro code    0x00000410 0x58   crt0.o [1]
                           - 0x00000468 0x468

...

This comes from the map file after building my user application code:

"A0": place at 0x0000a000 { ro section .intvec };
"P1": place in [from 0x0000a400 to 0x0000a40f] { section FlashConfig };
"P2": place in [from 0x0000a000 to 0x0000a3ff] |
               [from 0x0000a410 to 0x0007ffff] { ro };

...

Section           Kind      Address     Size   Object
-------           ----      -------     ----   ------

"A0":                                   0x400
  .intvec         ro code    0x0000a000 0x400  startup_MK22F51212.o [4]
                           - 0x0000a400 0x400

"P1":                                    0x10
  FlashConfig     ro code    0x0000a400  0x10   startup_MK22F51212.o [4]
                           - 0x0000a410  0x10

...

And this comes from the memory_map_K22F512.c file, also found in bootloader.eww:

memory_map_entry_t g_memoryMap[] = {
{ 0x00000000, 0x0007ffff, kMemoryIsExecutable, &g_flashMemoryInterface }, // Flash array (512KB)
{ 0x1fff8000, 0x2000ffff, kMemoryIsExecutable, &g_normalMemoryInterface }, // SRAM (96KB for KV31, 128KB for K22)
{ 0x40000000, 0x4007ffff, kMemoryNotExecutable, &g_deviceMemoryInterface }, // AIPS peripherals
{ 0x400ff000, 0x400fffff, kMemoryNotExecutable, &g_deviceMemoryInterface }, // GPIO
{ 0xe0000000, 0xe00fffff, kMemoryNotExecutable, &g_deviceMemoryInterface }, // M4 private peripherals
{ 0 } // Terminator
};

0 Kudos
2,347 Views
bobpaddock
Senior Contributor III

"I thought I'd want to jump to address 0x0 or 0x1C"

What that bootloader code does is read the ADDRESS of the bootloader from location 0x1CUL then jump to the address read.

The parts that do have ROM do not place them at zero.    Have to check the data sheet to find this indirection address for each part.

Also what is at address zero is the ADDRESS of the the code that starts at reset, not the code itself.  0x4UL has the top of stack pointer address.

It is usually best to issue a reset instruction, as discussed in the other thread, than jump to the the reset function

If FOPT is set to start the user application then, assuming it is live and well, it can set FORCEROM in the Reset Control Module to enable the bootloader, then issue the software reset which will start the bootloader:

void __attribute__ ((noreturn)) reset_mcu( void )
{
/*
* A DSB is required before generating self-reset to ensure all
* outstanding transfers are completed. 
*/
irq_disable();
sync_barrier_data();

SCB_AIRCR = (SCB_AIRCR_VECTKEY(0x05FAU) | SCB_AIRCR_SYSRESETREQ_MASK);

for(;;)
{
;
}
}

 

0 Kudos
2,347 Views
kevinlfw
Contributor III

I'm using the flash-resident bootloader, so I'm not jumping to a ROM bootloader like I think you are used to.  The image below shows the memory map for flash-resident bootloader.  So how can I set up the system correctly to start executing the bootloader code, when I'm already running the user application.  What I think I'm looking for, is how to figure out the Bootloader Entry Point address because the manual (#2) says you can just call into the bootloader entry point:

There are two ways to get into the flash-resident bootloader.
1. If the vector table at the start of internal flash holds a valid PC and SP, the hardware
boots into the bootloader.
2. A user application running on flash or RAM calls into the Kinetis bootloader entry
point address in flash to start the Kinetis bootloader execution.

Capture.PNG

0 Kudos
2,347 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Kevin Luty,

All of the comments by Bob are valid for the ROM Bootloader implementation and it is correct that things are slightly different for the flash-resident bootloader in your device (MK22F512VLH12).

In your case to jump to the bootloader from the application you can read the values for reset vector (entry point) and initial stack pointer from the bootloader's vector table. This corresponds to approach (2) of the Reference Manual. The next code can be used:

void (*runBootloader)(void);

void run_bootloader(void)
{
uint32_t runBootloaderAddress;

// Read the entry point from bootloader's vector table
runBootloaderAddress = *(uint32_t*)(0x00000004);
runBootloader = (void (*) (void))runBootloaderAddress;
runBootloader();
}

Then call run_bootloader() at the required point in the application's code.

Hope this helps. Let me know if you have questions.

Regards!

Jorge Gonzalez

0 Kudos
2,347 Views
nkp
Contributor II

"In your case to jump to the bootloader from the application you can read the values for reset vector (entry point) and initial stack pointer from the bootloader's vector table"

Hello Jorge,

I am trying to achieve jumping to bootloader mode during application run-time. Could you please let me know how I would go about reading the reset vectors and stack pointer and where I should update these values before running the 

run_bootloader();

function. Please advice.

Thank you!

Niyanth.

0 Kudos
2,347 Views
kevinlfw
Contributor III

The code doesn't compile.  I changed it to this:

uint32_t runBootloaderAddress;

// Read the entry point from bootloader's vector table
runBootloaderAddress = **(uint32_t**)(0x00000004);
runBootloader = (void (*) (void *))runBootloaderAddress;
runBootloader();‍‍‍‍‍‍

Additionally, it doesn't help.  The code is executed and nothing happens.  When I "break" after the above code runs, it just shows me that the MQX idle task is running.  

Is there a chance a demo could be put together that is running MQX, uses the BCA w/ the flash-resident bootloader, and sets the direct boot enable flag (0xFE)?  The user application should run immediately at startup, and when some interrupt occurs (like button pushed) it enters into bootloader.  Running and testing this on a FRDM-K22F board would be ideal.

If there isn't, what should my next attempt be?

EDIT:

Using your code did in fact compile, it must've been my error copying it over.  Although it compiled, and in fact jumps to the bootloader code, because the bootloader direct boot flags in BCA is set to 0xFE to skip the bootloader at startup, it also skips the bootloader because the flags are still set when you jump to the bootloader.  With that being said, how should I change either the BCA or the bootloader project so that I skip the bootloader at startup, but so I can still jump to the bootloader from my user application?

0 Kudos
2,346 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hi Kevin,

Thank you for the update. Indeed if bootFlags = 0xFE then the bootloader is skipped. You need to modify the bootloader code to have an extra decision parameter apart from the flag. There might be several options to do this but a simple solution I can think of is to reserve 4 bytes at the end of RAM in both linker files (bootloader and application). Then from the application you store a custom value in such RAM space before jumping to bootloader. Finally the bootloader checks the value in RAM and executes the bootloading process.

The check of bootFlags is made by function is_direct_boot() called from bl_main.c.

Let me know if this solution does not work for you or if you have doubts to implement it.

Regards!

Jorge Gonzalez