mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/setjmp_longjmp_4.0' into 'release/v4.0'
[system]: Made longjmp save for context switch (backport v4.0) See merge request espressif/esp-idf!13503
This commit is contained in:
commit
0242438e9d
@ -32,4 +32,6 @@ CFLAGS += -D BOOTLOADER_BUILD=1
|
|||||||
# include the top-level "project" include directory, for sdkconfig.h
|
# include the top-level "project" include directory, for sdkconfig.h
|
||||||
CFLAGS += -I$(BUILD_DIR_BASE)/../include
|
CFLAGS += -I$(BUILD_DIR_BASE)/../include
|
||||||
|
|
||||||
|
COMPONENT_ADD_LDFLAGS += -l$(COMPONENT_NAME) -Wl,--wrap=longjmp \
|
||||||
|
|
||||||
include $(IDF_PATH)/make/project.mk
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
@ -9,7 +9,7 @@ if(BOOTLOADER_BUILD)
|
|||||||
target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}")
|
target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}")
|
||||||
else()
|
else()
|
||||||
# Regular app build
|
# Regular app build
|
||||||
idf_component_register(SRCS "esp_rom.c"
|
idf_component_register(SRCS "esp_rom.c" "patches/esp_rom_longjmp.S"
|
||||||
INCLUDE_DIRS include)
|
INCLUDE_DIRS include)
|
||||||
|
|
||||||
set(scripts
|
set(scripts
|
||||||
@ -35,4 +35,6 @@ else()
|
|||||||
if(NOT CONFIG_SPI_FLASH_ROM_DRIVER_PATCH)
|
if(NOT CONFIG_SPI_FLASH_ROM_DRIVER_PATCH)
|
||||||
target_linker_script(${COMPONENT_LIB} INTERFACE "esp32/ld/esp32.rom.spiflash.ld")
|
target_linker_script(${COMPONENT_LIB} INTERFACE "esp32/ld/esp32.rom.spiflash.ld")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=longjmp")
|
||||||
endif()
|
endif()
|
||||||
|
@ -24,7 +24,10 @@ ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
|
|||||||
LINKER_SCRIPTS += esp32.rom.spiflash.ld
|
LINKER_SCRIPTS += esp32.rom.spiflash.ld
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
COMPONENT_SRCDIRS := patches
|
||||||
|
|
||||||
COMPONENT_ADD_LDFLAGS += -L $(COMPONENT_PATH)/esp32/ld \
|
COMPONENT_ADD_LDFLAGS += -L $(COMPONENT_PATH)/esp32/ld \
|
||||||
$(addprefix -T ,$(LINKER_SCRIPTS)) \
|
$(addprefix -T ,$(LINKER_SCRIPTS)) \
|
||||||
|
-l$(COMPONENT_NAME) -Wl,--wrap=longjmp \
|
||||||
|
|
||||||
COMPONENT_ADD_LINKER_DEPS += $(addprefix esp32/ld/, $(LINKER_SCRIPTS))
|
COMPONENT_ADD_LINKER_DEPS += $(addprefix esp32/ld/, $(LINKER_SCRIPTS))
|
||||||
|
71
components/esp_rom/patches/esp_rom_longjmp.S
Normal file
71
components/esp_rom/patches/esp_rom_longjmp.S
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2001-2006 by Tensilica Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file contains a modified version of the original Xtensa longjmp implementation.
|
||||||
|
In this modified version, setting WINDOWSTART = 1 << WINDOWBASE is done inside a critical section.
|
||||||
|
This is necessary because after a FreeRTOS context switch in IDF, the values of WINDOWBASE and WINDOWSTART
|
||||||
|
are not guaranteed to be the same as before the context switch.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xtensa/corebits.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replacement of the first instructions of void longjmp (jmp_buf env, int val)
|
||||||
|
*/
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.literal_position
|
||||||
|
.global __wrap_longjmp
|
||||||
|
.type __wrap_longjmp, @function
|
||||||
|
__wrap_longjmp:
|
||||||
|
entry sp, 16
|
||||||
|
|
||||||
|
/* Deactivate interrupts in order to modify WINDOWBASE and WINDOWSTART. */
|
||||||
|
rsr a7, PS /* to be restored after SPILL_ALL_WINDOWS */
|
||||||
|
movi a5, PS_EXCM /* PS_INTLEVEL_MASK */
|
||||||
|
or a5, a7, a5 /* get the current INTLEVEL */
|
||||||
|
wsr a5, PS
|
||||||
|
|
||||||
|
/* Invalidate all but the current window;
|
||||||
|
set WindowStart to (1 << WindowBase). */
|
||||||
|
rsr a5, WINDOWBASE
|
||||||
|
movi a4, 1
|
||||||
|
ssl a5
|
||||||
|
sll a4, a4
|
||||||
|
wsr a4, WINDOWSTART
|
||||||
|
rsync
|
||||||
|
|
||||||
|
/* Activate interrupts again after modifying WINDOWBASE and WINDOWSTART. */
|
||||||
|
wsr a7, PS
|
||||||
|
|
||||||
|
/* Jump back to original longjmp implementation.
|
||||||
|
The jump target is the instrucion
|
||||||
|
l32i a0, a2, 64
|
||||||
|
of the original code. Hence, the original code's entry instruction and windowstart modification are left
|
||||||
|
out.
|
||||||
|
*/
|
||||||
|
movi a0, __real_longjmp + 20
|
||||||
|
jx a0
|
||||||
|
|
||||||
|
.size __wrap_longjmp, . - __wrap_longjmp
|
@ -3,4 +3,3 @@ COMPONENT_ADD_INCLUDEDIRS := include esp32/include
|
|||||||
COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/esp32/libhal.a
|
COMPONENT_ADD_LDFLAGS += $(COMPONENT_PATH)/esp32/libhal.a
|
||||||
|
|
||||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||||
|
|
||||||
|
6
tools/test_apps/system/longjmp_test/CMakeLists.txt
Normal file
6
tools/test_apps/system/longjmp_test/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(hello-world)
|
8
tools/test_apps/system/longjmp_test/Makefile
Normal file
8
tools/test_apps/system/longjmp_test/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||||
|
# project subdirectory.
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT_NAME := longjmp_test
|
||||||
|
|
||||||
|
include $(IDF_PATH)/make/project.mk
|
13
tools/test_apps/system/longjmp_test/README.md
Normal file
13
tools/test_apps/system/longjmp_test/README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
| Supported Targets | ESP32 | ESP32-S2 |
|
||||||
|
| ----------------- | ----- | -------- |
|
||||||
|
|
||||||
|
# Building
|
||||||
|
Example building for ESP32:
|
||||||
|
```
|
||||||
|
idf.py set-target esp32
|
||||||
|
cp sdkconfig.defaults sdkconfig
|
||||||
|
idf.py build
|
||||||
|
```
|
||||||
|
|
||||||
|
# Running
|
||||||
|
All the setup needs to be done as described in the [test apps README](../../README.md).
|
18
tools/test_apps/system/longjmp_test/app_test.py
Normal file
18
tools/test_apps/system/longjmp_test/app_test.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import ttfw_idf
|
||||||
|
from tiny_test_fw import Utility
|
||||||
|
|
||||||
|
|
||||||
|
@ttfw_idf.idf_custom_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2'], group='test-apps')
|
||||||
|
def test_longjmp(env, _):
|
||||||
|
|
||||||
|
dut = env.get_dut('longjmp_test', 'tools/test_apps/system/longjmp_test')
|
||||||
|
dut.start_app()
|
||||||
|
dut.expect('Test successful', 15)
|
||||||
|
|
||||||
|
Utility.console_log('longjmp test done.')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_longjmp()
|
2
tools/test_apps/system/longjmp_test/main/CMakeLists.txt
Normal file
2
tools/test_apps/system/longjmp_test/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "hello_world_main.c"
|
||||||
|
INCLUDE_DIRS "")
|
5
tools/test_apps/system/longjmp_test/main/component.mk
Normal file
5
tools/test_apps/system/longjmp_test/main/component.mk
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#
|
||||||
|
# "main" pseudo-component makefile.
|
||||||
|
#
|
||||||
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||||
|
|
117
tools/test_apps/system/longjmp_test/main/hello_world_main.c
Normal file
117
tools/test_apps/system/longjmp_test/main/hello_world_main.c
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/* test longjmp
|
||||||
|
|
||||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, this
|
||||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_spi_flash.h"
|
||||||
|
#include <esp_task.h>
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#define LUAI_NOIPA __attribute__((__noipa__))
|
||||||
|
#define LUAI_THROW(c) longjmp((c)->b, 1)
|
||||||
|
#define LUAI_TRY(c,a) if (setjmp((c)->b) == 0) { a }
|
||||||
|
|
||||||
|
#define TIMEOUT 50
|
||||||
|
|
||||||
|
#define RECURSION 19
|
||||||
|
|
||||||
|
static esp_timer_handle_t crash_timer;
|
||||||
|
|
||||||
|
static uint32_t result = 0;
|
||||||
|
|
||||||
|
uint32_t calc_fac(uint32_t n) {
|
||||||
|
if (n == 1 || n == 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return n * calc_fac(n - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_cb(void *arg) {
|
||||||
|
result = calc_fac(RECURSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
jmp_buf b;
|
||||||
|
} jmp_ctx;
|
||||||
|
|
||||||
|
LUAI_NOIPA
|
||||||
|
static void pret(jmp_ctx *jc) {
|
||||||
|
LUAI_THROW(jc);
|
||||||
|
}
|
||||||
|
|
||||||
|
LUAI_NOIPA
|
||||||
|
static void precurse(jmp_ctx *jc, int n) {
|
||||||
|
if (n) precurse(jc, n - 1);
|
||||||
|
else pret(jc);
|
||||||
|
}
|
||||||
|
|
||||||
|
LUAI_NOIPA
|
||||||
|
static void ptest(jmp_ctx *jc) {
|
||||||
|
precurse(jc, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
LUAI_NOIPA
|
||||||
|
void pcall(void (*func)(jmp_ctx *ctx)) {
|
||||||
|
jmp_ctx jc;
|
||||||
|
LUAI_TRY(&jc,
|
||||||
|
ptest(&jc);
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sjlj_task(void *ctx) {
|
||||||
|
uint32_t start = xTaskGetTickCount();
|
||||||
|
for (;;) {
|
||||||
|
pcall(ptest);
|
||||||
|
uint32_t end = xTaskGetTickCount();
|
||||||
|
|
||||||
|
uint32_t dt = end - start;
|
||||||
|
if (dt >= 1000) {
|
||||||
|
start = end;
|
||||||
|
|
||||||
|
printf("[%u] sjlj tick %d\n", end, (int)ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end > 9800) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
const esp_timer_create_args_t timer_args = {
|
||||||
|
timer_cb,
|
||||||
|
NULL,
|
||||||
|
ESP_TIMER_TASK,
|
||||||
|
"crash_timer",
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_timer_create(&timer_args, &crash_timer);
|
||||||
|
esp_timer_start_periodic(crash_timer, TIMEOUT);
|
||||||
|
|
||||||
|
printf("Hello world!\n");
|
||||||
|
printf("Free heap: %d\n", esp_get_free_heap_size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 16; i++) {
|
||||||
|
xTaskCreate(sjlj_task, "sjlj_task", 4096, (void *) i, tskIDLE_PRIORITY + 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(10000);
|
||||||
|
printf("stopping timers...\n");
|
||||||
|
esp_timer_stop(crash_timer);
|
||||||
|
esp_timer_delete(crash_timer);
|
||||||
|
|
||||||
|
printf("Test successful\n");
|
||||||
|
}
|
11
tools/test_apps/system/longjmp_test/sdkconfig.defaults
Normal file
11
tools/test_apps/system/longjmp_test/sdkconfig.defaults
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
CONFIG_COMPILER_OPTIMIZATION_PERF=y
|
||||||
|
|
||||||
|
CONFIG_ESP_INT_WDT=n
|
||||||
|
CONFIG_ESP_TASK_WDT=n
|
||||||
|
|
||||||
|
CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
|
||||||
|
|
||||||
|
CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584
|
||||||
|
|
||||||
|
CONFIG_FREERTOS_UNICORE=y
|
||||||
|
CONFIG_FREERTOS_HZ=1000
|
Loading…
Reference in New Issue
Block a user