Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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}