Files
2025-04-12 13:34:38 +01:00

224 lines
7.5 KiB
C

/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : main.c
Purpose : Generic application start
*/
#include <stdio.h>
#include "em_device.h"
/// Bare boot table. Can be mapped on top of vector table to access contents.
typedef struct {
/// Pointer to top of stack
uint32_t *stackTop;
/// Pointer to reset vector
void (*resetVector)(void);
/// Reserved pointers to fault handlers
uint32_t reserved0[5];
/// Reserved pointers to RESERVED fields
uint32_t reserved1[3];
/// Pointer to bootloader table
void *table;
/// Reserved pointers to SVC and DebugMon interrupts
uint32_t reserved2[2];
/// Pointer to application signature
void *signature;
} BareBootTable_t;
#define BTL_FIRST_STAGE_BASE FLASH_BASE
#define BTL_APPLICATION_BASE (FLASH_BASE + 0x00006000UL)
__attribute__ ((noreturn)) static void jumpToApplicationRoutine(uint32_t startOfAppSpace);
//static void bootToApp(uint32_t startOfAppSpace);
/*********************************************************************
*
* main()
*
* Function description
* Application entry point.
*/
int btl_main(void) {
int i;
printf("Running the bootloader!\n");
for (i = 0; i < 100; i++) {
printf("Hello World %d!\n", i);
}
//TODO trigger reset
do {
i++;
} while (1);
}
/**
* Jump to app
*/
/*
__attribute__ ((noreturn, naked)) static void bootToApp(uint32_t startOfAppSpace)
{
jumpToApplicationRoutine(startOfAppSpace);
while (1) {
// Do nothing
}
}
*/
__attribute__ ((noreturn)) static inline void jumpToApplicationRoutine(uint32_t startOfAppSpace)
{
#if defined(BOOTLOADER_SECURE)
// Erase rw section
__ASM volatile(
"ldr r3,=0 \n"
"mov r1, %[rwStart] \n" // Load start address
"mov r2, %[rwEnd] \n" // Load end address
#if defined(__GNUC__)
"mov r4, %[bssStart] \n" // Load bss section start address
"mov r5, %[bssEnd] \n" // Load bss section end address
#endif
"data_clean_up_loop: \n"
"cmp r1, r2 \n" // Check if we have reached the end address
"beq data_clean_up_finished \n"
"str r3, [r1] \n" // Clear the RAM content pointed by R1
"add r1, r1, #4 \n" // Increment by 4 to get to the next word address
"b data_clean_up_loop \n"
"data_clean_up_finished: \n"
#if defined(__GNUC__)
"bss_clean_up_loop: \n"
"cmp r4, r5 \n" // Check if we have reached the end address
"beq bss_clean_up_finished \n"
"str r3, [r4] \n" // Clear the RAM content pointed by R4
"add r4, r4, #4 \n" // Increment by 4 to get to the next word address
"b bss_clean_up_loop \n"
"bss_clean_up_finished: \n"
#endif
: //No outputs
#if defined(__GNUC__)
:[rwStart] "r" (&__data_start__), [rwEnd] "r" (&__data_end__), [bssStart] "r" (&__bss_start__), [bssEnd] "r" (&__bss_end__) //Inputs
: "r1", "r2", "r3", "r4", "r5" //Clobbered registers
);
#else
:[rwStart] "r" (&STACKSEAL$$Limit), [rwEnd] "r" (&HEAP$$Base) //Inputs
: "r1", "r2", "r3" //Clobbered registers
);
#endif
#if defined(TEST_BOOTLOADER_RAM_CLEAN_UP)
__ASM volatile(
"mov r5, %[dataSection] \n" // Address of the last word in the rw section
"mov r6, %[stackSection] \n" // Address of the last word in the stack section
"mov r7, #0xFEEB \n" // Magic word stored at the end of data and stack sections
"sub r5, r5, #4 \n"
"sub r6, r6, #4 \n"
"str r7, [r5] \n" // Store magic word at the end of data section
"str r7, [r6] \n" // Store magic word at the end of stack section
: //No outputs
#if defined(__GNUC__)
:[dataSection] "r" (&__bss_end__), [stackSection] "r" (&__StackTop) //Inputs
: "r5", "r6", "r7", "r3" //Clobbered registers
);
#else
:[dataSection] "r" (&HEAP$$Base), [stackSection] "r" (&CSTACK$$Limit) //Inputs
: "r5", "r6", "r7", "r3" //Clobbered registers
);
#endif
#endif // end of TEST_BOOTLOADER_RAM_CLEAN_UP
#endif // end of BOOTLOADER_SECURE
#if defined(BOOTLOADER_SECURE)
// We should not leave any traces of the secure bootloader before jumping into the application
// clean up entire RAM content except for the reset reason word
__ASM volatile(
"ldr r4,=0 \n"
"mov r2, %[stackBase] \n" // Load start address
"mov r3, %[stackTop] \n" // Load end address
#if defined(TEST_BOOTLOADER_RAM_CLEAN_UP)
"sub r3, r3, #4 \n" // Account for magic word at the top of stack section
#endif
"mov r1, %[ramBase] \n"
"cmp r2, r1 \n" // Check if stack base is equal to SRAM_BASE
"bne ram_clean_up_loop \n"
"add r2, r2, #4 \n" // Increment by 4 to omit reset reason word in SRAM
"ram_clean_up_loop: \n"
"cmp r2, r3 \n" // Check if we have reached the end address
"beq ram_clean_up_finished \n"
"str r4, [r2] \n" // Clear the RAM content pointed by R2
"add r2, r2, #4 \n" // Increment by 4 to get to the next word address
"b ram_clean_up_loop \n"
"ram_clean_up_finished: \n"
#else
// Load SP and PC of application
__ASM volatile(
#endif // BOOTLOADER_SECURE
"mov r0, %[startOfAppSpace] \n" // Load address of SP into R0
"ldr r1, [r0] \n" // Load SP into R1
"msr msp, r1 \n" // Set MSP
"msr psp, r1 \n" // Set PSP
"ldr r0, [r0, #4] \n" // Load PC into R0
"mov pc, r0 \n" // Set PC
: // No outputs
#if defined(BOOTLOADER_SECURE)
#if defined(__GNUC__)
:[startOfAppSpace] "r" (startOfAppSpace), [stackBase] "r" (&__StackLimit), [stackTop] "r" (&__StackTop), [ramBase] "r" (SRAM_BASE) // Inputs
: "r0", "r1", "r2", "r3", "r4" // Clobbered registers
);
#else
:[startOfAppSpace] "r" (startOfAppSpace), [stackBase] "r" (&CSTACK$$Base), [stackTop] "r" (&CSTACK$$Limit), [ramBase] "r" (SRAM_BASE)
: "r0", "r1", "r2", "r3", "r4" // Clobbered registers
);
#endif // __GNUC__
#else
:[startOfAppSpace] "r" (startOfAppSpace) // Inputs
: "r0", "r1" // Clobbered registers
);
#endif // BOOTLOADER_SECURE
while (1) {
// Do nothing
}
}
/**************************************************************************//**
* @brief
* Initialize the system.
*
* @details
* Do required generic HW system init.
*
* @note
* This function is invoked during system init, before the main() routine
* and any data has been initialized. For this reason, it cannot do any
* initialization of variables etc.
*****************************************************************************/
void btl_init(void)
{
BareBootTable_t* startOfAppSpace = (BareBootTable_t *)BTL_APPLICATION_BASE;
// does application exist
uint32_t pc = *(uint32_t *)(startOfAppSpace + 4);
if (pc == 0xFFFFFFFF) {
printf("no data in application image!\n");
return;
}
SCB->VTOR = (uint32_t)startOfAppSpace;
jumpToApplicationRoutine((uint32_t)startOfAppSpace);
}
/*************************** End of file ****************************/