wolfBoot/src/boot_arm.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 */