]> granicus.if.org Git - esp-idf/commitdiff
Support ELF files loadable with gdb
authorRoland Dobai <dobai.roland@gmail.com>
Mon, 22 Jul 2019 14:04:03 +0000 (16:04 +0200)
committerbot <bot@espressif.com>
Tue, 24 Sep 2019 07:19:50 +0000 (07:19 +0000)
24 files changed:
.gitlab-ci.yml
Kconfig
components/bootloader/CMakeLists.txt
components/bootloader/project_include.cmake
components/esp32/Kconfig
components/esp32/clk.c
components/esp32/cpu_start.c
components/esp32/ld/esp32.ld
components/esp32/ld/esp32.project.ld.in
components/esp32/ld/esp32_fragments.lf
components/esp32/panic.c
components/esp_rom/esp32/ld/esp32.rom.spiflash.ld
components/esptool_py/CMakeLists.txt
components/esptool_py/Makefile.projbuild
components/esptool_py/project_include.cmake
components/soc/src/memory_layout_utils.c
examples/get-started/hello_world/.gdbinit.ci [new file with mode: 0644]
examples/get-started/hello_world/loadable_elf_example_test.py [new file with mode: 0644]
examples/get-started/hello_world/sdkconfig.ci [new file with mode: 0644]
make/project.mk
tools/ci/config/target-test.yml
tools/idf.py
tools/tiny-test-fw/IDF/IDFApp.py
tools/unit-test-app/components/test_utils/test_runner.c

index 5bf113b9468a3da285f76748a7f3d03946dab977..5d94e62310e2982a25397a36d07485e1c4ce509a 100644 (file)
@@ -66,7 +66,7 @@ variables:
   rm -rf "$CUSTOM_TOOLCHAIN_PATH"
 
 .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
   fi
 
diff --git a/Kconfig b/Kconfig
index 129a0abc69c694dec9e219d5c6c5a7ef152b542c..92c76c38d59d943fd1dbec42452bbb36c6f71480 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -68,6 +68,83 @@ mainmenu "Espressif IoT Development Framework 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"
 
     menu "Compiler options"
index afe1ad639b59aca1804fafd40392014c436e7cce..bc80cbbd942488e1ef75851eb4475f371ed5a805 100644 (file)
@@ -1,7 +1,7 @@
 idf_component_register(PRIV_REQUIRES partition_table)
 
 # 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()
 endif()
 
index fa26fd097fa16a1460c3baab66cf3616290e85c9..d883a234e851e8c337d20a508b40fba8daa5b383 100644 (file)
@@ -1,7 +1,7 @@
 set(BOOTLOADER_OFFSET 0x1000)
 
 # Do not generate flash file when building bootloader
-if(BOOTLOADER_BUILD)
+if(BOOTLOADER_BUILD OR NOT CONFIG_APP_BUILD_BOOTLOADER)
     return()
 endif()
 
@@ -125,4 +125,4 @@ endif()
 # So for now we just have the top-level build remove the final build products...
 set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
     ADDITIONAL_MAKE_CLEAN_FILES
-    ${bootloader_binary_files})
\ No newline at end of file
+    ${bootloader_binary_files})
index 5a512f56276ff55db870a007a6085898a56f56c3..b58e5cfe69d10ce95e079d350985b5438a2e9073 100644 (file)
@@ -738,6 +738,11 @@ menu "ESP32-specific"
 
             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
         bool "Place RTC_DATA_ATTR and RTC_RODATA_ATTR variables into RTC fast memory segment"
         default n
index fd5c477618d3e1281c8a0da2c20f4eeda8f149ed..28bcbec7feb2c9c4e1ebd281eecd6f506497d63f 100644 (file)
@@ -75,7 +75,7 @@ void esp_clk_init(void)
     rtc_config_t cfg = RTC_CONFIG_DEFAULT();
     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.
 
        Bootloaders pre-v2.1 don't do this.
@@ -293,6 +293,8 @@ void esp_perip_clk_init(void)
                         DPORT_I2S1_CLK_EN |
                         DPORT_SPI_DMA_CLK_EN;
 
+    common_perip_clk &= ~DPORT_SPI01_CLK_EN;
+
 #if CONFIG_SPIRAM_SPEED_80M
 //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'
index e3a4bc11ed278600bc5587f8eae52ea488902dbd..ebea01b62ba1a5dc0c3f1a6149bd0ec0f0ea23e3 100644 (file)
 #include "esp_efuse.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 STRINGIFY2(s) #s
 
@@ -391,6 +396,32 @@ void start_cpu0_default(void)
 #ifndef CONFIG_FREERTOS_UNICORE
     esp_dport_access_int_init();
 #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();
     /* init default OS-aware flash access critical section */
     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);
 #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",
                                                 ESP_TASK_MAIN_STACK, NULL,
                                                 ESP_TASK_MAIN_PRIO, NULL, 0);
index a52b56f90db51420ffd016ebcc094e67d5bf8871..0400fc2ab31dcff03aa8bab32bd006e032595507 100644 (file)
@@ -49,6 +49,7 @@ MEMORY
   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
   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
   */
   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
     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.
@@ -72,10 +74,12 @@ MEMORY
   dram0_0_seg (RW) :                 org = 0x3FFB0000 + CONFIG_BT_RESERVE_DRAM,
                                      len = DRAM0_0_SEG_LEN - CONFIG_BT_RESERVE_DRAM
 
+#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
   /* Flash mapped constant data */
   drom0_0_seg (R) :                  org = 0x3F400018, len = 0x400000-0x18
 
   /* (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.
    */
@@ -116,3 +120,15 @@ REGION_ALIAS("rtc_data_location", rtc_slow_seg );
 #else
 REGION_ALIAS("rtc_data_location", rtc_data_seg );
 #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
index 872cecd3302d97523329749d29e1c4a51616dbe6..b8e710e071d9dd4fa5b8073910ebae6c17da9efe 100644 (file)
@@ -161,12 +161,8 @@ SECTIONS
     mapping[iram0_text]
 
     _iram_text_end = ABSOLUTE(.);
-    _iram_end = ABSOLUTE(.);
   } > iram0_0_seg
 
-  ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
-          "IRAM0 segment data does not fit.")
-
   .dram0.data :
   {
     _data_start = ABSOLUTE(.);
@@ -312,7 +308,7 @@ SECTIONS
     *(.tbss.*)
     _thread_local_end = ABSOLUTE(.);
     . = ALIGN(4);
-  } >drom0_0_seg
+  } >default_rodata_seg
 
   .flash.text :
   {
@@ -334,5 +330,25 @@ SECTIONS
        the flash.text segment.
     */
     _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.")
index 932197caf022e8ba538fe464a869effd0fc2e9b6..abf8fa8bf759cbcc96ab947548443faae1375230 100644 (file)
@@ -50,8 +50,12 @@ entries:
 
 [scheme:default]
 entries:
-    text -> flash_text
-    rodata -> flash_rodata
+    if APP_BUILD_USE_FLASH_SECTIONS = y:
+        text -> flash_text
+        rodata -> flash_rodata
+    else:
+        text -> iram0_text
+        rodata -> dram0_data
     data -> dram0_data
     bss -> dram0_bss
     common -> dram0_bss
index d84ec1ecb4c6feab450e020aa3a9a7d2b0b25c0e..5a27f26d0d62624e66ebad0531694bba34703aa2 100644 (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)
 {
index 709b35811448e5d1eb171a72ea7ce71c02bdb314..56497f1407fdc015674fef6706d13dc7b39bfb8d 100644 (file)
@@ -8,6 +8,7 @@ PROVIDE ( esp_rom_spiflash_erase_area = 0x400631ac );
 PROVIDE ( esp_rom_spiflash_erase_block = 0x40062c4c );
 PROVIDE ( esp_rom_spiflash_erase_chip = 0x40062c14 );
 PROVIDE ( esp_rom_spiflash_erase_sector = 0x40062ccc );
+PROVIDE ( esp_rom_spiflash_attach = 0x40062a6c );
 PROVIDE ( esp_rom_spiflash_lock = 0x400628f0 );
 PROVIDE ( esp_rom_spiflash_read = 0x40062ed8 );
 PROVIDE ( esp_rom_spiflash_config_readmode = 0x40062b64 ); /* SPIMasterReadModeCnfig */
index d30210531f43226fab91a4f8de2ce9e872441409..8fae3c6eb290358e02971926d82f219066f20361 100644 (file)
@@ -1,6 +1,6 @@
 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}")
     set(ESPTOOLPY_FLASH_PROJECT_OPTIONS
         "${ESPTOOLPY_FLASH_PROJECT_OPTIONS}"
index a351e8282fdac5fae2061734b9ca67815b566a9b..9c00c4e3ff905f34820d763157b6289cd18025ce 100644 (file)
@@ -68,7 +68,11 @@ endif
 APP_BIN_UNSIGNED ?= $(APP_BIN)
 
 $(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 $@ $<
+else
+       @echo "Skipping the BIN generation"
+endif
 
 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
index af676a626b76dbe15ae2ae3c317aa6ec3125aa9b..f0433d842420e24d491a756106bc362df8f4b4e5 100644 (file)
@@ -78,24 +78,28 @@ set(PROJECT_BIN "${elf_name}.bin")
 #
 # Add 'app.bin' target - generates with elf2image
 #
-add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
-    COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS}
-        -o "${build_dir}/${unsigned_project_binary}" "${elf}"
-    COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}"
-    COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.bin_timestamp"
-    DEPENDS ${elf}
-    VERBATIM
-    WORKING_DIRECTORY ${build_dir}
-    COMMENT "Generating binary image from built executable"
-    )
-add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp")
+if(CONFIG_APP_BUILD_GENERATE_BINARIES)
+    add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
+        COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS}
+            -o "${build_dir}/${unsigned_project_binary}" "${elf}"
+        COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}"
+        COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.bin_timestamp"
+        DEPENDS ${elf}
+        VERBATIM
+        WORKING_DIRECTORY ${build_dir}
+        COMMENT "Generating binary image from built executable"
+        )
+    add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp")
+endif()
 
 set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
     APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
     "${build_dir}/${unsigned_project_binary}"
     )
 
-add_custom_target(app ALL DEPENDS gen_project_binary)
+if(CONFIG_APP_BUILD_GENERATE_BINARIES)
+    add_custom_target(app ALL DEPENDS gen_project_binary)
+endif()
 
 if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS)
     if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
index 29f752b9da6a803cbd3b1dbd4f22cb2b74801696..2f4acb5c2e369d0b17f0886fe9d9baaf317a92a0 100644 (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
 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 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));
 
     /* Add the EXTRA_RESERVED_REGIONS at the beginning */
-    reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss */
-    reserved[0].end = (intptr_t)&_static_data_end;
+    reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss and possibly rodata */
+    reserved[0].end = (intptr_t)&_heap_start;
     reserved[1].start = (intptr_t)&_iram_start; /* IRAM used by code */
     reserved[1].end = (intptr_t)&_iram_end;
 
diff --git a/examples/get-started/hello_world/.gdbinit.ci b/examples/get-started/hello_world/.gdbinit.ci
new file mode 100644 (file)
index 0000000..a7fb135
--- /dev/null
@@ -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
diff --git a/examples/get-started/hello_world/loadable_elf_example_test.py b/examples/get-started/hello_world/loadable_elf_example_test.py
new file mode 100644 (file)
index 0000000..c6f9e24
--- /dev/null
@@ -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()
diff --git a/examples/get-started/hello_world/sdkconfig.ci b/examples/get-started/hello_world/sdkconfig.ci
new file mode 100644 (file)
index 0000000..c8b9cae
--- /dev/null
@@ -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=
index 4c5935b07f00dd820f49052b409bb3878e2a4fd3..a8ec59f405538da7956a8ddad8e9d0ab6330efe0 100644 (file)
@@ -320,9 +320,15 @@ ifndef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
 endif
        @echo "To flash app & partition table, run 'make flash' or:"
 else
+ifdef CONFIG_APP_BUILD_GENERATE_BINARIES
        @echo "To flash all build output, run 'make flash' or:"
 endif
+endif
+ifdef CONFIG_APP_BUILD_GENERATE_BINARIES
        @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
@@ -533,6 +539,7 @@ $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp
        $(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP)
 
 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
        @echo "App built but not signed. Signing step via espsecure.py:"
        @echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)"
@@ -542,6 +549,9 @@ else
        @echo "App built. Default flash app command is:"
        @echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN)
 endif
+else
+       @echo "Application in not built and cannot be flashed."
+endif
 
 all_binaries: $(APP_BIN)
 
index 4609f10be17525e8f6bf2c1acb428d46a460f423..aeb627941e69a235bb14ead32fa29beaeecab00f 100644 (file)
@@ -202,6 +202,19 @@ example_test_008:
     - ESP32
     - 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:
   extends: .unit_test_template
   parallel: 50
index b35b60be82d0cc2d25db405d92a6f3a6f7d588af..406b45a3d1d6b4c37584c913f709e499bf4f6605 100755 (executable)
@@ -924,6 +924,10 @@ def init_cli(verbose_output=None):
                 print("Done")
                 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
             # how to flash them
             def print_flashing_message(title, key):
index 82f42b0c35a94812931361903bfcc8d5cb3701b4..6324071f577b8e8ff471b35c8cfc443f5cd1f1ea 100644 (file)
@@ -35,18 +35,21 @@ class IDFApp(App.BaseApp):
         self.binary_path = self.get_binary_path(app_path)
         self.elf_file = self._get_elf_file_path(self.binary_path)
         assert os.path.exists(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):
-                msg = ("Neither {} nor {} exists. "
-                       "Try to run 'make print_flash_cmd | tail -n 1 > {}/{}' "
-                       "or 'idf.py build' "
-                       "for resolving the issue."
-                       "").format(self.IDF_DOWNLOAD_CONFIG_FILE, self.IDF_FLASH_ARGS_FILE,
-                                  self.binary_path, self.IDF_DOWNLOAD_CONFIG_FILE)
-                raise AssertionError(msg)
-
-        self.flash_files, self.flash_settings = self._parse_flash_download_config()
-        self.partition_table = self._parse_partition_table()
+        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_FLASH_ARGS_FILE not in os.listdir(self.binary_path):
+                    msg = ("Neither {} nor {} exists. "
+                           "Try to run 'make print_flash_cmd | tail -n 1 > {}/{}' "
+                           "or 'idf.py build' "
+                           "for resolving the issue."
+                           "").format(self.IDF_DOWNLOAD_CONFIG_FILE, self.IDF_FLASH_ARGS_FILE,
+                                      self.binary_path, self.IDF_DOWNLOAD_CONFIG_FILE)
+                    raise AssertionError(msg)
+
+            self.flash_files, self.flash_settings = self._parse_flash_download_config()
+            self.partition_table = self._parse_partition_table()
 
     @classmethod
     def get_sdk_path(cls):
index 1f00a0168b1682f9dc60d36dfdf82af208370ecb..fc09d5a450685f42b2bc6bb4c9ac7e248021b7f1 100644 (file)
@@ -70,7 +70,15 @@ void setUp(void)
 #endif
 
     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 */
+#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
 
     unity_reset_leak_checks();
     test_utils_set_leak_level(CONFIG_UNITY_CRITICAL_LEAK_LEVEL_GENERAL, TYPE_LEAK_CRITICAL, COMP_LEAK_GENERAL);