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 */ 20 static DEFINE_MUTEX(kslt_lock); 21 22 /* Keyslot bitmask (0 = available, 1 = in use/not available) */ 23 static u16 tegra_se_keyslots = SE_KEY_RSVD_MASK; 24 25 static 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 44 static 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 51 static 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 99 static 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 114 static 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 125 void 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 138 int 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