File Index
Files and directories
Sign in
FILE

tegra-se-key.c

File preview with syntax highlighting.

linux-6.19.14/drivers/crypto/tegra/tegra-se-key.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  3/*
  4 * Crypto driver file to manage keys of NVIDIA Security Engine.
  5 */
  6
  7#include <linux/bitops.h>
  8#include <linux/module.h>
  9#include <crypto/aes.h>
 10
 11#include "tegra-se.h"
 12
 13#define SE_KEY_FULL_MASK		GENMASK(SE_MAX_KEYSLOT, 0)
 14
 15/* Reserve keyslot 0, 14, 15 */
 16#define SE_KEY_RSVD_MASK		(BIT(0) | BIT(14) | BIT(15))
 17#define SE_KEY_VALID_MASK		(SE_KEY_FULL_MASK & ~SE_KEY_RSVD_MASK)
 18
 19/* Mutex lock to guard keyslots */
 20static DEFINE_MUTEX(kslt_lock);
 21
 22/* Keyslot bitmask (0 = available, 1 = in use/not available) */
 23static u16 tegra_se_keyslots = SE_KEY_RSVD_MASK;
 24
 25static u16 tegra_keyslot_alloc(void)
 26{
 27	u16 keyid;
 28
 29	mutex_lock(&kslt_lock);
 30	/* Check if all key slots are full */
 31	if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0)) {
 32		mutex_unlock(&kslt_lock);
 33		return 0;
 34	}
 35
 36	keyid = ffz(tegra_se_keyslots);
 37	tegra_se_keyslots |= BIT(keyid);
 38
 39	mutex_unlock(&kslt_lock);
 40
 41	return keyid;
 42}
 43
 44static void tegra_keyslot_free(u16 slot)
 45{
 46	mutex_lock(&kslt_lock);
 47	tegra_se_keyslots &= ~(BIT(slot));
 48	mutex_unlock(&kslt_lock);
 49}
 50
 51static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
 52					   const u32 *key, u32 keylen, u16 slot, u32 alg)
 53{
 54	int i = 0, j;
 55
 56	cpuvaddr[i++] = host1x_opcode_setpayload(1);
 57	cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
 58	cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_DUMMY;
 59
 60	cpuvaddr[i++] = host1x_opcode_setpayload(1);
 61	cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->manifest);
 62	cpuvaddr[i++] = se->manifest(se->owner, alg, keylen);
 63	cpuvaddr[i++] = host1x_opcode_setpayload(1);
 64	cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_dst);
 65
 66	cpuvaddr[i++] = SE_AES_KEY_DST_INDEX(slot);
 67
 68	for (j = 0; j < keylen / 4; j++) {
 69		/* Set key address */
 70		cpuvaddr[i++] = host1x_opcode_setpayload(1);
 71		cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_addr);
 72		cpuvaddr[i++] = j;
 73
 74		/* Set key data */
 75		cpuvaddr[i++] = host1x_opcode_setpayload(1);
 76		cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_data);
 77		cpuvaddr[i++] = key[j];
 78	}
 79
 80	cpuvaddr[i++] = host1x_opcode_setpayload(1);
 81	cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
 82	cpuvaddr[i++] = SE_CFG_INS;
 83
 84	cpuvaddr[i++] = host1x_opcode_setpayload(1);
 85	cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
 86	cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
 87			SE_AES_OP_LASTBUF;
 88
 89	cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
 90	cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
 91			host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
 92
 93	dev_dbg(se->dev, "key-slot %u key-manifest %#x\n",
 94		slot, se->manifest(se->owner, alg, keylen));
 95
 96	return i;
 97}
 98
 99static bool tegra_key_in_kslt(u32 keyid)
100{
101	bool ret;
102
103	if (keyid > SE_MAX_KEYSLOT)
104		return false;
105
106	mutex_lock(&kslt_lock);
107	ret = ((BIT(keyid) & SE_KEY_VALID_MASK) &&
108		(BIT(keyid) & tegra_se_keyslots));
109	mutex_unlock(&kslt_lock);
110
111	return ret;
112}
113
114static int tegra_key_insert(struct tegra_se *se, const u8 *key,
115			    u32 keylen, u16 slot, u32 alg)
116{
117	const u32 *keyval = (u32 *)key;
118	u32 *addr = se->keybuf->addr, size;
119	int ret;
120
121	mutex_lock(&kslt_lock);
122
123	size = tegra_key_prep_ins_cmd(se, addr, keyval, keylen, slot, alg);
124	ret = tegra_se_host1x_submit(se, se->keybuf, size);
125
126	mutex_unlock(&kslt_lock);
127
128	return ret;
129}
130
131void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)
132{
133	u8 zkey[AES_MAX_KEY_SIZE] = {0};
134
135	if (!keyid)
136		return;
137
138	/* Overwrite the key with 0s */
139	tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
140
141	tegra_keyslot_free(keyid);
142}
143
144void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg)
145{
146	u8 zkey[AES_MAX_KEY_SIZE] = {0};
147
148	if (!keyid)
149		return;
150
151	/* Overwrite the key with 0s */
152	tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
153}
154
155inline int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key,
156				     u32 keylen, u32 alg, u32 *keyid)
157{
158	return tegra_key_insert(se, key, keylen, *keyid, alg);
159}
160
161int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u32 *keyid)
162{
163	int ret;
164
165	/* Use the existing slot if it is already allocated */
166	if (!tegra_key_in_kslt(*keyid)) {
167		*keyid = tegra_keyslot_alloc();
168		if (!(*keyid)) {
169			dev_dbg(se->dev, "failed to allocate key slot\n");
170			return -ENOMEM;
171		}
172	}
173
174	ret = tegra_key_insert(se, key, keylen, *keyid, alg);
175	if (ret)
176		return ret;
177
178	return 0;
179}
~/ Read-only file preview.