178 lines
5.4 KiB
C
178 lines
5.4 KiB
C
/*
|
|
* 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 <assert.h>
|
|
#include <stdint.h>
|
|
#include "mcu/mcu.h"
|
|
#include "mcu/da1469x_hal.h"
|
|
#include <flash_map/flash_map.h>
|
|
#include <mcu/da1469x_clock.h>
|
|
#if MCUBOOT_MYNEWT
|
|
#include "bootutil/bootutil.h"
|
|
#include "bootutil/image.h"
|
|
#include "bootutil/bootutil_log.h"
|
|
#include "mcu/da1469x_dma.h"
|
|
#include "mcu/da1469x_otp.h"
|
|
#endif
|
|
|
|
#if MYNEWT_VAL(BOOT_CUSTOM_START) && MCUBOOT_MYNEWT
|
|
sec_text_ram_core
|
|
#endif
|
|
void __attribute__((naked))
|
|
hal_system_start(void *img_start)
|
|
{
|
|
uint32_t img_data_addr;
|
|
uint32_t *img_data;
|
|
|
|
img_data_addr = MCU_MEM_QSPIF_M_START_ADDRESS + (uint32_t)img_start;
|
|
|
|
assert(img_data_addr < MCU_MEM_QSPIF_M_END_ADDRESS);
|
|
|
|
img_data = (uint32_t *)img_data_addr;
|
|
|
|
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]));
|
|
}
|
|
|
|
void
|
|
hal_system_restart(void *img_start)
|
|
{
|
|
uint32_t primask __attribute__((unused));
|
|
int i;
|
|
|
|
/*
|
|
* Disable interrupts, and leave them disabled.
|
|
* They get re-enabled when system starts coming back again.
|
|
*/
|
|
__HAL_DISABLE_INTERRUPTS(primask);
|
|
|
|
for (i = 0; i < sizeof(NVIC->ICER) / sizeof(NVIC->ICER[0]); i++) {
|
|
NVIC->ICER[i] = 0xffffffff;
|
|
}
|
|
|
|
hal_system_start(img_start);
|
|
}
|
|
|
|
#if MYNEWT_VAL(BOOT_CUSTOM_START) && MCUBOOT_MYNEWT
|
|
#define IMAGE_TLV_AES_NONCE 0x50
|
|
#define IMAGE_TLV_SECRET_ID 0x60
|
|
|
|
sec_text_ram_core void
|
|
boot_custom_start(uintptr_t flash_base, struct boot_rsp *rsp)
|
|
{
|
|
int rc;
|
|
struct image_tlv_iter it;
|
|
const struct flash_area *fap;
|
|
uint32_t off;
|
|
uint16_t len;
|
|
uint16_t type;
|
|
uint8_t buf[8];
|
|
uint8_t key;
|
|
uint32_t nonce[2];
|
|
bool has_aes_nonce;
|
|
bool has_secret_id;
|
|
DMA_Type *dma_regs = DMA;
|
|
uint32_t jump_offset = rsp->br_image_off + rsp->br_hdr->ih_hdr_size;
|
|
|
|
BOOT_LOG_INF("Custom initialization");
|
|
|
|
/* skip to booting if we are running nonsecure mode */
|
|
if (!(CRG_TOP->SECURE_BOOT_REG & 0x1)) {
|
|
hal_system_start((void *)(flash_base + jump_offset));
|
|
}
|
|
|
|
rc = flash_area_open(flash_area_id_from_image_slot(0), &fap);
|
|
assert(rc == 0);
|
|
|
|
rc = bootutil_tlv_iter_begin(&it, rsp->br_hdr, fap, IMAGE_TLV_ANY, true);
|
|
assert(rc == 0);
|
|
|
|
has_aes_nonce = has_secret_id = false;
|
|
while (true) {
|
|
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
|
|
assert(rc >= 0);
|
|
|
|
if (rc > 0) {
|
|
break;
|
|
}
|
|
|
|
if (type == IMAGE_TLV_AES_NONCE) {
|
|
assert(len == 8);
|
|
|
|
rc = flash_area_read(fap, off, buf, len);
|
|
assert(rc == 0);
|
|
|
|
nonce[0] = __builtin_bswap32(*(uint32_t *)buf);
|
|
nonce[1] = __builtin_bswap32(*(uint32_t *)(buf + 4));
|
|
has_aes_nonce = true;
|
|
} else if (type == IMAGE_TLV_SECRET_ID) {
|
|
assert(len == 4);
|
|
|
|
rc = flash_area_read(fap, off, buf, len);
|
|
assert(rc == 0);
|
|
|
|
key = buf[0];
|
|
has_secret_id = true;
|
|
}
|
|
}
|
|
|
|
assert(has_aes_nonce && has_secret_id && key <= 7);
|
|
|
|
/* enable OTP clock and set in read mode */
|
|
da1469x_clock_amba_enable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
|
|
da1469x_otp_set_mode(OTPC_MODE_READ);
|
|
|
|
/* disable decrypt on the fly and program start and end addresses */
|
|
QSPIC->QSPIC_CTR_CTRL_REG = 0;
|
|
QSPIC->QSPIC_CTR_SADDR_REG = jump_offset;
|
|
QSPIC->QSPIC_CTR_EADDR_REG = QSPIC->QSPIC_CTR_SADDR_REG +
|
|
rsp->br_hdr->ih_img_size - 1;
|
|
|
|
/* securely DMA hardware key from secret storage to QSPI decrypt engine */
|
|
dma_regs->DMA_REQ_MUX_REG |= 0xf000;
|
|
dma_regs->DMA7_LEN_REG = 8;
|
|
dma_regs->DMA7_A_START_REG = MCU_OTPM_BASE + OTP_SEGMENT_QSPI_FW_KEYS +
|
|
(32 * key);
|
|
dma_regs->DMA7_B_START_REG = (uint32_t)&QSPIC->QSPIC_CTR_KEY_0_3_REG;
|
|
dma_regs->DMA7_CTRL_REG = DMA_DMA7_CTRL_REG_AINC_Msk |
|
|
DMA_DMA7_CTRL_REG_BINC_Msk |
|
|
(MCU_DMA_BUS_WIDTH_4B << DMA_DMA7_CTRL_REG_BW_Pos) |
|
|
DMA_DMA7_CTRL_REG_DMA_ON_Msk;
|
|
while (dma_regs->DMA7_IDX_REG != 8);
|
|
|
|
/* program NONCE */
|
|
QSPIC->QSPIC_CTR_NONCE_0_3_REG = nonce[0];
|
|
QSPIC->QSPIC_CTR_NONCE_4_7_REG = nonce[1];
|
|
|
|
/* turn back on decrypt on the fly */
|
|
QSPIC->QSPIC_CTR_CTRL_REG = 1;
|
|
|
|
/* set OTP to standby and turn off clock */
|
|
da1469x_otp_set_mode(OTPC_MODE_STBY);
|
|
da1469x_clock_amba_disable(CRG_TOP_CLK_AMBA_REG_OTP_ENABLE_Msk);
|
|
|
|
hal_system_start((void *)(flash_base + jump_offset));
|
|
}
|
|
#endif
|