Support ELF files loadable with gdb

This commit is contained in:
Roland Dobai 2019-07-22 16:04:03 +02:00 committed by bot
parent 6a9288bc73
commit 5a916ce126
24 changed files with 387 additions and 55 deletions

View File

@ -66,7 +66,7 @@ variables:
rm -rf "$CUSTOM_TOOLCHAIN_PATH" rm -rf "$CUSTOM_TOOLCHAIN_PATH"
.setup_tools_unless_target_test: &setup_tools_unless_target_test | .setup_tools_unless_target_test: &setup_tools_unless_target_test |
if [ "$CI_JOB_STAGE" != "target_test" ]; then if [[ "$SETUP_TOOLS" == "1" || "$CI_JOB_STAGE" != "target_test" ]]; then
tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1 tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1
fi fi

77
Kconfig
View File

@ -68,6 +68,83 @@ mainmenu "Espressif IoT Development Framework Configuration"
endmenu # SDK tool configuration endmenu # SDK tool configuration
menu "Build type"
choice APP_BUILD_TYPE
prompt "Application build type"
default APP_BUILD_TYPE_APP_2NDBOOT
help
Select the way the application is built.
By default, the application is built as a binary file in a format compatible with
the ESP32 bootloader. In addition to this application, 2nd stage bootloader is
also built. Application and bootloader binaries can be written into flash and
loaded/executed from there.
Another option, useful for only very small and limited applications, is to only link
the .elf file of the application, such that it can be loaded directly into RAM over
JTAG. Note that since IRAM and DRAM sizes are very limited, it is not possible to
build any complex application this way. However for kinds of testing and debugging,
this option may provide faster iterations, since the application does not need to be
written into flash.
Note that at the moment, ESP-IDF does not contain all the startup code required to
initialize the CPUs and ROM memory (data/bss). Therefore it is necessary to execute
a bit of ROM code prior to executing the application. A gdbinit file may look as follows:
# Connect to a running instance of OpenOCD
target remote :3333
# Reset and halt the target
mon reset halt
# Run to a specific point in ROM code,
# where most of initialization is complete.
thb *0x40007901
c
# Load the application into RAM
load
# Run till app_main
tb app_main
c
Execute this gdbinit file as follows:
xtensa-esp32-elf-gdb build/app-name.elf -x gdbinit
Recommended sdkconfig.defaults for building loadable ELF files is as follows.
CONFIG_APP_BUILD_TYPE_ELF_RAM is required, other options help reduce application
memory footprint.
CONFIG_APP_BUILD_TYPE_ELF_RAM=y
CONFIG_VFS_SUPPORT_TERMIOS=
CONFIG_NEWLIB_NANO_FORMAT=y
CONFIG_ESP32_PANIC_PRINT_HALT=y
CONFIG_ESP32_DEBUG_STUBS_ENABLE=
CONFIG_ESP_ERR_TO_NAME_LOOKUP=
config APP_BUILD_TYPE_APP_2NDBOOT
bool
prompt "Default (binary application + 2nd stage bootloader)"
select APP_BUILD_GENERATE_BINARIES
select APP_BUILD_BOOTLOADER
select APP_BUILD_USE_FLASH_SECTIONS
config APP_BUILD_TYPE_ELF_RAM
bool
prompt "ELF file, loadable into RAM (EXPERIMENTAL))"
endchoice # APP_BUILD_TYPE
# Hidden options, set according to the choice above
config APP_BUILD_GENERATE_BINARIES
bool # Whether to generate .bin files or not
config APP_BUILD_BOOTLOADER
bool # Whether to build the bootloader
config APP_BUILD_USE_FLASH_SECTIONS
bool # Whether to place code/data into memory-mapped flash sections
endmenu # Build type
source "$COMPONENT_KCONFIGS_PROJBUILD" source "$COMPONENT_KCONFIGS_PROJBUILD"
menu "Compiler options" menu "Compiler options"

View File

@ -1,7 +1,7 @@
idf_component_register(PRIV_REQUIRES partition_table) idf_component_register(PRIV_REQUIRES partition_table)
# Do not generate flash file when building bootloader or is in early expansion of the build # Do not generate flash file when building bootloader or is in early expansion of the build
if(BOOTLOADER_BUILD) if(BOOTLOADER_BUILD OR NOT CONFIG_APP_BUILD_BOOTLOADER)
return() return()
endif() endif()

View File

@ -1,7 +1,7 @@
set(BOOTLOADER_OFFSET 0x1000) set(BOOTLOADER_OFFSET 0x1000)
# Do not generate flash file when building bootloader # Do not generate flash file when building bootloader
if(BOOTLOADER_BUILD) if(BOOTLOADER_BUILD OR NOT CONFIG_APP_BUILD_BOOTLOADER)
return() return()
endif() endif()

View File

@ -738,6 +738,11 @@ menu "ESP32-specific"
Enabling this setting adds approximately 1KB to the app's IRAM usage. Enabling this setting adds approximately 1KB to the app's IRAM usage.
config ESP32_APP_INIT_CLK
bool
default y if ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS
default y if APP_BUILD_TYPE_ELF_RAM
config ESP32_RTCDATA_IN_FAST_MEM config ESP32_RTCDATA_IN_FAST_MEM
bool "Place RTC_DATA_ATTR and RTC_RODATA_ATTR variables into RTC fast memory segment" bool "Place RTC_DATA_ATTR and RTC_RODATA_ATTR variables into RTC fast memory segment"
default n default n

View File

@ -75,7 +75,7 @@ void esp_clk_init(void)
rtc_config_t cfg = RTC_CONFIG_DEFAULT(); rtc_config_t cfg = RTC_CONFIG_DEFAULT();
rtc_init(cfg); rtc_init(cfg);
#ifdef CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS #if (CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS || CONFIG_ESP32_APP_INIT_CLK)
/* Check the bootloader set the XTAL frequency. /* Check the bootloader set the XTAL frequency.
Bootloaders pre-v2.1 don't do this. Bootloaders pre-v2.1 don't do this.
@ -293,6 +293,8 @@ void esp_perip_clk_init(void)
DPORT_I2S1_CLK_EN | DPORT_I2S1_CLK_EN |
DPORT_SPI_DMA_CLK_EN; DPORT_SPI_DMA_CLK_EN;
common_perip_clk &= ~DPORT_SPI01_CLK_EN;
#if CONFIG_SPIRAM_SPEED_80M #if CONFIG_SPIRAM_SPEED_80M
//80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in //80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in
//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs' //a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs'

View File

@ -72,6 +72,11 @@
#include "esp_efuse.h" #include "esp_efuse.h"
#include "bootloader_flash_config.h" #include "bootloader_flash_config.h"
#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM
#include "esp32/rom/efuse.h"
#include "esp32/rom/spi_flash.h"
#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM
#define STRINGIFY(s) STRINGIFY2(s) #define STRINGIFY(s) STRINGIFY2(s)
#define STRINGIFY2(s) #s #define STRINGIFY2(s) #s
@ -391,6 +396,32 @@ void start_cpu0_default(void)
#ifndef CONFIG_FREERTOS_UNICORE #ifndef CONFIG_FREERTOS_UNICORE
esp_dport_access_int_init(); esp_dport_access_int_init();
#endif #endif
bootloader_flash_update_id();
#if !CONFIG_SPIRAM_BOOT_INIT
// Read the application binary image header. This will also decrypt the header if the image is encrypted.
esp_image_header_t fhdr = {0};
#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM
fhdr.spi_mode = ESP_IMAGE_SPI_MODE_DIO;
fhdr.spi_speed = ESP_IMAGE_SPI_SPEED_40M;
fhdr.spi_size = ESP_IMAGE_FLASH_SIZE_4MB;
extern void esp_rom_spiflash_attach(uint32_t, bool);
esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false);
esp_rom_spiflash_unlock();
#else
// This assumes that DROM is the first segment in the application binary, i.e. that we can read
// the binary header through cache by accessing SOC_DROM_LOW address.
memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr));
#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM
// If psram is uninitialized, we need to improve some flash configuration.
bootloader_flash_clock_config(&fhdr);
bootloader_flash_gpio_config(&fhdr);
bootloader_flash_dummy_config(&fhdr);
bootloader_flash_cs_timing_config();
#endif //!CONFIG_SPIRAM_BOOT_INIT
spi_flash_init(); spi_flash_init();
/* init default OS-aware flash access critical section */ /* init default OS-aware flash access critical section */
spi_flash_guard_set(&g_flash_guard_default_ops); spi_flash_guard_set(&g_flash_guard_default_ops);
@ -424,20 +455,6 @@ void start_cpu0_default(void)
esp_coex_adapter_register(&g_coex_adapter_funcs); esp_coex_adapter_register(&g_coex_adapter_funcs);
#endif #endif
bootloader_flash_update_id();
#if !CONFIG_SPIRAM_BOOT_INIT
// Read the application binary image header. This will also decrypt the header if the image is encrypted.
esp_image_header_t fhdr = {0};
// This assumes that DROM is the first segment in the application binary, i.e. that we can read
// the binary header through cache by accessing SOC_DROM_LOW address.
memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr));
// If psram is uninitialized, we need to improve some flash configuration.
bootloader_flash_clock_config(&fhdr);
bootloader_flash_gpio_config(&fhdr);
bootloader_flash_dummy_config(&fhdr);
bootloader_flash_cs_timing_config();
#endif
portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_STACK, NULL,
ESP_TASK_MAIN_PRIO, NULL, 0); ESP_TASK_MAIN_PRIO, NULL, 0);

View File

@ -49,6 +49,7 @@ MEMORY
/* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */ /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
iram0_0_seg (RX) : org = 0x40080000, len = 0x20000 iram0_0_seg (RX) : org = 0x40080000, len = 0x20000
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Even though the segment name is iram, it is actually mapped to flash /* Even though the segment name is iram, it is actually mapped to flash
*/ */
iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000-0x18 iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000-0x18
@ -58,6 +59,7 @@ MEMORY
which is flashed to the chip has a 0x18 byte file header. Setting this offset makes it simple to meet the flash which is flashed to the chip has a 0x18 byte file header. Setting this offset makes it simple to meet the flash
cache MMU's constraint that (paddr % 64KB == vaddr % 64KB).) cache MMU's constraint that (paddr % 64KB == vaddr % 64KB).)
*/ */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Shared data RAM, excluding memory reserved for ROM bss/data/stack. /* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
@ -72,10 +74,12 @@ MEMORY
dram0_0_seg (RW) : org = 0x3FFB0000 + CONFIG_BT_RESERVE_DRAM, dram0_0_seg (RW) : org = 0x3FFB0000 + CONFIG_BT_RESERVE_DRAM,
len = DRAM0_0_SEG_LEN - CONFIG_BT_RESERVE_DRAM len = DRAM0_0_SEG_LEN - CONFIG_BT_RESERVE_DRAM
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped constant data */ /* Flash mapped constant data */
drom0_0_seg (R) : org = 0x3F400018, len = 0x400000-0x18 drom0_0_seg (R) : org = 0x3F400018, len = 0x400000-0x18
/* (See iram0_2_seg for meaning of 0x18 offset in the above.) */ /* (See iram0_2_seg for meaning of 0x18 offset in the above.) */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* RTC fast memory (executable). Persists over deep sleep. /* RTC fast memory (executable). Persists over deep sleep.
*/ */
@ -116,3 +120,15 @@ REGION_ALIAS("rtc_data_location", rtc_slow_seg );
#else #else
REGION_ALIAS("rtc_data_location", rtc_data_seg ); REGION_ALIAS("rtc_data_location", rtc_data_seg );
#endif #endif
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_code_seg", iram0_2_seg);
#else
REGION_ALIAS("default_code_seg", iram0_0_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_rodata_seg", drom0_0_seg);
#else
REGION_ALIAS("default_rodata_seg", dram0_0_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS

View File

@ -161,12 +161,8 @@ SECTIONS
mapping[iram0_text] mapping[iram0_text]
_iram_text_end = ABSOLUTE(.); _iram_text_end = ABSOLUTE(.);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg } > iram0_0_seg
ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
"IRAM0 segment data does not fit.")
.dram0.data : .dram0.data :
{ {
_data_start = ABSOLUTE(.); _data_start = ABSOLUTE(.);
@ -312,7 +308,7 @@ SECTIONS
*(.tbss.*) *(.tbss.*)
_thread_local_end = ABSOLUTE(.); _thread_local_end = ABSOLUTE(.);
. = ALIGN(4); . = ALIGN(4);
} >drom0_0_seg } >default_rodata_seg
.flash.text : .flash.text :
{ {
@ -334,5 +330,25 @@ SECTIONS
the flash.text segment. the flash.text segment.
*/ */
_flash_cache_start = ABSOLUTE(0); _flash_cache_start = ABSOLUTE(0);
} >iram0_2_seg } >default_code_seg
/* Marks the end of IRAM code segment */
.iram0.text_end (NOLOAD) :
{
. = ALIGN (4);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg
/* Marks the end of data, bss and possibly rodata */
.dram0.heap_start (NOLOAD) :
{
. = ALIGN (8);
_heap_start = ABSOLUTE(.);
} > dram0_0_seg
} }
ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
"IRAM0 segment data does not fit.")
ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
"DRAM segment data does not fit.")

View File

@ -50,8 +50,12 @@ entries:
[scheme:default] [scheme:default]
entries: entries:
if APP_BUILD_USE_FLASH_SECTIONS = y:
text -> flash_text text -> flash_text
rodata -> flash_rodata rodata -> flash_rodata
else:
text -> iram0_text
rodata -> dram0_data
data -> dram0_data data -> dram0_data
bss -> dram0_bss bss -> dram0_bss
common -> dram0_bss common -> dram0_bss

View File

@ -450,7 +450,7 @@ static void esp_panic_dig_reset(void)
; ;
} }
} }
#endif #endif // CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
static void putEntry(uint32_t pc, uint32_t sp) static void putEntry(uint32_t pc, uint32_t sp)
{ {

View File

@ -8,6 +8,7 @@ PROVIDE ( esp_rom_spiflash_erase_area = 0x400631ac );
PROVIDE ( esp_rom_spiflash_erase_block = 0x40062c4c ); PROVIDE ( esp_rom_spiflash_erase_block = 0x40062c4c );
PROVIDE ( esp_rom_spiflash_erase_chip = 0x40062c14 ); PROVIDE ( esp_rom_spiflash_erase_chip = 0x40062c14 );
PROVIDE ( esp_rom_spiflash_erase_sector = 0x40062ccc ); PROVIDE ( esp_rom_spiflash_erase_sector = 0x40062ccc );
PROVIDE ( esp_rom_spiflash_attach = 0x40062a6c );
PROVIDE ( esp_rom_spiflash_lock = 0x400628f0 ); PROVIDE ( esp_rom_spiflash_lock = 0x400628f0 );
PROVIDE ( esp_rom_spiflash_read = 0x40062ed8 ); PROVIDE ( esp_rom_spiflash_read = 0x40062ed8 );
PROVIDE ( esp_rom_spiflash_config_readmode = 0x40062b64 ); /* SPIMasterReadModeCnfig */ PROVIDE ( esp_rom_spiflash_config_readmode = 0x40062b64 ); /* SPIMasterReadModeCnfig */

View File

@ -1,6 +1,6 @@
idf_component_register(REQUIRES bootloader) idf_component_register(REQUIRES bootloader)
if(NOT BOOTLOADER_BUILD) if(NOT BOOTLOADER_BUILD AND CONFIG_APP_BUILD_GENERATE_BINARIES)
string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_FLASH_OPTIONS}") string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_FLASH_OPTIONS}")
set(ESPTOOLPY_FLASH_PROJECT_OPTIONS set(ESPTOOLPY_FLASH_PROJECT_OPTIONS
"${ESPTOOLPY_FLASH_PROJECT_OPTIONS}" "${ESPTOOLPY_FLASH_PROJECT_OPTIONS}"

View File

@ -68,7 +68,11 @@ endif
APP_BIN_UNSIGNED ?= $(APP_BIN) APP_BIN_UNSIGNED ?= $(APP_BIN)
$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) | check_python_dependencies $(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) | check_python_dependencies
ifeq ("$(CONFIG_APP_BUILD_GENERATE_BINARIES)","y")
$(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $< $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
else
@echo "Skipping the BIN generation"
endif
ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
encrypted-flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies encrypted-flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies

View File

@ -78,6 +78,7 @@ set(PROJECT_BIN "${elf_name}.bin")
# #
# Add 'app.bin' target - generates with elf2image # Add 'app.bin' target - generates with elf2image
# #
if(CONFIG_APP_BUILD_GENERATE_BINARIES)
add_custom_command(OUTPUT "${build_dir}/.bin_timestamp" add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS} COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS}
-o "${build_dir}/${unsigned_project_binary}" "${elf}" -o "${build_dir}/${unsigned_project_binary}" "${elf}"
@ -89,13 +90,16 @@ add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
COMMENT "Generating binary image from built executable" COMMENT "Generating binary image from built executable"
) )
add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp") add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp")
endif()
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
"${build_dir}/${unsigned_project_binary}" "${build_dir}/${unsigned_project_binary}"
) )
if(CONFIG_APP_BUILD_GENERATE_BINARIES)
add_custom_target(app ALL DEPENDS gen_project_binary) add_custom_target(app ALL DEPENDS gen_project_binary)
endif()
if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS) if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS)
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES) if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)

View File

@ -29,7 +29,7 @@ extern soc_reserved_region_t soc_reserved_memory_region_end;
These variables have the start and end of the data and static IRAM These variables have the start and end of the data and static IRAM
area used by the program. Defined in the linker script. area used by the program. Defined in the linker script.
*/ */
extern int _data_start, _static_data_end, _iram_start, _iram_end; extern int _data_start, _heap_start, _iram_start, _iram_end;
/* static DRAM & IRAM chunks */ /* static DRAM & IRAM chunks */
static const size_t EXTRA_RESERVED_REGIONS = 2; static const size_t EXTRA_RESERVED_REGIONS = 2;
@ -67,8 +67,8 @@ static void s_prepare_reserved_regions(soc_reserved_region_t *reserved, size_t c
(count - EXTRA_RESERVED_REGIONS) * sizeof(soc_reserved_region_t)); (count - EXTRA_RESERVED_REGIONS) * sizeof(soc_reserved_region_t));
/* Add the EXTRA_RESERVED_REGIONS at the beginning */ /* Add the EXTRA_RESERVED_REGIONS at the beginning */
reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss */ reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss and possibly rodata */
reserved[0].end = (intptr_t)&_static_data_end; reserved[0].end = (intptr_t)&_heap_start;
reserved[1].start = (intptr_t)&_iram_start; /* IRAM used by code */ reserved[1].start = (intptr_t)&_iram_start; /* IRAM used by code */
reserved[1].end = (intptr_t)&_iram_end; reserved[1].end = (intptr_t)&_iram_end;

View File

@ -0,0 +1,13 @@
# Connect to a running instance of OpenOCD
target remote 127.0.0.1:3333
# Reset and halt the target
mon reset halt
# Run to a specific point in ROM code,
# where most of initialization is complete.
thb *0x40007901
c
# Load the application into RAM
load
# Run till app_main
tb app_main
c

View File

@ -0,0 +1,129 @@
import os
import pexpect
import serial
import sys
import threading
import time
try:
import IDF
except ImportError:
test_fw_path = os.getenv('TEST_FW_PATH')
if test_fw_path and test_fw_path not in sys.path:
sys.path.insert(0, test_fw_path)
import IDF
import Utility
class CustomProcess(object):
def __init__(self, cmd, logfile):
self.f = open(logfile, 'wb')
self.p = pexpect.spawn(cmd, timeout=60, logfile=self.f)
def __enter__(self):
return self
def close(self):
self.p.terminate(force=True)
def __exit__(self, type, value, traceback):
self.close()
self.f.close()
class OCDProcess(CustomProcess):
def __init__(self, proj_path):
cmd = 'openocd -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg'
log_file = os.path.join(proj_path, 'openocd.log')
super(OCDProcess, self).__init__(cmd, log_file)
i = self.p.expect_exact(['Info : Listening on port 3333 for gdb connections', 'Error:'])
if i == 0:
Utility.console_log('openocd is listening for gdb connections')
else:
raise RuntimeError('openocd initialization has failed')
def close(self):
try:
self.p.sendcontrol('c')
self.p.expect_exact('shutdown command invoked')
except Exception:
Utility.console_log('openocd needs to be killed', 'O')
super(OCDProcess, self).close()
class GDBProcess(CustomProcess):
def __init__(self, proj_path, elf_path):
cmd = 'xtensa-esp32-elf-gdb -x {} --directory={} {}'.format(os.path.join(proj_path, '.gdbinit.ci'),
os.path.join(proj_path, 'main'),
elf_path)
log_file = os.path.join(proj_path, 'gdb.log')
super(GDBProcess, self).__init__(cmd, log_file)
self.p.sendline('') # it is for "---Type <return> to continue, or q <return> to quit---"
i = self.p.expect_exact(['Thread 1 hit Temporary breakpoint 2, app_main ()',
'Load failed'])
if i == 0:
Utility.console_log('gdb is at breakpoint')
else:
raise RuntimeError('Load failed: probably the ELF file was not built for loading with gdb')
self.p.expect_exact('(gdb)')
def close(self):
try:
self.p.sendline('q')
self.p.expect_exact('Quit anyway? (y or n)')
self.p.sendline('y')
self.p.expect_exact('Ending remote debugging.')
except Exception:
Utility.console_log('gdb needs to be killed', 'O')
super(GDBProcess, self).close()
def break_till_end(self):
self.p.sendline('b esp_restart')
self.p.sendline('c')
self.p.expect_exact('Thread 1 hit Breakpoint 3, esp_restart ()')
class SerialThread(object):
def run(self, log_path, exit_event):
with serial.Serial('/dev/ttyUSB1', 115200) as ser, open(log_path, 'wb') as f:
while True:
f.write(ser.read(ser.in_waiting))
if exit_event.is_set():
break
time.sleep(1)
def __init__(self, log_path):
self.exit_event = threading.Event()
self.t = threading.Thread(target=self.run, args=(log_path, self.exit_event,))
self.t.start()
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.exit_event.set()
self.t.join(60)
if self.t.is_alive():
Utility.console_log('The pyserial thread is still alive', 'O')
@IDF.idf_example_test(env_tag="test_jtag_arm")
def test_examples_loadable_elf(env, extra_data):
idf_path = os.environ['IDF_PATH']
rel_project_path = os.path.join('examples', 'get-started', 'hello_world')
proj_path = os.path.join(idf_path, rel_project_path)
elf_path = os.path.join(IDF.Example(rel_project_path).get_binary_path(rel_project_path), 'hello-world.elf')
esp_log_path = os.path.join(proj_path, 'esp.log')
with SerialThread(esp_log_path):
with OCDProcess(proj_path), GDBProcess(proj_path, elf_path) as gdb:
gdb.break_till_end()
if pexpect.run('grep "Restarting now." {}'.format(esp_log_path), withexitstatus=True)[1]:
raise RuntimeError('Expected output from ESP was not received')
if __name__ == '__main__':
test_examples_loadable_elf()

View File

@ -0,0 +1,6 @@
CONFIG_APP_BUILD_TYPE_ELF_RAM=y
CONFIG_VFS_SUPPORT_TERMIOS=
CONFIG_NEWLIB_NANO_FORMAT=y
CONFIG_ESP32_PANIC_PRINT_HALT=y
CONFIG_ESP32_DEBUG_STUBS_ENABLE=
CONFIG_ESP_ERR_TO_NAME_LOOKUP=

View File

@ -320,9 +320,15 @@ ifndef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
endif endif
@echo "To flash app & partition table, run 'make flash' or:" @echo "To flash app & partition table, run 'make flash' or:"
else else
ifdef CONFIG_APP_BUILD_GENERATE_BINARIES
@echo "To flash all build output, run 'make flash' or:" @echo "To flash all build output, run 'make flash' or:"
endif endif
endif
ifdef CONFIG_APP_BUILD_GENERATE_BINARIES
@echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) @echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
else
@echo "Binary is not available for flashing"
endif
# If we have `version.txt` then prefer that for extracting IDF version # If we have `version.txt` then prefer that for extracting IDF version
@ -533,6 +539,7 @@ $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp
$(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP) $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP)
app: $(APP_BIN) partition_table_get_info app: $(APP_BIN) partition_table_get_info
ifeq ("$(CONFIG_APP_BUILD_GENERATE_BINARIES)","y")
ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image
@echo "App built but not signed. Signing step via espsecure.py:" @echo "App built but not signed. Signing step via espsecure.py:"
@echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)" @echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)"
@ -542,6 +549,9 @@ else
@echo "App built. Default flash app command is:" @echo "App built. Default flash app command is:"
@echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN) @echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN)
endif endif
else
@echo "Application in not built and cannot be flashed."
endif
all_binaries: $(APP_BIN) all_binaries: $(APP_BIN)

View File

@ -202,6 +202,19 @@ example_test_008:
- ESP32 - ESP32
- Example_Flash_Encryption - Example_Flash_Encryption
example_test_009:
extends: .example_test_template
tags:
- ESP32
- test_jtag_arm
artifacts:
when: always
paths:
- $CI_PROJECT_DIR/examples/get-started/hello_world/*.log
expire_in: 1 week
variables:
SETUP_TOOLS: "1"
UT_001: UT_001:
extends: .unit_test_template extends: .unit_test_template
parallel: 50 parallel: 50

View File

@ -924,6 +924,10 @@ def init_cli(verbose_output=None):
print("Done") print("Done")
return return
if not os.path.exists(os.path.join(args.build_dir, "flasher_args.json")):
print("Done")
return
# Otherwise, if we built any binaries print a message about # Otherwise, if we built any binaries print a message about
# how to flash them # how to flash them
def print_flashing_message(title, key): def print_flashing_message(title, key):

View File

@ -35,6 +35,9 @@ class IDFApp(App.BaseApp):
self.binary_path = self.get_binary_path(app_path) self.binary_path = self.get_binary_path(app_path)
self.elf_file = self._get_elf_file_path(self.binary_path) self.elf_file = self._get_elf_file_path(self.binary_path)
assert os.path.exists(self.binary_path) assert os.path.exists(self.binary_path)
sdkconfig_dict = self.get_sdkconfig()
if "CONFIG_APP_BUILD_GENERATE_BINARIES" in sdkconfig_dict:
# There are no flashing targets available when no binaries where generated.
if self.IDF_DOWNLOAD_CONFIG_FILE not in os.listdir(self.binary_path): if self.IDF_DOWNLOAD_CONFIG_FILE not in os.listdir(self.binary_path):
if self.IDF_FLASH_ARGS_FILE not in os.listdir(self.binary_path): if self.IDF_FLASH_ARGS_FILE not in os.listdir(self.binary_path):
msg = ("Neither {} nor {} exists. " msg = ("Neither {} nor {} exists. "

View File

@ -70,7 +70,15 @@ void setUp(void)
#endif #endif
printf("%s", ""); /* sneakily lazy-allocate the reent structure for this test task */ printf("%s", ""); /* sneakily lazy-allocate the reent structure for this test task */
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* TODO: add sufficient startup code in case of building an ELF file, so that
* flash cache is initialized and can work in such mode.
* For now this is disabled to allow running unit tests which don't require
* flash cache related operations.
*/
get_test_data_partition(); /* allocate persistent partition table structures */ get_test_data_partition(); /* allocate persistent partition table structures */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
unity_reset_leak_checks(); unity_reset_leak_checks();
test_utils_set_leak_level(CONFIG_UNITY_CRITICAL_LEAK_LEVEL_GENERAL, TYPE_LEAK_CRITICAL, COMP_LEAK_GENERAL); test_utils_set_leak_level(CONFIG_UNITY_CRITICAL_LEAK_LEVEL_GENERAL, TYPE_LEAK_CRITICAL, COMP_LEAK_GENERAL);