mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
core dump: move stack into the internal memory when dumping to flash
Since SPI flash operations can not be performed when the stack is in external RAM, we need to switch to a different stack when doing a core dump to flash. This is achieved by a pair of longjmp's, one of which is crafted manually to jump into a designated function with a specific stack set up. The cost of this feature is a bit of IRAM, plus the DRAM required for the extra stack. Closes AUD-1355
This commit is contained in:
parent
a80cf2dc69
commit
de662d5e11
@ -621,11 +621,7 @@ static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
|
||||
disableAllWdts();
|
||||
s_dumping_core = true;
|
||||
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
|
||||
if (esp_ptr_external_ram(get_sp())) {
|
||||
panicPutStr("Stack in PSRAM, skipping core dump to Flash.")
|
||||
} else {
|
||||
esp_core_dump_to_flash(frame);
|
||||
}
|
||||
esp_core_dump_to_flash(frame);
|
||||
#endif
|
||||
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART && !CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
esp_core_dump_to_uart(frame);
|
||||
|
@ -6,6 +6,7 @@ set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
|
||||
set(COMPONENT_SRCS "src/core_dump_common.c"
|
||||
"src/core_dump_flash.c"
|
||||
"src/core_dump_port.c"
|
||||
"src/core_dump_uart.c")
|
||||
"src/core_dump_uart.c"
|
||||
"src/core_dump_flash_newstack.c")
|
||||
|
||||
register_component()
|
||||
|
@ -4,4 +4,5 @@ entries:
|
||||
core_dump_uart (noflash_text)
|
||||
core_dump_flash (noflash_text)
|
||||
core_dump_common (noflash_text)
|
||||
core_dump_port (noflash_text)
|
||||
core_dump_port (noflash_text)
|
||||
core_dump_flash_newstack (noflash_text)
|
||||
|
@ -25,7 +25,7 @@ const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_commo
|
||||
static esp_err_t esp_core_dump_write_binary(void *frame, core_dump_write_config_t *write_cfg)
|
||||
{
|
||||
esp_err_t err;
|
||||
core_dump_task_header_t tasks[CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM];
|
||||
static core_dump_task_header_t tasks[CONFIG_ESP32_CORE_DUMP_MAX_TASKS_NUM];
|
||||
uint32_t tcb_sz, task_num, tcb_sz_padded;
|
||||
bool task_is_valid = false;
|
||||
uint32_t data_len = 0, i;
|
||||
|
@ -198,8 +198,13 @@ static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
||||
#define esp_core_dump_to_flash esp_core_dump_to_flash_inner
|
||||
#endif // CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
||||
|
||||
void esp_core_dump_to_flash(XtExcFrame *frame)
|
||||
{
|
||||
ESP_COREDUMP_LOGI("%s called with sp: %p frame: %p", __func__, get_sp(), frame);
|
||||
core_dump_write_config_t wr_cfg;
|
||||
core_dump_write_flash_data_t wr_data;
|
||||
|
||||
@ -228,5 +233,5 @@ void esp_core_dump_to_flash(XtExcFrame *frame)
|
||||
esp_core_dump_write((void*)frame, &wr_cfg);
|
||||
ESP_COREDUMP_LOGI("Core dump has been saved to flash.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
|
||||
|
82
components/espcoredump/src/core_dump_flash_newstack.c
Normal file
82
components/espcoredump/src/core_dump_flash_newstack.c
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <string.h>
|
||||
#include "soc/soc.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#include "esp_core_dump_priv.h"
|
||||
|
||||
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
||||
|
||||
const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_flash_newstack";
|
||||
|
||||
/* Temporary stack used by the core dump; Stack size is chosen to be sufficient in case logging is enabled. */
|
||||
#define CORE_DUMP_STACK_SIZE 1024
|
||||
static uint8_t __attribute__((aligned(16))) core_dump_stack[CORE_DUMP_STACK_SIZE];
|
||||
|
||||
/* This jmp_buf is used to jump *into* switch_stack_helper function, simultaneously setting
|
||||
* the stack pointer to the temporary stack. It is initialized manually, not using setjmp.
|
||||
*/
|
||||
static jmp_buf switch_stack_jmp;
|
||||
|
||||
/* This jmp_buf is used to return to the original stack (in external RAM) after the core dump is done. */
|
||||
static jmp_buf return_jmp;
|
||||
|
||||
/* Internals of jmp_buf for Xtensa Window ABI. See setjmp.S for details */
|
||||
struct jmp_buf_impl {
|
||||
int regs[12];
|
||||
int save[4];
|
||||
void *return_address;
|
||||
};
|
||||
|
||||
/* Defined in core_dump_flash.c if CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is set */
|
||||
extern void esp_core_dump_to_flash_inner(XtExcFrame *frame);
|
||||
|
||||
/* We are going to jump to switch_stack_helper+3 (i.e. past the ENTRY instruction)
|
||||
* using longjmp(switch_stack_jmp). Execution will start on the temporary stack.
|
||||
*/
|
||||
static void switch_stack_helper(void* arg)
|
||||
{
|
||||
/* Using the new stack now, can perform the core dump */
|
||||
esp_core_dump_to_flash_inner((XtExcFrame*) arg);
|
||||
/* Jump back to where setjmp(return_jmp) was called, switching to the original stack */
|
||||
longjmp(return_jmp, 1);
|
||||
}
|
||||
|
||||
void esp_core_dump_to_flash(XtExcFrame *frame)
|
||||
{
|
||||
if (esp_ptr_external_ram(get_sp())) {
|
||||
ESP_COREDUMP_LOGI("Stack in external RAM, switching to new stack %p - %p", core_dump_stack, core_dump_stack + sizeof(core_dump_stack));
|
||||
/* Prepare new stack */
|
||||
uint32_t* stack_top = (uint32_t*) (core_dump_stack + sizeof(core_dump_stack)/sizeof(core_dump_stack[0]));
|
||||
stack_top -= 4;
|
||||
/* Prepare jmp_buf to jump into the switch_stack_helper, simultaneously switching to the new stack */
|
||||
struct jmp_buf_impl* jb = (struct jmp_buf_impl*) &switch_stack_jmp;
|
||||
jb->regs[1] = (int) stack_top; /* SP */
|
||||
jb->regs[2] = (int) frame; /* function argument (a2) */
|
||||
jb->save[1] = ((int)stack_top) + 32; /* pointer to base save area for the current frame */
|
||||
jb->return_address = ((uint8_t*)&switch_stack_helper) + 3; /* First instruction of switch_stack_helper, after ENTRY */
|
||||
|
||||
/* Set up return_jmp for returning here */
|
||||
if (!setjmp(return_jmp)) {
|
||||
longjmp(switch_stack_jmp, 1);
|
||||
}
|
||||
} else {
|
||||
ESP_COREDUMP_LOGI("Stack in DRAM");
|
||||
esp_core_dump_to_flash_inner(frame);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
|
@ -20,9 +20,9 @@ const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_port"
|
||||
|
||||
#if CONFIG_ESP32_ENABLE_COREDUMP
|
||||
|
||||
inline bool esp_task_stack_start_is_sane(uint32_t sp)
|
||||
static inline bool esp_task_stack_start_is_sane(uint32_t sp)
|
||||
{
|
||||
return !(sp < 0x3ffae010UL || sp > 0x3fffffffUL);
|
||||
return esp_ptr_in_dram((const void*)sp) || esp_ptr_external_ram((const void*)sp);
|
||||
}
|
||||
|
||||
inline bool esp_tcb_addr_is_sane(uint32_t addr, uint32_t sz)
|
||||
|
Loading…
x
Reference in New Issue
Block a user