Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions core/arch/arm/plat-qcom/hoya/arch_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@
#define HWKM_MASTER_BASE UL(0x010c0000)
#define HWKM_MASTER_SIZE UL(0x00020000)

#define HWKM_CRYPTO0_BASE UL(0x01dc0000)
#define HWKM_CRYPTO0_SIZE UL(0x00040000)

#define HWKM_UFS_MEM_ICE_BASE UL(0x01d88000)
#define HWKM_UFS_MEM_ICE_SIZE UL(0x00018000)

#define HWKM_SDC1_SDCC_ICE_BASE UL(0x087c8000)
#define HWKM_SDC1_SDCC_ICE_SIZE UL(0x00018000)

#define PERIPH_SS_SDC1_SDCC_ICE_LUT_KEYS UL(0x087cc000)
#define PERIPH_SS_SDC1_SDCC_ICE_LUT_KEYS_SIZE UL(0x00003000)

#define UFS_MEM_ICE_LUT_KEYS UL(0x01d8c000)
#define UFS_MEM_ICE_LUT_KEYS_SIZE UL(0x00003000)

#define IMEM_DIAG_OFFSET UL(0x720)
#define DIAG_SIZE UL(0x3000)
#define DIAG_BASE (IMEM_BASE + IMEM_SIZE - DIAG_SIZE)
Expand Down
3 changes: 3 additions & 0 deletions core/arch/arm/plat-qcom/hoya/lemans/target.mk
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ ifeq ($(CFG_QCOM_CLK_CFG),y)
$(call force,CFG_QCOM_CMD_DB,y)
$(call force,CFG_QCOM_RPMH_CLIENT,y)
endif

CFG_QCOM_STORAGE_UFS ?= y
CFG_ICE_FS_ENC_PTA ?= y
17 changes: 17 additions & 0 deletions core/arch/arm/plat-qcom/hoya/lemans/target_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,21 @@

#define TITAN_SS_BASE UL(0x0ac00000)
#define TITAN_SS_SIZE UL(0x00200000)

#if defined(CFG_QCOM_STORAGE_UFS)
#define HWKM_ICE_BASE HWKM_UFS_MEM_ICE_BASE
#define HWKM_ICE_SIZE HWKM_UFS_MEM_ICE_SIZE
#else /* CFG_QCOM_STORAGE_UFS */
#define HWKM_ICE_BASE HWKM_SDC1_SDCC_ICE_BASE
#define HWKM_ICE_SIZE HWKM_SDC1_SDCC_ICE_SIZE
#endif /* CFG_QCOM_STORAGE_UFS */

#if defined(CFG_QCOM_STORAGE_UFS)
#define ICE_LUT_KEYS UFS_MEM_ICE_LUT_KEYS
#define ICE_LUT_KEYS_SIZE UFS_MEM_ICE_LUT_KEYS_SIZE
#else /* CFG_QCOM_STORAGE_UFS */
#define ICE_LUT_KEYS PERIPH_SS_SDC1_SDCC_ICE_LUT_KEYS
#define ICE_LUT_KEYS_SIZE PERIPH_SS_SDC1_SDCC_ICE_LUT_KEYS_SIZE
#endif /* CFG_QCOM_STORAGE_UFS */

#endif /* TARGET_CONFIG_H */
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
#include <string.h>
#include <trace.h>

#include <hwkm.h>
#include <hwkm_errno.h>
#include <drivers/hwkm.h>
#include <drivers/hwkm_errno.h>

#define HWKM_HUK_MKS_CTX "OPTEE_HUK_HWKM_V1_MKS"
#define HWKM_HUK_L3_CTX "OPTEE_HUK_HWKM_V1_L3"
Expand Down
218 changes: 207 additions & 11 deletions core/drivers/crypto/qcom/hwkm.c → core/drivers/crypto/qcom/hwkm/hwkm.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Copyright (c) 2026, Qualcomm Technologies, Inc.
*/

#include <hwkm.h>
#include <hwkm_errno.h>
#include <drivers/hwkm.h>
#include <drivers/hwkm_errno.h>
#include <hwkm_regs.h>
#include <initcall.h>
#include <io.h>
Expand All @@ -21,6 +21,8 @@
#include <util.h>

register_phys_mem_pgdir(MEM_AREA_IO_SEC, HWKM_MASTER_BASE, HWKM_MASTER_SIZE);
register_phys_mem_pgdir(MEM_AREA_IO_SEC, HWKM_CRYPTO0_BASE, HWKM_CRYPTO0_SIZE);
register_phys_mem_pgdir(MEM_AREA_IO_SEC, HWKM_ICE_BASE, HWKM_ICE_SIZE);

static_assert(HW_UNIQUE_KEY_LENGTH <= HWKM_MAX_KEY_SIZE);

Expand Down Expand Up @@ -208,23 +210,28 @@ static TEE_Result hwkm_init(void)
return TEE_ERROR_GENERIC;

/* Check the hardware self-test status. */
status = io_read32_off(base, HWKM_TZ_KM_STATUS);
status = io_read32_off(base + HWKM_MASTER_TZ_REGS_OFFSET,
HWKM_TZ_KM_STATUS);
if (status & (HWKM_TZ_KM_STATUS_BIST_ERROR |
HWKM_TZ_KM_STATUS_CRYPTO_LIB_BIST_ERROR)) {
EMSG("hwkm: BIST failed, status=0x%08"PRIx32, status);
return TEE_ERROR_GENERIC;
}

/* Disable CRC checking on command packets. */
io_write32_off_field(base, HWKM_TZ_KM_CTL,
io_write32_off_field(base + HWKM_MASTER_TZ_REGS_OFFSET, HWKM_TZ_KM_CTL,
HWKM_TZ_KM_CTL_CRC_CHECK_EN, 0);

io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_0,
HWKM_BANK0_BBAC_0);
io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_1, 0);
io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_2, 0);
io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_3, 0);
io_write32_off(base, HWKM_BANK0_AC + HWKM_BANKn_AC_BBAC_4, 0);
io_write32_off(base + HWKM_MASTER_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_0, HWKM_BANK0_BBAC_0);
io_write32_off(base + HWKM_MASTER_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_1, 0);
io_write32_off(base + HWKM_MASTER_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_2, 0);
io_write32_off(base + HWKM_MASTER_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_3, 0);
io_write32_off(base + HWKM_MASTER_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_4, 0);

/*
* Clear the spurious RSP_FIFO_FULL sticky bit.
Expand All @@ -233,7 +240,8 @@ static TEE_Result hwkm_init(void)
* it does not interfere with CMD_DONE polling in
* master_run_transaction().
*/
io_write32_off(base, HWKM_BANK0_KM_IRQ_STATUS,
io_write32_off(base + HWKM_MASTER_BANK0_REGS_OFFSET,
HWKM_BANK0_KM_IRQ_STATUS,
HWKM_BANK0_KM_IRQ_STATUS_RSP_FIFO_FULL);

hwkm_ctx.base = base;
Expand All @@ -242,6 +250,182 @@ static TEE_Result hwkm_init(void)
return TEE_SUCCESS;
}

static TEE_Result gpce_init(void)
{
uint32_t status = 0;
vaddr_t base = 0;

base = (vaddr_t)phys_to_virt(HWKM_CRYPTO0_BASE, MEM_AREA_IO_SEC,
HWKM_CRYPTO0_SIZE);
if (!base)
return TEE_ERROR_GENERIC;

/* Check the hardware self-test status. */
status = io_read32_off(base + HWKM_CRYPTO0_TZ_REGS_OFFSET,
HWKM_TZ_KM_STATUS);
if (status & (HWKM_TZ_KM_STATUS_BIST_ERROR |
HWKM_TZ_KM_STATUS_CRYPTO_LIB_BIST_ERROR)) {
EMSG("hwkm: gpce BIST failed, status=0x%08"PRIx32, status);
return TEE_ERROR_GENERIC;
}

/* Disable CRC checking on command packets. */
io_write32_off_field(base + HWKM_CRYPTO0_TZ_REGS_OFFSET, HWKM_TZ_KM_CTL,
HWKM_TZ_KM_CTL_CRC_CHECK_EN, 0);

/* Grant TZ (BANK0) unrestricted access to all key slots. */
io_write32_off(base + HWKM_CRYPTO0_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_0, 0xFFFFFFFF);
io_write32_off(base + HWKM_CRYPTO0_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_1, 0xFFFFFFFF);
io_write32_off(base + HWKM_CRYPTO0_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_2, 0xFFFFFFFF);
io_write32_off(base + HWKM_CRYPTO0_BANK0_AC_REGS_OFFSET,
HWKM_BANKn_AC_BBAC_3, 0xFFFFFFFF);

/* Clear spurious RSP_FIFO_FULL sticky bit (HW errata QCTDD06252768). */
io_write32_off(base + HWKM_CRYPTO0_BANK0_REGS_OFFSET,
HWKM_BANK0_KM_IRQ_STATUS,
HWKM_BANK0_KM_IRQ_STATUS_RSP_FIFO_FULL);

hwkm_ctx.crypto0_base = base;

return TEE_SUCCESS;
}

static TEE_Result hwkm_generate_tp_and_swap_keys(void)
{
const struct hwkm_key_policy base_kdk_policy = {
.km_by_tz_allowed = true,
.alg_allowed = HWKM_ALGO_AES256_CMAC,
.enc_allowed = true,
.key_type = HWKM_KEY_TYPE_KDK,
.kdf_depth = 1,
.security_lvl = HWKM_KEY_SECURITY_LVL_HW_KEY,
.hw_destination = HWKM_KEY_DEST_KM_MASTER,
};
const struct hwkm_key_policy tpkey_policy = {
.km_by_tz_allowed = true,
.km_by_nsec_allowed = true,
.km_by_modem_allowed = true,
.km_by_spu_allowed = true,
.alg_allowed = HWKM_ALGO_AES256_SIV,
.enc_allowed = true,
.dec_allowed = true,
.key_type = HWKM_KEY_TYPE_TPKEY,
.security_lvl = HWKM_KEY_SECURITY_LVL_HW_KEY,
.hw_destination = HWKM_KEY_DEST_KM_MASTER,
};
const struct hwkm_key_policy swap_key_policy = {
.km_by_tz_allowed = true,
.alg_allowed = HWKM_ALGO_AES256_SIV,
.enc_allowed = true,
.dec_allowed = true,
.key_type = HWKM_KEY_TYPE_KSK,
.security_lvl = HWKM_KEY_SECURITY_LVL_HW_KEY,
.hw_destination = HWKM_KEY_DEST_KM_MASTER,
};
const struct hwkm_bsve bsve = {
.enabled = true,
.km_swc_en = true,
};
struct hwkm_transaction t_keygen = {
.cmd = {
.op = HWKM_OP_NIST_KEYGEN,
.keygen = {
.dks = HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT1,
.policy = base_kdk_policy,
},
},
};
struct hwkm_transaction t_tpkey_kdf = {
.cmd = {
.op = HWKM_OP_SYSTEM_KDF,
.kdf = {
.dks = HWKM_SLOT_TPKEY_SLOT,
.kdk = HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT1,
.policy = tpkey_policy,
.bsve = bsve,
.ctx_len = 16,
.ctx = {
0x54, 0x52, 0x41, 0x4e,
0x53, 0x50, 0x4f, 0x52,
0x54, 0x20, 0x4b, 0x45,
0x59, 0x00, 0x00, 0x00,
},
},
},
};
struct hwkm_transaction t_swap_kdf = {
.cmd = {
.op = HWKM_OP_SYSTEM_KDF,
.kdf = {
.dks = HWKM_SLOT_TZ_SWAP_KEY_SLOT,
.kdk = HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT1,
.policy = swap_key_policy,
.bsve = bsve,
.ctx_len = 8,
.ctx = {
0x53, 0x57, 0x41, 0x50,
0x20, 0x4b, 0x45, 0x59,
},
},
},
};
struct hwkm_transaction t_clear = {
.cmd = {
.op = HWKM_OP_KEY_SLOT_CLEAR,
.clear = {
.dks = HWKM_SLOT_TZ_GENERAL_PURPOSE_SLOT1,
.is_double_key = false,
},
},
};
TEE_Result res = TEE_ERROR_GENERIC;
int rc = HWKM_ERR_GENERIC;

rc = hwkm_run_transactions(HWKM_KEY_DEST_KM_MASTER, 4,
(struct hwkm_transaction *const[]){
&t_keygen, &t_tpkey_kdf,
&t_swap_kdf, &t_clear });
if (rc)
return hwkm_to_optee(rc);

if (t_keygen.rsp.status != HWKM_RSP_ERR_SUCCESS) {
EMSG("hwkm: initial NIST_KEYGEN failed: %s",
hwkm_err2str(t_keygen.rsp.status));
res = TEE_ERROR_GENERIC;
goto out;
}

if (t_tpkey_kdf.rsp.status != HWKM_RSP_ERR_SUCCESS) {
EMSG("hwkm: initial TPKEY SYSTEM_KDF failed: %s",
hwkm_err2str(t_tpkey_kdf.rsp.status));
res = TEE_ERROR_GENERIC;
goto out;
}

if (t_swap_kdf.rsp.status != HWKM_RSP_ERR_SUCCESS) {
EMSG("hwkm: initial SWAP SYSTEM_KDF failed: %s",
hwkm_err2str(t_swap_kdf.rsp.status));
res = TEE_ERROR_GENERIC;
goto out;
}

if (t_clear.rsp.status != HWKM_RSP_ERR_SUCCESS &&
t_clear.rsp.status != HWKM_CLEAR_ERR_DKS_SLOT_EMPTY) {
EMSG("hwkm: initial KEY_SLOT_CLEAR failed: %s",
hwkm_err2str(t_clear.rsp.status));
res = TEE_ERROR_GENERIC;
goto out;
}

res = TEE_SUCCESS;

out:
return res;
}

static TEE_Result hwkm_driver_init(void)
{
struct tee_hw_unique_key huk = { };
Expand All @@ -253,6 +437,18 @@ static TEE_Result hwkm_driver_init(void)
return res;
}

res = gpce_init();
if (res) {
EMSG("hwkm: gpce init failed: 0x%08"PRIx32, res);
return res;
}

res = hwkm_generate_tp_and_swap_keys();
if (res) {
EMSG("hwkm: TP and SWAP key generation failed: 0x%08"PRIx32, res);
return res;
}

res = tee_otp_get_hw_unique_key(&huk);
if (res) {
EMSG("hwkm: HUK derivation failed: 0x%08"PRIx32, res);
Expand Down
Loading