mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 04:34:31 +02:00
Merge branch 'feature/check_section_references' into 'master'
ci: add script to check section references See merge request espressif/esp-idf!9513
This commit is contained in:
@@ -86,6 +86,10 @@ elseif(CONFIG_COMPILER_STACK_CHECK_MODE_ALL)
|
||||
list(APPEND compile_options "-fstack-protector-all")
|
||||
endif()
|
||||
|
||||
if(CONFIG_COMPILER_DUMP_RTL_FILES)
|
||||
list(APPEND compile_options "-fdump-rtl-expand")
|
||||
endif()
|
||||
|
||||
list(APPEND link_options "-fno-lto")
|
||||
|
||||
idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND)
|
||||
|
6
Kconfig
6
Kconfig
@@ -335,6 +335,12 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
Enable this option if using GCC 6 or newer, and wanting to disable warnings which don't appear with
|
||||
GCC 5.
|
||||
|
||||
config COMPILER_DUMP_RTL_FILES
|
||||
bool "Dump RTL files during compilation"
|
||||
help
|
||||
If enabled, RTL files will be produced during compilation. These files
|
||||
can be used by other tools, for example to calculate call graphs.
|
||||
|
||||
|
||||
endmenu # Compiler Options
|
||||
|
||||
|
@@ -38,14 +38,15 @@ SECTIONS
|
||||
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
|
||||
*liblog.a:(.literal .text .literal.* .text.*)
|
||||
*libgcc.a:(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_clock.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_common.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_clock_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_common_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_efuse_esp32.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
@@ -53,8 +54,9 @@ SECTIONS
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_time.*(.literal .text .literal.* .text.*)
|
||||
*libefuse.a:*.*(.literal .text .literal.* .text.*)
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
|
@@ -25,13 +25,15 @@ SECTIONS
|
||||
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
|
||||
*liblog.a:(.literal .text .literal.* .text.*)
|
||||
*libgcc.a:(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_common.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_clock_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_common_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_efuse_esp32s2.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
@@ -39,7 +41,9 @@ SECTIONS
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_time.*(.literal .text .literal.* .text.*)
|
||||
*libefuse.a:*.*(.literal .text .literal.* .text.*)
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
|
@@ -40,7 +40,7 @@ SECTIONS
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*)
|
||||
*libefuse.a:*.*(.literal .text .literal.* .text.*)
|
||||
*(.fini.literal)
|
||||
|
@@ -1,6 +1,7 @@
|
||||
set(srcs
|
||||
"src/bootloader_clock.c"
|
||||
"src/bootloader_common.c"
|
||||
"src/bootloader_common_loader.c"
|
||||
"src/bootloader_clock_init.c"
|
||||
"src/bootloader_flash.c"
|
||||
"src/bootloader_mem.c"
|
||||
"src/bootloader_random.c"
|
||||
@@ -18,8 +19,10 @@ if(BOOTLOADER_BUILD)
|
||||
set(priv_requires micro-ecc spi_flash efuse)
|
||||
list(APPEND srcs
|
||||
"src/bootloader_init.c"
|
||||
"src/bootloader_clock_loader.c"
|
||||
"src/bootloader_console.c"
|
||||
"src/bootloader_console_loader.c"
|
||||
"src/bootloader_panic.c"
|
||||
"src/${IDF_TARGET}/bootloader_sha.c"
|
||||
"src/${IDF_TARGET}/flash_encrypt.c"
|
||||
"src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c"
|
||||
@@ -114,3 +117,7 @@ if(CONFIG_SECURE_SIGNED_APPS AND (CONFIG_SECURE_BOOT_V1_ENABLED OR CONFIG_SECURE
|
||||
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${secure_boot_verification_key}")
|
||||
endif()
|
||||
|
||||
if(BOOTLOADER_BUILD)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u abort")
|
||||
endif()
|
||||
|
@@ -16,7 +16,11 @@ COMPONENT_SRCDIRS += src/$(IDF_TARGET) # one sub-dir per chip
|
||||
endif
|
||||
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
COMPONENT_OBJEXCLUDE := src/bootloader_init.o
|
||||
COMPONENT_OBJEXCLUDE := src/bootloader_init.o \
|
||||
src/bootloader_panic.o \
|
||||
src/bootloader_clock_loader.o \
|
||||
src/bootloader_console.o \
|
||||
src/bootloader_console_loader.o
|
||||
endif
|
||||
|
||||
COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \
|
||||
|
@@ -75,11 +75,4 @@ void bootloader_clock_configure(void)
|
||||
#endif // CONFIG_ESP_SYSTEM_RTC_EXT_XTAL
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
int esp_clk_apb_freq(void)
|
||||
{
|
||||
return rtc_clk_apb_freq_get();
|
||||
}
|
||||
|
||||
#endif // BOOTLOADER_BUILD
|
24
components/bootloader_support/src/bootloader_clock_loader.c
Normal file
24
components/bootloader_support/src/bootloader_clock_loader.c
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2020 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 "soc/rtc.h"
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
int esp_clk_apb_freq(void)
|
||||
{
|
||||
return rtc_clk_apb_freq_get();
|
||||
}
|
||||
|
||||
#endif // BOOTLOADER_BUILD
|
@@ -41,21 +41,6 @@
|
||||
|
||||
static const char* TAG = "boot_comm";
|
||||
|
||||
uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return esp_rom_crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
|
||||
}
|
||||
|
||||
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return s->ota_seq == UINT32_MAX || s->ota_state == ESP_OTA_IMG_INVALID || s->ota_state == ESP_OTA_IMG_ABORTED;
|
||||
}
|
||||
|
||||
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return bootloader_common_ota_select_invalid(s) == false && s->crc == bootloader_common_ota_select_crc(s);
|
||||
}
|
||||
|
||||
esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio(uint32_t num_pin, uint32_t delay_sec)
|
||||
{
|
||||
esp_rom_gpio_pad_select_gpio(num_pin);
|
||||
@@ -190,43 +175,6 @@ esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t
|
||||
return bootloader_sha256_flash_contents(address, size, out_sha_256);
|
||||
}
|
||||
|
||||
int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, bool *valid_two_otadata, bool max)
|
||||
{
|
||||
if (two_otadata == NULL || valid_two_otadata == NULL) {
|
||||
return -1;
|
||||
}
|
||||
int active_otadata = -1;
|
||||
if (valid_two_otadata[0] && valid_two_otadata[1]) {
|
||||
int condition = (max == true) ? MAX(two_otadata[0].ota_seq, two_otadata[1].ota_seq) : MIN(two_otadata[0].ota_seq, two_otadata[1].ota_seq);
|
||||
if (condition == two_otadata[0].ota_seq) {
|
||||
active_otadata = 0;
|
||||
} else {
|
||||
active_otadata = 1;
|
||||
}
|
||||
ESP_LOGD(TAG, "Both OTA copies are valid");
|
||||
} else {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (valid_two_otadata[i]) {
|
||||
active_otadata = i;
|
||||
ESP_LOGD(TAG, "Only otadata[%d] is valid", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return active_otadata;
|
||||
}
|
||||
|
||||
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
if (two_otadata == NULL) {
|
||||
return -1;
|
||||
}
|
||||
bool valid_two_otadata[2];
|
||||
valid_two_otadata[0] = bootloader_common_ota_select_valid(&two_otadata[0]);
|
||||
valid_two_otadata[1] = bootloader_common_ota_select_valid(&two_otadata[1]);
|
||||
return bootloader_common_select_otadata(two_otadata, valid_two_otadata, true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc)
|
||||
{
|
||||
if (partition == NULL || app_desc == NULL || partition->offset == 0) {
|
||||
@@ -265,26 +213,6 @@ void bootloader_common_vddsdio_configure(void)
|
||||
}
|
||||
|
||||
|
||||
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
|
||||
if (chip_id != img_hdr->chip_id) {
|
||||
ESP_LOGE(TAG, "mismatch chip ID, expected %d, found %d", chip_id, img_hdr->chip_id);
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
uint8_t revision = bootloader_common_get_chip_revision();
|
||||
if (revision < img_hdr->min_chip_rev) {
|
||||
ESP_LOGE(TAG, "can't run on lower chip revision, expected %d, found %d", revision, img_hdr->min_chip_rev);
|
||||
err = ESP_FAIL;
|
||||
} else if (revision != img_hdr->min_chip_rev) {
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
ESP_LOGI(TAG, "chip revision: %d, min. %s chip revision: %d", revision, type == ESP_IMAGE_BOOTLOADER ? "bootloader" : "application", img_hdr->min_chip_rev);
|
||||
#endif
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
RESET_REASON bootloader_common_get_reset_reason(int cpu_no)
|
||||
{
|
||||
return rtc_get_reset_reason(cpu_no);
|
||||
|
99
components/bootloader_support/src/bootloader_common_loader.c
Normal file
99
components/bootloader_support/src/bootloader_common_loader.c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "string.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/spi_flash.h"
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#endif
|
||||
#include "esp_rom_crc.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "bootloader_flash.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "sys/param.h"
|
||||
|
||||
#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
|
||||
|
||||
static const char* TAG = "boot_comm";
|
||||
|
||||
uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return esp_rom_crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
|
||||
}
|
||||
|
||||
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return s->ota_seq == UINT32_MAX || s->ota_state == ESP_OTA_IMG_INVALID || s->ota_state == ESP_OTA_IMG_ABORTED;
|
||||
}
|
||||
|
||||
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return bootloader_common_ota_select_invalid(s) == false && s->crc == bootloader_common_ota_select_crc(s);
|
||||
}
|
||||
|
||||
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
if (two_otadata == NULL) {
|
||||
return -1;
|
||||
}
|
||||
bool valid_two_otadata[2];
|
||||
valid_two_otadata[0] = bootloader_common_ota_select_valid(&two_otadata[0]);
|
||||
valid_two_otadata[1] = bootloader_common_ota_select_valid(&two_otadata[1]);
|
||||
return bootloader_common_select_otadata(two_otadata, valid_two_otadata, true);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
|
||||
if (chip_id != img_hdr->chip_id) {
|
||||
ESP_LOGE(TAG, "mismatch chip ID, expected %d, found %d", chip_id, img_hdr->chip_id);
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
uint8_t revision = bootloader_common_get_chip_revision();
|
||||
if (revision < img_hdr->min_chip_rev) {
|
||||
ESP_LOGE(TAG, "can't run on lower chip revision, expected %d, found %d", revision, img_hdr->min_chip_rev);
|
||||
err = ESP_FAIL;
|
||||
} else if (revision != img_hdr->min_chip_rev) {
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
ESP_LOGI(TAG, "chip revision: %d, min. %s chip revision: %d", revision, type == ESP_IMAGE_BOOTLOADER ? "bootloader" : "application", img_hdr->min_chip_rev);
|
||||
#endif
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, bool *valid_two_otadata, bool max)
|
||||
{
|
||||
if (two_otadata == NULL || valid_two_otadata == NULL) {
|
||||
return -1;
|
||||
}
|
||||
int active_otadata = -1;
|
||||
if (valid_two_otadata[0] && valid_two_otadata[1]) {
|
||||
int condition = (max == true) ? MAX(two_otadata[0].ota_seq, two_otadata[1].ota_seq) : MIN(two_otadata[0].ota_seq, two_otadata[1].ota_seq);
|
||||
if (condition == two_otadata[0].ota_seq) {
|
||||
active_otadata = 0;
|
||||
} else {
|
||||
active_otadata = 1;
|
||||
}
|
||||
ESP_LOGD(TAG, "Both OTA copies are valid");
|
||||
} else {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (valid_two_otadata[i]) {
|
||||
active_otadata = i;
|
||||
ESP_LOGD(TAG, "Only otadata[%d] is valid", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return active_otadata;
|
||||
}
|
||||
|
@@ -101,10 +101,3 @@ void bootloader_print_banner(void)
|
||||
ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER);
|
||||
ESP_LOGI(TAG, "compile time " __TIME__);
|
||||
}
|
||||
|
||||
void __assert_func(const char *file, int line, const char *func, const char *expr)
|
||||
{
|
||||
ESP_LOGE(TAG, "Assert failed in %s, %s:%d (%s)", func, file, line, expr);
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
38
components/bootloader_support/src/bootloader_panic.c
Normal file
38
components/bootloader_support/src/bootloader_panic.c
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2020 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 "esp_log.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
|
||||
void __assert_func(const char *file, int line, const char *func, const char *expr)
|
||||
{
|
||||
esp_rom_printf("Assert failed in %s, %s:%d (%s)\r\n", func, file, line, expr);
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
|
||||
esp_rom_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3);
|
||||
#endif
|
||||
if (esp_cpu_in_ocd_debug_mode()) {
|
||||
__asm__("break 0,0");
|
||||
}
|
||||
while (1) {
|
||||
}
|
||||
}
|
@@ -351,18 +351,6 @@ static void bootloader_check_wdt_reset(void)
|
||||
wdt_reset_cpu0_info_enable();
|
||||
}
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
|
||||
esp_rom_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3);
|
||||
#endif
|
||||
if (esp_cpu_in_ocd_debug_mode()) {
|
||||
__asm__("break 0,0");
|
||||
}
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t bootloader_init(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
@@ -46,7 +46,7 @@
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "boot.esp32s2";
|
||||
void bootloader_configure_spi_pins(int drv)
|
||||
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
|
||||
{
|
||||
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
|
||||
uint8_t wp_pin = esp_rom_efuse_get_flash_wp_gpio();
|
||||
@@ -276,18 +276,6 @@ static void bootloader_check_wdt_reset(void)
|
||||
wdt_reset_cpu0_info_enable();
|
||||
}
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
|
||||
esp_rom_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3);
|
||||
#endif
|
||||
if (esp_cpu_in_ocd_debug_mode()) {
|
||||
__asm__("break 0,0");
|
||||
}
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
|
||||
static void bootloader_super_wdt_auto_feed(void)
|
||||
{
|
||||
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN);
|
||||
|
418
tools/ci/check_callgraph.py
Executable file
418
tools/ci/check_callgraph.py
Executable file
@@ -0,0 +1,418 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Based on cally.py (https://github.com/chaudron/cally/), Copyright 2018, Eelco Chaudron
|
||||
# Copyright 2020 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.
|
||||
|
||||
import argparse
|
||||
from functools import partial
|
||||
import os
|
||||
import re
|
||||
|
||||
import elftools
|
||||
from elftools.elf import elffile
|
||||
|
||||
try:
|
||||
from typing import List, Optional, BinaryIO, Tuple, Generator, Dict, Callable
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
FUNCTION_REGEX = re.compile(
|
||||
r"^;; Function (?P<mangle>.*)\s+\((?P<function>\S+)(,.*)?\).*$"
|
||||
)
|
||||
CALL_REGEX = re.compile(r'^.*\(call.*"(?P<target>.*)".*$')
|
||||
SYMBOL_REF_REGEX = re.compile(r'^.*\(symbol_ref[^()]*\("(?P<target>.*)"\).*$')
|
||||
|
||||
|
||||
class RtlFunction(object):
|
||||
def __init__(self, name, rtl_filename, tu_filename):
|
||||
self.name = name
|
||||
self.rtl_filename = rtl_filename
|
||||
self.tu_filename = tu_filename
|
||||
self.calls = list() # type: List[str]
|
||||
self.refs = list() # type: List[str]
|
||||
self.sym = None
|
||||
|
||||
|
||||
class SectionAddressRange(object):
|
||||
def __init__(self, name, addr, size): # type: (str, int, int) -> None
|
||||
self.name = name
|
||||
self.low = addr
|
||||
self.high = addr + size
|
||||
|
||||
def __str__(self):
|
||||
return "{}: 0x{:08x} - 0x{:08x}".format(self.name, self.low, self.high)
|
||||
|
||||
def contains_address(self, addr):
|
||||
return self.low <= addr < self.high
|
||||
|
||||
|
||||
TARGET_SECTIONS = {
|
||||
"esp32": [
|
||||
SectionAddressRange(".rom.text", 0x40000000, 0x70000),
|
||||
SectionAddressRange(".rom.rodata", 0x3ff96000, 0x9018)
|
||||
],
|
||||
"esp32s2": [
|
||||
SectionAddressRange(".rom.text", 0x40000000, 0x1bed0),
|
||||
SectionAddressRange(".rom.rodata", 0x3ffac600, 0x392c)
|
||||
],
|
||||
"esp32s3": [
|
||||
SectionAddressRange(".rom.text", 0x40000000, 0x568d0),
|
||||
SectionAddressRange(".rom.rodata", 0x3ff071c0, 0x8e30)
|
||||
]
|
||||
} # type: Dict[str, List[SectionAddressRange]]
|
||||
|
||||
|
||||
class Symbol(object):
|
||||
def __init__(self, name, addr, local, filename, section): # type: (str, int, bool, Optional[str], Optional[str]) -> None
|
||||
self.name = name
|
||||
self.addr = addr
|
||||
self.local = local
|
||||
self.filename = filename
|
||||
self.section = section
|
||||
self.refers_to = list() # type: List[Symbol]
|
||||
self.referred_from = list() # type: List[Symbol]
|
||||
|
||||
def __str__(self):
|
||||
return "{} @0x{:08x} [{}]{} {}".format(
|
||||
self.name,
|
||||
self.addr,
|
||||
self.section or "unknown",
|
||||
" (local)" if self.local else "",
|
||||
self.filename
|
||||
)
|
||||
|
||||
|
||||
class Reference(object):
|
||||
def __init__(self, from_sym, to_sym): # type: (Symbol, Symbol) -> None
|
||||
self.from_sym = from_sym
|
||||
self.to_sym = to_sym
|
||||
|
||||
def __str__(self):
|
||||
return "{} @0x{:08x} ({}) -> {} @0x{:08x} ({})".format(
|
||||
self.from_sym.name,
|
||||
self.from_sym.addr,
|
||||
self.from_sym.section,
|
||||
self.to_sym.name,
|
||||
self.to_sym.addr,
|
||||
self.to_sym.section
|
||||
)
|
||||
|
||||
|
||||
class ElfInfo(object):
|
||||
def __init__(self, elf_file): # type: (BinaryIO) -> None
|
||||
self.elf_file = elf_file
|
||||
self.elf_obj = elffile.ELFFile(self.elf_file)
|
||||
self.section_ranges = self._load_sections()
|
||||
self.symbols = self._load_symbols()
|
||||
|
||||
def _load_symbols(self): # type: () -> List[Symbol]
|
||||
symbols = []
|
||||
for s in self.elf_obj.iter_sections():
|
||||
if not isinstance(s, elftools.elf.sections.SymbolTableSection):
|
||||
continue
|
||||
filename = None
|
||||
for sym in s.iter_symbols():
|
||||
sym_type = sym.entry["st_info"]["type"]
|
||||
if sym_type == "STT_FILE":
|
||||
filename = sym.name
|
||||
if sym_type in ["STT_NOTYPE", "STT_FUNC", "STT_OBJECT"]:
|
||||
local = sym.entry["st_info"]["bind"] == "STB_LOCAL"
|
||||
addr = sym.entry["st_value"]
|
||||
symbols.append(
|
||||
Symbol(
|
||||
sym.name,
|
||||
addr,
|
||||
local,
|
||||
filename if local else None,
|
||||
self.section_for_addr(addr),
|
||||
)
|
||||
)
|
||||
return symbols
|
||||
|
||||
def _load_sections(self): # type: () -> List[SectionAddressRange]
|
||||
result = []
|
||||
for segment in self.elf_obj.iter_segments():
|
||||
if segment["p_type"] == "PT_LOAD":
|
||||
for section in self.elf_obj.iter_sections():
|
||||
if not segment.section_in_segment(section):
|
||||
continue
|
||||
result.append(
|
||||
SectionAddressRange(
|
||||
section.name, section["sh_addr"], section["sh_size"]
|
||||
)
|
||||
)
|
||||
|
||||
target = os.environ.get("IDF_TARGET")
|
||||
if target in TARGET_SECTIONS:
|
||||
result += TARGET_SECTIONS[target]
|
||||
|
||||
return result
|
||||
|
||||
def symbols_by_name(self, name): # type: (str) -> List[Symbol]
|
||||
res = []
|
||||
for sym in self.symbols:
|
||||
if sym.name == name:
|
||||
res.append(sym)
|
||||
return res
|
||||
|
||||
def section_for_addr(self, sym_addr): # type: (int) -> Optional[str]
|
||||
for sar in self.section_ranges:
|
||||
if sar.contains_address(sym_addr):
|
||||
return sar.name
|
||||
return None
|
||||
|
||||
|
||||
def load_rtl_file(rtl_filename, tu_filename, functions): # type: (str, str, List[RtlFunction]) -> None
|
||||
last_function = None # type: Optional[RtlFunction]
|
||||
for line in open(rtl_filename):
|
||||
# Find function definition
|
||||
match = re.match(FUNCTION_REGEX, line)
|
||||
if match:
|
||||
function_name = match.group("function")
|
||||
last_function = RtlFunction(function_name, rtl_filename, tu_filename)
|
||||
functions.append(last_function)
|
||||
continue
|
||||
|
||||
if last_function:
|
||||
# Find direct function calls
|
||||
match = re.match(CALL_REGEX, line)
|
||||
if match:
|
||||
target = match.group("target")
|
||||
if target not in last_function.calls:
|
||||
last_function.calls.append(target)
|
||||
continue
|
||||
|
||||
# Find symbol references
|
||||
match = re.match(SYMBOL_REF_REGEX, line)
|
||||
if match:
|
||||
target = match.group("target")
|
||||
if target not in last_function.refs:
|
||||
last_function.refs.append(target)
|
||||
continue
|
||||
|
||||
|
||||
def rtl_filename_matches_sym_filename(rtl_filename, symbol_filename): # type: (str, str) -> bool
|
||||
# Symbol file names (from ELF debug info) are short source file names, without path: "cpu_start.c".
|
||||
# RTL file names are paths relative to the build directory, e.g.:
|
||||
# "build/esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/cpu_start.c.234r.expand"
|
||||
#
|
||||
# The check below may give a false positive if there are two files with the same name in
|
||||
# different directories. This doesn't seem to happen in IDF now, but if it does happen,
|
||||
# an assert in find_symbol_by_rtl_func should catch this.
|
||||
#
|
||||
# If this becomes and issue, consider also loading the .map file and using it to figure out
|
||||
# which object file was used as the source of each symbol. Names of the object files and RTL files
|
||||
# should be much easier to match.
|
||||
return os.path.basename(rtl_filename).startswith(symbol_filename)
|
||||
|
||||
|
||||
class SymbolNotFound(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def find_symbol_by_name(name, elfinfo, local_func_matcher): # type: (str, ElfInfo, Callable[[Symbol], bool]) -> Optional[Symbol]
|
||||
"""
|
||||
Find an ELF symbol for the given name.
|
||||
local_func_matcher is a callback function which checks is the candidate local symbol is suitable.
|
||||
"""
|
||||
syms = elfinfo.symbols_by_name(name)
|
||||
if not syms:
|
||||
return None
|
||||
if len(syms) == 1:
|
||||
return syms[0]
|
||||
else:
|
||||
# There are multiple symbols with a given name. Find the best fit.
|
||||
local_candidate = None
|
||||
global_candidate = None
|
||||
for sym in syms:
|
||||
if not sym.local:
|
||||
assert not global_candidate # can't have two global symbols with the same name
|
||||
global_candidate = sym
|
||||
elif local_func_matcher(sym):
|
||||
assert not local_candidate # can't have two symbols with the same name in a single file
|
||||
local_candidate = sym
|
||||
|
||||
# If two symbols with the same name are defined, a global and a local one,
|
||||
# prefer the local symbol as the reference target.
|
||||
return local_candidate or global_candidate
|
||||
|
||||
|
||||
def match_local_source_func(rtl_filename, sym): # type: (str, Symbol) -> bool
|
||||
"""
|
||||
Helper for match_rtl_funcs_to_symbols, checks if local symbol sym is a good candidate for the
|
||||
reference source (caller), based on the RTL file name.
|
||||
"""
|
||||
assert sym.filename # should be set for local functions
|
||||
return rtl_filename_matches_sym_filename(rtl_filename, sym.filename)
|
||||
|
||||
|
||||
def match_local_target_func(rtl_filename, sym_from, sym): # type: (str, Symbol, Symbol) -> bool
|
||||
"""
|
||||
Helper for match_rtl_funcs_to_symbols, checks if local symbol sym is a good candidate for the
|
||||
reference target (callee or referenced data), based on RTL filename of the source symbol
|
||||
and the source symbol itself.
|
||||
"""
|
||||
assert sym.filename # should be set for local functions
|
||||
if sym_from.local:
|
||||
# local symbol referencing another local symbol
|
||||
return sym_from.filename == sym.filename
|
||||
else:
|
||||
# global symbol referencing a local symbol;
|
||||
# source filename is not known, use RTL filename as a hint
|
||||
return rtl_filename_matches_sym_filename(rtl_filename, sym.filename)
|
||||
|
||||
|
||||
def match_rtl_funcs_to_symbols(rtl_functions, elfinfo): # type: (List[RtlFunction], ElfInfo) -> Tuple[List[Symbol], List[Reference]]
|
||||
symbols = [] # type: List[Symbol]
|
||||
refs = [] # type: List[Reference]
|
||||
|
||||
# General idea:
|
||||
# - iterate over RTL functions.
|
||||
# - for each RTL function, find the corresponding symbol
|
||||
# - iterate over the functions and variables referenced from this RTL function
|
||||
# - find symbols corresponding to the references
|
||||
# - record every pair (sym_from, sym_to) as a Reference object
|
||||
|
||||
for source_rtl_func in rtl_functions:
|
||||
maybe_sym_from = find_symbol_by_name(source_rtl_func.name, elfinfo, partial(match_local_source_func, source_rtl_func.rtl_filename))
|
||||
if maybe_sym_from is None:
|
||||
# RTL references a symbol, but the symbol is not defined in the generated object file.
|
||||
# This means that the symbol was likely removed (or not included) at link time.
|
||||
# There is nothing we can do to check section placement in this case.
|
||||
continue
|
||||
sym_from = maybe_sym_from
|
||||
|
||||
if sym_from not in symbols:
|
||||
symbols.append(sym_from)
|
||||
|
||||
for target_rtl_func_name in source_rtl_func.calls + source_rtl_func.refs:
|
||||
if "*.LC" in target_rtl_func_name: # skip local labels
|
||||
continue
|
||||
|
||||
maybe_sym_to = find_symbol_by_name(target_rtl_func_name, elfinfo, partial(match_local_target_func, source_rtl_func.rtl_filename, sym_from))
|
||||
if not maybe_sym_to:
|
||||
# This may happen for a extern reference in the RTL file, if the reference was later removed
|
||||
# by one of the optimization passes, and the external definition got garbage-collected.
|
||||
# TODO: consider adding some sanity check that we are here not because of some bug in
|
||||
# find_symbol_by_name?..
|
||||
continue
|
||||
sym_to = maybe_sym_to
|
||||
|
||||
sym_from.refers_to.append(sym_to)
|
||||
sym_to.referred_from.append(sym_from)
|
||||
refs.append(Reference(sym_from, sym_to))
|
||||
if sym_to not in symbols:
|
||||
symbols.append(sym_to)
|
||||
|
||||
return symbols, refs
|
||||
|
||||
|
||||
def get_symbols_and_refs(rtl_list, elf_file): # type: (List[str], BinaryIO) -> Tuple[List[Symbol], List[Reference]]
|
||||
elfinfo = ElfInfo(elf_file)
|
||||
|
||||
rtl_functions = [] # type: List[RtlFunction]
|
||||
for file_name in rtl_list:
|
||||
load_rtl_file(file_name, file_name, rtl_functions)
|
||||
|
||||
return match_rtl_funcs_to_symbols(rtl_functions, elfinfo)
|
||||
|
||||
|
||||
def list_refs_from_to_sections(refs, from_sections, to_sections): # type: (List[Reference], List[str], List[str]) -> int
|
||||
found = 0
|
||||
for ref in refs:
|
||||
if (not from_sections or ref.from_sym.section in from_sections) and \
|
||||
(not to_sections or ref.to_sym.section in to_sections):
|
||||
print(str(ref))
|
||||
found += 1
|
||||
return found
|
||||
|
||||
|
||||
def find_files_recursive(root_path, ext): # type: (str, str) -> Generator[str, None, None]
|
||||
for root, _, files in os.walk(root_path):
|
||||
for basename in files:
|
||||
if basename.endswith(ext):
|
||||
filename = os.path.join(root, basename)
|
||||
yield filename
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"--rtl-list",
|
||||
help="File with the list of RTL files",
|
||||
type=argparse.FileType("r"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--rtl-dir", help="Directory where to look for RTL files, recursively"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--elf-file",
|
||||
required=True,
|
||||
help="Program ELF file",
|
||||
type=argparse.FileType("rb"),
|
||||
)
|
||||
action_sub = parser.add_subparsers(dest="action")
|
||||
find_refs_parser = action_sub.add_parser(
|
||||
"find-refs",
|
||||
help="List the references coming from a given list of source sections"
|
||||
"to a given list of target sections.",
|
||||
)
|
||||
find_refs_parser.add_argument(
|
||||
"--from-sections", help="comma-separated list of source sections"
|
||||
)
|
||||
find_refs_parser.add_argument(
|
||||
"--to-sections", help="comma-separated list of target sections"
|
||||
)
|
||||
find_refs_parser.add_argument(
|
||||
"--exit-code",
|
||||
action="store_true",
|
||||
help="If set, exits with non-zero code when any references found",
|
||||
)
|
||||
action_sub.add_parser(
|
||||
"all-refs",
|
||||
help="Print the list of all references",
|
||||
)
|
||||
|
||||
parser.parse_args()
|
||||
args = parser.parse_args()
|
||||
if args.rtl_list:
|
||||
with open(args.rtl_list, "r") as rtl_list_file:
|
||||
rtl_list = [line.strip for line in rtl_list_file]
|
||||
else:
|
||||
if not args.rtl_dir:
|
||||
raise RuntimeError("Either --rtl-list or --rtl-dir must be specified")
|
||||
rtl_list = list(find_files_recursive(args.rtl_dir, ".expand"))
|
||||
|
||||
if not rtl_list:
|
||||
raise RuntimeError("No RTL files specified")
|
||||
|
||||
_, refs = get_symbols_and_refs(rtl_list, args.elf_file)
|
||||
|
||||
if args.action == "find-refs":
|
||||
from_sections = args.from_sections.split(",") if args.from_sections else []
|
||||
to_sections = args.to_sections.split(",") if args.to_sections else []
|
||||
found = list_refs_from_to_sections(
|
||||
refs, from_sections, to_sections
|
||||
)
|
||||
if args.exit_code and found:
|
||||
raise SystemExit(1)
|
||||
elif args.action == "all-refs":
|
||||
for r in refs:
|
||||
print(str(r))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@@ -39,6 +39,7 @@ tools/ci/build_template_app.sh
|
||||
tools/ci/check-executable.sh
|
||||
tools/ci/check-line-endings.sh
|
||||
tools/ci/check_build_warnings.py
|
||||
tools/ci/check_callgraph.py
|
||||
tools/ci/check_deprecated_kconfigs.py
|
||||
tools/ci/check_examples_cmake_make.py
|
||||
tools/ci/check_examples_rom_header.sh
|
||||
|
17
tools/test_apps/system/bootloader_sections/CMakeLists.txt
Normal file
17
tools/test_apps/system/bootloader_sections/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(test_build)
|
||||
|
||||
add_custom_target(check_bootloader_sections ALL
|
||||
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
|
||||
--rtl-dir ${CMAKE_BINARY_DIR}/bootloader
|
||||
--elf-file ${CMAKE_BINARY_DIR}/bootloader/bootloader.elf
|
||||
find-refs
|
||||
--from-sections=.iram_loader.text
|
||||
--to-sections=.iram.text
|
||||
--exit-code
|
||||
DEPENDS bootloader
|
||||
)
|
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "test_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
|
||||
|
@@ -0,0 +1,3 @@
|
||||
void app_main(void)
|
||||
{
|
||||
}
|
@@ -0,0 +1,2 @@
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y
|
@@ -0,0 +1 @@
|
||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
Reference in New Issue
Block a user