diff mbox series

[v3,04/12] soc: qcom: ice: support for hardware wrapped keys

Message ID 20231122053817.3401748-5-quic_gaurkash@quicinc.com (mailing list archive)
State New
Headers show
Series Hardware wrapped key support for qcom ice and ufs | expand

Commit Message

Gaurav Kashyap Nov. 22, 2023, 5:38 a.m. UTC
Now that HWKM support is added to ICE, extend the ICE
driver to support hardware wrapped keys programming coming
in from the storage controllers (ufs and emmc). The patches that follow
will add ufs and emmc support.

Derive software secret support is also added by forwarding the
call the corresponding scm api.

Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
---
 drivers/soc/qcom/ice.c | 114 +++++++++++++++++++++++++++++++++++++----
 include/soc/qcom/ice.h |   4 ++
 2 files changed, 107 insertions(+), 11 deletions(-)

Comments

Om Prakash Singh Dec. 8, 2023, 7:45 a.m. UTC | #1
On 11/22/2023 11:08 AM, Gaurav Kashyap wrote:
> Now that HWKM support is added to ICE, extend the ICE
> driver to support hardware wrapped keys programming coming
> in from the storage controllers (ufs and emmc). The patches that follow
> will add ufs and emmc support.
> 
> Derive software secret support is also added by forwarding the
> call the corresponding scm api.
> 
> Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
> ---
>   drivers/soc/qcom/ice.c | 114 +++++++++++++++++++++++++++++++++++++----
>   include/soc/qcom/ice.h |   4 ++
>   2 files changed, 107 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
> index adf9cab848fa..ee7c0beef3d2 100644
> --- a/drivers/soc/qcom/ice.c
> +++ b/drivers/soc/qcom/ice.c
> @@ -27,6 +27,8 @@
>   #define QCOM_ICE_REG_BIST_STATUS		0x0070
>   #define QCOM_ICE_REG_ADVANCED_CONTROL		0x1000
>   #define QCOM_ICE_REG_CONTROL			0x0
> +#define QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16		0x4040
> +
>   /* QCOM ICE HWKM registers */
>   #define QCOM_ICE_REG_HWKM_TZ_KM_CTL			0x1000
>   #define QCOM_ICE_REG_HWKM_TZ_KM_STATUS			0x1004
> @@ -37,6 +39,7 @@
>   #define QCOM_ICE_REG_HWKM_BANK0_BBAC_3			0x500C
>   #define QCOM_ICE_REG_HWKM_BANK0_BBAC_4			0x5010
>   
> +/* QCOM ICE HWKM BIST vals */
>   #define QCOM_ICE_HWKM_BIST_DONE_V1_VAL		0x11
>   #define QCOM_ICE_HWKM_BIST_DONE_V2_VAL		0x287
>   
> @@ -47,6 +50,8 @@
>   #define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK	0x2
>   #define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK	0x4
>   
> +#define QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET	0x80
> +
>   #define QCOM_ICE_HWKM_REG_OFFSET	0x8000
>   #define HWKM_OFFSET(reg)		((reg) + QCOM_ICE_HWKM_REG_OFFSET)
>   
> @@ -67,6 +72,16 @@ struct qcom_ice {
>   	bool hwkm_init_complete;
>   };
>   
> +union crypto_cfg {
> +	__le32 regval;
> +	struct {
> +		u8 dusize;
> +		u8 capidx;
> +		u8 reserved;
> +		u8 cfge;
> +	};
> +};
> +
>   static bool qcom_ice_check_supported(struct qcom_ice *ice)
>   {
>   	u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
> @@ -237,6 +252,8 @@ static void qcom_ice_hwkm_init(struct qcom_ice *ice)
>   	/* Clear HWKM response FIFO before doing anything */
>   	qcom_ice_writel(ice, 0x8,
>   			HWKM_OFFSET(QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STATUS));
> +
> +	ice->hwkm_init_complete = true;
This this change should go with previous patch 3/12.
>   }
>   
>   int qcom_ice_enable(struct qcom_ice *ice)
> @@ -284,6 +301,51 @@ int qcom_ice_suspend(struct qcom_ice *ice)
>   }
>   EXPORT_SYMBOL_GPL(qcom_ice_suspend);
>   
> +/*
> + * HW dictates the internal mapping between the ICE and HWKM slots,
> + * which are different for different versions, make the translation
> + * here. For v1 however, the translation is done in trustzone.
> + */
> +static int translate_hwkm_slot(struct qcom_ice *ice, int slot)
> +{
> +	return (ice->hwkm_version == 1) ? slot : (slot * 2);
> +}
> +
> +static int qcom_ice_program_wrapped_key(struct qcom_ice *ice,
> +					const struct blk_crypto_key *key,
> +					u8 data_unit_size, int slot)
> +{
> +	int hwkm_slot;
> +	int err;
> +	union crypto_cfg cfg;
> +
> +	hwkm_slot = translate_hwkm_slot(ice, slot);
> +
> +	memset(&cfg, 0, sizeof(cfg));
> +	cfg.dusize = data_unit_size;
> +	cfg.capidx = QCOM_SCM_ICE_CIPHER_AES_256_XTS;
> +	cfg.cfge = 0x80;
use macro for constant value "0x80"
> +
> +	/* Clear CFGE */
> +	qcom_ice_writel(ice, 0x0, QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 +
> +				  QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET * slot);
> +
> +	/* Call trustzone to program the wrapped key using hwkm */
> +	err = qcom_scm_ice_set_key(hwkm_slot, key->raw, key->size,
> +				   QCOM_SCM_ICE_CIPHER_AES_256_XTS, data_unit_size);
> +	if (err) {
> +		pr_err("%s:SCM call Error: 0x%x slot %d\n", __func__, err,
> +		       slot);
> +		return err;
> +	}
> +
> +	/* Enable CFGE after programming key */
> +	qcom_ice_writel(ice, cfg.regval, QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 +
> +					 QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET * slot);
> +
> +	return err;
> +}
> +
>   int qcom_ice_program_key(struct qcom_ice *ice,
>   			 u8 algorithm_id, u8 key_size,
>   			 const struct blk_crypto_key *bkey,
> @@ -299,24 +361,31 @@ int qcom_ice_program_key(struct qcom_ice *ice,
>   
>   	/* Only AES-256-XTS has been tested so far. */
>   	if (algorithm_id != QCOM_ICE_CRYPTO_ALG_AES_XTS ||
> -	    key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256) {
> +	    (key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256 &&
> +	    key_size != QCOM_ICE_CRYPTO_KEY_SIZE_WRAPPED)) {
Can you please check the logic with && operation. the condition will 
always be false.
>   		dev_err_ratelimited(dev,
>   				    "Unhandled crypto capability; algorithm_id=%d, key_size=%d\n",
>   				    algorithm_id, key_size);
>   		return -EINVAL;
>   	}
>   
> -	memcpy(key.bytes, bkey->raw, AES_256_XTS_KEY_SIZE);
> -
> -	/* The SCM call requires that the key words are encoded in big endian */
> -	for (i = 0; i < ARRAY_SIZE(key.words); i++)
> -		__cpu_to_be32s(&key.words[i]);
> +	if (bkey->crypto_cfg.key_type == BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) {
> +		if (!ice->use_hwkm)
> +			return -EINVAL;
having error log in failure case would help in debugging.
> +		err = qcom_ice_program_wrapped_key(ice, bkey, data_unit_size,
> +						   slot);
> +	} else {
> +		memcpy(key.bytes, bkey->raw, AES_256_XTS_KEY_SIZE);
>   
> -	err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE,
> -				   QCOM_SCM_ICE_CIPHER_AES_256_XTS,
> -				   data_unit_size);
> +		/* The SCM call requires that the key words are encoded in big endian */
> +		for (i = 0; i < ARRAY_SIZE(key.words); i++)
> +			__cpu_to_be32s(&key.words[i]);
>   
> -	memzero_explicit(&key, sizeof(key));
> +		err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE,
> +					   QCOM_SCM_ICE_CIPHER_AES_256_XTS,
> +					   data_unit_size);
> +		memzero_explicit(&key, sizeof(key));
> +	}
>   
>   	return err;
>   }
> @@ -324,7 +393,21 @@ EXPORT_SYMBOL_GPL(qcom_ice_program_key);
>   
>   int qcom_ice_evict_key(struct qcom_ice *ice, int slot)
>   {
> -	return qcom_scm_ice_invalidate_key(slot);
> +	int hwkm_slot = slot;
> +
> +	if (ice->use_hwkm) {
> +		hwkm_slot = translate_hwkm_slot(ice, slot);
> +	/*
> +	 * Ignore calls to evict key when HWKM is supported and hwkm init
> +	 * is not yet done. This is to avoid the clearing all slots call
> +	 * during a storage reset when ICE is still in legacy mode. HWKM slave
> +	 * in ICE takes care of zeroing out the keytable on reset.
> +	 */
> +		if (!ice->hwkm_init_complete)
> +			return 0;
> +	}
> +
> +	return qcom_scm_ice_invalidate_key(hwkm_slot);
>   }
>   EXPORT_SYMBOL_GPL(qcom_ice_evict_key);
>   
> @@ -334,6 +417,15 @@ bool qcom_ice_hwkm_supported(struct qcom_ice *ice)
>   }
>   EXPORT_SYMBOL_GPL(qcom_ice_hwkm_supported);
>   
> +int qcom_ice_derive_sw_secret(struct qcom_ice *ice, const u8 wkey[],
> +			      unsigned int wkey_size,
> +			      u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
> +{
> +	return qcom_scm_derive_sw_secret(wkey, wkey_size,
> +					 sw_secret, BLK_CRYPTO_SW_SECRET_SIZE);
> +}
> +EXPORT_SYMBOL_GPL(qcom_ice_derive_sw_secret);
> +
>   static struct qcom_ice *qcom_ice_create(struct device *dev,
>   					void __iomem *base)
>   {
> diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h
> index 1f52e82e3e1c..dabe0d3a1fd0 100644
> --- a/include/soc/qcom/ice.h
> +++ b/include/soc/qcom/ice.h
> @@ -17,6 +17,7 @@ enum qcom_ice_crypto_key_size {
>   	QCOM_ICE_CRYPTO_KEY_SIZE_192		= 0x2,
>   	QCOM_ICE_CRYPTO_KEY_SIZE_256		= 0x3,
>   	QCOM_ICE_CRYPTO_KEY_SIZE_512		= 0x4,
> +	QCOM_ICE_CRYPTO_KEY_SIZE_WRAPPED	= 0x5,
>   };
>   
>   enum qcom_ice_crypto_alg {
> @@ -35,5 +36,8 @@ int qcom_ice_program_key(struct qcom_ice *ice,
>   			 u8 data_unit_size, int slot);
>   int qcom_ice_evict_key(struct qcom_ice *ice, int slot);
>   bool qcom_ice_hwkm_supported(struct qcom_ice *ice);
> +int qcom_ice_derive_sw_secret(struct qcom_ice *ice, const u8 wkey[],
> +			      unsigned int wkey_size,
> +			      u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
>   struct qcom_ice *of_qcom_ice_get(struct device *dev);
>   #endif /* __QCOM_ICE_H__ */
Gaurav Kashyap Dec. 12, 2023, 4:04 a.m. UTC | #2
Hello Om

On 12/07/2023, Om Prakash Singh wrote:
> On 11/22/2023 11:08 AM, Gaurav Kashyap wrote:
> > Now that HWKM support is added to ICE, extend the ICE driver to
> > support hardware wrapped keys programming coming in from the storage
> > controllers (ufs and emmc). The patches that follow will add ufs and
> > emmc support.
> >
> > Derive software secret support is also added by forwarding the call
> > the corresponding scm api.
> >
> > Signed-off-by: Gaurav Kashyap <quic_gaurkash@quicinc.com>
> > ---
> >   drivers/soc/qcom/ice.c | 114
> +++++++++++++++++++++++++++++++++++++----
> >   include/soc/qcom/ice.h |   4 ++
> >   2 files changed, 107 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c index
> > adf9cab848fa..ee7c0beef3d2 100644
> > --- a/drivers/soc/qcom/ice.c
> > +++ b/drivers/soc/qcom/ice.c
> > @@ -27,6 +27,8 @@
> >   #define QCOM_ICE_REG_BIST_STATUS		0x0070
> >   #define QCOM_ICE_REG_ADVANCED_CONTROL		0x1000
> >   #define QCOM_ICE_REG_CONTROL			0x0
> > +#define QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16		0x4040
> > +
> >   /* QCOM ICE HWKM registers */
> >   #define QCOM_ICE_REG_HWKM_TZ_KM_CTL
> 	0x1000
> >   #define QCOM_ICE_REG_HWKM_TZ_KM_STATUS
> 	0x1004
> > @@ -37,6 +39,7 @@
> >   #define QCOM_ICE_REG_HWKM_BANK0_BBAC_3
> 	0x500C
> >   #define QCOM_ICE_REG_HWKM_BANK0_BBAC_4
> 	0x5010
> >
> > +/* QCOM ICE HWKM BIST vals */
> >   #define QCOM_ICE_HWKM_BIST_DONE_V1_VAL		0x11
> >   #define QCOM_ICE_HWKM_BIST_DONE_V2_VAL		0x287
> >
> > @@ -47,6 +50,8 @@
> >   #define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK	0x2
> >   #define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK	0x4
> >
> > +#define QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET	0x80
> > +
> >   #define QCOM_ICE_HWKM_REG_OFFSET	0x8000
> >   #define HWKM_OFFSET(reg)		((reg) +
> QCOM_ICE_HWKM_REG_OFFSET)
> >
> > @@ -67,6 +72,16 @@ struct qcom_ice {
> >   	bool hwkm_init_complete;
> >   };
> >
> > +union crypto_cfg {
> > +	__le32 regval;
> > +	struct {
> > +		u8 dusize;
> > +		u8 capidx;
> > +		u8 reserved;
> > +		u8 cfge;
> > +	};
> > +};
> > +
> >   static bool qcom_ice_check_supported(struct qcom_ice *ice)
> >   {
> >   	u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION); @@ -
> 237,6
> > +252,8 @@ static void qcom_ice_hwkm_init(struct qcom_ice *ice)
> >   	/* Clear HWKM response FIFO before doing anything */
> >   	qcom_ice_writel(ice, 0x8,
> >
> 	HWKM_OFFSET(QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STA
> TUS));
> > +
> > +	ice->hwkm_init_complete = true;
> This this change should go with previous patch 3/12.

Okay, makes sense.

> >   }
> >
> >   int qcom_ice_enable(struct qcom_ice *ice) @@ -284,6 +301,51 @@ int
> > qcom_ice_suspend(struct qcom_ice *ice)
> >   }
> >   EXPORT_SYMBOL_GPL(qcom_ice_suspend);
> >
> > +/*
> > + * HW dictates the internal mapping between the ICE and HWKM slots,
> > + * which are different for different versions, make the translation
> > + * here. For v1 however, the translation is done in trustzone.
> > + */
> > +static int translate_hwkm_slot(struct qcom_ice *ice, int slot) {
> > +	return (ice->hwkm_version == 1) ? slot : (slot * 2); }
> > +
> > +static int qcom_ice_program_wrapped_key(struct qcom_ice *ice,
> > +					const struct blk_crypto_key *key,
> > +					u8 data_unit_size, int slot)
> > +{
> > +	int hwkm_slot;
> > +	int err;
> > +	union crypto_cfg cfg;
> > +
> > +	hwkm_slot = translate_hwkm_slot(ice, slot);
> > +
> > +	memset(&cfg, 0, sizeof(cfg));
> > +	cfg.dusize = data_unit_size;
> > +	cfg.capidx = QCOM_SCM_ICE_CIPHER_AES_256_XTS;
> > +	cfg.cfge = 0x80;
> use macro for constant value "0x80"
> > +
> > +	/* Clear CFGE */
> > +	qcom_ice_writel(ice, 0x0, QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 +
> > +				  QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET
> * slot);
> > +
> > +	/* Call trustzone to program the wrapped key using hwkm */
> > +	err = qcom_scm_ice_set_key(hwkm_slot, key->raw, key->size,
> > +				   QCOM_SCM_ICE_CIPHER_AES_256_XTS,
> data_unit_size);
> > +	if (err) {
> > +		pr_err("%s:SCM call Error: 0x%x slot %d\n", __func__, err,
> > +		       slot);
> > +		return err;
> > +	}
> > +
> > +	/* Enable CFGE after programming key */
> > +	qcom_ice_writel(ice, cfg.regval,
> QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 +
> > +
> QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET * slot);
> > +
> > +	return err;
> > +}
> > +
> >   int qcom_ice_program_key(struct qcom_ice *ice,
> >   			 u8 algorithm_id, u8 key_size,
> >   			 const struct blk_crypto_key *bkey, @@ -299,24
> +361,31 @@ int
> > qcom_ice_program_key(struct qcom_ice *ice,
> >
> >   	/* Only AES-256-XTS has been tested so far. */
> >   	if (algorithm_id != QCOM_ICE_CRYPTO_ALG_AES_XTS ||
> > -	    key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256) {
> > +	    (key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256 &&
> > +	    key_size != QCOM_ICE_CRYPTO_KEY_SIZE_WRAPPED)) {
> Can you please check the logic with && operation. the condition will always
> be false.

No, the condition won't always be false, my v2 patches were wrong which was pointed out by Neil
https://lore.kernel.org/all/fcbf6dee-aa6a-4af8-9ff1-495adbcb5a57@linaro.org/

The condition would check if the size passed is either 256 or wrapped.

> >   		dev_err_ratelimited(dev,
> >   				    "Unhandled crypto capability;
> algorithm_id=%d, key_size=%d\n",
> >   				    algorithm_id, key_size);
> >   		return -EINVAL;
> >   	}
> >
> > -	memcpy(key.bytes, bkey->raw, AES_256_XTS_KEY_SIZE);
> > -
> > -	/* The SCM call requires that the key words are encoded in big
> endian */
> > -	for (i = 0; i < ARRAY_SIZE(key.words); i++)
> > -		__cpu_to_be32s(&key.words[i]);
> > +	if (bkey->crypto_cfg.key_type ==
> BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) {
> > +		if (!ice->use_hwkm)
> > +			return -EINVAL;
> having error log in failure case would help in debugging.
> > +		err = qcom_ice_program_wrapped_key(ice, bkey,
> data_unit_size,
> > +						   slot);
> > +	} else {
> > +		memcpy(key.bytes, bkey->raw, AES_256_XTS_KEY_SIZE);
> >
> > -	err = qcom_scm_ice_set_key(slot, key.bytes,
> AES_256_XTS_KEY_SIZE,
> > -				   QCOM_SCM_ICE_CIPHER_AES_256_XTS,
> > -				   data_unit_size);
> > +		/* The SCM call requires that the key words are encoded in
> big endian */
> > +		for (i = 0; i < ARRAY_SIZE(key.words); i++)
> > +			__cpu_to_be32s(&key.words[i]);
> >
> > -	memzero_explicit(&key, sizeof(key));
> > +		err = qcom_scm_ice_set_key(slot, key.bytes,
> AES_256_XTS_KEY_SIZE,
> > +
> QCOM_SCM_ICE_CIPHER_AES_256_XTS,
> > +					   data_unit_size);
> > +		memzero_explicit(&key, sizeof(key));
> > +	}
> >
> >   	return err;
> >   }
> > @@ -324,7 +393,21 @@ EXPORT_SYMBOL_GPL(qcom_ice_program_key);
> >
> >   int qcom_ice_evict_key(struct qcom_ice *ice, int slot)
> >   {
> > -	return qcom_scm_ice_invalidate_key(slot);
> > +	int hwkm_slot = slot;
> > +
> > +	if (ice->use_hwkm) {
> > +		hwkm_slot = translate_hwkm_slot(ice, slot);
> > +	/*
> > +	 * Ignore calls to evict key when HWKM is supported and hwkm init
> > +	 * is not yet done. This is to avoid the clearing all slots call
> > +	 * during a storage reset when ICE is still in legacy mode. HWKM slave
> > +	 * in ICE takes care of zeroing out the keytable on reset.
> > +	 */
> > +		if (!ice->hwkm_init_complete)
> > +			return 0;
> > +	}
> > +
> > +	return qcom_scm_ice_invalidate_key(hwkm_slot);
> >   }
> >   EXPORT_SYMBOL_GPL(qcom_ice_evict_key);
> >
> > @@ -334,6 +417,15 @@ bool qcom_ice_hwkm_supported(struct qcom_ice
> *ice)
> >   }
> >   EXPORT_SYMBOL_GPL(qcom_ice_hwkm_supported);
> >
> > +int qcom_ice_derive_sw_secret(struct qcom_ice *ice, const u8 wkey[],
> > +			      unsigned int wkey_size,
> > +			      u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
> > +{
> > +	return qcom_scm_derive_sw_secret(wkey, wkey_size,
> > +					 sw_secret,
> BLK_CRYPTO_SW_SECRET_SIZE); }
> > +EXPORT_SYMBOL_GPL(qcom_ice_derive_sw_secret);
> > +
> >   static struct qcom_ice *qcom_ice_create(struct device *dev,
> >   					void __iomem *base)
> >   {
> > diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h index
> > 1f52e82e3e1c..dabe0d3a1fd0 100644
> > --- a/include/soc/qcom/ice.h
> > +++ b/include/soc/qcom/ice.h
> > @@ -17,6 +17,7 @@ enum qcom_ice_crypto_key_size {
> >   	QCOM_ICE_CRYPTO_KEY_SIZE_192		= 0x2,
> >   	QCOM_ICE_CRYPTO_KEY_SIZE_256		= 0x3,
> >   	QCOM_ICE_CRYPTO_KEY_SIZE_512		= 0x4,
> > +	QCOM_ICE_CRYPTO_KEY_SIZE_WRAPPED	= 0x5,
> >   };
> >
> >   enum qcom_ice_crypto_alg {
> > @@ -35,5 +36,8 @@ int qcom_ice_program_key(struct qcom_ice *ice,
> >   			 u8 data_unit_size, int slot);
> >   int qcom_ice_evict_key(struct qcom_ice *ice, int slot);
> >   bool qcom_ice_hwkm_supported(struct qcom_ice *ice);
> > +int qcom_ice_derive_sw_secret(struct qcom_ice *ice, const u8 wkey[],
> > +			      unsigned int wkey_size,
> > +			      u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
> >   struct qcom_ice *of_qcom_ice_get(struct device *dev);
> >   #endif /* __QCOM_ICE_H__ */
diff mbox series

Patch

diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index adf9cab848fa..ee7c0beef3d2 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -27,6 +27,8 @@ 
 #define QCOM_ICE_REG_BIST_STATUS		0x0070
 #define QCOM_ICE_REG_ADVANCED_CONTROL		0x1000
 #define QCOM_ICE_REG_CONTROL			0x0
+#define QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16		0x4040
+
 /* QCOM ICE HWKM registers */
 #define QCOM_ICE_REG_HWKM_TZ_KM_CTL			0x1000
 #define QCOM_ICE_REG_HWKM_TZ_KM_STATUS			0x1004
@@ -37,6 +39,7 @@ 
 #define QCOM_ICE_REG_HWKM_BANK0_BBAC_3			0x500C
 #define QCOM_ICE_REG_HWKM_BANK0_BBAC_4			0x5010
 
+/* QCOM ICE HWKM BIST vals */
 #define QCOM_ICE_HWKM_BIST_DONE_V1_VAL		0x11
 #define QCOM_ICE_HWKM_BIST_DONE_V2_VAL		0x287
 
@@ -47,6 +50,8 @@ 
 #define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK	0x2
 #define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK	0x4
 
+#define QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET	0x80
+
 #define QCOM_ICE_HWKM_REG_OFFSET	0x8000
 #define HWKM_OFFSET(reg)		((reg) + QCOM_ICE_HWKM_REG_OFFSET)
 
@@ -67,6 +72,16 @@  struct qcom_ice {
 	bool hwkm_init_complete;
 };
 
+union crypto_cfg {
+	__le32 regval;
+	struct {
+		u8 dusize;
+		u8 capidx;
+		u8 reserved;
+		u8 cfge;
+	};
+};
+
 static bool qcom_ice_check_supported(struct qcom_ice *ice)
 {
 	u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
@@ -237,6 +252,8 @@  static void qcom_ice_hwkm_init(struct qcom_ice *ice)
 	/* Clear HWKM response FIFO before doing anything */
 	qcom_ice_writel(ice, 0x8,
 			HWKM_OFFSET(QCOM_ICE_REG_HWKM_BANK0_BANKN_IRQ_STATUS));
+
+	ice->hwkm_init_complete = true;
 }
 
 int qcom_ice_enable(struct qcom_ice *ice)
@@ -284,6 +301,51 @@  int qcom_ice_suspend(struct qcom_ice *ice)
 }
 EXPORT_SYMBOL_GPL(qcom_ice_suspend);
 
+/*
+ * HW dictates the internal mapping between the ICE and HWKM slots,
+ * which are different for different versions, make the translation
+ * here. For v1 however, the translation is done in trustzone.
+ */
+static int translate_hwkm_slot(struct qcom_ice *ice, int slot)
+{
+	return (ice->hwkm_version == 1) ? slot : (slot * 2);
+}
+
+static int qcom_ice_program_wrapped_key(struct qcom_ice *ice,
+					const struct blk_crypto_key *key,
+					u8 data_unit_size, int slot)
+{
+	int hwkm_slot;
+	int err;
+	union crypto_cfg cfg;
+
+	hwkm_slot = translate_hwkm_slot(ice, slot);
+
+	memset(&cfg, 0, sizeof(cfg));
+	cfg.dusize = data_unit_size;
+	cfg.capidx = QCOM_SCM_ICE_CIPHER_AES_256_XTS;
+	cfg.cfge = 0x80;
+
+	/* Clear CFGE */
+	qcom_ice_writel(ice, 0x0, QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 +
+				  QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET * slot);
+
+	/* Call trustzone to program the wrapped key using hwkm */
+	err = qcom_scm_ice_set_key(hwkm_slot, key->raw, key->size,
+				   QCOM_SCM_ICE_CIPHER_AES_256_XTS, data_unit_size);
+	if (err) {
+		pr_err("%s:SCM call Error: 0x%x slot %d\n", __func__, err,
+		       slot);
+		return err;
+	}
+
+	/* Enable CFGE after programming key */
+	qcom_ice_writel(ice, cfg.regval, QCOM_ICE_LUT_KEYS_CRYPTOCFG_R16 +
+					 QCOM_ICE_LUT_KEYS_CRYPTOCFG_OFFSET * slot);
+
+	return err;
+}
+
 int qcom_ice_program_key(struct qcom_ice *ice,
 			 u8 algorithm_id, u8 key_size,
 			 const struct blk_crypto_key *bkey,
@@ -299,24 +361,31 @@  int qcom_ice_program_key(struct qcom_ice *ice,
 
 	/* Only AES-256-XTS has been tested so far. */
 	if (algorithm_id != QCOM_ICE_CRYPTO_ALG_AES_XTS ||
-	    key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256) {
+	    (key_size != QCOM_ICE_CRYPTO_KEY_SIZE_256 &&
+	    key_size != QCOM_ICE_CRYPTO_KEY_SIZE_WRAPPED)) {
 		dev_err_ratelimited(dev,
 				    "Unhandled crypto capability; algorithm_id=%d, key_size=%d\n",
 				    algorithm_id, key_size);
 		return -EINVAL;
 	}
 
-	memcpy(key.bytes, bkey->raw, AES_256_XTS_KEY_SIZE);
-
-	/* The SCM call requires that the key words are encoded in big endian */
-	for (i = 0; i < ARRAY_SIZE(key.words); i++)
-		__cpu_to_be32s(&key.words[i]);
+	if (bkey->crypto_cfg.key_type == BLK_CRYPTO_KEY_TYPE_HW_WRAPPED) {
+		if (!ice->use_hwkm)
+			return -EINVAL;
+		err = qcom_ice_program_wrapped_key(ice, bkey, data_unit_size,
+						   slot);
+	} else {
+		memcpy(key.bytes, bkey->raw, AES_256_XTS_KEY_SIZE);
 
-	err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE,
-				   QCOM_SCM_ICE_CIPHER_AES_256_XTS,
-				   data_unit_size);
+		/* The SCM call requires that the key words are encoded in big endian */
+		for (i = 0; i < ARRAY_SIZE(key.words); i++)
+			__cpu_to_be32s(&key.words[i]);
 
-	memzero_explicit(&key, sizeof(key));
+		err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE,
+					   QCOM_SCM_ICE_CIPHER_AES_256_XTS,
+					   data_unit_size);
+		memzero_explicit(&key, sizeof(key));
+	}
 
 	return err;
 }
@@ -324,7 +393,21 @@  EXPORT_SYMBOL_GPL(qcom_ice_program_key);
 
 int qcom_ice_evict_key(struct qcom_ice *ice, int slot)
 {
-	return qcom_scm_ice_invalidate_key(slot);
+	int hwkm_slot = slot;
+
+	if (ice->use_hwkm) {
+		hwkm_slot = translate_hwkm_slot(ice, slot);
+	/*
+	 * Ignore calls to evict key when HWKM is supported and hwkm init
+	 * is not yet done. This is to avoid the clearing all slots call
+	 * during a storage reset when ICE is still in legacy mode. HWKM slave
+	 * in ICE takes care of zeroing out the keytable on reset.
+	 */
+		if (!ice->hwkm_init_complete)
+			return 0;
+	}
+
+	return qcom_scm_ice_invalidate_key(hwkm_slot);
 }
 EXPORT_SYMBOL_GPL(qcom_ice_evict_key);
 
@@ -334,6 +417,15 @@  bool qcom_ice_hwkm_supported(struct qcom_ice *ice)
 }
 EXPORT_SYMBOL_GPL(qcom_ice_hwkm_supported);
 
+int qcom_ice_derive_sw_secret(struct qcom_ice *ice, const u8 wkey[],
+			      unsigned int wkey_size,
+			      u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE])
+{
+	return qcom_scm_derive_sw_secret(wkey, wkey_size,
+					 sw_secret, BLK_CRYPTO_SW_SECRET_SIZE);
+}
+EXPORT_SYMBOL_GPL(qcom_ice_derive_sw_secret);
+
 static struct qcom_ice *qcom_ice_create(struct device *dev,
 					void __iomem *base)
 {
diff --git a/include/soc/qcom/ice.h b/include/soc/qcom/ice.h
index 1f52e82e3e1c..dabe0d3a1fd0 100644
--- a/include/soc/qcom/ice.h
+++ b/include/soc/qcom/ice.h
@@ -17,6 +17,7 @@  enum qcom_ice_crypto_key_size {
 	QCOM_ICE_CRYPTO_KEY_SIZE_192		= 0x2,
 	QCOM_ICE_CRYPTO_KEY_SIZE_256		= 0x3,
 	QCOM_ICE_CRYPTO_KEY_SIZE_512		= 0x4,
+	QCOM_ICE_CRYPTO_KEY_SIZE_WRAPPED	= 0x5,
 };
 
 enum qcom_ice_crypto_alg {
@@ -35,5 +36,8 @@  int qcom_ice_program_key(struct qcom_ice *ice,
 			 u8 data_unit_size, int slot);
 int qcom_ice_evict_key(struct qcom_ice *ice, int slot);
 bool qcom_ice_hwkm_supported(struct qcom_ice *ice);
+int qcom_ice_derive_sw_secret(struct qcom_ice *ice, const u8 wkey[],
+			      unsigned int wkey_size,
+			      u8 sw_secret[BLK_CRYPTO_SW_SECRET_SIZE]);
 struct qcom_ice *of_qcom_ice_get(struct device *dev);
 #endif /* __QCOM_ICE_H__ */