Compare commits

...

38 Commits

Author SHA1 Message Date
Mahavir Jain
3e9fdf085f Merge branch 'fix/update_postman_root_certificate_v5.1' into 'release/v5.1'
Updated postman root certificate (v5.1)

See merge request espressif/esp-idf!41055
2025-08-05 19:45:20 +05:30
hrushikesh.bhosale
1f37e2776a fix(esp_http_client): Moved httpd_async request from cert_pem to crt_bundle
Moved the httpd_async request from cert_pem to esp_crt_bundle. As cert_pem
is alredy tested for howmyssl URL
2025-08-05 16:28:16 +05:30
Island
b63fa75d66 Merge branch 'bugfix/fix_bt_hci_not_effective_v5.1' into 'release/v5.1'
Fixed bt hci event was not report to host when hci command was sent (v5.1)

See merge request espressif/esp-idf!41010
2025-08-05 14:31:08 +08:00
Mahavir Jain
e0d824a721 Merge branch 'fix(esp_http_client)/fix_potential_double_free_v5.1' into 'release/v5.1'
fix(esp_http_client): fix possible double memory free (v5.1)

See merge request espressif/esp-idf!40981
2025-08-05 09:49:56 +05:30
Jiang Jiang Jian
a96fb81744 Merge branch 'fix/wpa_eap_v1_192_bit_cert_v5.1' into 'release/v5.1'
Sending disconnect event in connect fail and add enterprise check 192 bit and some fixes for wpa_supplicant(v5.1)

See merge request espressif/esp-idf!41009
2025-08-04 15:00:01 +08:00
Jiang Jiang Jian
9c3469d612 Merge branch 'fix/c6_phylib_for_modem_state_v5.1' into 'release/v5.1'
fix(esp_phy): fix c6 modem state (v5.1)

See merge request espressif/esp-idf!40872
2025-08-04 14:48:21 +08:00
Jiang Jiang Jian
26307750da Merge branch 'bugfix/esp_flash_escape_checking_v5.1' into 'release/v5.1'
fix(esp_flash): fixed issue of escaping boundary check (v5.1)

See merge request espressif/esp-idf!40121
2025-08-04 14:30:27 +08:00
Jiang Jiang Jian
97429efba8 Merge branch 'fix/wpsreg_crash_due_to_double_reset_v5.1' into 'release/v5.1'
fix(wifi): Fix crash in WPS-registrar due to nested 'eap_wsc_reset()' calls (backport v5.1)

See merge request espressif/esp-idf!40964
2025-08-04 14:02:24 +08:00
Jiang Jiang Jian
4a67ad9eca Merge branch 'bugfix/fixed_ble_dtm_err_v5.1' into 'release/v5.1'
Bugfix/fixed ble dtm err (v5.1)

See merge request espressif/esp-idf!40951
2025-08-04 12:09:55 +08:00
Jiang Jiang Jian
b0947e3639 Merge branch 'fix/fix_mmu_map_concurrent_issue_v5.1' into 'release/v5.1'
mmu: fix mmu map concurrent issue (v5.1)

See merge request espressif/esp-idf!38412
2025-08-04 12:03:13 +08:00
Zhang Hai Peng
2c4e2255e9 fix(bt/ble): Update esp32 libbtdm_app.a (722c907a)
- Fixed bt hci event was not report to host when hci command was sent


(cherry picked from commit 155c32be209a44c251d29bb9d96ca603e9bba582)

Co-authored-by: zhanghaipeng <zhanghaipeng@espressif.com>
2025-08-04 11:53:19 +08:00
Wang Meng Yang
ab3034f72d Merge branch 'feat/add_handl_in_sdp_evt_v5.1' into 'release/v5.1'
feat(bt): Add record_handle in ESP_SDP_REMOVE_RECORD_COMP_EVT(v5.1)

See merge request espressif/esp-idf!40722
2025-08-02 14:59:07 +08:00
Kapil Gupta
1264331285 fix (esp_wifi): Set default akm as eap for non AKM APs 2025-08-02 10:42:49 +05:30
Kapil Gupta
9f524203d8 fix(wpa_supplicant): Delay sending of EAP_START for EAP auth 2025-08-02 10:41:01 +05:30
tarun.kumar
3afd8f8b19 fix(wifi): Sending disconnect event in connect fail and add enterprise check in Suite-B 192-bit certification 2025-08-02 10:38:30 +05:30
tarun.kumar
53e113f87a fix(softAP): Adjusted authentication mode for wpa-eap version 1 2025-08-02 10:35:17 +05:30
Alexey Gerenkov
c7b762c455 Merge branch 'fix/cxx-tls-destructors_v5.1' into 'release/v5.1'
fix(cxx): fix TLS classes destructor call (v5.1)

See merge request espressif/esp-idf!34211
2025-08-01 22:46:33 +08:00
Alexey Gerenkov
f34978b594 Merge branch 'ci/enable_sysview_tests_v5.1' into 'release/v5.1'
ci: enable sysview example tests for all chips (v5.1)

See merge request espressif/esp-idf!39476
2025-08-01 22:34:57 +08:00
Jiang Jiang Jian
92a6718847 Merge branch 'fix/__atomic_test_and_set_v5.1' into 'release/v5.1'
fix(newlib): fix __atomic_test_and_set to ensure atomicity (v5.1)

See merge request espressif/esp-idf!37453
2025-08-01 17:35:48 +08:00
Ashish Sharma
ed9266b194 fix(esp_http_client): fix possible double memory free 2025-08-01 15:10:31 +08:00
wangtao@espressif.com
8b50310ae8 fix(phy): fix esp32c2 build issue 2025-08-01 12:05:29 +08:00
Sarvesh Bodakhe
aa0344c054 fix(wifi): prevent crash in WPS-registrar due to nested 'eap_wsc_reset()' calls
When a WPS handshake is already in progress and the enrollee sends another EAPOL-Start
(e.g., due to missed packets or timeout), the registrar resets its state by calling
'eap_wsc_reset()'. This function frees 'sm->eap_method_priv' and then calls
'esp_wifi_ap_wps_disable()', which internally triggers another call to 'eap_wsc_reset()'.

This results in a double reset where the second invocation accesses the already freed
'sm->eap_method_priv', leading to a crash.

This fix sets 'sm->eap_method_priv' to NULL immediately after freeing it to ensure
any subsequent calls to eap_wsc_reset() do not access an invalid pointer.
2025-08-01 09:06:14 +05:30
Zhao Wei Liang
076e6e9ad6 fix(ble): fixed dtm function error on ESP32-H2
(cherry picked from commit 43c82b3b20b458c6b5eeb48d197488e36c857b15)

Co-authored-by: zwl <zhaoweiliang@espressif.com>
2025-08-01 10:20:11 +08:00
Zhao Wei Liang
f6d9263ecf fix(ble): fixed dtm function error on ESP32-C6
(cherry picked from commit ca0fdad4f2b23948203a9705aac6a2d5af2b2a40)

Co-authored-by: zwl <zhaoweiliang@espressif.com>
2025-08-01 10:20:09 +08:00
Alexey Lapshin
3b1916ad06 fix(newlib): fix __atomic_test_and_set to ensure atomicity
Before the change described in
https://gcc.gnu.org/pipermail/gcc-patches/2023-September/631393.html it
appeared that inlining built-in GCC function __atomic_test_and_set() was
incorrect. It resulted in a non-atomic write.
For GCC toolchains which do not have such patch yet, this commit fixes
__atomic_test_and_set to be atomic in IDF's builds.
2025-07-31 17:53:37 +07:00
zwx
da56c54d0b fix(esp_phy): fix c6 modem state 2025-07-30 20:45:48 +08:00
Alexey Lapshin
b8ab882ab2 fix(cxx): fix TLS classes destructor call
Closes https://github.com/espressif/esp-idf/issues/14360
2025-07-30 17:14:03 +07:00
xiongweichao
3cbf1d7ab3 feat(bt): Add record_handle in ESP_SDP_REMOVE_RECORD_COMP_EVT 2025-07-28 07:48:40 +00:00
Xiao Xufeng
2b66f127fd fix(esp_flash): fixed issue of escaping boundary check
Also patched corresponding ROM functions
2025-07-28 14:10:06 +08:00
Fu Hanxi
7d9b355c18 ci: use fixed telnetlib since python 3.13 removed this from stdlib 2025-07-21 15:19:46 +02:00
Fu Hanxi
72d648b292 feat(ci): enable jtag tests for esp32[c6|h2] 2025-07-18 11:47:08 +02:00
Erhan Kurubas
ff73ef0bb1 feat(tools): add esp32c3 rev1.1 rom version string 2025-07-18 11:47:08 +02:00
Samuel Obuch
e46d033d1d ci: use shared OpenOCD class for GDB test app 2025-07-18 11:47:08 +02:00
Samuel Obuch
c2dd5c35e0 ci: OpenOCD class as fixture 2025-07-18 11:47:04 +02:00
Samuel Obuch
8cee39c53c ci: enable sysview examples for all chips 2025-07-18 11:46:15 +02:00
armando
84c6a7f596 test(system): increased 200B memory leak thresh due to mmu mmap mutex
200B to extend the thresh, real increase to the memory usage will be smaller
2025-07-08 10:07:17 +08:00
armando
43b4810f56 test(mmu): added esp_mmu_map concurrency test 2025-07-08 10:07:17 +08:00
armando
34e8b36239 fix(mmu): fixed esp_mmu_map concurrent issue and add related docs 2025-07-08 10:07:17 +08:00
61 changed files with 807 additions and 483 deletions

View File

@@ -155,7 +155,9 @@
- "**/build*/flash_project_args"
- "**/build*/config/sdkconfig.json"
- "**/build*/bootloader/*.bin"
- "**/build*/bootloader/*.elf"
- "**/build*/partition_table/*.bin"
- "**/build*/project_description.json"
- list_job_*.json
- size_info.txt
when: always

View File

@@ -133,6 +133,28 @@ pytest_examples_esp32s2_jtag:
SETUP_TOOLS: "1" # need gdb openocd
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
pytest_examples_esp32c6_usb_serial_jtag:
extends:
- .pytest_examples_dir_template
- .rules:test:example_test-esp32c6
needs:
- build_pytest_examples_jtag
tags: [ esp32c6, usb_serial_jtag ]
variables:
SETUP_TOOLS: "1" # need gdb openocd
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
pytest_examples_esp32h2_usb_serial_jtag:
extends:
- .pytest_examples_dir_template
- .rules:test:example_test-esp32h2
needs:
- build_pytest_examples_jtag
tags: [ esp32h2, usb_serial_jtag ]
variables:
SETUP_TOOLS: "1" # need gdb openocd
PYTEST_EXTRA_FLAGS: "--log-cli-level DEBUG"
pytest_examples_esp32s3_generic:
extends:
- .pytest_examples_dir_template

View File

@@ -248,7 +248,9 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU")
endif()
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
list(APPEND compile_options "-fno-use-cxa-atexit")
list(APPEND compile_options "-fno-use-cxa-atexit") # TODO IDF-10934
else()
list(APPEND cxx_compile_options "-fuse-cxa-atexit")
endif()
# For the transition period from 32-bit time_t to 64-bit time_t,

View File

@@ -883,3 +883,7 @@ menu "Reserved Memory Config"
The actual reserved memory count will be the minimum value between the maximum
connection instances and the BT_LE_CONN_RESERVED_MEMORY_COUNT.
endmenu
config BT_LE_DTM_ENABLED
bool "Enable Direct Test Mode (DTM) feature"
default n

View File

@@ -37,6 +37,13 @@ void sync_stack_deinitEnv(void);
int sync_stack_enable(void);
void sync_stack_disable(void);
#if CONFIG_BT_LE_DTM_ENABLED
int dtm_stack_initEnv(void);
void dtm_stack_deinitEnv(void);
int dtm_stack_enable(void);
void dtm_stack_disable(void);
#endif // CONFIG_BT_LE_DTM_ENABLED
#if CONFIG_BT_LE_ERROR_SIM_ENABLED
int conn_errorSim_initEnv(void);
void conn_errorSim_deinitEnv(void);
@@ -134,6 +141,12 @@ int ble_stack_initEnv(void)
return rc;
}
#if CONFIG_BT_LE_DTM_ENABLED
rc = dtm_stack_initEnv();
if (rc) {
return rc;
}
#endif // CONFIG_BT_LE_DTM_ENABLED
return 0;
}
@@ -145,8 +158,9 @@ void ble_stack_deinitEnv(void)
#endif // CONFIG_BT_LE_ERROR_SIM_ENABLED
conn_stack_deinitEnv();
#endif // DEFAULT_BT_LE_MAX_CONNECTIONS
#if CONFIG_BT_LE_DTM_ENABLED
dtm_stack_deinitEnv();
#endif // CONFIG_BT_LE_DTM_ENABLED
sync_stack_deinitEnv();
extAdv_stack_deinitEnv();
adv_stack_deinitEnv();
@@ -177,6 +191,13 @@ int ble_stack_enable(void)
return rc;
}
#if CONFIG_BT_LE_DTM_ENABLED
rc = dtm_stack_enable();
if (rc) {
return rc;
}
#endif // CONFIG_BT_LE_DTM_ENABLED
#if DEFAULT_BT_LE_MAX_CONNECTIONS
rc = conn_stack_enable();
if (rc) {
@@ -215,6 +236,9 @@ void ble_stack_disable(void)
#endif // CONFIG_BT_LE_ERROR_SIM_ENABLED
conn_stack_disable();
#endif // DEFAULT_BT_LE_MAX_CONNECTIONS
#if CONFIG_BT_LE_DTM_ENABLED
dtm_stack_disable();
#endif // CONFIG_BT_LE_DTM_ENABLED
sync_stack_disable();
extAdv_stack_disable();
adv_stack_disable();

View File

@@ -887,3 +887,7 @@ menu "Reserved Memory Config"
The actual reserved memory count will be the minimum value between the maximum connection instances and
the BT_LE_CONN_RESERVED_MEMORY_COUNT.
endmenu
config BT_LE_DTM_ENABLED
bool "Enable Direct Test Mode (DTM) feature"
default n

View File

@@ -37,6 +37,13 @@ void sync_stack_deinitEnv(void);
int sync_stack_enable(void);
void sync_stack_disable(void);
#if CONFIG_BT_LE_DTM_ENABLED
int dtm_stack_initEnv(void);
void dtm_stack_deinitEnv(void);
int dtm_stack_enable(void);
void dtm_stack_disable(void);
#endif // CONFIG_BT_LE_DTM_ENABLED
#if CONFIG_BT_LE_ERROR_SIM_ENABLED
int conn_errorSim_initEnv(void);
void conn_errorSim_deinitEnv(void);
@@ -115,6 +122,12 @@ int ble_stack_initEnv(void)
return rc;
}
#if CONFIG_BT_LE_DTM_ENABLED
rc = dtm_stack_initEnv();
if (rc) {
return rc;
}
#endif // CONFIG_BT_LE_DTM_ENABLED
#if DEFAULT_BT_LE_MAX_CONNECTIONS
rc = conn_stack_initEnv();
@@ -140,6 +153,9 @@ void ble_stack_deinitEnv(void)
#endif // CONFIG_BT_LE_ERROR_SIM_ENABLED
conn_stack_deinitEnv();
#endif // DEFAULT_BT_LE_MAX_CONNECTIONS
#if CONFIG_BT_LE_DTM_ENABLED
dtm_stack_deinitEnv();
#endif // CONFIG_BT_LE_DTM_ENABLED
sync_stack_deinitEnv();
extAdv_stack_deinitEnv();
adv_stack_deinitEnv();
@@ -170,6 +186,13 @@ int ble_stack_enable(void)
return rc;
}
#if CONFIG_BT_LE_DTM_ENABLED
rc = dtm_stack_enable();
if (rc) {
return rc;
}
#endif // CONFIG_BT_LE_DTM_ENABLED
#if DEFAULT_BT_LE_MAX_CONNECTIONS
rc = conn_stack_enable();
if (rc) {
@@ -208,6 +231,9 @@ void ble_stack_disable(void)
#endif // CONFIG_BT_LE_ERROR_SIM_ENABLED
conn_stack_disable();
#endif // DEFAULT_BT_LE_MAX_CONNECTIONS
#if CONFIG_BT_LE_DTM_ENABLED
dtm_stack_disable();
#endif // CONFIG_BT_LE_DTM_ENABLED
sync_stack_disable();
extAdv_stack_disable();
adv_stack_disable();

View File

@@ -191,6 +191,7 @@ typedef union {
*/
struct sdp_remove_record_evt_param {
esp_sdp_status_t status; /*!< Status */
int record_handle; /*!< SDP record handle */
} remove_record; /*!< SDP callback param of ESP_SDP_REMOVE_RECORD_COMP_EVT */
} esp_sdp_cb_param_t;

View File

@@ -1181,7 +1181,8 @@ static void btc_sdp_remove_record(btc_sdp_args_t *arg)
} while(0);
if (ret != ESP_SDP_SUCCESS) {
param.create_record.status = ret;
param.remove_record.status = ret;
param.remove_record.record_handle = arg->remove_record.record_handle;
btc_sdp_cb_to_app(ESP_SDP_REMOVE_RECORD_COMP_EVT, &param);
}
}
@@ -1330,6 +1331,7 @@ void btc_sdp_cb_handler(btc_msg_t *msg)
}
param.remove_record.status = p_data->sdp_remove_record.status;
param.remove_record.record_handle = p_data->sdp_remove_record.handle;
btc_sdp_cb_to_app(ESP_SDP_REMOVE_RECORD_COMP_EVT, &param);
break;
default:

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -210,6 +210,12 @@ extern "C" void __cxa_guard_abort(__guard* pg) throw()
}
}
/* Originally, this should come with crtbegin.o from the toolchain (if GCC is configured with --enable-__cxa_atexit).
Since we do not link with crtbegin.o and have not configured GCC with --enable-__cxa_atexit, it is declared here.
Note: It should have a unique value in every shared object; in the main program its value is zero. */
extern "C" void *__dso_handle __attribute__((__visibility__("hidden")));
void *__dso_handle = 0;
/**
* Dummy function used to force linking this file instead of the same one in libstdc++.
* This works via -u __cxa_guard_dummy flag in component.mk

View File

@@ -198,7 +198,7 @@ struct PriorityInitTest
int PriorityInitTest::order = 0;
// init_priority objects are initialized from the lowest to the heighest priority number
// init_priority objects are initialized from the lowest to the highest priority number
// Default init_priority is always the lowest (highest priority number)
PriorityInitTest g_static_init_priority_test2;
PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(1000)));
@@ -246,6 +246,37 @@ TEST_CASE("can use std::vector", "[misc]")
TEST_ASSERT_EQUAL(51, std::accumulate(std::begin(v), std::end(v), 0));
}
static volatile bool is_tls_class_destructor_called;
struct TestTLS {
TestTLS() { }
~TestTLS()
{
is_tls_class_destructor_called = true;
}
void foo() { }
};
thread_local TestTLS s_testTLS;
void test_thread_local_destructors(void * arg)
{
s_testTLS.foo();
xSemaphoreGive(s_slow_init_sem);
vTaskDelete(NULL);
}
TEST_CASE("call destructors for thread_local classes CXX", "[misc]")
{
is_tls_class_destructor_called = false;
s_slow_init_sem = xSemaphoreCreateCounting(1, 0);
xTaskCreate(test_thread_local_destructors, "test_thread_local_destructors", 2048, NULL, 10, NULL);
vTaskDelay(1); /* Triggers IDLE task to call prvCheckTasksWaitingTermination() which cleans task-specific data */
TEST_ASSERT_TRUE(xSemaphoreTake(s_slow_init_sem, 500 / portTICK_PERIOD_MS));
vSemaphoreDelete(s_slow_init_sem);
vTaskDelay(10); // Allow tasks to clean up, avoids race with leak detector
TEST_ASSERT_TRUE(is_tls_class_destructor_called);
}
/* These test cases pull a lot of code from libstdc++ and are disabled for now
*/
#if 0
@@ -294,6 +325,7 @@ TEST_CASE("stack smashing protection CXX", "[stack_smash]")
extern "C" void app_main(void)
{
s_testTLS.foo(); /* allocates memory that will be reused */
printf("CXX GENERAL TEST\n");
unity_run_menu();
}

View File

@@ -9,7 +9,7 @@
#include "esp_heap_caps.h"
// iterator to load partition tables in `test spi bus lock, with flash` will lead memory not free
#define TEST_MEMORY_LEAK_THRESHOLD (350)
#define TEST_MEMORY_LEAK_THRESHOLD (450)
static size_t before_free_8bit;
static size_t before_free_32bit;

View File

@@ -65,15 +65,8 @@ char *http_utils_append_string(char **str, const char *new_str, int len)
}
if (old_str) {
old_len = strlen(old_str);
// old_str should not be reallocated directly, as in case of memory exhaustion,
// it will be lost and we will not be able to free it.
char *tmp = realloc(old_str, old_len + l + 1);
if (tmp == NULL) {
free(old_str);
old_str = NULL;
ESP_RETURN_ON_FALSE(old_str, NULL, "http_utils", "Memory exhausted");
}
old_str = tmp;
old_str = realloc(old_str, old_len + l + 1);
mem_check(old_str);
// Ensure the new string is null-terminated
old_str[old_len + l] = 0;
} else {

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -9,6 +9,7 @@
#include <sys/param.h>
#include <sys/queue.h>
#include <inttypes.h>
#include <sys/lock.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_log.h"
@@ -106,6 +107,10 @@ typedef struct {
* Only the first `num_regions` items are valid
*/
mem_region_t mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM];
/**
* driver layer mutex lock
*/
_lock_t mutex;
} mmu_ctx_t;
@@ -420,17 +425,15 @@ esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_target_t target,
ESP_RETURN_ON_FALSE((paddr_start % CONFIG_MMU_PAGE_SIZE == 0), ESP_ERR_INVALID_ARG, TAG, "paddr must be rounded up to the nearest multiple of CONFIG_MMU_PAGE_SIZE");
ESP_RETURN_ON_ERROR(s_mem_caps_check(caps), TAG, "invalid caps");
_lock_acquire(&s_mmu_ctx.mutex);
mem_block_t *dummy_head = NULL;
mem_block_t *dummy_tail = NULL;
size_t aligned_size = ALIGN_UP_BY(size, CONFIG_MMU_PAGE_SIZE);
int32_t found_region_id = s_find_available_region(s_mmu_ctx.mem_regions, s_mmu_ctx.num_regions, aligned_size, caps, target);
if (found_region_id == -1) {
ESP_EARLY_LOGE(TAG, "no such vaddr range");
return ESP_ERR_NOT_FOUND;
}
ESP_GOTO_ON_FALSE(found_region_id != -1, ESP_ERR_NOT_FOUND, err, TAG, "no such vaddr range");
//Now we're sure we can find an available block inside a certain region
mem_region_t *found_region = &s_mmu_ctx.mem_regions[found_region_id];
mem_block_t *dummy_head = NULL;
mem_block_t *dummy_tail = NULL;
mem_block_t *new_block = NULL;
if (TAILQ_EMPTY(&found_region->mem_block_head)) {
@@ -479,7 +482,6 @@ esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_target_t target,
}
if (is_enclosed) {
ESP_LOGW(TAG, "paddr block is mapped already, vaddr_start: %p, size: 0x%x", (void *)mem_block->vaddr_start, mem_block->size);
/*
* This condition is triggered when `s_is_enclosed` is true and hence
* we are sure that `paddr_start` >= `mem_block->paddr_start`.
@@ -489,12 +491,11 @@ esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_target_t target,
*/
const uint32_t new_paddr_offset = paddr_start - mem_block->paddr_start;
*out_ptr = (void *)mem_block->vaddr_start + new_paddr_offset;
return ESP_ERR_INVALID_STATE;
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_STATE, err, TAG, "paddr block is mapped already, vaddr_start: %p, size: 0x%x", (void *)mem_block->vaddr_start, mem_block->size);
}
if (!allow_overlap && is_overlapped) {
ESP_LOGE(TAG, "paddr block is overlapped with an already mapped paddr block");
return ESP_ERR_INVALID_ARG;
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "paddr block is overlapped with an already mapped paddr block");
}
#endif //#if ENABLE_PADDR_CHECK
@@ -529,7 +530,6 @@ esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_target_t target,
assert(found);
//insert the to-be-mapped new block to the list
TAILQ_INSERT_BEFORE(found_block, new_block, entries);
//Finally, we update the max_slot_size
found_region->max_slot_size = max_slot_len;
@@ -551,6 +551,7 @@ esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_target_t target,
//do mapping
s_do_mapping(target, new_block->vaddr_start, paddr_start, aligned_size);
*out_ptr = (void *)new_block->vaddr_start;
_lock_release(&s_mmu_ctx.mutex);
return ESP_OK;
@@ -561,6 +562,7 @@ err:
if (dummy_head) {
free(dummy_head);
}
_lock_release(&s_mmu_ctx.mutex);
return ret;
}
@@ -590,17 +592,19 @@ esp_err_t esp_mmu_unmap(void *ptr)
{
ESP_RETURN_ON_FALSE(ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer");
esp_err_t ret = ESP_FAIL;
mem_region_t *region = NULL;
mem_block_t *mem_block = NULL;
uint32_t ptr_laddr = mmu_ll_vaddr_to_laddr((uint32_t)ptr);
size_t slot_len = 0;
_lock_acquire(&s_mmu_ctx.mutex);
for (int i = 0; i < s_mmu_ctx.num_regions; i++) {
if (ptr_laddr >= s_mmu_ctx.mem_regions[i].free_head && ptr_laddr < s_mmu_ctx.mem_regions[i].end) {
region = &s_mmu_ctx.mem_regions[i];
}
}
ESP_RETURN_ON_FALSE(region, ESP_ERR_NOT_FOUND, TAG, "munmap target pointer is outside external memory regions");
ESP_GOTO_ON_FALSE(region, ESP_ERR_NOT_FOUND, err, TAG, "munmap target pointer is outside external memory regions");
bool found = false;
mem_block_t *found_block = NULL;
@@ -621,15 +625,23 @@ esp_err_t esp_mmu_unmap(void *ptr)
}
}
ESP_RETURN_ON_FALSE(found, ESP_ERR_NOT_FOUND, TAG, "munmap target pointer isn't mapped yet");
if (found) {
TAILQ_REMOVE(&region->mem_block_head, found_block, entries);
}
ESP_GOTO_ON_FALSE(found, ESP_ERR_NOT_FOUND, err, TAG, "munmap target pointer isn't mapped yet");
//do unmap
s_do_unmapping(mem_block->vaddr_start, mem_block->size);
//remove the already unmapped block from the list
TAILQ_REMOVE(&region->mem_block_head, found_block, entries);
free(found_block);
_lock_release(&s_mmu_ctx.mutex);
return ESP_OK;
err:
_lock_release(&s_mmu_ctx.mutex);
return ret;
}

View File

@@ -61,8 +61,6 @@ typedef uint32_t esp_paddr_t;
/**
* @brief Map a physical memory block to external virtual address block, with given capabilities.
*
* @note This API does not guarantee thread safety
*
* @param[in] paddr_start Start address of the physical memory block
* @param[in] size Size to be mapped. Size will be rounded up by to the nearest multiple of MMU page size
* @param[in] target Physical memory target you're going to map to, see `mmu_target_t`
@@ -89,8 +87,6 @@ esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_target_t target,
/**
* @brief Unmap a previously mapped virtual memory block
*
* @note This API does not guarantee thread safety
*
* @param[in] ptr Start address of the virtual memory
*
* @return

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,6 +8,9 @@
#include <sys/param.h>
#include <string.h>
#include "inttypes.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "unity.h"
@@ -70,3 +73,56 @@ TEST_CASE("Can find paddr caps by any paddr offset", "[mmu]")
TEST_ESP_OK(esp_mmu_unmap(ptr0));
}
typedef struct {
SemaphoreHandle_t done;
} test_task_arg_t;
void map_task(void *varg)
{
esp_err_t ret = ESP_FAIL;
test_task_arg_t* args = (test_task_arg_t*) varg;
const esp_partition_t *part = s_get_partition();
srand(199);
int cnt = 0;
while (true) {
if (cnt >= 10000) {
break;
}
size_t i = rand() % part->size;
void *ptr0 = NULL;
size_t phys_addr = part->address + i;
size_t region_offset = phys_addr & (CONFIG_MMU_PAGE_SIZE - 1);
size_t mmap_addr = phys_addr & ~(CONFIG_MMU_PAGE_SIZE - 1);
ret = esp_mmu_map(mmap_addr, 1 + region_offset, MMU_TARGET_FLASH0, MMU_MEM_CAP_READ | MMU_MEM_CAP_8BIT, ESP_MMU_MMAP_FLAG_PADDR_SHARED, &ptr0);
if (ret == ESP_OK) {
esp_mmu_unmap(ptr0);
}
cnt++;
vTaskDelay(pdMS_TO_TICKS(1));
}
xSemaphoreGive(args->done);
vTaskDelete(NULL);
}
TEST_CASE("Test mmap concurrency", "[mmu][manual][ignore]")
{
test_task_arg_t args0 = {
.done = xSemaphoreCreateBinary(),
};
test_task_arg_t args1 = {
.done = xSemaphoreCreateBinary(),
};
xTaskCreate(map_task, "map0_task", 8096, &args0, 1, NULL);
xTaskCreate(map_task, "map1_task", 8096, &args1, 1, NULL);
xSemaphoreTake(args0.done, portMAX_DELAY);
xSemaphoreTake(args1.done, portMAX_DELAY);
vTaskDelay(100);
vSemaphoreDelete(args0.done);
vSemaphoreDelete(args1.done);
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,11 +13,11 @@
* - traversing all vaddr range to check their attributes
*
* These tests need certain number of internal resources (heap memory), as they uses up the vaddr ranges
* On ESP32, it should be around 450
* On ESP32S2, it should be around 600
* On other chips, it should be around 400
* On ESP32, it should be around 650
* On ESP32S2, it should be around 800
* On other chips, it should be around 600
*/
#define TEST_MEMORY_LEAK_THRESHOLD (-650)
#define TEST_MEMORY_LEAK_THRESHOLD (-800)
static size_t before_free_8bit;
static size_t before_free_32bit;

View File

@@ -7,12 +7,29 @@ if IDF_TARGET_ESP32 = y:
entries:
.phyiram+
if IDF_TARGET_ESP32C2 = y:
[scheme:phy_iram]
entries:
phy_iram -> iram0_text
[sections:phy_iram]
entries:
.phyiram+
[mapping:btbb]
archive: libbtbb.a
entries:
if IDF_TARGET_ESP32C2 = y:
* (phy_iram)
[mapping:phy]
archive: libphy.a
entries:
* (noflash_data)
if ESP_WIFI_SLP_IRAM_OPT = y && IDF_TARGET_ESP32 = y:
* (phy_iram)
if IDF_TARGET_ESP32C2 = y:
* (phy_iram)
[mapping:rtc]
archive: librtc.a

View File

@@ -8,7 +8,7 @@
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
#define TEST_MEMORY_LEAK_THRESHOLD (-600)
#define TEST_MEMORY_LEAK_THRESHOLD (-750)
static size_t before_free_8bit;
static size_t before_free_32bit;

View File

@@ -347,15 +347,15 @@ PROVIDE( esp_flash_chip_driver_initialized = 0x40000430 );
PROVIDE( esp_flash_read_id = 0x40000434 );
PROVIDE( esp_flash_get_size = 0x40000438 );
PROVIDE( esp_flash_erase_chip = 0x4000043c );
PROVIDE( esp_flash_erase_region = 0x40000440 );
PROVIDE( rom_esp_flash_erase_region = 0x40000440 );
PROVIDE( esp_flash_get_chip_write_protect = 0x40000444 );
PROVIDE( esp_flash_set_chip_write_protect = 0x40000448 );
PROVIDE( esp_flash_get_protectable_regions = 0x4000044c );
PROVIDE( esp_flash_get_protected_region = 0x40000450 );
PROVIDE( esp_flash_set_protected_region = 0x40000454 );
PROVIDE( esp_flash_read = 0x40000458 );
PROVIDE( esp_flash_write = 0x4000045c );
PROVIDE( esp_flash_write_encrypted = 0x40000460 );
PROVIDE( rom_esp_flash_write = 0x4000045c );
PROVIDE( rom_esp_flash_write_encrypted = 0x40000460 );
PROVIDE( esp_flash_read_encrypted = 0x40000464 );
PROVIDE( esp_flash_get_io_mode = 0x40000468 );
PROVIDE( esp_flash_set_io_mode = 0x4000046c );
@@ -1024,7 +1024,7 @@ ieee80211_getcapinfo = 0x40002130;
/* sta_recv_sa_query_resp = 0x40002144; */
ieee80211_set_max_rate = 0x4000214c;
ic_set_sta = 0x40002150;
ieee80211_parse_wpa = 0x40002158;
/* ieee80211_parse_wpa = 0x40002158; */
ieee80211_add_assoc_req_ies = 0x40002160;
ieee80211_add_probe_req_ies = 0x40002164;
/* Data (.data, .bss, .rodata) */

View File

@@ -267,8 +267,8 @@ PROVIDE( esp_flash_get_protectable_regions = 0x40000318 );
PROVIDE( esp_flash_get_protected_region = 0x4000031c );
PROVIDE( esp_flash_set_protected_region = 0x40000320 );
PROVIDE( esp_flash_read = 0x40000324 );
PROVIDE( esp_flash_write = 0x40000328 );
PROVIDE( esp_flash_write_encrypted = 0x4000032c );
PROVIDE( rom_esp_flash_write = 0x40000328 );
PROVIDE( rom_esp_flash_write_encrypted = 0x4000032c );
PROVIDE( esp_flash_read_encrypted = 0x40000330 );
PROVIDE( esp_flash_get_io_mode = 0x40000334 );
PROVIDE( esp_flash_set_io_mode = 0x40000338 );

View File

@@ -50,15 +50,15 @@ esp_flash_chip_driver_initialized = 0x4000022c;
esp_flash_read_id = 0x40000230;
esp_flash_get_size = 0x40000234;
esp_flash_erase_chip = 0x40000238;
esp_flash_erase_region = 0x4000023c;
rom_esp_flash_erase_region = 0x4000023c;
esp_flash_get_chip_write_protect = 0x40000240;
esp_flash_set_chip_write_protect = 0x40000244;
esp_flash_get_protectable_regions = 0x40000248;
esp_flash_get_protected_region = 0x4000024c;
esp_flash_set_protected_region = 0x40000250;
esp_flash_read = 0x40000254;
esp_flash_write = 0x40000258;
esp_flash_write_encrypted = 0x4000025c;
rom_esp_flash_write = 0x40000258;
rom_esp_flash_write_encrypted = 0x4000025c;
esp_flash_read_encrypted = 0x40000260;
esp_flash_get_io_mode = 0x40000264;
esp_flash_set_io_mode = 0x40000268;

View File

@@ -50,15 +50,15 @@ esp_flash_chip_driver_initialized = 0x40000224;
esp_flash_read_id = 0x40000228;
esp_flash_get_size = 0x4000022c;
esp_flash_erase_chip = 0x40000230;
esp_flash_erase_region = 0x40000234;
rom_esp_flash_erase_region = 0x40000234;
esp_flash_get_chip_write_protect = 0x40000238;
esp_flash_set_chip_write_protect = 0x4000023c;
esp_flash_get_protectable_regions = 0x40000240;
esp_flash_get_protected_region = 0x40000244;
esp_flash_set_protected_region = 0x40000248;
esp_flash_read = 0x4000024c;
esp_flash_write = 0x40000250;
esp_flash_write_encrypted = 0x40000254;
rom_esp_flash_write = 0x40000250;
rom_esp_flash_write_encrypted = 0x40000254;
esp_flash_read_encrypted = 0x40000258;
esp_flash_get_io_mode = 0x4000025c;
esp_flash_set_io_mode = 0x40000260;

View File

@@ -341,8 +341,8 @@ PROVIDE( esp_flash_get_protectable_regions = 0x40001110 );
PROVIDE( esp_flash_get_protected_region = 0x4000111c );
PROVIDE( esp_flash_set_protected_region = 0x40001128 );
PROVIDE( esp_flash_read = 0x40001134 );
PROVIDE( esp_flash_write = 0x40001140 );
PROVIDE( esp_flash_write_encrypted = 0x4000114c );
PROVIDE( rom_esp_flash_write = 0x40001140 );
PROVIDE( rom_esp_flash_write_encrypted = 0x4000114c );
PROVIDE( esp_flash_read_encrypted = 0x40001158 );
PROVIDE( esp_flash_get_io_mode = 0x40001164 );
PROVIDE( esp_flash_set_io_mode = 0x40001170 );

View File

@@ -11,7 +11,7 @@
#include "freertos/task.h"
// Some resources are lazy allocated, the threshold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (-800)
#define TEST_MEMORY_LEAK_THRESHOLD (-1100)
static size_t before_free_8bit;
static size_t before_free_32bit;

View File

@@ -1406,7 +1406,7 @@ esp_err_t esp_wifi_force_wakeup_release(void);
/**
* @brief configure country
*
* @attention 1. When ieee80211d_enabled, the country info of the AP to which
* @attention 1. When ieee80211d_enabled is enabled, the country info of the AP to which
* the station is connected is used. E.g. if the configured country is US
* and the country info of the AP to which the station is connected is JP
* then the country info that will be used is JP. If the station disconnected

View File

@@ -59,7 +59,7 @@ typedef struct {
* @brief Wi-Fi authmode type
* Strength of authmodes
* Personal Networks : OPEN < WEP < WPA_PSK < OWE < WPA2_PSK = WPA_WPA2_PSK < WAPI_PSK < WPA3_PSK = WPA2_WPA3_PSK
* Enterprise Networks : WIFI_AUTH_WPA2_ENTERPRISE < WIFI_AUTH_WPA3_ENT_192
* Enterprise Networks : WIFI_AUTH_WPA_ENTERPRISE < WIFI_AUTH_WPA2_ENTERPRISE < WIFI_AUTH_WPA3_ENT_192
*/
typedef enum {
WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */
@@ -67,13 +67,19 @@ typedef enum {
WIFI_AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */
WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */
WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */
WIFI_AUTH_ENTERPRISE, /**< authenticate mode : WiFi EAP security */
WIFI_AUTH_WPA2_ENTERPRISE = WIFI_AUTH_ENTERPRISE, /**< authenticate mode : WiFi EAP security */
WIFI_AUTH_ENTERPRISE, /**< authenticate mode : WiFi EAP security, treated the same as WIFI_AUTH_WPA2_ENTERPRISE */
WIFI_AUTH_WPA2_ENTERPRISE = WIFI_AUTH_ENTERPRISE, /**< authenticate mode : WPA2-Enterprise security */
WIFI_AUTH_WPA3_PSK, /**< authenticate mode : WPA3_PSK */
WIFI_AUTH_WPA2_WPA3_PSK, /**< authenticate mode : WPA2_WPA3_PSK */
WIFI_AUTH_WAPI_PSK, /**< authenticate mode : WAPI_PSK */
WIFI_AUTH_OWE, /**< authenticate mode : OWE */
WIFI_AUTH_WPA3_ENT_192, /**< authenticate mode : WPA3_ENT_SUITE_B_192_BIT */
WIFI_AUTH_DUMMY1,
WIFI_AUTH_DUMMY2,
WIFI_AUTH_DUMMY3,
WIFI_AUTH_DUMMY4,
WIFI_AUTH_DUMMY5,
WIFI_AUTH_WPA_ENTERPRISE, /**< Authenticate mode : WPA-Enterprise security */
WIFI_AUTH_MAX
} wifi_auth_mode_t;

View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include_next "stdatomic.h"
#ifndef __clang__
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
static inline bool __atomic_test_and_set(volatile void *ptr, int memorder)
{
return __atomic_exchange_1((bool *)ptr, true, memorder);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -21,6 +21,18 @@ atomic_ushort g_atomic16;
atomic_uchar g_atomic8;
TEST_CASE("stdatomic - test_atomic_flag", "[newlib_stdatomic]")
{
bool x8 = 0;
g_atomic8 = 0;
x8 = atomic_flag_test_and_set(&g_atomic8);
TEST_ASSERT_EQUAL_HEX8(0x00, x8);
TEST_ASSERT_EQUAL_HEX8(0x01, g_atomic8);
atomic_flag_clear(&g_atomic8);
TEST_ASSERT_EQUAL_HEX8(0x00, g_atomic8);
}
TEST_CASE("stdatomic - test_64bit_atomics", "[newlib_stdatomic]")
{
unsigned long long x64 = 0;
@@ -248,7 +260,7 @@ TEST_CASE("stdatomic - test_" #NAME, "[newlib_stdatomic]")
TEST_ASSERT_EQUAL##ASSERT_SUFFIX((FINAL), var_##NAME); \
}
// Note that the assert at the end is doing an excat bitwise comparison.
// Note that the assert at the end is doing an exact bitwise comparison.
// This easily can fail due to rounding errors. However, there is currently
// no corresponding Unity assert macro for long double. USE THIS WITH CARE!
#define TEST_RACE_OPERATION_LONG_DOUBLE(NAME, LHSTYPE, PRE, POST, INIT, FINAL) \

View File

@@ -553,9 +553,6 @@ esp_err_t IRAM_ATTR esp_flash_get_physical_size(esp_flash_t *chip, uint32_t *fla
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
/* Return true if regions 'a' and 'b' overlap at all, based on their start offsets and lengths. */
inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len);
esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
@@ -586,7 +583,21 @@ esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip)
err = esp_flash_erase_region(chip, 0, size);
return err;
}
#endif // !CONFIG_SPI_FLASH_ROM_IMPL
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
inline static IRAM_ATTR bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len)
{
uint32_t a_end = a_start + a_len;
uint32_t b_end = b_start + b_len;
return (a_end > b_start && b_end > a_start);
}
/* ROM and patch information
* Latest: Fixed region check escape
* V2: Fixed size == 0 bug.
* V1 (ESP_ROM_HAS_ERASE_0_REGION_BUG): Added to ROM
*/
esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
@@ -602,7 +613,7 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
if (sector_size == 0 || (block_erase_size % sector_size) != 0) {
return ESP_ERR_FLASH_NOT_INITIALISED;
}
if (start > chip->size || start + len > chip->size) {
if (start > chip->size || len > chip->size - start) {
return ESP_ERR_INVALID_ARG;
}
if ((start % chip->chip_drv->sector_size) != 0 || (len % chip->chip_drv->sector_size) != 0) {
@@ -697,26 +708,45 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui
return rom_spiflash_api_funcs->flash_end_flush_cache(chip, err, bus_acquired, start, len);
}
#endif // !CONFIG_SPI_FLASH_ROM_IMPL
#if defined(CONFIG_SPI_FLASH_ROM_IMPL) && ESP_ROM_HAS_ERASE_0_REGION_BUG
/* ROM esp_flash_erase_region implementation doesn't handle 0 erase size correctly.
#else //!CONFIG_SPI_FLASH_ROM_IMPL
extern esp_err_t rom_esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len);
# if ESP_ROM_HAS_ERASE_0_REGION_BUG
// Usel ROM impl v1 but workaround ESP_ROM_HAS_ERASE_0_REGION_BUG and region check escape.
/* ROM V1 esp_flash_erase_region implementation doesn't handle 0 erase size correctly.
* Check the size and call ROM function instead of overriding it completely.
* The behavior is slightly different from esp_flash_erase_region above, thought:
* The behavior is slightly different from latest esp_flash_erase_region above, thought:
* here the check for 0 size is done first, but in esp_flash_erase_region the check is
* done after the other arguments are checked.
*/
extern esp_err_t rom_esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len);
esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}
if (len == 0) {
return ESP_OK;
}
if (len > chip->size - start) {
return ESP_ERR_INVALID_ARG;
}
return rom_esp_flash_erase_region(chip, start, len);
}
#endif // defined(CONFIG_SPI_FLASH_ROM_IMPL) && ESP_ROM_HAS_ERASE_0_REGION_BUG
# else
// Usel ROM impl v2 but workaround region check escape.
esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}
if (len > chip->size - start) {
return ESP_ERR_INVALID_ARG;
}
return rom_esp_flash_erase_region(chip, start, len);
}
# endif // ESP_ROM_HAS_ERASE_0_REGION_BUG
#endif // !CONFIG_SPI_FLASH_ROM_IMPL
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
@@ -921,7 +951,10 @@ esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t add
COUNTER_STOP(read);
return err;
}
#endif //!CONFIG_SPI_FLASH_ROM_IMPL
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
//This checking is available only when !CONFIG_SPI_FLASH_ROM_IMPL
#if CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE
static esp_err_t IRAM_ATTR s_check_setting_zero_to_one(esp_flash_t *chip, uint32_t verify_address, uint32_t remain_verify_len, const uint32_t *to_write_buf, bool is_encrypted)
{
@@ -961,6 +994,7 @@ static esp_err_t IRAM_ATTR s_check_setting_zero_to_one(esp_flash_t *chip, uint32
}
#endif //#if CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE
//This checking is available only when !CONFIG_SPI_FLASH_ROM_IMPL
#if CONFIG_SPI_FLASH_VERIFY_WRITE
static esp_err_t IRAM_ATTR s_verify_write(esp_flash_t *chip, uint32_t verify_address, uint32_t remain_verify_len, const uint32_t *expected_buf, bool is_encrypted)
{
@@ -999,6 +1033,13 @@ static esp_err_t IRAM_ATTR s_verify_write(esp_flash_t *chip, uint32_t verify_add
}
#endif //#if CONFIG_SPI_FLASH_VERIFY_WRITE
/* ROM and patch information
* Latest:
- Provide debugging utils (CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE, CONFIG_SPI_FLASH_VERIFY_WRITE)
- Fixed region check escape
* V1: added to ROM
*/
//When use the ROM impl, can't use these debugging utils.
esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
esp_err_t ret = ESP_FAIL;
@@ -1010,7 +1051,7 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(write);
CHECK_WRITE_ADDRESS(chip, address, length);
if (buffer == NULL || address > chip->size || address+length > chip->size) {
if (buffer == NULL || address > chip->size || length > chip->size - address) {
return ESP_ERR_INVALID_ARG;
}
if (length == 0) {
@@ -1120,14 +1161,23 @@ restore_cache:
return err;
}
inline static IRAM_ATTR bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len)
#else
extern esp_err_t rom_esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length);
// Usel ROM impl v1 but workaround region check escape.
esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
uint32_t a_end = a_start + a_len;
uint32_t b_end = b_start + b_len;
return (a_end > b_start && b_end > a_start);
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}
if (length > chip->size - address) {
return ESP_ERR_INVALID_ARG;
}
return rom_esp_flash_write(chip, buffer, address, length);
}
#endif //!CONFIG_SPI_FLASH_ROM_IMPL
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
esp_err_t IRAM_ATTR esp_flash_read_encrypted(esp_flash_t *chip, uint32_t address, void *out_buffer, uint32_t length)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
@@ -1194,6 +1244,8 @@ IRAM_ATTR esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
}
#endif //CONFIG_SPI_FLASH_ROM_IMPL
#if !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV)
// use `esp_flash_write_encrypted` ROM version on chips later than C3 and S3
FORCE_INLINE_ATTR esp_err_t s_encryption_write_lock(esp_flash_t *chip) {
#if CONFIG_IDF_TARGET_ESP32S2
esp_crypto_dma_lock_acquire();
@@ -1209,10 +1261,14 @@ FORCE_INLINE_ATTR esp_err_t s_encryption_write_unlock(esp_flash_t *chip) {
return err;
}
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
// use `esp_flash_write_encrypted` ROM version not in C3 and S3
/* ROM and patch information
* Latest:
- Provide debugging utils (CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE, CONFIG_SPI_FLASH_VERIFY_WRITE)
- Fixed region check escape
* V2: Bug fixed
* V1 (ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV): added to ROM but has bug
*/
//When use the ROM impl, can't use these debugging utils.
esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length)
{
esp_err_t ret = ESP_FAIL;
@@ -1229,7 +1285,7 @@ esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t addres
}
CHECK_WRITE_ADDRESS(chip, address, length);
if (buffer == NULL || address + length > chip->size) {
if (buffer == NULL || address > chip->size || length > chip->size - address) {
return ESP_ERR_INVALID_ARG;
}
@@ -1412,8 +1468,21 @@ restore_cache:
return err;
}
#endif // !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
#else
extern esp_err_t rom_esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length);
// Usel ROM impl v2 but workaround region check escape.
esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}
if (length > chip->size - address) {
return ESP_ERR_INVALID_ARG;
}
return rom_esp_flash_write_encrypted(chip, address, buffer, length);
}
#endif // !(CONFIG_SPI_FLASH_ROM_IMPL && !ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV)
//init suspend mode cmd, uses internal.
esp_err_t esp_flash_suspend_cmd_init(esp_flash_t* chip)

View File

@@ -847,6 +847,41 @@ static void test_write_large_buffer(const esp_partition_t* part, const uint8_t *
write_large_buffer(part, source, length);
read_and_check(part, source, length);
}
#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
static void test_write_over_boundary(const esp_partition_t* part)
{
esp_flash_t* chip = part->flash_chip;
uint32_t flash_size;
esp_err_t err = esp_flash_get_size(chip, &flash_size);
TEST_ESP_OK(err);
const uint32_t SECTOR_SIZE = 4096;
uint8_t buf[0];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 0, flash_size+SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, SECTOR_SIZE, flash_size));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size/2, flash_size/2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size/2 + SECTOR_SIZE, flash_size/2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, 2 * SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 2 * SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, UINT32_MAX - SECTOR_SIZE + 1));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, UINT32_MAX - SECTOR_SIZE + 1, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, 0, flash_size+SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, SECTOR_SIZE, flash_size));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size/2, flash_size/2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size/2 + SECTOR_SIZE, flash_size/2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size - SECTOR_SIZE, 2 * SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, 2 * SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size - SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, flash_size - SECTOR_SIZE, UINT32_MAX - SECTOR_SIZE + 1));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write(chip, buf, UINT32_MAX - SECTOR_SIZE + 1, flash_size - SECTOR_SIZE));
}
TEST_CASE_FLASH("Test flash write over boundary", test_write_over_boundary);
TEST_CASE_MULTI_FLASH("Test flash write over boundary", test_write_over_boundary);
#endif //CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
#ifdef CONFIG_SPIRAM_USE_MALLOC
@@ -994,3 +1029,16 @@ void test_flash_counter(const esp_partition_t* part)
TEST_CASE_FLASH("SPI flash counter test", test_flash_counter);
#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS
#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS
TEST_CASE("test writes to dangerous regions like bootloader", "[esp_flash]")
{
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_erase_region(NULL, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, 4*4096));
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_erase_region(NULL, CONFIG_PARTITION_TABLE_OFFSET, 4096));
char buffer[32] = {0xa5};
// Encrypted writes to bootloader region not allowed
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_write(NULL, buffer, CONFIG_BOOTLOADER_OFFSET_IN_FLASH, sizeof(buffer)));
// Encrypted writes to partition table region not allowed
TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, esp_flash_write(NULL, buffer, CONFIG_PARTITION_TABLE_OFFSET, sizeof(buffer)));
}
#endif //!CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS

View File

@@ -1,2 +1,4 @@
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_SPI_FLASH_ROM_IMPL=y
# Unrelated to rom, but to test if the boundary checking works well
CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED=y

View File

@@ -1,4 +1,6 @@
CONFIG_ESP_TASK_WDT=n
CONFIG_ESP_TASK_WDT_INIT=n
CONFIG_SPI_FLASH_VERIFY_WRITE=y
CONFIG_SPI_FLASH_LOG_FAILED_WRITE=y
CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE=y
# Unrelated to verify, but to test if the boundary checking works well
CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED=y

View File

@@ -370,4 +370,37 @@ TEST_CASE("test read & write encrypted data with large buffer in ram", "[flash_e
free(buf);
}
#if CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS
#elif CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED
TEST_CASE("Test flash encrypted write over boundary", "[flash_encryption]")
{
esp_flash_t* chip = NULL;
uint32_t flash_size;
esp_err_t err = esp_flash_get_size(chip, &flash_size);
TEST_ESP_OK(err);
const uint32_t SECTOR_SIZE = 4096;
uint8_t buf[0];
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 0, flash_size+SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, SECTOR_SIZE, flash_size));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size/2, flash_size/2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size/2 + SECTOR_SIZE, flash_size/2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, 2 * SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, 2 * SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, flash_size - SECTOR_SIZE, UINT32_MAX - SECTOR_SIZE + 1));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_erase_region(chip, UINT32_MAX - SECTOR_SIZE + 1, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, 0, buf, flash_size+SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, SECTOR_SIZE, buf, flash_size));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size/2, buf, flash_size/2 + SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size/2 + SECTOR_SIZE, buf, flash_size/2));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size - SECTOR_SIZE, buf, 2 * SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, 2 * SECTOR_SIZE, buf, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size - SECTOR_SIZE, buf, flash_size - SECTOR_SIZE));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, flash_size - SECTOR_SIZE, buf, UINT32_MAX - SECTOR_SIZE + 1));
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_flash_write_encrypted(chip, UINT32_MAX - SECTOR_SIZE + 1, buf, flash_size - SECTOR_SIZE));
}
#endif //CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS
#endif // CONFIG_SECURE_FLASH_ENC_ENABLED

View File

@@ -3,3 +3,5 @@ CONFIG_SPI_FLASH_ROM_IMPL=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
# Unrelated to rom, but to test if the boundary checking works well
CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED=y

View File

@@ -17,3 +17,6 @@ CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
CONFIG_SPI_FLASH_VERIFY_WRITE=y
CONFIG_SPI_FLASH_LOG_FAILED_WRITE=y
CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE=y
# Unrelated to verify, but to test if the boundary checking works well
CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED=y

View File

@@ -1,4 +1,4 @@
CONFIG_ESP_TASK_WDT=n
CONFIG_ESP_TASK_WDT_INIT=n
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@@ -1,3 +1,3 @@
CONFIG_ESP_TASK_WDT=n
CONFIG_ESP_TASK_WDT_INIT=n
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"

View File

@@ -60,6 +60,7 @@ static struct eap_sm *gEapSm = NULL;
static int eap_peer_sm_init(void);
static void eap_peer_sm_deinit(void);
static void eap_start_eapol(void *ctx, void *data);
static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid);
static int wpa2_start_eapol_internal(void);
@@ -529,6 +530,10 @@ static int eap_sm_rx_eapol_internal(u8 *src_addr, u8 *buf, u32 len, uint8_t *bss
return ESP_FAIL;
}
if (!sm->eap_process_started) {
sm->eap_process_started = true;
eloop_cancel_timeout(eap_start_eapol, NULL, NULL);
}
if (len < sizeof(*hdr) + sizeof(*ehdr)) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA "
"EAPOL-Key (len %lu, expecting at least %lu)",
@@ -612,15 +617,28 @@ _out:
return ret;
}
static int wpa2_start_eapol(void)
static void eap_start_eapol(void *ctx, void *data)
{
#ifdef USE_WPA2_TASK
return wpa2_post(SIG_WPA2_START, 0);
wpa2_post(SIG_WPA2_START, 0);
#else
return wpa2_start_eapol_internal();
wpa2_start_eapol_internal();
#endif
}
static int eap_start_eapol_timer(void)
{
/*
* Do not send EAPOL-Start immediately since in most cases,
* Authenticator is going to start authentication immediately
* after association and an extra EAPOL-Start is just going to
* delay authentication. Use a short timeout to send the first
* EAPOL-Start if Authenticator does not start authentication.
*/
eloop_register_timeout(2, 0, eap_start_eapol, NULL, NULL);
return 0;
}
static int wpa2_start_eapol_internal(void)
{
struct eap_sm *sm = gEapSm;
@@ -739,6 +757,7 @@ static int eap_peer_sm_init(void)
wpa_printf(MSG_INFO, "wifi_task prio:%d, stack:%d", WPA2_TASK_PRIORITY, WPA2_TASK_STACK_SIZE);
#endif
sm->workaround = 1;
sm->eap_process_started = false;
return ESP_OK;
_err:
@@ -806,7 +825,7 @@ static esp_err_t esp_client_enable_fn(void *arg)
}
wpa2_cb->wpa2_sm_rx_eapol = wpa2_ent_rx_eapol;
wpa2_cb->wpa2_start = wpa2_start_eapol;
wpa2_cb->wpa2_start = eap_start_eapol_timer;
wpa2_cb->wpa2_init = eap_peer_sm_init;
wpa2_cb->wpa2_deinit = eap_peer_sm_deinit;

View File

@@ -311,6 +311,7 @@ struct eap_sm {
size_t eapKeyDataLen;
struct wpabuf *lastRespData;
const struct eap_method *m;
bool eap_process_started;
};
typedef enum {

View File

@@ -104,6 +104,7 @@ static void eap_wsc_reset(struct eap_sm *sm, void *priv)
//wps_deinit(data->wps);
os_free(data);
#ifdef ESP_SUPPLICANT
sm->eap_method_priv = NULL;
/* TODO: When wps-registrar is shifted in a separate task other than wifi task,
* call esp_wifi_ap_wps_disable() here instead of wifi_ap_wps_disable_internal()
* */

View File

@@ -2287,7 +2287,7 @@ void wpa_set_profile(u32 wpa_proto, u8 auth_mode)
struct wpa_sm *sm = &gWpaSm;
sm->proto = wpa_proto;
if (auth_mode == WPA2_AUTH_ENT) {
if (auth_mode == WPA2_AUTH_ENT || (auth_mode == WPA_AUTH_UNSPEC)) {
sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X; /* for wpa2 enterprise */
} else if (auth_mode == WPA2_AUTH_ENT_SHA256) {
sm->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; /* for wpa2 enterprise sha256 */
@@ -2386,7 +2386,7 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher,
}
#ifdef CONFIG_SUITEB192
extern bool g_wpa_suiteb_certification;
if (g_wpa_suiteb_certification) {
if (is_wpa2_enterprise_connection() && g_wpa_suiteb_certification) {
if (sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256) {
wpa_printf(MSG_ERROR, "suite-b 192bit certification, only GMAC256 is supported");
return -1;

View File

@@ -13,14 +13,18 @@
import logging
import os
import re
import signal
import sys
import time
import xml.etree.ElementTree as ET
from fnmatch import fnmatch
from typing import Any
from typing import Callable
from typing import List
from typing import Optional
from typing import Tuple
import pexpect
import pytest
from _pytest.config import Config
from _pytest.config import ExitCode
@@ -34,8 +38,11 @@ from _pytest.terminal import TerminalReporter
from pytest_embedded.plugin import multi_dut_argument
from pytest_embedded.plugin import multi_dut_fixture
from pytest_embedded.utils import find_by_suffix
from pytest_embedded.utils import to_bytes
from pytest_embedded.utils import to_str
from pytest_embedded_idf.dut import IdfDut
from pytest_embedded_idf.unity_tester import CaseTester
from pytest_embedded_jtag._telnetlib.telnetlib import Telnet # python 3.13 removed telnetlib, use this instead
try:
from idf_ci_utils import to_list
@@ -49,6 +56,12 @@ except ImportError:
sys.path.append(os.path.join(os.path.dirname(__file__), 'tools', 'ci', 'python_packages'))
import common_test_methods # noqa: F401
try:
from idf_py_actions.debug_ext import get_openocd_arguments
except ModuleNotFoundError:
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from idf_py_actions.debug_ext import get_openocd_arguments
SUPPORTED_TARGETS = ['esp32', 'esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32h2']
PREVIEW_TARGETS: List[str] = [] # this PREVIEW_TARGETS excludes 'linux' target
DEFAULT_SDKCONFIG = 'default'
@@ -256,6 +269,103 @@ def test_case_name(request: FixtureRequest, target: str, config: str) -> str:
return format_case_id(target, config, request.node.originalname)
class OpenOCD:
def __init__(self, dut: 'IdfDut'):
self.MAX_RETRIES = 3
self.RETRY_DELAY = 1
self.TELNET_PORT = 4444
self.dut = dut
self.telnet: Optional[Telnet] = None
self.log_file = os.path.join(self.dut.logdir, 'ocd.txt')
self.proc: Optional[pexpect.spawn] = None
def __enter__(self) -> 'OpenOCD':
return self
def __exit__(self, exception_type: Any, exception_value: Any, exception_traceback: Any) -> None:
self.kill()
def run(self) -> Optional['OpenOCD']:
openocd_scripts = os.getenv('OPENOCD_SCRIPTS')
if not openocd_scripts:
raise RuntimeError('OPENOCD_SCRIPTS environment variable is not set.')
debug_args = get_openocd_arguments(self.dut.target)
assert debug_args
# For debug purposes, make the value '4'
ocd_env = os.environ.copy()
ocd_env['LIBUSB_DEBUG'] = '1'
for _ in range(1, self.MAX_RETRIES + 1):
try:
self.proc = pexpect.spawn(
command='openocd',
args=['-s', openocd_scripts] + debug_args.split(),
timeout=5,
encoding='utf-8',
codec_errors='ignore',
env=ocd_env,
)
if self.proc and self.proc.isalive():
self.proc.expect_exact('Info : Listening on port 3333 for gdb connections', timeout=5)
self.connect_telnet()
self.write('log_output {}'.format(self.log_file))
return self
except (pexpect.exceptions.EOF, pexpect.exceptions.TIMEOUT, ConnectionRefusedError) as e:
logging.error('Error running OpenOCD: %s', str(e))
self.kill()
time.sleep(self.RETRY_DELAY)
raise RuntimeError('Failed to run OpenOCD after %d attempts.', self.MAX_RETRIES)
def connect_telnet(self) -> None:
for attempt in range(1, self.MAX_RETRIES + 1):
try:
self.telnet = Telnet('127.0.0.1', self.TELNET_PORT, 5)
break
except ConnectionRefusedError as e:
logging.error('Error telnet connection: %s in attempt:%d', e, attempt)
time.sleep(1)
else:
raise ConnectionRefusedError
def write(self, s: str) -> Any:
if self.telnet is None:
logging.error('Telnet connection is not established.')
return ''
resp = self.telnet.read_very_eager()
self.telnet.write(to_bytes(s, '\n'))
resp += self.telnet.read_until(b'>')
return to_str(resp)
def apptrace_wait_stop(self, timeout: int = 30) -> None:
stopped = False
end_before = time.time() + timeout
while not stopped:
cmd_out = self.write('esp apptrace status')
for line in cmd_out.splitlines():
if line.startswith('Tracing is STOPPED.'):
stopped = True
break
if not stopped and time.time() > end_before:
raise pexpect.TIMEOUT('Failed to wait for apptrace stop!')
time.sleep(1)
def kill(self) -> None:
# Check if the process is still running
if self.proc and self.proc.isalive():
self.proc.terminate()
self.proc.kill(signal.SIGKILL)
@pytest.fixture
def openocd_dut(dut: IdfDut) -> OpenOCD:
if isinstance(dut, tuple):
raise ValueError('Multi-DUT support is not implemented yet')
return OpenOCD(dut)
@pytest.fixture
@multi_dut_fixture
def build_dir(app_path: str, target: Optional[str], config: Optional[str]) -> str:

View File

@@ -35,3 +35,4 @@ Bugfixes Introduced in ESP-IDF but not in Chip-ROM
:esp32s3: - Fixed issue that only 16MB virtual address ranges can be mapped to read-only data on Flash.
:esp32c3: - Fixed issue that only 128KB virtual address ranges can be mapped to instructions on Flash.
:esp32c2: - Fixed issue that only at most 128KB virtual address ranges can be mapped to instructions on Flash.
- Fixed issue that address range may escape from checking for erasing and writing function when their sum overflows 32-bit boundary.

View File

@@ -157,7 +157,9 @@ SPI Flash can be accessed by SPI1 (ESP-IDF `esp_flash` driver APIs), or by point
Thread Safety
=============
APIs in `esp_mmu_map.h` are not guaranteed to be thread-safe.
Following APIs in ``esp_mmu_map.h`` are not guaranteed to be thread-safe:
- :cpp:func:`esp_mmu_map_dump_mapped_blocks`
APIs in `esp_cache.h` are guaranteed to be thread-safe.

View File

@@ -9,6 +9,5 @@ if(${target} STREQUAL "linux")
endif()
idf_component_register(SRCS "esp_http_client_example.c"
INCLUDE_DIRS "."
REQUIRES ${requires}
EMBED_TXTFILES howsmyssl_com_root_cert.pem
postman_root_cert.pem)
PRIV_REQUIRES ${requires}
EMBED_TXTFILES howsmyssl_com_root_cert.pem)

View File

@@ -47,9 +47,6 @@ static const char *TAG = "HTTP_CLIENT";
extern const char howsmyssl_com_root_cert_pem_start[] asm("_binary_howsmyssl_com_root_cert_pem_start");
extern const char howsmyssl_com_root_cert_pem_end[] asm("_binary_howsmyssl_com_root_cert_pem_end");
extern const char postman_root_cert_pem_start[] asm("_binary_postman_root_cert_pem_start");
extern const char postman_root_cert_pem_end[] asm("_binary_postman_root_cert_pem_end");
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
static char *output_buffer; // Buffer to store response of http request from event handler
@@ -598,7 +595,7 @@ static void https_async(void)
esp_http_client_config_t config = {
.url = "https://postman-echo.com/post",
.event_handler = _http_event_handler,
.cert_pem = postman_root_cert_pem_start,
.crt_bundle_attach = esp_crt_bundle_attach,
.is_async = true,
.timeout_ms = 5000,
};

View File

@@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----

View File

@@ -36,12 +36,6 @@ examples/system/flash_suspend:
temporary: true
reason: the other targets are not tested yet
examples/system/gcov:
disable_test:
- if: IDF_TARGET == "esp32s3"
temporary: true
reason: unstable, known data corruption issue #TODO: OCD-1048
examples/system/gdbstub:
disable:
- if: IDF_TARGET == "esp32c2" or IDF_TARGET == "esp32h2"
@@ -138,18 +132,10 @@ examples/system/select:
examples/system/sysview_tracing:
disable:
- if: SOC_GPTIMER_SUPPORTED != 1
disable_test:
- if: IDF_TARGET != "esp32"
temporary: true
reason: lack of runners
examples/system/sysview_tracing_heap_log:
disable:
- if: SOC_GPTIMER_SUPPORTED != 1
disable_test:
- if: IDF_TARGET != "esp32"
temporary: true
reason: lack of runners
examples/system/task_watchdog:
disable_test:

View File

@@ -1,120 +1,18 @@
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import logging
import os
import signal
import sys
import time
from telnetlib import Telnet
from typing import Any
from typing import Optional
import typing
import pexpect
import pytest
from pytest_embedded.utils import to_bytes
from pytest_embedded.utils import to_str
from pytest_embedded_idf import IdfDut
try:
from idf_py_actions.debug_ext import get_openocd_arguments
except ModuleNotFoundError:
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from idf_py_actions.debug_ext import get_openocd_arguments
MAX_RETRIES = 3
RETRY_DELAY = 1
TELNET_PORT = 4444
if typing.TYPE_CHECKING:
from conftest import OpenOCD
class OpenOCD:
def __init__(self, dut: 'IdfDut'):
self.dut = dut
self.telnet: Optional[Telnet] = None
self.log_file = os.path.join(self.dut.logdir, 'ocd.txt')
self.proc: Optional[pexpect.spawn] = None
def run(self) -> Optional['OpenOCD']:
openocd_scripts = os.getenv('OPENOCD_SCRIPTS')
if not openocd_scripts:
logging.error('OPENOCD_SCRIPTS environment variable is not set.')
return None
debug_args = get_openocd_arguments(self.dut.target)
assert debug_args
# For debug purposes, make the value '4'
ocd_env = os.environ.copy()
ocd_env['LIBUSB_DEBUG'] = '1'
for _ in range(1, MAX_RETRIES + 1):
try:
self.proc = pexpect.spawn(
command='openocd',
args=['-s', openocd_scripts] + debug_args.split(),
timeout=5,
encoding='utf-8',
codec_errors='ignore',
env=ocd_env,
)
if self.proc and self.proc.isalive():
self.proc.expect_exact('Info : Listening on port 3333 for gdb connections', timeout=5)
return self
except (pexpect.exceptions.EOF, pexpect.exceptions.TIMEOUT) as e:
logging.error('Error running OpenOCD: %s', str(e))
if self.proc and self.proc.isalive():
self.proc.terminate()
time.sleep(RETRY_DELAY)
logging.error('Failed to run OpenOCD after %d attempts.', MAX_RETRIES)
return None
def connect_telnet(self) -> None:
for attempt in range(1, MAX_RETRIES + 1):
try:
self.telnet = Telnet('127.0.0.1', TELNET_PORT, 5)
break
except ConnectionRefusedError as e:
logging.error('Error telnet connection: %s in attempt:%d', e, attempt)
time.sleep(1)
else:
raise ConnectionRefusedError
def write(self, s: str) -> Any:
if self.telnet is None:
logging.error('Telnet connection is not established.')
return ''
resp = self.telnet.read_very_eager()
self.telnet.write(to_bytes(s, '\n'))
resp += self.telnet.read_until(b'>')
return to_str(resp)
def apptrace_wait_stop(self, timeout: int = 30) -> None:
stopped = False
end_before = time.time() + timeout
while not stopped:
cmd_out = self.write('esp apptrace status')
for line in cmd_out.splitlines():
if line.startswith('Tracing is STOPPED.'):
stopped = True
break
if not stopped and time.time() > end_before:
raise pexpect.TIMEOUT('Failed to wait for apptrace stop!')
time.sleep(1)
def kill(self) -> None:
# Check if the process is still running
if self.proc and self.proc.isalive():
self.proc.terminate()
self.proc.kill(signal.SIGKILL)
def _test_examples_app_trace_basic(dut: IdfDut) -> None:
def _test_examples_app_trace_basic(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
dut.expect_exact('example: Waiting for OpenOCD connection', timeout=5)
openocd = OpenOCD(dut).run()
assert openocd
try:
openocd.connect_telnet()
openocd.write('log_output {}'.format(openocd.log_file))
with openocd_dut.run() as openocd:
openocd.write('reset run')
dut.expect_exact('example: Waiting for OpenOCD connection', timeout=5)
time.sleep(1) # wait for APPTRACE_INIT semihosting call
@@ -145,16 +43,14 @@ def _test_examples_app_trace_basic(dut: IdfDut) -> None:
break
if found is not True:
raise RuntimeError('"{}" could not be found in {}'.format(log_str, 'apptrace.log'))
finally:
openocd.kill()
@pytest.mark.esp32
@pytest.mark.esp32c2
@pytest.mark.esp32s2
@pytest.mark.esp32c2
@pytest.mark.jtag
def test_examples_app_trace_basic(dut: IdfDut) -> None:
_test_examples_app_trace_basic(dut)
def test_examples_app_trace_basic(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
_test_examples_app_trace_basic(openocd_dut, dut)
@pytest.mark.esp32s3
@@ -162,5 +58,5 @@ def test_examples_app_trace_basic(dut: IdfDut) -> None:
@pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.usb_serial_jtag
def test_examples_app_trace_basic_usj(dut: IdfDut) -> None:
_test_examples_app_trace_basic(dut)
def test_examples_app_trace_basic_usj(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
_test_examples_app_trace_basic(openocd_dut, dut)

View File

@@ -1,123 +1,22 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import logging
import os
import signal
import sys
import os.path
import time
from telnetlib import Telnet
from typing import Any
from typing import Optional
import typing
import pexpect
import pytest
from pytest_embedded.utils import to_bytes
from pytest_embedded.utils import to_str
from pytest_embedded_idf import IdfDut
try:
from idf_py_actions.debug_ext import get_openocd_arguments
except ModuleNotFoundError:
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from idf_py_actions.debug_ext import get_openocd_arguments
MAX_RETRIES = 3
RETRY_DELAY = 1
TELNET_PORT = 4444
if typing.TYPE_CHECKING:
from conftest import OpenOCD
class OpenOCD:
def __init__(self, dut: 'IdfDut'):
self.dut = dut
self.telnet: Optional[Telnet] = None
self.log_file = os.path.join(self.dut.logdir, 'ocd.txt')
self.proc: Optional[pexpect.spawn] = None
def run(self) -> Optional['OpenOCD']:
openocd_scripts = os.getenv('OPENOCD_SCRIPTS')
if not openocd_scripts:
logging.error('OPENOCD_SCRIPTS environment variable is not set.')
return None
debug_args = get_openocd_arguments(self.dut.target)
assert debug_args
# For debug purposes, make the value '4'
ocd_env = os.environ.copy()
ocd_env['LIBUSB_DEBUG'] = '1'
for _ in range(1, MAX_RETRIES + 1):
try:
self.proc = pexpect.spawn(
command='openocd',
args=['-s', openocd_scripts] + debug_args.split(),
timeout=5,
encoding='utf-8',
codec_errors='ignore',
env=ocd_env,
)
if self.proc and self.proc.isalive():
self.proc.expect_exact('Info : Listening on port 3333 for gdb connections', timeout=5)
return self
except (pexpect.exceptions.EOF, pexpect.exceptions.TIMEOUT) as e:
logging.error('Error running OpenOCD: %s', str(e))
if self.proc and self.proc.isalive():
self.proc.terminate()
time.sleep(RETRY_DELAY)
logging.error('Failed to run OpenOCD after %d attempts.', MAX_RETRIES)
return None
def connect_telnet(self) -> None:
for attempt in range(1, MAX_RETRIES + 1):
try:
self.telnet = Telnet('127.0.0.1', TELNET_PORT, 5)
break
except ConnectionRefusedError as e:
logging.error('Error telnet connection: %s in attempt:%d', e, attempt)
time.sleep(1)
else:
raise ConnectionRefusedError
def write(self, s: str) -> Any:
if self.telnet is None:
logging.error('Telnet connection is not established.')
return ''
resp = self.telnet.read_very_eager()
self.telnet.write(to_bytes(s, '\n'))
resp += self.telnet.read_until(b'>')
return to_str(resp)
def apptrace_wait_stop(self, timeout: int = 30) -> None:
stopped = False
end_before = time.time() + timeout
while not stopped:
cmd_out = self.write('esp apptrace status')
for line in cmd_out.splitlines():
if line.startswith('Tracing is STOPPED.'):
stopped = True
break
if not stopped and time.time() > end_before:
raise pexpect.TIMEOUT('Failed to wait for apptrace stop!')
time.sleep(1)
def kill(self) -> None:
# Check if the process is still running
if self.proc and self.proc.isalive():
self.proc.terminate()
self.proc.kill(signal.SIGKILL)
def _test_gcov(dut: IdfDut) -> None:
def _test_gcov(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
# create the generated .gcda folder, otherwise would have error: failed to open file.
# normally this folder would be created via `idf.py build`. but in CI the non-related files would not be preserved
os.makedirs(os.path.join(dut.app.binary_path, 'esp-idf', 'main', 'CMakeFiles', '__idf_main.dir'), exist_ok=True)
os.makedirs(os.path.join(dut.app.binary_path, 'esp-idf', 'sample', 'CMakeFiles', '__idf_sample.dir'), exist_ok=True)
dut.expect_exact('example: Ready for OpenOCD connection', timeout=5)
openocd = OpenOCD(dut).run()
assert openocd
def expect_counter_output(loop: int, timeout: int = 10) -> None:
dut.expect_exact(
[f'blink_dummy_func: Counter = {loop}', f'some_dummy_func: Counter = {loop * 2}'],
@@ -147,9 +46,8 @@ def _test_gcov(dut: IdfDut) -> None:
assert len(expect_lines) == 0
try:
openocd.connect_telnet()
openocd.write('log_output {}'.format(openocd.log_file))
dut.expect_exact('example: Ready for OpenOCD connection', timeout=5)
with openocd_dut.run() as openocd:
openocd.write('reset run')
dut.expect_exact('example: Ready for OpenOCD connection', timeout=5)
@@ -171,21 +69,20 @@ def _test_gcov(dut: IdfDut) -> None:
time.sleep(1)
# Test instant run-time dump
dump_coverage('esp gcov')
finally:
openocd.kill()
@pytest.mark.jtag
@pytest.mark.esp32
@pytest.mark.esp32c2
@pytest.mark.esp32s2
def test_gcov(dut: IdfDut) -> None:
_test_gcov(dut)
def test_gcov(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
_test_gcov(openocd_dut, dut)
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.usb_serial_jtag
def test_gcov_usj(dut: IdfDut) -> None:
_test_gcov(dut)
def test_gcov_usj(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
_test_gcov(openocd_dut, dut)

View File

@@ -133,11 +133,13 @@ static void example_task(void *p)
void app_main(void)
{
ESP_LOGI(TAG, "Ready for OpenOCD connection");
static example_event_data_t event_data[portNUM_PROCESSORS];
#if CONFIG_APPTRACE_SV_ENABLE && CONFIG_USE_CUSTOM_EVENT_ID
// Currently OpenOCD does not support requesting module info from target. So do the following...
// Wait untill SystemView module receives START command from host,
// Wait until SystemView module receives START command from host,
// after that data can be sent to the host using onboard API,
// so user module description does not need to be requested by OpenOCD itself.
while (!SEGGER_SYSVIEW_Started()) {

View File

@@ -1,47 +1,70 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import os.path
import re
import time
import typing
import pexpect.fdpexpect
import pexpect
import pytest
from pytest_embedded_idf import IdfDut
if typing.TYPE_CHECKING:
from conftest import OpenOCD
def _test_examples_sysview_tracing(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
# Construct trace log paths
trace_log = [
os.path.join(dut.logdir, 'sys_log0.svdat') # pylint: disable=protected-access
]
if not dut.app.sdkconfig.get('ESP_SYSTEM_SINGLE_CORE_MODE') or dut.target == 'esp32s3':
trace_log.append(os.path.join(dut.logdir, 'sys_log1.svdat')) # pylint: disable=protected-access
trace_files = ' '.join([f'file://{log}' for log in trace_log])
# Prepare gdbinit file
gdb_logfile = os.path.join(dut.logdir, 'gdb.txt')
gdbinit_orig = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'gdbinit')
gdbinit = os.path.join(dut.logdir, 'gdbinit')
with open(gdbinit_orig, 'r') as f_r, open(gdbinit, 'w') as f_w:
for line in f_r:
if line.startswith('mon esp sysview start'):
f_w.write(f'mon esp sysview start {trace_files}\n')
else:
f_w.write(line)
@pytest.mark.esp32
@pytest.mark.jtag
@pytest.mark.parametrize(
'embedded_services',
[
'esp,idf,jtag',
],
indirect=True,
)
def test_examples_sysview_tracing(dut: IdfDut) -> None:
def dut_expect_task_event() -> None:
dut.expect(re.compile(rb'example: Task\[0x3[0-9A-Fa-f]+\]: received event \d+'), timeout=30)
dut.gdb.write('mon reset halt')
dut.gdb.write('maintenance flush register-cache')
dut.gdb.write('b app_main')
dut.gdb.write('commands', non_blocking=True)
dut.gdb.write(
'mon esp sysview start file:///tmp/sysview_example0.svdat file:///tmp/sysview_example1.svdat', non_blocking=True
)
dut.gdb.write('c', non_blocking=True)
dut.gdb.write('end')
dut.gdb.write('c', non_blocking=True)
time.sleep(1) # to avoid EOF file error
with open(dut.gdb._logfile) as fr: # pylint: disable=protected-access
gdb_pexpect_proc = pexpect.fdpexpect.fdspawn(fr.fileno())
gdb_pexpect_proc.expect('Thread 2 "main" hit Breakpoint 1, app_main ()')
dut.expect(re.compile(rb'example: Task\[0x[0-9A-Fa-f]+\]: received event \d+'), timeout=30)
dut.expect_exact('example: Ready for OpenOCD connection', timeout=5)
with openocd_dut.run() as openocd, open(gdb_logfile, 'w') as gdb_log, pexpect.spawn(
f'idf.py -B {dut.app.binary_path} gdb --batch --gdbinit {gdbinit}',
timeout=60,
logfile=gdb_log,
encoding='utf-8',
codec_errors='ignore',
) as p:
p.expect_exact('hit Breakpoint 1, app_main ()')
dut.expect('example: Created task') # dut has been restarted by gdb since the last dut.expect()
dut_expect_task_event()
# Do a sleep while sysview samples are captured.
time.sleep(3)
# GDB isn't responding now to any commands, therefore, the following command is issued to openocd
dut.openocd.write('esp sysview stop')
openocd.write('esp sysview stop')
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32c2
@pytest.mark.jtag
def test_examples_sysview_tracing(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
_test_examples_sysview_tracing(openocd_dut, dut)
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.usb_serial_jtag
def test_examples_sysview_tracing_usj(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
_test_examples_sysview_tracing(openocd_dut, dut)

View File

@@ -1,5 +1,3 @@
# Enable single core mode by default
CONFIG_FREERTOS_UNICORE=y
# 1ms tick period
CONFIG_FREERTOS_HZ=1000
# Enable application tracing by default

View File

@@ -72,6 +72,8 @@ static void alloc_task(void *p)
void app_main(void)
{
ESP_LOGI(TAG, "Ready for OpenOCD connection");
const int num_allocers = 3;
char task_name[20];
// redirect log messages to the host using SystemView tracing module

View File

@@ -1,47 +1,46 @@
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import os.path
import time
import typing
import pexpect.fdpexpect
import pytest
from pytest_embedded_idf import IdfDut
if typing.TYPE_CHECKING:
from conftest import OpenOCD
@pytest.mark.esp32
@pytest.mark.jtag
@pytest.mark.parametrize('config', ['app_trace_jtag'], indirect=True)
@pytest.mark.parametrize('embedded_services', ['esp,idf,jtag'], indirect=True)
def test_examples_sysview_tracing_heap_log(idf_path: str, dut: IdfDut) -> None:
def _test_examples_sysview_tracing_heap_log(openocd_dut: 'OpenOCD', idf_path: str, dut: IdfDut) -> None:
# Construct trace log paths
trace_log = [
os.path.join(os.path.dirname(dut.gdb._logfile), 'heap_log0.svdat') # pylint: disable=protected-access
os.path.join(dut.logdir, 'heap_log0.svdat') # pylint: disable=protected-access
]
if dut.target in ['esp32', 'esp32s3', 'esp32p4']:
trace_log.append(os.path.join(os.path.dirname(dut.gdb._logfile), 'heap_log1.svdat')) # pylint: disable=protected-access
# Set up GDB
dut.gdb.write('set width unlimited') # Don't split output lines for easy parsing
dut.gdb.write('mon reset halt')
dut.gdb.write('maintenance flush register-cache')
# Start sysview tracing
dut.gdb.write('tb heap_trace_start')
dut.gdb.write('commands', non_blocking=True)
if not dut.app.sdkconfig.get('ESP_SYSTEM_SINGLE_CORE_MODE') or dut.target == 'esp32s3':
trace_log.append(os.path.join(dut.logdir, 'heap_log1.svdat')) # pylint: disable=protected-access
trace_files = ' '.join([f'file://{log}' for log in trace_log])
dut.gdb.write(f'mon esp sysview start {trace_files}', non_blocking=True)
dut.gdb.write('c', non_blocking=True)
dut.gdb.write('end')
# Stop sysview tracing
dut.gdb.write('tb heap_trace_stop')
dut.gdb.write('commands', non_blocking=True)
dut.gdb.write('mon esp sysview stop', non_blocking=True)
dut.gdb.write('end')
dut.gdb.write('c', non_blocking=True)
# Prepare gdbinit file
gdb_logfile = os.path.join(dut.logdir, 'gdb.txt')
gdbinit_orig = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'gdbinit')
gdbinit = os.path.join(dut.logdir, 'gdbinit')
with open(gdbinit_orig, 'r') as f_r, open(gdbinit, 'w') as f_w:
for line in f_r:
if line.startswith('mon esp sysview start'):
f_w.write(f'mon esp sysview start {trace_files}\n')
else:
f_w.write(line)
# Wait for sysview files to be generated
time.sleep(1)
dut.expect_exact('example: Ready for OpenOCD connection', timeout=5)
with openocd_dut.run(), open(gdb_logfile, 'w') as gdb_log, pexpect.spawn(
f'idf.py -B {dut.app.binary_path} gdb --batch --gdbinit {gdbinit}',
timeout=60,
logfile=gdb_log,
encoding='utf-8',
codec_errors='ignore',
) as p:
# Wait for sysview files to be generated
p.expect_exact('Tracing is STOPPED')
# Process sysview trace logs
command = [os.path.join(idf_path, 'tools', 'esp_app_trace', 'sysviewtrace_proc.py'), '-p'] + trace_log
@@ -49,8 +48,27 @@ def test_examples_sysview_tracing_heap_log(idf_path: str, dut: IdfDut) -> None:
sysviewtrace.expect(r'Found \d+ leaked bytes in \d+ blocks.', timeout=120)
# Validate GDB logs
with open(dut.gdb._logfile) as fr: # pylint: disable=protected-access
with open(gdb_logfile) as fr: # pylint: disable=protected-access
gdb_pexpect_proc = pexpect.fdpexpect.fdspawn(fr.fileno())
gdb_pexpect_proc.expect_exact(
'Thread 2 "main" hit Temporary breakpoint 1, heap_trace_start (mode_param=HEAP_TRACE_ALL)', timeout=10)
'Thread 2 "main" hit Temporary breakpoint 1, heap_trace_start (mode_param', timeout=10)
gdb_pexpect_proc.expect_exact('Thread 2 "main" hit Temporary breakpoint 2, heap_trace_stop ()', timeout=10)
@pytest.mark.parametrize('config', ['app_trace_jtag'], indirect=True)
@pytest.mark.jtag
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32c2
def test_examples_sysview_tracing_heap_log(openocd_dut: 'OpenOCD', idf_path: str, dut: IdfDut) -> None:
_test_examples_sysview_tracing_heap_log(openocd_dut, idf_path, dut)
@pytest.mark.parametrize('config', ['app_trace_jtag'], indirect=True)
@pytest.mark.usb_serial_jtag
@pytest.mark.esp32s3
@pytest.mark.esp32c3
@pytest.mark.esp32c6
@pytest.mark.esp32h2
def test_examples_sysview_tracing_heap_log_usj(openocd_dut: 'OpenOCD', idf_path: str, dut: IdfDut) -> None:
_test_examples_sysview_tracing_heap_log(openocd_dut, idf_path, dut)

View File

@@ -42,6 +42,11 @@
"rev": 3,
"build_date_str_addr": "0x3ff1a374",
"build_date_str": "Feb 7 2021"
},
{
"rev": 101,
"build_date_str_addr": "0x3ff1a3dc",
"build_date_str": "Mar 1 2023"
}
],
"esp32c6": [

View File

@@ -1,25 +1,18 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import logging
import os
import re
import subprocess
import sys
import typing
import pexpect
import pytest
from pytest_embedded_idf import IdfDut
try:
from idf_py_actions.debug_ext import get_openocd_arguments
except ModuleNotFoundError:
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from idf_py_actions.debug_ext import get_openocd_arguments
if typing.TYPE_CHECKING:
from conftest import OpenOCD
@pytest.mark.supported_targets
@pytest.mark.jtag
def test_idf_gdb(dut: IdfDut) -> None:
def _test_idf_gdb(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
# Need to wait a moment to connect via OpenOCD after the hard reset happened.
# Along with this check that app runs ok
dut.expect('Hello world!')
@@ -27,29 +20,34 @@ def test_idf_gdb(dut: IdfDut) -> None:
# Don't need to have output from UART anymore
dut.serial.stop_redirect_thread()
with open(os.path.join(dut.logdir, 'ocd.txt'), 'w') as ocd_log:
cmd = ['openocd', *get_openocd_arguments(dut.target).split()]
openocd_scripts = os.getenv('OPENOCD_SCRIPTS')
if openocd_scripts:
cmd.extend(['-s', openocd_scripts])
gdb_env = os.environ.copy()
gdb_env['ESP_IDF_GDB_TESTING'] = '1'
logging.info('Running %s', cmd)
ocd = subprocess.Popen(cmd, stdout=ocd_log, stderr=ocd_log)
with openocd_dut.run(), open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, pexpect.spawn(
f'idf.py -B {dut.app.binary_path} gdb --batch',
env=gdb_env,
timeout=60,
logfile=gdb_log,
encoding='utf-8',
codec_errors='ignore',
) as p:
p.expect(re.compile(r'add symbol table from file.*bootloader.elf'))
p.expect(re.compile(r'add symbol table from file.*rom.elf'))
p.expect_exact('hit Temporary breakpoint 1, app_main ()')
try:
gdb_env = os.environ.copy()
gdb_env['ESP_IDF_GDB_TESTING'] = '1'
with open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, \
pexpect.spawn(f'idf.py -B {dut.app.binary_path} gdb --batch',
env=gdb_env,
timeout=60,
logfile=gdb_log,
encoding='utf-8',
codec_errors='ignore') as p:
p.expect(re.compile(r'add symbol table from file.*bootloader.elf'))
p.expect(re.compile(r'add symbol table from file.*rom.elf'))
p.expect_exact('hit Temporary breakpoint 1, app_main ()')
finally:
ocd.terminate()
ocd.kill()
@pytest.mark.jtag
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32c2
def test_idf_gdb(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
_test_idf_gdb(openocd_dut, dut)
@pytest.mark.usb_serial_jtag
@pytest.mark.esp32c3
@pytest.mark.esp32s3
@pytest.mark.esp32c6
@pytest.mark.esp32h2
def test_idf_gdb_usj(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
_test_idf_gdb(openocd_dut, dut)