#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
-//#include "esp_attr.h"
#include "esp_panic.h"
#include "esp_partition.h"
// TODO: allow user to set this in menuconfig or get tasks iteratively
#define COREDUMP_MAX_TASKS_NUM 32
-typedef esp_err_t (*esp_core_dump_write_prepare_t)(void *priv, uint32_t *data_len);
-typedef esp_err_t (*esp_core_dump_write_start_t)(void *priv);
-typedef esp_err_t (*esp_core_dump_write_end_t)(void *priv);
-typedef esp_err_t (*esp_core_dump_flash_write_data_t)(void *priv, void * data, uint32_t data_len);
+typedef esp_err_t (*esp_core_dump_write_prepare_t)(void *priv, uint32_t *data_len, int verb);
+typedef esp_err_t (*esp_core_dump_write_start_t)(void *priv, int verb);
+typedef esp_err_t (*esp_core_dump_write_end_t)(void *priv, int verb);
+typedef esp_err_t (*esp_core_dump_flash_write_data_t)(void *priv, void * data, uint32_t data_len, int verb);
typedef struct _core_dump_write_config_t
{
if (tasks[i].pxTCB == xTaskGetCurrentTaskHandle()) {
// set correct stack top for current task
tasks[i].pxTopOfStack = (StackType_t *)frame;
+ if (verb)
+ ets_printf("Current task EXIT/PC/PS/A0/SP %x %x %x %x %x\r\n", frame->exit, frame->pc, frame->ps, frame->a0, frame->a1);
+ }
+ else {
if (verb) {
- esp_panicPutStr("Current task PC/A0/SP ");
- esp_panicPutHex(frame->pc);
- esp_panicPutStr(" ");
- esp_panicPutHex(frame->a0);
- esp_panicPutStr(" ");
- esp_panicPutHex(frame->a1);
- esp_panicPutStr("\r\n");
+ XtSolFrame *task_frame = (XtSolFrame *)tasks[i].pxTopOfStack;
+ if (task_frame->exit == 0) {
+ ets_printf("Task EXIT/PC/PS/A0/SP %x %x %x %x %x\r\n", task_frame->exit, task_frame->pc, task_frame->ps, task_frame->a0, task_frame->a1);
+ }
+ else {
+ XtExcFrame *task_frame2 = (XtExcFrame *)tasks[i].pxTopOfStack;
+ ets_printf("Task EXIT/PC/PS/A0/SP %x %x %x %x %x\r\n", task_frame2->exit, task_frame2->pc, task_frame2->ps, task_frame2->a0, task_frame2->a1);
+ }
}
}
#if( portSTACK_GROWTH < 0 )
len = (uint32_t)tasks[i].pxTopOfStack - (uint32_t)tasks[i].pxEndOfStack;
#endif
if (verb) {
- esp_panicPutStr("stack len = ");
- esp_panicPutHex(len);
- esp_panicPutStr(" ");
- esp_panicPutHex((int)tasks[i].pxTopOfStack);
- esp_panicPutStr(" ");
- esp_panicPutHex((int)tasks[i].pxEndOfStack);
- esp_panicPutStr("\r\n");
+ ets_printf("Stack len = %lu (%x %x)\r\n", len, tasks[i].pxTopOfStack, tasks[i].pxEndOfStack);
}
// take stack padding into account
if (len % sizeof(uint32_t))
// prepare write
if (write_cfg->prepare) {
- err = write_cfg->prepare(write_cfg->priv, &data_len);
+ err = write_cfg->prepare(write_cfg->priv, &data_len, verb);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to prepare core dump ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to prepare core dump (%d)!\r\n", err);
return;
}
}
if (verb) {
- esp_panicPutStr("Core dump len =");
- esp_panicPutHex(data_len);
- esp_panicPutStr("\r\n");
+ ets_printf("Core dump len = %lu\r\n", data_len);
}
- // write start marker
+ // write start
if (write_cfg->start) {
- err = write_cfg->start(write_cfg->priv);
+ err = write_cfg->start(write_cfg->priv, verb);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to start core dump ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to start core dump (%d)!\r\n", err);
return;
}
}
rom_data.data32[0] = data_len;
rom_data.data32[1] = task_num;
rom_data.data32[2] = tcb_sz;
- err = write_cfg->write(write_cfg->priv, &rom_data, 3*sizeof(uint32_t));
+ err = write_cfg->write(write_cfg->priv, &rom_data, 3*sizeof(uint32_t), verb);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to write core dump header ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to write core dump header (%d)!\r\n", err);
return;
}
// write tasks
for (i = 0; i < task_num; i++) {
if (verb) {
- esp_panicPutStr("Dump task ");
- esp_panicPutHex((int)tasks[i].pxTCB);
- esp_panicPutStr("\r\n");
+ ets_printf("Dump task %x\r\n", tasks[i].pxTCB);
}
// save TCB address, stack base and stack top addr
rom_data.data32[0] = (uint32_t)tasks[i].pxTCB;
rom_data.data32[1] = (uint32_t)tasks[i].pxTopOfStack;
rom_data.data32[2] = (uint32_t)tasks[i].pxEndOfStack;
- err = write_cfg->write(write_cfg->priv, &rom_data, 3*sizeof(uint32_t));
+ err = write_cfg->write(write_cfg->priv, &rom_data, 3*sizeof(uint32_t), verb);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to write task header ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to write task header (%d)!\r\n", err);
return;
}
// save TCB
- err = write_cfg->write(write_cfg->priv, tasks[i].pxTCB, tcb_sz);
+ err = write_cfg->write(write_cfg->priv, tasks[i].pxTCB, tcb_sz, verb);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to write task header ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to write TCB (%d)!\r\n", err);
return;
}
// save task stack
- /*int k;
- for (k = 0; k < 8*4; k++) {
- esp_panicPutStr("stack[");
- esp_panicPutDec(k);
- esp_panicPutStr("] = ");
- esp_panicPutHex(((uint8_t *)tasks[i].pxTopOfStack)[k]);
- esp_panicPutStr("\r\n");
- }*/
err = write_cfg->write(write_cfg->priv,
#if( portSTACK_GROWTH < 0 )
tasks[i].pxTopOfStack,
tasks[i].pxEndOfStack,
(uint32_t)tasks[i].pxTopOfStack - (uint32_t)tasks[i].pxEndOfStack
#endif
- );
+ , verb);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to write task header ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to write task stack (%d)!\r\n", err);
return;
}
}
- // write end marker
+ // write end
if (write_cfg->end) {
- err = write_cfg->end(write_cfg->priv);
+ err = write_cfg->end(write_cfg->priv, verb);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to end core dump ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to end core dump (%d)!\r\n", err);
return;
}
}
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
// magic numbers to control core dump data consistency
-#define COREDUMP_FLASH_MAGIC_START 0xDEADBEEFUL
-#define COREDUMP_FLASH_MAGIC_END 0xACDCFEEDUL
+#define COREDUMP_FLASH_MAGIC_START 0xE32C04EDUL
+#define COREDUMP_FLASH_MAGIC_END 0xE32C04EDUL
typedef struct _core_dump_write_flash_data_t
{
} rom_data;
data_len = (data_size / sizeof(uint32_t)) * sizeof(uint32_t);
- err = spi_flash_write_panic(off, data, data_len);
+ err = spi_flash_write(off, data, data_len);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to write data");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to write data to flash (%d)!\r\n", err);
return 0;
}
rom_data.data32 = 0;
for (k = 0; k < len; k++)
rom_data.data8[k] = *(data + data_len + k);
- err = spi_flash_write_panic(off + data_len, &rom_data, sizeof(uint32_t));
+ err = spi_flash_write(off + data_len, &rom_data, sizeof(uint32_t));
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to write data end");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to finish write data to flash (%d)!\r\n", err);
return 0;
}
data_len += sizeof(uint32_t);
return data_len;
}
-static esp_err_t esp_core_dump_flash_write_prepare(void *priv, uint32_t *data_len)
+static esp_err_t esp_core_dump_flash_write_prepare(void *priv, uint32_t *data_len, int verb)
{
esp_err_t err;
uint32_t sec_num;
core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
- esp_panicPutStr("Core dump len1 = ");
- esp_panicPutHex(*data_len);
- esp_panicPutStr("\r\n");
-
// add space for 2 magics. TODO: change to CRC
- *data_len += 2*sizeof(uint32_t);
- if (*data_len > s_core_part_size) {
- esp_panicPutStr("ERROR: Not enough space to save core dump!");
+ if ((*data_len + 2*sizeof(uint32_t)) > s_core_part_size) {
+ ets_printf("ERROR: Not enough space to save core dump!\r\n");
return ESP_ERR_NO_MEM;
}
-
- esp_panicPutStr("Core dump len2 = ");
- esp_panicPutHex(*data_len);
- esp_panicPutStr("\r\n");
+ *data_len += 2*sizeof(uint32_t);
wr_data->off = 0;
sec_num = *data_len / SPI_FLASH_SEC_SIZE;
if (*data_len % SPI_FLASH_SEC_SIZE)
sec_num++;
- err = spi_flash_erase_range_panic(s_core_part_start + 0, sec_num * SPI_FLASH_SEC_SIZE);
+ err = spi_flash_erase_range(s_core_part_start + 0, sec_num * SPI_FLASH_SEC_SIZE);
if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to erase flash ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to erase flash (%d)!\r\n", err);
return err;
}
esp_err_t err = ESP_OK;
uint32_t data32 = word;
- err = spi_flash_write_panic(s_core_part_start + wr_data->off, &data32, sizeof(uint32_t));
+ err = spi_flash_write(s_core_part_start + wr_data->off, &data32, sizeof(uint32_t));
if (err != ESP_OK) {
- esp_panicPutStr("Failed to write to flash ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
+ ets_printf("ERROR: Failed to write to flash (%d)!\r\n", err);
return err;
}
wr_data->off += sizeof(uint32_t);
return err;
}
-static esp_err_t esp_core_dump_flash_write_start(void *priv)
+static esp_err_t esp_core_dump_flash_write_start(void *priv, int verb)
{
core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
// save magic 1
return esp_core_dump_flash_write_word(wr_data, COREDUMP_FLASH_MAGIC_START);
}
-static esp_err_t esp_core_dump_flash_write_end(void *priv)
+static esp_err_t esp_core_dump_flash_write_end(void *priv, int verb)
{
core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
uint32_t i;
uint32_t data32[4];
} rom_data;
- // TEST READ START
- esp_err_t err = spi_flash_read_panic(s_core_part_start + 0, &rom_data, sizeof(rom_data));
- if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to read flash ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
- return err;
- }
- else {
- esp_panicPutStr("Data from flash:\r\n");
- for (i = 0; i < sizeof(rom_data)/sizeof(rom_data.data32[0]); i++) {
- esp_panicPutHex(rom_data.data32[i]);
- esp_panicPutStr("\r\n");
+ if (verb) {
+ // TEST READ START
+ esp_err_t err = spi_flash_read(s_core_part_start + 0, &rom_data, sizeof(rom_data));
+ if (err != ESP_OK) {
+ ets_printf("ERROR: Failed to read flash (%d)!\r\n", err);
+ return err;
+ }
+ else {
+ ets_printf("Data from flash:\r\n");
+ for (i = 0; i < sizeof(rom_data)/sizeof(rom_data.data32[0]); i++) {
+ ets_printf("%x\r\n", rom_data.data32[i]);
+ }
}
-// rom_data[4] = 0;
-// esp_panicPutStr(rom_data);
-// esp_panicPutStr("\r\n");
+ // TEST READ END
}
- // TEST READ END
// save magic 2
return esp_core_dump_flash_write_word(wr_data, COREDUMP_FLASH_MAGIC_END);
}
-static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_t data_len)
+static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_t data_len, int verb)
{
esp_err_t err = ESP_OK;
core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
*/
void esp_core_dump_to_flash(XtExcFrame *frame)
{
-#if 1
core_dump_write_config_t wr_cfg;
core_dump_write_flash_data_t wr_data;
+ /* init non-OS flash access critical section */
+ spi_flash_guard_set(&g_flash_guard_no_os_ops);
+
wr_cfg.prepare = esp_core_dump_flash_write_prepare;
wr_cfg.start = esp_core_dump_flash_write_start;
wr_cfg.end = esp_core_dump_flash_write_end;
wr_cfg.write = esp_core_dump_flash_write_data;
wr_cfg.priv = &wr_data;
- esp_panicPutStr("Save core dump to flash...\r\n");
- esp_core_dump_write(frame, &wr_cfg, 1);
-#else
- union
- {
- uint8_t data8[16];
- uint32_t data32[4];
- } rom_data;
- //const esp_partition_t *core_part;
- esp_err_t err;
- TaskSnapshot_t tasks[COREDUMP_MAX_TASKS_NUM];
- UBaseType_t tcb_sz, task_num;
- uint32_t data_len = 0, i, len, sec_num;
- size_t off;
-
- esp_panicPutStr("Save core dump to flash...\r\n");
- task_num = uxTaskGetSnapshotAll(tasks, COREDUMP_MAX_TASKS_NUM, &tcb_sz);
- // take TCB padding into account, actual TCB size will be stored in header
- if (tcb_sz % sizeof(uint32_t))
- len = (tcb_sz / sizeof(uint32_t) + 1) * sizeof(uint32_t);
- else
- len = tcb_sz;
- // header + magic2 + tasknum*(tcb + stack start/end + tcb addr)
- data_len = 5*sizeof(uint32_t) + task_num*(len + 2*sizeof(uint32_t) + sizeof(uint32_t *));
- for (i = 0; i < task_num; i++) {
- if (tasks[i].pxTCB == xTaskGetCurrentTaskHandle()) {
- // set correct stack top for current task
- tasks[i].pxTopOfStack = (StackType_t *)frame;
- esp_panicPutStr("Current task PC/A0/SP ");
- esp_panicPutHex(frame->pc);
- esp_panicPutStr(" ");
- esp_panicPutHex(frame->a0);
- esp_panicPutStr(" ");
- esp_panicPutHex(frame->a1);
- esp_panicPutStr("\r\n");
- }
-#if( portSTACK_GROWTH < 0 )
- len = (uint32_t)tasks[i].pxEndOfStack - (uint32_t)tasks[i].pxTopOfStack;
-#else
- len = (uint32_t)tasks[i].pxTopOfStack - (uint32_t)tasks[i].pxEndOfStack;
-#endif
- esp_panicPutStr("stack len = ");
- esp_panicPutHex(len);
- esp_panicPutStr(" ");
- esp_panicPutHex((int)tasks[i].pxTopOfStack);
- esp_panicPutStr(" ");
- esp_panicPutHex((int)tasks[i].pxEndOfStack);
- esp_panicPutStr("\r\n");
- // take stack padding into account
- if (len % sizeof(uint32_t))
- len = (len / sizeof(uint32_t) + 1) * sizeof(uint32_t);
- data_len += len;
- }
- esp_panicPutStr("Core dump len =");
- esp_panicPutHex(data_len);
- esp_panicPutStr("\r\n");
- if (data_len > s_core_part_size) {
- esp_panicPutStr("ERROR: Not enough space to save core dump!");
- return;
- }
-
- // TEST READ START
- err = spi_flash_read_panic(s_core_part_start + 0, &rom_data, sizeof(rom_data));
- if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to read flash ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
- return;
- }
- else {
- esp_panicPutStr("Data from flash:\r\n");
- for (i = 0; i < sizeof(rom_data)/sizeof(rom_data.data32[0]); i++) {
- esp_panicPutHex(rom_data.data32[i]);
- esp_panicPutStr("\r\n");
- }
-// rom_data[4] = 0;
-// esp_panicPutStr(rom_data);
-// esp_panicPutStr("\r\n");
- }
- // TEST READ END
-
- sec_num = data_len / SPI_FLASH_SEC_SIZE;
- if (data_len % SPI_FLASH_SEC_SIZE)
- sec_num++;
- err = spi_flash_erase_range_panic(s_core_part_start + 0, sec_num * SPI_FLASH_SEC_SIZE);
- if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to erase flash ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
- return;
- }
-
- rom_data.data32[0] = COREDUMP_FLASH_MAGIC_START;
- rom_data.data32[1] = data_len;
- rom_data.data32[2] = task_num;
- rom_data.data32[3] = tcb_sz;
- err = spi_flash_write_panic(s_core_part_start + 0, &rom_data, sizeof(rom_data));
- if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to write core dump header ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
- return;
- }
- off = sizeof(rom_data);
-
- for (i = 0; i < task_num; i++) {
- esp_panicPutStr("Dump task ");
- esp_panicPutHex((int)tasks[i].pxTCB);
- esp_panicPutStr("\r\n");
-
- // save TCB address, stack base and stack top addr
- rom_data.data32[0] = (uint32_t)tasks[i].pxTCB;
- rom_data.data32[1] = (uint32_t)tasks[i].pxTopOfStack;
- rom_data.data32[2] = (uint32_t)tasks[i].pxEndOfStack;
- err = spi_flash_write_panic(s_core_part_start + off, &rom_data, 3*sizeof(uint32_t));
- if (err != ESP_OK) {
- esp_panicPutStr("ERROR: Failed to write task header ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
- return;
- }
- off += 3*sizeof(uint32_t);
- // save TCB
- len = esp_core_dump_write_flash_padded(s_core_part_start + off, tasks[i].pxTCB, tcb_sz);
- if (len == 0)
- return;
- off += len;
- // save task stack
- /*int k;
- for (k = 0; k < 8*4; k++) {
- esp_panicPutStr("stack[");
- esp_panicPutDec(k);
- esp_panicPutStr("] = ");
- esp_panicPutHex(((uint8_t *)tasks[i].pxTopOfStack)[k]);
- esp_panicPutStr("\r\n");
- }*/
- len = esp_core_dump_write_flash_padded(s_core_part_start + off,
-#if( portSTACK_GROWTH < 0 )
- tasks[i].pxTopOfStack,
- (uint32_t)tasks[i].pxEndOfStack - (uint32_t)tasks[i].pxTopOfStack
-#else
- tasks[i].pxEndOfStack,
- (uint32_t)tasks[i].pxTopOfStack - (uint32_t)tasks[i].pxEndOfStack
-#endif
- );
- if (len == 0)
- return;
- off += len;
- }
-
- rom_data.data32[0] = COREDUMP_FLASH_MAGIC_END;
- err = spi_flash_write_panic(s_core_part_start + off, &rom_data, sizeof(uint32_t));
- if (err != ESP_OK) {
- esp_panicPutStr("Failed to write to flash ");
- esp_panicPutHex(err);
- esp_panicPutStr("!\r\n");
- return;
- }
-#endif
- esp_panicPutStr("Core dump has been saved to flash.\r\n");
+ ets_printf("Save core dump to flash...\r\n");
+ esp_core_dump_write(frame, &wr_cfg, 0);
+ ets_printf("Core dump has been saved to flash.\r\n");
}
#endif
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART
-#if 0
-#define BASE64_ENCODE_BODY(_src, _src_len, _dst) \
- do { \
- static const char *b64 = \
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
- int i, j, a, b, c; \
- \
- for (i = j = 0; i < _src_len; i += 3) { \
- a = _src[i]; \
- b = i + 1 >= _src_len ? 0 : _src[i + 1]; \
- c = i + 2 >= _src_len ? 0 : _src[i + 2]; \
- \
- /*BASE64_OUT(b64[a >> 2], _dst[j]);*/ \
- _dst[j++] = b64[a >> 2]; \
- /*BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)], _dst[j]);*/ \
- _dst[j++] = b64[((a & 3) << 4) | (b >> 4)]; \
- j++; \
- if (i + 1 < _src_len) { \
- BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)], _dst[j]); \
- j++; \
- } \
- if (i + 2 < _src_len) { \
- BASE64_OUT(b64[c & 63], _dst[j]); \
- j++; \
- } \
- } \
- \
- while (j % 4 != 0) { \
- BASE64_OUT('=', _dst); \
- } \
- BASE64_FLUSH(_dst) \
- } while(0)
-
-#define BASE64_OUT(ch, _dst) \
- do { \
- _dst = (ch); \
- } while (0)
-
-#define BASE64_FLUSH(_dst) \
- do { \
- _dst = '\0'; \
- } while (0)
-#endif
static void esp_core_dump_b64_encode(const uint8_t *src, uint32_t src_len, uint8_t *dst) {
// BASE64_ENCODE_BODY(src, src_len, dst);
static const char *b64 =
dst[j++] = '\0';
}
-/*static esp_err_t esp_core_dump_uart_write_prepare(void *priv, uint32_t *data_len)
-{
- esp_err_t err = ESP_OK;
- return err;
-}*/
-
-static esp_err_t esp_core_dump_uart_write_start(void *priv)
+static esp_err_t esp_core_dump_uart_write_start(void *priv, int verb)
{
-// core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
esp_err_t err = ESP_OK;
- esp_panicPutStr("================= CORE DUMP START =================\r\n");
+ ets_printf("================= CORE DUMP START =================\r\n");
return err;
}
-static esp_err_t esp_core_dump_uart_write_end(void *priv)
+static esp_err_t esp_core_dump_uart_write_end(void *priv, int verb)
{
-// core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
esp_err_t err = ESP_OK;
- esp_panicPutStr("================= CORE DUMP END =================\r\n");
+ ets_printf("================= CORE DUMP END =================\r\n");
return err;
}
-static esp_err_t esp_core_dump_uart_write_data(void *priv, void * data, uint32_t data_len)
+static esp_err_t esp_core_dump_uart_write_data(void *priv, void * data, uint32_t data_len, int verb)
{
-// core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv;
esp_err_t err = ESP_OK;
char buf[64 + 4], *addr = data;
char *end = addr + data_len;
-// esp_panicPutStr("CORE DUMP SEC: ");
-// esp_panicPutDec(data_len);
-// esp_panicPutStr("bytes\r\n");
while (addr < end) {
size_t len = end - addr;
memcpy(tmp, addr, len);
esp_core_dump_b64_encode((const uint8_t *)tmp, len, (uint8_t *)buf);
addr += len;
- esp_panicPutStr(buf);
-// for (size_t i = 0; buf[i] != '\0'; i++) {
-// panicPutChar(buf[i]);
-// }
- //if (addr % 96 == 0)
- esp_panicPutStr("\r\n");
- /* Feed the Cerberus. */
-// TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
-// TIMERG0.wdt_feed = 1;
+ ets_printf("%s\r\n", buf);
}
return err;
void esp_core_dump_to_uart(XtExcFrame *frame)
{
core_dump_write_config_t wr_cfg;
- //core_dump_write_flash_data_t wr_data;
- wr_cfg.prepare = NULL;//esp_core_dump_uart_write_prepare;
+ wr_cfg.prepare = NULL;
wr_cfg.start = esp_core_dump_uart_write_start;
wr_cfg.end = esp_core_dump_uart_write_end;
wr_cfg.write = esp_core_dump_uart_write_data;
wr_cfg.priv = NULL;
- esp_panicPutStr("Save core dump to flash...\r\n");
+ ets_printf("Print core dump to uart...\r\n");
esp_core_dump_write(frame, &wr_cfg, 0);
- esp_panicPutStr("Core dump has been written to uart.\r\n");
+ ets_printf("Core dump has been written to uart.\r\n");
}
#endif
#endif
esp_ipc_init();
spi_flash_init();
+ /* init default OS-aware flash access critical section */
+ spi_flash_guard_set(&g_flash_guard_default_ops);
#if CONFIG_ESP32_PHY_AUTO_INIT
nvs_flash_init();
*/
void esp_set_breakpoint_if_jtag(void *fn);
-void esp_panicPutChar(char c);
-void esp_panicPutStr(const char *c);
-void esp_panicPutHex(int a);
-void esp_panicPutDec(int a);
#define ESP_WATCHPOINT_LOAD 0x40000000
#define ESP_WATCHPOINT_STORE 0x80000000
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
//printf may be broken, so we fix our own printing fns...
-void esp_panicPutChar(char c)
+static void panicPutChar(char c)
{
while (((READ_PERI_REG(UART_STATUS_REG(0)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ;
WRITE_PERI_REG(UART_FIFO_REG(0), c);
}
-void esp_panicPutStr(const char *c)
+static void panicPutStr(const char *c)
{
int x = 0;
while (c[x] != 0) {
- esp_panicPutChar(c[x]);
+ panicPutChar(c[x]);
x++;
}
}
-void esp_panicPutHex(int a)
+static void panicPutHex(int a)
{
int x;
int c;
for (x = 0; x < 8; x++) {
c = (a >> 28) & 0xf;
if (c < 10) {
- esp_panicPutChar('0' + c);
+ panicPutChar('0' + c);
} else {
- esp_panicPutChar('a' + c - 10);
+ panicPutChar('a' + c - 10);
}
a <<= 4;
}
}
-void esp_panicPutDec(int a)
+static void panicPutDec(int a)
{
int n1, n2;
n1 = a % 10;
n2 = a / 10;
if (n2 == 0) {
- esp_panicPutChar(' ');
+ panicPutChar(' ');
} else {
- esp_panicPutChar(n2 + '0');
+ panicPutChar(n2 + '0');
}
- esp_panicPutChar(n1 + '0');
+ panicPutChar(n1 + '0');
}
#else
//No printing wanted. Stub out these functions.
-void esp_panicPutChar(char c) { }
-void esp_panicPutStr(const char *c) { }
-void esp_panicPutHex(int a) { }
-void esp_panicPutDec(int a) { }
+static void panicPutChar(char c) { }
+static void panicPutStr(const char *c) { }
+static void panicPutHex(int a) { }
+static void panicPutDec(int a) { }
#endif
void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
{
- esp_panicPutStr("***ERROR*** A stack overflow in task ");
- esp_panicPutStr((char *)pcTaskName);
- esp_panicPutStr(" has been detected.\r\n");
+ panicPutStr("***ERROR*** A stack overflow in task ");
+ panicPutStr((char *)pcTaskName);
+ panicPutStr(" has been detected.\r\n");
abort();
}
int x;
haltOtherCore();
- esp_panicPutStr("Guru Meditation Error of type ");
+ panicPutStr("Guru Meditation Error of type ");
x = regs[20];
if (x < 40) {
- esp_panicPutStr(edesc[x]);
+ panicPutStr(edesc[x]);
} else {
- esp_panicPutStr("Unknown");
+ panicPutStr("Unknown");
}
- esp_panicPutStr(" occurred on core ");
- esp_panicPutDec(xPortGetCoreID());
+ panicPutStr(" occurred on core ");
+ panicPutDec(xPortGetCoreID());
if (esp_cpu_in_ocd_debug_mode()) {
- esp_panicPutStr(" at pc=");
- esp_panicPutHex(regs[1]);
- esp_panicPutStr(". Setting bp and returning..\r\n");
+ panicPutStr(" at pc=");
+ panicPutHex(regs[1]);
+ panicPutStr(". Setting bp and returning..\r\n");
//Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger
//will kick in exactly at the context the error happened.
setFirstBreakpoint(regs[1]);
return;
}
- esp_panicPutStr(". Exception was unhandled.\r\n");
+ panicPutStr(". Exception was unhandled.\r\n");
commonErrorHandler(frame);
}
if (pc & 0x80000000) {
pc = (pc & 0x3fffffff) | 0x40000000;
}
- esp_panicPutStr(" 0x");
- esp_panicPutHex(pc);
- esp_panicPutStr(":0x");
- esp_panicPutHex(sp);
+ panicPutStr(" 0x");
+ panicPutHex(pc);
+ panicPutStr(":0x");
+ panicPutHex(sp);
}
static void doBacktrace(XtExcFrame *frame)
{
uint32_t i = 0, pc = frame->pc, sp = frame->a1;
- esp_panicPutStr("\r\nBacktrace:");
+ panicPutStr("\r\nBacktrace:");
/* Do not check sanity on first entry, PC could be smashed. */
putEntry(pc, sp);
pc = frame->a0;
break;
}
}
- esp_panicPutStr("\r\n\r\n");
+ panicPutStr("\r\n\r\n");
}
/*
the register window is no longer useful.
*/
if (!abort_called) {
- esp_panicPutStr("Register dump:\r\n");
+ panicPutStr("Register dump:\r\n");
for (x = 0; x < 24; x += 4) {
for (y = 0; y < 4; y++) {
if (sdesc[x + y][0] != 0) {
- esp_panicPutStr(sdesc[x + y]);
- esp_panicPutStr(": 0x");
- esp_panicPutHex(regs[x + y + 1]);
- esp_panicPutStr(" ");
+ panicPutStr(sdesc[x + y]);
+ panicPutStr(": 0x");
+ panicPutHex(regs[x + y + 1]);
+ panicPutStr(" ");
}
- esp_panicPutStr("\r\n");
+ panicPutStr("\r\n");
}
}
}
#if CONFIG_ESP32_PANIC_GDBSTUB
disableAllWdts();
- esp_panicPutStr("Entering gdb stub now.\r\n");
+ panicPutStr("Entering gdb stub now.\r\n");
esp_gdbstub_panic_handler(frame);
#else
#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
esp_core_dump_to_uart(frame);
#endif
#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
- esp_panicPutStr("Rebooting...\r\n");
+ panicPutStr("Rebooting...\r\n");
for (x = 0; x < 100; x++) {
ets_delay_us(1000);
}
software_reset();
#else
disableAllWdts();
- esp_panicPutStr("CPU halted.\r\n");
+ panicPutStr("CPU halted.\r\n");
while (1);
#endif
#endif
__version__ = "0.1-dev"
+if os.name == 'nt':
+ CLOSE_FDS = False
+else:
+ CLOSE_FDS = True
+
class Struct(object):
def __init__(self, buf=None):
print "get_registers_from_stack: pc %x ps %x a0 %x a1 %x a2 %x a3 %x" % (
regs[REG_PC_IDX], regs[REG_PS_IDX], regs[REG_AR_NUM + 0],
regs[REG_AR_NUM + 1], regs[REG_AR_NUM + 2], regs[REG_AR_NUM + 3])
+ # FIXME: crashed and some running tasks (e.g. prvIdleTask) have EXCM bit set
+ # and GDB can not unwind callstack properly (it implies not windowed call0)
+ if regs[REG_PS_IDX] & (1 << 5):
+ regs[REG_PS_IDX] &= ~(1 << 4)
else:
print "SOLSTACKFRAME %d" % rc
regs[REG_PC_IDX] = stack[XT_SOL_PC]
os.remove(fname)
except OSError as e:
if e.errno != errno.ENOENT:
- print "Warning failed to remove temp file '%s'!" % fname
+ print "Warning failed to remove temp file '%s' (%d)!" % (fname, e.errno)
def cleanup(self):
if self.fcore:
self.fcore.close()
- self.remove_tmp_file(self.fcore.name)
+ if self.fcore_name:
+ self.remove_tmp_file(self.fcore_name)
def create_corefile(self, core_fname=None, off=0):
""" TBD
"""
core_off = off
- print "Read core dump header"
data = self.read_data(core_off, self.ESP32_COREDUMP_HDR_SZ)
tot_len,task_num,tcbsz = struct.unpack_from(self.ESP32_COREDUMP_HDR_FMT, data)
tcbsz_aligned = tcbsz
core_elf = ESPCoreDumpElfFile()
notes = b''
for i in range(task_num):
- print "Read task[%d] header" % i
data = self.read_data(core_off, self.ESP32_COREDUMP_TSK_HDR_SZ)
tcb_addr,stack_top,stack_end = struct.unpack_from(self.ESP32_COREDUMP_TSK_HDR_FMT, data)
if stack_end > stack_top:
stack_len_aligned = 4*(stack_len_aligned/4 + 1)
core_off += self.ESP32_COREDUMP_TSK_HDR_SZ
- print "Read task[%d] TCB" % i
data = self.read_data(core_off, tcbsz_aligned)
if tcbsz != tcbsz_aligned:
core_elf.add_program_segment(tcb_addr, data[:tcbsz - tcbsz_aligned], ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
core_elf.add_program_segment(tcb_addr, data, ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
# print "tcb=%s" % data
core_off += tcbsz_aligned
- print "Read task[%d] stack %d bytes" % (i,stack_len)
data = self.read_data(core_off, stack_len_aligned)
# print "stk=%s" % data
if stack_len != stack_len_aligned:
data = data[:stack_len - stack_len_aligned]
core_elf.add_program_segment(stack_base, data, ESPCoreDumpElfFile.PT_LOAD, ESPCoreDumpSegment.PF_R | ESPCoreDumpSegment.PF_W)
core_off += stack_len_aligned
-
- task_regs = self._get_registers_from_stack(data, stack_end > stack_top)
+ try:
+ task_regs = self._get_registers_from_stack(data, stack_end > stack_top)
+ except Exception as e:
+ print e
+ return None
prstatus = XtensaPrStatus()
prstatus.pr_cursig = 0 # TODO: set sig only for current/failed task
prstatus.pr_pid = i # TODO: use pid assigned by OS
self.fcore = self._load_coredump(path, b64)
def _load_coredump(self, path, b64):
+ """Loads core dump from (raw binary or base64-encoded) file
+ """
+ self.fcore_name = None
if b64:
- fhnd,fname = tempfile.mkstemp()
- print "tmpname %s" % fname
+ fhnd,self.fcore_name = tempfile.mkstemp()
fcore = os.fdopen(fhnd, 'wb')
- fb64 = open(path, 'r')
+ fb64 = open(path, 'rb')
try:
while True:
line = fb64.readline()
if len(line) == 0:
break
- data = base64.b64decode(line.rstrip('\r\n'))#, validate=True)
+ data = base64.standard_b64decode(line.rstrip('\r\n'))
fcore.write(data)
fcore.close()
- fcore = open(fname, 'r')
+ fcore = open(self.fcore_name, 'rb')
+ except Exception as e:
+ if self.fcore_name:
+ self.remove_tmp_file(self.fcore_name)
+ raise e
finally:
fb64.close()
else:
- fcore = open(path, 'r')
+ fcore = open(path, 'rb')
return fcore
class ESPCoreDumpFlashLoader(ESPCoreDumpLoader):
""" TBD
"""
- ESP32_COREDUMP_FLASH_MAGIC_START = 0xDEADBEEF
- ESP32_COREDUMP_FLASH_MAGIC_END = 0xACDCFEED
+ ESP32_COREDUMP_FLASH_MAGIC_START = 0xE32C04ED
+ ESP32_COREDUMP_FLASH_MAGIC_END = 0xE32C04ED
ESP32_COREDUMP_FLASH_MAGIC_FMT = '<L'
ESP32_COREDUMP_FLASH_MAGIC_SZ = struct.calcsize(ESP32_COREDUMP_FLASH_MAGIC_FMT)
ESP32_COREDUMP_FLASH_HDR_FMT = '<4L'
self.fcore = self._load_coredump(off)
def _load_coredump(self, off):
- args = [self.path, '-c', self.chip]
+ """Loads core dump from flash
+ """
+ tool_args = [sys.executable, self.path, '-c', self.chip]
if self.port:
- args.extend(['-p', self.port])
+ tool_args.extend(['-p', self.port])
if self.baud:
- args.extend(['-b', str(self.baud)])
- args.extend(['read_flash', str(off), str(self.ESP32_COREDUMP_FLASH_HDR_SZ), ''])
+ tool_args.extend(['-b', str(self.baud)])
+ tool_args.extend(['read_flash', str(off), str(self.ESP32_COREDUMP_FLASH_HDR_SZ), ''])
- fname = None
+ self.fcore_name = None
try:
- fhnd,fname = tempfile.mkstemp()
- args[-1] = fname
+ fhnd,self.fcore_name = tempfile.mkstemp()
+ tool_args[-1] = self.fcore_name
# read core dump length
- et_out = subprocess.check_output(args)
+ et_out = subprocess.check_output(tool_args)
print et_out
- f = os.fdopen(fhnd, 'r')
+ f = os.fdopen(fhnd, 'rb')
self.dump_sz = self._read_core_dump_length(f)
# read core dump
- args[-2] = str(self. dump_sz)
- et_out = subprocess.check_output(args)
+ tool_args[-2] = str(self. dump_sz)
+ et_out = subprocess.check_output(tool_args)
print et_out
except subprocess.CalledProcessError as e:
print "esptool script execution failed with err %d" % e.returncode
print "Command ran: '%s'" % e.cmd
print "Command out:"
print e.output
- self.remove_tmp_file(fname)
+ if self.fcore_name:
+ self.remove_tmp_file(self.fcore_name)
raise e
return f
def create_corefile(self, core_fname=None):
""" TBD
"""
- print "Read core dump start marker"
data = self.read_data(0, self.ESP32_COREDUMP_FLASH_MAGIC_SZ)
mag1, = struct.unpack_from(self.ESP32_COREDUMP_FLASH_MAGIC_FMT, data)
if mag1 != self.ESP32_COREDUMP_FLASH_MAGIC_START:
print "Invalid start marker %x" % mag1
return None
- print "Read core dump end marker"
data = self.read_data(self.dump_sz-self.ESP32_COREDUMP_FLASH_MAGIC_SZ, self.ESP32_COREDUMP_FLASH_MAGIC_SZ)
mag2, = struct.unpack_from(self.ESP32_COREDUMP_FLASH_MAGIC_FMT, data)
if mag2 != self.ESP32_COREDUMP_FLASH_MAGIC_END:
def dbg_corefile(args):
""" TBD
"""
- print "dbg_corefile %s %s %s %s" % (args.gdb, args.prog, args.core, args.save_core)
+ global CLOSE_FDS
loader = None
if not args.core:
loader = ESPCoreDumpFlashLoader(args.off, port=args.port)
core_fname = loader.create_corefile(args.save_core)
if not core_fname:
print "Failed to create corefile!"
+ loader.cleanup()
return
else:
core_fname = args.core
core_fname = loader.create_corefile(args.save_core)
if not core_fname:
print "Failed to create corefile!"
+ loader.cleanup()
return
p = subprocess.Popen(
'--core=%s' % core_fname, # core file
args.prog],
stdin = None, stdout = None, stderr = None,
- close_fds = True
+ close_fds = CLOSE_FDS
)
p.wait()
# def info_corefile(args):
""" TBD
"""
- print "info_corefile %s %s %s" % (args.gdb, args.prog, args.core)
-
-
+ global CLOSE_FDS
def gdbmi_console_stream_handler(ln):
# print ln
sys.stdout.write(ln)
""" TBD
"""
while True:
- ln = f.readline().rstrip(' \n')
- # print "LINE='{0}'".format(ln)
+ ln = f.readline().rstrip(' \r\n')
if ln == '(gdb)':
break
elif len(ln) == 0:
core_fname = loader.create_corefile(args.save_core)
if not core_fname:
print "Failed to create corefile!"
+ loader.cleanup()
return
else:
core_fname = args.core
core_fname = loader.create_corefile(args.save_core)
if not core_fname:
print "Failed to create corefile!"
+ loader.cleanup()
return
handlers = {}
'--interpreter=mi2', # use GDB/MI v2
'--core=%s' % core_fname, # core file
args.prog],
-# ],
stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT,
- close_fds = True
+ close_fds = CLOSE_FDS
)
-
gdbmi_read2prompt(p.stdout, handlers)
exe_elf = ESPCoreDumpElfFile(args.prog)
core_elf = ESPCoreDumpElfFile(core_fname)
print "Name Address Size Attrs"
for ms in merged_segs:
print "%s 0x%x 0x%x %s" % (ms[0], ms[1], ms[2], ms[3])
+ for cs in core_segs:
+ print ".coredump.tasks 0x%x 0x%x %s" % (cs.addr, len(cs.data), cs.attr_str())
if args.print_mem:
- print "\n====================== MEMORY CONTENTS ========================"
- for ms in merged_segs:
-# if ms[3].find('W') == -1:
- if not ms[4]:
- continue
- print "%s 0x%x 0x%x %s" % (ms[0], ms[1], ms[2], ms[3])
- p.stdin.write("-interpreter-exec console \"x/%dx 0x%x\"\n" % (ms[2]/4, ms[1]))
+ print "\n====================== CORE DUMP MEMORY CONTENTS ========================"
+ for cs in core_elf.program_segments:
+ print ".coredump.tasks 0x%x 0x%x %s" % (cs.addr, len(cs.data), cs.attr_str())
+ p.stdin.write("-interpreter-exec console \"x/%dx 0x%x\"\n" % (len(cs.data)/4, cs.addr))
gdbmi_read2prompt(p.stdout, handlers)
if handlers[GDBMIResultHandler.TAG].result_class != GDBMIResultHandler.RC_DONE:
print "GDB/MI command failed (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str)
print "\n===================== ESP32 CORE DUMP END ====================="
print "==============================================================="
- p.terminate()
+ p.stdin.write('q\n')
+ p.wait()
p.stdin.close()
p.stdout.close()
def main():
- parser = argparse.ArgumentParser(description='coredumper.py v%s - ESP32 Core Dump Utility' % __version__, prog='coredumper')
+ parser = argparse.ArgumentParser(description='espcoredump.py v%s - ESP32 Core Dump Utility' % __version__, prog='espcoredump')
parser.add_argument('--chip', '-c',
help='Target chip type',
*pxTcbSz = sizeof(TCB_t);
- //vTaskSuspendAll(); //WARNING: This only suspends one CPU. ToDo: suspend others as well. Mux using taskQueueMutex maybe?
{
/* Fill in an TaskStatus_t structure with information on each
task in the Ready state. */
}
#endif
}
- //( void ) xTaskResumeAll();
-#if 0
- /* Convention: First num_cpus slots will have current task for that cpu. */
- for (i = 0; i < portNUM_PROCESSORS; i++) {
- if (pxCurrentTCB[i] == NULL || pxCurrentTCB == pxTaskSnapshotArray[i]) {
- continue;
- } else {
- UBaseType_t j;
- for (j = i; j < uxTask; j++) {
- if (pxTaskSnapshotArray[j] == pxCurrentTCB[i]) {
- TaskHandle_t tmp = pxTaskSnapshotArray[i];
- pxTaskSnapshotArray[i] = pxTaskSnapshotArray[j];
- pxTaskSnapshotArray[j] = tmp;
- break;
- }
- }
- }
- }
-#endif
return uxTask;
}
esp_intr_noniram_enable();
}
-void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_panic()
+void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
{
const uint32_t cpuid = xPortGetCoreID();
const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
}
-void IRAM_ATTR spi_flash_enable_interrupts_caches_panic()
+void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os()
{
const uint32_t cpuid = xPortGetCoreID();
esp_intr_noniram_enable();
}
-void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_panic()
+void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
{
// Kill interrupts that aren't located in IRAM
esp_intr_noniram_disable();
spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
}
-void IRAM_ATTR spi_flash_enable_interrupts_caches_panic()
+void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os()
{
// Re-enable cache on this CPU
spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
void spi_flash_enable_interrupts_caches_and_other_cpu();
// Disables non-IRAM interrupt handlers on current CPU and caches on both CPUs.
-// This function is implied to be called from panic handler
+// This function is implied to be called from panic handler or when no OS is present
// when non-current CPU is halted and can not execute code from flash.
-void spi_flash_disable_interrupts_caches_and_other_cpu_panic();
+void spi_flash_disable_interrupts_caches_and_other_cpu_no_os();
// Enable cache, enable interrupts (to be added in future) on current CPU.
-// This function is implied to be called from panic handler
+// This function is implied to be called from panic handler or when no OS is present
// when non-current CPU is halted and can not execute code from flash.
-void spi_flash_enable_interrupts_caches_panic();
+void spi_flash_enable_interrupts_caches_no_os();
#endif //ESP_SPI_FLASH_CACHE_UTILS_H
#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS
-/* SPI flash access critical section management functions */
-typedef void (*spi_flash_guard_start_func_t)(void);
-typedef void (*spi_flash_guard_end_func_t)(void);
-
-/**
- * Structure holding SPI flash access critical section management functions
- */
-typedef struct {
- spi_flash_guard_start_func_t start; // critical section start func
- spi_flash_guard_end_func_t end; // critical section end func
-} spi_flash_guard_funcs_t;
-
#define FLASH_GUARD_START(_gp_) do{if((_gp_)) (_gp_)->start();}while(0)
#define FLASH_GUARD_END(_gp_) do{if((_gp_)) (_gp_)->end();}while(0)
static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc);
-static esp_err_t spi_flash_erase_range_internal(uint32_t start_addr, uint32_t size, const spi_flash_guard_funcs_t *flash_guard);
-static esp_err_t spi_flash_write_internal(size_t dst, const void *srcv, size_t size, const spi_flash_guard_funcs_t *flash_guard);
-static esp_err_t spi_flash_read_internal(size_t src, void *dstv, size_t size, const spi_flash_guard_funcs_t *flash_guard);
-const DRAM_ATTR spi_flash_guard_funcs_t s_flash_guard_ops = {
+const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_default_ops = {
.start = spi_flash_disable_interrupts_caches_and_other_cpu,
.end = spi_flash_enable_interrupts_caches_and_other_cpu
};
-const DRAM_ATTR spi_flash_guard_funcs_t s_flash_guard_panic_ops = {
- .start = spi_flash_disable_interrupts_caches_and_other_cpu_panic,
- .end = spi_flash_enable_interrupts_caches_panic
+const DRAM_ATTR spi_flash_guard_funcs_t g_flash_guard_no_os_ops = {
+ .start = spi_flash_disable_interrupts_caches_and_other_cpu_no_os,
+ .end = spi_flash_enable_interrupts_caches_no_os
};
+static const spi_flash_guard_funcs_t *s_flash_guard_ops;
+
void spi_flash_init()
{
spi_flash_init_lock();
#endif
}
+void spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs)
+{
+ s_flash_guard_ops = funcs;
+}
+
size_t spi_flash_get_chip_size()
{
return g_rom_flashchip.chip_size;
}
esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size)
-{
- return spi_flash_erase_range_internal(start_addr, size, &s_flash_guard_ops);
-}
-
-esp_err_t IRAM_ATTR spi_flash_erase_range_panic(uint32_t start_addr, uint32_t size)
-{
- return spi_flash_erase_range_internal(start_addr, size, &s_flash_guard_panic_ops);
-}
-
-static esp_err_t IRAM_ATTR spi_flash_erase_range_internal(uint32_t start_addr, uint32_t size, const spi_flash_guard_funcs_t *flash_guard)
{
if (start_addr % SPI_FLASH_SEC_SIZE != 0) {
return ESP_ERR_INVALID_ARG;
size_t end = start + size / SPI_FLASH_SEC_SIZE;
const size_t sectors_per_block = BLOCK_ERASE_SIZE / SPI_FLASH_SEC_SIZE;
COUNTER_START();
- FLASH_GUARD_START(flash_guard);
+ FLASH_GUARD_START(s_flash_guard_ops);
SpiFlashOpResult rc;
rc = spi_flash_unlock();
if (rc == SPI_FLASH_RESULT_OK) {
}
}
}
- FLASH_GUARD_END(flash_guard);
+ FLASH_GUARD_END(s_flash_guard_ops);
COUNTER_STOP(erase);
return spi_flash_translate_rc(rc);
}
esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
-{
- return spi_flash_write_internal(dst, srcv, size, &s_flash_guard_ops);
-}
-
-esp_err_t IRAM_ATTR spi_flash_write_panic(size_t dst, const void *srcv, size_t size)
-{
- return spi_flash_write_internal(dst, srcv, size, &s_flash_guard_panic_ops);
-}
-
-static esp_err_t IRAM_ATTR spi_flash_write_internal(size_t dst, const void *srcv, size_t size, const spi_flash_guard_funcs_t *flash_guard)
{
// Out of bound writes are checked in ROM code, but we can give better
// error code here
if (left_size > 0) {
uint32_t t = 0xffffffff;
memcpy(((uint8_t *) &t) + (dst - left_off), srcc, left_size);
- FLASH_GUARD_START(flash_guard);
+ FLASH_GUARD_START(s_flash_guard_ops);
rc = SPIWrite(left_off, &t, 4);
- FLASH_GUARD_END(flash_guard);
+ FLASH_GUARD_END(s_flash_guard_ops);
if (rc != SPI_FLASH_RESULT_OK) {
goto out;
}
bool in_dram = true;
#endif
if (in_dram && (((uintptr_t) srcc) + mid_off) % 4 == 0) {
- FLASH_GUARD_START(flash_guard);
+ FLASH_GUARD_START(s_flash_guard_ops);
rc = SPIWrite(dst + mid_off, (const uint32_t *) (srcc + mid_off), mid_size);
- FLASH_GUARD_END(flash_guard);
+ FLASH_GUARD_END(s_flash_guard_ops);
if (rc != SPI_FLASH_RESULT_OK) {
goto out;
}
uint32_t t[8];
uint32_t write_size = MIN(mid_size, sizeof(t));
memcpy(t, srcc + mid_off, write_size);
- FLASH_GUARD_START(flash_guard);
+ FLASH_GUARD_START(s_flash_guard_ops);
rc = SPIWrite(dst + mid_off, t, write_size);
- FLASH_GUARD_END(flash_guard);
+ FLASH_GUARD_END(s_flash_guard_ops);
if (rc != SPI_FLASH_RESULT_OK) {
goto out;
}
if (right_size > 0) {
uint32_t t = 0xffffffff;
memcpy(&t, srcc + right_off, right_size);
- FLASH_GUARD_START(flash_guard);
+ FLASH_GUARD_START(s_flash_guard_ops);
rc = SPIWrite(dst + right_off, &t, 4);
- FLASH_GUARD_END(flash_guard);
+ FLASH_GUARD_END(s_flash_guard_ops);
if (rc != SPI_FLASH_RESULT_OK) {
goto out;
}
}
esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size)
-{
- return spi_flash_read_internal(src, dstv, size, &s_flash_guard_ops);
-}
-
-esp_err_t IRAM_ATTR spi_flash_read_panic(size_t src, void *dstv, size_t size)
-{
- return spi_flash_read_internal(src, dstv, size, &s_flash_guard_panic_ops);
-}
-
-static esp_err_t IRAM_ATTR spi_flash_read_internal(size_t src, void *dstv, size_t size, const spi_flash_guard_funcs_t *flash_guard)
{
// Out of bound reads are checked in ROM code, but we can give better
// error code here
SpiFlashOpResult rc = SPI_FLASH_RESULT_OK;
COUNTER_START();
- FLASH_GUARD_START(flash_guard);
+ FLASH_GUARD_START(s_flash_guard_ops);
/* To simplify boundary checks below, we handle small reads separately. */
if (size < 16) {
uint32_t t[6]; /* Enough for 16 bytes + 4 on either side for padding. */
memcpy(dstc + pad_right_off, t, pad_right_size);
}
out:
- FLASH_GUARD_END(flash_guard);
+ FLASH_GUARD_END(s_flash_guard_ops);
COUNTER_STOP(read);
return spi_flash_translate_rc(rc);
}
void spi_flash_mmap_dump();
/**
- * @brief Erase a range of flash sectors.
- *
- * @note This version of function is to be called from panic handler.
- * It does not use any OS primitives and IPC and implies that
- * only calling CPU is active.
- *
- * @param start_address Address where erase operation has to start.
- * Must be 4kB-aligned
- * @param size Size of erased range, in bytes. Must be divisible by 4kB.
- *
- * @return esp_err_t
+ * @brief SPI flash critical section enter function.
+ */
+typedef void (*spi_flash_guard_start_func_t)(void);
+/**
+ * @brief SPI flash critical section exit function.
*/
-esp_err_t spi_flash_erase_range_panic(size_t start_address, size_t size);
+typedef void (*spi_flash_guard_end_func_t)(void);
+/**
+ * Structure holding SPI flash access critical section management functions
+ */
+typedef struct {
+ spi_flash_guard_start_func_t start; /**< critical section start func */
+ spi_flash_guard_end_func_t end; /**< critical section end func */
+} spi_flash_guard_funcs_t;
/**
- * @brief Write data to Flash.
+ * @brief Erase a range of flash sectors.
*
- * @note This version of function is to be called from panic handler.
- * It does not use any OS primitives and IPC and implies that
- * only calling CPU is active.
-
- * @note If source address is in DROM, this function will return
- * ESP_ERR_INVALID_ARG.
*
- * @param dest destination address in Flash. Must be a multiple of 4 bytes.
- * @param src pointer to the source buffer.
- * @param size length of data, in bytes. Must be a multiple of 4 bytes.
+ * @param start_address Address where erase operation has to start.
+ * Must be 4kB-aligned
+ * @param size Size of erased range, in bytes. Must be divisible by 4kB.
*
* @return esp_err_t
*/
-esp_err_t spi_flash_write_panic(size_t dest, const void *src, size_t size);
+void spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs);
+/** Default OS-aware flash access critical section functions */
+extern const spi_flash_guard_funcs_t g_flash_guard_default_ops;
-/**
- * @brief Read data from Flash.
+/** Non-OS flash access critical section functions
*
- * @note This version of function is to be called from panic handler.
+ * @note This version of functions is to be used when no OS is present or from panic handler.
* It does not use any OS primitives and IPC and implies that
* only calling CPU is active.
- *
- * @param src source address of the data in Flash.
- * @param dest pointer to the destination buffer
- * @param size length of data
- *
- * @return esp_err_t
*/
-esp_err_t spi_flash_read_panic(size_t src, void *dest, size_t size);
+extern const spi_flash_guard_funcs_t g_flash_guard_no_os_ops;
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS