// Copyright 2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "esp_efuse.h" #include "esp_efuse_utility.h" #include "soc/efuse_periph.h" #include "assert.h" #include "sdkconfig.h" #include "esp_efuse_table.h" static __attribute__((unused)) const char *TAG = "efuse"; /** * @brief Keys and their attributes are packed into a structure */ typedef struct { const esp_efuse_desc_t** key_rd_dis; /**< Read protection of a key */ const esp_efuse_desc_t** key_wr_dis; /**< Write protection of a key*/ } esp_efuse_keys_t; const esp_efuse_keys_t s_table[EFUSE_BLK_KEY_MAX - EFUSE_BLK_KEY0] = { {ESP_EFUSE_RD_DIS_BLK1, ESP_EFUSE_WR_DIS_BLK1}, {ESP_EFUSE_RD_DIS_BLK2, ESP_EFUSE_WR_DIS_BLK2}, {ESP_EFUSE_RD_DIS_BLK3, ESP_EFUSE_WR_DIS_BLK3}, }; // Sets a write protection for the whole block. esp_err_t esp_efuse_set_write_protect(esp_efuse_block_t blk) { if (blk == EFUSE_BLK0 || blk >= EFUSE_BLK_MAX) { return ESP_ERR_NOT_SUPPORTED; } unsigned idx = blk - EFUSE_BLK1; return esp_efuse_write_field_cnt(s_table[idx].key_wr_dis, 1); } // read protect for blk. esp_err_t esp_efuse_set_read_protect(esp_efuse_block_t blk) { if (blk == EFUSE_BLK0 || blk >= EFUSE_BLK_MAX) { return ESP_ERR_NOT_SUPPORTED; } unsigned idx = blk - EFUSE_BLK1; return esp_efuse_write_field_cnt(s_table[idx].key_rd_dis, 1); } // get efuse coding_scheme. esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk) { esp_efuse_coding_scheme_t scheme; if (blk == EFUSE_BLK0) { scheme = EFUSE_CODING_SCHEME_NONE; } else { uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME); if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE || coding_scheme == (EFUSE_CODING_SCHEME_VAL_34 | EFUSE_CODING_SCHEME_VAL_REPEAT)) { scheme = EFUSE_CODING_SCHEME_NONE; } else if (coding_scheme == EFUSE_CODING_SCHEME_VAL_34) { scheme = EFUSE_CODING_SCHEME_3_4; } else { scheme = EFUSE_CODING_SCHEME_REPEAT; } } return scheme; } bool esp_efuse_block_is_empty(esp_efuse_block_t block) { unsigned blk_len_bit = 256; uint32_t key[8]; if (esp_efuse_get_coding_scheme(block) == EFUSE_CODING_SCHEME_3_4) { blk_len_bit = 192; } esp_err_t err = esp_efuse_read_block(block, &key, 0, blk_len_bit); if (err != ESP_OK) { return false; } unsigned zeros = 0; for (unsigned i = 0; i < blk_len_bit / 32; ++i) { if (key[i] == 0) { ++zeros; } } if (zeros == blk_len_bit / 32) { return true; } return false; } bool esp_efuse_get_key_dis_read(esp_efuse_block_t block) { assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX); unsigned idx = block - EFUSE_BLK_KEY0; return esp_efuse_read_field_bit(s_table[idx].key_rd_dis); } esp_err_t esp_efuse_set_key_dis_read(esp_efuse_block_t block) { if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) { return ESP_ERR_INVALID_ARG; } unsigned idx = block - EFUSE_BLK_KEY0; const uint8_t one = 1; return esp_efuse_write_field_blob(s_table[idx].key_rd_dis, &one, 1); } bool esp_efuse_get_key_dis_write(esp_efuse_block_t block) { assert(block >= EFUSE_BLK_KEY0 && block < EFUSE_BLK_KEY_MAX); unsigned idx = block - EFUSE_BLK_KEY0; return esp_efuse_read_field_bit(s_table[idx].key_wr_dis); } esp_err_t esp_efuse_set_key_dis_write(esp_efuse_block_t block) { if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) { return ESP_ERR_INVALID_ARG; } unsigned idx = block - EFUSE_BLK_KEY0; const uint8_t one = 1; return esp_efuse_write_field_blob(s_table[idx].key_wr_dis, &one, 1); } bool esp_efuse_key_block_unused(esp_efuse_block_t block) { if (block < EFUSE_BLK_KEY0 || block >= EFUSE_BLK_KEY_MAX) { return false; // Not a key block } if (esp_efuse_get_key_dis_read(block) || esp_efuse_get_key_dis_write(block) || !esp_efuse_block_is_empty(block)) { return false; // Block in use! } return true; // Unused }