mirror of https://github.com/wolfSSL/wolfBoot.git
768 lines
23 KiB
C
768 lines
23 KiB
C
/* nrf5340.c
|
|
*
|
|
* Copyright (C) 2024 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 3 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
|
|
*/
|
|
|
|
/* Note: Also used by TARGET_nrf5340_net */
|
|
#ifdef TARGET_nrf5340
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "image.h"
|
|
#include "string.h"
|
|
#include "printf.h"
|
|
#include "nrf5340.h"
|
|
#include "spi_flash.h"
|
|
|
|
/* TODO:
|
|
* Key Storage: See 7.1.18.4.2 Key storage:
|
|
* The key storage region of the UICR can contain multiple keys of different type, including symmetrical keys, hashes, public/private key pairs and other device secrets
|
|
* Key headers are allocated an address range of 0x400 in the UICR memory map, allowing a total of 128 keys to be addressable inside the key storage region.
|
|
* The key storage region contains multiple key slots, where each slot consists of a key header and an associated key value. The key value is limited to 128 bits.
|
|
* Any key size greater than 128 bits must be divided and distributed over multiple key slot instances.
|
|
*/
|
|
|
|
#ifndef USE_RTC
|
|
#define USE_RTC 0 /* Use RTC0 for sleep */
|
|
#endif
|
|
|
|
/* Network updates can be signed with "--id 2" and placed into the normal update partition,
|
|
* or they can be placed into the external flash at offset 0x100000 */
|
|
/* Set Partition ID in .config using WOLFBOOT_PART_ID=2 */
|
|
#ifndef PART_NET_ID
|
|
#define PART_NET_ID 2 /* default */
|
|
#endif
|
|
|
|
/* Offset in external QSPI flash for network update
|
|
* Comes from nrf5340_net.config WOLFBOOT_PARTITION_UPDATE_ADDRESS) */
|
|
#ifndef PART_NET_ADDR
|
|
#define PART_NET_ADDR 0x100000UL
|
|
#endif
|
|
|
|
/* IPC Channels 0/1 */
|
|
/* Channel 0: APP Send -> NET Recv
|
|
* Channel 1: NET Send -> APP Recv */
|
|
#ifdef TARGET_nrf5340_app
|
|
#define USE_IPC_SEND 0
|
|
#define USE_IPC_RECV 1
|
|
#else
|
|
#define USE_IPC_SEND 1
|
|
#define USE_IPC_RECV 0
|
|
#endif
|
|
|
|
/* SHM: Shared Memory between network and application cores */
|
|
/* first 64KB (0x10000) is used by wolfBoot and limited in nrf5340.ld */
|
|
#ifndef SHARED_MEM_ADDR
|
|
#define SHARED_MEM_ADDR (0x20000000UL + (64 * 1024))
|
|
#endif
|
|
|
|
/* Shared memory states (mask, easier to check) */
|
|
#define SHARED_STATUS_UNKNOWN 0x00
|
|
#define SHARED_STATUS_READY 0x01
|
|
#define SHARED_STATUS_VERSION 0x02
|
|
#define SHARED_STATUS_UPDATE_START 0x04
|
|
#define SHARED_STATUS_UPDATE_DONE 0x08
|
|
#define SHARED_STATUS_DO_BOOT 0x10
|
|
#define SHARED_STATUS_TIMEOUT 0x80
|
|
|
|
#define SHAREM_MEM_MAGIC 0x5753484D /* WSHM */
|
|
|
|
typedef struct {
|
|
uint32_t magic;
|
|
uint32_t status;
|
|
uint32_t version; /* always refers to network core version */
|
|
uint32_t size;
|
|
} ShmInfo_t;
|
|
|
|
typedef struct {
|
|
ShmInfo_t net; /* network core write location */
|
|
ShmInfo_t app; /* application core write location */
|
|
} SharedCores_t;
|
|
|
|
typedef struct {
|
|
SharedCores_t core;
|
|
|
|
/* Note: If enableShm=0 do not access below */
|
|
/* application places firmware here */
|
|
uint8_t data[FLASH_SIZE_NET];
|
|
/* used as "swap" */
|
|
uint8_t swap[FLASH_PAGESZ_NET];
|
|
} SharedMem_t;
|
|
|
|
static int enableShm = 0;
|
|
static int doUpdateNet = 0;
|
|
|
|
#ifdef TARGET_nrf5340_app
|
|
static SharedMem_t* shm = (SharedMem_t*)SHARED_MEM_ADDR;
|
|
#else
|
|
static SharedCores_t shm_shadow;
|
|
static SharedMem_t* shm = (SharedMem_t*)&shm_shadow;
|
|
#endif
|
|
|
|
|
|
/* UART */
|
|
#ifdef DEBUG_UART
|
|
#ifndef UART_SEL
|
|
#define UART_SEL 0 /* select UART 0 or 1 */
|
|
#endif
|
|
#if !defined(UART_PORT) && !defined(UART_PIN)
|
|
#if defined(TARGET_nrf5340_app)
|
|
#define UART_PORT 0
|
|
#define UART_PIN 20
|
|
#define UART_NET_PORT 1
|
|
#define UART_NET_PIN 1
|
|
#else
|
|
#define UART_PORT 1
|
|
#define UART_PIN 1
|
|
#endif
|
|
#endif
|
|
|
|
void uart_init(void)
|
|
{
|
|
/* nRF5340-DK: (P0.20 or P1.01)
|
|
* App: UART0=P0.20
|
|
* Net: UART0=P1.01 */
|
|
UART_ENABLE(UART_SEL) = 0;
|
|
GPIO_PIN_CNF(UART_PORT, UART_PIN) = (GPIO_CNF_OUT
|
|
#ifdef TARGET_nrf5340_net
|
|
| GPIO_CNF_MCUSEL(1)
|
|
#endif
|
|
);
|
|
UART_PSEL_TXD(UART_SEL) = (PSEL_PORT(UART_PORT) | UART_PIN);
|
|
UART_BAUDRATE(UART_SEL) = BAUD_115200;
|
|
UART_CONFIG(UART_SEL) = 0; /* Flow=Diabled, Stop=1-bit, Parity exclude */
|
|
UART_ENABLE(UART_SEL) = 8;
|
|
|
|
/* allow network core access to UART pin - must be set from app core */
|
|
#if defined(TARGET_nrf5340_app) && \
|
|
defined(UART_NET_PORT) && defined(UART_NET_PIN)
|
|
GPIO_PIN_CNF(UART_NET_PORT, UART_NET_PIN) =
|
|
(GPIO_CNF_OUT | GPIO_CNF_MCUSEL(1));
|
|
#endif
|
|
}
|
|
|
|
#ifndef UART_TX_MAX_SZ
|
|
#define UART_TX_MAX_SZ 128
|
|
#endif
|
|
void uart_write_sz(const char* c, unsigned int sz)
|
|
{
|
|
/* EasyDMA must be a RAM buffer */
|
|
static uint8_t uartTxBuf[UART_TX_MAX_SZ];
|
|
|
|
while (sz > 0) {
|
|
unsigned int xfer = sz;
|
|
if (xfer > sizeof(uartTxBuf))
|
|
xfer = sizeof(uartTxBuf);
|
|
memcpy(uartTxBuf, c, xfer);
|
|
|
|
UART_EVENT_ENDTX(UART_SEL) = 0;
|
|
|
|
UART_TXD_PTR(UART_SEL) = (uint32_t)uartTxBuf;
|
|
UART_TXD_MAXCOUNT(UART_SEL) = xfer;
|
|
UART_TASK_STARTTX(UART_SEL) = 1;
|
|
while (UART_EVENT_ENDTX(UART_SEL) == 0);
|
|
|
|
sz -= xfer;
|
|
c += xfer;
|
|
}
|
|
}
|
|
|
|
void uart_write(const char* buf, unsigned int sz)
|
|
{
|
|
const char* line;
|
|
unsigned int lineSz;
|
|
do {
|
|
/* find `\n` */
|
|
line = memchr(buf, '\n', sz);
|
|
if (line == NULL) {
|
|
uart_write_sz(buf, sz);
|
|
break;
|
|
}
|
|
lineSz = line - buf;
|
|
if (lineSz > sz-1)
|
|
lineSz = sz-1;
|
|
|
|
uart_write_sz(buf, lineSz);
|
|
uart_write_sz("\r\n", 2); /* handle CRLF */
|
|
|
|
buf = line;
|
|
sz -= lineSz + 1; /* skip \n, already sent */
|
|
} while ((int)sz > 0);
|
|
}
|
|
#endif /* DEBUG_UART */
|
|
|
|
/* Non-volatile memory controller - use actual flash address */
|
|
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
|
|
{
|
|
int i = 0;
|
|
uint32_t *src, *dst;
|
|
#ifdef DEBUG_FLASH
|
|
wolfBoot_printf("Internal Flash Write: addr 0x%x, len %d\n", address, len);
|
|
#endif
|
|
while (i < len) {
|
|
if ((len - i > 3) && ((((address + i) & 0x03) == 0) &&
|
|
((((uint32_t)data) + i) & 0x03) == 0)) {
|
|
src = (uint32_t *)data;
|
|
dst = (uint32_t *)address;
|
|
/* set both secure and non-secure registers */
|
|
NVMC_CONFIG = NVMC_CONFIG_WEN;
|
|
NVMC_CONFIGNS = NVMC_CONFIG_WEN;
|
|
while (NVMC_READY == 0);
|
|
dst[i >> 2] = src[i >> 2];
|
|
while (NVMC_READY == 0);
|
|
i+=4;
|
|
} else {
|
|
uint32_t val;
|
|
uint8_t *vbytes = (uint8_t *)(&val);
|
|
int off = (address + i) - (((address + i) >> 2) << 2);
|
|
dst = (uint32_t *)(address - off);
|
|
val = dst[i >> 2];
|
|
vbytes[off] = data[i];
|
|
/* set both secure and non-secure registers */
|
|
NVMC_CONFIG = NVMC_CONFIG_WEN;
|
|
NVMC_CONFIGNS = NVMC_CONFIG_WEN;
|
|
while (NVMC_READY == 0);
|
|
dst[i >> 2] = val;
|
|
while (NVMC_READY == 0);
|
|
i++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
|
|
{
|
|
uint32_t end = address + len - 1;
|
|
uint32_t p;
|
|
#if defined(DEBUG_FLASH) && DEBUG_FLASH > 1
|
|
wolfBoot_printf("Internal Flash Erase: addr 0x%x, len %d\n", address, len);
|
|
#endif
|
|
/* mask to page start address */
|
|
address &= ~(FLASH_PAGE_SIZE-1);
|
|
for (p = address; p <= end; p += FLASH_PAGE_SIZE) {
|
|
/* set both secure and non-secure registers */
|
|
NVMC_CONFIG = NVMC_CONFIG_EEN;
|
|
NVMC_CONFIGNS = NVMC_CONFIG_EEN;
|
|
while (NVMC_READY == 0);
|
|
*(volatile uint32_t *)p = 0xFFFFFFFF;
|
|
while (NVMC_READY == 0);
|
|
#ifdef DEBUG_FLASH
|
|
wolfBoot_printf("Internal Flash Erase: page 0x%x\n", p);
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void RAMFUNCTION hal_flash_unlock(void)
|
|
{
|
|
}
|
|
|
|
void RAMFUNCTION hal_flash_lock(void)
|
|
{
|
|
}
|
|
|
|
#ifdef TARGET_nrf5340_net
|
|
/* external flash is access application core shared memory directly */
|
|
|
|
/* calculates location in shared memory */
|
|
static uintptr_t ext_flash_addr_calc(uintptr_t address)
|
|
{
|
|
/* offset external flash addresses by the update partition address */
|
|
address -= WOLFBOOT_PARTITION_UPDATE_ADDRESS;
|
|
/* check address */
|
|
if (address >= (FLASH_SIZE_NET + FLASH_PAGESZ_NET)) {
|
|
address = 0;
|
|
}
|
|
return address;
|
|
}
|
|
|
|
int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
|
|
{
|
|
uintptr_t addr = ext_flash_addr_calc(address);
|
|
#ifdef DEBUG_FLASH
|
|
wolfBoot_printf("Ext Write: Len %d, Addr 0x%x (off 0x%x) -> 0x%x\n",
|
|
len, address, addr, data);
|
|
#endif
|
|
if (enableShm)
|
|
memcpy(shm->data + addr, data, len);
|
|
return 0;
|
|
}
|
|
|
|
int ext_flash_read(uintptr_t address, uint8_t *data, int len)
|
|
{
|
|
uintptr_t addr = ext_flash_addr_calc(address);
|
|
#ifdef DEBUG_FLASH
|
|
wolfBoot_printf("Ext Read: Len %d, Addr 0x%x (off 0x%x) -> %p\n",
|
|
len, address, addr, data);
|
|
#endif
|
|
if (enableShm)
|
|
memcpy(data, shm->data + addr, len);
|
|
else
|
|
memset(data, FLASH_BYTE_ERASED, len);
|
|
return len;
|
|
}
|
|
|
|
int ext_flash_erase(uintptr_t address, int len)
|
|
{
|
|
uintptr_t addr = ext_flash_addr_calc(address);
|
|
#ifdef DEBUG_FLASH
|
|
wolfBoot_printf("Ext Erase: Len %d, Addr 0x%x (off 0x%x)\n",
|
|
len, address, addr);
|
|
#endif
|
|
if (enableShm)
|
|
memset(shm->data + addr, FLASH_BYTE_ERASED, len);
|
|
return 0;
|
|
}
|
|
|
|
void ext_flash_lock(void)
|
|
{
|
|
/* no op */
|
|
}
|
|
void ext_flash_unlock(void)
|
|
{
|
|
/* no op */
|
|
}
|
|
#endif /* TARGET_nrf5340_net */
|
|
|
|
static void clock_init(void)
|
|
{
|
|
#ifdef TARGET_nrf5340_app
|
|
CLOCK_HFCLKSRC = 1; /* use external high frequency clock */
|
|
CLOCK_HFCLKSTART = 1;
|
|
/* wait for high frequency clock startup */
|
|
while (CLOCK_HFCLKSTARTED == 0);
|
|
#endif
|
|
/* Start low frequency clock - used by RTC */
|
|
CLOCK_LFCLKSRC = 0; /* internal low power */
|
|
CLOCK_LFCLKSTART = 1;
|
|
/* wait for high frequency clock startup */
|
|
while (CLOCK_LFCLKSTARTED == 0);
|
|
|
|
RTC_PRESCALER(USE_RTC) = 0; /* 32768 per second */
|
|
}
|
|
|
|
void sleep_us(uint32_t usec)
|
|
{
|
|
/* Calculate number ticks to wait */
|
|
uint32_t comp = ((usec * 32768UL) / 1000000);
|
|
if (comp == 0)
|
|
comp = 1; /* wait at least 1 tick */
|
|
if (comp > RTC_OVERFLOW)
|
|
comp = RTC_OVERFLOW; /* max wait (512 seconds with prescaler=0) */
|
|
|
|
RTC_CLEAR(USE_RTC) = 1;
|
|
RTC_EVTENSET(USE_RTC) = RTC_EVTENSET_CC0;
|
|
RTC_EVENT_CC(USE_RTC, 0) = 0; /* clear compare event */
|
|
RTC_CC(USE_RTC, 0) = comp;
|
|
RTC_START(USE_RTC) = 1;
|
|
/* wait for compare event */
|
|
while (RTC_EVENT_CC(USE_RTC, 0) == 0);
|
|
RTC_STOP(USE_RTC) = 1;
|
|
}
|
|
|
|
#ifdef TARGET_nrf5340_app
|
|
void hal_net_core(int hold) /* 1=hold, 0=release */
|
|
{
|
|
if (hold) {
|
|
/* stop the network core from booting */
|
|
NETWORK_FORCEOFF = NETWORK_FORCEOFF_HOLD;
|
|
}
|
|
else {
|
|
/* release network core - errata 161 network core release */
|
|
NETWORK_ERRATA_161 = 1;
|
|
NETWORK_FORCEOFF = NETWORK_FORCEOFF_RELEASE;
|
|
sleep_us(5);
|
|
NETWORK_FORCEOFF = NETWORK_FORCEOFF_HOLD;
|
|
sleep_us(1);
|
|
NETWORK_FORCEOFF = NETWORK_FORCEOFF_RELEASE;
|
|
NETWORK_ERRATA_161 = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static uint8_t* get_image_hdr(struct wolfBoot_image* img)
|
|
{
|
|
#ifdef EXT_FLASH
|
|
return img->hdr_cache;
|
|
#else
|
|
return img->hdr;
|
|
#endif
|
|
}
|
|
static uint16_t get_image_partition_id(struct wolfBoot_image* img)
|
|
{
|
|
return wolfBoot_get_blob_type(get_image_hdr(img)) & HDR_IMG_TYPE_PART_MASK;
|
|
}
|
|
|
|
#define IMAGE_IS_NET_CORE(img) ( \
|
|
(get_image_partition_id(img) == PART_NET_ID) && \
|
|
(img->fw_size < (FLASH_SIZE_NET - IMAGE_HEADER_SIZE)))
|
|
static int hal_net_get_image(struct wolfBoot_image* img, ShmInfo_t* info)
|
|
{
|
|
int ret;
|
|
#ifdef TARGET_nrf5340_app
|
|
/* check the update partition for a network core update */
|
|
ret = wolfBoot_open_image(img, PART_UPDATE);
|
|
if (ret == 0 && !IMAGE_IS_NET_CORE(img)) {
|
|
ret = -1;
|
|
}
|
|
/* if external flash is enabled, try an alternate location */
|
|
#ifdef EXT_FLASH
|
|
if (ret != 0) {
|
|
ret = wolfBoot_open_image_external(img, PART_UPDATE,
|
|
(uint8_t*)PART_NET_ADDR);
|
|
if (ret == 0 && !IMAGE_IS_NET_CORE(img)) {
|
|
ret = -1;
|
|
}
|
|
}
|
|
#endif
|
|
#else /* TARGET_nrf5340_net */
|
|
ret = wolfBoot_open_image(img, PART_BOOT);
|
|
#endif /* TARGET_nrf5340_* */
|
|
if (ret == 0) {
|
|
uint32_t ver = wolfBoot_get_blob_version(get_image_hdr(img));
|
|
/* Note: network core fault writing to shared memory means application
|
|
* core did not enable access at run-time yet */
|
|
info->version = ver;
|
|
info->size = IMAGE_HEADER_SIZE + img->fw_size;
|
|
wolfBoot_printf("Network Image: Ver 0x%x, Size %d\n",
|
|
ver, img->fw_size);
|
|
}
|
|
else {
|
|
info->version = 0; /* not known */
|
|
wolfBoot_printf("Network Image: Update not found\n");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void hal_shm_init(void)
|
|
{
|
|
IPC_SEND_CNF(USE_IPC_SEND) = (1 << USE_IPC_SEND);
|
|
IPC_RECEIVE_CNF(USE_IPC_RECV) = (1 << USE_IPC_RECV);
|
|
IPC_EVENTS_RECEIVE(USE_IPC_SEND) = 0;
|
|
IPC_EVENTS_RECEIVE(USE_IPC_RECV) = 0;
|
|
|
|
#ifdef TARGET_nrf5340_app
|
|
/* Allow the network core to access shared SDRAM at 0x2000_0000 */
|
|
SPU_EXTDOMAIN_PERM(0) =
|
|
(SPU_EXTDOMAIN_PERM_SECATTR_SECURE | SPU_EXTDOMAIN_PERM_UNLOCK);
|
|
#endif
|
|
}
|
|
|
|
static void hal_shm_status_set(ShmInfo_t* info, uint32_t status)
|
|
{
|
|
IPC_TASKS_SEND(USE_IPC_SEND) = 1;
|
|
if (info != NULL) {
|
|
info->magic = SHAREM_MEM_MAGIC;
|
|
info->status = status;
|
|
}
|
|
}
|
|
|
|
static uint32_t hal_shm_status_wait(ShmInfo_t* info, uint32_t status,
|
|
uint32_t timeout_ms)
|
|
{
|
|
uint32_t status_ret = SHARED_STATUS_UNKNOWN;
|
|
int ret = 0;
|
|
|
|
do {
|
|
/* see if status shared already */
|
|
if (info != NULL && (info->magic == SHAREM_MEM_MAGIC &&
|
|
(info->status & status) != 0)) {
|
|
status_ret = info->status;
|
|
break;
|
|
}
|
|
/* Wait for event */
|
|
while (IPC_EVENTS_RECEIVE(USE_IPC_RECV) == 0 && --timeout_ms > 0) {
|
|
sleep_us(1000);
|
|
}
|
|
if (timeout_ms == 0) {
|
|
status_ret = SHARED_STATUS_TIMEOUT;
|
|
break;
|
|
}
|
|
/* clear event */
|
|
IPC_EVENTS_RECEIVE(USE_IPC_RECV) = 0;
|
|
/* if we got an event and "info" not provided, just return status to
|
|
* signal event occurred */
|
|
if (info == NULL) {
|
|
status_ret = status;
|
|
break;
|
|
}
|
|
} while (1);
|
|
return status_ret;
|
|
}
|
|
|
|
static void hal_shm_cleanup(void)
|
|
{
|
|
#ifdef TARGET_nrf5340_app
|
|
/* Restore defaults preventing network core from accessing shared SDRAM */
|
|
SPU_EXTDOMAIN_PERM(0) =
|
|
(SPU_EXTDOMAIN_PERM_SECATTR_NONSECURE | SPU_EXTDOMAIN_PERM_UNLOCK);
|
|
#endif
|
|
}
|
|
|
|
static const char* hal_shm_status_string(uint32_t status)
|
|
{
|
|
switch (status) {
|
|
case SHARED_STATUS_READY:
|
|
return "Ready";
|
|
case SHARED_STATUS_VERSION:
|
|
return "Version";
|
|
case SHARED_STATUS_UPDATE_START:
|
|
return "Update Start";
|
|
case SHARED_STATUS_UPDATE_DONE:
|
|
return "Update Done";
|
|
case SHARED_STATUS_DO_BOOT:
|
|
return "Do boot";
|
|
case SHARED_STATUS_TIMEOUT:
|
|
return "Timeout";
|
|
default:
|
|
break;
|
|
}
|
|
return "Unknown";
|
|
}
|
|
|
|
static int hal_net_signal_wait_ready(uint32_t timeout_ms)
|
|
{
|
|
int ret = 0;
|
|
uint32_t status;
|
|
|
|
/* wait for network core ready */
|
|
do {
|
|
hal_shm_status_set(NULL, SHARED_STATUS_READY);
|
|
status = hal_shm_status_wait(NULL, SHARED_STATUS_READY, 1);
|
|
} while (status == SHARED_STATUS_TIMEOUT && --timeout_ms > 0);
|
|
if (timeout_ms == 0 && status == SHARED_STATUS_TIMEOUT) {
|
|
ret = -1;
|
|
}
|
|
return ret;
|
|
}
|
|
/* Handles network core updates */
|
|
static void hal_net_check_version(void)
|
|
{
|
|
int ret;
|
|
struct wolfBoot_image img;
|
|
uint32_t timeout, status = 0;
|
|
|
|
#ifdef TARGET_nrf5340_app
|
|
/* check the network core version */
|
|
hal_net_get_image(&img, &shm->core.app);
|
|
|
|
/* release network core - issue boot command */
|
|
hal_net_core(0);
|
|
|
|
wolfBoot_printf("Waiting for ready from net core...\n");
|
|
|
|
/* wait for ready status from network core */
|
|
ret = hal_net_signal_wait_ready(500);
|
|
if (ret == 0) {
|
|
enableShm = 1;
|
|
wolfBoot_printf("Net core ready\n");
|
|
|
|
/* wait for version */
|
|
status = hal_shm_status_wait(&shm->core.net,
|
|
SHARED_STATUS_VERSION, 2*1000);
|
|
}
|
|
else {
|
|
wolfBoot_printf("Net core timeout, disable shared mem\n");
|
|
}
|
|
|
|
/* check if network core can continue booting or needs to wait for update */
|
|
if (ret != 0 || shm->core.app.version <= shm->core.net.version) {
|
|
wolfBoot_printf("Network Core: Releasing for boot\n");
|
|
}
|
|
else {
|
|
wolfBoot_printf("Found Network Core update: Ver %d->%d, Size %d->%d\n",
|
|
shm->core.net.version, shm->core.app.version,
|
|
shm->core.net.size, shm->core.app.size);
|
|
|
|
/* validate the update is valid */
|
|
if (wolfBoot_verify_integrity(&img) == 0 &&
|
|
wolfBoot_verify_authenticity(&img) == 0)
|
|
{
|
|
wolfBoot_printf("Network image valid, loading into shared mem\n");
|
|
/* relocate image to shared ram */
|
|
#ifdef EXT_FLASH
|
|
/* must be multiple of 4 (READ.CNT length must be multiple of 4) */
|
|
ret = ext_flash_read(PART_NET_ADDR, shm->data,
|
|
(shm->core.app.size + 3) & ~3);
|
|
#else
|
|
memcpy(shm->data, img.hdr, shm->core.app.size);
|
|
#endif
|
|
/* initialize remainder of shared memory with 0xFF (erased) */
|
|
memset(shm->data + shm->core.app.size, FLASH_BYTE_ERASED,
|
|
sizeof(shm->data) - shm->core.app.size);
|
|
if (ret >= 0) {
|
|
doUpdateNet = 1;
|
|
|
|
/* signal network core to do update */
|
|
hal_shm_status_set(&shm->core.app, SHARED_STATUS_UPDATE_START);
|
|
|
|
#ifndef NRF_SYNC_CORES
|
|
wolfBoot_printf("Waiting for net core update to finish...\n");
|
|
|
|
/* wait for update_done - 30 seconds */
|
|
status = hal_shm_status_wait(&shm->core.net,
|
|
SHARED_STATUS_UPDATE_DONE, 30*1000);
|
|
if (status == SHARED_STATUS_UPDATE_DONE) {
|
|
wolfBoot_printf("Network core firmware update done\n");
|
|
}
|
|
#else
|
|
wolfBoot_printf("Continuing boot while network core updates\n");
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
wolfBoot_printf("Network image failed: Hdr %d, Hash %d, Sig %d\n",
|
|
img.hdr_ok, img.sha_ok, img.signature_ok);
|
|
}
|
|
}
|
|
/* inform network core to boot */
|
|
hal_shm_status_set(&shm->core.app, SHARED_STATUS_DO_BOOT);
|
|
#else /* TARGET_nrf5340_net */
|
|
/* wait for IPC event indicating application core exists */
|
|
ret = hal_net_signal_wait_ready(500);
|
|
if (ret == 0) {
|
|
/* enable use of shared memory */
|
|
shm = (SharedMem_t*)SHARED_MEM_ADDR;
|
|
enableShm = 1;
|
|
}
|
|
else {
|
|
wolfBoot_printf("App core timeout, disable shared mem\n");
|
|
}
|
|
|
|
/* inform application core we are ready */
|
|
hal_shm_status_set(&shm->core.net, SHARED_STATUS_READY);
|
|
|
|
if (enableShm) {
|
|
wolfBoot_printf("App core ready\n");
|
|
|
|
hal_net_get_image(&img, &shm->core.net);
|
|
hal_shm_status_set(&shm->core.net, SHARED_STATUS_VERSION);
|
|
|
|
/* wait for do_boot or update from app core - 2 seconds */
|
|
wolfBoot_printf("Waiting for update or boot from app core...\n");
|
|
status = hal_shm_status_wait(&shm->core.app,
|
|
(SHARED_STATUS_UPDATE_START | SHARED_STATUS_DO_BOOT), 2*1000);
|
|
|
|
/* are we updating? */
|
|
if (status == SHARED_STATUS_UPDATE_START) {
|
|
wolfBoot_printf("Starting update: Ver %d->%d, Size %d->%d\n",
|
|
shm->core.net.version, shm->core.app.version,
|
|
shm->core.net.size, shm->core.app.size);
|
|
doUpdateNet = 1;
|
|
|
|
/* trigger update */
|
|
wolfBoot_set_partition_state(PART_UPDATE, IMG_STATE_UPDATING);
|
|
}
|
|
}
|
|
/* proceed to update_flash routines */
|
|
#endif /* TARGET_nrf5340_* */
|
|
exit:
|
|
wolfBoot_printf("Status: App %s (ver %d), Net %s (ver %d)\n",
|
|
hal_shm_status_string(shm->core.app.status), shm->core.app.version,
|
|
hal_shm_status_string(shm->core.net.status), shm->core.net.version);
|
|
}
|
|
|
|
|
|
void hal_init(void)
|
|
{
|
|
#ifdef DEBUG_UART
|
|
const char* bootStr = "wolfBoot HAL Init (" CORE_STR " core)\n";
|
|
#endif
|
|
|
|
clock_init();
|
|
|
|
#ifdef DEBUG_UART
|
|
uart_init();
|
|
uart_write(bootStr, strlen(bootStr));
|
|
#endif
|
|
|
|
hal_shm_init();
|
|
|
|
/* need early init of external flash to support checking network core */
|
|
spi_flash_probe();
|
|
|
|
hal_net_check_version();
|
|
}
|
|
|
|
/* enable write protection for the region of flash specified */
|
|
int hal_flash_protect(uint32_t start, uint32_t len)
|
|
{
|
|
/* only application core supports SPU */
|
|
#ifdef TARGET_nrf5340_app
|
|
uint32_t region, n, i;
|
|
|
|
/* limit check */
|
|
if (start > FLASH_SIZE)
|
|
return -1;
|
|
/* truncate if exceeds flash size */
|
|
if (start + len > FLASH_SIZE)
|
|
len = FLASH_SIZE - start;
|
|
|
|
region = (start / SPU_BLOCK_SIZE);
|
|
n = (len / SPU_BLOCK_SIZE);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
/* do not allow write to this region and lock till next reset */
|
|
SPU_FLASHREGION_PERM(region+i) = (
|
|
SPU_FLASHREGION_PERM_EXEC |
|
|
SPU_FLASHREGION_PERM_READ |
|
|
SPU_FLASHREGION_PERM_SECATTR |
|
|
SPU_FLASHREGION_PERM_LOCK
|
|
);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void hal_prepare_boot(void)
|
|
{
|
|
/* Write protect bootloader region of flash */
|
|
hal_flash_protect(WOLFBOOT_ORIGIN, BOOTLOADER_PARTITION_SIZE);
|
|
|
|
if (enableShm) {
|
|
#ifdef TARGET_nrf5340_net
|
|
if (doUpdateNet) {
|
|
/* signal application core update done */
|
|
struct wolfBoot_image img;
|
|
/* Reopen image and refresh information */
|
|
hal_net_get_image(&img, &shm->core.net);
|
|
wolfBoot_printf("Network version (after update): 0x%x\n",
|
|
shm->core.net.version);
|
|
hal_shm_status_set(&shm->core.net, SHARED_STATUS_UPDATE_DONE);
|
|
}
|
|
else {
|
|
hal_shm_status_set(&shm->core.net, SHARED_STATUS_DO_BOOT);
|
|
}
|
|
#endif
|
|
|
|
#if defined(TARGET_nrf5340_app) && defined(NRF_SYNC_CORES)
|
|
/* if core synchronization enabled,
|
|
* then wait for update_done or do_boot (5 seconds, 30 for update) */
|
|
wolfBoot_printf("Waiting for network core...\n");
|
|
(void)hal_shm_status_wait(&shm->core.net,
|
|
(SHARED_STATUS_UPDATE_DONE | SHARED_STATUS_DO_BOOT),
|
|
doUpdateNet ? 30*1000 : 5*1000);
|
|
#endif
|
|
}
|
|
|
|
hal_shm_cleanup();
|
|
}
|
|
|
|
#endif /* TARGET_* */
|