-
Notifications
You must be signed in to change notification settings - Fork 134
/
esp_flash.c
1808 lines (1596 loc) · 57.9 KB
/
esp_flash.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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
174
175
176
177
178
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* SPDX-License-Identifier: GPL-2.0-or-later */
/***************************************************************************
* Generic flash driver for Espressif chips *
* Copyright (C) 2021 Espressif Systems Ltd. *
***************************************************************************/
/**
* Overview
* --------
* Like many other flash drivers this one uses special binary program (stub) running on target
* to perform all operations and communicate to the host. Stub has entry function which accepts
* variable number of arguments and therefore can handle different flash operation requests.
* Only the first argument of the stub entry function is mandatory for all operations it must
* specify the type of flash function to perform (read, write etc.). Actually stub main function
* is a dispatcher which determines the type of flash operation to perform, retrieves other
* arguments and calls corresponding handler. In C notation entry function looks like the following:
* int stub_main(int cmd, ...);
* In general every flash operation consists of the following steps:
* 1) Stub is loaded to target.
* 2) Necessary arguments are prepared and stub's main function is called.
* 3) Stub does the work and returns the result.
* Stub Loading
* ------------
* To execute the stub, the code and data sections need to be loaded onto the target device.
* This is accomplished using the working area API. In ESP32, the code and data address spaces are separate,
* but the CPU can read and write memory from both the data bus and the instruction bus.
* This means that data written from the data bus can be accessed from the instruction bus.
* However, ESP32 differs from other chips as it maps these buses differently.
* To address this, the load function in the algorithm will make the necessary adjustments.
* It is crucial that both the stub code and data sections are located at the beginning of their respective
* working areas because the stub code is linked as ELF and therefore its position is dependent.
* Hence, allocating target memory for the stub code and data is the first step in this process.
* Stub Execution
* --------------
* Special wrapping code is used to enter and exit the stub's main function. It prepares register arguments
* before Windowed ABI call to stub entry and upon return from it executes break command to indicate to OpenOCD
* that operation is finished.
* Flash Data Transfers
* --------------------
* To transfer data from/to target a buffer should be allocated at ESP32 side. Also during the data transfer
* target and host must maintain the state of that buffer (read/write pointers etc.). So host needs to check
* the state of that buffer periodically and write to or read from it (depending on flash operation type).
* ESP32 does not support access to its memory via JTAG when it is not halted, so accessing target memory would
* requires halting the CPUs every time the host needs to check if there are incoming data or free space available
* in the buffer. This fact can slow down flash write/read operations dramatically. To avoid this flash driver and
* stub use application level tracing module API to transfer the data in 'non-stop' mode.
*
**/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include <helper/sha256.h>
#include <helper/binarybuffer.h>
#include <target/register.h>
#include <target/xtensa/xtensa.h>
#include <target/espressif/esp.h>
#include <helper/time_support.h>
#include <helper/align.h>
#include <target/smp.h>
#include "contrib/loaders/flash/espressif/stub_flasher.h"
#include <target/smp.h>
#include "esp_flash.h"
#define ESP_FLASH_RW_TMO 20000 /* ms */
#define ESP_FLASH_ERASE_TMO 60000 /* ms */
#define ESP_FLASH_VERIFY_TMO 30000 /* ms */
#define ESP_FLASH_MAPS_MAX 2
struct esp_flash_rw_args {
int (*xfer)(struct target *target, uint32_t block_id, uint32_t len, void *priv);
uint8_t *buffer;
uint32_t count;
uint32_t total_count;
bool connected;
const struct esp_flash_apptrace_hw *apptrace;
target_addr_t apptrace_ctrl_addr;
};
struct esp_flash_write_state {
struct esp_flash_rw_args rw;
uint32_t prev_block_id;
struct working_area *target_buf;
struct working_area *stub_wargs_area;
struct esp_flash_stub_flash_write_args stub_wargs;
};
struct esp_flash_read_state {
struct esp_flash_rw_args rw;
uint8_t *rd_buf;
};
struct esp_flash_erase_check_args {
struct working_area *erased_state_buf;
uint32_t num_sectors;
};
struct esp_flash_bp_op_state {
struct working_area *target_buf;
struct esp_flash_bank *esp_info;
struct esp_flash_breakpoint *sw_bp;
size_t num_bps;
};
#if BUILD_ESP_COMPRESSION
#include <zlib.h>
static int esp_algo_flash_compress(const uint8_t *in, uint32_t in_len, uint8_t **out, uint32_t *out_len)
{
z_stream strm;
int wbits = -MAX_WBITS; /*deflate */
int level = Z_DEFAULT_COMPRESSION; /*Z_BEST_SPEED; */
/* Don't use Z_NULL to make Sparse tool happy */
strm.zalloc = NULL;
strm.zfree = NULL;
strm.opaque = NULL;
if (deflateInit2(&strm, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL,
Z_DEFAULT_STRATEGY) != Z_OK) {
LOG_ERROR("deflateInit2 error!");
return ERROR_FAIL;
}
strm.avail_out = deflateBound(&strm, (uLong)in_len);
/* Some compression methods may need a little more space */
strm.avail_out += 100;
if (strm.avail_out > INT_MAX) {
deflateEnd(&strm);
return ERROR_FAIL;
}
*out = (uint8_t *)malloc((int)strm.avail_out);
if (*out == NULL) {
LOG_ERROR("out buffer allocation failed!");
return ERROR_FAIL;
}
strm.next_out = *out;
strm.next_in = (uint8_t *)in;
strm.avail_in = (uInt)in_len;
/* always compress in one pass - the return value holds the entire
* decompressed data anyway, so there's no reason to do chunked
* decompression */
if (deflate(&strm, Z_FINISH) != Z_STREAM_END) {
free(*out);
deflateEnd(&strm);
LOG_ERROR("not enough output space");
return ERROR_FAIL;
}
deflateEnd(&strm);
if (strm.total_out > INT_MAX) {
free(*out);
LOG_ERROR("too much output");
return ERROR_FAIL;
}
*out_len = strm.total_out;
LOG_DEBUG("inlen:(%u) outlen:(%u)!", in_len, *out_len);
return ERROR_OK;
}
#else
static int esp_algo_flash_compress(const uint8_t *in, uint32_t in_len, uint8_t **out, uint32_t *out_len)
{
return ERROR_FAIL;
}
#endif
static int esp_algo_calc_hash(const uint8_t *data, size_t datalen, uint8_t *hash)
{
if (data == NULL || hash == NULL || datalen == 0)
return ERROR_FAIL;
struct tc_sha256_state_struct sha256_state;
if (tc_sha256_init(&sha256_state) != TC_CRYPTO_SUCCESS) {
LOG_ERROR("tc_sha256_init failed!");
return ERROR_FAIL;
}
if (tc_sha256_update(&sha256_state, data, datalen) != TC_CRYPTO_SUCCESS) {
LOG_ERROR("tc_sha256_update failed!");
return ERROR_FAIL;
}
if (tc_sha256_final(hash, &sha256_state) != TC_CRYPTO_SUCCESS) {
LOG_ERROR("tc_sha256_final failed!");
return ERROR_FAIL;
}
return ERROR_OK;
}
static int esp_algo_flasher_algorithm_init(struct esp_algorithm_run_data *algo,
const struct esp_algorithm_hw *stub_hw,
const struct esp_flasher_stub_config *stub_cfg)
{
if (!stub_cfg) {
LOG_ERROR("Invalid stub!");
return ERROR_FAIL;
}
memset(algo, 0, sizeof(*algo));
algo->hw = stub_hw;
algo->reg_args.first_user_param = stub_cfg->first_user_reg_param;
algo->image.code_size = stub_cfg->code_sz;
algo->image.data_size = stub_cfg->data_sz;
algo->image.bss_size = stub_cfg->bss_sz;
algo->image.iram_org = stub_cfg->iram_org;
algo->image.iram_len = stub_cfg->iram_len;
algo->image.dram_org = stub_cfg->dram_org;
algo->image.dram_len = stub_cfg->dram_len;
algo->image.reverse = stub_cfg->reverse;
algo->stub.log_buff_addr = stub_cfg->log_buff_addr;
algo->stub.log_buff_size = stub_cfg->log_buff_size;
memset(&algo->image.image, 0, sizeof(algo->image.image));
int ret = image_open(&algo->image.image, NULL, "build");
if (ret != ERROR_OK) {
LOG_ERROR("Failed to create image (%d)!", ret);
return ret;
}
algo->image.image.start_address_set = 1;
algo->image.image.start_address = stub_cfg->entry_addr;
ret = image_add_section(&algo->image.image,
0,
stub_cfg->code_sz,
ESP_IMAGE_ELF_PHF_EXEC,
stub_cfg->code);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to create image (%d)!", ret);
image_close(&algo->image.image);
return ret;
}
ret = image_add_section(&algo->image.image, 0, stub_cfg->data_sz, 0, stub_cfg->data);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to create image (%d)!", ret);
image_close(&algo->image.image);
return ret;
}
LOG_DEBUG("base=%08x set=%d",
(unsigned int)algo->image.image.base_address,
algo->image.image.base_address_set);
return ret;
}
int esp_algo_flash_init(struct esp_flash_bank *esp_info, uint32_t sec_sz,
int (*run_func_image)(struct target *target, struct esp_algorithm_run_data *run,
uint32_t num_args, ...),
bool (*is_irom_address)(target_addr_t addr),
bool (*is_drom_address)(target_addr_t addr),
const struct esp_flasher_stub_config *(*get_stub)(struct flash_bank *bank, int cmd),
const struct esp_flash_apptrace_hw *apptrace_hw,
const struct esp_algorithm_hw *stub_hw,
bool check_preloaded_binary)
{
esp_info->probed = 0;
esp_info->sec_sz = sec_sz;
esp_info->get_stub = get_stub;
esp_info->run_func_image = run_func_image;
esp_info->is_irom_address = is_irom_address;
esp_info->is_drom_address = is_drom_address;
esp_info->hw_flash_base = 0;
esp_info->appimage_flash_base = (uint32_t)-1;
esp_info->compression = BUILD_ESP_COMPRESSION;
esp_info->apptrace_hw = apptrace_hw;
esp_info->stub_hw = stub_hw;
esp_info->check_preloaded_binary = check_preloaded_binary;
return ERROR_OK;
}
int esp_algo_flash_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
{
return ERROR_FAIL;
}
int esp_algo_flash_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
int esp_algo_flash_blank_check(struct flash_bank *bank)
{
struct esp_flash_bank *esp_info = bank->driver_priv;
struct esp_algorithm_run_data run;
const struct esp_flasher_stub_config *stub_cfg = esp_info->get_stub(bank, ESP_STUB_CMD_FLASH_ERASE_CHECK);
const uint32_t stack_size = esp_info->stub_log_enabled ?
stub_cfg->stack_default_sz * 2 : stub_cfg->stack_default_sz;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted!");
return ERROR_TARGET_NOT_HALTED;
}
int ret = esp_algo_flasher_algorithm_init(&run, esp_info->stub_hw, stub_cfg);
if (ret != ERROR_OK)
return ret;
run.stack_size = stack_size;
struct mem_param mp;
init_mem_param(&mp, 3 /*3rd usr arg*/, bank->num_sectors /*size in bytes*/, PARAM_IN);
run.mem_args.params = ∓
run.mem_args.count = 1;
ret = esp_info->run_func_image(bank->target,
&run,
4,
ESP_STUB_CMD_FLASH_ERASE_CHECK /*cmd*/,
esp_info->hw_flash_base / esp_info->sec_sz /*start*/,
bank->num_sectors /*sectors num*/,
0 /*address to store sectors' state*/);
image_close(&run.image.image);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to run flasher stub (%d)!", ret);
destroy_mem_param(&mp);
return ret;
}
if (run.ret_code != ESP_STUB_ERR_OK) {
LOG_ERROR("Failed to check erase flash (%" PRId32 ")!", run.ret_code);
ret = ERROR_FAIL;
} else {
for (unsigned int i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = mp.value[i];
}
destroy_mem_param(&mp);
return ret;
}
static int esp_algo_flash_get_mappings(struct flash_bank *bank,
struct esp_flash_bank *esp_info,
struct esp_stub_flash_map *flash_map,
uint32_t appimage_flash_base)
{
struct esp_algorithm_run_data run;
const struct esp_flasher_stub_config *stub_cfg = esp_info->get_stub(bank, ESP_STUB_CMD_FLASH_MAP_GET);
const uint32_t stack_size = esp_info->stub_log_enabled ?
stub_cfg->stack_default_sz * 2 : stub_cfg->stack_default_sz;
int ret = esp_algo_flasher_algorithm_init(&run, esp_info->stub_hw, stub_cfg);
if (ret != ERROR_OK)
return ret;
run.stack_size = stack_size;
run.check_preloaded_binary = esp_info->stub_log_enabled ? false : esp_info->check_preloaded_binary;
struct mem_param mp;
init_mem_param(&mp,
2 /*2nd usr arg*/,
sizeof(struct esp_stub_flash_map) /*size in bytes*/,
PARAM_IN);
run.mem_args.params = ∓
run.mem_args.count = 1;
ret = esp_info->run_func_image(bank->target,
&run,
3 /*args num*/,
ESP_STUB_CMD_FLASH_MAP_GET /*cmd*/,
appimage_flash_base,
0 /*address to store mappings*/);
image_close(&run.image.image);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to run flasher stub (%d)!", ret);
destroy_mem_param(&mp);
return ret;
}
flash_map->flash_size = target_buffer_get_u32(bank->target, mp.value + ESP_STUB_FLASHMAP_FLASH_SIZE);
flash_map->retcode = target_buffer_get_u32(bank->target, mp.value + ESP_STUB_FLASHMAP_RETCODE);
if (flash_map->retcode != ESP_STUB_ERR_OK) {
LOG_WARNING("Failed to get flash maps (%" PRId32 ")!", flash_map->retcode);
if (flash_map->retcode == ESP_STUB_ERR_INVALID_IMAGE)
LOG_WARNING(
"Application image is invalid! Check configured binary flash offset 'appimage_offset'.");
else if (flash_map->retcode == ESP_STUB_ERR_INVALID_PARTITION)
LOG_WARNING("Invalid partition! One of the partition size exceeds the flash chip size!");
else if (flash_map->retcode == ESP_STUB_ERR_INVALID_APP_MAGIC)
LOG_WARNING("Invalid magic number in app image!");
else if (flash_map->retcode == ESP_STUB_ERR_FLASH_SIZE)
LOG_WARNING("Failed to read flash size!");
else if (flash_map->retcode == ESP_STUB_ERR_READ_PARTITION)
LOG_WARNING("Failed to read partititon table!");
else if (flash_map->retcode == ESP_STUB_ERR_READ_APP_SEGMENT)
LOG_WARNING("Failed to read app segment header!");
else if (flash_map->retcode == ESP_STUB_ERR_READ_APP_IMAGE_HEADER)
LOG_WARNING("Failed to read app image header!");
ret = ERROR_FAIL;
} else {
flash_map->map.maps_num = target_buffer_get_u32(bank->target, mp.value + ESP_STUB_FLASHMAP_MAPSNUM_OFF);
if (flash_map->map.maps_num > ESP_FLASH_MAPS_MAX) {
LOG_ERROR("Too many flash mappings %d! Must be %d.",
flash_map->map.maps_num,
ESP_FLASH_MAPS_MAX);
ret = ERROR_FAIL;
} else if (flash_map->map.maps_num == 0) {
LOG_WARNING("Empty flash mapping!");
} else {
for (uint32_t i = 0; i < flash_map->map.maps_num; i++) {
flash_map->map.maps[i].phy_addr =
target_buffer_get_u32(bank->target, mp.value + ESP_STUB_FLASHMAP_PHYADDR_OFF(i));
flash_map->map.maps[i].load_addr =
target_buffer_get_u32(bank->target, mp.value + ESP_STUB_FLASHMAP_LOADADDR_OFF(i));
flash_map->map.maps[i].size =
target_buffer_get_u32(bank->target, mp.value + ESP_STUB_FLASHMAP_SIZE_OFF(i));
LOG_INFO("Flash mapping %d: 0x%x -> 0x%x, %d KB",
i,
flash_map->map.maps[i].phy_addr,
flash_map->map.maps[i].load_addr,
flash_map->map.maps[i].size / 1024);
}
}
}
destroy_mem_param(&mp);
return ret;
}
int esp_algo_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
{
struct esp_flash_bank *esp_info = bank->driver_priv;
struct esp_algorithm_run_data run;
const struct esp_flasher_stub_config *stub_cfg = esp_info->get_stub(bank, ESP_STUB_CMD_FLASH_READ);
const uint32_t stack_size = esp_info->stub_log_enabled ?
stub_cfg->stack_default_sz * 2 : stub_cfg->stack_default_sz;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
assert((first <= last) && (last < bank->num_sectors));
struct duration bench;
duration_start(&bench);
int ret = esp_algo_flasher_algorithm_init(&run, esp_info->stub_hw,
esp_info->get_stub(bank, ESP_STUB_CMD_FLASH_ERASE));
if (ret != ERROR_OK)
return ret;
run.stack_size = stack_size;
run.timeout_ms = ESP_FLASH_ERASE_TMO;
ret = esp_info->run_func_image(bank->target,
&run,
3,
ESP_STUB_CMD_FLASH_ERASE,
/* cmd */
esp_info->hw_flash_base + first * esp_info->sec_sz,
/* start addr */
(last - first + 1) * esp_info->sec_sz); /* size */
image_close(&run.image.image);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to run flasher stub (%d)!", ret);
return ret;
}
if (run.ret_code != ESP_STUB_ERR_OK) {
LOG_ERROR("Failed to erase flash (%" PRId32 ")!", run.ret_code);
ret = ERROR_FAIL;
} else {
duration_measure(&bench);
LOG_INFO("PROF: Erased %d bytes in %g ms",
(last - first + 1) * esp_info->sec_sz,
duration_elapsed(&bench) * 1000);
}
return ret;
}
static int esp_algo_flash_rw_do(struct target *target, void *priv)
{
struct duration algo_time, tmo_time;
struct esp_flash_rw_args *rw = (struct esp_flash_rw_args *)priv;
int retval = ERROR_OK, busy_num = 0;
if (duration_start(&algo_time) != 0) {
LOG_ERROR("Failed to start data write time measurement!");
return ERROR_FAIL;
}
while (rw->total_count < rw->count) {
uint32_t block_id = 0, len = 0;
LOG_DEBUG("Transfer block on %s", target_name(target));
retval = rw->apptrace->data_len_read(target, &block_id, &len);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read apptrace status (%d)!", retval);
return retval;
}
/* transfer block */
LOG_DEBUG("Transfer block %d, read %d bytes from target", block_id, len);
retval = rw->xfer(target, block_id, len, rw);
if (retval == ERROR_WAIT) {
LOG_DEBUG("Block not ready");
if (busy_num++ == 0) {
if (duration_start(&tmo_time) != 0) {
LOG_ERROR("Failed to start data write time measurement!");
return ERROR_FAIL;
}
} else {
/* if no transfer check tmo */
if (duration_measure(&tmo_time) != 0) {
LOG_ERROR("Failed to stop algo run measurement!");
return ERROR_FAIL;
}
if (1000 * duration_elapsed(&tmo_time) > ESP_FLASH_RW_TMO) {
LOG_ERROR("Transfer data tmo!");
return ERROR_WAIT;
}
}
} else if (retval != ERROR_OK) {
LOG_ERROR("Failed to transfer flash data block (%d)!", retval);
return retval;
} else {
busy_num = 0;
}
if (rw->total_count < rw->count && target->state != TARGET_DEBUG_RUNNING) {
LOG_ERROR(
"Algorithm accidentally stopped (%d)! Transferred %" PRIu32 " of %"
PRIu32,
target->state,
rw->total_count,
rw->count);
return ERROR_FAIL;
}
alive_sleep(10);
int smp = target->smp;
target->smp = 0;
target_poll(target);
target->smp = smp;
}
if (duration_measure(&algo_time) != 0) {
LOG_ERROR("Failed to stop data write measurement!");
return ERROR_FAIL;
}
LOG_INFO("PROF: Data transferred in %g ms @ %g KB/s",
duration_elapsed(&algo_time) * 1000,
duration_kbps(&algo_time, rw->total_count));
return ERROR_OK;
}
static int esp_algo_flash_write_xfer(struct target *target, uint32_t block_id, uint32_t len, void *priv)
{
struct esp_flash_write_state *state = (struct esp_flash_write_state *)priv;
int retval;
/* check for target to get connected */
if (!state->rw.connected) {
retval =
state->rw.apptrace->ctrl_reg_read(target, NULL, NULL, &state->rw.connected);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read apptrace control reg (%d)!", retval);
return retval;
}
if (!state->rw.connected)
return ERROR_WAIT;
/* got connected, apptrace is initied on target, call `info_init` once more to
* update control block info */
if (state->rw.apptrace->info_init) {
retval = state->rw.apptrace->info_init(target,
state->rw.apptrace_ctrl_addr,
NULL);
if (retval != ERROR_OK)
return retval;
}
}
if (state->prev_block_id == block_id)
return ERROR_WAIT;
uint32_t wr_sz = state->rw.count - state->rw.total_count <
state->rw.apptrace->usr_block_max_size_get(target) ?
state->rw.count -
state->rw.total_count : state->rw.apptrace->usr_block_max_size_get(target);
retval = state->rw.apptrace->usr_block_write(target,
block_id,
state->rw.buffer + state->rw.total_count,
wr_sz);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to write apptrace data (%d)!", retval);
return retval;
}
state->rw.total_count += wr_sz;
state->prev_block_id = block_id;
LOG_DEBUG("Transferred %u bytes to target. %u/%u", wr_sz, state->rw.total_count, state->rw.count);
return ERROR_OK;
}
static int esp_algo_flash_write_state_init(struct target *target,
struct esp_algorithm_run_data *run,
struct esp_flash_write_state *state)
{
struct duration algo_time;
/* clear control register, stub will set APPTRACE_HOST_CONNECT bit when it will be
* ready */
int ret = state->rw.apptrace->ctrl_reg_write(target,
0 /*block_id*/,
0 /*len*/,
false /*conn*/,
false /*data*/);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to clear apptrace ctrl reg (%d)!", ret);
return ret;
}
/* alloc memory for stub flash write arguments in data working area */
if (target_alloc_working_area(target, sizeof(state->stub_wargs),
&state->stub_wargs_area) != ERROR_OK) {
LOG_ERROR("no working area available, can't alloc space for stub flash arguments!");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
/* memory buffer */
if (duration_start(&algo_time) != 0) {
LOG_ERROR("Failed to start workarea alloc time measurement!");
return ERROR_FAIL;
}
uint32_t buffer_size = 64 * 1024;
while (target_alloc_working_area_try(target, buffer_size,
&state->target_buf) != ERROR_OK) {
buffer_size /= 2;
if (buffer_size == 0) {
LOG_ERROR("Failed to alloc target buffer for flash data!");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
}
if (duration_measure(&algo_time) != 0) {
LOG_ERROR("Failed to stop workarea alloc measurement!");
return ERROR_FAIL;
}
LOG_DEBUG("PROF: Allocated target buffer %d bytes in %g ms",
buffer_size,
duration_elapsed(&algo_time) * 1000);
state->stub_wargs.down_buf_addr = state->target_buf->address;
state->stub_wargs.down_buf_size = state->target_buf->size;
ret = target_write_buffer(target, state->stub_wargs_area->address,
sizeof(state->stub_wargs), (uint8_t *)&state->stub_wargs);
if (ret != ERROR_OK) {
LOG_ERROR("Write memory at address " TARGET_ADDR_FMT " failed",
state->stub_wargs_area->address);
return ERROR_TARGET_FAILURE;
}
esp_algorithm_user_arg_set_uint(run, 1, state->stub_wargs_area->address);
return ERROR_OK;
}
static void esp_algo_flash_write_state_cleanup(struct target *target,
struct esp_algorithm_run_data *run,
struct esp_flash_write_state *state)
{
struct duration algo_time;
if (!state->target_buf)
return;
if (duration_start(&algo_time) != 0)
LOG_ERROR("Failed to start workarea alloc time measurement!");
target_free_working_area(target, state->target_buf);
target_free_working_area(target, state->stub_wargs_area);
if (duration_measure(&algo_time) != 0)
LOG_ERROR("Failed to stop data write measurement!");
LOG_DEBUG("PROF: Workarea freed in %g ms", duration_elapsed(&algo_time) * 1000);
}
static int esp_algo_flash_apptrace_info_init(struct target *target, struct esp_flash_bank *esp_info,
target_addr_t new_addr, target_addr_t *old_addr)
{
if (esp_info->apptrace_hw->info_init)
return esp_info->apptrace_hw->info_init(target, new_addr, old_addr);
*old_addr = 0;
return ERROR_OK;
}
static int esp_algo_flash_apptrace_info_restore(struct target *target,
struct esp_flash_bank *esp_info,
target_addr_t old_addr)
{
if (esp_info->apptrace_hw->info_init && old_addr > 0)
return esp_info->apptrace_hw->info_init(target, old_addr, NULL);
return ERROR_OK;
}
int esp_algo_flash_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct esp_flash_bank *esp_info = bank->driver_priv;
struct esp_algorithm_run_data run;
struct esp_flash_write_state wr_state;
const struct esp_flasher_stub_config *stub_cfg = esp_info->get_stub(bank,
esp_info->compression ? ESP_STUB_CMD_FLASH_WRITE_DEFLATED : ESP_STUB_CMD_FLASH_WRITE);
uint8_t *compressed_buff = NULL;
uint32_t compressed_len = 0;
uint32_t stack_size = esp_info->stub_log_enabled ?
stub_cfg->stack_default_sz * 2 : stub_cfg->stack_default_sz;
if (offset & 0x3UL) {
LOG_ERROR("Unaligned offset!");
return ERROR_FAIL;
}
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
target_addr_t old_addr = 0;
/* apptrace is not running on target, so not all fields are inited. */
/* Now we just set control struct addr to be able to communicate and detect that apptrace is
* inited */
/* TODO: for m-core chip stub_cfg->apptrace_ctrl_addr is array address of control structs
* for all cores */
int ret = esp_algo_flash_apptrace_info_init(bank->target,
esp_info,
stub_cfg->apptrace_ctrl_addr,
&old_addr);
if (ret != ERROR_OK)
return ret;
ret = esp_algo_flasher_algorithm_init(&run, esp_info->stub_hw, stub_cfg);
if (ret != ERROR_OK) {
esp_algo_flash_apptrace_info_restore(bank->target, esp_info, old_addr);
return ret;
}
if (esp_info->compression) {
struct duration bench;
duration_start(&bench);
if (esp_algo_flash_compress(buffer, count, &compressed_buff,
&compressed_len) != ERROR_OK) {
LOG_ERROR("Compression failed!");
image_close(&run.image.image);
return ERROR_FAIL;
}
duration_measure(&bench);
LOG_INFO("PROF: Compressed %" PRIu32 " bytes to %" PRIu32 " bytes "
"in %fms",
count,
compressed_len,
duration_elapsed(&bench) * 1000);
stack_size += ESP_STUB_IFLATOR_SIZE;
}
run.stack_size = stack_size + ESP_STUB_UNZIP_BUFF_SIZE + stub_cfg->stack_data_pool_sz;
run.usr_func = esp_algo_flash_rw_do;
run.usr_func_arg = &wr_state;
run.usr_func_init = (esp_algorithm_usr_func_init_t)esp_algo_flash_write_state_init;
run.usr_func_done = (esp_algorithm_usr_func_done_t)esp_algo_flash_write_state_cleanup;
memset(&wr_state, 0, sizeof(struct esp_flash_write_state));
wr_state.rw.buffer = esp_info->compression ? compressed_buff : (uint8_t *)buffer;
wr_state.rw.count = esp_info->compression ? compressed_len : count;
wr_state.rw.xfer = esp_algo_flash_write_xfer;
wr_state.rw.apptrace = esp_info->apptrace_hw;
wr_state.prev_block_id = (uint32_t)-1;
wr_state.rw.apptrace_ctrl_addr = stub_cfg->apptrace_ctrl_addr;
/* stub flasher arguments */
wr_state.stub_wargs.size = wr_state.rw.count;
wr_state.stub_wargs.total_size = count;
wr_state.stub_wargs.start_addr = esp_info->hw_flash_base + offset;
wr_state.stub_wargs.down_buf_addr = 0;
wr_state.stub_wargs.down_buf_size = 0;
wr_state.stub_wargs.options = ESP_STUB_FLASH_WR_RAW;
if (esp_info->encryption_needed_on_chip)
wr_state.stub_wargs.options |= ESP_STUB_FLASH_ENCRYPT_BINARY;
struct duration wr_time;
duration_start(&wr_time);
ret = esp_info->run_func_image(bank->target,
&run,
2,
esp_info->compression ? ESP_STUB_CMD_FLASH_WRITE_DEFLATED :
ESP_STUB_CMD_FLASH_WRITE,
/* cmd */
0
/* esp_stub_flash_write_args */);
image_close(&run.image.image);
if (compressed_buff)
free(compressed_buff);
esp_algo_flash_apptrace_info_restore(bank->target, esp_info, old_addr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to run flasher stub (%d)!", ret);
return ret;
}
if (run.ret_code != ESP_STUB_ERR_OK) {
LOG_ERROR("Failed to write flash (%" PRId32 ")!", run.ret_code);
ret = ERROR_FAIL;
} else {
duration_measure(&wr_time);
LOG_INFO("PROF: Wrote %d bytes in %g ms (data transfer time included)",
wr_state.stub_wargs.total_size,
duration_elapsed(&wr_time) * 1000);
}
return ret;
}
static int esp_algo_flash_read_xfer(struct target *target, uint32_t block_id, uint32_t len, void *priv)
{
struct esp_flash_read_state *state = (struct esp_flash_read_state *)priv;
int retval;
/* check for target to get connected */
if (!state->rw.connected) {
retval =
state->rw.apptrace->ctrl_reg_read(target, NULL, NULL, &state->rw.connected);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read apptrace control reg (%d)!", retval);
return retval;
}
if (!state->rw.connected)
return ERROR_WAIT;
/* got connected, apptrace is initied on target, call `info_init` once more to
* update control block info */
if (state->rw.apptrace->info_init) {
retval = state->rw.apptrace->info_init(target,
state->rw.apptrace_ctrl_addr,
NULL);
if (retval != ERROR_OK)
return retval;
}
state->rd_buf = malloc(state->rw.apptrace->block_max_size_get(target));
if (!state->rd_buf) {
LOG_ERROR("Failed to alloc read buffer!");
return ERROR_FAIL;
}
}
if (len == 0)
return ERROR_WAIT;
retval = state->rw.apptrace->data_read(target, len, state->rd_buf, block_id, 1 /*ack*/);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read apptrace status (%d)!", retval);
return retval;
}
LOG_DEBUG("DATA %d bytes: %x %x %x %x %x %x %x %x", len,
state->rd_buf[0], state->rd_buf[1], state->rd_buf[2], state->rd_buf[3],
state->rd_buf[4], state->rd_buf[5], state->rd_buf[6], state->rd_buf[7]);
uint8_t *ptr = state->rd_buf;
while (ptr < state->rd_buf + len) {
uint32_t data_sz = 0;
ptr = state->rw.apptrace->usr_block_get(target, ptr, &data_sz);
if (data_sz > 0)
memcpy(state->rw.buffer + state->rw.total_count, ptr, data_sz);
ptr += data_sz;
state->rw.total_count += data_sz;
}
return ERROR_OK;
}
static int esp_algo_flash_read_state_init(struct target *target,
struct esp_algorithm_run_data *run,
struct esp_flash_read_state *state)
{
/* clear control register, stub will set APPTRACE_HOST_CONNECT bit when it will be
* ready */
int ret = state->rw.apptrace->ctrl_reg_write(target,
0 /*block_id*/,
0 /*len*/,
false /*conn*/,
false /*data*/);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to clear apptrace ctrl reg (%d)!", ret);
return ret;
}
return ERROR_OK;
}
int esp_algo_flash_read(struct flash_bank *bank, uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct esp_flash_bank *esp_info = bank->driver_priv;
struct esp_algorithm_run_data run;
struct esp_flash_read_state rd_state;
const struct esp_flasher_stub_config *stub_cfg = esp_info->get_stub(bank, ESP_STUB_CMD_FLASH_READ);
const uint32_t stack_size = esp_info->stub_log_enabled ?
stub_cfg->stack_default_sz * 2 : stub_cfg->stack_default_sz;
if (offset & 0x3UL) {
LOG_ERROR("Unaligned offset!");
return ERROR_FAIL;
}
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
target_addr_t old_addr = 0;
/* apptrace is not running on target, so not all fields are inited. */
/* Now we just set control struct addr to be able to communicate and detect that apptrace is
* inited */
/* TODO: for m-core chip stub_cfg->apptrace_ctrl_addr is array address of control structs
* for all cores */
int ret = esp_algo_flash_apptrace_info_init(bank->target,
esp_info,
stub_cfg->apptrace_ctrl_addr,
&old_addr);
if (ret != ERROR_OK)
return ret;
ret = esp_algo_flasher_algorithm_init(&run, esp_info->stub_hw, stub_cfg);
if (ret != ERROR_OK) {
esp_algo_flash_apptrace_info_restore(bank->target, esp_info, old_addr);
return ret;
}
run.stack_size = stack_size + stub_cfg->stack_data_pool_sz;
run.usr_func_init = (esp_algorithm_usr_func_init_t)esp_algo_flash_read_state_init;
run.usr_func = esp_algo_flash_rw_do;
run.usr_func_arg = &rd_state;
memset(&rd_state, 0, sizeof(struct esp_flash_read_state));
rd_state.rw.buffer = buffer;
rd_state.rw.count = count;
rd_state.rw.xfer = esp_algo_flash_read_xfer;
rd_state.rw.apptrace = esp_info->apptrace_hw;
rd_state.rw.apptrace_ctrl_addr = stub_cfg->apptrace_ctrl_addr;
ret = esp_info->run_func_image(bank->target,
&run,
3,
/* cmd */
ESP_STUB_CMD_FLASH_READ,
/* start addr */
esp_info->hw_flash_base + offset,
/* size */
count);
image_close(&run.image.image);
free(rd_state.rd_buf);
esp_algo_flash_apptrace_info_restore(bank->target, esp_info, old_addr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to run flasher stub (%d)!", ret);
return ret;
}
if (run.ret_code != ESP_STUB_ERR_OK) {
LOG_ERROR("Failed to read flash (%" PRId32 ")!", run.ret_code);
ret = ERROR_FAIL;
}
return ret;
}
#define BANK_SUBNAME(_b_, _n_) (strcmp((_b_)->name + strlen((_b_)->name) - strlen(_n_), _n_) == 0)
int esp_algo_flash_probe(struct flash_bank *bank)
{
struct esp_flash_bank *esp_info = bank->driver_priv;
struct esp_stub_flash_map flash_map = { .map.maps_num = 0 };
uint32_t irom_base = 0, irom_sz = 0, drom_base = 0, drom_sz = 0, irom_flash_base = 0,
drom_flash_base = 0;
esp_info->probed = 0;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
LOG_DEBUG("Flash size = %d KB @ "TARGET_ADDR_FMT " '%s' - '%s'",
bank->size / 1024,
bank->base,
target_name(bank->target),
target_state_name(bank->target));
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
int ret = esp_algo_flash_get_mappings(bank,
esp_info,
&flash_map,
esp_info->appimage_flash_base);
if (ret != ERROR_OK || flash_map.map.maps_num == 0) {
LOG_WARNING("Failed to get flash mappings (%d)!", ret);
/* if no DROM/IROM mappings so pretend they are at the end of the HW flash bank and
* have zero size to allow correct memory map with non zero RAM region */
irom_base = flash_map.flash_size;
drom_base = flash_map.flash_size;
} else {
/* flash map index 0 belongs to drom */
if (esp_info->is_drom_address(flash_map.map.maps[0].load_addr)) {
drom_flash_base = flash_map.map.maps[0].phy_addr & ~(esp_info->sec_sz - 1);
drom_base = flash_map.map.maps[0].load_addr & ~(esp_info->sec_sz - 1);
drom_sz = flash_map.map.maps[0].size;
if (drom_sz & (esp_info->sec_sz - 1))
drom_sz = (drom_sz & ~(esp_info->sec_sz - 1)) + esp_info->sec_sz;
}