1
6
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
33
34
35
36
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
65
66
70
71
83
84
88
89
90
91
92
93
97
98
99
103
104
105
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
128
129
130
131
132
133
134
143
144
145
146
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
177
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
207
208
209
214
215
217
221
222
224
225
226
227
228
231
232
235
236
237
238
239
240
243
244
245
246
247
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
272
273
274
275
276
277
278
279
281
282
283
285
286
287
288
289
290
291
292
293
294
295
296
301
302
306
307
308
309
310
311
312
326
327
328
329
330
331
332
333
334
335
336
337
339
340
341
342
343
344
345
346
349
350
352
353
354
355
356
357
358
360
361
362
363
364
368
369
370
371
372
373
374
375
376
377
378
379
380
382
383
387
388
389
397
398
399
400
401
402
403
404
405
407
408
409
410
411
412
413
414
418
422
423
424
425
429
430
431
434
435
436
441
442
443
444
445
446
447
448
449
450
451
454
455
456
457
458
459
463
467
468
470
471
475
476
477
481
482
486
487
488
491
492
495
496
497
498
499
500
501
502
503
504
505
506
509
510
511
512
513
516
517
518
519
520
521
522
523
524
/* ... */
#include <string.h>
#include "esp_partition.h"
#include "esp_log.h"
#include "esp_core_dump_types.h"
#include "core_dump_checksum.h"
#include "esp_flash_internal.h"
#include "esp_flash_encrypt.h"
#include "esp_rom_crc.h"
#include "esp_private/spi_flash_os.h"
#include "spi_flash_mmap.h"10 includes
#define BLANK_COREDUMP_SIZE 0xFFFFFFFF
const static char TAG[] __attribute__((unused)) = "esp_core_dump_flash";
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
typedef struct _core_dump_partition_t {
uint32_t start;
uint32_t size;
bool encrypted;
#if CONFIG_ESP_COREDUMP_FLASH_NO_OVERWRITE
bool empty;/* ... */
#endif
}{...} core_dump_partition_t;
typedef struct _core_dump_flash_config_t {
core_dump_partition_t partition;
core_dump_crc_t partition_config_crc;
}{...} core_dump_flash_config_t;
static core_dump_flash_config_t s_core_flash_config;
void esp_core_dump_print_write_start(void) __attribute__((alias("esp_core_dump_flash_print_write_start")));
void esp_core_dump_print_write_end(void) __attribute__((alias("esp_core_dump_flash_print_write_end")));
esp_err_t esp_core_dump_write_init(void) __attribute__((alias("esp_core_dump_flash_hw_init")));
esp_err_t esp_core_dump_write_prepare(core_dump_write_data_t *wr_data, uint32_t *data_len) __attribute__((alias("esp_core_dump_flash_write_prepare")));
esp_err_t esp_core_dump_write_start(core_dump_write_data_t *wr_data) __attribute__((alias("esp_core_dump_flash_write_start")));
esp_err_t esp_core_dump_write_end(core_dump_write_data_t *wr_data) __attribute__((alias("esp_core_dump_flash_write_end")));
esp_err_t esp_core_dump_write_data(core_dump_write_data_t *wr_data, void *data, uint32_t data_len) __attribute__((alias("esp_core_dump_flash_write_data")));
#define ESP_COREDUMP_FLASH_WRITE(_off_, _data_, _len_) esp_flash_write(esp_flash_default_chip, _data_, _off_, _len_)
#define ESP_COREDUMP_FLASH_WRITE_ENCRYPTED(_off_, _data_, _len_) esp_flash_write_encrypted(esp_flash_default_chip, _off_, _data_, _len_)
#define ESP_COREDUMP_FLASH_ERASE(_off_, _len_) esp_flash_erase_region(esp_flash_default_chip, _off_, _len_)
esp_err_t esp_core_dump_image_check(void);
esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size);
static void esp_core_dump_flash_print_write_start(void)
{
ESP_COREDUMP_LOGI("Save core dump to flash...");
}{...}
static void esp_core_dump_flash_print_write_end(void)
{
ESP_COREDUMP_LOGI("Core dump has been saved to flash.");
}{...}
static esp_err_t esp_core_dump_flash_custom_write(uint32_t address, const void *buffer, uint32_t length)
{
esp_err_t err = ESP_OK;
if (esp_flash_encryption_enabled() && s_core_flash_config.partition.encrypted) {
err = ESP_COREDUMP_FLASH_WRITE_ENCRYPTED(address, buffer, length);
}{...} else {
err = ESP_COREDUMP_FLASH_WRITE(address, buffer, length);
}{...}
return err;
}{...}
static inline core_dump_crc_t esp_core_dump_calc_flash_config_crc(void)
{
return esp_rom_crc32_le(0, (uint8_t const *)&s_core_flash_config.partition, sizeof(s_core_flash_config.partition));
}{...}
static esp_err_t esp_core_dump_flash_hw_init(void)
{
core_dump_crc_t crc = esp_core_dump_calc_flash_config_crc();
if (s_core_flash_config.partition_config_crc != crc) {
ESP_COREDUMP_LOGE("Core dump flash config is corrupted! CRC=0x%x instead of 0x%x", crc, s_core_flash_config.partition_config_crc);
return ESP_FAIL;
}{...}
if (s_core_flash_config.partition.start == 0 || s_core_flash_config.partition.size < sizeof(uint32_t)) {
ESP_COREDUMP_LOGE("Invalid flash partition config!");
return ESP_FAIL;
}{...}
#if CONFIG_ESP_COREDUMP_FLASH_NO_OVERWRITE
if (!s_core_flash_config.partition.empty) {
ESP_COREDUMP_LOGW("Core dump already exists in flash, will not overwrite it with a new core dump");
return ESP_FAIL;
}{...}
/* ... */#endif
spi_flash_guard_set(&g_flash_guard_no_os_ops);
esp_flash_app_disable_protect(true);
return ESP_OK;
}{...}
static void esp_core_dump_partition_init(void)
{
const esp_partition_t *core_part = NULL;
ESP_COREDUMP_LOGI("Init core dump to flash");
core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, NULL);
if (!core_part) {
ESP_COREDUMP_LOGE("No core dump partition found!");
return;
}{...}
ESP_COREDUMP_LOGI("Found partition '%s' @ %x %d bytes", core_part->label, core_part->address, core_part->size);
s_core_flash_config.partition.start = core_part->address;
s_core_flash_config.partition.size = core_part->size;
s_core_flash_config.partition.encrypted = core_part->encrypted;
#if CONFIG_ESP_COREDUMP_FLASH_NO_OVERWRITE
uint32_t core_size = 0;
esp_err_t err = esp_partition_read(core_part, 0, &core_size, sizeof(core_size));
if (err == ESP_OK) {
s_core_flash_config.partition.empty = (core_size == BLANK_COREDUMP_SIZE);
}{...} else {
ESP_COREDUMP_LOGE("Failed to read core dump data size (%d)!", err);
s_core_flash_config.partition.empty = false;
}{...}
/* ... */#endif
s_core_flash_config.partition_config_crc = esp_core_dump_calc_flash_config_crc();
if (esp_flash_encryption_enabled() && !core_part->encrypted) {
ESP_COREDUMP_LOGW("core dump partition is plain text, consider enabling `encrypted` flag");
}{...}
}{...}
static esp_err_t esp_core_dump_flash_write_data(core_dump_write_data_t* wr_data, uint8_t* data, uint32_t data_size)
{
esp_err_t err = ESP_OK;
uint32_t written = 0;
uint32_t wr_sz = 0;
ESP_COREDUMP_ASSERT((wr_data->off + wr_data->cached_bytes + data_size) < s_core_flash_config.partition.size);
while (data_size > 0) {
wr_sz = MIN(data_size, COREDUMP_CACHE_SIZE - wr_data->cached_bytes);
memcpy(&wr_data->cached_data[wr_data->cached_bytes], data + written, wr_sz);
wr_data->cached_bytes += wr_sz;
if (wr_data->cached_bytes == COREDUMP_CACHE_SIZE) {
err = esp_core_dump_flash_custom_write(s_core_flash_config.partition.start + wr_data->off,
wr_data->cached_data,
COREDUMP_CACHE_SIZE);
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to write cached data to flash (%d)!", err);
return err;
}{...}
/* ... */
wr_data->off += COREDUMP_CACHE_SIZE;
esp_core_dump_checksum_update(&wr_data->checksum_ctx, wr_data->cached_data, COREDUMP_CACHE_SIZE);
wr_data->cached_bytes = 0;
memset(wr_data->cached_data, 0, COREDUMP_CACHE_SIZE);
}{...}
written += wr_sz;
data_size -= wr_sz;
}{...}
return ESP_OK;
}{...}
static esp_err_t esp_core_dump_flash_write_prepare(core_dump_write_data_t *wr_data, uint32_t *data_len)
{
esp_err_t err = ESP_OK;
uint32_t sec_num = 0;
uint32_t cs_len = 0;
cs_len = esp_core_dump_checksum_size();
/* ... */
uint32_t padding = 0;
const uint32_t modulo = *data_len % COREDUMP_CACHE_SIZE;
if (modulo != 0) {
/* ... */
padding = COREDUMP_CACHE_SIZE - modulo;
}{...}
/* ... */
if ((*data_len + padding + cs_len) > s_core_flash_config.partition.size) {
ESP_COREDUMP_LOGE("Not enough space to save core dump!");
return ESP_ERR_NO_MEM;
}{...}
/* ... */
*data_len += padding + cs_len;
memset(wr_data, 0, sizeof(core_dump_write_data_t));
/* ... */
sec_num = *data_len / SPI_FLASH_SEC_SIZE;
if (*data_len % SPI_FLASH_SEC_SIZE) {
sec_num++;
}{...}
ESP_COREDUMP_LOGI("Erase flash %d bytes @ 0x%x", sec_num * SPI_FLASH_SEC_SIZE, s_core_flash_config.partition.start + 0);
ESP_COREDUMP_ASSERT(sec_num * SPI_FLASH_SEC_SIZE <= s_core_flash_config.partition.size);
err = ESP_COREDUMP_FLASH_ERASE(s_core_flash_config.partition.start + 0, sec_num * SPI_FLASH_SEC_SIZE);
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to erase flash (%d)!", err);
}{...}
return err;
}{...}
static esp_err_t esp_core_dump_flash_write_start(core_dump_write_data_t *wr_data)
{
esp_core_dump_checksum_init(&wr_data->checksum_ctx);
return ESP_OK;
}{...}
static esp_err_t esp_core_dump_flash_write_end(core_dump_write_data_t *wr_data)
{
esp_err_t err = ESP_OK;
core_dump_checksum_bytes checksum = NULL;
uint32_t cs_len = 0;
cs_len = esp_core_dump_checksum_size();
if (wr_data->cached_bytes) {
err = esp_core_dump_flash_custom_write(s_core_flash_config.partition.start + wr_data->off,
wr_data->cached_data,
COREDUMP_CACHE_SIZE);
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to flush cached data to flash (%d)!", err);
return err;
}{...}
esp_core_dump_checksum_update(&wr_data->checksum_ctx, wr_data->cached_data, COREDUMP_CACHE_SIZE);
wr_data->off += COREDUMP_CACHE_SIZE;
wr_data->cached_bytes = 0;
}{...}
/* ... */
esp_core_dump_checksum_finish(&wr_data->checksum_ctx, &checksum);
/* ... */
if (cs_len < COREDUMP_CACHE_SIZE) {
memcpy(wr_data->cached_data, checksum, cs_len);
memset(wr_data->cached_data + cs_len, 0, COREDUMP_CACHE_SIZE - cs_len);
err = esp_core_dump_flash_custom_write(s_core_flash_config.partition.start + wr_data->off,
wr_data->cached_data,
COREDUMP_CACHE_SIZE);
}{...} else {
ESP_COREDUMP_ASSERT(cs_len % 16 == 0);
err = esp_core_dump_flash_custom_write(s_core_flash_config.partition.start + wr_data->off, checksum, cs_len);
}{...}
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to flush cached data to flash (%d)!", err);
return err;
}{...}
wr_data->off += cs_len;
ESP_COREDUMP_LOGI("Write end offset 0x%x, check sum length %d", wr_data->off, cs_len);
return err;
}{...}
void esp_core_dump_init(void)
{
esp_core_dump_partition_init();
#if CONFIG_ESP_COREDUMP_CHECK_BOOT
const esp_partition_t *partition = 0;
uint32_t size = 0;
if (esp_core_dump_image_check() == ESP_OK
&& esp_core_dump_partition_and_size_get(&partition, &size) == ESP_OK) {
ESP_COREDUMP_LOGI("Found core dump %d bytes in flash @ 0x%x", size, partition->address);
}{...}
/* ... */#endif
}{...}
esp_err_t esp_core_dump_image_check(void)
{
esp_err_t err = ESP_OK;
const esp_partition_t *core_part = NULL;
core_dump_write_data_t wr_data = { 0 };
uint32_t size = 0;
uint32_t total_size = 0;
uint32_t offset = 0;
const uint32_t checksum_size = esp_core_dump_checksum_size();
core_dump_checksum_bytes checksum_calc = NULL;
/* ... */
uint8_t checksum_read[COREDUMP_CHECKSUM_MAX_LEN] = { 0 };
ESP_COREDUMP_DEBUG_ASSERT(checksum_size <= COREDUMP_CHECKSUM_MAX_LEN);
err = esp_core_dump_partition_and_size_get(&core_part, &total_size);
if (err != ESP_OK) {
return err;
}{...}
/* ... */
size = total_size - checksum_size ;
esp_core_dump_checksum_init(&wr_data.checksum_ctx);
while (size > 0) {
/* ... */
const uint32_t toread = (size < COREDUMP_CACHE_SIZE) ? size : COREDUMP_CACHE_SIZE;
err = esp_partition_read(core_part, offset, wr_data.cached_data, toread);
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to read data from core dump (%d)!", err);
return err;
}{...}
esp_core_dump_checksum_update(&wr_data.checksum_ctx, wr_data.cached_data, toread);
offset += toread;
size -= toread;
}{...}
esp_core_dump_checksum_finish(&wr_data.checksum_ctx, &checksum_calc);
/* ... */
err = esp_partition_read(core_part, total_size - checksum_size, checksum_read, checksum_size);
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to read checksum from core dump (%d)!", err);
return err;
}{...}
if (memcmp(checksum_calc, checksum_read, checksum_size) != 0) {
ESP_COREDUMP_LOGE("Core dump data check failed:");
esp_core_dump_print_checksum("Calculated checksum", checksum_calc);
esp_core_dump_print_checksum("Image checksum", checksum_read);
return ESP_ERR_INVALID_CRC;
}{...} else {
ESP_COREDUMP_LOGI("Core dump data checksum is correct");
}{...}
return ESP_OK;
}{...}
/* ... */
#endif
esp_err_t esp_core_dump_image_erase(void)
{
/* ... */
uint32_t helper[4] = { BLANK_COREDUMP_SIZE };
_Static_assert(sizeof(helper) % 16 == 0, "esp_partition_write() needs multiple of 16 bytes long buffers");
const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (!core_part) {
ESP_LOGE(TAG, "No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}{...}
if (core_part->size < sizeof(uint32_t)) {
ESP_LOGE(TAG, "Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}{...}
esp_err_t err = ESP_OK;
err = esp_partition_erase_range(core_part, 0, core_part->size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase core dump partition (%d)!", err);
return err;
}{...}
err = esp_partition_write(core_part, 0, helper, sizeof(helper));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to write core dump partition size (%d)!", err);
}{...}
#if CONFIG_ESP_COREDUMP_FLASH_NO_OVERWRITE
if (!s_core_flash_config.partition.empty) {
s_core_flash_config.partition.empty = true;
s_core_flash_config.partition_config_crc = esp_core_dump_calc_flash_config_crc();
}{...}
#endif/* ... */
return err;
}{ ... }
esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size)
{
uint32_t core_size = 0;
const esp_partition_t *core_part = NULL;
if (partition == NULL && size == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (core_part == NULL) {
ESP_COREDUMP_LOGE("No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}{...}
if (core_part->size < sizeof(uint32_t)) {
ESP_COREDUMP_LOGE("Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}{...}
/* ... */
esp_err_t err = esp_partition_read(core_part, 0, &core_size, sizeof(uint32_t));
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to read core dump data size (%d)!", err);
return err;
}{...}
if (core_size == 0xFFFFFFFF) {
ESP_COREDUMP_LOGD("Blank core dump partition!");
return ESP_ERR_INVALID_SIZE;
}{...}
if ((core_size < sizeof(uint32_t)) || (core_size > core_part->size)) {
ESP_COREDUMP_LOGE("Incorrect size of core dump image: %d", core_size);
return ESP_ERR_INVALID_SIZE;
}{...}
if (partition != NULL) {
*partition = core_part;
}{...}
if (size != NULL) {
*size = core_size;
}{...}
return ESP_OK;
}{ ... }
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
{
esp_err_t err = ESP_OK;
uint32_t size = 0;
const esp_partition_t *core_part = NULL;
if (out_addr == NULL || out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
err = esp_core_dump_partition_and_size_get(&core_part, &size);
if (err != ESP_OK) {
return err;
}{...}
*out_addr = core_part->address;
*out_size = size;
return ESP_OK;
}{ ... }