Patched version of nrf51822 FOTA compatible driver, with GPTIO disabled, as it clashed with the mbed definitions...

Fork of nRF51822 by Nordic Semiconductor

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers bootloader_util_arm.c Source File

bootloader_util_arm.c

00001 /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
00002  *
00003  * The information contained herein is property of Nordic Semiconductor ASA.
00004  * Terms and conditions of usage are described in detail in NORDIC
00005  * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
00006  *
00007  * Licensees are granted free, non-transferable use of the information. NO
00008  * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
00009  * the file.
00010  *
00011  */
00012 
00013 #include "bootloader_util.h "
00014 #include <stdint.h>
00015 #include <string.h>
00016 
00017 
00018 /**
00019  * @brief Function for aborting current handler mode and jump to to other application/bootloader.
00020  *
00021  * @details This functions will use the address provide (reset handler) to be executed after 
00022  *          handler mode is exited. It creates an initial stack to ensure correct reset behavior 
00023  *          when the reset handler is executed.
00024  *          See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babefdjc.html
00025  *
00026  * @param[in]  reset_handler  Address of the reset handler to be executed when handler mode exits.
00027  *
00028  * @note This function must never be called directly from 'C' but is intended only to be used from 
00029  *       \ref bootloader_util_reset. This function will never return but issue a reset into 
00030  *       provided address.
00031  */
00032 
00033 
00034 /**
00035  * @brief Function for aborting current application/bootloader jump to to other app/bootloader.
00036  *
00037  * @details This functions will use the address provide to swap the stack pointer and then load 
00038  *          the address of the reset handler to be executed. It will check current system mode 
00039  *          (thread/handler) and if in thread mode it will reset into other application.
00040  *          If in handler mode \ref isr_abort will be executed to ensure correct exit of handler 
00041  *          mode and jump into reset handler of other application.
00042  *
00043  * @param[in]  start_addr  Start address of other application. This address must point to the 
00044                initial stack pointer of the application.
00045  *
00046  * @note This function will never return but issue a reset into provided application.
00047  */
00048 #ifdef TOOLCHAIN_ARM
00049 __asm static void bootloader_util_reset(uint32_t start_addr)
00050 {
00051 MASK_ONES       EQU 0xFFFFFFFF  ; Ones, to be loaded into register as default value before reset.
00052 MASK_ZEROS      EQU 0x00000000  ; Zeros, to be loaded into register as default value before reset.
00053 xPSR_RESET      EQU 0x21000000  ; Default value of xPSR after System Reset.
00054 EXC_RETURN_CMD  EQU 0xFFFFFFF9  ; EXC_RETURN for ARM Cortex. When loaded to PC the current interrupt service routine (handler mode) willl exit and the stack will be popped. Execution will continue in thread mode.
00055     LDR   R5, [R0]              ; Get App initial MSP for bootloader.
00056     MSR   MSP, R5               ; Set the main stack pointer to the applications MSP.
00057     LDR   R6, [R0, #0x04]       ; Load Reset handler into register 6.
00058 
00059     LDR   R2, =MASK_ZEROS       ; Load zeros to R2
00060     MRS   R3, IPSR              ; Load IPSR to R3 to check for handler or thread mode 
00061     CMP   R2, R3                ; Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader
00062     MOV   R0, R6
00063     BNE   isr_abort             ; If not zero we need to exit current ISR and jump to reset handler of bootloader
00064 
00065     LDR   R4, =MASK_ONES        ; Load ones to R4 to be placed in Link Register.
00066     MOV   LR, R4                ; Clear the link register and set to ones to ensure no return.
00067     BX    R6                    ; Branch to reset handler of bootloader
00068 isr_abort
00069     LDR   R4,=MASK_ONES         ; Fill with ones before jumping to reset handling. We be popped as R12 when exiting ISR (Cleaning up the registers).
00070     LDR   R5,=MASK_ONES         ; Fill with ones before jumping to reset handling. We be popped as LR when exiting ISR. Ensures no return to application.
00071     MOV   R6, R0                ; Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR.
00072     LDR   R7,=xPSR_RESET        ; Move reset value of xPSR to R7. Will be popped as xPSR when exiting ISR.
00073     PUSH  {r4-r7}               ; Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
00074 
00075     LDR   R4,=MASK_ZEROS        ; Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers).
00076     LDR   R5,=MASK_ZEROS        ; Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers).
00077     LDR   R6,=MASK_ZEROS        ; Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers).
00078     LDR   R7,=MASK_ZEROS        ; Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers).
00079     PUSH  {r4-r7}               ; Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
00080 
00081     LDR   R0,=EXC_RETURN_CMD    ; Load the execution return command into register.
00082     BX    R0                    ; No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
00083     ALIGN
00084 }
00085 #elif defined(TOOLCHAIN_GCC)
00086 static void bootloader_util_reset(uint32_t start_addr)
00087 {
00088     asm(
00089         ".equ MASK_ONES,  0xFFFFFFFF\n\t" /* Ones, to be loaded into register as default value before reset.  */
00090         ".equ MASK_ZEROS, 0x00000000\n\t" /* Zeros, to be loaded into register as default value before reset. */
00091 
00092         "LDR   r5, [r0]       \n\t"       /* Get App initial MSP for bootloader.                              */
00093         "MSR   MSP, r5        \n\t"       /* Set the main stack pointer to the applications MSP.              */
00094         "LDR   r6,[r0, #0x04] \n\t"       /* Load Reset handler into register 0.                              */
00095 
00096         "LDR   r2, =MASK_ZEROS\n\t"       /* Load zeros to R2                                                 */
00097         "MRS   r3, IPSR       \n\t"       /* Load IPSR to R3 to check for handler or thread mode              */
00098         "CMP   r2, r3         \n\t"       /* Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader */
00099         "MOV   R0, R6         \n\t"
00100         "BNE   isr_abort      \n\t"       /* If not zero we need to exit current ISR and jump to reset handler of bootloader */
00101 
00102         "LDR   r4, =MASK_ONES \n\t"       /* Load ones to R4 to be placed in Link Register.                   */
00103         "MOV   LR, r4         \n\t"       /* Clear the link register and set to ones to ensure no return.     */
00104         "BX    r6             \n\t"       /* Branch to reset handler of bootloader                            */
00105         "isr_abort:           \n\t"
00106         "LDR   R4,=MASK_ONES \n\t" /* Fill with ones before jumping to reset handling. We be popped as R12 when exiting ISR (Cleaning up the registers). */
00107         "LDR   R5,=MASK_ONES \n\t" /* Fill with ones before jumping to reset handling. We be popped as LR when exiting ISR. Ensures no return to application. */
00108         "MOV   R6, R0        \n\t" /* Move address of reset handler to R6. Will be popped as PC when exiting ISR. Ensures the reset handler will be executed when exist ISR. */
00109         "LDR   R7,=xPSR_RESET\n\t" /* Move reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. */
00110         "PUSH  {r4-r7}       \n\t" /* Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR. */
00111 
00112         "LDR   R4,=MASK_ZEROS\n\t" /* Fill with zeros before jumping to reset handling. We be popped as R0 when exiting ISR (Cleaning up of the registers). */
00113         "LDR   R5,=MASK_ZEROS\n\t" /* Fill with zeros before jumping to reset handling. We be popped as R1 when exiting ISR (Cleaning up of the registers). */
00114         "LDR   R6,=MASK_ZEROS\n\t" /* Fill with zeros before jumping to reset handling. We be popped as R2 when exiting ISR (Cleaning up of the registers). */
00115         "LDR   R7,=MASK_ZEROS\n\t" /* Fill with zeros before jumping to reset handling. We be popped as R3 when exiting ISR (Cleaning up of the registers). */
00116         "PUSH  {r4-r7}       \n\t" /* Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine. */
00117 
00118         "LDR   R0,=EXC_RETURN_CMD\n\t" /* Load the execution return command into register. */
00119         "BX    R0                \n\t" /* No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application. */
00120         : /* output operands */
00121         : /* input operands */
00122         : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" /* clobber list */
00123         );
00124 }
00125 #endif /* TOOLCHAIN_ARM */
00126 
00127 void bootloader_util_app_start(uint32_t start_addr)
00128 {
00129     bootloader_util_reset(start_addr);
00130 }