1
6
7
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
54
55
56
57
58
59
60
61
62
63
64
67
68
69
70
71
72
73
76
77
78
79
80
81
84
85
86
87
88
89
90
91
92
93
94
95
96
97
103
104
105
112
113
114
115
116
123
124
125
130
131
132
133
134
135
136
137
138
139
143
144
147
148
149
150
151
162
163
174
175
176
177
178
179
181
182
183
184
185
186
187
188
197
198
199
200
201
202
203
204
205
206
207
208
215
216
217
218
219
220
221
222
223
224
225
245
246
247
255
256
257
261
262
263
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
315
316
317
318
319
320
321
322
323
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
358
359
360
370
371
372
373
374
375
376
377
378
379
380
381
382
383
388
389
390
391
392
393
394
395
396
403
404
405
406
407
408
412
413
417
418
419
420
421
422
423
424
425
429
430
431
432
436
437
444
445
446
447
448
449
450
451
452
456
457
458
462
463
464
468
469
470
471
472
473
474
475
476
477
481
482
483
489
494
495
/* ... */
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "assert.h"
#include "sdkconfig.h"
#include <sys/param.h>7 includes
static const char *TAG = "efuse";
static volatile unsigned s_burn_counter = 0;
#ifdef CONFIG_EFUSE_VIRTUAL
uint32_t virt_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK];
#endif
extern const esp_efuse_range_addr_t range_read_addr_blocks[];
extern const esp_efuse_range_addr_t range_write_addr_blocks[];
static uint32_t get_mask(unsigned int bit_count, unsigned int shift);
static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value);
static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob);
static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt);
static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits);
esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, size_t ptr_size_bits, efuse_func_proc_t func_proc)
{
esp_err_t err = ESP_OK;
int bits_counter = 0;
int field_len = esp_efuse_get_field_size(field);
int req_size = (ptr_size_bits == 0) ? field_len : MIN(ptr_size_bits, field_len);
unsigned count_before = s_burn_counter;
for (const esp_efuse_desc_t* f = field[0]; (err == ESP_OK && req_size > bits_counter && f != NULL); ++f) {
if (check_range_of_bits(f->efuse_block, f->bit_start, f->bit_count) == false) {
ESP_EARLY_LOGE(TAG, "Range of data does not match the coding scheme");
err = ESP_ERR_CODING;
break;
}{...}
int end_bit_in_block = (f->bit_start + f->bit_count - 1);
int first_reg = f->bit_start / 32;
int last_reg = end_bit_in_block / 32;
int start_bit_in_reg = f->bit_start % 32;
for (int num_reg = first_reg; num_reg <= last_reg; ++num_reg) {
int first_bit_in_reg = (num_reg == first_reg) ? start_bit_in_reg % 32 : 0;
int last_bit_in_reg = (num_reg == last_reg) ? end_bit_in_block % 32 : 31;
int use_bit_in_reg = (last_bit_in_reg - first_bit_in_reg) + 1;
if ((bits_counter + use_bit_in_reg) > req_size) {
use_bit_in_reg = req_size - bits_counter;
}{...}
int end_bit_in_reg = start_bit_in_reg + use_bit_in_reg - 1;
ESP_EARLY_LOGD(TAG, "BLK%d REG%d [%d-%d], len=%d bits", (int)f->efuse_block, num_reg, start_bit_in_reg, end_bit_in_reg, use_bit_in_reg);
err = func_proc(num_reg, f->efuse_block, start_bit_in_reg, use_bit_in_reg, ptr, &bits_counter);
start_bit_in_reg = 0;
if (err != ESP_OK || req_size <= bits_counter) {
break;
}{...}
}{...}
}{...}
unsigned count_after = s_burn_counter;
if (err == ESP_OK &&
(func_proc == esp_efuse_utility_fill_buff || func_proc == esp_efuse_utility_count_once) &&
(count_before != count_after || (count_after & 1) == 1)) {
err = ESP_ERR_DAMAGED_READING;
}{...}
assert(bits_counter <= req_size);
return err;
}{ ... }
esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_out, int* bits_counter)
{
uint8_t* blob = (uint8_t *) arr_out;
uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
uint64_t reg_of_aligned_bits = (reg >> bit_start) & get_mask(bit_count, 0);
int shift_bit = (*bits_counter) % 8;
if (shift_bit != 0) {
blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits << shift_bit);
shift_bit = ((8 - shift_bit) < bit_count) ? (8 - shift_bit) : bit_count;
(*bits_counter) += shift_bit;
bit_count -= shift_bit;
}{...}
int sum_shift = 0;
while (bit_count > 0) {
sum_shift += shift_bit;
blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits >> sum_shift);
shift_bit = (bit_count > 8) ? 8 : bit_count;
(*bits_counter) += shift_bit;
bit_count -= shift_bit;
}{...};
return ESP_OK;
}{ ... }
esp_err_t esp_efuse_utility_count_once(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* out_cnt, int* bits_counter)
{
uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
*((size_t *)out_cnt) += __builtin_popcount(reg & get_mask(bit_count, bit_start));
*bits_counter += bit_count;
return ESP_OK;
}{ ... }
esp_err_t esp_efuse_utility_write_blob(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_in, int* bits_counter)
{
uint32_t reg_to_write = fill_reg(bit_start, bit_count, (uint8_t *)arr_in, bits_counter);
return esp_efuse_utility_write_reg(efuse_block, num_reg, reg_to_write);
}{ ... }
esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* cnt, int* bits_counter)
{
esp_err_t err = ESP_OK;
uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
size_t* set_bits = (size_t*)cnt;
uint32_t mask = get_mask(bit_count, bit_start);
uint32_t reg_masked_bits = reg & mask;
if ((reg_masked_bits ^ mask) != 0) {
uint32_t reg_to_write = set_cnt_in_reg(bit_start, bit_count, reg_masked_bits, set_bits);
write_reg(efuse_block, num_reg, reg_to_write);
}{...}
*bits_counter += bit_count;
if ((*set_bits) == 0) {
err = ESP_OK_EFUSE_CNT;
}{...}
return err;
}{ ... }
void esp_efuse_utility_reset(void)
{
++s_burn_counter;
esp_efuse_utility_clear_program_registers();
++s_burn_counter;
for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
for (uintptr_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) {
REG_WRITE(addr_wr_block, 0);
}{...}
}{...}
}{ ... }
void esp_efuse_utility_debug_dump_pending(void)
{
for (int num_block = 0; num_block < EFUSE_BLK_MAX; num_block++) {
for (uintptr_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) {
if (REG_READ(addr_wr_block) != 0) {
esp_efuse_utility_debug_dump_single_block(num_block, false);
break;
}{...}
}{...}
}{...}
}{ ... }
esp_err_t esp_efuse_utility_burn_efuses(void)
{
++s_burn_counter;
#ifdef CONFIG_EFUSE_VIRTUAL_LOG_ALL_WRITES
ESP_EARLY_LOGW(TAG, "Burn:");
esp_efuse_utility_debug_dump_pending();/* ... */
#endif
esp_err_t err = esp_efuse_utility_burn_chip();
++s_burn_counter;
return err;
}{ ... }
void esp_efuse_utility_erase_virt_blocks(void)
{
#ifdef CONFIG_EFUSE_VIRTUAL
memset(virt_blocks, 0, sizeof(virt_blocks));
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_utility_write_efuses_to_flash();
#endif/* ... */
#endif
}{ ... }
void esp_efuse_utility_update_virt_blocks(void)
{
#ifdef CONFIG_EFUSE_VIRTUAL
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
if (!esp_efuse_utility_load_efuses_from_flash()) {
#else
if (1) {
#endif
ESP_EARLY_LOGW(TAG, "[Virtual] Loading virtual efuse blocks from real efuses");
for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
int subblock = 0;
for (uintptr_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) {
virt_blocks[num_block][subblock++] = REG_READ(addr_rd_block);
}{...}
ESP_EARLY_LOGD(TAG, "[Virtual] virt_blocks[%d] is filled by EFUSE_BLOCK%d", num_block, num_block);
}{...}
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
esp_efuse_utility_write_efuses_to_flash();
#endif
}{...}
#else
ESP_EARLY_LOGI(TAG, "Emulate efuse is disabled");
#endif
}{ ... }
void esp_efuse_utility_debug_dump_single_block(int num_block, bool from_read)
{
esp_rom_printf("%d) ", num_block);
int num_reg = 0;
if (from_read) {
for (uintptr_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, num_reg++) {
#ifdef CONFIG_EFUSE_VIRTUAL
esp_rom_printf("%08" PRIx32 " ", virt_blocks[num_block][num_reg]);
#else
esp_rom_printf("%08" PRIx32 " ", REG_READ(addr_rd_block));
(void) num_reg;/* ... */
#endif
}{...}
}{...} else {
for (uintptr_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4, num_reg++) {
esp_rom_printf("%08" PRIx32 " ", REG_READ(addr_wr_block));
}{...}
}{...}
esp_rom_printf("\n");
}{ ... }
void esp_efuse_utility_debug_dump_blocks(void)
{
esp_rom_printf("EFUSE_BLKx:\n");
for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
esp_efuse_utility_debug_dump_single_block(num_block, true);
}{...}
esp_rom_printf("\n");
}{ ... }
int esp_efuse_utility_get_number_of_items(int bits, int size_of_base)
{
return bits / size_of_base + (bits % size_of_base > 0 ? 1 : 0);
}{ ... }
esp_err_t esp_efuse_utility_write_reg(esp_efuse_block_t efuse_block, unsigned int num_reg, uint32_t reg_to_write)
{
esp_err_t err = ESP_OK;
uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
if (reg & reg_to_write) {
ESP_EARLY_LOGE(TAG, "Repeated programming of programmed bits is strictly forbidden 0x%08" PRIx32, reg & reg_to_write);
err = ESP_ERR_EFUSE_REPEATED_PROG;
}{...} else {
write_reg(efuse_block, num_reg, reg_to_write);
}{...}
return err;
}{ ... }
uint32_t esp_efuse_utility_read_reg(esp_efuse_block_t blk, unsigned int num_reg)
{
assert(blk >= 0 && blk < EFUSE_BLK_MAX);
assert(num_reg <= (range_read_addr_blocks[blk].end - range_read_addr_blocks[blk].start) / sizeof(uint32_t));
uint32_t value;
#ifdef CONFIG_EFUSE_VIRTUAL
value = virt_blocks[blk][num_reg];
#else
value = REG_READ(range_read_addr_blocks[blk].start + num_reg * 4);
#endif
return value;
}{ ... }
static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value)
{
assert(blk >= 0 && blk < EFUSE_BLK_MAX);
assert(num_reg <= (range_read_addr_blocks[blk].end - range_read_addr_blocks[blk].start) / sizeof(uint32_t));
uintptr_t addr_wr_reg = range_write_addr_blocks[blk].start + num_reg * 4;
uint32_t reg_to_write = REG_READ(addr_wr_reg) | value;
REG_WRITE(addr_wr_reg, reg_to_write);
}{ ... }
static uint32_t get_mask(unsigned int bit_count, unsigned int shift)
{
uint32_t mask;
if (bit_count != 32) {
mask = (1 << bit_count) - 1;
}{...} else {
mask = 0xFFFFFFFF;
}{...}
return mask << shift;
}{ ... }
static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob)
{
uint32_t reg_to_write = 0;
uint32_t temp_blob_32;
int shift_bit = (*filled_bits_blob) % 8;
if (shift_bit != 0) {
temp_blob_32 = blob[(*filled_bits_blob) / 8] >> shift_bit;
shift_bit = ((8 - shift_bit) < bit_count_in_reg) ? (8 - shift_bit) : bit_count_in_reg;
reg_to_write = temp_blob_32 & get_mask(shift_bit, 0);
(*filled_bits_blob) += shift_bit;
bit_count_in_reg -= shift_bit;
}{...}
int shift_reg = shift_bit;
while (bit_count_in_reg > 0) {
temp_blob_32 = blob[(*filled_bits_blob) / 8];
shift_bit = (bit_count_in_reg > 8) ? 8 : bit_count_in_reg;
reg_to_write |= (temp_blob_32 & get_mask(shift_bit, 0)) << shift_reg;
(*filled_bits_blob) += shift_bit;
bit_count_in_reg -= shift_bit;
shift_reg += 8;
}{...};
return reg_to_write << bit_start_in_reg;
}{ ... }
static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt)
{
assert((bit_start_in_reg + bit_count_used_in_reg) <= 32);
uint32_t reg_to_write = 0;
for (int i = bit_start_in_reg; i < bit_start_in_reg + bit_count_used_in_reg; ++i) {
if ((reg_masked & (1 << i)) == 0) {
reg_to_write |= (1 << i);
if (--(*cnt) == 0) {
break;
}{...}
}{...}
}{...}
return reg_to_write;
}{ ... }
static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits)
{
int max_num_bit = offset_in_bits + size_bits;
if (max_num_bit > 256) {
return false;
}{...} else {
ESP_EFUSE_FIELD_CORRESPONDS_CODING_SCHEME(blk, max_num_bit);
}{...}
return true;
}{ ... }
uintptr_t esp_efuse_utility_get_read_register_address(esp_efuse_block_t block)
{
assert(block < EFUSE_BLK_MAX);
#ifdef CONFIG_EFUSE_VIRTUAL
return (uintptr_t)&virt_blocks[block][0];
#else
return range_read_addr_blocks[block].start;
#endif
}{ ... }
#if defined(BOOTLOADER_BUILD) && defined(CONFIG_EFUSE_VIRTUAL) && !defined(CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH)
void esp_efuse_init_virtual_mode_in_ram(void)
{
esp_efuse_utility_update_virt_blocks();
}{...}
/* ... */#endif
#ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
#include "../bootloader_flash/include/bootloader_flash_priv.h"
static uint32_t esp_efuse_flash_offset = 0;
static uint32_t esp_efuse_flash_size = 0;
void esp_efuse_init_virtual_mode_in_flash(uint32_t offset, uint32_t size)
{
esp_efuse_flash_offset = offset;
esp_efuse_flash_size = size;
esp_efuse_utility_update_virt_blocks();
esp_efuse_utility_debug_dump_blocks();
}{...}
void esp_efuse_utility_erase_efuses_in_flash(void)
{
ESP_EARLY_LOGW(TAG, "[Virtual] Erasing eFuses in flash");
if (esp_efuse_flash_offset == 0) {
ESP_EARLY_LOGE(TAG, "[Virtual] no efuse partition in partition_table? (Flash is not updated)");
abort();
}{...}
esp_err_t err = bootloader_flash_erase_range(esp_efuse_flash_offset, esp_efuse_flash_size);
if (err != ESP_OK) {
ESP_EARLY_LOGE(TAG, "[Virtual] Failed to erase flash. err = 0x%x", err);
abort();
}{...}
ESP_EARLY_LOGW(TAG, "[Virtual] Erase complete");
}{...}
bool esp_efuse_utility_load_efuses_from_flash(void)
{
ESP_EARLY_LOGW(TAG, "[Virtual] try loading efuses from flash: 0x%" PRIx32 " (offset)", esp_efuse_flash_offset);
if (esp_efuse_flash_offset == 0) {
ESP_EARLY_LOGE(TAG, "[Virtual] no efuse partition in partition_table? (Flash is not updated)");
abort();
}{...}
uint32_t efuses_in_flash[sizeof(virt_blocks)];
esp_err_t err = bootloader_flash_read(esp_efuse_flash_offset, &efuses_in_flash, sizeof(efuses_in_flash), false);
if (err != ESP_OK) {
ESP_EARLY_LOGE(TAG, "[Virtual] Can not read eFuse partition from flash (err=0x%x)", err);
abort();
}{...}
for (unsigned i = 0; i < sizeof(virt_blocks); ++i) {
if (efuses_in_flash[i] != 0xFFFFFFFF) {
ESP_EARLY_LOGW(TAG, "[Virtual] Loading virtual efuse blocks from flash");
memcpy(virt_blocks, efuses_in_flash, sizeof(virt_blocks));
return true;
}{...}
}{...}
ESP_EARLY_LOGW(TAG, "[Virtual] no efuses found in flash");
return false;
}{...}
void esp_efuse_utility_write_efuses_to_flash(void)
{
if (esp_efuse_flash_offset == 0) {
ESP_EARLY_LOGE(TAG, "[Virtual] no efuse partition in partition_table? (Flash is not updated)");
abort();
}{...}
esp_err_t err = bootloader_flash_erase_range(esp_efuse_flash_offset, esp_efuse_flash_size);
if (err != ESP_OK) {
ESP_EARLY_LOGE(TAG, "[Virtual] Failed to erase flash. err = 0x%x", err);
abort();
}{...}
err = bootloader_flash_write(esp_efuse_flash_offset, &virt_blocks, sizeof(virt_blocks), false);
if (err != ESP_OK) {
ESP_EARLY_LOGE(TAG, "[Virtual] Failed to write eFuses to flash. err = 0x%x", err);
abort();
}{...}
}{...}
/* ... */#endif
bool esp_efuse_utility_is_correct_written_data(esp_efuse_block_t block, unsigned r_data_len)
{
uintptr_t* w_data = (uintptr_t*)range_write_addr_blocks[block].start;
uintptr_t* r_data = (uintptr_t*)range_read_addr_blocks[block].start;
bool correct_written_data = memcmp(w_data, r_data, r_data_len) == 0;
if (correct_written_data) {
ESP_LOGI(TAG, "BURN BLOCK%d - OK (write block == read block)", block);
return true;
}{...}
correct_written_data = true;
for (unsigned i = 0; i < r_data_len / 4; i++) {
if ((*(r_data + i) & *(w_data + i)) != *(w_data + i)) {
correct_written_data = false;
break;
}{...}
}{...}
if (correct_written_data) {
ESP_LOGI(TAG, "BURN BLOCK%d - OK (all write block bits are set)", block);
}{...} else {
ESP_LOGE(TAG, "BURN BLOCK%d - ERROR (written bits != read bits)", block);
}{...}
return correct_written_data;
}{ ... }