blob: c744a5bc5e28118336ee056e857e75f1de2e78a2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <stddef.h>
#include <inttypes.h>
#include <mcu/cortex_m33.h>
#include <mcu/nrf5340_hal.h>
#include <bsp/bsp.h>
#include <nrf_gpio.h>
#if MCUBOOT_MYNEWT
#include <bootutil/bootutil.h>
#endif
#include <os/util.h>
#if MYNEWT_VAL(BOOT_LOADER) && !MYNEWT_VAL(MCU_APP_SECURE)
struct periph_id_range {
uint8_t first;
uint8_t last;
};
/* Array of peripheral ID ranges that will be set as unsecure before bootloader jumps to application code */
static const struct periph_id_range ns_peripheral_ids[] = {
{ 0, 0 },
{ 4, 6 },
{ 8, 12 },
{ 14, 17 },
{ 20, 21 },
{ 23, 36 },
{ 38, 38 },
{ 40, 40 },
{ 42, 43 },
{ 45, 45 },
{ 48, 48 },
{ 51, 52 },
{ 54, 55 },
{ 57, 57 },
{ 66, 66 },
{ 128, 129 },
};
/* Below is to unmangle comma separated GPIO pins from MYNEWT_VAL */
#define _Args(...) __VA_ARGS__
#define STRIP_PARENS(X) X
#define UNMANGLE_MYNEWT_VAL(X) STRIP_PARENS(_Args X)
#if MYNEWT_VAL(MCU_GPIO_NET)
static const unsigned int net_gpios[] = { UNMANGLE_MYNEWT_VAL(MYNEWT_VAL(MCU_GPIO_NET)) };
#endif
#if MYNEWT_VAL(MCU_GPIO_PERIPH)
static const unsigned int periph_gpios[] = { UNMANGLE_MYNEWT_VAL(MYNEWT_VAL(MCU_GPIO_PERIPH)) };
#endif
extern uint8_t __StackTop[];
void
hal_system_start(void *img_start)
{
int i;
int j;
int range_count;
struct flash_sector_range sr;
uintptr_t *img_data;
/* Number of 16kB flash regions used by bootloader */
int bootloader_flash_regions;
__attribute__((cmse_nonsecure_call, noreturn)) void (* app_reset)(void);
__disable_irq();
/* Mark selected peripherals as unsecure */
for (i = 0; i < ARRAY_SIZE(ns_peripheral_ids); ++i) {
for (j = ns_peripheral_ids[i].first; j <= ns_peripheral_ids[i].last; ++j) {
if (((NRF_SPU->PERIPHID[j].PERM & SPU_PERIPHID_PERM_PRESENT_Msk) == 0) ||
((NRF_SPU->PERIPHID[j].PERM & SPU_PERIPHID_PERM_SECUREMAPPING_Msk) < SPU_PERIPHID_PERM_SECUREMAPPING_UserSelectable)) {
continue;
}
NRF_SPU->PERIPHID[j].PERM &= ~SPU_PERIPHID_PERM_SECATTR_Msk;
}
}
/* Route exceptions to non-secure, allow software reset from non-secure */
SCB->AIRCR = 0x05FA0000 | (SCB->AIRCR & (~SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_SYSRESETREQS_Msk)) | SCB_AIRCR_BFHFNMINS_Msk;
for (i = 0; i < ARRAY_SIZE(NVIC->ITNS); ++i) {
NVIC->ITNS[i] = 0xFFFFFFFF;
}
/* Mark non-bootloader flash regions as non-secure */
flash_area_to_sector_ranges(FLASH_AREA_BOOTLOADER, &range_count, &sr);
bootloader_flash_regions = (sr.fsr_sector_count * sr.fsr_sector_size) / 0x4000;
for (i = bootloader_flash_regions; i < 64; ++i) {
NRF_SPU->FLASHREGION[i].PERM &= ~SPU_FLASHREGION_PERM_SECATTR_Msk;
}
/* Mark RAM as non-secure */
for (i = 0; i < 64; ++i) {
NRF_SPU->RAMREGION[i].PERM &= ~SPU_FLASHREGION_PERM_SECATTR_Msk;
}
/* Move DPPI to non-secure area */
NRF_SPU->DPPI->PERM = 0;
/* Move GPIO to non-secure area */
NRF_SPU->GPIOPORT[0].PERM = 0;
NRF_SPU->GPIOPORT[1].PERM = 0;
#if MYNEWT_VAL(MCU_GPIO_NET)
for (i = 0; i < ARRAY_SIZE(net_gpios); ++i) {
nrf_gpio_pin_mcu_select(net_gpios[i], GPIO_PIN_CNF_MCUSEL_NetworkMCU);
}
#endif
#if MYNEWT_VAL(MCU_GPIO_PERIPH)
for (i = 0; i < ARRAY_SIZE(periph_gpios); ++i) {
nrf_gpio_pin_mcu_select(periph_gpios[i], GPIO_PIN_CNF_MCUSEL_Peripheral);
}
#endif
/*
* For now whole RAM is marked as non-secure. To prevent data leak from secure to
* non-secure, whole RAM is cleared before starting application code.
* Interrupt VTOR for secure world that was previously put in RAM is moved to
* flash again.
*/
SCB->VTOR = 0;
/*
* Normal loop here is inlined by GCC to call to memset hence asm version of
* memset that does not use stack (that just get erased).
*/
asm volatile(" mov r0, #0 \n"
"1: stmia %0!, {r0} \n"
" cmp %0, %1 \n"
" blt 1b \n"
:
: "r" (&_ram_start), "r" (&__StackTop)
: "r0");
/* Application startup code expects interrupts to be enabled */
__enable_irq();
img_data = img_start;
app_reset = (void *)(img_data[1]);
__TZ_set_MSP_NS(img_data[0]);
app_reset();
}
#else
/**
* Boots the image described by the supplied image header.
*
* @param hdr The header for the image to boot.
*/
void __attribute__((naked))
hal_system_start(void *img_start)
{
uint32_t *img_data = img_start;
asm volatile (".syntax unified \n"
/* 1st word is stack pointer */
" msr msp, %0 \n"
/* 2nd word is a reset handler (image entry) */
" bx %1 \n"
: /* no output */
: "r" (img_data[0]), "r" (img_data[1]));
}
#endif
/**
* Boots the image described by the supplied image header.
* This routine is used in split-app scenario when loader decides
* that it wants to run the app instead.
*
* @param hdr The header for the image to boot.
*/
void
hal_system_restart(void *img_start)
{
int i;
/*
* NOTE: on reset, PRIMASK should have global interrupts enabled so
* the code disables interrupts, clears the interrupt enable bits,
* clears any pending interrupts, then enables global interrupts
* so processor looks like state it would be in if it reset.
*/
__disable_irq();
for (i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++) {
NVIC->ICER[i] = 0xffffffff;
}
for (i = 0; i < sizeof(NVIC->ICPR) / sizeof(NVIC->ICPR[0]); i++) {
NVIC->ICPR[i] = 0xffffffff;
}
__enable_irq();
hal_system_start(img_start);
}