Initial public version
This commit is contained in:
13
components/bootloader/src/main/Makefile
Normal file
13
components/bootloader/src/main/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default,
|
||||
# this will take the sources in the src/ directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T eagle.bootloader.ld -T $(SDK_PATH)/components/esp32/ld/eagle.fpga32.rom.addr.v7.ld
|
||||
COMPONENT_EXTRA_INCLUDES := $(SDK_PATH)/components/esp32/include
|
||||
|
||||
include $(SDK_PATH)/make/component.mk
|
||||
138
components/bootloader/src/main/bootloader_config.h
Normal file
138
components/bootloader/src/main/bootloader_config.h
Normal file
@@ -0,0 +1,138 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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.
|
||||
#ifndef __BOOT_CONFIG_H__
|
||||
#define __BOOT_CONFIG_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#define BOOT_VERSION "V0.1"
|
||||
#define SPI_SEC_SIZE 0x1000
|
||||
#define MEM_CACHE(offset) (uint8_t *)(0x3f400000 + (offset))
|
||||
#define CACHE_READ_32(offset) ((uint32_t *)(0x3f400000 + (offset)))
|
||||
#define PARTITION_ADD 0x4000
|
||||
#define PARTITION_MAGIC 0x50AA
|
||||
#define IROM_LOW 0x400D0000
|
||||
#define IROM_HIGH 0x40400000
|
||||
#define DROM_LOW 0x3F400000
|
||||
#define DROM_HIGH 0x3F800000
|
||||
|
||||
/*spi mode,saved in third byte in flash */
|
||||
enum {
|
||||
SPI_MODE_QIO,
|
||||
SPI_MODE_QOUT,
|
||||
SPI_MODE_DIO,
|
||||
SPI_MODE_DOUT,
|
||||
SPI_MODE_FAST_READ,
|
||||
SPI_MODE_SLOW_READ
|
||||
};
|
||||
/* spi speed*/
|
||||
enum {
|
||||
SPI_SPEED_40M,
|
||||
SPI_SPEED_26M,
|
||||
SPI_SPEED_20M,
|
||||
SPI_SPEED_80M = 0xF
|
||||
};
|
||||
/*suppport flash size in esp32 */
|
||||
enum {
|
||||
SPI_SIZE_1MB = 0,
|
||||
SPI_SIZE_2MB,
|
||||
SPI_SIZE_4MB,
|
||||
SPI_SIZE_8MB,
|
||||
SPI_SIZE_16MB,
|
||||
SPI_SIZE_MAX
|
||||
};
|
||||
|
||||
|
||||
struct flash_hdr {
|
||||
char magic;
|
||||
char blocks;
|
||||
char spi_mode; /* flag of flash read mode in unpackage and usage in future */
|
||||
char spi_speed: 4; /* low bit */
|
||||
char spi_size: 4;
|
||||
unsigned int entry_addr;
|
||||
uint8_t encrypt_flag; /* encrypt flag */
|
||||
uint8_t secury_boot_flag; /* secury boot flag */
|
||||
char extra_header[14]; /* ESP32 additional header, unused by second bootloader */
|
||||
};
|
||||
|
||||
/* each header of flash bin block */
|
||||
struct block_hdr {
|
||||
unsigned int load_addr;
|
||||
unsigned int data_len;
|
||||
};
|
||||
|
||||
/* OTA selection structure (two copies in the OTA data partition.)
|
||||
|
||||
Size of 32 bytes is friendly to flash encryption */
|
||||
typedef struct {
|
||||
uint32_t ota_seq;
|
||||
uint8_t seq_label[24];
|
||||
uint32_t crc; /* CRC32 of ota_seq field only */
|
||||
} ota_select;
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
} partition_pos_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t magic;
|
||||
uint8_t type; /* partition Type */
|
||||
uint8_t subtype; /* part_subtype */
|
||||
partition_pos_t pos;
|
||||
uint8_t label[16]; /* label for the partition */
|
||||
uint8_t reserved[4]; /* reserved */
|
||||
} partition_info_t;
|
||||
|
||||
#define PART_TYPE_APP 0x00
|
||||
#define PART_SUBTYPE_FACTORY 0x00
|
||||
#define PART_SUBTYPE_OTA_FLAG 0x10
|
||||
#define PART_SUBTYPE_OTA_MASK 0x0f
|
||||
#define PART_SUBTYPE_TEST 0x20
|
||||
|
||||
#define PART_TYPE_DATA 0x01
|
||||
#define PART_SUBTYPE_DATA_OTA 0x00
|
||||
#define PART_SUBTYPE_DATA_RF 0x01
|
||||
#define PART_SUBTYPE_DATA_WIFI 0x02
|
||||
|
||||
#define PART_TYPE_END 0xff
|
||||
#define PART_SUBTYPE_END 0xff
|
||||
|
||||
#define SPI_ERROR_LOG "spi flash error"
|
||||
|
||||
typedef struct {
|
||||
partition_pos_t ota_info;
|
||||
partition_pos_t factory;
|
||||
partition_pos_t test;
|
||||
partition_pos_t ota[16];
|
||||
uint32_t app_count;
|
||||
uint32_t selected_subtype;
|
||||
} bootloader_state_t;
|
||||
|
||||
void boot_cache_redirect( uint32_t pos, size_t size );
|
||||
uint32_t get_bin_len(uint32_t pos);
|
||||
|
||||
bool flash_encrypt(bootloader_state_t *bs);
|
||||
bool secure_boot(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BOOT_CONFIG_H__ */
|
||||
89
components/bootloader/src/main/bootloader_log.h
Normal file
89
components/bootloader/src/main/bootloader_log.h
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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.
|
||||
#ifndef __BOOT_LOG_H__
|
||||
#define __BOOT_LOG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOT_LOG_LEVEL_ERROR (1)
|
||||
#define BOOT_LOG_LEVEL_WARN (2)
|
||||
#define BOOT_LOG_LEVEL_INFO (3)
|
||||
#define BOOT_LOG_LEVEL_NOTICE (4)
|
||||
#define BOOT_LOG_LEVEL_DEBUG (5)
|
||||
|
||||
#define Black 0;30
|
||||
#define Red 0;31
|
||||
#define Green 0;32
|
||||
#define Brown 0;33
|
||||
#define Blue 0;34
|
||||
#define Purple 0;35
|
||||
#define Cyan 0;36
|
||||
|
||||
// TODO: move BOOT_LOG_LEVEL into menuconfig
|
||||
//#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_ERROR
|
||||
#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_NOTICE
|
||||
|
||||
//printf("\033[0;36m[NOTICE][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);
|
||||
#define log_notice(format, ...) \
|
||||
do{\
|
||||
if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE){\
|
||||
ets_printf("\033[0;36m" format "\r\n", ##__VA_ARGS__);\
|
||||
ets_printf("\033[0m"); \
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
#define log_info(format, ...) \
|
||||
do{\
|
||||
if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_INFO){\
|
||||
ets_printf("\033[1;36m" format "\r\n", ##__VA_ARGS__);\
|
||||
ets_printf("\033[0m"); \
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
//printf("\033[0;31m[ERROR][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);
|
||||
#define log_error(format, ...) \
|
||||
do{\
|
||||
if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_ERROR){\
|
||||
ets_printf("\033[0;31m[ERROR][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
|
||||
ets_printf("\033[0m"); \
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
//printf("\033[1;33m[WARN][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);
|
||||
#define log_warn(format, ...) \
|
||||
do{\
|
||||
if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_WARN){\
|
||||
ets_printf("\033[1;33m[WARN][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);\
|
||||
ets_printf("\033[0m"); \
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
//printf("\033[1;32m[DEBUG][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);
|
||||
#define log_debug(format, ...) \
|
||||
do{\
|
||||
if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_DEBUG){\
|
||||
ets_printf("\033[1;32m[DEBUG][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
ets_printf("\033[0m"); \
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BOOT_LOGGING_H__ */
|
||||
597
components/bootloader/src/main/bootloader_start.c
Normal file
597
components/bootloader/src/main/bootloader_start.c
Normal file
@@ -0,0 +1,597 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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 <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
|
||||
#include "rom/cache.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/crc.h"
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/timers_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_log.h"
|
||||
#include "bootloader_config.h"
|
||||
|
||||
extern int _bss_start;
|
||||
extern int _bss_end;
|
||||
/*
|
||||
We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
|
||||
flash cache is down and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
|
||||
*/
|
||||
|
||||
// TODO: make a nice header file for ROM functions instead of adding externs all over the place
|
||||
extern void Cache_Flush(int);
|
||||
|
||||
void bootloader_main();
|
||||
void unpack_load_app(const partition_pos_t *app_node);
|
||||
void print_flash_info(struct flash_hdr* pfhdr);
|
||||
void IRAM_ATTR set_cache_and_start_app(uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
uint32_t drom_size,
|
||||
uint32_t irom_addr,
|
||||
uint32_t irom_load_addr,
|
||||
uint32_t irom_size,
|
||||
uint32_t entry_addr);
|
||||
|
||||
|
||||
void IRAM_ATTR call_start_cpu0()
|
||||
{
|
||||
//Make page 0 access raise an exception
|
||||
//Also some other unused pages so we can catch weirdness
|
||||
//ToDo: this but nicer.
|
||||
asm volatile (\
|
||||
"movi a4,0x00000000\n" \
|
||||
"movi a5,0xf\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x80000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xa0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xc0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0xe0000000\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x20000000\n" \
|
||||
"movi a5,0x0\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"movi a4,0x40000000\n" \
|
||||
"movi a5,0x2\n" \
|
||||
"wdtlb a5,a4\n" \
|
||||
"witlb a5,a4\n" \
|
||||
"isync\n" \
|
||||
:::"a4","a5");
|
||||
|
||||
//Clear bss
|
||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
||||
|
||||
/* completely reset MMU for both CPUs
|
||||
(in case serial bootloader was running) */
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Read_Disable(1);
|
||||
Cache_Flush(0);
|
||||
Cache_Flush(1);
|
||||
mmu_init(0);
|
||||
mmu_init(1);
|
||||
/* (above steps probably unnecessary for most serial bootloader
|
||||
usage, all that's absolutely needed is that we unmask DROM0
|
||||
cache on the following two lines - normal ROM boot exits with
|
||||
DROM0 cache unmasked, but serial bootloader exits with it
|
||||
masked. However can't hurt to be thorough and reset
|
||||
everything.)
|
||||
*/
|
||||
REG_CLR_BIT(PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
|
||||
REG_CLR_BIT(APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
|
||||
|
||||
bootloader_main();
|
||||
}
|
||||
|
||||
/**
|
||||
* @function : get_bin_len
|
||||
* @description: get bin's length
|
||||
*
|
||||
* @inputs: pos bin locate address in flash
|
||||
* @return: uint32 length of bin,if bin MAGIC error return 0
|
||||
*/
|
||||
|
||||
uint32_t get_bin_len(uint32_t pos)
|
||||
{
|
||||
uint32_t len = 8 + 16;
|
||||
uint8_t i;
|
||||
log_debug("pos %d %x\n",pos,*(uint8_t *)pos);
|
||||
if(0xE9 != *(uint8_t *)pos) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < *(uint8_t *)(pos + 1); i++) {
|
||||
len += *(uint32_t *)(pos + len + 4) + 8;
|
||||
}
|
||||
if (len % 16 != 0) {
|
||||
len = (len / 16 + 1) * 16;
|
||||
} else {
|
||||
len += 16;
|
||||
}
|
||||
log_debug("bin length = %d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function : boot_cache_redirect
|
||||
* @description: Configure several pages in flash map so that `size` bytes
|
||||
* starting at `pos` are mapped to 0x3f400000.
|
||||
* This sets up mapping only for PRO CPU.
|
||||
*
|
||||
* @inputs: pos address in flash
|
||||
* size size of the area to map, in bytes
|
||||
*/
|
||||
void boot_cache_redirect( uint32_t pos, size_t size )
|
||||
{
|
||||
uint32_t pos_aligned = pos & 0xffff0000;
|
||||
uint32_t count = (size + 0xffff) / 0x10000;
|
||||
Cache_Read_Disable( 0 );
|
||||
Cache_Flush( 0 );
|
||||
log_debug( "mmu set paddr=%08x count=%d", pos_aligned, count );
|
||||
cache_flash_mmu_set( 0, 0, 0x3f400000, pos_aligned, 64, count );
|
||||
Cache_Read_Enable( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @function : load_partition_table
|
||||
* @description: Parse partition table, get useful data such as location of
|
||||
* OTA info sector, factory app sector, and test app sector.
|
||||
*
|
||||
* @inputs: bs bootloader state structure used to save the data
|
||||
* addr address of partition table in flash
|
||||
* @return: return true, if the partition table is loaded (and MD5 checksum is valid)
|
||||
*
|
||||
*/
|
||||
bool load_partition_table(bootloader_state_t* bs, uint32_t addr)
|
||||
{
|
||||
partition_info_t partition;
|
||||
uint32_t end = addr + 0x1000;
|
||||
int index = 0;
|
||||
char *partition_usage;
|
||||
|
||||
log_info("Partition Table:");
|
||||
log_info("## Label Usage Type ST Offset Length");
|
||||
|
||||
while (addr < end) {
|
||||
log_debug("load partition table entry from %x(%08x)", addr, MEM_CACHE(addr));
|
||||
memcpy(&partition, MEM_CACHE(addr), sizeof(partition));
|
||||
log_debug("type=%x subtype=%x", partition.type, partition.subtype);
|
||||
partition_usage = "unknown";
|
||||
|
||||
if (partition.magic == PARTITION_MAGIC) { /* valid partition definition */
|
||||
switch(partition.type) {
|
||||
case PART_TYPE_APP: /* app partition */
|
||||
switch(partition.subtype) {
|
||||
case PART_SUBTYPE_FACTORY: /* factory binary */
|
||||
bs->factory = partition.pos;
|
||||
partition_usage = "factory app";
|
||||
break;
|
||||
case PART_SUBTYPE_TEST: /* test binary */
|
||||
bs->test = partition.pos;
|
||||
partition_usage = "test app";
|
||||
break;
|
||||
default:
|
||||
/* OTA binary */
|
||||
if ((partition.subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
|
||||
bs->ota[partition.subtype & PART_SUBTYPE_OTA_MASK] = partition.pos;
|
||||
++bs->app_count;
|
||||
partition_usage = "OTA app";
|
||||
}
|
||||
else {
|
||||
partition_usage = "Unknown app";
|
||||
}
|
||||
break;
|
||||
}
|
||||
break; /* PART_TYPE_APP */
|
||||
case PART_TYPE_DATA: /* data partition */
|
||||
switch(partition.subtype) {
|
||||
case PART_SUBTYPE_DATA_OTA: /* ota data */
|
||||
bs->ota_info = partition.pos;
|
||||
partition_usage = "OTA data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_RF:
|
||||
partition_usage = "RF data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_WIFI:
|
||||
partition_usage = "WiFi data";
|
||||
break;
|
||||
default:
|
||||
partition_usage = "Unknown data";
|
||||
break;
|
||||
}
|
||||
break; /* PARTITION_USAGE_DATA */
|
||||
default: /* other partition type */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* invalid partition magic number */
|
||||
else {
|
||||
break; /* todo: validate md5 */
|
||||
}
|
||||
|
||||
/* print partition type info */
|
||||
log_info("%2d %-16s %-16s %02x %02x %08x %08x", index, partition.label, partition_usage,
|
||||
partition.type, partition.subtype,
|
||||
partition.pos.offset, partition.pos.size);
|
||||
index++;
|
||||
addr += sizeof(partition);
|
||||
}
|
||||
|
||||
log_info("End of partition table");
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t ota_select_crc(const ota_select *s)
|
||||
{
|
||||
return crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
|
||||
}
|
||||
|
||||
static bool ota_select_valid(const ota_select *s)
|
||||
{
|
||||
return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function : bootloader_main
|
||||
* @description: entry function of 2nd bootloader
|
||||
*
|
||||
* @inputs: void
|
||||
*/
|
||||
|
||||
void bootloader_main()
|
||||
{
|
||||
//Run start routine.
|
||||
/*ESP32 2ND bootload start here*/
|
||||
|
||||
|
||||
log_info( "\n" );
|
||||
log_info( "**************************************" );
|
||||
log_info( "* hello espressif ESP32! *" );
|
||||
log_info( "* 2nd boot is running! *" );
|
||||
log_info( "* version (%s) *", BOOT_VERSION);
|
||||
log_info( "**************************************");
|
||||
|
||||
struct flash_hdr fhdr;
|
||||
bootloader_state_t bs;
|
||||
SpiFlashOpResult spiRet1,spiRet2;
|
||||
ota_select sa,sb;
|
||||
memset(&bs, 0, sizeof(bs));
|
||||
|
||||
log_notice( "compile time %s\n", __TIME__ );
|
||||
/* close watch dog here */
|
||||
REG_CLR_BIT( RTC_WDTCONFIG0, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
|
||||
REG_CLR_BIT( WDTCONFIG0, TIMERS_WDT_FLASHBOOT_MOD_EN );
|
||||
SPIUnlock();
|
||||
/*register first sector in drom0 page 0 */
|
||||
boot_cache_redirect( 0, 0x5000 );
|
||||
|
||||
memcpy((unsigned int *) &fhdr, MEM_CACHE(0x1000), sizeof(struct flash_hdr) );
|
||||
|
||||
print_flash_info(&fhdr);
|
||||
|
||||
if (!load_partition_table(&bs, PARTITION_ADD)) {
|
||||
log_error("load partition table error!");
|
||||
return;
|
||||
}
|
||||
|
||||
partition_pos_t load_part_pos;
|
||||
|
||||
if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
|
||||
//log_error("OTA info sector handling is not implemented");
|
||||
boot_cache_redirect(bs.ota_info.offset, bs.ota_info.size );
|
||||
memcpy(&sa,MEM_CACHE(bs.ota_info.offset & 0x0000ffff),sizeof(sa));
|
||||
memcpy(&sb,MEM_CACHE((bs.ota_info.offset + 0x1000)&0x0000ffff) ,sizeof(sb));
|
||||
if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
|
||||
// init status flash
|
||||
load_part_pos = bs.ota[0];
|
||||
sa.ota_seq = 0x01;
|
||||
sa.crc = ota_select_crc(&sa);
|
||||
sb.ota_seq = 0x00;
|
||||
sb.crc = ota_select_crc(&sb);
|
||||
|
||||
Cache_Read_Disable(0);
|
||||
spiRet1 = SPIEraseSector(bs.ota_info.offset/0x1000);
|
||||
spiRet2 = SPIEraseSector(bs.ota_info.offset/0x1000+1);
|
||||
if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) {
|
||||
log_error(SPI_ERROR_LOG);
|
||||
return;
|
||||
}
|
||||
spiRet1 = SPIWrite(bs.ota_info.offset,(uint32_t *)&sa,sizeof(ota_select));
|
||||
spiRet2 = SPIWrite(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(ota_select));
|
||||
if (spiRet1 != SPI_FLASH_RESULT_OK || spiRet2 != SPI_FLASH_RESULT_OK ) {
|
||||
log_error(SPI_ERROR_LOG);
|
||||
return;
|
||||
}
|
||||
Cache_Read_Enable(0);
|
||||
//TODO:write data in ota info
|
||||
} else {
|
||||
if(ota_select_valid(&sa) && ota_select_valid(&sb)) {
|
||||
load_part_pos = bs.ota[(((sa.ota_seq > sb.ota_seq)?sa.ota_seq:sb.ota_seq) - 1)%bs.app_count];
|
||||
}else if(ota_select_valid(&sa)) {
|
||||
load_part_pos = bs.ota[(sa.ota_seq - 1) % bs.app_count];
|
||||
}else if(ota_select_valid(&sb)) {
|
||||
load_part_pos = bs.ota[(sb.ota_seq - 1) % bs.app_count];
|
||||
}else {
|
||||
log_error("ota data partition info error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (bs.factory.offset != 0) { // otherwise, look for factory app partition
|
||||
load_part_pos = bs.factory;
|
||||
} else if (bs.test.offset != 0) { // otherwise, look for test app parition
|
||||
load_part_pos = bs.test;
|
||||
} else { // nothing to load, bail out
|
||||
log_error("nothing to load");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("Loading app partition at offset %08x", load_part_pos);
|
||||
if(fhdr.secury_boot_flag == 0x01) {
|
||||
/* protect the 2nd_boot */
|
||||
if(false == secure_boot()){
|
||||
log_error("secure boot failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(fhdr.encrypt_flag == 0x01) {
|
||||
/* encrypt flash */
|
||||
if (false == flash_encrypt(&bs)) {
|
||||
log_error("flash encrypt failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// copy sections to RAM, set up caches, and start application
|
||||
unpack_load_app(&load_part_pos);
|
||||
}
|
||||
|
||||
|
||||
void unpack_load_app(const partition_pos_t* partition)
|
||||
{
|
||||
boot_cache_redirect(partition->offset, partition->size);
|
||||
|
||||
uint32_t pos = 0;
|
||||
struct flash_hdr image_header;
|
||||
memcpy(&image_header, MEM_CACHE(pos), sizeof(image_header));
|
||||
pos += sizeof(image_header);
|
||||
|
||||
uint32_t drom_addr = 0;
|
||||
uint32_t drom_load_addr = 0;
|
||||
uint32_t drom_size = 0;
|
||||
uint32_t irom_addr = 0;
|
||||
uint32_t irom_load_addr = 0;
|
||||
uint32_t irom_size = 0;
|
||||
|
||||
log_debug("bin_header: %u %u %u %u %08x\n", image_header.magic,
|
||||
image_header.blocks,
|
||||
image_header.spi_mode,
|
||||
image_header.spi_size,
|
||||
(unsigned)image_header.entry_addr);
|
||||
|
||||
for (uint32_t section_index = 0;
|
||||
section_index < image_header.blocks;
|
||||
++section_index) {
|
||||
struct block_hdr section_header = {0};
|
||||
memcpy(§ion_header, MEM_CACHE(pos), sizeof(section_header));
|
||||
pos += sizeof(section_header);
|
||||
|
||||
const uint32_t address = section_header.load_addr;
|
||||
bool load = true;
|
||||
bool map = false;
|
||||
if (address == 0x00000000) { // padding, ignore block
|
||||
load = false;
|
||||
}
|
||||
if (address == 0x00000004) {
|
||||
load = false; // md5 checksum block
|
||||
// TODO: actually check md5
|
||||
}
|
||||
|
||||
if (address >= DROM_LOW && address < DROM_HIGH) {
|
||||
log_debug("found drom section, map from %08x to %08x\n", pos,
|
||||
section_header.load_addr);
|
||||
drom_addr = partition->offset + pos - sizeof(section_header);
|
||||
drom_load_addr = section_header.load_addr;
|
||||
drom_size = section_header.data_len + sizeof(section_header);
|
||||
load = false;
|
||||
map = true;
|
||||
}
|
||||
|
||||
if (address >= IROM_LOW && address < IROM_HIGH) {
|
||||
log_debug("found irom section, map from %08x to %08x\n", pos,
|
||||
section_header.load_addr);
|
||||
irom_addr = partition->offset + pos - sizeof(section_header);
|
||||
irom_load_addr = section_header.load_addr;
|
||||
irom_size = section_header.data_len + sizeof(section_header);
|
||||
load = false;
|
||||
map = true;
|
||||
}
|
||||
|
||||
log_notice("section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos, section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":"");
|
||||
|
||||
if (!load) {
|
||||
pos += section_header.data_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy((void*) section_header.load_addr, MEM_CACHE(pos), section_header.data_len);
|
||||
pos += section_header.data_len;
|
||||
}
|
||||
|
||||
set_cache_and_start_app(drom_addr,
|
||||
drom_load_addr,
|
||||
drom_size,
|
||||
irom_addr,
|
||||
irom_load_addr,
|
||||
irom_size,
|
||||
image_header.entry_addr);
|
||||
}
|
||||
|
||||
void IRAM_ATTR set_cache_and_start_app(
|
||||
uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
uint32_t drom_size,
|
||||
uint32_t irom_addr,
|
||||
uint32_t irom_load_addr,
|
||||
uint32_t irom_size,
|
||||
uint32_t entry_addr)
|
||||
{
|
||||
log_debug("configure drom and irom and start\n");
|
||||
Cache_Read_Disable( 0 );
|
||||
Cache_Read_Disable( 1 );
|
||||
Cache_Flush( 0 );
|
||||
Cache_Flush( 1 );
|
||||
uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
||||
log_debug( "d mmu set paddr=%08x vaddr=%08x size=%d n=%d \n", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
|
||||
int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||
log_debug( "rc=%d", rc );
|
||||
rc = cache_flash_mmu_set( 1, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||
log_debug( "rc=%d", rc );
|
||||
uint32_t irom_page_count = (irom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
||||
log_debug( "i mmu set paddr=%08x vaddr=%08x size=%d n=%d\n", irom_addr & 0xffff0000, irom_load_addr & 0xffff0000, irom_size, irom_page_count );
|
||||
rc = cache_flash_mmu_set( 0, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
|
||||
log_debug( "rc=%d", rc );
|
||||
rc = cache_flash_mmu_set( 1, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
|
||||
log_debug( "rc=%d", rc );
|
||||
REG_CLR_BIT( PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 );
|
||||
REG_CLR_BIT( APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 );
|
||||
Cache_Read_Enable( 0 );
|
||||
Cache_Read_Enable( 1 );
|
||||
|
||||
log_notice("start: 0x%08x\n", entry_addr);
|
||||
typedef void (*entry_t)(void);
|
||||
entry_t entry = ((entry_t) entry_addr);
|
||||
|
||||
// TODO: we have used quite a bit of stack at this point.
|
||||
// use "movsp" instruction to reset stack back to where ROM stack starts.
|
||||
(*entry)();
|
||||
}
|
||||
|
||||
|
||||
void print_flash_info(struct flash_hdr* pfhdr)
|
||||
{
|
||||
#if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
|
||||
|
||||
struct flash_hdr fhdr = *pfhdr;
|
||||
|
||||
log_debug( "[D]: magic %02x\n", fhdr.magic );
|
||||
log_debug( "[D]: blocks %02x\n", fhdr.blocks );
|
||||
log_debug( "[D]: spi_mode %02x\n", fhdr.spi_mode );
|
||||
log_debug( "[D]: spi_speed %02x\n", fhdr.spi_speed );
|
||||
log_debug( "[D]: spi_size %02x\n", fhdr.spi_size );
|
||||
|
||||
const char* str;
|
||||
switch ( fhdr.spi_speed ) {
|
||||
case SPI_SPEED_40M:
|
||||
str = "40MHz";
|
||||
break;
|
||||
|
||||
case SPI_SPEED_26M:
|
||||
str = "26.7MHz";
|
||||
break;
|
||||
|
||||
case SPI_SPEED_20M:
|
||||
str = "20MHz";
|
||||
break;
|
||||
|
||||
case SPI_SPEED_80M:
|
||||
str = "80MHz";
|
||||
break;
|
||||
|
||||
default:
|
||||
str = "20MHz";
|
||||
break;
|
||||
}
|
||||
log_notice( " SPI Speed : %s", str );
|
||||
|
||||
|
||||
|
||||
switch ( fhdr.spi_mode ) {
|
||||
case SPI_MODE_QIO:
|
||||
str = "QIO";
|
||||
break;
|
||||
|
||||
case SPI_MODE_QOUT:
|
||||
str = "QOUT";
|
||||
break;
|
||||
|
||||
case SPI_MODE_DIO:
|
||||
str = "DIO";
|
||||
break;
|
||||
|
||||
case SPI_MODE_DOUT:
|
||||
str = "DOUT";
|
||||
break;
|
||||
|
||||
case SPI_MODE_FAST_READ:
|
||||
str = "FAST READ";
|
||||
break;
|
||||
|
||||
case SPI_MODE_SLOW_READ:
|
||||
str = "SLOW READ";
|
||||
break;
|
||||
default:
|
||||
str = "DIO";
|
||||
break;
|
||||
}
|
||||
log_notice( " SPI Mode : %s", str );
|
||||
|
||||
|
||||
|
||||
switch ( fhdr.spi_size ) {
|
||||
case SPI_SIZE_1MB:
|
||||
str = "1MB";
|
||||
break;
|
||||
|
||||
case SPI_SIZE_2MB:
|
||||
str = "2MB";
|
||||
break;
|
||||
|
||||
case SPI_SIZE_4MB:
|
||||
str = "4MB";
|
||||
break;
|
||||
|
||||
case SPI_SIZE_8MB:
|
||||
str = "8MB";
|
||||
break;
|
||||
|
||||
case SPI_SIZE_16MB:
|
||||
str = "16MB";
|
||||
break;
|
||||
|
||||
default:
|
||||
str = "1MB";
|
||||
break;
|
||||
}
|
||||
log_notice( " SPI Flash Size : %s", str );
|
||||
#endif
|
||||
}
|
||||
148
components/bootloader/src/main/eagle.bootloader.ld
Normal file
148
components/bootloader/src/main/eagle.bootloader.ld
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Linker file used to link the bootloader.
|
||||
|
||||
*WARNING* For now this linker dumps everything into IRAM/DRAM. ToDo: move
|
||||
some/most stuff to DROM/IROM.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES */
|
||||
/* The load addresses are defined later using the AT statements. */
|
||||
MEMORY
|
||||
{
|
||||
/* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
|
||||
of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
|
||||
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||
dport0_seg (RW) : org = 0x3FF00000, len = 0x10 /* IO */
|
||||
iram_seg (RWX) : org = 0x40098000, len = 0x1000
|
||||
iram_pool_1_seg (RWX) : org = 0x40078000, len = 0x8000 /* IRAM POOL1, used for APP CPU cache. We can abuse it in bootloader because APP CPU is still held in reset, until we enable APP CPU cache */
|
||||
dram_seg (RW) : org = 0x3FFC0000, len = 0x20000 /* Shared RAM, minus rom bss/data/stack.*/
|
||||
}
|
||||
|
||||
/* Default entry point: */
|
||||
ENTRY(call_start_cpu0);
|
||||
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.iram1.text :
|
||||
{
|
||||
_init_start = ABSOLUTE(.);
|
||||
*(.UserEnter.literal);
|
||||
*(.UserEnter.text);
|
||||
. = ALIGN (16);
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
_init_end = ABSOLUTE(.);
|
||||
|
||||
/* Code marked as runnning out of IRAM */
|
||||
_iram_text_start = ABSOLUTE(.);
|
||||
*(.iram1 .iram1.*)
|
||||
_iram_text_end = ABSOLUTE(.);
|
||||
} > iram_seg
|
||||
|
||||
|
||||
/* Shared RAM */
|
||||
.dram0.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN (8);
|
||||
_bss_start = ABSOLUTE(.);
|
||||
*(.dynsbss)
|
||||
*(.sbss)
|
||||
*(.sbss.*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
*(.sbss2)
|
||||
*(.sbss2.*)
|
||||
*(.gnu.linkonce.sb2.*)
|
||||
*(.dynbss)
|
||||
KEEP(*(.bss))
|
||||
*(.bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
_bss_end = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
|
||||
.dram0.data :
|
||||
{
|
||||
_data_start = ABSOLUTE(.);
|
||||
KEEP(*(.data))
|
||||
KEEP(*(.data.*))
|
||||
KEEP(*(.gnu.linkonce.d.*))
|
||||
KEEP(*(.data1))
|
||||
KEEP(*(.sdata))
|
||||
KEEP(*(.sdata.*))
|
||||
KEEP(*(.gnu.linkonce.s.*))
|
||||
KEEP(*(.sdata2))
|
||||
KEEP(*(.sdata2.*))
|
||||
KEEP(*(.gnu.linkonce.s2.*))
|
||||
KEEP(*(.jcr))
|
||||
_data_end = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
|
||||
|
||||
|
||||
.dram0.rodata :
|
||||
{
|
||||
_rodata_start = ABSOLUTE(.);
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
*(.gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
__XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
|
||||
*(.xt_except_table)
|
||||
*(.gcc_except_table)
|
||||
*(.gnu.linkonce.e.*)
|
||||
*(.gnu.version_r)
|
||||
*(.eh_frame)
|
||||
. = (. + 3) & ~ 3;
|
||||
/* C++ constructor and destructor tables, properly ordered: */
|
||||
__init_array_start = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
__init_array_end = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
/* C++ exception handlers table: */
|
||||
__XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
|
||||
*(.xt_except_desc)
|
||||
*(.gnu.linkonce.h.*)
|
||||
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
|
||||
*(.xt_except_desc_end)
|
||||
*(.dynamic)
|
||||
*(.gnu.version_d)
|
||||
_rodata_end = ABSOLUTE(.);
|
||||
/* Literals are also RO data. */
|
||||
_lit4_start = ABSOLUTE(.);
|
||||
*(*.lit4)
|
||||
*(.lit4.*)
|
||||
*(.gnu.linkonce.lit4.*)
|
||||
_lit4_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_heap_start = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
.iram_pool_1.text :
|
||||
{
|
||||
_stext = .;
|
||||
_text_start = ABSOLUTE(.);
|
||||
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||
*(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} >iram_pool_1_seg
|
||||
|
||||
}
|
||||
190
components/bootloader/src/main/flash_encrypt.c
Normal file
190
components/bootloader/src/main/flash_encrypt.c
Normal file
@@ -0,0 +1,190 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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 <string.h>
|
||||
|
||||
#include "esp_types.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#include "rom/cache.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/spi_flash.h"
|
||||
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_log.h"
|
||||
#include "bootloader_config.h"
|
||||
|
||||
/**
|
||||
* @function : bitcount
|
||||
* @description: caculate bit 1 in flash_crypt_cnt
|
||||
* if it's even number ,need encrypt flash data,and burn efuse
|
||||
*
|
||||
* @inputs: n flash_crypt_cnt
|
||||
* @return: number of 1 in flash_crypt_cnt
|
||||
*
|
||||
*/
|
||||
int bitcount(int n){
|
||||
int count = 0;
|
||||
while (n > 0) {
|
||||
count += n & 1;
|
||||
n >>= 1;
|
||||
}
|
||||
return count;
|
||||
|
||||
}
|
||||
/**
|
||||
* @function : flash_encrypt_write
|
||||
* @description: write encrypted data in flash
|
||||
*
|
||||
* @inputs: pos address in flash
|
||||
* len size of data need encrypt
|
||||
* @return: return true, if the write flash success
|
||||
*
|
||||
*/
|
||||
bool flash_encrypt_write(uint32_t pos, uint32_t len)
|
||||
{
|
||||
SpiFlashOpResult spiRet;
|
||||
uint32_t buf[1024];
|
||||
int i = 0;
|
||||
Cache_Read_Disable(0);
|
||||
for (i = 0;i<((len-1)/0x1000 + 1);i++) {
|
||||
spiRet = SPIRead(pos, buf, SPI_SEC_SIZE);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
Cache_Read_Enable(0);
|
||||
log_error(SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
spiRet = SPIEraseSector(pos/SPI_SEC_SIZE);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
Cache_Read_Enable(0);
|
||||
log_error(SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
spiRet = SPI_Encrypt_Write(pos, buf, SPI_SEC_SIZE);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
Cache_Read_Enable(0);
|
||||
log_error(SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
pos += SPI_SEC_SIZE;
|
||||
}
|
||||
Cache_Read_Enable(0);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @function : flash_encrypt
|
||||
* @description: encrypt 2nd boot ,partition table ,factory bin <20><>test bin (if use)<29><>ota bin
|
||||
* <20><>OTA info sector.
|
||||
*
|
||||
* @inputs: bs bootloader state structure used to save the data
|
||||
*
|
||||
* @return: return true, if the encrypt flash success
|
||||
*
|
||||
*/
|
||||
bool flash_encrypt(bootloader_state_t *bs)
|
||||
{
|
||||
uint32_t bin_len = 0;
|
||||
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0, EFUSE_FLASH_CRYPT_CNT);
|
||||
uint8_t count = bitcount(flash_crypt_cnt);
|
||||
int i = 0;
|
||||
log_debug("flash crypt cnt %x, count %d\n", flash_crypt_cnt, count);
|
||||
|
||||
if ((count % 2) == 0) {
|
||||
boot_cache_redirect( 0, 64*1024);
|
||||
/* encrypt iv and abstruct */
|
||||
if (false == flash_encrypt_write(0,SPI_SEC_SIZE)) {
|
||||
log_error("encrypt iv and abstruct error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* encrypt write boot bin*/
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
|
||||
if(bin_len != 0) {
|
||||
if (false == flash_encrypt_write(0x1000,bin_len)) {
|
||||
log_error("encrypt 2nd boot error");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
log_error("2nd boot len error");
|
||||
return false;
|
||||
}
|
||||
/* encrypt partition table */
|
||||
if (false == flash_encrypt_write(PARTITION_ADD,SPI_SEC_SIZE)) {
|
||||
log_error("encrypt partition table error");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* encrypt write factory bin */
|
||||
if(bs->factory.offset != 0x00) {
|
||||
log_debug("have factory bin\n");
|
||||
boot_cache_redirect(bs->factory.offset,bs->factory.size);
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->factory.offset&0xffff));
|
||||
if(bin_len != 0) {
|
||||
if (false == flash_encrypt_write(bs->factory.offset,bin_len)) {
|
||||
log_error("encrypt factory bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* encrypt write test bin */
|
||||
if(bs->test.offset != 0x00) {
|
||||
ets_printf("have test bin\n");
|
||||
boot_cache_redirect(bs->test.offset,bs->test.size);
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->test.offset&0xffff));
|
||||
if(bin_len != 0) {
|
||||
if (false == flash_encrypt_write(bs->test.offset,bin_len)) {
|
||||
log_error("encrypt test bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* encrypt write ota bin */
|
||||
for (i = 0;i<16;i++) {
|
||||
if(bs->ota[i].offset != 0x00) {
|
||||
log_debug("have ota[%d] bin\n",i);
|
||||
boot_cache_redirect(bs->ota[i].offset,bs->ota[i].size);
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->ota[i].offset&0xffff));
|
||||
if(bin_len != 0) {
|
||||
if (false == flash_encrypt_write(bs->ota[i].offset,bin_len)) {
|
||||
log_error("encrypt ota bin error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* encrypt write ota info bin */
|
||||
if (false == flash_encrypt_write(bs->ota_info.offset,2*SPI_SEC_SIZE)) {
|
||||
log_error("encrypt ota binfo error");
|
||||
return false;
|
||||
}
|
||||
REG_SET_FIELD(EFUSE_BLK0_WDATA0, EFUSE_FLASH_CRYPT_CNT, 0x04);
|
||||
REG_WRITE(EFUSE_CONF, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
|
||||
REG_WRITE(EFUSE_CMD, 0x02); /* efuse_pgm_cmd */
|
||||
while (REG_READ(EFUSE_CMD)); /* wait for efuse_pagm_cmd=0 */
|
||||
log_warn("burn flash_crypt_cnt\n");
|
||||
REG_WRITE(EFUSE_CONF, 0x5AA5); /* efuse_read_op_ena, release force */
|
||||
REG_WRITE(EFUSE_CMD, 0x01); /* efuse_read_cmd */
|
||||
while (REG_READ(EFUSE_CMD)); /* wait for efuse_read_cmd=0 */
|
||||
return true;
|
||||
} else {
|
||||
log_info("flash already encrypted.\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
125
components/bootloader/src/main/secure_boot.c
Normal file
125
components/bootloader/src/main/secure_boot.c
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed 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 <string.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_types.h"
|
||||
|
||||
#include "rom/cache.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/secure_boot.h"
|
||||
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "bootloader_log.h"
|
||||
#include "bootloader_config.h"
|
||||
|
||||
/**
|
||||
* @function : secure_boot_generate
|
||||
* @description: generate boot abstruct & iv
|
||||
*
|
||||
* @inputs: bool
|
||||
*/
|
||||
bool secure_boot_generate(uint32_t bin_len){
|
||||
SpiFlashOpResult spiRet;
|
||||
uint16_t i;
|
||||
uint32_t buf[32];
|
||||
if (bin_len % 128 != 0) {
|
||||
bin_len = (bin_len / 128 + 1) * 128;
|
||||
}
|
||||
ets_secure_boot_start();
|
||||
ets_secure_boot_rd_iv(buf);
|
||||
ets_secure_boot_hash(NULL);
|
||||
Cache_Read_Disable(0);
|
||||
/* iv stored in sec 0 */
|
||||
spiRet = SPIEraseSector(0);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
log_error(SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
/* write iv to flash, 0x0000, 128 bytes (1024 bits) */
|
||||
spiRet = SPIWrite(0, buf, 128);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
log_error(SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
log_debug("write iv to flash.\n");
|
||||
Cache_Read_Enable(0);
|
||||
/* read 4K code image from flash, for test */
|
||||
for (i = 0; i < bin_len; i+=128) {
|
||||
ets_secure_boot_hash((uint32_t *)(0x3f400000 + 0x1000 + i));
|
||||
}
|
||||
|
||||
ets_secure_boot_obtain();
|
||||
ets_secure_boot_rd_abstract(buf);
|
||||
ets_secure_boot_finish();
|
||||
Cache_Read_Disable(0);
|
||||
/* write abstract to flash, 0x0080, 64 bytes (512 bits) */
|
||||
spiRet = SPIWrite(0x80, buf, 64);
|
||||
if (spiRet != SPI_FLASH_RESULT_OK) {
|
||||
log_error(SPI_ERROR_LOG);
|
||||
return false;
|
||||
}
|
||||
log_debug("write abstract to flash.\n");
|
||||
Cache_Read_Enable(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @function : secure_boot
|
||||
* @description: protect boot code inflash
|
||||
*
|
||||
* @inputs: bool
|
||||
*/
|
||||
bool secure_boot(void){
|
||||
uint32_t bin_len = 0;
|
||||
if (REG_READ(EFUSE_BLK0_RDATA6) & EFUSE_RD_ABS_DONE_0)
|
||||
{
|
||||
log_info("already secure boot !\n");
|
||||
return true;
|
||||
} else {
|
||||
boot_cache_redirect( 0, 64*1024);
|
||||
bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
|
||||
if (bin_len == 0) {
|
||||
log_error("boot len is error");
|
||||
return false;
|
||||
}
|
||||
if (false == secure_boot_generate(bin_len)){
|
||||
log_error("secure boot generate failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
REG_SET_BIT(EFUSE_BLK0_WDATA6, EFUSE_RD_ABS_DONE_0);
|
||||
REG_WRITE(EFUSE_CONF, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
|
||||
REG_WRITE(EFUSE_CMD, 0x02); /* efuse_pgm_cmd */
|
||||
while (REG_READ(EFUSE_CMD)); /* wait for efuse_pagm_cmd=0 */
|
||||
log_warn("burn abstract_done_0\n");
|
||||
REG_WRITE(EFUSE_CONF, 0x5AA5); /* efuse_read_op_ena, release force */
|
||||
REG_WRITE(EFUSE_CMD, 0x01); /* efuse_read_cmd */
|
||||
while (REG_READ(EFUSE_CMD)); /* wait for efuse_read_cmd=0 */
|
||||
log_debug("read EFUSE_BLK0_RDATA6 %x\n", REG_READ(EFUSE_BLK0_RDATA6));
|
||||
return true;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user