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