Merge branch 'master' into driver_merge_tmp/merge_gpio

This commit is contained in:
Wangjialin 2016-09-22 10:50:06 +08:00
commit 71fe8d9f15
27 changed files with 1126 additions and 426 deletions

View file

@ -95,6 +95,7 @@ test_build_system:
when: on_success
only:
- master
- triggers
variables:
# need user to set SDK_NAME and CONFIG_FILE (may need to set BIN_PATH and APP_NAME later) in before_script

View file

@ -1,33 +1,31 @@
menu "Bootloader config"
choice BOOTLOADER_LOG_LEVEL
choice LOG_BOOTLOADER_LEVEL
bool "Bootloader log verbosity"
default BOOTLOADER_LOG_LEVEL_NOTICE
default LOG_BOOTLOADER_LEVEL_WARN
help
Specify how much output to see in the bootloader logs.
Specify how much output to see in bootloader logs.
Note that if MTDO is HIGH on reset, all early boot output
(including bootloader logs) are suppressed.
config BOOTLOADER_LOG_LEVEL_NONE
config LOG_BOOTLOADER_LEVEL_NONE
bool "No output"
config BOOTLOADER_LOG_LEVEL_ERROR
config LOG_BOOTLOADER_LEVEL_ERROR
bool "Error"
config BOOTLOADER_LOG_LEVEL_WARN
config LOG_BOOTLOADER_LEVEL_WARN
bool "Warning"
config BOOTLOADER_LOG_LEVEL_INFO
config LOG_BOOTLOADER_LEVEL_INFO
bool "Info"
config BOOTLOADER_LOG_LEVEL_NOTICE
bool "Notice"
config BOOTLOADER_LOG_LEVEL_DEBUG
config LOG_BOOTLOADER_LEVEL_DEBUG
bool "Debug"
config LOG_BOOTLOADER_LEVEL_VERBOSE
bool "Verbose"
endchoice
config BOOTLOADER_LOG_COLORS
bool "Use ANSI terminal colors in bootloader log output"
default "y"
help
Enable ANSI terminal color codes in bootloader output.
In order to view these, your terminal program must support ANSI color codes.
config LOG_BOOTLOADER_LEVEL
int
default 0 if LOG_BOOTLOADER_LEVEL_NONE
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
default 2 if LOG_BOOTLOADER_LEVEL_WARN
default 3 if LOG_BOOTLOADER_LEVEL_INFO
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
endmenu

View file

@ -45,4 +45,7 @@ $(COMPONENT_PATH)/src/sdkconfig: $(PROJECT_PATH)/sdkconfig
bootloader-flash: $(BOOTLOADER_BIN)
$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src flash MAKEFLAGS= V=$(V)
else
CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include
endif

View file

@ -4,14 +4,14 @@
#
PROJECT_NAME := bootloader
COMPONENTS := esptool_py bootloader
COMPONENTS := esptool_py bootloader log
# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
#
# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op
IS_BOOTLOADER_BUILD := 1
#We cannot include the esp32 component directly but we need its includes. This is fixed by
#adding it in the main/Makefile directory.
#We cannot include the esp32 component directly but we need its includes.
#This is fixed by adding CFLAGS from Makefile.projbuild
include $(IDF_PATH)/make/project.mk

View file

@ -1,114 +0,0 @@
// 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
#include "sdkconfig.h"
#define BOOT_LOG_LEVEL_NONE (0)
#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 "30"
#define Red "31"
#define Green "32"
#define Brown "33"
#define Blue "34"
#define Purple "35"
#define Cyan "36"
#if CONFIG_BOOTLOADER_LOG_COLORS
#define LOG_COLOR(COLOR) "\033[0;"COLOR"m"
#define LOG_BOLD(COLOR) "\033[1;"COLOR"m"
#define LOG_RESET_COLOR "\033[0m"
#else
#define LOG_COLOR(...)
#define LOG_BOLD(...)
#define LOG_RESET_COLOR ""
#endif
// BOOT_LOG_LEVEL defined by make menuconfig
#if CONFIG_BOOTLOADER_LOG_LEVEL_NONE
#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_NONE
#elif CONFIG_BOOTLOADER_LOG_LEVEL_ERROR
#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_ERROR
#elif CONFIG_BOOTLOADER_LOG_LEVEL_WARN
#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_WARN
#elif CONFIG_BOOTLOADER_LOG_LEVEL_INFO
#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_INFO
#elif CONFIG_BOOTLOADER_LOG_LEVEL_NOTICE
#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_NOTICE
#elif CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG
#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_DEBUG
#else
#error "No bootloader log level set in menuconfig!"
#endif
//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(LOG_COLOR(Cyan) format "\r\n", ##__VA_ARGS__); \
ets_printf(LOG_RESET_COLOR); \
}\
}while(0)
#define log_info(format, ...) \
do{\
if(BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_INFO){\
ets_printf(LOG_BOLD(Cyan) format "\r\n", ##__VA_ARGS__); \
ets_printf(LOG_RESET_COLOR); \
}\
}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(LOG_COLOR(Red) "[ERROR][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ets_printf(LOG_RESET_COLOR); \
}\
}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(LOG_BOLD(Brown) "[WARN][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ets_printf(LOG_RESET_COLOR); \
}\
}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(LOG_BOLD(Green) "[DEBUG][%s][%s][%d]\n" format "\r\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ets_printf(LOG_RESET_COLOR); \
}\
}while(0)
#ifdef __cplusplus
}
#endif
#endif /* __BOOT_LOGGING_H__ */

View file

@ -16,6 +16,7 @@
#include <limits.h>
#include "esp_attr.h"
#include "esp_log.h"
#include "rom/cache.h"
#include "rom/ets_sys.h"
@ -23,6 +24,7 @@
#include "rom/crc.h"
#include "soc/soc.h"
#include "soc/cpu.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/efuse_reg.h"
@ -31,11 +33,12 @@
#include "sdkconfig.h"
#include "bootloader_log.h"
#include "bootloader_config.h"
extern int _bss_start;
extern int _bss_end;
static const char* TAG = "boot";
/*
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.
@ -58,36 +61,7 @@ void IRAM_ATTR set_cache_and_start_app(uint32_t drom_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");
cpu_configure_region_protection();
//Clear bss
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
@ -130,7 +104,7 @@ 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);
ESP_LOGD(TAG, "pos %d %x",pos,*(uint8_t *)pos);
if(0xE9 != *(uint8_t *)pos) {
return 0;
}
@ -142,7 +116,7 @@ uint32_t get_bin_len(uint32_t pos)
} else {
len += 16;
}
log_debug("bin length = %d\n", len);
ESP_LOGD(TAG, "bin length = %d", len);
return len;
}
@ -161,7 +135,7 @@ void boot_cache_redirect( uint32_t pos, size_t size )
uint32_t count = (size + 0xffff) / 0x10000;
Cache_Read_Disable( 0 );
Cache_Flush( 0 );
log_debug( "mmu set paddr=%08x count=%d", pos_aligned, count );
ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", pos_aligned, count );
cache_flash_mmu_set( 0, 0, 0x3f400000, pos_aligned, 64, count );
Cache_Read_Enable( 0 );
}
@ -183,13 +157,13 @@ bool load_partition_table(bootloader_state_t* bs, uint32_t addr)
int index = 0;
char *partition_usage;
log_info("Partition Table:");
log_info("## Label Usage Type ST Offset Length");
ESP_LOGI(TAG, "Partition Table:");
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
while (addr < end) {
log_debug("load partition table entry from %x(%08x)", addr, MEM_CACHE(addr));
ESP_LOGD(TAG, "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);
ESP_LOGD(TAG, "type=%x subtype=%x", partition.type, partition.subtype);
partition_usage = "unknown";
if (partition.magic == PARTITION_MAGIC) { /* valid partition definition */
@ -244,14 +218,14 @@ bool load_partition_table(bootloader_state_t* bs, uint32_t addr)
}
/* print partition type info */
log_info("%2d %-16s %-16s %02x %02x %08x %08x", index, partition.label, partition_usage,
ESP_LOGI(TAG, "%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");
ESP_LOGI(TAG,"End of partition table");
return true;
}
@ -274,14 +248,7 @@ static bool ota_select_valid(const ota_select *s)
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( "**************************************");
ESP_LOGI(TAG, "Espressif ESP32 2nd stage bootloader v. %s", BOOT_VERSION);
struct flash_hdr fhdr;
bootloader_state_t bs;
@ -289,7 +256,7 @@ void bootloader_main()
ota_select sa,sb;
memset(&bs, 0, sizeof(bs));
log_notice( "compile time %s\n", __TIME__ );
ESP_LOGI(TAG, "compile time " __TIME__ );
/* close watch dog here */
REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
@ -302,14 +269,14 @@ void bootloader_main()
print_flash_info(&fhdr);
if (!load_partition_table(&bs, PARTITION_ADD)) {
log_error("load partition table error!");
ESP_LOGE(TAG, "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");
//ESP_LOGE("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));
@ -325,13 +292,13 @@ void bootloader_main()
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);
ESP_LOGE(TAG, 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);
ESP_LOGE(TAG, SPI_ERROR_LOG);
return;
}
Cache_Read_Enable(0);
@ -344,7 +311,7 @@ void bootloader_main()
}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");
ESP_LOGE(TAG, "ota data partition info error");
return;
}
}
@ -353,15 +320,15 @@ void bootloader_main()
} 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");
ESP_LOGE(TAG, "nothing to load");
return;
}
log_info("Loading app partition at offset %08x", load_part_pos);
ESP_LOGI(TAG, "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");
ESP_LOGE(TAG, "secure boot failed");
return;
}
}
@ -369,7 +336,7 @@ void bootloader_main()
if(fhdr.encrypt_flag == 0x01) {
/* encrypt flash */
if (false == flash_encrypt(&bs)) {
log_error("flash encrypt failed");
ESP_LOGE(TAG, "flash encrypt failed");
return;
}
}
@ -395,7 +362,7 @@ void unpack_load_app(const partition_pos_t* partition)
uint32_t irom_load_addr = 0;
uint32_t irom_size = 0;
log_debug("bin_header: %u %u %u %u %08x\n", image_header.magic,
ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
image_header.blocks,
image_header.spi_mode,
image_header.spi_size,
@ -420,7 +387,7 @@ void unpack_load_app(const partition_pos_t* partition)
}
if (address >= DROM_LOW && address < DROM_HIGH) {
log_debug("found drom section, map from %08x to %08x\n", pos,
ESP_LOGD(TAG, "found drom section, map from %08x to %08x", pos,
section_header.load_addr);
drom_addr = partition->offset + pos - sizeof(section_header);
drom_load_addr = section_header.load_addr;
@ -430,7 +397,7 @@ void unpack_load_app(const partition_pos_t* partition)
}
if (address >= IROM_LOW && address < IROM_HIGH) {
log_debug("found irom section, map from %08x to %08x\n", pos,
ESP_LOGD(TAG, "found irom section, map from %08x to %08x", pos,
section_header.load_addr);
irom_addr = partition->offset + pos - sizeof(section_header);
irom_load_addr = section_header.load_addr;
@ -439,7 +406,7 @@ void unpack_load_app(const partition_pos_t* partition)
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":"");
ESP_LOGI(TAG, "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;
@ -468,29 +435,29 @@ void IRAM_ATTR set_cache_and_start_app(
uint32_t irom_size,
uint32_t entry_addr)
{
log_debug("configure drom and irom and start\n");
ESP_LOGD(TAG, "configure drom and irom and start");
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 );
ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", 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 );
ESP_LOGV(TAG, "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 );
ESP_LOGV(TAG, "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 );
ESP_LOGV(TAG, "i mmu set paddr=%08x vaddr=%08x size=%d n=%d", 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 );
ESP_LOGV(TAG, "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 );
ESP_LOGV(TAG, "rc=%d", rc );
REG_CLR_BIT( DPORT_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( DPORT_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);
ESP_LOGD(TAG, "start: 0x%08x", entry_addr);
typedef void (*entry_t)(void);
entry_t entry = ((entry_t) entry_addr);
@ -506,11 +473,11 @@ void print_flash_info(struct flash_hdr* pfhdr)
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 );
ESP_LOGD(TAG, "magic %02x", fhdr.magic );
ESP_LOGD(TAG, "blocks %02x", fhdr.blocks );
ESP_LOGD(TAG, "spi_mode %02x", fhdr.spi_mode );
ESP_LOGD(TAG, "spi_speed %02x", fhdr.spi_speed );
ESP_LOGD(TAG, "spi_size %02x", fhdr.spi_size );
const char* str;
switch ( fhdr.spi_speed ) {
@ -534,7 +501,7 @@ void print_flash_info(struct flash_hdr* pfhdr)
str = "20MHz";
break;
}
log_notice( " SPI Speed : %s", str );
ESP_LOGI(TAG, "SPI Speed : %s", str );
@ -566,7 +533,7 @@ void print_flash_info(struct flash_hdr* pfhdr)
str = "DIO";
break;
}
log_notice( " SPI Mode : %s", str );
ESP_LOGI(TAG, "SPI Mode : %s", str );
@ -595,6 +562,6 @@ void print_flash_info(struct flash_hdr* pfhdr)
str = "1MB";
break;
}
log_notice( " SPI Flash Size : %s", str );
ESP_LOGI(TAG, "SPI Flash Size : %s", str );
#endif
}

View file

@ -8,6 +8,5 @@
#
COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld
COMPONENT_EXTRA_INCLUDES := $(IDF_PATH)/components/esp32/include
include $(IDF_PATH)/make/component_common.mk

View file

@ -16,6 +16,7 @@
#include "esp_types.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "rom/cache.h"
#include "rom/ets_sys.h"
@ -28,13 +29,14 @@
#include "sdkconfig.h"
#include "bootloader_log.h"
#include "bootloader_config.h"
static const char* TAG = "flash_encrypt";
/**
* @function : bitcount
* @description: caculate bit 1 in flash_crypt_cnt
* if it's even number ,need encrypt flash data,and burn efuse
* @description: calculate 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
@ -68,19 +70,19 @@ bool flash_encrypt_write(uint32_t pos, uint32_t len)
spiRet = SPIRead(pos, buf, SPI_SEC_SIZE);
if (spiRet != SPI_FLASH_RESULT_OK) {
Cache_Read_Enable(0);
log_error(SPI_ERROR_LOG);
ESP_LOGE(TAG, 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);
ESP_LOGE(TAG, 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);
ESP_LOGE(TAG, SPI_ERROR_LOG);
return false;
}
pos += SPI_SEC_SIZE;
@ -104,53 +106,53 @@ bool flash_encrypt(bootloader_state_t *bs)
uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, 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);
ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", 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");
if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
ESP_LOGE(TAG, "encrypt iv and abstract 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");
if (false == flash_encrypt_write(0x1000, bin_len)) {
ESP_LOGE(TAG, "encrypt 2nd boot error");
return false;
}
} else {
log_error("2nd boot len error");
ESP_LOGE(TAG, "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");
if (false == flash_encrypt_write(PARTITION_ADD, SPI_SEC_SIZE)) {
ESP_LOGE(TAG, "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);
ESP_LOGD(TAG, "have factory bin");
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");
if (false == flash_encrypt_write(bs->factory.offset, bin_len)) {
ESP_LOGE(TAG, "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);
ESP_LOGD(TAG, "have test bin");
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");
if (false == flash_encrypt_write(bs->test.offset, bin_len)) {
ESP_LOGE(TAG, "encrypt test bin error");
return false;
}
}
@ -158,33 +160,33 @@ bool flash_encrypt(bootloader_state_t *bs)
/* 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);
ESP_LOGD(TAG, "have ota[%d] bin",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");
if (false == flash_encrypt_write(bs->ota[i].offset, bin_len)) {
ESP_LOGE(TAG, "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");
if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
ESP_LOGE(TAG, "encrypt ota info error");
return false;
}
REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04);
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
log_warn("burn flash_crypt_cnt\n");
ESP_LOGW(TAG, "burn flash_crypt_cnt");
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
return true;
} else {
log_info("flash already encrypted.\n");
ESP_LOGI(TAG, "flash already encrypted.");
return true;
}
}

View file

@ -16,6 +16,7 @@
#include "esp_attr.h"
#include "esp_types.h"
#include "esp_log.h"
#include "rom/cache.h"
#include "rom/ets_sys.h"
@ -29,12 +30,13 @@
#include "sdkconfig.h"
#include "bootloader_log.h"
#include "bootloader_config.h"
static const char* TAG = "secure_boot";
/**
* @function : secure_boot_generate
* @description: generate boot abstruct & iv
* @description: generate boot abstract & iv
*
* @inputs: bool
*/
@ -53,17 +55,17 @@ bool secure_boot_generate(uint32_t bin_len){
spiRet = SPIEraseSector(0);
if (spiRet != SPI_FLASH_RESULT_OK)
{
log_error(SPI_ERROR_LOG);
ESP_LOGE(TAG, 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);
ESP_LOGE(TAG, SPI_ERROR_LOG);
return false;
}
log_debug("write iv to flash.\n");
ESP_LOGD(TAG, "write iv to flash.");
Cache_Read_Enable(0);
/* read 4K code image from flash, for test */
for (i = 0; i < bin_len; i+=128) {
@ -77,10 +79,10 @@ bool secure_boot_generate(uint32_t bin_len){
/* 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);
ESP_LOGE(TAG, SPI_ERROR_LOG);
return false;
}
log_debug("write abstract to flash.\n");
ESP_LOGD(TAG, "write abstract to flash.");
Cache_Read_Enable(0);
return true;
}
@ -88,7 +90,7 @@ bool secure_boot_generate(uint32_t bin_len){
/**
* @function : secure_boot
* @description: protect boot code inflash
* @description: protect boot code in flash
*
* @inputs: bool
*/
@ -96,17 +98,17 @@ bool secure_boot(void){
uint32_t bin_len = 0;
if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0)
{
log_info("already secure boot !\n");
ESP_LOGD(TAG, "already secure boot !");
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");
ESP_LOGE(TAG, "boot len is error");
return false;
}
if (false == secure_boot_generate(bin_len)){
log_error("secure boot generate failed");
ESP_LOGE(TAG, "secure boot generate failed");
return false;
}
}
@ -115,11 +117,11 @@ bool secure_boot(void){
REG_WRITE(EFUSE_CONF_REG, 0x5A5A); /* efuse_pgm_op_ena, force no rd/wr disable */
REG_WRITE(EFUSE_CMD_REG, 0x02); /* efuse_pgm_cmd */
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_pagm_cmd=0 */
log_warn("burn abstract_done_0\n");
ESP_LOGW(TAG, "burn abstract_done_0");
REG_WRITE(EFUSE_CONF_REG, 0x5AA5); /* efuse_read_op_ena, release force */
REG_WRITE(EFUSE_CMD_REG, 0x01); /* efuse_read_cmd */
while (REG_READ(EFUSE_CMD_REG)); /* wait for efuse_read_cmd=0 */
log_debug("read EFUSE_BLK0_RDATA6 %x\n", REG_READ(EFUSE_BLK0_RDATA6_REG));
ESP_LOGI(TAG, "read EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
return true;
}

View file

@ -1,5 +1,25 @@
menu "ESP32-specific config"
choice ESP32_DEFAULT_CPU_FREQ_MHZ
prompt "CPU frequency"
default ESP32_DEFAULT_CPU_FREQ_240
help
CPU frequency to be set on application startup.
config ESP32_DEFAULT_CPU_FREQ_80
bool "80 MHz"
config ESP32_DEFAULT_CPU_FREQ_160
bool "160 MHz"
config ESP32_DEFAULT_CPU_FREQ_240
bool "240 MHz"
endchoice
config ESP32_DEFAULT_CPU_FREQ_MHZ
int
default 80 if ESP32_DEFAULT_CPU_FREQ_80
default 160 if ESP32_DEFAULT_CPU_FREQ_160
default 240 if ESP32_DEFAULT_CPU_FREQ_240
config WIFI_ENABLED
bool "Enable low-level WiFi stack"
default "y"

View file

@ -0,0 +1,79 @@
// 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 <stdint.h>
#include "rom/ets_sys.h"
#include "rom/uart.h"
#include "sdkconfig.h"
typedef enum{
XTAL_40M = 40,
XTAL_26M = 26,
XTAL_24M = 24,
XTAL_AUTO = 0
} xtal_freq_t;
typedef enum{
CPU_80M = 1,
CPU_160M = 2,
CPU_240M = 3,
} cpu_freq_t;
extern void phy_get_romfunc_addr();
// TODO: these functions need to be moved from librtc to ESP-IDF
extern void rtc_init_lite();
extern void rtc_set_cpu_freq(xtal_freq_t xtal_freq, cpu_freq_t cpu_freq);
/*
* This function is not exposed as an API at this point,
* because FreeRTOS doesn't yet support dynamic changing of
* CPU frequency. Also we need to implement hooks for
* components which want to be notified of CPU frequency
* changes.
*/
void esp_set_cpu_freq(void)
{
uint32_t freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
phy_get_romfunc_addr();
// freq will be changed to 40MHz in rtc_init_lite,
// wait uart tx finish, otherwise some uart output will be lost
uart_tx_wait_idle(0);
rtc_init_lite();
cpu_freq_t freq = CPU_80M;
switch(freq_mhz) {
case 240:
freq = CPU_240M;
break;
case 160:
freq = CPU_160M;
break;
default:
freq_mhz = 80;
/* no break */
case 80:
freq = CPU_80M;
break;
}
// freq will be changed to freq in rtc_set_cpu_freq,
// wait uart tx finish, otherwise some uart output will be lost
uart_tx_wait_idle(0);
rtc_set_cpu_freq(XTAL_AUTO, freq);
ets_update_cpu_frequency(freq_mhz);
}

View file

@ -20,8 +20,10 @@
#include "rom/ets_sys.h"
#include "rom/uart.h"
#include "soc/cpu.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -39,194 +41,132 @@
#include "esp_event.h"
#include "esp_spi_flash.h"
#include "esp_ipc.h"
#include "esp_log.h"
static void IRAM_ATTR user_start_cpu0(void);
static void IRAM_ATTR call_user_start_cpu1();
static void IRAM_ATTR user_start_cpu1(void);
void Cache_Read_Enable();
extern void ets_setup_syscalls(void);
extern esp_err_t app_main(void *ctx);
extern int __cpu1_entry_point;
extern int _bss_start;
extern int _bss_end;
extern int _init_start;
extern int _init_end;
extern int _iram_romjumptable_start;
extern int _iram_romjumptable_end;
extern int _iram_text_start;
extern int _iram_text_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.
*/
static bool app_cpu_started = false;
void IRAM_ATTR call_user_start_cpu0() {
//Kill wdt
REG_CLR_BIT(0x3ff4808c, BIT(10)); //RTCCNTL+8C RTC_WDTCONFIG0 RTC_
REG_CLR_BIT(0x6001f048, BIT(14)); //DR_REG_BB_BASE+48
//Move exception vectors to IRAM
asm volatile (\
"wsr %0, vecbase\n" \
::"r"(&_init_start));
uartAttach();
ets_install_uart_printf();
//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");
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
//Initialize heap allocator
heap_alloc_caps_init();
ets_printf("Pro cpu up.\n");
#ifndef CONFIG_FREERTOS_UNICORE
ets_printf("Starting app cpu, entry point is %p\n", call_user_start_cpu1);
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1);
while (!app_cpu_started) {
ets_delay_us(100);
}
#else
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
#endif
ets_printf("Pro cpu start user code\n");
user_start_cpu0();
}
extern int _init_start;
void IRAM_ATTR call_user_start_cpu1() {
asm volatile (\
"wsr %0, vecbase\n" \
::"r"(&_init_start));
//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");
ets_printf("App cpu up.\n");
app_cpu_started = 1;
user_start_cpu1();
}
extern volatile int port_xSchedulerRunning[2];
void IRAM_ATTR user_start_cpu1(void) {
// Wait for FreeRTOS initialization to finish on PRO CPU
while (port_xSchedulerRunning[0] == 0) {
;
}
ets_printf("Starting scheduler on APP CPU.\n");
xPortStartScheduler();
}
extern void (*__init_array_start)(void);
extern void (*__init_array_end)(void);
extern volatile int port_xSchedulerRunning[2];
static void do_global_ctors(void) {
void (**p)(void);
for(p = &__init_array_start; p != &__init_array_end; ++p)
(*p)();
static const char* TAG = "cpu_start";
static bool app_cpu_started = false;
/*
* We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
* and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
*/
void IRAM_ATTR call_user_start_cpu0()
{
//Kill wdt
REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
REG_CLR_BIT(0x6001f048, BIT(14)); //DR_REG_BB_BASE+48
cpu_configure_region_protection();
//Move exception vectors to IRAM
asm volatile (\
"wsr %0, vecbase\n" \
::"r"(&_init_start));
uartAttach();
ets_install_uart_printf();
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
// Initialize heap allocator
heap_alloc_caps_init();
ESP_EARLY_LOGI(TAG, "Pro cpu up.");
#ifndef CONFIG_FREERTOS_UNICORE
ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_user_start_cpu1);
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1);
while (!app_cpu_started) {
ets_delay_us(100);
}
#else
ESP_EARLY_LOGI(TAG, "Single core mode");
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
#endif
ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
user_start_cpu0();
}
extern esp_err_t app_main(void *ctx);
void user_start_cpu0(void) {
ets_setup_syscalls();
do_global_ctors();
esp_ipc_init();
spi_flash_init();
void IRAM_ATTR call_user_start_cpu1()
{
asm volatile (\
"wsr %0, vecbase\n" \
::"r"(&_init_start));
cpu_configure_region_protection();
ESP_EARLY_LOGI(TAG, "App cpu up.");
app_cpu_started = 1;
user_start_cpu1();
}
void IRAM_ATTR user_start_cpu1(void)
{
// Wait for FreeRTOS initialization to finish on PRO CPU
while (port_xSchedulerRunning[0] == 0) {
;
}
ESP_LOGI(TAG, "Starting scheduler on APP CPU.");
xPortStartScheduler();
}
static void do_global_ctors(void)
{
void (**p)(void);
for (p = &__init_array_start; p != &__init_array_end; ++p) {
(*p)();
}
}
void user_start_cpu0(void)
{
esp_set_cpu_freq(); // set CPU frequency configured in menuconfig
uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
ets_setup_syscalls();
do_global_ctors();
esp_ipc_init();
spi_flash_init();
#if CONFIG_WIFI_ENABLED
esp_err_t ret = nvs_flash_init(5, 3);
if (ret != ESP_OK) {
printf("nvs_flash_init failed, ret=%d\n", ret);
ESP_LOGE(TAG, "nvs_flash_init failed, ret=%d", ret);
}
system_init();
esp_event_init(NULL, NULL);
tcpip_adapter_init();
#endif
#if CONFIG_WIFI_ENABLED && CONFIG_WIFI_AUTO_STARTUP
#include "esp_wifi.h"
esp_wifi_startup(app_main, NULL);
esp_wifi_startup(app_main, NULL);
#else
app_main(NULL);
app_main(NULL);
#endif
ets_printf("Starting scheduler on PRO CPU.\n");
vTaskStartScheduler();
ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
vTaskStartScheduler();
}

View file

@ -17,6 +17,9 @@
#include "heap_alloc_caps.h"
#include "spiram.h"
#include "esp_log.h"
static const char* TAG = "heap_alloc_caps";
/*
This file, combined with a region allocator that supports tags, solves the problem that the ESP32 has RAM that's
@ -147,7 +150,7 @@ static void disable_mem_region(void *from, void *to) {
regions[i].xSizeInBytes-=(uint8_t *)regEnd-(uint8_t *)from;
} else if (regStart<from && regEnd>to) {
//Range punches a hole in the region! We do not support this.
ets_printf("%s: region %d: hole punching is not supported!\n", i);
ESP_EARLY_LOGE(TAG, "region %d: hole punching is not supported!", i);
regions[i].xTag=-1; //Just disable memory region. That'll teach them!
}
}
@ -204,12 +207,13 @@ void heap_alloc_caps_init() {
}
}
#if 1 //Change to 1 to show the regions the heap allocator is initialized with.
ets_printf("Initializing heap allocator:\n");
ESP_EARLY_LOGI(TAG, "Initializing heap allocator:");
for (i=0; regions[i].xSizeInBytes!=0; i++) {
if ( regions[i].xTag != -1 ) ets_printf("Region %02d: %08X len %08X tag %d\n", i, (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag);
if (regions[i].xTag != -1) {
ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %d", i,
(int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag);
}
}
#endif
//Initialize the malloc implementation.
vPortDefineHeapRegionsTagged( regions );
}

View file

@ -33,4 +33,49 @@ static inline bool cpu_in_interrupt_context(void)
return (ps & PS_UM) == 0;
}
/* Functions to set page attributes for Region Protection option in the CPU.
* See Xtensa ISA Reference manual for explanation of arguments (section 4.6.3.2).
*/
static inline void cpu_write_dtlb(uint32_t vpn, unsigned attr)
{
asm volatile ("wdtlb %1, %0; dsync\n" :: "r" (vpn), "r" (attr));
}
static inline void cpu_write_itlb(unsigned vpn, unsigned attr)
{
asm volatile ("witlb %1, %0; isync\n" :: "r" (vpn), "r" (attr));
}
/* Make page 0 access raise an exception.
* Also protect some other unused pages so we can catch weirdness.
* Useful attribute values:
* 0 cached, RW
* 2 bypass cache, RWX (default value after CPU reset)
* 15 no access, raise exception
*/
static inline void cpu_configure_region_protection()
{
const uint32_t pages_to_protect[] = {0x00000000, 0x80000000, 0xa0000000, 0xc0000000, 0xe0000000};
for (int i = 0; i < sizeof(pages_to_protect)/sizeof(pages_to_protect[0]); ++i) {
cpu_write_dtlb(pages_to_protect[i], 0xf);
cpu_write_itlb(pages_to_protect[i], 0xf);
}
cpu_write_dtlb(0x20000000, 0);
cpu_write_itlb(0x20000000, 0);
}
/*
* @brief Set CPU frequency to the value defined in menuconfig
*
* Called from cpu_start.c, not intended to be called from other places.
* This is a temporary function which will be replaced once dynamic
* CPU frequency changing is implemented.
*/
void esp_set_cpu_freq(void);
#endif

@ -1 +1 @@
Subproject commit 1303c92c1056b7f59b95360b58e70a21cb4a93e1
Subproject commit 9f26b9a190e6a6ca42656685df9287253badfa46

View file

@ -367,6 +367,23 @@ void IRAM_ATTR _lock_release_recursive(_lock_t *lock) {
lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX);
}
// This function is not part on newlib API, it is defined in libc/stdio/local.h
// It is called as part of _reclaim_reent via a pointer in __cleanup member
// of struct _reent.
// This function doesn't call _fclose_r for _stdin, _stdout, _stderr members
// of struct reent. Not doing so causes a memory leak each time a task is
// terminated. We replace __cleanup member with _extra_cleanup_r (below) to work
// around this.
extern void _cleanup_r(struct _reent* r);
void _extra_cleanup_r(struct _reent* r)
{
_cleanup_r(r);
_fclose_r(r, r->_stdout);
_fclose_r(r, r->_stderr);
_fclose_r(r, r->_stdin);
}
static struct _reent s_reent;
/*

View file

@ -100,7 +100,7 @@
#define configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS 1
/* TODO: config freq by menuconfig */
#define XT_CLOCK_FREQ 80000000
#define XT_CLOCK_FREQ (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000)
/* Required for configuration-dependent settings */
#include "xtensa_config.h"

View file

@ -85,6 +85,7 @@ task.h is included from an application file. */
#include "StackMacros.h"
#include "portmacro.h"
#include "semphr.h"
#include "sys/reent.h"
/* Lint e961 and e750 are suppressed as a MISRA exception justified because the
MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
@ -3489,6 +3490,9 @@ TCB_t *pxNewTCB;
#if ( INCLUDE_vTaskDelete == 1 )
// TODO: move this to newlib component and provide a header file
extern void _extra_cleanup_r(struct _reent* r);
static void prvDeleteTCB( TCB_t *pxTCB )
{
/* This call is required specifically for the TriCore port. It must be
@ -3500,6 +3504,7 @@ TCB_t *pxNewTCB;
to the task to free any memory allocated at the application level. */
#if ( configUSE_NEWLIB_REENTRANT == 1 )
{
pxTCB->xNewLib_reent.__cleanup = &_extra_cleanup_r;
_reclaim_reent( &( pxTCB->xNewLib_reent ) );
}
#endif /* configUSE_NEWLIB_REENTRANT */

48
components/log/Kconfig Normal file
View file

@ -0,0 +1,48 @@
menu "Log output"
choice LOG_DEFAULT_LEVEL
bool "Default log verbosity"
default LOG_DEFAULT_LEVEL_INFO
help
Specify how much output to see in logs by default.
You can set lower verbosity level at runtime using
esp_log_level_set function.
Note that this setting limits which log statements
are compiled into the program. So setting this to, say,
"Warning" would mean that changing log level to "Debug"
at runtime will not be possible.
config LOG_DEFAULT_LEVEL_NONE
bool "No output"
config LOG_DEFAULT_LEVEL_ERROR
bool "Error"
config LOG_DEFAULT_LEVEL_WARN
bool "Warning"
config LOG_DEFAULT_LEVEL_INFO
bool "Info"
config LOG_DEFAULT_LEVEL_DEBUG
bool "Debug"
config LOG_DEFAULT_LEVEL_VERBOSE
bool "Verbose"
endchoice
config LOG_DEFAULT_LEVEL
int
default 0 if LOG_DEFAULT_LEVEL_NONE
default 1 if LOG_DEFAULT_LEVEL_ERROR
default 2 if LOG_DEFAULT_LEVEL_WARN
default 3 if LOG_DEFAULT_LEVEL_INFO
default 4 if LOG_DEFAULT_LEVEL_DEBUG
default 5 if LOG_DEFAULT_LEVEL_VERBOSE
config LOG_COLORS
bool "Use ANSI terminal colors in log output"
default "y"
help
Enable ANSI terminal color codes in bootloader output.
In order to view these, your terminal program must support ANSI color codes.
endmenu

3
components/log/component.mk Executable file
View file

@ -0,0 +1,3 @@
COMPONENT_ADD_INCLUDEDIRS := include
include $(IDF_PATH)/make/component_common.mk

View file

@ -0,0 +1,209 @@
// 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 __ESP_LOG_H__
#define __ESP_LOG_H__
#include <stdint.h>
#include <stdarg.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Logging library
*
* Log library has two ways of managing log verbosity: compile time, set via
* menuconfig, and runtime, using esp_log_set_level function.
*
* At compile time, filtering is done using CONFIG_LOG_DEFAULT_LEVEL macro, set via
* menuconfig. All logging statments for levels higher than CONFIG_LOG_DEFAULT_LEVEL
* will be removed by the preprocessor.
*
* At run time, all logs below CONFIG_LOG_DEFAULT_LEVEL are enabled by default.
* esp_log_set_level function may be used to set logging level per module.
* Modules are identified by their tags, which are human-readable ASCII
* zero-terminated strings.
*
* How to use this library:
*
* In each C file which uses logging functionality, define TAG variable like this:
*
* static const char* TAG = "MyModule";
*
* then use one of logging macros to produce output, e.g:
*
* ESP_LOGW(TAG, "Baud rate error %.1f%%. Requested: %d baud, actual: %d baud", error * 100, baud_req, baud_real);
*
* Several macros are available for different verbosity levels:
*
* ESP_LOGE error
* ESP_LOGW warning
* ESP_LOGI info
* ESP_LOGD - debug
* ESP_LOGV - verbose
*
* Additionally there is an _EARLY_ variant for each of these macros (e.g. ESP_EARLY_LOGE).
* These variants can run in startup code, before heap allocator and syscalls
* have been initialized.
* When compiling bootloader, normal ESP_LOGx macros fall back to the same implementation
* as ESP_EARLY_LOGx macros. So the only place where ESP_EARLY_LOGx have to be used explicitly
* is the early startup code, such as heap allocator initialization code.
*
* (Note that such distinction would not have been necessary if we would have an
* ets_vprintf function in the ROM. Then it would be possible to switch implementation
* from _EARLY version to normal version on the fly. Unfortunately, ets_vprintf in ROM
* has been inlined by the compiler into ets_printf, so it is not accessible outside.)
*
* To override default verbosity level at file or component scope, define LOG_LOCAL_LEVEL macro.
* At file scope, define it before including esp_log.h, e.g.:
*
* #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
* #include "esp_log.h"
*
* At component scope, define it in component makefile:
*
* CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG
*
* To configure logging output per module at runtime, add calls to esp_log_set_level function:
*
* esp_log_set_level("*", ESP_LOG_ERROR); // set all components to ERROR level
* esp_log_set_level("wifi", ESP_LOG_WARN); // enable WARN logs from WiFi stack
* esp_log_set_level("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client
*
*/
typedef enum {
ESP_LOG_NONE, // No log output
ESP_LOG_ERROR, // Critical errors, software module can not recover on its own
ESP_LOG_WARN, // Error conditions from which recovery measures have been taken
ESP_LOG_INFO, // Information messages which describe normal flow of events
ESP_LOG_DEBUG, // Extra information which is not necessary for normal use (values, pointers, sizes, etc).
ESP_LOG_VERBOSE // Bigger chunks of debugging information, or frequent messages which can potentially flood the output.
} esp_log_level_t;
typedef int (*vprintf_like_t)(const char *, va_list);
/**
* @brief Set log level for given tag
*
* If logging for given component has already been enabled, changes previous setting.
*
* @param tag Tag of the log entries to enable. Must be a non-NULL zero terminated string.
* Value "*" resets log level for all tags to the given value.
*
* @param level Selects log level to enable. Only logs at this and lower levels will be shown.
*/
void esp_log_level_set(const char* tag, esp_log_level_t level);
/**
* @brief Set function used to output log entries
*
* By default, log output goes to UART0. This function can be used to redirect log
* output to some other destination, such as file or network.
*
* @param func Function used for output. Must have same signature as vprintf.
*/
void esp_log_set_vprintf(vprintf_like_t func);
/**
* @brief Write message into the log
*
* This function is not intended to be used directly. Instead, use one of
* ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros.
*
* This function or these macros should not be used from an interrupt.
*/
void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
/**
* @brief Function which returns timestamp to be used in log output
*
* This function is used in expansion of ESP_LOGx macros.
* In the 2nd stage bootloader, and at early application startup stage
* this function uses CPU cycle counter as time source. Later when
* FreeRTOS scheduler start running, it switches to FreeRTOS tick count.
*
* For now, we ignore millisecond counter overflow.
*
* @return timestamp, in milliseconds
*/
uint32_t esp_log_timestamp();
#if CONFIG_LOG_COLORS
#define LOG_COLOR_BLACK "30"
#define LOG_COLOR_RED "31"
#define LOG_COLOR_GREEN "32"
#define LOG_COLOR_BROWN "33"
#define LOG_COLOR_BLUE "34"
#define LOG_COLOR_PURPLE "35"
#define LOG_COLOR_CYAN "36"
#define LOG_COLOR(COLOR) "\033[0;" COLOR "m"
#define LOG_BOLD(COLOR) "\033[1;" COLOR "m"
#define LOG_RESET_COLOR "\033[0m"
#define LOG_COLOR_E LOG_COLOR(LOG_COLOR_RED)
#define LOG_COLOR_W LOG_COLOR(LOG_COLOR_BROWN)
#define LOG_COLOR_I LOG_COLOR(LOG_COLOR_GREEN)
#define LOG_COLOR_D
#define LOG_COLOR_V
#else //CONFIG_LOG_COLORS
#define LOG_COLOR_E
#define LOG_COLOR_W
#define LOG_COLOR_I
#define LOG_COLOR_D
#define LOG_COLOR_V
#define LOG_RESET_COLOR
#endif //CONFIG_LOG_COLORS
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n"
#ifndef LOG_LOCAL_LEVEL
#ifndef BOOTLOADER_BUILD
#define LOG_LOCAL_LEVEL ((esp_log_level_t) CONFIG_LOG_DEFAULT_LEVEL)
#else
#define LOG_LOCAL_LEVEL ((esp_log_level_t) CONFIG_LOG_BOOTLOADER_LEVEL)
#endif
#endif
#define ESP_EARLY_LOGE( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_EARLY_LOGW( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { ets_printf(LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_EARLY_LOGI( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { ets_printf(LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_EARLY_LOGD( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { ets_printf(LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_EARLY_LOGV( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { ets_printf(LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#ifndef BOOTLOADER_BUILD
#define ESP_LOGE( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGW( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGI( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGD( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGV( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#else
#define ESP_LOGE( tag, format, ... ) ESP_EARLY_LOGE(tag, format, ##__VA_ARGS__)
#define ESP_LOGW( tag, format, ... ) ESP_EARLY_LOGW(tag, format, ##__VA_ARGS__)
#define ESP_LOGI( tag, format, ... ) ESP_EARLY_LOGI(tag, format, ##__VA_ARGS__)
#define ESP_LOGD( tag, format, ... ) ESP_EARLY_LOGD(tag, format, ##__VA_ARGS__)
#define ESP_LOGV( tag, format, ... ) ESP_EARLY_LOGV(tag, format, ##__VA_ARGS__)
#endif // BOOTLOADER_BUILD
#ifdef __cplusplus
}
#endif
#endif /* __ESP_LOG_H__ */

313
components/log/log.c Normal file
View file

@ -0,0 +1,313 @@
// 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.
/*
* Log library implementation notes.
*
* Log library stores all tags provided to esp_log_set_level as a linked
* list. See uncached_tag_entry_t structure.
*
* To avoid looking up log level for given tag each time message is
* printed, this library caches pointers to tags. Because the suggested
* way of creating tags uses one 'TAG' constant per file, this caching
* should be effective. Cache is a binary min-heap of cached_tag_entry_t
* items, ordering is done on 'generation' member. In this context,
* generation is an integer which is incremented each time an operation
* with cache is performed. When cache is full, new item is inserted in
* place of an oldest item (that is, with smallest 'generation' value).
* After that, bubble-down operation is performed to fix ordering in the
* min-heap.
*
* The potential problem with wrap-around of cache generation counter is
* ignored for now. This will happen if someone happens to output more
* than 4 billion log entries, at which point wrap-around will not be
* the biggest problem.
*
*/
#ifndef BOOTLOADER_BUILD
#include <freertos/FreeRTOS.h>
#include <freertos/FreeRTOSConfig.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#endif
#include "esp_attr.h"
#include "xtensa/hal.h"
#include "soc/soc.h"
#include <stdbool.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "esp_log.h"
#ifndef BOOTLOADER_BUILD
// Number of tags to be cached. Must be 2**n - 1, n >= 2.
#define TAG_CACHE_SIZE 31
// Maximum time to wait for the mutex in a logging statement.
#define MAX_MUTEX_WAIT_MS 10
#define MAX_MUTEX_WAIT_TICKS ((MAX_MUTEX_WAIT_MS + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS)
// Uncomment this to enable consistency checks and cache statistics in this file.
// #define LOG_BUILTIN_CHECKS
typedef struct {
const char* tag;
uint32_t level : 3;
uint32_t generation : 29;
} cached_tag_entry_t;
typedef struct uncached_tag_entry_{
struct uncached_tag_entry_* next;
uint8_t level; // esp_log_level_t as uint8_t
char tag[0]; // beginning of a zero-terminated string
} uncached_tag_entry_t;
static esp_log_level_t s_log_default_level = ESP_LOG_VERBOSE;
static uncached_tag_entry_t* s_log_tags_head = NULL;
static uncached_tag_entry_t* s_log_tags_tail = NULL;
static cached_tag_entry_t s_log_cache[TAG_CACHE_SIZE];
static uint32_t s_log_cache_max_generation = 0;
static uint32_t s_log_cache_entry_count = 0;
static vprintf_like_t s_log_print_func = &vprintf;
static SemaphoreHandle_t s_log_mutex = NULL;
#ifdef LOG_BUILTIN_CHECKS
static uint32_t s_log_cache_misses = 0;
#endif
static inline bool get_cached_log_level(const char* tag, esp_log_level_t* level);
static inline bool get_uncached_log_level(const char* tag, esp_log_level_t* level);
static inline void add_to_cache(const char* tag, esp_log_level_t level);
static void heap_bubble_down(int index);
static inline void heap_swap(int i, int j);
static inline bool should_output(esp_log_level_t level_for_message, esp_log_level_t level_for_tag);
static inline void clear_log_level_list();
void esp_log_set_vprintf(vprintf_like_t func)
{
s_log_print_func = func;
}
void esp_log_level_set(const char* tag, esp_log_level_t level)
{
if (!s_log_mutex) {
s_log_mutex = xSemaphoreCreateMutex();
}
xSemaphoreTake(s_log_mutex, portMAX_DELAY);
// for wildcard tag, remove all linked list items and clear the cache
if (strcmp(tag, "*") == 0) {
s_log_default_level = level;
clear_log_level_list();
xSemaphoreGive(s_log_mutex);
return;
}
// allocate new linked list entry and append it to the endo of the list
size_t entry_size = offsetof(uncached_tag_entry_t, tag) + strlen(tag) + 1;
uncached_tag_entry_t* new_entry = (uncached_tag_entry_t*) malloc(entry_size);
if (!new_entry) {
xSemaphoreGive(s_log_mutex);
return;
}
new_entry->next = NULL;
new_entry->level = (uint8_t) level;
strcpy(new_entry->tag, tag);
if (s_log_tags_tail) {
s_log_tags_tail->next = new_entry;
}
s_log_tags_tail = new_entry;
if (!s_log_tags_head) {
s_log_tags_head = new_entry;
}
xSemaphoreGive(s_log_mutex);
}
void clear_log_level_list()
{
for (uncached_tag_entry_t* it = s_log_tags_head; it != NULL; ) {
uncached_tag_entry_t* next = it->next;
free(it);
it = next;
}
s_log_tags_tail = NULL;
s_log_tags_head = NULL;
s_log_cache_entry_count = 0;
s_log_cache_max_generation = 0;
#ifdef LOG_BUILTIN_CHECKS
s_log_cache_misses = 0;
#endif
}
void IRAM_ATTR esp_log_write(esp_log_level_t level,
const char* tag,
const char* format, ...)
{
if (!s_log_mutex) {
s_log_mutex = xSemaphoreCreateMutex();
}
if (xSemaphoreTake(s_log_mutex, MAX_MUTEX_WAIT_TICKS) == pdFALSE) {
return;
}
esp_log_level_t level_for_tag;
// Look for the tag in cache first, then in the linked list of all tags
if (!get_cached_log_level(tag, &level_for_tag)) {
if (!get_uncached_log_level(tag, &level_for_tag)) {
level_for_tag = s_log_default_level;
}
add_to_cache(tag, level_for_tag);
#ifdef LOG_BUILTIN_CHECKS
++s_log_cache_misses;
#endif
}
xSemaphoreGive(s_log_mutex);
if (!should_output(level, level_for_tag)) {
return;
}
va_list list;
va_start(list, format);
(*s_log_print_func)(format, list);
va_end(list);
}
static inline bool get_cached_log_level(const char* tag, esp_log_level_t* level)
{
// Look for `tag` in cache
int i;
for (i = 0; i < s_log_cache_entry_count; ++i) {
#ifdef LOG_BUILTIN_CHECKS
assert(i == 0 || s_log_cache[(i - 1) / 2].generation < s_log_cache[i].generation);
#endif
if (s_log_cache[i].tag == tag) {
break;
}
}
if (i == s_log_cache_entry_count) { // Not found in cache
return false;
}
// Return level from cache
*level = (esp_log_level_t) s_log_cache[i].level;
// If cache has been filled, start taking ordering into account
// (other options are: dynamically resize cache, add "dummy" entries
// to the cache; this option was chosen because code is much simpler,
// and the unfair behavior of cache will show it self at most once, when
// it has just been filled)
if (s_log_cache_entry_count == TAG_CACHE_SIZE) {
// Update item generation
s_log_cache[i].generation = s_log_cache_max_generation++;
// Restore heap ordering
heap_bubble_down(i);
}
return true;
}
static inline void add_to_cache(const char* tag, esp_log_level_t level)
{
uint32_t generation = s_log_cache_max_generation++;
// First consider the case when cache is not filled yet.
// In this case, just add new entry at the end.
// This happens to satisfy binary min-heap ordering.
if (s_log_cache_entry_count < TAG_CACHE_SIZE) {
s_log_cache[s_log_cache_entry_count] = (cached_tag_entry_t) {
.generation = generation,
.level = level,
.tag = tag
};
++s_log_cache_entry_count;
return;
}
// Cache is full, so we replace the oldest entry (which is at index 0
// because this is a min-heap) with the new one, and do bubble-down
// operation to restore min-heap ordering.
s_log_cache[0] = (cached_tag_entry_t) {
.tag = tag,
.level = level,
.generation = generation
};
heap_bubble_down(0);
}
static inline bool get_uncached_log_level(const char* tag, esp_log_level_t* level)
{
// Walk the linked list of all tags and see if given tag is present in the list.
// This is slow because tags are compared as strings.
for (uncached_tag_entry_t* it = s_log_tags_head; it != NULL; it = it->next) {
if (strcmp(tag, it->tag) == 0) {
*level = it->level;
return true;
}
}
return false;
}
static inline bool should_output(esp_log_level_t level_for_message, esp_log_level_t level_for_tag)
{
return level_for_message <= level_for_tag;
}
static void heap_bubble_down(int index)
{
while (index < TAG_CACHE_SIZE / 2) {
int left_index = index * 2 + 1;
int right_index = left_index + 1;
int next = (s_log_cache[left_index].generation < s_log_cache[right_index].generation) ? left_index : right_index;
heap_swap(index, next);
index = next;
}
}
static inline void heap_swap(int i, int j)
{
cached_tag_entry_t tmp = s_log_cache[i];
s_log_cache[i] = s_log_cache[j];
s_log_cache[j] = tmp;
}
#endif //BOOTLOADER_BUILD
inline IRAM_ATTR uint32_t esp_log_early_timestamp()
{
return xthal_get_ccount() / (CPU_CLK_FREQ_ROM / 1000);
}
#ifndef BOOTLOADER_BUILD
uint32_t IRAM_ATTR esp_log_timestamp()
{
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
return esp_log_early_timestamp();
}
static uint32_t base = 0;
if (base == 0) {
base = esp_log_early_timestamp();
}
return base + xTaskGetTickCount() * (1000 / configTICK_RATE_HZ);
}
#else
uint32_t IRAM_ATTR esp_log_timestamp()
{
return esp_log_early_timestamp();
}
#endif //BOOTLOADER_BUILD

View file

@ -16,6 +16,13 @@ config LWIP_THREAD_LOCAL_STORAGE_INDEX
Specify the thread-local-storage-pointer index for lwip
use.
config LWIP_SO_REUSE
bool "Enable SO_REUSEADDR option"
default 0
help
Enabling this option allows binding to a port which remains in
TIME_WAIT.
endmenu

View file

@ -0,0 +1,126 @@
// 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 "lwip/lwip_debug.h"
#include "lwip/api.h"
#include "lwip/netbuf.h"
#include "lwip/tcp.h"
#include "lwip/udp.h"
#include "lwip/priv/tcp_priv.h"
#define DBG_LWIP_IP_SHOW(info, ip) printf("%s type=%d ip=%x\n", (info), (ip).type, (ip).u_addr.ip4.addr)
#define DBG_LWIP_IP_PCB_SHOW(pcb) \
DBG_LWIP_IP_SHOW("local ip", (pcb)->local_ip);\
DBG_LWIP_IP_SHOW("remote ip", (pcb)->local_ip);\
printf("so_options=%x, tos=%d ttl=%d\n", (pcb)->so_options, (pcb)->tos, (pcb)->ttl)
#define DBG_LWIP_SEG_SHOW(seg) while(seg) { printf("\tseg=%p next=%p pbuf=%p flags=%x\n", (seg), (seg)->next, (seg)->p, (seg)->flags); (seg)=(seg)->next;}
static void dbg_lwip_tcp_pcb_one_show(struct tcp_pcb* pcb)
{
struct tcp_seg *seg = NULL;
if (!pcb) {
return;
}
printf("\npcb=%p next=%p cb_arg=%p\n", pcb, pcb->next, pcb->callback_arg);
DBG_LWIP_IP_PCB_SHOW(pcb);
printf("state=%x\n", pcb->state);
printf("prio=%d\n", pcb->prio);
printf("local_port=%d, remote_port=%d\n", pcb->local_port, pcb->remote_port);
printf("flags=%x\n", pcb->flags);
printf("pooltmr=%d pollinterval=%d, last_tmr=%d tmr=%d rtmer=%d\n", pcb->polltmr, pcb->pollinterval, pcb->last_timer, pcb->tmr, pcb->rtime);
printf("recv_nxt=%d recv_wnd=%d recv_ann_wnd=%d recv_ann_right_edge=%d\n", pcb->rcv_nxt, pcb->rcv_wnd, pcb->rcv_ann_wnd, pcb->rcv_ann_right_edge);
printf("mss=%d\n", pcb->mss);
printf("rttest=%d rtseq=%d sa=%d sv=%d\n", pcb->rttest, pcb->rtseq, pcb->sa, pcb->sv);
printf("rto=%d nrtx=%d\n", pcb->rto, pcb->nrtx);
printf("dupacks=%d lastack=%d\n", pcb->dupacks, pcb->lastack);
printf("cwnd=%d ssthreash=%d\n", pcb->cwnd, pcb->ssthresh);
printf("snd_next=%d snd_wl1=%d snd_wl2=%d\n", pcb->snd_nxt, pcb->snd_wl1, pcb->snd_wl2);
printf("snd_lbb=%d snd_wnd=%d snd_wnd_max=%d\n", pcb->snd_lbb, pcb->snd_wnd, pcb->snd_wnd_max);
printf("acked=%d\n", pcb->acked);
printf("snd_buf=%d snd_queuelen=%d\n", pcb->snd_buf, pcb->snd_queuelen);
printf("unsent_oversize=%d\n", pcb->unsent_oversize);
printf("keep_idle=%d keep_intvl=%d keep_cnt=%d\n", pcb->keep_idle, pcb->keep_intvl, pcb->keep_cnt);
printf("persist_cnt=%d persist_backoff=%d\n", pcb->persist_cnt, pcb->persist_backoff);
printf("keep_cnt_sent=%d\n", pcb->keep_cnt_sent);
printf("unsent segments:\n");
seg = pcb->unsent;
DBG_LWIP_SEG_SHOW(seg)
printf("unacked segments:\n");
seg = pcb->unacked;
DBG_LWIP_SEG_SHOW(seg);
printf("ooseg semengts:\n");
seg = pcb->ooseq;
DBG_LWIP_SEG_SHOW(seg);
printf("refused data=%p\n", pcb->refused_data);
}
static void dbg_lwip_tcp_pcb_list_show(struct tcp_pcb* pcb)
{
while(pcb){
dbg_lwip_tcp_pcb_one_show(pcb);
pcb = pcb->next;
}
}
extern struct tcp_pcb *tcp_bound_pcbs;
extern struct tcp_pcb *tcp_active_pcbs;
extern struct tcp_pcb *tcp_tw_pcbs;
void dbg_lwip_tcp_pcb_show(void)
{
printf("-------------active pcbs------------\n");
dbg_lwip_tcp_pcb_list_show(tcp_active_pcbs);
printf("-------------bound pcbs-------------\n");
dbg_lwip_tcp_pcb_list_show(tcp_bound_pcbs);
printf("-------------tw pcbs------------\n");
dbg_lwip_tcp_pcb_list_show(tcp_tw_pcbs);
}
void dbg_lwip_udp_pcb_one_show(struct udp_pcb *pcb)
{
printf("pcb=%p next=%p\n", pcb, (void*)pcb->next);
DBG_LWIP_IP_PCB_SHOW(pcb);
printf("flags=%x\n", pcb->flags);
printf("local_port=%d remote_port=%d\n", pcb->local_port, pcb->remote_port);
printf("recv cb=%p recv_arg=%p\n", pcb->recv, pcb->recv_arg);
}
extern struct udp_pcb *udp_pcbs;
void dbg_lwip_udp_pcb_show(void)
{
struct udp_pcb *pcb = udp_pcbs;
while (pcb){
dbg_lwip_udp_pcb_one_show(pcb);
pcb = pcb->next;
}
}
void dbg_lwip_tcp_rxtx_show(void)
{
printf("TBC\n");
}
void dbg_lwip_udp_rxtx_show(void)
{
printf("TBC\n");
}

View file

@ -0,0 +1,24 @@
// 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 _LWIP_DEBUG_H
#define _LWIP_DEBUG_H
void dbg_lwip_tcp_pcb_show(void);
void dbg_lwip_udp_pcb_show(void);
void dbg_lwip_tcp_rxtx_show(void);
void dbg_lwip_udp_rxtx_show(void);
#endif

View file

@ -34,6 +34,7 @@
#include <stdlib.h>
#include "esp_task.h"
#include "sdkconfig.h"
/* Enable all Espressif-only options */
#define LWIP_ESP8266
@ -404,8 +405,9 @@ extern unsigned char misc_prof_get_tcp_snd_buf(void);
/**
* SO_REUSE==1: Enable SO_REUSEADDR option.
* This option is set via menuconfig.
*/
#define SO_REUSE 1
#define SO_REUSE CONFIG_LWIP_SO_REUSE
/*
----------------------------------------

View file

@ -302,7 +302,7 @@ zconf.lex.c: zconf.l
zconf.hash.c: zconf.gperf
# strip CRs on Windows systems where gperf will otherwise barf on them
sed -E "s/\r//" zconf.gperf | gperf -t --output-file zconf.hash.c -a -C -E -g -k '1,3,$$' -p -t
sed -E "s/\\x0D$$//" zconf.gperf | gperf -t --output-file zconf.hash.c -a -C -E -g -k '1,3,$$' -p -t
zconf.tab.c: zconf.y
bison -t -l -p zconf -o zconf.tab.c zconf.y