diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 74028b6e9..394bcc1bd 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -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 diff --git a/components/bootloader/Makefile.projbuild b/components/bootloader/Makefile.projbuild index cf8b05673..d45cf144e 100644 --- a/components/bootloader/Makefile.projbuild +++ b/components/bootloader/Makefile.projbuild @@ -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 diff --git a/components/bootloader/src/Makefile b/components/bootloader/src/Makefile index b6b0c1af0..f30e314a5 100644 --- a/components/bootloader/src/Makefile +++ b/components/bootloader/src/Makefile @@ -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 diff --git a/components/bootloader/src/main/bootloader_log.h b/components/bootloader/src/main/bootloader_log.h deleted file mode 100644 index 1f7ec62ad..000000000 --- a/components/bootloader/src/main/bootloader_log.h +++ /dev/null @@ -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__ */ diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index f53598527..6b3298c29 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -16,6 +16,7 @@ #include #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 } diff --git a/components/bootloader/src/main/component.mk b/components/bootloader/src/main/component.mk index 1671095f1..8c8ea4cb6 100644 --- a/components/bootloader/src/main/component.mk +++ b/components/bootloader/src/main/component.mk @@ -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 diff --git a/components/bootloader/src/main/flash_encrypt.c b/components/bootloader/src/main/flash_encrypt.c index 51f6e1c55..26e66aa03 100644 --- a/components/bootloader/src/main/flash_encrypt.c +++ b/components/bootloader/src/main/flash_encrypt.c @@ -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; } } diff --git a/components/bootloader/src/main/secure_boot.c b/components/bootloader/src/main/secure_boot.c index 15afb1a61..3dfdbd141 100644 --- a/components/bootloader/src/main/secure_boot.c +++ b/components/bootloader/src/main/secure_boot.c @@ -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; } diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index d895e908e..cb31fbd46 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -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,130 @@ #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) +{ + 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(); } diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index e816175b9..5b3ec33db 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -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 (regStartto) { //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 ); } diff --git a/components/esp32/include/soc/cpu.h b/components/esp32/include/soc/cpu.h index fdcf62190..b45f742ce 100644 --- a/components/esp32/include/soc/cpu.h +++ b/components/esp32/include/soc/cpu.h @@ -33,4 +33,39 @@ 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); +} + + #endif diff --git a/components/log/Kconfig b/components/log/Kconfig new file mode 100644 index 000000000..1627ea183 --- /dev/null +++ b/components/log/Kconfig @@ -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 diff --git a/components/log/component.mk b/components/log/component.mk new file mode 100755 index 000000000..ef497a7ec --- /dev/null +++ b/components/log/component.mk @@ -0,0 +1,3 @@ +COMPONENT_ADD_INCLUDEDIRS := include + +include $(IDF_PATH)/make/component_common.mk diff --git a/components/log/include/esp_log.h b/components/log/include/esp_log.h new file mode 100644 index 000000000..8ca6e241d --- /dev/null +++ b/components/log/include/esp_log.h @@ -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 +#include +#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__ */ diff --git a/components/log/log.c b/components/log/log.c new file mode 100644 index 000000000..aae12a773 --- /dev/null +++ b/components/log/log.c @@ -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 +#include +#include +#include +#endif + +#include "esp_attr.h" +#include "xtensa/hal.h" +#include "soc/soc.h" +#include +#include +#include +#include +#include +#include +#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