kboot: jump to bootloader from application

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

kboot: jump to bootloader from application

4,597 Views
peterruesch
Contributor IV


Hi,

I was searching for how I could jump to the bootloader when running the application.

the Kinetis Booloader Reference Manual states the following:

To get the address of the entry point, the user application reads the word containing the

pointer to the bootloader API tree at offset 0x1C of the bootloader's vector table. The

vector table is placed at the base of the bootloader's address range.

But when I look at the bootlaoder sources there is no evidence that this is actually done.

1. The vector table defined in the startup_*.s file does not place the g_bootloaderTree symbol at a specific offset

2. The linker file does also not contain an explicit location for g_bootloaderTree.

so what am I missing? How can the application expect an bootloader entry point at 0x1C?

Seems like I just should to it as the bootloader jumps to the application (jump_to_application() )

Tags (2)
0 Kudos
Reply
11 Replies

2,779 Views
bobpaddock
Senior Contributor III

As it appears the bootloader is what will run out of reset, restarting the bootloader via reset is better than a jump to it.

This will assure that the stack pointer gets set correctly from the value at 0x00000000UL.

/*

* Data Synchronization Barrier (DSB): Ensures that all explicit data

* memory transfer before the DSB are complete before any instruction

* after the DSB is executed.

*

*      Ensure effects of an access to SCS take place before the next

*      operation

*

*      Ensure memory is updated before the next operation, for

*      example, SVC, WFI, WFE.

*

*      Vector table changes:

*              If the program changes an entry in the vector table,

*              and then enables the corresponding exception, a DSB

*              instruction should be used between these two

*              operations. This ensures that if the exception is

*              taken after being enabled the processor uses the new

*              exception vector. If the updated vector table is

*              required immediately, for example if an SVC

*              immediately follows an update to the SVC table entry

*              via a store, then a DSB is also required.

*

*      Memory Map modifications:

*              If the system contains a memory map switching

*              mechanism then use a DSB instruction after switching

*              the memory map in the program. This ensures subsequent

*              instruction execution uses the updated memory map, if

*              the memory system makes the updated memory map visible

*              to all subsequent memory accesses.

*

*              Note:

*                      An ISB or an exception entry/return is required

*                      to ensure that the subsequent instructions are

*                      fetched using the new memory map.

*

* The memory barrier instructions, DMB and DSB, can be used to ensure

* that the write buffer on the processor has completed its operation

* before subsequent operations can be started. However, it does not

* check the status of the bus level write buffers. In such cases, if

* the system is based on AHB or AHB Lite, you might need to perform a

* dummy read through the bus bridge to ensure that the bus bridge has

* completed its operation.

*

* The Cortex-M0 processor (r0p0) and the Cortex-M0+ processor (r0p0)

* do not include a write buffer in their processor bus interface.

*

* Architecturally, a DSB instruction should be used after changing

* the VTOR if an exception is to be generated immediately and should

* use the latest vector table setting.

*

* In Cortex-M3, Cortex-M4 and Cortex-M0+ processors, accesses to the

* SCS have the DSB behavior, so there is no need to insert the DSB

* instruction.

*

* A DSB is required before generating self-reset to ensure all

* outstanding transfers are completed. The use of the CPSID I

* instruction is optional.

*/

static inline ATTR_NO_INSTRUMENT_FUNCTION void sync_barrier_data( void )

{

  __asm__ __volatile__ ("dsb");

}

void __attribute__ ((noreturn)) reset_mcu( void )

{

  /*

   * A DSB is required before generating self-reset to ensure all

   * outstanding transfers are completed. The use of the CPSID I

   * instruction is optional, if state of system is understood.

   * sync_barrier_data();

   */

  irq_disable();

  sync_barrier_data();

  SCB_AIRCR = (SCB_AIRCR_VECTKEY(0x05FAU) | SCB_AIRCR_SYSRESETREQ_MASK); /* Generate a System Reset */

  for(;;)

    {

      ;

    }

0 Kudos
Reply

2,779 Views
kevinlfw
Contributor III

bobpaddock‌ I cannot get your code to compile, and using the method with address 0x04UL doesn't work either--my linker file is the same.  Also, I am running MQX, which I'm not sure matters.  

Any pointers on getting the above code running.  On the static inline function itself I'm getting a "inline specifier allowed on function declarations only" and "explicit type is missing ("int" assumed)".  I'm using IAR EWARM.

Edit:

I added "#define ATTR_NO_INSTRUMENT_FUNCTION __attribute__( ( no_instrument_function ) )  /* Really needed for these inlined single instructions */" and that prompted a "the "no_instrument_function" attribute is not supported".

0 Kudos
Reply

2,779 Views
bobpaddock
Senior Contributor III

#define ATTR_NO_INSTRUMENT_FUNCTION __attribute__( ( no_instrument_function ) )


Those can be deleted.  They are only needed if CFLAGS += -finstrument-functions is used.

The above code is written for GCC.

0 Kudos
Reply

2,779 Views
kevinlfw
Contributor III

Not GCC; I'm using IAR EWARM (IAR Embedded Workbench).

0 Kudos
Reply

2,779 Views
bobpaddock
Senior Contributor III

Will this line compile?:

  SCB_AIRCR = (SCB_AIRCR_VECTKEY(0x05FAU) | SCB_AIRCR_SYSRESETREQ_MASK); /* Generate a System Reset */

If not the header files are different.

IAR should have intrinsic that replace the GCC Attributes.  The main one is to disable the interrupts before generating the reset.  Flushing the caches and pending writes is wise, may not absolutely needed.

0 Kudos
Reply

2,779 Views
kevinlfw
Contributor III

It seems the IAR equivalent is below, however it does not work.  The system is reset, but it doesn't put me in the bootloader, at least in my case.  I currently have my BCA configured to direct boot into the user application. I've created a question regarding this yesterday: Jumping from bootloader to user application 

static inline void sync_barrier_data( void )
{
   __ASM volatile ("dsb");
}
void __attribute__ ((noreturn)) reset_mcu( void )
{
   /*
   * A DSB is required before generating self-reset to ensure all
   * outstanding transfers are completed. The use of the CPSID I
   * instruction is optional, if state of system is understood.
   * sync_barrier_data();
   */
   __disable_irq();
   sync_barrier_data();


   NVIC_SystemReset();

   for(;;)
   {
      ;
   }
}  

0 Kudos
Reply

2,779 Views
bobpaddock
Senior Contributor III

See attached files on how to do it.  This is using GCC.

/** @(#)bootldrstart.c     <18-Nov-2015 08:13:50 bob p>

*  \date Last Time-stamp: <12-Jul-2016 08:24:01 bob p>

*

*  \file bootldrstart.c

*  \brief  Jump to Boot Loader.

*

* Note:

*      You may not even convert a void * to a function pointer by

*      explicit casting (6.3.2.3|1).

*

*      C's abstract machine does not assume that code and data are

*      addressed the same way, so as far as C is concerned function

*      pointers and data pointers have nothing to do with each other

*      (they could have different widths).

*/

/*lint -save */

#include "includes.h" /* Include things like stdint.h etc. */

#define  DEFINE_SPACE_BOOTLDRSTART_H (1)

#include "bootldrstart.h"

/* Function Pointer returning void, past void pointer: */

void (*_boot_loader_start)( void * arg );

void boot_loader_start( void )

{

  /* Read the function address from the ROM API tree: */

   uint32_t const _boot_loader_start_address = **(uint32_t **)(0x1C00001CUL);

  /* Turn address in to a funciton pointer: */

  _boot_loader_start = (void (*)(void * arg))_boot_loader_start_address;

  _boot_loader_start( NULL ); /* Call the function.  Will not return from here */

  for(;;) /* Pacify the compiler about returning from a no return funciton */

    ;

}

0 Kudos
Reply

2,779 Views
peterruesch
Contributor IV

thanks for your attention, but 0x1C00001CUL seems not to be in the flash memory region into which the bootloader is linked.

is your implementation only valid for ROM resident bootloaders?

br

0 Kudos
Reply

2,779 Views
bobpaddock
Senior Contributor III

0x1C is offset from the start of the bootloader address of where ever it is located.

Yes my example is for the KL27 ROM Bootloader.

What does your linker script look like?  It should be defining a symbol to the start of the bootloader.

Are you linking both the bootloader and your application at the same time or separately?

0 Kudos
Reply

2,779 Views
peterruesch
Contributor IV

Hi Bob,

this is a part of the booloader linker file:

MEMORY

{

  m_interrupts          (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000400

  m_flash_config        (RX)  : ORIGIN = 0x00000400, LENGTH = 0x00000010

  m_text                (RX)  : ORIGIN = 0x00000410, LENGTH = 0x000FFBF0

  m_data                (RW)  : ORIGIN = 0x1FFF0000, LENGTH = 0x00040000

}

it does not define a special region for the bootloader entry symbol. thats why I'm confused about the proposed fixed entry point for the bootloader.

bootloader and application get compiled and linked in two different projects.

0 Kudos
Reply

2,779 Views
bobpaddock
Senior Contributor III

Replace 0x1C00001CUL with 0x00000004UL in the  code I posted above.

0 Kudos
Reply