mirror of https://github.com/wolfSSL/wolfBoot.git
524 lines
13 KiB
C
524 lines
13 KiB
C
/* boot_arm.c
|
|
*
|
|
* Copyright (C) 2021 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfBoot.
|
|
*
|
|
* wolfBoot is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfBoot is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "image.h"
|
|
#include "loader.h"
|
|
#include "wolfboot/wolfboot.h"
|
|
|
|
extern unsigned int _start_text;
|
|
extern unsigned int _stored_data;
|
|
extern unsigned int _start_data;
|
|
extern unsigned int _end_data;
|
|
extern unsigned int _start_bss;
|
|
extern unsigned int _end_bss;
|
|
|
|
extern uint32_t *END_STACK;
|
|
|
|
extern void main(void);
|
|
|
|
#ifndef WOLFBOOT_NO_MPU
|
|
|
|
#define MPU_BASE (0xE000ED90)
|
|
#define MPU_TYPE *((volatile uint32_t *)(MPU_BASE + 0x00))
|
|
#define MPU_CTRL *((volatile uint32_t *)(MPU_BASE + 0x04))
|
|
#define MPU_RNR *((volatile uint32_t *)(MPU_BASE + 0x08))
|
|
#define MPU_RBAR *((volatile uint32_t *)(MPU_BASE + 0x0C))
|
|
#define MPU_RASR *((volatile uint32_t *)(MPU_BASE + 0x10))
|
|
|
|
#define MPU_RASR_ENABLE (1 << 0)
|
|
#define MPU_RASR_ATTR_XN (1 << 28)
|
|
#define MPU_RASR_ATTR_AP (7 << 24)
|
|
#define MPU_RASR_ATTR_AP_PNO_UNO (0 << 24)
|
|
#define MPU_RASR_ATTR_AP_PRW_UNO (1 << 24)
|
|
#define MPU_RASR_ATTR_AP_PRW_URO (2 << 24)
|
|
#define MPU_RASR_ATTR_AP_PRW_URW (3 << 24)
|
|
#define MPU_RASR_ATTR_AP_PRO_UNO (5 << 24)
|
|
#define MPU_RASR_ATTR_AP_PRO_URO (6 << 24)
|
|
#define MPU_RASR_ATTR_TEX (7 << 19)
|
|
#define MPU_RASR_ATTR_S (1 << 18)
|
|
#define MPU_RASR_ATTR_C (1 << 17)
|
|
#define MPU_RASR_ATTR_B (1 << 16)
|
|
#define MPU_RASR_ATTR_SCB (7 << 16)
|
|
|
|
static int mpu_is_on = 0;
|
|
|
|
static void mpu_setaddr(int region, uint32_t addr)
|
|
{
|
|
MPU_RNR = region;
|
|
MPU_RBAR = addr;
|
|
}
|
|
|
|
static void mpu_setattr(int region, uint32_t attr)
|
|
{
|
|
MPU_RNR = region;
|
|
MPU_RASR = attr;
|
|
}
|
|
|
|
static void mpu_on(void)
|
|
{
|
|
if (mpu_is_on)
|
|
return;
|
|
if (MPU_TYPE == 0)
|
|
return;
|
|
MPU_CTRL = 1;
|
|
mpu_is_on = 1;
|
|
}
|
|
|
|
#define MPUSIZE_8K (0x0c << 1)
|
|
#define MPUSIZE_16K (0x0d << 1)
|
|
#define MPUSIZE_32K (0x0e << 1)
|
|
#define MPUSIZE_64K (0x0f << 1)
|
|
/* ... */
|
|
#define MPUSIZE_256M (0x1b << 1)
|
|
#define MPUSIZE_512M (0x1c << 1)
|
|
#define MPUSIZE_1G (0x1d << 1)
|
|
#define MPUSIZE_4G (0x1f << 1)
|
|
#define MPUSIZE_ERR (0xff << 1)
|
|
|
|
static uint32_t mpusize(uint32_t size)
|
|
{
|
|
if (size <= (8 * 1024))
|
|
return MPUSIZE_8K;
|
|
if (size <= (16 * 1024))
|
|
return MPUSIZE_16K;
|
|
if (size <= (32 * 1024))
|
|
return MPUSIZE_32K;
|
|
if (size <= (64 * 1024))
|
|
return MPUSIZE_64K;
|
|
return MPUSIZE_ERR;
|
|
}
|
|
|
|
static void mpu_init(void)
|
|
{
|
|
uint32_t wolfboot_flash_size = (uint32_t)&_stored_data -
|
|
(uint32_t)&_start_text;
|
|
uint32_t wolfboot_mpusize;
|
|
uint32_t ram_base = (uint32_t)(&_start_data);
|
|
uint32_t flash_base = (uint32_t)(&_start_text);
|
|
if (MPU_TYPE == 0)
|
|
return;
|
|
|
|
/* Read access to address space with XN */
|
|
mpu_setaddr(0, 0);
|
|
mpu_setattr(0, MPUSIZE_4G | MPU_RASR_ENABLE | MPU_RASR_ATTR_SCB |
|
|
MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN);
|
|
|
|
wolfboot_mpusize = mpusize(wolfboot_flash_size);
|
|
if (wolfboot_mpusize == MPUSIZE_ERR)
|
|
return;
|
|
|
|
/* wolfBoot .text section in flash memory (exec OK) */
|
|
mpu_setaddr(1, flash_base);
|
|
mpu_setattr(1, wolfboot_mpusize | MPU_RASR_ENABLE | MPU_RASR_ATTR_SCB |
|
|
MPU_RASR_ATTR_AP_PRW_UNO);
|
|
|
|
/* Data in RAM */
|
|
mpu_setaddr(2, ram_base);
|
|
|
|
mpu_setattr(2, MPUSIZE_64K | MPU_RASR_ENABLE | MPU_RASR_ATTR_SCB |
|
|
MPU_RASR_ATTR_AP_PRW_UNO
|
|
#ifndef RAM_CODE
|
|
| MPU_RASR_ATTR_XN
|
|
#endif
|
|
);
|
|
|
|
/* Peripherals 0x40000000:0x5FFFFFFF (512MB)*/
|
|
mpu_setaddr(5, 0x40000000);
|
|
mpu_setattr(5, MPUSIZE_512M | MPU_RASR_ENABLE | MPU_RASR_ATTR_S |
|
|
MPU_RASR_ATTR_B | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN);
|
|
|
|
/* External peripherals 0xA0000000:0xCFFFFFFF (1GB)*/
|
|
mpu_setaddr(6, 0xA0000000);
|
|
mpu_setattr(6, MPUSIZE_1G | MPU_RASR_ENABLE | MPU_RASR_ATTR_S |
|
|
MPU_RASR_ATTR_B | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN);
|
|
|
|
/* System control 0xE0000000:0xEFFFFFF */
|
|
mpu_setaddr(7, 0xE0000000);
|
|
mpu_setattr(7, MPUSIZE_256M | MPU_RASR_ENABLE | MPU_RASR_ATTR_S |
|
|
MPU_RASR_ATTR_B | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN);
|
|
mpu_on();
|
|
}
|
|
|
|
static void RAMFUNCTION mpu_off(void)
|
|
{
|
|
mpu_is_on = 0;
|
|
MPU_CTRL = 0;
|
|
}
|
|
#else
|
|
#define mpu_init() do{}while(0)
|
|
#define mpu_off() do{}while(0)
|
|
#endif /* !WOLFBOOT_NO_MPU */
|
|
|
|
|
|
#ifdef CORTEX_R5
|
|
#define MINITGCR ((volatile uint32_t *)0xFFFFFF5C)
|
|
#define MSINENA ((volatile uint32_t *)0xFFFFFF60)
|
|
#define MSTCGSTAT ((volatile uint32_t *)0xFFFFFF68)
|
|
|
|
#define MINIDONE_FLAG 0x0100
|
|
|
|
asm(
|
|
" .global __STACK_END\n"
|
|
"_c_int00:\n"
|
|
" movw sp, __STACK_END\n"
|
|
" movt sp, __STACK_END\n"
|
|
" b isr_reset\n"
|
|
);
|
|
#endif
|
|
|
|
void isr_reset(void) {
|
|
register unsigned int *src, *dst;
|
|
#if defined(PLATFORM_kinetis)
|
|
/* Immediately disable Watchdog after boot */
|
|
/* Write Keys to unlock register */
|
|
*((volatile unsigned short *)0x4005200E) = 0xC520;
|
|
*((volatile unsigned short *)0x4005200E) = 0xD928;
|
|
/* disable watchdog via STCTRLH register */
|
|
*((volatile unsigned short *)0x40052000) = 0x01D2u;
|
|
#endif
|
|
|
|
/* init stack pointers and SRAM */
|
|
#ifdef CORTEX_R5
|
|
/* 2.2.4.2 Auto-Initialization of On-Chip SRAM Modules */
|
|
/* 1. Set memory self-init */
|
|
*MINITGCR = 0xA;
|
|
*MSTCGSTAT = 0;
|
|
/* 2. enable self-init for L2 SRAM (see Table 2-7 of TRM) */
|
|
*MSINENA = 0x1;
|
|
/* 3-5. wait to complete */
|
|
while ( (*MSTCGSTAT & MINIDONE_FLAG) != MINIDONE_FLAG)
|
|
;
|
|
/* set opposite bit pattern to maximize not setting incorrectly (2.5.1.21 note) */
|
|
*MINITGCR = 0x5;
|
|
/* Clear global stat */
|
|
*MSTCGSTAT = 0;
|
|
|
|
/* init stack pointers */
|
|
|
|
asm(
|
|
" cps #0x1f\n"
|
|
" movw sp, __STACK_END\n"
|
|
" movt sp, __STACK_END\n"
|
|
);
|
|
#endif
|
|
|
|
/* Copy the .data section from flash to RAM. */
|
|
src = (unsigned int *) &_stored_data;
|
|
dst = (unsigned int *) &_start_data;
|
|
while (dst < (unsigned int *)&_end_data) {
|
|
*dst = *src;
|
|
dst++;
|
|
src++;
|
|
}
|
|
|
|
/* Initialize the BSS section to 0 */
|
|
dst = &_start_bss;
|
|
while (dst < (unsigned int *)&_end_bss) {
|
|
*dst = 0U;
|
|
dst++;
|
|
}
|
|
|
|
mpu_init();
|
|
|
|
/* Run the program! */
|
|
main();
|
|
}
|
|
|
|
#ifdef CORTEX_R5
|
|
|
|
/* forward to app handler */
|
|
|
|
/* jump to address in only parameter */
|
|
__attribute__ ((section(".text")))
|
|
const void* isr_table2[] = {
|
|
(void*)(WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE + 0x08),
|
|
(void*)(WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE + 0x08),
|
|
(void*)(WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE + 0x08),
|
|
(void*)(WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE + 0x08),
|
|
};
|
|
|
|
void isr_swi(void);
|
|
void isr_abort_prefetch(void);
|
|
void isr_abort_data(void);
|
|
void isr_reserved(void);
|
|
|
|
asm(
|
|
"isr_table:\n"
|
|
" .word isr_table2"
|
|
);
|
|
|
|
asm(
|
|
"isr_swi:"
|
|
" mov r1, #0x00\n"
|
|
" ldr r0, isr_table\n"
|
|
" ldr r0, [r0, r1]\n"
|
|
" bx r0\n");
|
|
asm(
|
|
"isr_abort_prefetch:"
|
|
" mov r1, #0x04\n"
|
|
" ldr r0, isr_table\n"
|
|
" ldr r0, [r0, r1]\n"
|
|
" bx r0\n");
|
|
asm(
|
|
"isr_abort_data:"
|
|
" mov r1, #0x08\n"
|
|
" ldr r0, isr_table\n"
|
|
" ldr r0, [r0, r1]\n"
|
|
" bx r0\n");
|
|
asm(
|
|
"isr_reserved:"
|
|
" mov r1, #0x0c\n"
|
|
" ldr r0, isr_table\n"
|
|
" ldr r0, [r0, r1]\n"
|
|
" bx r0\n");
|
|
|
|
|
|
|
|
#endif /* CORTEX_R5 */
|
|
|
|
void isr_fault(void)
|
|
{
|
|
/* Panic. */
|
|
while(1) ;;
|
|
}
|
|
|
|
void isr_empty(void)
|
|
{
|
|
/* Ignore unmapped event and continue */
|
|
}
|
|
|
|
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
|
# define isr_securefault isr_fault
|
|
#else
|
|
# define isr_securefault 0
|
|
#endif
|
|
|
|
/* This is the main loop for the bootloader.
|
|
*
|
|
* It performs the following actions:
|
|
* - globally disable interrupts
|
|
* - update the Interrupt Vector using the address of the app
|
|
* - Set the initial stack pointer and the offset of the app
|
|
* - Change the stack pointer
|
|
* - Call the application entry point
|
|
*
|
|
*/
|
|
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
|
#define VTOR (*(volatile uint32_t *)(0xE002ED08)) // SCB_NS -> VTOR
|
|
#else
|
|
#define VTOR (*(volatile uint32_t *)(0xE000ED08))
|
|
#endif
|
|
|
|
|
|
static void *app_entry;
|
|
static uint32_t app_end_stack;
|
|
|
|
|
|
void RAMFUNCTION do_boot(const uint32_t *app_offset)
|
|
{
|
|
#if defined(CORTEX_R5)
|
|
(void)app_entry;
|
|
(void)app_end_stack;
|
|
/* limitations with TI arm compiler requires assembly */
|
|
asm volatile("do_boot_r5:\n"
|
|
" mov pc, r0\n");
|
|
|
|
#elif defined(CORTEX_M33) /* Armv8 boot procedure */
|
|
|
|
/* Get stack pointer, entry point */
|
|
app_end_stack = (*((uint32_t *)(app_offset)));
|
|
app_entry = (void *)(*((uint32_t *)(app_offset + 1)));
|
|
/* Disable interrupts */
|
|
asm volatile("cpsid i");
|
|
/* Update IV */
|
|
VTOR = ((uint32_t)app_offset);
|
|
asm volatile("msr msplim, %0" ::"r"(0));
|
|
# if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
|
|
asm volatile("msr msp_ns, %0" ::"r"(app_end_stack));
|
|
/* Jump to non secure app_entry */
|
|
asm volatile("mov r7, %0" ::"r"(app_entry));
|
|
asm volatile("bic.w r7, r7, #1");
|
|
asm volatile("blxns r7" );
|
|
# else
|
|
asm volatile("msr msp, %0" ::"r"(app_end_stack));
|
|
asm volatile("mov pc, %0":: "r"(app_entry));
|
|
# endif
|
|
|
|
#else /* Armv6/v7 boot procedure */
|
|
|
|
mpu_off();
|
|
# ifndef NO_VTOR
|
|
/* Disable interrupts */
|
|
asm volatile("cpsid i");
|
|
/* Update IV */
|
|
VTOR = ((uint32_t)app_offset);
|
|
# endif
|
|
/* Get stack pointer, entry point */
|
|
app_end_stack = (*((uint32_t *)(app_offset)));
|
|
app_entry = (void *)(*((uint32_t *)(app_offset + 1)));
|
|
|
|
/* Update stack pointer */
|
|
asm volatile("msr msp, %0" ::"r"(app_end_stack));
|
|
# ifndef NO_VTOR
|
|
asm volatile("cpsie i");
|
|
# endif
|
|
|
|
/* Unconditionally jump to app_entry */
|
|
asm volatile("mov pc, %0" ::"r"(app_entry));
|
|
#endif
|
|
}
|
|
|
|
#ifdef PLATFORM_psoc6
|
|
typedef void(*NMIHANDLER)(void);
|
|
# define isr_NMI (NMIHANDLER)(0x0000000D)
|
|
#else
|
|
# define isr_NMI isr_empty
|
|
#endif
|
|
|
|
#ifdef CORTEX_R5
|
|
asm volatile (
|
|
" .sect \".isr_vector\"\n"
|
|
"resetEntry:\n"
|
|
" b _c_int00\n" // Reset
|
|
" b isr_fault\n" // Undefined
|
|
" b isr_swi \n" // Software interrupt
|
|
" b isr_abort_prefetch\n" // Abort (Prefetch)
|
|
" b isr_abort_data\n" // Abort (Data)
|
|
" b isr_reserved\n" // Reserved
|
|
" ldr pc,[pc,#-0x1b0]\n" // IRQ |
|
|
" ldr pc,[pc,#-0x1b0]\n" // FIQ
|
|
);
|
|
|
|
#else
|
|
__attribute__ ((section(".isr_vector")))
|
|
void (* const IV[])(void) =
|
|
{
|
|
(void (*)(void))(&END_STACK),
|
|
isr_reset, // Reset
|
|
isr_NMI, // NMI
|
|
isr_fault, // HardFault
|
|
isr_fault, // MemFault
|
|
isr_fault, // BusFault
|
|
isr_fault, // UsageFault
|
|
isr_securefault, // SecureFault on M23/33, reserved otherwise (0)
|
|
0, // reserved
|
|
0, // reserved
|
|
0, // reserved
|
|
isr_empty, // SVC
|
|
isr_empty, // DebugMonitor
|
|
0, // reserved
|
|
isr_empty, // PendSV
|
|
isr_empty, // SysTick
|
|
#if defined(PLATFORM_stm32l5) ||defined(PLATFORM_stm32u5) /* Fill with extra unused handlers */
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
isr_empty,
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
#ifdef RAM_CODE
|
|
|
|
#ifdef CORTEX_R5
|
|
// Section 2.5.1.45 of spnu563A
|
|
# define SYSECR *((volatile uint32_t *)0xFFFFFFE0)
|
|
# define ECR_RESET (1 << 15)
|
|
#else
|
|
# define AIRCR *(volatile uint32_t *)(0xE000ED0C)
|
|
# define AIRCR_VKEY (0x05FA << 16)
|
|
# define AIRCR_SYSRESETREQ (1 << 2)
|
|
#endif
|
|
|
|
void RAMFUNCTION arch_reboot(void)
|
|
{
|
|
#ifdef CORTEX_R5
|
|
SYSECR = ECR_RESET;
|
|
#else
|
|
AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY;
|
|
#endif
|
|
while(1)
|
|
;
|
|
}
|
|
#endif /* RAM_CODE */
|