From 7d2065cd9b1105809fdb35b2d7b799ee3bd22fae Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Wed, 8 Apr 2020 12:21:45 +0530 Subject: [PATCH] soc: qcom: Add HWKM driver for FBE Add hardware key manager driver in the HLOS kernel to facilitate storage encryption using HWKM. Change-Id: I6d7b04445aa04fd160ab4dde9b75aa4b79ae82b1 Signed-off-by: AnilKumar Chimata --- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/hwkm.c | 1214 +++++++++++++++++++++++++++++ drivers/soc/qcom/hwkm_serialize.h | 122 +++ drivers/soc/qcom/hwkmregs.h | 261 +++++++ include/linux/hwkm.h | 306 ++++++++ 6 files changed, 1914 insertions(+) create mode 100644 drivers/soc/qcom/hwkm.c create mode 100644 drivers/soc/qcom/hwkm_serialize.h create mode 100644 drivers/soc/qcom/hwkmregs.h create mode 100644 include/linux/hwkm.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 98c3c24b88f5..ee74d75788a6 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -873,6 +873,15 @@ config QCOM_HYP_CORE_CTL An offline CPU is considered as a reserved CPU since this OS can't use it. +config QTI_HW_KEY_MANAGER + tristate "Enable QTI Hardware Key Manager for storage encryption" + default n + help + Say 'Y' to enable the hardware key manager driver used to operate + and access key manager hardware block. This is used to interface with + HWKM hardware to perform key operations from the kernel which will + be used for storage encryption. + source "drivers/soc/qcom/icnss2/Kconfig" config ICNSS diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 4856a437c764..82a260ecdcc4 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -102,3 +102,5 @@ obj-$(CONFIG_QTI_L2_REUSE) += l2_reuse.o obj-$(CONFIG_ICNSS2) += icnss2/ obj-$(CONFIG_QTI_CRYPTO_COMMON) += crypto-qti-common.o obj-$(CONFIG_QTI_CRYPTO_TZ) += crypto-qti-tz.o +obj-$(CONFIG_QTI_HW_KEY_MANAGER) += hwkm_qti.o +hwkm_qti-y += hwkm.o diff --git a/drivers/soc/qcom/hwkm.c b/drivers/soc/qcom/hwkm.c new file mode 100644 index 000000000000..af19d185d1bd --- /dev/null +++ b/drivers/soc/qcom/hwkm.c @@ -0,0 +1,1214 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * QTI hardware key manager driver. + * + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "hwkmregs.h" +#include "hwkm_serialize.h" + +#define BYTES_TO_WORDS(bytes) (((bytes) + 3) / 4) + +#define WRITE_TO_KDF_PACKET(cmd_ptr, src, len) \ + do { \ + memcpy(cmd_ptr, src, len); \ + cmd_ptr += len; \ + } while (0) + +#define ASYNC_CMD_HANDLING false + +// Maximum number of times to poll +#define MAX_RETRIES 20000 + +int retries; +#define WAIT_UNTIL(cond) \ +for (retries = 0; !(cond) && (retries < MAX_RETRIES); retries++) + +#define ICEMEM_SLAVE_TPKEY_VAL 0x192 +#define ICEMEM_SLAVE_TPKEY_SLOT 0x92 +#define KM_MASTER_TPKEY_SLOT 10 + +struct hwkm_clk_info { + struct list_head list; + struct clk *clk; + const char *name; + u32 max_freq; + u32 min_freq; + u32 curr_freq; + bool enabled; +}; + +struct hwkm_device { + struct device *dev; + void __iomem *km_base; + void __iomem *ice_base; + struct resource *km_res; + struct resource *ice_res; + struct list_head clk_list_head; + bool is_hwkm_clk_available; + bool is_hwkm_enabled; +}; + +static struct hwkm_device *km_device; + +#define qti_hwkm_readl(hwkm, reg, dest) \ + (((dest) == KM_MASTER) ? \ + (readl_relaxed((hwkm)->km_base + (reg))) : \ + (readl_relaxed((hwkm)->ice_base + (reg)))) +#define qti_hwkm_writel(hwkm, val, reg, dest) \ + (((dest) == KM_MASTER) ? \ + (writel_relaxed((val), (hwkm)->km_base + (reg))) : \ + (writel_relaxed((val), (hwkm)->ice_base + (reg)))) +#define qti_hwkm_setb(hwkm, reg, nr, dest) { \ + u32 val = qti_hwkm_readl(hwkm, reg, dest); \ + val |= (0x1 << nr); \ + qti_hwkm_writel(hwkm, val, reg, dest); \ +} +#define qti_hwkm_clearb(hwkm, reg, nr, dest) { \ + u32 val = qti_hwkm_readl(hwkm, reg, dest); \ + val &= ~(0x1 << nr); \ + qti_hwkm_writel(hwkm, val, reg, dest); \ +} + +static inline bool qti_hwkm_testb(struct hwkm_device *hwkm, u32 reg, u8 nr, + enum hwkm_destination dest) +{ + u32 val = qti_hwkm_readl(hwkm, reg, dest); + + val = (val >> nr) & 0x1; + if (val == 0) + return false; + return true; +} + +static inline unsigned int qti_hwkm_get_reg_data(struct hwkm_device *dev, + u32 reg, u32 offset, u32 mask, + enum hwkm_destination dest) +{ + u32 val = 0; + + val = qti_hwkm_readl(dev, reg, dest); + return ((val & mask) >> offset); +} + +/** + * @brief Send a command packet to the HWKM Master instance as described + * in section 3.2.5.1 of Key Manager HPG + * - Clear CMD FIFO + * - Clear Error Status Register + * - Write CMD_ENABLE = 1 + * - for word in cmd_packet: + * - poll until CMD_FIFO_AVAILABLE_SPACE > 0. + * Timeout error after 1,000 retries. + * - write word to CMD register + * - for word in rsp_packet: + * - poll until RSP_FIFO_AVAILABLE_DATA > 0. + * Timeout error after 1,000 retries. + * - read word from RSP register + * - Verify CMD_DONE == 1 + * - Clear CMD_DONE + * + * @return HWKM_SUCCESS if successful. HWKW Error Code otherwise. + */ + +static int qti_hwkm_master_transaction(struct hwkm_device *dev, + const uint32_t *cmd_packet, + size_t cmd_words, + uint32_t *rsp_packet, + size_t rsp_words) +{ + int i = 0; + int err = 0; + + // Clear CMD FIFO + qti_hwkm_setb(dev, QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL, + CMD_FIFO_CLEAR_BIT, KM_MASTER); + /* Write memory barrier */ + wmb(); + qti_hwkm_clearb(dev, QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL, + CMD_FIFO_CLEAR_BIT, KM_MASTER); + /* Write memory barrier */ + wmb(); + + // Clear previous CMD errors + qti_hwkm_writel(dev, 0x0, QTI_HWKM_MASTER_RG_BANK2_BANKN_ESR, + KM_MASTER); + /* Write memory barrier */ + wmb(); + + // Enable command + qti_hwkm_setb(dev, QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL, CMD_ENABLE_BIT, + KM_MASTER); + /* Write memory barrier */ + wmb(); + + if (qti_hwkm_testb(dev, QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL, + CMD_FIFO_CLEAR_BIT, KM_MASTER)) { + + pr_err("%s: CMD_FIFO_CLEAR_BIT not set\n", __func__); + err = -1; + return -err; + } + + for (i = 0; i < cmd_words; i++) { + WAIT_UNTIL(qti_hwkm_get_reg_data(dev, + QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS, + CMD_FIFO_AVAILABLE_SPACE, CMD_FIFO_AVAILABLE_SPACE_MASK, + KM_MASTER) > 0); + if (qti_hwkm_get_reg_data(dev, + QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS, + CMD_FIFO_AVAILABLE_SPACE, CMD_FIFO_AVAILABLE_SPACE_MASK, + KM_MASTER) == 0) { + pr_err("%s: cmd fifo space not available\n", __func__); + err = -1; + return err; + } + qti_hwkm_writel(dev, cmd_packet[i], + QTI_HWKM_MASTER_RG_BANK2_CMD_0, KM_MASTER); + /* Write memory barrier */ + wmb(); + } + + for (i = 0; i < rsp_words; i++) { + WAIT_UNTIL(qti_hwkm_get_reg_data(dev, + QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS, + RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK, + KM_MASTER) > 0); + if (qti_hwkm_get_reg_data(dev, + QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS, + RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK, + KM_MASTER) == 0) { + pr_err("%s: rsp fifo data not available\n", __func__); + err = -1; + return err; + } + rsp_packet[i] = qti_hwkm_readl(dev, + QTI_HWKM_MASTER_RG_BANK2_RSP_0, KM_MASTER); + } + + if (!qti_hwkm_testb(dev, QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_STATUS, + CMD_DONE_BIT, KM_MASTER)) { + pr_err("%s: CMD_DONE_BIT not set\n", __func__); + err = -1; + return err; + } + + // Clear CMD_DONE status bit + qti_hwkm_setb(dev, QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_STATUS, + CMD_DONE_BIT, KM_MASTER); + /* Write memory barrier */ + wmb(); + + return err; +} + +/** + * @brief Send a command packet to the HWKM ICE slave instance as described in + * section 3.2.5.1 of Key Manager HPG + * - Clear CMD FIFO + * - Clear Error Status Register + * - Write CMD_ENABLE = 1 + * - for word in cmd_packet: + * - poll until CMD_FIFO_AVAILABLE_SPACE > 0. + * Timeout error after 1,000 retries. + * - write word to CMD register + * - for word in rsp_packet: + * - poll until RSP_FIFO_AVAILABLE_DATA > 0. + * Timeout error after 1,000 retries. + * - read word from RSP register + * - Verify CMD_DONE == 1 + * - Clear CMD_DONE + * + * @return HWKM_SUCCESS if successful. HWKW Error Code otherwise. + */ + +static int qti_hwkm_ice_transaction(struct hwkm_device *dev, + const uint32_t *cmd_packet, + size_t cmd_words, + uint32_t *rsp_packet, + size_t rsp_words) +{ + int i = 0; + int err = 0; + + // Clear CMD FIFO + qti_hwkm_setb(dev, QTI_HWKM_ICE_RG_BANK0_BANKN_CTL, + CMD_FIFO_CLEAR_BIT, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + qti_hwkm_clearb(dev, QTI_HWKM_ICE_RG_BANK0_BANKN_CTL, + CMD_FIFO_CLEAR_BIT, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + + // Clear previous CMD errors + qti_hwkm_writel(dev, 0x0, QTI_HWKM_ICE_RG_BANK0_BANKN_ESR, + ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + + // Enable command + qti_hwkm_setb(dev, QTI_HWKM_ICE_RG_BANK0_BANKN_CTL, CMD_ENABLE_BIT, + ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + + if (qti_hwkm_testb(dev, QTI_HWKM_ICE_RG_BANK0_BANKN_CTL, + CMD_FIFO_CLEAR_BIT, ICEMEM_SLAVE)) { + + pr_err("%s: CMD_FIFO_CLEAR_BIT not set\n", __func__); + err = -1; + return err; + } + + for (i = 0; i < cmd_words; i++) { + WAIT_UNTIL(qti_hwkm_get_reg_data(dev, + QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS, + CMD_FIFO_AVAILABLE_SPACE, CMD_FIFO_AVAILABLE_SPACE_MASK, + ICEMEM_SLAVE) > 0); + if (qti_hwkm_get_reg_data(dev, + QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS, + CMD_FIFO_AVAILABLE_SPACE, CMD_FIFO_AVAILABLE_SPACE_MASK, + ICEMEM_SLAVE) == 0) { + pr_err("%s: cmd fifo space not available\n", __func__); + err = -1; + return err; + } + qti_hwkm_writel(dev, cmd_packet[i], + QTI_HWKM_ICE_RG_BANK0_CMD_0, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + } + + for (i = 0; i < rsp_words; i++) { + WAIT_UNTIL(qti_hwkm_get_reg_data(dev, + QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS, + RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK, + ICEMEM_SLAVE) > 0); + if (qti_hwkm_get_reg_data(dev, + QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS, + RSP_FIFO_AVAILABLE_DATA, RSP_FIFO_AVAILABLE_DATA_MASK, + ICEMEM_SLAVE) == 0) { + pr_err("%s: rsp fifo data not available\n", __func__); + err = -1; + return err; + } + rsp_packet[i] = qti_hwkm_readl(dev, + QTI_HWKM_ICE_RG_BANK0_RSP_0, ICEMEM_SLAVE); + } + + if (!qti_hwkm_testb(dev, QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS, + CMD_DONE_BIT, ICEMEM_SLAVE)) { + pr_err("%s: CMD_DONE_BIT not set\n", __func__); + err = -1; + return err; + } + + // Clear CMD_DONE status bit + qti_hwkm_setb(dev, QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS, + CMD_DONE_BIT, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + + return err; +} + +/* + * @brief Send a command packet to the selected KM instance and read + * the response + * + * @param dest [in] Destination KM instance + * @param cmd_packet [in] pointer to start of command packet + * @param cmd_words [in] words in the command packet + * @param rsp_packet [out] pointer to start of response packet + * @param rsp_words [in] words in the response buffer + * + * @return HWKM_SUCCESS if successful. HWKW Error Code otherwise. + */ + +static int qti_hwkm_run_transaction(enum hwkm_destination dest, + const uint32_t *cmd_packet, + size_t cmd_words, + uint32_t *rsp_packet, + size_t rsp_words) +{ + int status = 0; + + if (cmd_packet == NULL || rsp_packet == NULL) { + status = -1; + return status; + } + + switch (dest) { + case KM_MASTER: + status = qti_hwkm_master_transaction(km_device, + cmd_packet, cmd_words, + rsp_packet, rsp_words); + break; + case ICEMEM_SLAVE: + status = qti_hwkm_ice_transaction(km_device, + cmd_packet, cmd_words, + rsp_packet, rsp_words); + break; + default: + status = -2; + break; + } + + return status; +} + +static void serialize_policy(struct hwkm_serialized_policy *out, + const struct hwkm_key_policy *policy) +{ + memset(out, 0, sizeof(struct hwkm_serialized_policy)); + out->wrap_with_tpkey = policy->wrap_with_tpk_allowed; + out->hw_destination = policy->hw_destination; + out->security_level = policy->security_lvl; + out->swap_export_allowed = policy->swap_export_allowed; + out->wrap_export_allowed = policy->wrap_export_allowed; + out->key_type = policy->key_type; + out->kdf_depth = policy->kdf_depth; + out->encrypt_allowed = policy->enc_allowed; + out->decrypt_allowed = policy->dec_allowed; + out->alg_allowed = policy->alg_allowed; + out->key_management_by_tz_secure_allowed = policy->km_by_tz_allowed; + out->key_management_by_nonsecure_allowed = policy->km_by_nsec_allowed; + out->key_management_by_modem_allowed = policy->km_by_modem_allowed; + out->key_management_by_spu_allowed = policy->km_by_spu_allowed; +} + +static void serialize_kdf_bsve(struct hwkm_kdf_bsve *out, + const struct hwkm_bsve *bsve, u8 mks) +{ + memset(out, 0, sizeof(struct hwkm_kdf_bsve)); + out->mks = mks; + out->key_policy_version_en = bsve->km_key_policy_ver_en; + out->apps_secure_en = bsve->km_apps_secure_en; + out->msa_secure_en = bsve->km_msa_secure_en; + out->lcm_fuse_row_en = bsve->km_lcm_fuse_en; + out->boot_stage_otp_en = bsve->km_boot_stage_otp_en; + out->swc_en = bsve->km_swc_en; + out->fuse_region_sha_digest_en = bsve->km_fuse_region_sha_digest_en; + out->child_key_policy_en = bsve->km_child_key_policy_en; + out->mks_en = bsve->km_mks_en; +} + +static void deserialize_policy(struct hwkm_key_policy *out, + const struct hwkm_serialized_policy *policy) +{ + memset(out, 0, sizeof(struct hwkm_key_policy)); + out->wrap_with_tpk_allowed = policy->wrap_with_tpkey; + out->hw_destination = policy->hw_destination; + out->security_lvl = policy->security_level; + out->swap_export_allowed = policy->swap_export_allowed; + out->wrap_export_allowed = policy->wrap_export_allowed; + out->key_type = policy->key_type; + out->kdf_depth = policy->kdf_depth; + out->enc_allowed = policy->encrypt_allowed; + out->dec_allowed = policy->decrypt_allowed; + out->alg_allowed = policy->alg_allowed; + out->km_by_tz_allowed = policy->key_management_by_tz_secure_allowed; + out->km_by_nsec_allowed = policy->key_management_by_nonsecure_allowed; + out->km_by_modem_allowed = policy->key_management_by_modem_allowed; + out->km_by_spu_allowed = policy->key_management_by_spu_allowed; +} + +static void reverse_key(u8 *key, size_t keylen) +{ + size_t left = 0; + size_t right = 0; + + for (left = 0, right = keylen - 1; left < right; left++, right--) { + key[left] ^= key[right]; + key[right] ^= key[left]; + key[left] ^= key[right]; + } +} + +/* + * Command packet format (word indices): + * CMD[0] = Operation info (OP, IRQ_EN, DKS, LEN) + * CMD[1:17] = Wrapped Key Blob + * CMD[18] = CRC (disabled) + * + * Response packet format (word indices): + * RSP[0] = Operation info (OP, IRQ_EN, LEN) + * RSP[1] = Error status + */ + +static int qti_handle_key_unwrap_import(const struct hwkm_cmd *cmd_in, + struct hwkm_rsp *rsp_in) +{ + int status = 0; + u32 cmd[UNWRAP_IMPORT_CMD_WORDS] = {0}; + u32 rsp[UNWRAP_IMPORT_RSP_WORDS] = {0}; + struct hwkm_operation_info operation = { + .op = KEY_UNWRAP_IMPORT, + .irq_en = ASYNC_CMD_HANDLING, + .slot1_desc = cmd_in->unwrap.dks, + .slot2_desc = cmd_in->unwrap.kwk, + .len = UNWRAP_IMPORT_CMD_WORDS + }; + + pr_debug("%s: KEY_UNWRAP_IMPORT start\n", __func__); + + memcpy(cmd, &operation, OPERATION_INFO_LENGTH); + memcpy(cmd + COMMAND_WRAPPED_KEY_IDX, cmd_in->unwrap.wkb, + cmd_in->unwrap.sz); + + status = qti_hwkm_run_transaction(ICEMEM_SLAVE, cmd, + UNWRAP_IMPORT_CMD_WORDS, rsp, UNWRAP_IMPORT_RSP_WORDS); + if (status) { + pr_err("%s: Error running transaction %d\n", __func__, status); + return status; + } + + rsp_in->status = rsp[RESPONSE_ERR_IDX]; + if (rsp_in->status) { + pr_err("%s: KEY_UNWRAP_IMPORT error status 0x%x\n", __func__, + rsp_in->status); + return rsp_in->status; + } + + return status; +} + +/* + * Command packet format (word indices): + * CMD[0] = Operation info (OP, IRQ_EN, DKS, DK, LEN) + * CMD[1] = CRC (disabled) + * + * Response packet format (word indices): + * RSP[0] = Operation info (OP, IRQ_EN, LEN) + * RSP[1] = Error status + */ + +static int qti_handle_keyslot_clear(const struct hwkm_cmd *cmd_in, + struct hwkm_rsp *rsp_in) +{ + int status = 0; + u32 cmd[KEYSLOT_CLEAR_CMD_WORDS] = {0}; + u32 rsp[KEYSLOT_CLEAR_RSP_WORDS] = {0}; + struct hwkm_operation_info operation = { + .op = KEY_SLOT_CLEAR, + .irq_en = ASYNC_CMD_HANDLING, + .slot1_desc = cmd_in->clear.dks, + .op_flag = cmd_in->clear.is_double_key, + .len = KEYSLOT_CLEAR_CMD_WORDS + }; + + pr_debug("%s: KEY_SLOT_CLEAR start\n", __func__); + + memcpy(cmd, &operation, OPERATION_INFO_LENGTH); + + status = qti_hwkm_run_transaction(ICEMEM_SLAVE, cmd, + KEYSLOT_CLEAR_CMD_WORDS, rsp, + KEYSLOT_CLEAR_RSP_WORDS); + if (status) { + pr_err("%s: Error running transaction %d\n", __func__, status); + return status; + } + + rsp_in->status = rsp[RESPONSE_ERR_IDX]; + if (rsp_in->status) { + pr_err("%s: KEYSLOT_CLEAR error status 0x%x\n", + __func__, rsp_in->status); + return rsp_in->status; + } + + return status; +} + +/* + * NOTE: The command packet can vary in length. If BE = 0, the last 2 indices + * for the BSVE are skipped. Similarly, if Software Context Length (SCL) < 16, + * only SCL words are written to the packet. The CRC word is after the last + * word of the SWC. The LEN field of this command does not include the SCL + * (unlike other commands where the LEN field is the length of the entire + * packet). The HW will expect SCL + LEN words to be sent. + * + * Command packet format (word indices): + * CMD[0] = Operation info (OP, IRQ_EN, DKS, KDK, BE, SCL, LEN) + * CMD[1:2] = Policy + * CMD[3] = BSVE[0] if BE = 1, 0 if BE = 0 + * CMD[4:5] = BSVE[1:2] if BE = 1, skipped if BE = 0 + * CMD[6:21] = Software Context, only writing the number of words in SCL + * CMD[22] = CRC + * + * Response packet format (word indices): + * RSP[0] = Operation info (OP, IRQ_EN, LEN) + * RSP[1] = Error status + */ + +static int qti_handle_system_kdf(const struct hwkm_cmd *cmd_in, + struct hwkm_rsp *rsp_in) +{ + int status = 0; + u32 cmd[SYSTEM_KDF_CMD_MAX_WORDS] = {0}; + u32 rsp[SYSTEM_KDF_RSP_WORDS] = {0}; + u8 *cmd_ptr = (u8 *) cmd; + struct hwkm_serialized_policy policy; + struct hwkm_operation_info operation = { + .op = SYSTEM_KDF, + .irq_en = ASYNC_CMD_HANDLING, + .slot1_desc = cmd_in->kdf.dks, + .slot2_desc = cmd_in->kdf.kdk, + .op_flag = cmd_in->kdf.bsve.enabled, + .context_len = BYTES_TO_WORDS(cmd_in->kdf.sz), + .len = SYSTEM_KDF_CMD_MIN_WORDS + + (cmd_in->kdf.bsve.enabled ? BSVE_WORDS : 1) + }; + + pr_debug("%s: SYSTEM_KDF start\n", __func__); + + serialize_policy(&policy, &cmd_in->kdf.policy); + + WRITE_TO_KDF_PACKET(cmd_ptr, &operation, OPERATION_INFO_LENGTH); + WRITE_TO_KDF_PACKET(cmd_ptr, &policy, KEY_POLICY_LENGTH); + + if (cmd_in->kdf.bsve.enabled) { + struct hwkm_kdf_bsve bsve; + + serialize_kdf_bsve(&bsve, &cmd_in->kdf.bsve, cmd_in->kdf.mks); + WRITE_TO_KDF_PACKET(cmd_ptr, &bsve, MAX_BSVE_LENGTH); + } else { + // Skip the remaining 3 bytes of the current word + cmd_ptr += 3 * (sizeof(u8)); + } + + WRITE_TO_KDF_PACKET(cmd_ptr, cmd_in->kdf.ctx, cmd_in->kdf.sz); + + status = qti_hwkm_run_transaction(ICEMEM_SLAVE, cmd, + operation.len + operation.context_len, + rsp, SYSTEM_KDF_RSP_WORDS); + if (status) { + pr_err("%s: Error running transaction %d\n", __func__, status); + return status; + } + + rsp_in->status = rsp[RESPONSE_ERR_IDX]; + if (rsp_in->status) { + pr_err("%s: SYSTEM_KDF error status 0x%x\n", __func__, + rsp_in->status); + return rsp_in->status; + } + + return status; +} + +/* + * Command packet format (word indices): + * CMD[0] = Operation info (OP, IRQ_EN, SKS, LEN) + * CMD[1] = CRC (disabled) + * + * Response packet format (word indices): + * RSP[0] = Operation info (OP, IRQ_EN, LEN) + * RSP[1] = Error status + */ + +static int qti_handle_set_tpkey(const struct hwkm_cmd *cmd_in, + struct hwkm_rsp *rsp_in) +{ + int status = 0; + u32 cmd[SET_TPKEY_CMD_WORDS] = {0}; + u32 rsp[SET_TPKEY_RSP_WORDS] = {0}; + struct hwkm_operation_info operation = { + .op = SET_TPKEY, + .irq_en = ASYNC_CMD_HANDLING, + .slot1_desc = cmd_in->set_tpkey.sks, + .len = SET_TPKEY_CMD_WORDS + }; + + pr_debug("%s: SET_TPKEY start\n", __func__); + + memcpy(cmd, &operation, OPERATION_INFO_LENGTH); + + status = qti_hwkm_run_transaction(KM_MASTER, cmd, + SET_TPKEY_CMD_WORDS, rsp, SET_TPKEY_RSP_WORDS); + if (status) { + pr_err("%s: Error running transaction %d\n", __func__, status); + return status; + } + + rsp_in->status = rsp[RESPONSE_ERR_IDX]; + if (rsp_in->status) { + pr_err("%s: SET_TPKEY error status 0x%x\n", __func__, + rsp_in->status); + return rsp_in->status; + } + + return status; +} + +/** + * 254 * NOTE: To anyone maintaining or porting this code wondering why the key + * is reversed in the command packet: the plaintext key value is expected by + * the HW in reverse byte order. + * See section 1.8.2.2 of the HWKM CPAS for more details + * Mapping of key to CE key read order: + * Key[255:224] -> CRYPTO0_CRYPTO_ENCR_KEY0 + * Key[223:192] -> CRYPTO0_CRYPTO_ENCR_KEY1 + * ... + * Key[63:32] -> CRYPTO0_CRYPTO_ENCR_KEY6 + * Key[31:0] -> CRYPTO0_CRYPTO_ENCR_KEY7 + * In this notation Key[31:0] is the least significant word of the key + * If the key length is less than 256 bits, the key is filled in from + * higher index to lower + * For example, for a 128 bit key, Key[255:128] would have the key, + * Key[127:0] would be all 0 + * This means that CMD[3:6] is all 0, CMD[7:10] has the key value. + * + * Command packet format (word indices): + * CMD[0] = Operation info (OP, IRQ_EN, DKS/SKS, WE, LEN) + * CMD[1:2] = Policy (0 if we == 0) + * CMD[3:10] = Write key value (0 if we == 0) + * CMD[11] = CRC (disabled) + * + * Response packet format (word indices): + * RSP[0] = Operation info (OP, IRQ_EN, LEN) + * RSP[1] = Error status + * RSP[2:3] = Policy (0 if we == 1) + * RSP[4:11] = Read key value (0 if we == 1) + **/ + +static int qti_handle_keyslot_rdwr(const struct hwkm_cmd *cmd_in, + struct hwkm_rsp *rsp_in) +{ + int status = 0; + u32 cmd[KEYSLOT_RDWR_CMD_WORDS] = {0}; + u32 rsp[KEYSLOT_RDWR_RSP_WORDS] = {0}; + struct hwkm_serialized_policy policy; + struct hwkm_operation_info operation = { + .op = KEY_SLOT_RDWR, + .irq_en = ASYNC_CMD_HANDLING, + .slot1_desc = cmd_in->rdwr.slot, + .op_flag = cmd_in->rdwr.is_write, + .len = KEYSLOT_RDWR_CMD_WORDS + }; + + pr_debug("%s: KEY_SLOT_RDWR start\n", __func__); + memcpy(cmd, &operation, OPERATION_INFO_LENGTH); + + if (cmd_in->rdwr.is_write) { + serialize_policy(&policy, &cmd_in->rdwr.policy); + memcpy(cmd + COMMAND_KEY_POLICY_IDX, &policy, + KEY_POLICY_LENGTH); + memcpy(cmd + COMMAND_KEY_VALUE_IDX, cmd_in->rdwr.key, + cmd_in->rdwr.sz); + // Need to reverse the key because the HW expects it in reverse + // byte order + reverse_key((u8 *) (cmd + COMMAND_KEY_VALUE_IDX), + HWKM_MAX_KEY_SIZE); + } + + status = qti_hwkm_run_transaction(ICEMEM_SLAVE, cmd, + KEYSLOT_RDWR_CMD_WORDS, rsp, KEYSLOT_RDWR_RSP_WORDS); + if (status) { + pr_err("%s: Error running transaction %d\n", __func__, status); + return status; + } + + rsp_in->status = rsp[RESPONSE_ERR_IDX]; + if (rsp_in->status) { + pr_err("%s: KEY_SLOT_RDWR error status 0x%x\n", + __func__, rsp_in->status); + return rsp_in->status; + } + + if (!cmd_in->rdwr.is_write && + (rsp_in->status == 0)) { + memcpy(&policy, rsp + RESPONSE_KEY_POLICY_IDX, + KEY_POLICY_LENGTH); + memcpy(rsp_in->rdwr.key, + rsp + RESPONSE_KEY_VALUE_IDX, RESPONSE_KEY_LENGTH); + // Need to reverse the key because the HW returns it in + // reverse byte order + reverse_key(rsp_in->rdwr.key, HWKM_MAX_KEY_SIZE); + deserialize_policy(&rsp_in->rdwr.policy, &policy); + } + + // Clear cmd and rsp buffers, since they may contain plaintext keys + memset(cmd, 0, sizeof(cmd)); + memset(rsp, 0, sizeof(rsp)); + + return status; +} + +static int qti_hwkm_parse_clock_info(struct platform_device *pdev, + struct hwkm_device *hwkm_dev) +{ + int ret = -1, cnt, i, len; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + char *name; + struct hwkm_clk_info *clki; + u32 *clkfreq = NULL; + + if (!np) + goto out; + + cnt = of_property_count_strings(np, "clock-names"); + if (cnt <= 0) { + dev_info(dev, "%s: Unable to find clocks, assuming enabled\n", + __func__); + ret = cnt; + goto out; + } + + if (!of_get_property(np, "qcom,op-freq-hz", &len)) { + dev_info(dev, "qcom,op-freq-hz property not specified\n"); + goto out; + } + + len = len/sizeof(*clkfreq); + if (len != cnt) + goto out; + + clkfreq = devm_kzalloc(dev, len * sizeof(*clkfreq), GFP_KERNEL); + if (!clkfreq) { + ret = -ENOMEM; + goto out; + } + ret = of_property_read_u32_array(np, "qcom,op-freq-hz", clkfreq, len); + + INIT_LIST_HEAD(&hwkm_dev->clk_list_head); + + for (i = 0; i < cnt; i++) { + ret = of_property_read_string_index(np, + "clock-names", i, (const char **)&name); + if (ret) + goto out; + + clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL); + if (!clki) { + ret = -ENOMEM; + goto out; + } + clki->max_freq = clkfreq[i]; + clki->name = kstrdup(name, GFP_KERNEL); + list_add_tail(&clki->list, &hwkm_dev->clk_list_head); + } +out: + return ret; +} + +static int qti_hwkm_init_clocks(struct hwkm_device *hwkm_dev) +{ + int ret = -EINVAL; + struct hwkm_clk_info *clki = NULL; + struct device *dev = hwkm_dev->dev; + struct list_head *head = &hwkm_dev->clk_list_head; + + if (!hwkm_dev->is_hwkm_clk_available) + return 0; + + if (!head || list_empty(head)) { + dev_err(dev, "%s: HWKM clock list null/empty\n", __func__); + goto out; + } + + list_for_each_entry(clki, head, list) { + if (!clki->name) + continue; + + clki->clk = devm_clk_get(dev, clki->name); + if (IS_ERR(clki->clk)) { + ret = PTR_ERR(clki->clk); + dev_err(dev, "%s: %s clk get failed, %d\n", + __func__, clki->name, ret); + goto out; + } + + ret = 0; + if (clki->max_freq) { + ret = clk_set_rate(clki->clk, clki->max_freq); + if (ret) { + dev_err(dev, + "%s: %s clk set rate(%dHz) failed, %d\n", + __func__, clki->name, clki->max_freq, ret); + goto out; + } + clki->curr_freq = clki->max_freq; + dev_dbg(dev, "%s: clk: %s, rate: %lu\n", __func__, + clki->name, clk_get_rate(clki->clk)); + } + } +out: + return ret; +} + +static int qti_hwkm_enable_disable_clocks(struct hwkm_device *hwkm_dev, + bool enable) +{ + int ret = 0; + struct hwkm_clk_info *clki = NULL; + struct device *dev = hwkm_dev->dev; + struct list_head *head = &hwkm_dev->clk_list_head; + + if (!head || list_empty(head)) { + dev_err(dev, "%s: HWKM clock list null/empty\n", __func__); + ret = -EINVAL; + goto out; + } + + if (!hwkm_dev->is_hwkm_clk_available) { + dev_err(dev, "%s: HWKM clock not available\n", __func__); + ret = -EINVAL; + goto out; + } + + list_for_each_entry(clki, head, list) { + if (!clki->name) + continue; + + if (enable) + ret = clk_prepare_enable(clki->clk); + else + clk_disable_unprepare(clki->clk); + + if (ret) { + dev_err(dev, "Unable to %s HWKM clock\n", + enable?"enable":"disable"); + goto out; + } + } +out: + return ret; +} + +int qti_hwkm_clocks(bool on) +{ + int ret = 0; + + ret = qti_hwkm_enable_disable_clocks(km_device, on); + if (ret) { + pr_err("%s:%pK Could not enable/disable clocks\n", + __func__, km_device); + } + + return ret; +} +EXPORT_SYMBOL(qti_hwkm_clocks); + +static int qti_hwkm_get_device_tree_data(struct platform_device *pdev, + struct hwkm_device *hwkm_dev) +{ + struct device *dev = &pdev->dev; + int ret = 0; + + hwkm_dev->km_res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "km_master"); + hwkm_dev->ice_res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "ice_slave"); + if (!hwkm_dev->km_res || !hwkm_dev->ice_res) { + pr_err("%s: No memory available for IORESOURCE\n", __func__); + return -ENOMEM; + } + + hwkm_dev->km_base = devm_ioremap_resource(dev, hwkm_dev->km_res); + hwkm_dev->ice_base = devm_ioremap_resource(dev, hwkm_dev->ice_res); + + if (IS_ERR(hwkm_dev->km_base) || IS_ERR(hwkm_dev->ice_base)) { + ret = PTR_ERR(hwkm_dev->km_base); + pr_err("%s: Error = %d mapping HWKM memory\n", __func__, ret); + goto out; + } + + hwkm_dev->is_hwkm_clk_available = of_property_read_bool( + dev->of_node, "qcom,enable-hwkm-clk"); + + if (hwkm_dev->is_hwkm_clk_available) { + ret = qti_hwkm_parse_clock_info(pdev, hwkm_dev); + if (ret) { + pr_err("%s: qti_hwkm_parse_clock_info failed (%d)\n", + __func__, ret); + goto out; + } + } + +out: + return ret; +} + +int qti_hwkm_handle_cmd(struct hwkm_cmd *cmd, struct hwkm_rsp *rsp) +{ + switch (cmd->op) { + case SYSTEM_KDF: + return qti_handle_system_kdf(cmd, rsp); + case KEY_UNWRAP_IMPORT: + return qti_handle_key_unwrap_import(cmd, rsp); + case KEY_SLOT_CLEAR: + return qti_handle_keyslot_clear(cmd, rsp); + case KEY_SLOT_RDWR: + return qti_handle_keyslot_rdwr(cmd, rsp); + case SET_TPKEY: + return qti_handle_set_tpkey(cmd, rsp); + case NIST_KEYGEN: + case KEY_WRAP_EXPORT: + case QFPROM_KEY_RDWR: // cmd for HW initialization cmd only + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(qti_hwkm_handle_cmd); + +static void qti_hwkm_configure_slot_access(struct hwkm_device *dev) +{ + qti_hwkm_writel(dev, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_0, ICEMEM_SLAVE); + qti_hwkm_writel(dev, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_1, ICEMEM_SLAVE); + qti_hwkm_writel(dev, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_2, ICEMEM_SLAVE); + qti_hwkm_writel(dev, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_3, ICEMEM_SLAVE); + qti_hwkm_writel(dev, 0xffffffff, + QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_4, ICEMEM_SLAVE); +} + +static int qti_hwkm_check_bist_status(struct hwkm_device *hwkm_dev) +{ + if (!qti_hwkm_testb(hwkm_dev, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + BIST_DONE, ICEMEM_SLAVE)) { + pr_err("%s: Error with BIST_DONE\n", __func__); + return -EINVAL; + } + + if (!qti_hwkm_testb(hwkm_dev, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + CRYPTO_LIB_BIST_DONE, ICEMEM_SLAVE)) { + pr_err("%s: Error with CRYPTO_LIB_BIST_DONE\n", __func__); + return -EINVAL; + } + + if (!qti_hwkm_testb(hwkm_dev, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + BOOT_CMD_LIST1_DONE, ICEMEM_SLAVE)) { + pr_err("%s: Error with BOOT_CMD_LIST1_DONE\n", __func__); + return -EINVAL; + } + + if (!qti_hwkm_testb(hwkm_dev, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + BOOT_CMD_LIST0_DONE, ICEMEM_SLAVE)) { + pr_err("%s: Error with BOOT_CMD_LIST0_DONE\n", __func__); + return -EINVAL; + } + + if (!qti_hwkm_testb(hwkm_dev, QTI_HWKM_ICE_RG_TZ_KM_STATUS, + KT_CLEAR_DONE, ICEMEM_SLAVE)) { + pr_err("%s: KT_CLEAR_DONE\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int qti_hwkm_ice_init_sequence(struct hwkm_device *hwkm_dev) +{ + int ret = 0; + + // Put ICE in standard mode + qti_hwkm_writel(hwkm_dev, 0x7, QTI_HWKM_ICE_RG_TZ_KM_CTL, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + + ret = qti_hwkm_check_bist_status(hwkm_dev); + if (ret) { + pr_err("%s: Error in BIST initialization %d\n", __func__, ret); + return ret; + } + + // Disable CRC checks + qti_hwkm_clearb(hwkm_dev, QTI_HWKM_ICE_RG_TZ_KM_CTL, CRC_CHECK_EN, + ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + + // Configure key slots to be accessed by HLOS + qti_hwkm_configure_slot_access(hwkm_dev); + /* Write memory barrier */ + wmb(); + + // Clear RSP_FIFO_FULL bit + qti_hwkm_setb(hwkm_dev, QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS, + RSP_FIFO_FULL, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + + return ret; +} + +static void qti_hwkm_enable_slave_receive_mode(struct hwkm_device *hwkm_dev) +{ + qti_hwkm_clearb(hwkm_dev, QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL, + TPKEY_EN, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); + qti_hwkm_writel(hwkm_dev, ICEMEM_SLAVE_TPKEY_VAL, + QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); +} + +static void qti_hwkm_disable_slave_receive_mode(struct hwkm_device *hwkm_dev) +{ + qti_hwkm_clearb(hwkm_dev, QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL, + TPKEY_EN, ICEMEM_SLAVE); + /* Write memory barrier */ + wmb(); +} + +static void qti_hwkm_check_tpkey_status(struct hwkm_device *hwkm_dev) +{ + int val = 0; + + val = qti_hwkm_readl(hwkm_dev, QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_STATUS, + ICEMEM_SLAVE); + + pr_debug("%s: Tpkey receive status 0x%x\n", __func__, val); +} + +static int qti_hwkm_set_tpkey(void) +{ + int ret = 0; + struct hwkm_cmd cmd; + struct hwkm_rsp rsp; + + cmd.op = SET_TPKEY; + cmd.set_tpkey.sks = KM_MASTER_TPKEY_SLOT; + + qti_hwkm_enable_slave_receive_mode(km_device); + ret = qti_hwkm_handle_cmd(&cmd, &rsp); + if (ret) { + pr_err("%s: Error running commands\n", __func__, ret); + return ret; + } + + qti_hwkm_check_tpkey_status(km_device); + qti_hwkm_disable_slave_receive_mode(km_device); + + return 0; +} + +int qti_hwkm_init(void) +{ + int ret = 0; + + ret = qti_hwkm_ice_init_sequence(km_device); + if (ret) { + pr_err("%s: Error in ICE init sequence %d\n", __func__, ret); + return ret; + } + + ret = qti_hwkm_set_tpkey(); + if (ret) { + pr_err("%s: Error setting ICE to receive %d\n", __func__, ret); + return ret; + } + /* Write memory barrier */ + wmb(); + return ret; +} +EXPORT_SYMBOL(qti_hwkm_init); + +static int qti_hwkm_probe(struct platform_device *pdev) +{ + struct hwkm_device *hwkm_dev; + int ret = 0; + + pr_debug("%s %d: HWKM probe start\n", __func__, __LINE__); + if (!pdev) { + pr_err("%s: Invalid platform_device passed\n", __func__); + return -EINVAL; + } + + hwkm_dev = kzalloc(sizeof(struct hwkm_device), GFP_KERNEL); + if (!hwkm_dev) { + ret = -ENOMEM; + pr_err("%s: Error %d allocating memory for HWKM device\n", + __func__, ret); + goto err_hwkm_dev; + } + + hwkm_dev->dev = &pdev->dev; + if (!hwkm_dev->dev) { + ret = -EINVAL; + pr_err("%s: Invalid device passed in platform_device\n", + __func__); + goto err_hwkm_dev; + } + + if (pdev->dev.of_node) + ret = qti_hwkm_get_device_tree_data(pdev, hwkm_dev); + else { + ret = -EINVAL; + pr_err("%s: HWKM device node not found\n", __func__); + } + if (ret) + goto err_hwkm_dev; + + ret = qti_hwkm_init_clocks(hwkm_dev); + if (ret) { + pr_err("%s: Error initializing clocks %d\n", __func__, ret); + goto err_hwkm_dev; + } + + hwkm_dev->is_hwkm_enabled = true; + km_device = hwkm_dev; + platform_set_drvdata(pdev, hwkm_dev); + + pr_debug("%s %d: HWKM probe ends\n", __func__, __LINE__); + return ret; + +err_hwkm_dev: + km_device = NULL; + kfree(hwkm_dev); + return ret; +} + + +static int qti_hwkm_remove(struct platform_device *pdev) +{ + kfree(km_device); + return 0; +} + +static const struct of_device_id qti_hwkm_match[] = { + { .compatible = "qcom,hwkm"}, + {}, +}; +MODULE_DEVICE_TABLE(of, qti_hwkm_match); + +static struct platform_driver qti_hwkm_driver = { + .probe = qti_hwkm_probe, + .remove = qti_hwkm_remove, + .driver = { + .name = "qti_hwkm", + .of_match_table = qti_hwkm_match, + }, +}; +module_platform_driver(qti_hwkm_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("QTI Hardware Key Manager driver"); diff --git a/drivers/soc/qcom/hwkm_serialize.h b/drivers/soc/qcom/hwkm_serialize.h new file mode 100644 index 000000000000..2d73ff5e528a --- /dev/null +++ b/drivers/soc/qcom/hwkm_serialize.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __HWKM_SERIALIZE_H_ +#define __HWKM_SERIALIZE_H_ + +#include +#include + +#include + +/* Command lengths (words) */ +#define NIST_KEYGEN_CMD_WORDS 4 +#define SYSTEM_KDF_CMD_MIN_WORDS 4 +#define SYSTEM_KDF_CMD_MAX_WORDS 29 +#define KEYSLOT_CLEAR_CMD_WORDS 2 +#define UNWRAP_IMPORT_CMD_WORDS 19 +#define WRAP_EXPORT_CMD_WORDS 5 +#define SET_TPKEY_CMD_WORDS 2 +#define KEYSLOT_RDWR_CMD_WORDS 12 +#define QFPROM_RDWR_CMD_WORDS 2 + +/* Response lengths (words) */ +#define NIST_KEYGEN_RSP_WORDS 2 +#define SYSTEM_KDF_RSP_WORDS 2 +#define KEYSLOT_CLEAR_RSP_WORDS 2 +#define UNWRAP_IMPORT_RSP_WORDS 2 +#define WRAP_EXPORT_RSP_WORDS 19 +#define SET_TPKEY_RSP_WORDS 2 +#define KEYSLOT_RDWR_RSP_WORDS 12 +#define QFPROM_RDWR_RSP_WORDS 2 + +/* Field lengths (words) */ +#define OPERATION_INFO_WORDS 1 +#define KEY_POLICY_WORDS 2 +#define BSVE_WORDS 3 +#define MAX_SWC_WORDS 16 +#define RESPONSE_KEY_WORDS 8 +#define KEY_BLOB_WORDS 17 + +/* Field lengths (bytes) */ +#define OPERATION_INFO_LENGTH (OPERATION_INFO_WORDS * sizeof(uint32_t)) +#define KEY_POLICY_LENGTH (KEY_POLICY_WORDS * sizeof(uint32_t)) +#define MAX_BSVE_LENGTH (BSVE_WORDS * sizeof(uint32_t)) +#define MAX_SWC_LENGTH (MAX_SWC_WORDS * sizeof(uint32_t)) +#define RESPONSE_KEY_LENGTH (RESPONSE_KEY_WORDS * sizeof(uint32_t)) +#define KEY_BLOB_LENGTH (KEY_BLOB_WORDS * sizeof(uint32_t)) + +/* Command indices */ +#define COMMAND_KEY_POLICY_IDX 1 +#define COMMAND_KEY_VALUE_IDX 3 +#define COMMAND_WRAPPED_KEY_IDX 1 +#define COMMAND_KEY_WRAP_BSVE_IDX 1 + +/* Response indices */ +#define RESPONSE_ERR_IDX 1 +#define RESPONSE_KEY_POLICY_IDX 2 +#define RESPONSE_KEY_VALUE_IDX 4 +#define RESPONSE_WRAPPED_KEY_IDX 2 + +struct hwkm_serialized_policy { + unsigned dbg_qfprom_key_rd_iv_sel:1; // [0] + unsigned reserved0:1; // [1] + unsigned wrap_with_tpkey:1; // [2] + unsigned hw_destination:4; // [3:6] + unsigned reserved1:1; // [7] + unsigned propagate_sec_level_to_child_keys:1; // [8] + unsigned security_level:2; // [9:10] + unsigned swap_export_allowed:1; // [11] + unsigned wrap_export_allowed:1; // [12] + unsigned key_type:3; // [13:15] + unsigned kdf_depth:8; // [16:23] + unsigned decrypt_allowed:1; // [24] + unsigned encrypt_allowed:1; // [25] + unsigned alg_allowed:6; // [26:31] + unsigned key_management_by_tz_secure_allowed:1; // [32] + unsigned key_management_by_nonsecure_allowed:1; // [33] + unsigned key_management_by_modem_allowed:1; // [34] + unsigned key_management_by_spu_allowed:1; // [35] + unsigned reserved2:28; // [36:63] +} __packed; + +struct hwkm_kdf_bsve { + unsigned mks:8; // [0:7] + unsigned key_policy_version_en:1; // [8] + unsigned apps_secure_en:1; // [9] + unsigned msa_secure_en:1; // [10] + unsigned lcm_fuse_row_en:1; // [11] + unsigned boot_stage_otp_en:1; // [12] + unsigned swc_en:1; // [13] + u64 fuse_region_sha_digest_en:64; // [14:78] + unsigned child_key_policy_en:1; // [79] + unsigned mks_en:1; // [80] + unsigned reserved:16; // [81:95] +} __packed; + +struct hwkm_wrapping_bsve { + unsigned key_policy_version_en:1; // [0] + unsigned apps_secure_en:1; // [1] + unsigned msa_secure_en:1; // [2] + unsigned lcm_fuse_row_en:1; // [3] + unsigned boot_stage_otp_en:1; // [4] + unsigned swc_en:1; // [5] + u64 fuse_region_sha_digest_en:64; // [6:69] + unsigned child_key_policy_en:1; // [70] + unsigned mks_en:1; // [71] + unsigned reserved:24; // [72:95] +} __packed; + +struct hwkm_operation_info { + unsigned op:4; // [0-3] + unsigned irq_en:1; // [4] + unsigned slot1_desc:8; // [5,12] + unsigned slot2_desc:8; // [13,20] + unsigned op_flag:1; // [21] + unsigned context_len:5; // [22-26] + unsigned len:5; // [27-31] +} __packed; + +#endif /* __HWKM_SERIALIZE_H_ */ diff --git a/drivers/soc/qcom/hwkmregs.h b/drivers/soc/qcom/hwkmregs.h new file mode 100644 index 000000000000..552e489fd9ab --- /dev/null +++ b/drivers/soc/qcom/hwkmregs.h @@ -0,0 +1,261 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _QTI_HARDWARE_KEY_MANAGER_REGS_H_ +#define _QTI_HARDWARE_KEY_MANAGER_REGS_H_ + +#define HWKM_VERSION_STEP_REV_MASK 0xFFFF +#define HWKM_VERSION_STEP_REV 0 /* bit 15-0 */ +#define HWKM_VERSION_MAJOR_REV_MASK 0xFF000000 +#define HWKM_VERSION_MAJOR_REV 24 /* bit 31-24 */ +#define HWKM_VERSION_MINOR_REV_MASK 0xFF0000 +#define HWKM_VERSION_MINOR_REV 16 /* bit 23-16 */ + +/* QTI HWKM master registers from SWI */ +/* QTI HWKM master shared registers */ +#define QTI_HWKM_MASTER_RG_IPCAT_VERSION 0x0000 +#define QTI_HWKM_MASTER_RG_KEY_POLICY_VERSION 0x0004 +#define QTI_HWKM_MASTER_RG_SHARED_STATUS 0x0008 +#define QTI_HWKM_MASTER_RG_KEYTABLE_SIZE 0x000C + +/* QTI HWKM master register bank 2 */ +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_CTL 0x4000 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_STATUS 0x4004 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_STATUS 0x4008 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_MASK 0x400C +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_ESR 0x4010 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_ESR_IRQ_MASK 0x4014 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_ESYNR 0x4018 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_0 0x401C +#define QTI_HWKM_MASTER_RG_BANK2_CMD_1 0x4020 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_2 0x4024 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_3 0x4028 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_4 0x402C +#define QTI_HWKM_MASTER_RG_BANK2_CMD_5 0x4030 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_6 0x4034 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_7 0x4038 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_8 0x403C +#define QTI_HWKM_MASTER_RG_BANK2_CMD_9 0x4040 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_10 0x4044 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_11 0x4048 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_12 0x404C +#define QTI_HWKM_MASTER_RG_BANK2_CMD_13 0x4050 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_14 0x4054 +#define QTI_HWKM_MASTER_RG_BANK2_CMD_15 0x4058 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_0 0x405C +#define QTI_HWKM_MASTER_RG_BANK2_RSP_1 0x4060 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_2 0x4064 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_3 0x4068 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_4 0x406C +#define QTI_HWKM_MASTER_RG_BANK2_RSP_5 0x4070 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_6 0x4074 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_7 0x4078 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_8 0x407C +#define QTI_HWKM_MASTER_RG_BANK2_RSP_9 0x4080 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_10 0x4084 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_11 0x4088 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_12 0x408C +#define QTI_HWKM_MASTER_RG_BANK2_RSP_13 0x4090 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_14 0x4094 +#define QTI_HWKM_MASTER_RG_BANK2_RSP_15 0x4098 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_IRQ_ROUTING 0x409C +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_BBAC_0 0x40A0 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_BBAC_1 0x40A4 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_BBAC_2 0x40A8 +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_BBAC_3 0x40AC +#define QTI_HWKM_MASTER_RG_BANK2_BANKN_BBAC_4 0x40B0 + +/* QTI HWKM master register bank 3 */ +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_CTL 0x5000 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_STATUS 0x5004 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_IRQ_STATUS 0x5008 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_IRQ_MASK 0x500C +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_ESR 0x5010 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_ESR_IRQ_MASK 0x5014 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_ESYNR 0x5018 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_0 0x501C +#define QTI_HWKM_MASTER_RG_BANK3_CMD_1 0x5020 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_2 0x5024 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_3 0x5028 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_4 0x502C +#define QTI_HWKM_MASTER_RG_BANK3_CMD_5 0x5030 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_6 0x5034 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_7 0x5038 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_8 0x503C +#define QTI_HWKM_MASTER_RG_BANK3_CMD_9 0x5040 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_10 0x5044 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_11 0x5048 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_12 0x504C +#define QTI_HWKM_MASTER_RG_BANK3_CMD_13 0x5050 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_14 0x5054 +#define QTI_HWKM_MASTER_RG_BANK3_CMD_15 0x5058 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_0 0x505C +#define QTI_HWKM_MASTER_RG_BANK3_RSP_1 0x5060 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_2 0x5064 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_3 0x5068 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_4 0x506C +#define QTI_HWKM_MASTER_RG_BANK3_RSP_5 0x5070 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_6 0x5074 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_7 0x5078 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_8 0x507C +#define QTI_HWKM_MASTER_RG_BANK3_RSP_9 0x5080 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_10 0x5084 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_11 0x5088 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_12 0x508C +#define QTI_HWKM_MASTER_RG_BANK3_RSP_13 0x5090 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_14 0x5094 +#define QTI_HWKM_MASTER_RG_BANK3_RSP_15 0x5098 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_IRQ_ROUTING 0x509C +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_BBAC_0 0x50A0 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_BBAC_1 0x50A4 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_BBAC_2 0x50A8 +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_BBAC_3 0x50AC +#define QTI_HWKM_MASTER_RG_BANK3_BANKN_BBAC_4 0x50B0 + +/* QTI HWKM access control registers for Bank 2 */ +#define QTI_HWKM_MASTER_RG_BANK2_AC_BANKN_BBAC_0 0x8000 +#define QTI_HWKM_MASTER_RG_BANK2_AC_BANKN_BBAC_1 0x8004 +#define QTI_HWKM_MASTER_RG_BANK2_AC_BANKN_BBAC_2 0x8008 +#define QTI_HWKM_MASTER_RG_BANK2_AC_BANKN_BBAC_3 0x800C +#define QTI_HWKM_MASTER_RG_BANK2_AC_BANKN_BBAC_4 0x8010 + +/* QTI HWKM access control registers for Bank 3 */ +#define QTI_HWKM_MASTER_RG_BANK3_AC_BANKN_BBAC_0 0x9000 +#define QTI_HWKM_MASTER_RG_BANK3_AC_BANKN_BBAC_1 0x9004 +#define QTI_HWKM_MASTER_RG_BANK3_AC_BANKN_BBAC_2 0x9008 +#define QTI_HWKM_MASTER_RG_BANK3_AC_BANKN_BBAC_3 0x900C +#define QTI_HWKM_MASTER_RG_BANK3_AC_BANKN_BBAC_4 0x9010 + +/* QTI HWKM ICE slave config and status registers */ +#define QTI_HWKM_ICE_RG_TZ_KM_CTL 0x1000 +#define QTI_HWKM_ICE_RG_TZ_KM_STATUS 0x1004 +#define QTI_HWKM_ICE_RG_TZ_KM_STATUS_IRQ_MASK 0x1008 +#define QTI_HWKM_ICE_RG_TZ_KM_BOOT_STAGE_OTP 0x100C +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_CTL 0x1010 +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_WRITE 0x1014 +#define QTI_HWKM_ICE_RG_TZ_KM_DEBUG_READ 0x1018 +#define QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_CTL 0x101C +#define QTI_HWKM_ICE_RG_TZ_TPKEY_RECEIVE_STATUS 0x1020 +#define QTI_HWKM_ICE_RG_TZ_KM_COMMON_IRQ_ROUTING 0x1024 + +/* QTI HWKM ICE slave registers from SWI */ +/* QTI HWKM ICE slave shared registers */ +#define QTI_HWKM_ICE_RG_IPCAT_VERSION 0x0000 +#define QTI_HWKM_ICE_RG_KEY_POLICY_VERSION 0x0004 +#define QTI_HWKM_ICE_RG_SHARED_STATUS 0x0008 +#define QTI_HWKM_ICE_RG_KEYTABLE_SIZE 0x000C + +/* QTI HWKM ICE slave register bank 0 */ +#define QTI_HWKM_ICE_RG_BANK0_BANKN_CTL 0x2000 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_STATUS 0x2004 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_STATUS 0x2008 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_MASK 0x200C +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESR 0x2010 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESR_IRQ_MASK 0x2014 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_ESYNR 0x2018 +#define QTI_HWKM_ICE_RG_BANK0_CMD_0 0x201C +#define QTI_HWKM_ICE_RG_BANK0_CMD_1 0x2020 +#define QTI_HWKM_ICE_RG_BANK0_CMD_2 0x2024 +#define QTI_HWKM_ICE_RG_BANK0_CMD_3 0x2028 +#define QTI_HWKM_ICE_RG_BANK0_CMD_4 0x202C +#define QTI_HWKM_ICE_RG_BANK0_CMD_5 0x2030 +#define QTI_HWKM_ICE_RG_BANK0_CMD_6 0x2034 +#define QTI_HWKM_ICE_RG_BANK0_CMD_7 0x2038 +#define QTI_HWKM_ICE_RG_BANK0_CMD_8 0x203C +#define QTI_HWKM_ICE_RG_BANK0_CMD_9 0x2040 +#define QTI_HWKM_ICE_RG_BANK0_CMD_10 0x2044 +#define QTI_HWKM_ICE_RG_BANK0_CMD_11 0x2048 +#define QTI_HWKM_ICE_RG_BANK0_CMD_12 0x204C +#define QTI_HWKM_ICE_RG_BANK0_CMD_13 0x2050 +#define QTI_HWKM_ICE_RG_BANK0_CMD_14 0x2054 +#define QTI_HWKM_ICE_RG_BANK0_CMD_15 0x2058 +#define QTI_HWKM_ICE_RG_BANK0_RSP_0 0x205C +#define QTI_HWKM_ICE_RG_BANK0_RSP_1 0x2060 +#define QTI_HWKM_ICE_RG_BANK0_RSP_2 0x2064 +#define QTI_HWKM_ICE_RG_BANK0_RSP_3 0x2068 +#define QTI_HWKM_ICE_RG_BANK0_RSP_4 0x206C +#define QTI_HWKM_ICE_RG_BANK0_RSP_5 0x2070 +#define QTI_HWKM_ICE_RG_BANK0_RSP_6 0x2074 +#define QTI_HWKM_ICE_RG_BANK0_RSP_7 0x2078 +#define QTI_HWKM_ICE_RG_BANK0_RSP_8 0x207C +#define QTI_HWKM_ICE_RG_BANK0_RSP_9 0x2080 +#define QTI_HWKM_ICE_RG_BANK0_RSP_10 0x2084 +#define QTI_HWKM_ICE_RG_BANK0_RSP_11 0x2088 +#define QTI_HWKM_ICE_RG_BANK0_RSP_12 0x208C +#define QTI_HWKM_ICE_RG_BANK0_RSP_13 0x2090 +#define QTI_HWKM_ICE_RG_BANK0_RSP_14 0x2094 +#define QTI_HWKM_ICE_RG_BANK0_RSP_15 0x2098 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_IRQ_ROUTING 0x209C +#define QTI_HWKM_ICE_RG_BANK0_BANKN_BBAC_0 0x20A0 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_BBAC_1 0x20A4 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_BBAC_2 0x20A8 +#define QTI_HWKM_ICE_RG_BANK0_BANKN_BBAC_3 0x20AC +#define QTI_HWKM_ICE_RG_BANK0_BANKN_BBAC_4 0x20B0 + +/* QTI HWKM access control registers for Bank 2 */ +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_0 0x5000 +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_1 0x5004 +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_2 0x5008 +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_3 0x500C +#define QTI_HWKM_ICE_RG_BANK0_AC_BANKN_BBAC_4 0x5010 + + +/* QTI HWKM ICE slave config reg vals */ + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_CTL */ +#define CRC_CHECK_EN 0 +#define KEYTABLE_HW_WR_ACCESS_EN 1 +#define KEYTABLE_HW_RD_ACCESS_EN 2 +#define BOOT_INIT0_DISABLE 3 +#define BOOT_INIT1_DISABLE 4 +#define ICE_LEGACY_MODE_EN_OTP 5 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_KM_STATUS */ +#define KT_CLEAR_DONE 0 +#define BOOT_CMD_LIST0_DONE 1 +#define BOOT_CMD_LIST1_DONE 2 +#define KEYTABLE_KEY_POLICY 3 +#define KEYTABLE_INTEGRITY_ERROR 4 +#define KEYTABLE_KEY_SLOT_ERROR 5 +#define KEYTABLE_KEY_SLOT_NOT_EVEN_ERROR 6 +#define KEYTABLE_KEY_SLOT_OUT_OF_RANGE 7 +#define KEYTABLE_KEY_SIZE_ERROR 8 +#define KEYTABLE_OPERATION_ERROR 9 +#define LAST_ACTIVITY_BANK 10 +#define CRYPTO_LIB_BIST_ERROR 13 +#define CRYPTO_LIB_BIST_DONE 14 +#define BIST_ERROR 15 +#define BIST_DONE 16 +#define LAST_ACTIVITY_BANK_MASK 0x1c00 + +/* HWKM_ICEMEM_SLAVE_ICE_KM_RG_TZ_TPKEY_RECEIVE_CTL */ +#define TPKEY_EN 8 + +/* QTI HWKM Bank status & control reg vals */ + +/* HWKM_MASTER_CFG_KM_BANKN_CTL */ +#define CMD_ENABLE_BIT 0 +#define CMD_FIFO_CLEAR_BIT 1 + +/* HWKM_MASTER_CFG_KM_BANKN_STATUS */ +#define CURRENT_CMD_REMAINING_LENGTH 0 +#define MOST_RECENT_OPCODE 5 +#define RSP_FIFO_AVAILABLE_DATA 9 +#define CMD_FIFO_AVAILABLE_SPACE 14 +#define ICE_LEGACY_MODE_BIT 19 +#define CMD_FIFO_AVAILABLE_SPACE_MASK 0x7c000 +#define RSP_FIFO_AVAILABLE_DATA_MASK 0x3e00 +#define MOST_RECENT_OPCODE_MASK 0x1e0 +#define CURRENT_CMD_REMAINING_LENGTH_MASK 0x1f + +/* HWKM_MASTER_CFG_KM_BANKN_IRQ_STATUS */ +#define ARB_GRAN_WINNER 0 +#define CMD_DONE_BIT 1 +#define RSP_FIFO_NOT_EMPTY 2 +#define RSP_FIFO_FULL 3 +#define RSP_FIFO_UNDERFLOW 4 +#define CMD_FIFO_UNDERFLOW 5 + +#endif /* __QTI_HARDWARE_KEY_MANAGER_REGS_H_ */ diff --git a/include/linux/hwkm.h b/include/linux/hwkm.h new file mode 100644 index 000000000000..4af06b925337 --- /dev/null +++ b/include/linux/hwkm.h @@ -0,0 +1,306 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __HWKM_H_ +#define __HWKM_H_ + +#include +#include + +/* Maximum number of bytes in a key used in a KEY_SLOT_RDWR operation */ +#define HWKM_MAX_KEY_SIZE 32 +/* Maximum number of bytes in a SW ctx used in a SYSTEM_KDF operation */ +#define HWKM_MAX_CTX_SIZE 64 +/* Maximum number of bytes in a WKB used in a key wrap or unwrap operation */ +#define HWKM_MAX_BLOB_SIZE 68 + + +/* Opcodes to be set in the op field of a command */ +enum hwkm_op { + /* Opcode to generate a random key */ + NIST_KEYGEN = 0, + /* Opcode to derive a key */ + SYSTEM_KDF, + /* Used only by HW */ + QFPROM_KEY_RDWR, + /* Opcode to wrap a key and export the wrapped key */ + KEY_WRAP_EXPORT, + /* + * Opcode to import a wrapped key and unwrap it in the + * specified key slot + */ + KEY_UNWRAP_IMPORT, + /* Opcode to clear a slot */ + KEY_SLOT_CLEAR, + /* Opcode to read or write a key from/to a slot */ + KEY_SLOT_RDWR, + /* + * Opcode to broadcast a TPKEY to all slaves configured + * to receive a TPKEY. + */ + SET_TPKEY, + + + HWKM_MAX_OP, + HWKM_UNDEF_OP = 0xFF +}; + +/* + * Algorithm values which can be used in the alg_allowed field of the + * key policy. + */ +enum hwkm_alg { + AES128_ECB = 0, + AES256_ECB = 1, + DES_ECB = 2, + TDES_ECB = 3, + AES128_CBC = 4, + AES256_CBC = 5, + DES_CBC = 6, + TDES_CBC = 7, + AES128_CCM_TC = 8, + AES128_CCM_NTC = 9, + AES256_CCM_TC = 10, + AES256_CCM_NTC = 11, + AES256_SIV = 12, + AES128_CTR = 13, + AES256_CTR = 14, + AES128_XTS = 15, + AES256_XTS = 16, + SHA1_HMAC = 17, + SHA256_HMAC = 18, + AES128_CMAC = 19, + AES256_CMAC = 20, + SHA384_HMAC = 21, + SHA512_HMAC = 22, + AES128_GCM = 23, + AES256_GCM = 24, + KASUMI = 25, + SNOW3G = 26, + ZUC = 27, + PRINCE = 28, + SIPHASH = 29, + QARMA64 = 30, + QARMA128 = 31, + + HWKM_ALG_MAX, + + HWKM_UNDEF_ALG = 0xFF +}; + +/* Key type values which can be used in the key_type field of the key policy */ +enum hwkm_type { + KEY_DERIVATION_KEY = 0, + KEY_WRAPPING_KEY = 1, + KEY_SWAPPING_KEY = 2, + TRANSPORT_KEY = 3, + GENERIC_KEY = 4, + + HWKM_TYPE_MAX, + + HWKM_UNDEF_KEY_TYPE = 0xFF +}; + +/* Destinations which a context can use */ +enum hwkm_destination { + KM_MASTER = 0, + GPCE_SLAVE = 1, + MCE_SLAVE = 2, + PIMEM_SLAVE = 3, + ICE0_SLAVE = 4, + ICE1_SLAVE = 5, + ICE2_SLAVE = 6, + ICE3_SLAVE = 7, + DP0_HDCP_SLAVE = 8, + DP1_HDCP_SLAVE = 9, + ICEMEM_SLAVE = 10, + + HWKM_DESTINATION_MAX, + + HWKM_UNDEF_DESTINATION = 0xFF +}; + +/* + * Key security levels which can be set in the security_lvl field of + * key policy. + */ +enum hwkm_security_level { + /* Can be read by SW in plaintext using KEY_SLOT_RDWR cmd. */ + SW_KEY = 0, + /* Usable by SW, but not readable in plaintext. */ + MANAGED_KEY = 1, + /* Not usable by SW. */ + HW_KEY = 2, + + HWKM_SECURITY_LEVEL_MAX, + + HWKM_UNDEF_SECURITY_LEVEL = 0xFF +}; + +struct hwkm_key_policy { + bool km_by_spu_allowed; + bool km_by_modem_allowed; + bool km_by_nsec_allowed; + bool km_by_tz_allowed; + + enum hwkm_alg alg_allowed; + + bool enc_allowed; + bool dec_allowed; + + enum hwkm_type key_type; + u8 kdf_depth; + + bool wrap_export_allowed; + bool swap_export_allowed; + + enum hwkm_security_level security_lvl; + + enum hwkm_destination hw_destination; + + bool wrap_with_tpk_allowed; +}; + +struct hwkm_bsve { + bool enabled; + bool km_key_policy_ver_en; + bool km_apps_secure_en; + bool km_msa_secure_en; + bool km_lcm_fuse_en; + bool km_boot_stage_otp_en; + bool km_swc_en; + bool km_child_key_policy_en; + bool km_mks_en; + u64 km_fuse_region_sha_digest_en; +}; + +struct hwkm_keygen_cmd { + u8 dks; /* Destination Key Slot */ + struct hwkm_key_policy policy; /* Key policy */ +}; + +struct hwkm_rdwr_cmd { + uint8_t slot; /* Key Slot */ + bool is_write; /* Write or read op */ + struct hwkm_key_policy policy; /* Key policy for write */ + uint8_t key[HWKM_MAX_KEY_SIZE]; /* Key for write */ + size_t sz; /* Length of key in bytes */ +}; + +struct hwkm_kdf_cmd { + uint8_t dks; /* Destination Key Slot */ + uint8_t kdk; /* Key Derivation Key Slot */ + uint8_t mks; /* Mixing key slot (bsve controlled) */ + struct hwkm_key_policy policy; /* Key policy. */ + struct hwkm_bsve bsve; /* Binding state vector */ + uint8_t ctx[HWKM_MAX_CTX_SIZE]; /* Context */ + size_t sz; /* Length of context in bytes */ +}; + +struct hwkm_set_tpkey_cmd { + uint8_t sks; /* The slot to use as the TPKEY */ +}; + +struct hwkm_unwrap_cmd { + uint8_t dks; /* Destination Key Slot */ + uint8_t kwk; /* Key Wrapping Key Slot */ + uint8_t wkb[HWKM_MAX_BLOB_SIZE];/* Wrapped Key Blob */ + uint8_t sz; /* Length of WKB in bytes */ +}; + +struct hwkm_wrap_cmd { + uint8_t sks; /* Destination Key Slot */ + uint8_t kwk; /* Key Wrapping Key Slot */ + struct hwkm_bsve bsve; /* Binding state vector */ +}; + +struct hwkm_clear_cmd { + uint8_t dks; /* Destination key slot */ + bool is_double_key; /* Whether this is a double key */ +}; + + +struct hwkm_cmd { + enum hwkm_op op; /* Operation */ + union /* Structs with opcode specific parameters */ + { + struct hwkm_keygen_cmd keygen; + struct hwkm_rdwr_cmd rdwr; + struct hwkm_kdf_cmd kdf; + struct hwkm_set_tpkey_cmd set_tpkey; + struct hwkm_unwrap_cmd unwrap; + struct hwkm_wrap_cmd wrap; + struct hwkm_clear_cmd clear; + }; +}; + +struct hwkm_rdwr_rsp { + struct hwkm_key_policy policy; /* Key policy for read */ + uint8_t key[HWKM_MAX_KEY_SIZE]; /* Only available for read op */ + size_t sz; /* Length of the key (bytes) */ +}; + +struct hwkm_wrap_rsp { + uint8_t wkb[HWKM_MAX_BLOB_SIZE]; /* Wrapping key blob */ + size_t sz; /* key blob len (bytes) */ +}; + +struct hwkm_rsp { + u32 status; + union /* Structs with opcode specific outputs */ + { + struct hwkm_rdwr_rsp rdwr; + struct hwkm_wrap_rsp wrap; + }; +}; + +enum hwkm_master_key_slots { + /** L1 KDKs. Not usable by SW. Used by HW to derive L2 KDKs */ + NKDK_L1 = 0, + PKDK_L1 = 1, + SKDK_L1 = 2, + UKDK_L1 = 3, + + /* + * L2 KDKs, used to derive keys by SW. + * Cannot be used for crypto, only key derivation + */ + TZ_NKDK_L2 = 4, + TZ_PKDK_L2 = 5, + TZ_SKDK_L2 = 6, + MODEM_PKDK_L2 = 7, + MODEM_SKDK_L2 = 8, + TZ_UKDK_L2 = 9, + + /** Slots reserved for TPKEY */ + TPKEY_EVEN_SLOT = 10, + TPKEY_KEY_ODD_SLOT = 11, + + /** First key slot available for general purpose use cases */ + MASTER_GENERIC_SLOTS_START, + + UNDEF_SLOT = 0xFF +}; + +#if IS_ENABLED(CONFIG_QTI_HW_KEY_MANAGER) +int qti_hwkm_handle_cmd(struct hwkm_cmd *cmd, struct hwkm_rsp *rsp); +int qti_hwkm_clocks(bool on); +int qti_hwkm_init(void); +#else +static inline int qti_hwkm_add_req(struct hwkm_cmd *cmd, + struct hwkm_rsp *rsp) +{ + return -EOPNOTSUPP; +} +static inline int qti_hwkm_clocks(bool on) +{ + return -EOPNOTSUPP; +} +static inline int qti_hwkm_init(void) +{ + return -EOPNOTSUPP; +} +#endif /* CONFIG_QTI_HW_KEY_MANAGER */ +#endif /* __HWKM_H_ */