| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- // SPDX-License-Identifier: GPL-2.0-only
- // SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
- /*
- * Crypto driver file to manage keys of NVIDIA Security Engine.
- */
- #include <linux/bitops.h>
- #include <linux/module.h>
- #include <crypto/aes.h>
- #include "tegra-se.h"
- #define SE_KEY_FULL_MASK GENMASK(SE_MAX_KEYSLOT, 0)
- /* Reserve keyslot 0, 14, 15 */
- #define SE_KEY_RSVD_MASK (BIT(0) | BIT(14) | BIT(15))
- #define SE_KEY_VALID_MASK (SE_KEY_FULL_MASK & ~SE_KEY_RSVD_MASK)
- /* Mutex lock to guard keyslots */
- static DEFINE_MUTEX(kslt_lock);
- /* Keyslot bitmask (0 = available, 1 = in use/not available) */
- static u16 tegra_se_keyslots = SE_KEY_RSVD_MASK;
- static u16 tegra_keyslot_alloc(void)
- {
- u16 keyid;
- mutex_lock(&kslt_lock);
- /* Check if all key slots are full */
- if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0)) {
- mutex_unlock(&kslt_lock);
- return 0;
- }
- keyid = ffz(tegra_se_keyslots);
- tegra_se_keyslots |= BIT(keyid);
- mutex_unlock(&kslt_lock);
- return keyid;
- }
- static void tegra_keyslot_free(u16 slot)
- {
- mutex_lock(&kslt_lock);
- tegra_se_keyslots &= ~(BIT(slot));
- mutex_unlock(&kslt_lock);
- }
- static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
- const u32 *key, u32 keylen, u16 slot, u32 alg)
- {
- int i = 0, j;
- cpuvaddr[i++] = host1x_opcode_setpayload(1);
- cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
- cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_DUMMY;
- cpuvaddr[i++] = host1x_opcode_setpayload(1);
- cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->manifest);
- cpuvaddr[i++] = se->manifest(se->owner, alg, keylen);
- cpuvaddr[i++] = host1x_opcode_setpayload(1);
- cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_dst);
- cpuvaddr[i++] = SE_AES_KEY_DST_INDEX(slot);
- for (j = 0; j < keylen / 4; j++) {
- /* Set key address */
- cpuvaddr[i++] = host1x_opcode_setpayload(1);
- cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_addr);
- cpuvaddr[i++] = j;
- /* Set key data */
- cpuvaddr[i++] = host1x_opcode_setpayload(1);
- cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_data);
- cpuvaddr[i++] = key[j];
- }
- cpuvaddr[i++] = host1x_opcode_setpayload(1);
- cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
- cpuvaddr[i++] = SE_CFG_INS;
- cpuvaddr[i++] = host1x_opcode_setpayload(1);
- cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
- cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
- SE_AES_OP_LASTBUF;
- cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
- cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
- host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
- dev_dbg(se->dev, "key-slot %u key-manifest %#x\n",
- slot, se->manifest(se->owner, alg, keylen));
- return i;
- }
- static bool tegra_key_in_kslt(u32 keyid)
- {
- bool ret;
- if (keyid > SE_MAX_KEYSLOT)
- return false;
- mutex_lock(&kslt_lock);
- ret = ((BIT(keyid) & SE_KEY_VALID_MASK) &&
- (BIT(keyid) & tegra_se_keyslots));
- mutex_unlock(&kslt_lock);
- return ret;
- }
- static int tegra_key_insert(struct tegra_se *se, const u8 *key,
- u32 keylen, u16 slot, u32 alg)
- {
- const u32 *keyval = (u32 *)key;
- u32 *addr = se->keybuf->addr, size;
- int ret;
- mutex_lock(&kslt_lock);
- size = tegra_key_prep_ins_cmd(se, addr, keyval, keylen, slot, alg);
- ret = tegra_se_host1x_submit(se, se->keybuf, size);
- mutex_unlock(&kslt_lock);
- return ret;
- }
- void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)
- {
- u8 zkey[AES_MAX_KEY_SIZE] = {0};
- if (!keyid)
- return;
- /* Overwrite the key with 0s */
- tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
- tegra_keyslot_free(keyid);
- }
- void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg)
- {
- u8 zkey[AES_MAX_KEY_SIZE] = {0};
- if (!keyid)
- return;
- /* Overwrite the key with 0s */
- tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
- }
- inline int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key,
- u32 keylen, u32 alg, u32 *keyid)
- {
- return tegra_key_insert(se, key, keylen, *keyid, alg);
- }
- int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u32 *keyid)
- {
- int ret;
- /* Use the existing slot if it is already allocated */
- if (!tegra_key_in_kslt(*keyid)) {
- *keyid = tegra_keyslot_alloc();
- if (!(*keyid)) {
- dev_dbg(se->dev, "failed to allocate key slot\n");
- return -ENOMEM;
- }
- }
- ret = tegra_key_insert(se, key, keylen, *keyid, alg);
- if (ret)
- return ret;
- return 0;
- }
|