mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-07 03:48:49 +00:00
Compare commits
38 Commits
0c4a4ef019
...
3e9fdf085f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3e9fdf085f | ||
![]() |
1f37e2776a | ||
![]() |
b63fa75d66 | ||
![]() |
e0d824a721 | ||
![]() |
a96fb81744 | ||
![]() |
9c3469d612 | ||
![]() |
26307750da | ||
![]() |
97429efba8 | ||
![]() |
4a67ad9eca | ||
![]() |
b0947e3639 | ||
![]() |
2c4e2255e9 | ||
![]() |
ab3034f72d | ||
![]() |
1264331285 | ||
![]() |
9f524203d8 | ||
![]() |
3afd8f8b19 | ||
![]() |
53e113f87a | ||
![]() |
c7b762c455 | ||
![]() |
f34978b594 | ||
![]() |
92a6718847 | ||
![]() |
ed9266b194 | ||
![]() |
8b50310ae8 | ||
![]() |
aa0344c054 | ||
![]() |
076e6e9ad6 | ||
![]() |
f6d9263ecf | ||
![]() |
3b1916ad06 | ||
![]() |
da56c54d0b | ||
![]() |
b8ab882ab2 | ||
![]() |
3cbf1d7ab3 | ||
![]() |
2b66f127fd | ||
![]() |
7d9b355c18 | ||
![]() |
72d648b292 | ||
![]() |
ff73ef0bb1 | ||
![]() |
e46d033d1d | ||
![]() |
c2dd5c35e0 | ||
![]() |
8cee39c53c | ||
![]() |
84c6a7f596 | ||
![]() |
43b4810f56 | ||
![]() |
34e8b36239 |
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
Submodule components/bt/controller/lib_esp32 updated: b8a08a0680...185c7205db
@@ -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;
|
||||
|
@@ -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, ¶m);
|
||||
}
|
||||
}
|
||||
@@ -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, ¶m);
|
||||
break;
|
||||
default:
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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 {
|
||||
|
@@ -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(®ion->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(®ion->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;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Submodule components/esp_phy/lib updated: fc76520d48...96a56a29a3
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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) */
|
||||
|
@@ -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 );
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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 );
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
||||
|
Submodule components/esp_wifi/lib updated: e6c344109c...a34ac915ef
24
components/newlib/platform_include/stdatomic.h
Normal file
24
components/newlib/platform_include/stdatomic.h
Normal 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
|
@@ -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) \
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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"
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -311,6 +311,7 @@ struct eap_sm {
|
||||
size_t eapKeyDataLen;
|
||||
struct wpabuf *lastRespData;
|
||||
const struct eap_method *m;
|
||||
bool eap_process_started;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
@@ -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()
|
||||
* */
|
||||
|
@@ -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;
|
||||
|
110
conftest.py
110
conftest.py
@@ -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:
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -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-----
|
@@ -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:
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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()) {
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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": [
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user