test

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 /*
00002  * Copyright (c) Nordic Semiconductor ASA
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without modification,
00006  * are permitted provided that the following conditions are met:
00007  *
00008  *   1. Redistributions of source code must retain the above copyright notice, this
00009  *   list of conditions and the following disclaimer.
00010  *
00011  *   2. Redistributions in binary form must reproduce the above copyright notice, this
00012  *   list of conditions and the following disclaimer in the documentation and/or
00013  *   other materials provided with the distribution.
00014  *
00015  *   3. Neither the name of Nordic Semiconductor ASA nor the names of other
00016  *   contributors to this software may be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00024  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00027  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  */
00032 #include "compiler_abstraction.h"
00033 #include "bootloader_util.h "
00034 #include <stdint.h>
00035 #include <string.h>
00036 
00037 /**
00038  * @brief Function for aborting current application/bootloader jump to to other app/bootloader.
00039  *
00040  * @details This functions will use the address provide to swap the stack pointer and then load
00041  *          the address of the reset handler to be executed. It will check current system mode
00042  *          (thread/handler) and if in thread mode it will reset into other application.
00043  *          If in handler mode \ref isr_abort will be executed to ensure correct exit of handler
00044  *          mode and jump into reset handler of other application.
00045  *
00046  * @param[in]  start_addr  Start address of other application. This address must point to the
00047                initial stack pointer of the application.
00048  *
00049  * @note This function will never return but issue a reset into provided application.
00050  */
00051 #ifdef TOOLCHAIN_ARM
00052 __asm static void bootloader_util_reset(uint32_t start_addr)
00053 {
00054 MASK_ONES       EQU 0xFFFFFFFF  ; Ones, to be loaded into register as default value before reset.
00055 MASK_ZEROS      EQU 0x00000000  ; Zeros, to be loaded into register as default value before reset.
00056 xPSR_RESET      EQU 0x21000000  ; Default value of xPSR after System Reset.
00057 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.
00058     LDR   R5, [R0]              ; Get App initial MSP for bootloader.
00059     MSR   MSP, R5               ; Set the main stack pointer to the applications MSP.
00060     LDR   R6, [R0, #0x04]       ; Load Reset handler into register 6.
00061 
00062     LDR   R2, =MASK_ZEROS       ; Load zeros to R2
00063     MRS   R3, IPSR              ; Load IPSR to R3 to check for handler or thread mode
00064     CMP   R2, R3                ; Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader
00065     MOV   R0, R6
00066     BNE   isr_abort             ; If not zero we need to exit current ISR and jump to reset handler of bootloader
00067 
00068     LDR   R4, =MASK_ONES        ; Load ones to R4 to be placed in Link Register.
00069     MOV   LR, R4                ; Clear the link register and set to ones to ensure no return.
00070     BX    R6                    ; Branch to reset handler of bootloader
00071 isr_abort
00072     LDR   R4,=MASK_ONES         ; Fill with ones before jumping to reset handling. We be popped as R12 when exiting ISR (Cleaning up the registers).
00073     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.
00074     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.
00075     LDR   R7,=xPSR_RESET        ; Move reset value of xPSR to R7. Will be popped as xPSR when exiting ISR.
00076     PUSH  {r4-r7}               ; Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR.
00077 
00078     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).
00079     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).
00080     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).
00081     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).
00082     PUSH  {r4-r7}               ; Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine.
00083 
00084     LDR   R0,=EXC_RETURN_CMD    ; Load the execution return command into register.
00085     BX    R0                    ; No return - Handler mode will be exited. Stack will be popped and execution will continue in reset handler initializing other application.
00086     ALIGN
00087 }
00088 #elif defined(TOOLCHAIN_GCC)
00089 static void bootloader_util_reset(uint32_t start_addr)
00090 {
00091     __ASM(
00092         ".equ MASK_ONES,  0xFFFFFFFF\n\t" /* Ones, to be loaded into register as default value before reset.  */
00093         ".equ MASK_ZEROS, 0x00000000\n\t" /* Zeros, to be loaded into register as default value before reset. */
00094         ".equ xPSR_RESET, 0x21000000\n\t" /* Default value of xPSR after System Reset. */
00095         ".equ EXC_RETURN_CMD, 0xFFFFFFF9\n\t" /* 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. */
00096 
00097         "LDR   r5, [r0]       \n\t"       /* Get App initial MSP for bootloader.                              */
00098         "MSR   MSP, r5        \n\t"       /* Set the main stack pointer to the applications MSP.              */
00099         "LDR   r6,[r0, #0x04] \n\t"       /* Load Reset handler into register 0.                              */
00100 
00101         "LDR   r2, =MASK_ZEROS\n\t"       /* Load zeros to R2                                                 */
00102         "MRS   r3, IPSR       \n\t"       /* Load IPSR to R3 to check for handler or thread mode              */
00103         "CMP   r2, r3         \n\t"       /* Compare, if 0 then we are in thread mode and can continue to reset handler of bootloader */
00104         "MOV   R0, R6         \n\t"
00105         "BNE   isr_abort      \n\t"       /* If not zero we need to exit current ISR and jump to reset handler of bootloader */
00106 
00107         "LDR   r4, =MASK_ONES \n\t"       /* Load ones to R4 to be placed in Link Register.                   */
00108         "MOV   LR, r4         \n\t"       /* Clear the link register and set to ones to ensure no return.     */
00109         "BX    r6             \n\t"       /* Branch to reset handler of bootloader                            */
00110         "isr_abort:           \n\t"
00111         "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). */
00112         "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. */
00113         "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. */
00114         "LDR   R7,=xPSR_RESET\n\t" /* Move reset value of xPSR to R7. Will be popped as xPSR when exiting ISR. */
00115         "PUSH  {r4-r7}       \n\t" /* Push everything to new stack to allow interrupt handler to fetch it on exiting the ISR. */
00116 
00117         "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). */
00118         "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). */
00119         "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). */
00120         "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). */
00121         "PUSH  {r4-r7}       \n\t" /* Push zeros (R4-R7) to stack to prepare for exiting the interrupt routine. */
00122 
00123         "LDR   R0,=EXC_RETURN_CMD\n\t" /* Load the execution return command into register. */
00124         "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. */
00125         : /* output operands */
00126         : /* input operands */
00127         : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" /* clobber list */
00128         );
00129 }
00130 #endif /* TOOLCHAIN_ARM */
00131 
00132 void bootloader_util_app_start(uint32_t start_addr)
00133 {
00134     bootloader_util_reset(start_addr);
00135 }