brintos

brintos / linux-shallow public Read only

0
0
Text · 3.9 KiB · ac14678 Raw
157 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// 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->cmdbuf->addr, size;119 120	size = tegra_key_prep_ins_cmd(se, addr, keyval, keylen, slot, alg);121 122	return tegra_se_host1x_submit(se, size);123}124 125void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)126{127	u8 zkey[AES_MAX_KEY_SIZE] = {0};128 129	if (!keyid)130		return;131 132	/* Overwrite the key with 0s */133	tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);134 135	tegra_keyslot_free(keyid);136}137 138int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u32 *keyid)139{140	int ret;141 142	/* Use the existing slot if it is already allocated */143	if (!tegra_key_in_kslt(*keyid)) {144		*keyid = tegra_keyslot_alloc();145		if (!(*keyid)) {146			dev_err(se->dev, "failed to allocate key slot\n");147			return -ENOMEM;148		}149	}150 151	ret = tegra_key_insert(se, key, keylen, *keyid, alg);152	if (ret)153		return ret;154 155	return 0;156}157