// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (C) 2022 Foundries.io Ltd * Jorge Ramirez-Ortiz * * Copyright (C) ProvenRun SAS 2023 */ #include #include #include #include #include #include #include #include #include #define NVM_WORD_LEN 4 /* Protocol API with the remote processor */ #define NVM_MODULE_SHIFT 8 #define NVM_MODULE 11 #define NVM_API_ID(_id) (SHIFT_U32(NVM_MODULE, NVM_MODULE_SHIFT) | (_id)) #define __aligned_efuse __aligned(CACHELINE_LEN) #define EFUSE_CACHE_DNA_OFFSET 0x20 #define EFUSE_CACHE_BOOT_ENV_CTRL_OFFSET 0x94 #define EFUSE_CACHE_MISC_CTRL_OFFSET 0xA0 #define EFUSE_CACHE_PUF_ECC_CTRL_OFFSET 0xA4 #define EFUSE_CACHE_PUF_CHASH_OFFSET 0xA8 #define EFUSE_CACHE_SEC_CTRL_OFFSET 0xAC #define EFUSE_CACHE_REVOCATION_ID0_OFFSET 0xB0 #define EFUSE_CACHE_SEC_MISC0_OFFSET 0xE4 #define EFUSE_CACHE_SEC_MISC1_OFFSET 0xE8 #define EFUSE_CACHE_PPK0_OFFSET 0x100 #define EFUSE_CACHE_PPK1_OFFSET 0x120 #define EFUSE_CACHE_PPK2_OFFSET 0x140 #define EFUSE_CACHE_OFFCHIP_REVOKE_ID0_OFFSET 0x160 #define EFUSE_CACHE_METAHEADER_IV_RANGE0_OFFSET 0x180 #define EFUSE_CACHE_BLACK_IV0_OFFSET 0x1D0 #define EFUSE_CACHE_PLM_IV_RANGE0_OFFSET 0x1DC #define EFUSE_CACHE_DATA_PARTITION_IV_RANGE0_OFFSET 0x1E8 #define EFUSE_CACHE_USER0_OFFSET 0x240 #define EFUSE_CACHE_PUF_SYN0_OFFSET 0x300 #define EFUSE_ENV_DIS_FLAG 0 #define EFUSE_AES_KEY_ID 0 #define EFUSE_USER_KEY0_ID 1 #define EFUSE_USER_KEY1_ID 2 #define EFUSE_WRITE_PUF_DATA_WORDS (PUF_SYN_DATA_WORDS + 6) /* Internal */ struct versal_efuse_write_puf_data { uint32_t sec_ctrl; uint32_t prgm_puf_helper_data; uint32_t env_monitor_dis; uint32_t syn[PUF_SYN_DATA_WORDS]; uint32_t chash; uint32_t aux; uint32_t ro_swap; }; /* * Max size of the buffer needed for the remote processor to DMA efuse _data_ * to/from */ #define EFUSE_MAX_LEN (EFUSE_MAX_USER_FUSES * sizeof(uint32_t)) enum versal_nvm_api_id { API_FEATURES = 0, BBRAM_WRITE_AES_KEY = 1, BBRAM_ZEROIZE = 2, BBRAM_WRITE_USER_DATA = 3, BBRAM_READ_USER_DATA = 4, BBRAM_LOCK_WRITE_USER_DATA = 5, BBRAM_WRITE_AES_KEY_FROM_PLOAD = 6, EFUSE_WRITE_AES_KEY = 7, EFUSE_WRITE_AES_KEY_FROM_PLOAD = 8, EFUSE_WRITE_PPK_HASH = 9, EFUSE_WRITE_PPK_HASH_FROM_PLOAD = 10, EFUSE_WRITE_IV = 11, EFUSE_WRITE_IV_FROM_PLOAD = 12, EFUSE_WRITE_GLITCH_CONFIG = 13, EFUSE_WRITE_DEC_ONLY = 14, EFUSE_WRITE_REVOCATION_ID = 15, EFUSE_WRITE_OFFCHIP_REVOKE_ID = 16, EFUSE_WRITE_MISC_CTRL_BITS = 17, EFUSE_WRITE_SEC_CTRL_BITS = 18, EFUSE_WRITE_MISC1_CTRL_BITS = 19, EFUSE_WRITE_BOOT_ENV_CTRL_BITS = 20, EFUSE_WRITE_FIPS_INFO = 21, EFUSE_WRITE_UDS_FROM_PLOAD = 22, EFUSE_WRITE_DME_KEY_FROM_PLOAD = 23, EFUSE_WRITE_DME_REVOKE = 24, EFUSE_WRITE_PLM_UPDATE = 25, EFUSE_WRITE_BOOT_MODE_DISABLE = 26, EFUSE_WRITE_CRC = 27, EFUSE_WRITE_DME_MODE = 28, EFUSE_WRITE_PUF_HD_FROM_PLOAD = 29, EFUSE_WRITE_PUF = 30, EFUSE_WRITE_ROM_RSVD = 31, EFUSE_WRITE_PUF_CTRL_BITS = 32, EFUSE_READ_CACHE = 33, EFUSE_RELOAD_N_PRGM_PROT_BITS = 34, EFUSE_INVALID = 35, }; /* uint64_t are memory addresses */ struct versal_efuse_data { uint64_t env_mon_dis_flag; uint64_t aes_key_addr; uint64_t ppk_hash_addr; uint64_t dec_only_addr; uint64_t sec_ctrl_addr; uint64_t misc_ctrl_addr; uint64_t revoke_id_addr; uint64_t iv_addr; uint64_t user_fuse_addr; uint64_t glitch_cfg_addr; uint64_t boot_env_ctrl_addr; uint64_t misc1_ctrl_addr; uint64_t offchip_id_addr; uint8_t pad[24]; }; /* Helper read and write requests (not part of the protocol) */ struct versal_nvm_buf { size_t len; void *buf; }; struct versal_nvm_read_req { enum versal_nvm_api_id efuse_id; struct versal_nvm_buf ibuf[VERSAL_MAX_IPI_BUF]; }; struct versal_bbram_data { size_t aes_key_len; uint32_t user_data; }; struct versal_nvm_write_req { struct versal_efuse_data data; struct versal_bbram_data bbram; struct versal_nvm_buf ibuf[VERSAL_MAX_IPI_BUF]; enum versal_nvm_api_id efuse_id; }; static TEE_Result prepare_cmd(struct versal_ipi_cmd *cmd, enum versal_nvm_api_id efuse, struct versal_nvm_buf *ibufs, uint32_t *arg) { uint32_t low = 0; uint32_t hi = 0; size_t i = 0; cmd->data[i++] = NVM_API_ID(efuse); if (arg) cmd->data[i++] = *arg; if (!ibufs[0].buf) return TEE_SUCCESS; reg_pair_from_64(virt_to_phys(ibufs[0].buf), &hi, &low); cmd->data[i++] = low; cmd->data[i++] = hi; for (i = 0; i < VERSAL_MAX_IPI_BUF; i++) { cmd->ibuf[i].mem.alloc_len = ibufs[i].len; cmd->ibuf[i].mem.buf = ibufs[i].buf; } return TEE_SUCCESS; } static TEE_Result efuse_req(enum versal_nvm_api_id efuse, struct versal_nvm_buf *ibufs, uint32_t *arg) { struct versal_ipi_cmd cmd = { }; TEE_Result ret = TEE_SUCCESS; ret = prepare_cmd(&cmd, efuse, ibufs, arg); if (ret) return ret; ret = versal_pmc_notify(&cmd, NULL, NULL); if (ret) EMSG("Mailbox error"); return ret; } static TEE_Result versal_alloc_read_buffer(struct versal_nvm_read_req *req) { assert(req); req->ibuf[0].len = 1024; req->ibuf[0].buf = alloc_cache_aligned(req->ibuf[0].len); if (!req->ibuf[0].buf) return TEE_ERROR_OUT_OF_MEMORY; return TEE_SUCCESS; } static void versal_free_read_buffer(struct versal_nvm_read_req *req) { assert(req); free(req->ibuf[0].buf); } static void *versal_get_read_buffer(struct versal_nvm_read_req *req) { assert(req); return req->ibuf[0].buf; } static TEE_Result versal_nvm_read(struct versal_nvm_read_req *req) { if (!req) return TEE_ERROR_GENERIC; switch (req->efuse_id) { case EFUSE_READ_CACHE: case BBRAM_READ_USER_DATA: break; default: return TEE_ERROR_GENERIC; } return efuse_req(req->efuse_id, req->ibuf, NULL); } static TEE_Result versal_nvm_write(struct versal_nvm_write_req *req) { uint32_t *arg = NULL; uint32_t val = 0; switch (req->efuse_id) { case BBRAM_WRITE_AES_KEY: val = req->bbram.aes_key_len; arg = &val; break; case BBRAM_ZEROIZE: break; case BBRAM_WRITE_USER_DATA: val = req->bbram.user_data; arg = &val; break; default: return TEE_ERROR_GENERIC; } return efuse_req(req->efuse_id, req->ibuf, arg); } static TEE_Result versal_efuse_read_cache(uint16_t off, uint16_t num, uint32_t *buf, size_t len) { struct versal_ipi_cmd cmd = { }; struct versal_mbox_mem p = { }; TEE_Result ret = TEE_SUCCESS; uint32_t low = 0; uint32_t hi = 0; if (!buf) return TEE_ERROR_BAD_PARAMETERS; if (len < num * NVM_WORD_LEN) return TEE_ERROR_BAD_PARAMETERS; ret = versal_mbox_alloc(num * NVM_WORD_LEN, NULL, &p); if (ret) return ret; reg_pair_from_64(virt_to_phys(p.buf), &hi, &low); cmd.data[0] = NVM_API_ID(EFUSE_READ_CACHE); cmd.data[1] = SHIFT_U32(num, 16) | off; cmd.data[2] = low; cmd.data[3] = hi; cmd.ibuf[0].mem = p; ret = versal_pmc_notify(&cmd, NULL, NULL); if (ret) EMSG("Mailbox error"); else memcpy(buf, p.buf, num * NVM_WORD_LEN); versal_mbox_free(&p); return ret; } TEE_Result versal_efuse_read_user_data(uint32_t *buf, size_t len, uint32_t first, size_t num) { uint16_t offset = 0; if (first + num > EFUSE_MAX_USER_FUSES || len < num * NVM_WORD_LEN) return TEE_ERROR_BAD_PARAMETERS; offset = EFUSE_CACHE_USER0_OFFSET + first * NVM_WORD_LEN; return versal_efuse_read_cache(offset, num, buf, len); } TEE_Result versal_efuse_read_dna(uint32_t *buf, size_t len) { if (len < EFUSE_DNA_LEN) return TEE_ERROR_BAD_PARAMETERS; return versal_efuse_read_cache(EFUSE_CACHE_DNA_OFFSET, EFUSE_DNA_LEN / NVM_WORD_LEN, buf, len); } TEE_Result versal_efuse_read_iv(uint32_t *buf, size_t len, enum versal_nvm_iv_type type) { uint16_t offset = 0; switch (type) { case EFUSE_META_HEADER_IV_RANGE: offset = EFUSE_CACHE_METAHEADER_IV_RANGE0_OFFSET; break; case EFUSE_BLACK_IV: offset = EFUSE_CACHE_BLACK_IV0_OFFSET; break; case EFUSE_PLM_IV_RANGE: offset = EFUSE_CACHE_PLM_IV_RANGE0_OFFSET; break; case EFUSE_DATA_PARTITION_IV_RANGE: offset = EFUSE_CACHE_DATA_PARTITION_IV_RANGE0_OFFSET; break; default: return TEE_ERROR_BAD_PARAMETERS; } return versal_efuse_read_cache(offset, EFUSE_IV_LEN / NVM_WORD_LEN, buf, len); } TEE_Result versal_efuse_read_ppk(uint32_t *buf, size_t len, enum versal_nvm_ppk_type type) { uint16_t offset = 0; switch (type) { case EFUSE_PPK0: offset = EFUSE_CACHE_PPK0_OFFSET; break; case EFUSE_PPK1: offset = EFUSE_CACHE_PPK1_OFFSET; break; case EFUSE_PPK2: offset = EFUSE_CACHE_PPK2_OFFSET; break; default: return TEE_ERROR_BAD_PARAMETERS; } return versal_efuse_read_cache(offset, EFUSE_PPK_LEN / NVM_WORD_LEN, buf, len); } TEE_Result versal_efuse_write_user_data(uint32_t *buf __unused, size_t len __unused, uint32_t first __unused, size_t num __unused) { return TEE_ERROR_NOT_IMPLEMENTED; } static TEE_Result do_write_efuses_buffer(enum versal_nvm_api_id id, uint16_t type, uint32_t *buf, size_t len) { struct versal_ipi_cmd cmd = { }; struct versal_mbox_mem p = { }; TEE_Result ret = TEE_SUCCESS; uint32_t low = 0; uint32_t hi = 0; ret = versal_mbox_alloc(len, buf, &p); if (ret) return ret; reg_pair_from_64(virt_to_phys(p.buf), &hi, &low); cmd.data[0] = NVM_API_ID(id); cmd.data[1] = SHIFT_U32(type, 16) | EFUSE_ENV_DIS_FLAG; cmd.data[2] = low; cmd.data[3] = hi; cmd.ibuf[0].mem = p; ret = versal_pmc_notify(&cmd, NULL, NULL); versal_mbox_free(&p); return ret; } static TEE_Result do_write_efuses_value(enum versal_nvm_api_id id, uint32_t val) { struct versal_ipi_cmd cmd = { }; cmd.data[0] = NVM_API_ID(id); cmd.data[1] = EFUSE_ENV_DIS_FLAG; cmd.data[2] = val; return versal_pmc_notify(&cmd, NULL, NULL); } static TEE_Result do_write_efuses(enum versal_nvm_api_id id) { return do_write_efuses_value(id, 0); } TEE_Result versal_efuse_write_aes_keys(struct versal_efuse_aes_keys *keys) { TEE_Result res = TEE_SUCCESS; TEE_Result res2 = TEE_SUCCESS; if (!keys) return TEE_ERROR_BAD_PARAMETERS; if (keys->prgm_aes_key) { res2 = do_write_efuses_buffer(EFUSE_WRITE_AES_KEY, EFUSE_AES_KEY_ID, keys->aes_key, EFUSE_AES_KEY_LEN); if (res2) { DMSG("Error programming AES key (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } if (keys->prgm_user_key0) { res2 = do_write_efuses_buffer(EFUSE_WRITE_AES_KEY, EFUSE_USER_KEY0_ID, keys->user_key0, EFUSE_AES_KEY_LEN); if (res2) { DMSG("Error programming User key 0 (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } if (keys->prgm_user_key1) { res2 = do_write_efuses_buffer(EFUSE_WRITE_AES_KEY, EFUSE_USER_KEY1_ID, keys->user_key1, EFUSE_AES_KEY_LEN); if (res2) { DMSG("Error programming User key 1 (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } return res; } TEE_Result versal_efuse_write_ppk_hash(struct versal_efuse_ppk_hash *hash) { TEE_Result res = TEE_SUCCESS; TEE_Result res2 = TEE_SUCCESS; if (!hash) return TEE_ERROR_BAD_PARAMETERS; if (hash->prgm_ppk0_hash) { res2 = do_write_efuses_buffer(EFUSE_WRITE_PPK_HASH, EFUSE_PPK0, hash->ppk0_hash, EFUSE_PPK_LEN); if (res2) { DMSG("Error programming PPK hash 0 (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } if (hash->prgm_ppk1_hash) { res2 = do_write_efuses_buffer(EFUSE_WRITE_PPK_HASH, EFUSE_PPK1, hash->ppk1_hash, EFUSE_PPK_LEN); if (res2) { DMSG("Error programming PPK hash 1 (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } if (hash->prgm_ppk2_hash) { res2 = do_write_efuses_buffer(EFUSE_WRITE_PPK_HASH, EFUSE_PPK2, hash->ppk2_hash, EFUSE_PPK_LEN); if (res2) { DMSG("Error programming PPK hash 2 (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } return res; } TEE_Result versal_efuse_write_iv(struct versal_efuse_ivs *p) { TEE_Result res = TEE_SUCCESS; TEE_Result res2 = TEE_SUCCESS; if (!p) return TEE_ERROR_BAD_PARAMETERS; if (p->prgm_meta_header_iv) { res2 = do_write_efuses_buffer(EFUSE_WRITE_IV, EFUSE_META_HEADER_IV_RANGE, p->meta_header_iv, EFUSE_IV_LEN); if (res2) { DMSG("Error programming meta header IV (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } if (p->prgm_blk_obfus_iv) { res2 = do_write_efuses_buffer(EFUSE_WRITE_IV, EFUSE_BLACK_IV, p->blk_obfus_iv, EFUSE_IV_LEN); if (res2) { DMSG("Error programming black IV (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } if (p->prgm_plm_iv) { res2 = do_write_efuses_buffer(EFUSE_WRITE_IV, EFUSE_PLM_IV_RANGE, p->plm_iv, EFUSE_IV_LEN); if (res2) { DMSG("Error programming plm IV (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } if (p->prgm_data_partition_iv) { res2 = do_write_efuses_buffer(EFUSE_WRITE_IV, EFUSE_DATA_PARTITION_IV_RANGE, p->data_partition_iv, EFUSE_IV_LEN); if (res2) { DMSG("Error programming data IV (0x%" PRIx32 ")", res2); res = TEE_ERROR_GENERIC; } } return res; } TEE_Result versal_efuse_write_dec_only(struct versal_efuse_dec_only *p) { if (!p) return TEE_ERROR_BAD_PARAMETERS; if (!p->prgm_dec_only) return TEE_SUCCESS; return do_write_efuses(EFUSE_WRITE_DEC_ONLY); } TEE_Result versal_efuse_write_sec(struct versal_efuse_sec_ctrl_bits *p) { uint32_t val = 0; if (!p) return TEE_ERROR_BAD_PARAMETERS; val = SHIFT_U32(p->reg_init_dis & 0x3, 30) | SHIFT_U32(p->boot_env_wr_lk & 0x1, 28) | SHIFT_U32(p->sec_lock_dbg_dis & 0x3, 21) | SHIFT_U32(p->sec_dbg_dis & 0x3, 19) | SHIFT_U32(p->user_key1_wr_lk & 0x1, 15) | SHIFT_U32(p->user_key1_crc_lk & 0x1, 14) | SHIFT_U32(p->user_key0_wr_lk & 0x1, 13) | SHIFT_U32(p->user_key0_crc_lk & 0x1, 12) | SHIFT_U32(p->aes_wr_lk & 0x1, 11) | SHIFT_U32(p->aes_crc_lk & 0x3, 9) | SHIFT_U32(p->ppk2_wr_lk & 0x1, 8) | SHIFT_U32(p->ppk1_wr_lk & 0x1, 7) | SHIFT_U32(p->ppk0_wr_lk & 0x1, 6) | SHIFT_U32(p->jtag_dis & 0x1, 2) | SHIFT_U32(p->jtag_err_out_dis & 0x1, 1) | (p->aes_dis & 0x1); return do_write_efuses_value(EFUSE_WRITE_SEC_CTRL_BITS, val); } TEE_Result versal_efuse_write_misc(struct versal_efuse_misc_ctrl_bits *p) { uint32_t val = 0; if (!p) return TEE_ERROR_BAD_PARAMETERS; val = SHIFT_U32(p->glitch_det_halt_boot_en & 0x3, 30) | SHIFT_U32(p->glitch_det_rom_monitor_en & 0x1, 29) | SHIFT_U32(p->halt_boot_error & 0x3, 21) | SHIFT_U32(p->halt_boot_env & 0x3, 19) | SHIFT_U32(p->crypto_kat_en & 0x1, 15) | SHIFT_U32(p->lbist_en & 0x1, 14) | SHIFT_U32(p->safety_mission_en & 0x1, 8) | SHIFT_U32(p->ppk2_invalid & 0x3, 6) | SHIFT_U32(p->ppk1_invalid & 0x3, 4) | SHIFT_U32(p->ppk0_invalid & 0x3, 2); return do_write_efuses_value(EFUSE_WRITE_MISC_CTRL_BITS, val); } TEE_Result versal_efuse_write_glitch_cfg(struct versal_efuse_glitch_cfg_bits *p) { uint32_t val = 0; if (!p) return TEE_ERROR_BAD_PARAMETERS; if (!p->prgm_glitch) return TEE_SUCCESS; val = SHIFT_U32(p->glitch_det_wr_lk & 0x1, 31) | p->glitch_det_trim; return do_write_efuses_value(EFUSE_WRITE_GLITCH_CONFIG, val); } TEE_Result versal_efuse_write_boot_env(struct versal_efuse_boot_env_ctrl_bits *p) { uint32_t val = 0; if (!p) return TEE_ERROR_BAD_PARAMETERS; val = SHIFT_U32(p->sysmon_temp_en & 0x1, 21) | SHIFT_U32(p->sysmon_volt_en & 0x1, 20) | SHIFT_U32(p->sysmon_temp_hot & 0x3, 17) | SHIFT_U32(p->sysmon_volt_pmc & 0x3, 12) | SHIFT_U32(p->sysmon_volt_pslp & 0x3, 10) | SHIFT_U32(p->sysmon_volt_soc & 0x3, 8) | (p->sysmon_temp_cold & 0x2); return do_write_efuses_value(EFUSE_WRITE_BOOT_ENV_CTRL_BITS, val); } TEE_Result versal_efuse_write_sec_misc1(struct versal_efuse_sec_misc1_bits *p) { uint32_t val = 0; if (!p) return TEE_ERROR_BAD_PARAMETERS; val = SHIFT_U32(p->lpd_mbist_en & 0x7, 10) | SHIFT_U32(p->pmc_mbist_en & 0x7, 7) | SHIFT_U32(p->lpd_noc_sc_en & 0x7, 4) | SHIFT_U32(p->sysmon_volt_mon_en & 0x3, 2) | (p->sysmon_temp_mon_en & 0x3); return do_write_efuses_value(EFUSE_WRITE_MISC1_CTRL_BITS, val); } TEE_Result versal_efuse_write_offchip_ids(struct versal_efuse_offchip_ids *p) { uint32_t id = 0; bool id_valid = false; /* * XilNvm API id 0xb10 (EFUSE_WRITE_OFFCHIP_REVOKE_ID) can write a * single OffChip Revoke Id eFuse bit at a time, only! */ for (int word = 0; word <= EFUSE_OFFCHIP_REVOKE_ID_7; ++word) { uint32_t current_word = p->offchip_id[word]; if (!current_word) continue; if (id_valid) { EMSG("Trying to write multiple offchip IDs"); return TEE_ERROR_BAD_PARAMETERS; } id_valid = true; /* Determine if only 1 bit is set. */ if (!IS_POWER_OF_TWO(current_word)) { EMSG("Trying to write multiple bits (0x%08x) in offchip ID %u", current_word, word); return TEE_ERROR_BAD_PARAMETERS; } /* Determine which bit is set. */ id = (word * 32) + (31 - __builtin_clz(current_word)); } if (!id_valid) { EMSG("Trying to write no offchip IDs"); return TEE_ERROR_BAD_PARAMETERS; } /* * Do not send any command to PLM firmware, if we do not * actually want to write any eFuse. Mimics behavior of XilNvm * API id EFUSE_WRITE (0xb06) on Versal. */ if (p->prgm_offchip_id) return do_write_efuses_value(EFUSE_WRITE_OFFCHIP_REVOKE_ID, id); return TEE_SUCCESS; } TEE_Result versal_efuse_write_revoke_ppk(enum versal_nvm_ppk_type type) { struct versal_efuse_misc_ctrl_bits misc_ctrl = {}; switch (type) { case EFUSE_PPK0: misc_ctrl.ppk0_invalid = 0x3; break; case EFUSE_PPK1: misc_ctrl.ppk1_invalid = 0x3; break; case EFUSE_PPK2: misc_ctrl.ppk2_invalid = 0x3; break; default: return TEE_ERROR_BAD_PARAMETERS; } return versal_efuse_write_misc(&misc_ctrl); } TEE_Result versal_efuse_write_revoke_id(uint32_t id) { if (id < VERSAL_NET_REVOKE_EFUSE_MIN || id > VERSAL_NET_REVOKE_EFUSE_MAX) return TEE_ERROR_BAD_PARAMETERS; return do_write_efuses_value(EFUSE_WRITE_REVOCATION_ID, id); } TEE_Result versal_efuse_read_revoke_id(uint32_t *buf, size_t len, enum versal_nvm_revocation_id id) { uint32_t reg = EFUSE_CACHE_REVOCATION_ID0_OFFSET; reg += id; return versal_efuse_read_cache(reg, EFUSE_REVOCATION_ID_LEN / NVM_WORD_LEN, buf, len); } TEE_Result versal_efuse_read_misc_ctrl(struct versal_efuse_misc_ctrl_bits *buf) { TEE_Result ret = TEE_SUCCESS; uint32_t misc_ctrl = 0; if (!buf) return TEE_ERROR_BAD_PARAMETERS; ret = versal_efuse_read_cache(EFUSE_CACHE_MISC_CTRL_OFFSET, 1, &misc_ctrl, sizeof(misc_ctrl)); if (ret) return ret; buf->glitch_det_halt_boot_en = (misc_ctrl & GENMASK_32(31, 30)) >> 30; buf->glitch_det_rom_monitor_en = (misc_ctrl & BIT(29)) >> 29; buf->halt_boot_error = (misc_ctrl & GENMASK_32(22, 21)) >> 21; buf->halt_boot_env = (misc_ctrl & GENMASK_32(20, 19)) >> 19; buf->crypto_kat_en = (misc_ctrl & BIT(15)) >> 15; buf->lbist_en = (misc_ctrl & BIT(14)) >> 14; buf->safety_mission_en = (misc_ctrl & BIT(8)) >> 8; buf->ppk0_invalid = (misc_ctrl & GENMASK_32(7, 6)) >> 6; buf->ppk1_invalid = (misc_ctrl & GENMASK_32(5, 4)) >> 4; buf->ppk2_invalid = (misc_ctrl & GENMASK_32(3, 2)) >> 2; return TEE_SUCCESS; } TEE_Result versal_efuse_read_sec_ctrl(struct versal_efuse_sec_ctrl_bits *buf) { TEE_Result ret = TEE_SUCCESS; uint32_t sec_ctrl = 0; if (!buf) return TEE_ERROR_BAD_PARAMETERS; ret = versal_efuse_read_cache(EFUSE_CACHE_SEC_CTRL_OFFSET, 1, &sec_ctrl, sizeof(sec_ctrl)); if (ret) return ret; buf->aes_dis = sec_ctrl & BIT(0); buf->jtag_err_out_dis = (sec_ctrl & BIT(1)) >> 1; buf->jtag_dis = (sec_ctrl & BIT(2)) >> 2; buf->ppk0_wr_lk = (sec_ctrl & BIT(6)) >> 6; buf->ppk1_wr_lk = (sec_ctrl & BIT(7)) >> 7; buf->ppk2_wr_lk = (sec_ctrl & BIT(8)) >> 8; buf->aes_crc_lk = (sec_ctrl & GENMASK_32(10, 9)) >> 9; buf->aes_wr_lk = (sec_ctrl & BIT(11)) >> 11; buf->user_key0_crc_lk = (sec_ctrl & BIT(12)) >> 12; buf->user_key0_wr_lk = (sec_ctrl & BIT(13)) >> 13; buf->user_key1_crc_lk = (sec_ctrl & BIT(14)) >> 14; buf->user_key1_wr_lk = (sec_ctrl & BIT(15)) >> 15; buf->sec_dbg_dis = (sec_ctrl & GENMASK_32(20, 19)) >> 19; buf->sec_lock_dbg_dis = (sec_ctrl & GENMASK_32(22, 21)) >> 21; buf->boot_env_wr_lk = (sec_ctrl & BIT(28)) >> 28; buf->reg_init_dis = (sec_ctrl & GENMASK_32(31, 30)) >> 30; return TEE_SUCCESS; } TEE_Result versal_efuse_read_sec_misc1(struct versal_efuse_sec_misc1_bits *buf) { TEE_Result ret = TEE_SUCCESS; uint32_t sec_misc1 = 0; if (!buf) return TEE_ERROR_BAD_PARAMETERS; ret = versal_efuse_read_cache(EFUSE_CACHE_SEC_MISC1_OFFSET, 1, &sec_misc1, sizeof(sec_misc1)); if (ret) return ret; buf->lpd_mbist_en = (sec_misc1 & GENMASK_32(12, 10)) >> 10; buf->pmc_mbist_en = (sec_misc1 & GENMASK_32(9, 7)) >> 7; buf->lpd_noc_sc_en = (sec_misc1 & GENMASK_32(6, 4)) >> 4; buf->sysmon_volt_mon_en = (sec_misc1 & GENMASK_32(3, 2)) >> 2; buf->sysmon_temp_mon_en = sec_misc1 & GENMASK_32(1, 0); return TEE_SUCCESS; } TEE_Result versal_efuse_read_boot_env_ctrl(struct versal_efuse_boot_env_ctrl_bits *buf) { TEE_Result ret = TEE_SUCCESS; uint32_t boot_env_ctrl = 0; if (!buf) return TEE_ERROR_BAD_PARAMETERS; ret = versal_efuse_read_cache(EFUSE_CACHE_BOOT_ENV_CTRL_OFFSET, 1, &boot_env_ctrl, sizeof(boot_env_ctrl)); if (ret) return ret; buf->sysmon_temp_en = (boot_env_ctrl & BIT(21)) >> 21; buf->sysmon_volt_en = (boot_env_ctrl & BIT(20)) >> 20; buf->sysmon_temp_hot = (boot_env_ctrl & GENMASK_32(18, 17)) >> 17; buf->sysmon_volt_pmc = (boot_env_ctrl & GENMASK_32(13, 12)) >> 12; buf->sysmon_volt_pslp = (boot_env_ctrl & GENMASK_32(11, 10)) >> 10; buf->sysmon_volt_soc = (boot_env_ctrl & GENMASK_32(9, 8)) >> 8; buf->sysmon_temp_cold = boot_env_ctrl & GENMASK_32(1, 0); return TEE_SUCCESS; } TEE_Result versal_efuse_read_offchip_revoke_id(uint32_t *buf, size_t len, enum versal_nvm_offchip_id id) { uint32_t reg = EFUSE_CACHE_OFFCHIP_REVOKE_ID0_OFFSET; if (len < EFUSE_OFFCHIP_REVOCATION_ID_LEN) return TEE_ERROR_BAD_PARAMETERS; reg += id; return versal_efuse_read_cache(reg, EFUSE_OFFCHIP_REVOCATION_ID_LEN / NVM_WORD_LEN, buf, len); } TEE_Result versal_efuse_read_dec_only(uint32_t *buf, size_t len) { TEE_Result ret = TEE_SUCCESS; uint32_t sec_misc0 = 0; if (len < EFUSE_DEC_ONLY_LEN) return TEE_ERROR_BAD_PARAMETERS; ret = versal_efuse_read_cache(EFUSE_CACHE_SEC_MISC0_OFFSET, 1, &sec_misc0, sizeof(sec_misc0)); if (ret) return ret; sec_misc0 &= GENMASK_32(15, 0); memcpy(buf, &sec_misc0, EFUSE_DEC_ONLY_LEN); return TEE_SUCCESS; } TEE_Result versal_efuse_read_puf_sec_ctrl(struct versal_efuse_puf_sec_ctrl_bits *buf) { TEE_Result ret = TEE_SUCCESS; uint32_t puf_ctrl = 0; uint32_t sec_ctrl = 0; if (!buf) return TEE_ERROR_BAD_PARAMETERS; ret = versal_efuse_read_cache(EFUSE_CACHE_PUF_ECC_CTRL_OFFSET, 1, &puf_ctrl, sizeof(puf_ctrl)); if (ret) return ret; /* Some fuses have moved from PUF_ECC_CTRL to SECURITY_CTRL */ ret = versal_efuse_read_cache(EFUSE_CACHE_SEC_CTRL_OFFSET, 1, &sec_ctrl, sizeof(sec_ctrl)); if (ret) return ret; buf->puf_regen_dis = (puf_ctrl & BIT(31)) >> 31; buf->puf_hd_invalid = (puf_ctrl & BIT(30)) >> 30; buf->puf_test2_dis = (puf_ctrl & BIT(29)) >> 29; buf->puf_dis = (sec_ctrl & BIT(18)) >> 18; buf->puf_syn_lk = (sec_ctrl & BIT(16)) >> 16; return TEE_SUCCESS; } TEE_Result versal_efuse_read_puf(struct versal_efuse_puf_header *buf) { TEE_Result ret = TEE_SUCCESS; if (!buf) return TEE_ERROR_BAD_PARAMETERS; ret = versal_efuse_read_puf_sec_ctrl(&buf->sec_ctrl); if (ret) return ret; ret = versal_efuse_read_cache(EFUSE_CACHE_SEC_CTRL_OFFSET, 1, &buf->aux, sizeof(uint32_t)); if (ret) return ret; buf->aux &= GENMASK_32(23, 0); ret = versal_efuse_read_cache(EFUSE_CACHE_PUF_CHASH_OFFSET, 1, &buf->chash, sizeof(uint32_t)); if (ret) return ret; return versal_efuse_read_cache(EFUSE_CACHE_PUF_SYN0_OFFSET, PUF_SYN_DATA_WORDS, buf->efuse_syn_data, PUF_SYN_DATA_WORDS * NVM_WORD_LEN); } TEE_Result versal_efuse_read_puf_as_user_fuse(struct versal_efuse_puf_user_fuse *p __unused) { return TEE_ERROR_NOT_IMPLEMENTED; } TEE_Result versal_efuse_write_puf_as_user_fuse(struct versal_efuse_puf_user_fuse *p __unused) { return TEE_ERROR_NOT_IMPLEMENTED; } TEE_Result versal_efuse_write_puf(struct versal_efuse_puf_header *buf) { struct versal_ipi_cmd cmd = { }; struct versal_mbox_mem p = { }; TEE_Result ret = TEE_SUCCESS; uint32_t low = 0; uint32_t hi = 0; struct versal_efuse_write_puf_data *data = NULL; if (!buf) return TEE_ERROR_BAD_PARAMETERS; ret = versal_mbox_alloc(EFUSE_WRITE_PUF_DATA_WORDS * NVM_WORD_LEN, NULL, &p); if (ret) return ret; data = p.buf; data->sec_ctrl = 0; data->prgm_puf_helper_data = buf->prmg_puf_helper_data; data->env_monitor_dis = buf->env_monitor_dis; memcpy(data->syn, buf->efuse_syn_data, PUF_SYN_DATA_WORDS * NVM_WORD_LEN); data->chash = buf->chash; data->aux = buf->aux; data->ro_swap = 0; reg_pair_from_64(virt_to_phys(p.buf), &hi, &low); cmd.data[0] = NVM_API_ID(EFUSE_WRITE_PUF); cmd.data[2] = low; cmd.data[3] = hi; cmd.ibuf[0].mem = p; ret = versal_pmc_notify(&cmd, NULL, NULL); versal_mbox_free(&p); return ret; } TEE_Result versal_bbram_write_aes_key(uint8_t *key, size_t len) { struct versal_nvm_write_req req __aligned_efuse = { .efuse_id = BBRAM_WRITE_AES_KEY, .bbram.aes_key_len = len, }; void *buf = NULL; if (len != 32) return TEE_ERROR_BAD_PARAMETERS; buf = alloc_cache_aligned(1024); if (!buf) return TEE_ERROR_OUT_OF_MEMORY; memcpy(buf, key, len); req.ibuf[0].buf = buf; req.ibuf[0].len = 1024; if (versal_nvm_write(&req)) { free(buf); return TEE_ERROR_GENERIC; } free(buf); return TEE_SUCCESS; } TEE_Result versal_bbram_zeroize(void) { struct versal_nvm_write_req req __aligned_efuse = { .efuse_id = BBRAM_ZEROIZE, }; if (versal_nvm_write(&req)) return TEE_ERROR_GENERIC; return TEE_SUCCESS; } TEE_Result versal_bbram_write_user_data(uint32_t data) { struct versal_nvm_write_req req __aligned_efuse = { .efuse_id = BBRAM_WRITE_USER_DATA, .bbram.user_data = data, }; if (versal_nvm_write(&req)) return TEE_ERROR_GENERIC; return TEE_SUCCESS; } TEE_Result versal_bbram_read_user_data(uint32_t *data) { struct versal_nvm_read_req req = { .efuse_id = BBRAM_READ_USER_DATA, }; if (versal_alloc_read_buffer(&req)) return TEE_ERROR_OUT_OF_MEMORY; if (versal_nvm_read(&req)) { versal_free_read_buffer(&req); return TEE_ERROR_GENERIC; } memcpy(data, versal_get_read_buffer(&req), sizeof(*data)); versal_free_read_buffer(&req); return TEE_SUCCESS; } TEE_Result versal_bbram_lock_write_user_data(void) { struct versal_nvm_write_req req __aligned_efuse = { .efuse_id = BBRAM_LOCK_WRITE_USER_DATA, }; if (versal_nvm_write(&req)) return TEE_ERROR_GENERIC; return TEE_SUCCESS; }