xref: /linux/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2024 Intel Corporation */
3 
4 #include <linux/slab.h>
5 #include <linux/types.h>
6 #include "adf_mstate_mgr.h"
7 
8 #define ADF_MSTATE_MAGIC	0xADF5CAEA
9 #define ADF_MSTATE_VERSION	0x1
10 
11 struct adf_mstate_sect_h {
12 	u8 id[ADF_MSTATE_ID_LEN];
13 	u32 size;
14 	u32 sub_sects;
15 	u8 state[];
16 };
17 
adf_mstate_state_size(struct adf_mstate_mgr * mgr)18 u32 adf_mstate_state_size(struct adf_mstate_mgr *mgr)
19 {
20 	return mgr->state - mgr->buf;
21 }
22 
adf_mstate_avail_room(struct adf_mstate_mgr * mgr)23 static inline u32 adf_mstate_avail_room(struct adf_mstate_mgr *mgr)
24 {
25 	return mgr->buf + mgr->size - mgr->state;
26 }
27 
adf_mstate_mgr_init(struct adf_mstate_mgr * mgr,u8 * buf,u32 size)28 void adf_mstate_mgr_init(struct adf_mstate_mgr *mgr, u8 *buf, u32 size)
29 {
30 	mgr->buf = buf;
31 	mgr->state = buf;
32 	mgr->size = size;
33 	mgr->n_sects = 0;
34 };
35 
adf_mstate_mgr_new(u8 * buf,u32 size)36 struct adf_mstate_mgr *adf_mstate_mgr_new(u8 *buf, u32 size)
37 {
38 	struct adf_mstate_mgr *mgr;
39 
40 	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
41 	if (!mgr)
42 		return NULL;
43 
44 	adf_mstate_mgr_init(mgr, buf, size);
45 
46 	return mgr;
47 }
48 
adf_mstate_mgr_destroy(struct adf_mstate_mgr * mgr)49 void adf_mstate_mgr_destroy(struct adf_mstate_mgr *mgr)
50 {
51 	kfree(mgr);
52 }
53 
adf_mstate_mgr_init_from_parent(struct adf_mstate_mgr * mgr,struct adf_mstate_mgr * p_mgr)54 void adf_mstate_mgr_init_from_parent(struct adf_mstate_mgr *mgr,
55 				     struct adf_mstate_mgr *p_mgr)
56 {
57 	adf_mstate_mgr_init(mgr, p_mgr->state,
58 			    p_mgr->size - adf_mstate_state_size(p_mgr));
59 }
60 
adf_mstate_mgr_init_from_psect(struct adf_mstate_mgr * mgr,struct adf_mstate_sect_h * p_sect)61 void adf_mstate_mgr_init_from_psect(struct adf_mstate_mgr *mgr,
62 				    struct adf_mstate_sect_h *p_sect)
63 {
64 	adf_mstate_mgr_init(mgr, p_sect->state, p_sect->size);
65 	mgr->n_sects = p_sect->sub_sects;
66 }
67 
adf_mstate_preamble_init(struct adf_mstate_preh * preamble)68 static void adf_mstate_preamble_init(struct adf_mstate_preh *preamble)
69 {
70 	preamble->magic = ADF_MSTATE_MAGIC;
71 	preamble->version = ADF_MSTATE_VERSION;
72 	preamble->preh_len = sizeof(*preamble);
73 	preamble->size = 0;
74 	preamble->n_sects = 0;
75 }
76 
77 /* default preambles checker */
adf_mstate_preamble_def_checker(struct adf_mstate_preh * preamble,void * opaque)78 static int adf_mstate_preamble_def_checker(struct adf_mstate_preh *preamble,
79 					   void *opaque)
80 {
81 	struct adf_mstate_mgr *mgr = opaque;
82 
83 	if (preamble->magic != ADF_MSTATE_MAGIC ||
84 	    preamble->version > ADF_MSTATE_VERSION ||
85 	    preamble->preh_len > mgr->size) {
86 		pr_debug("QAT: LM - Invalid state (magic=%#x, version=%#x, hlen=%u), state_size=%u\n",
87 			 preamble->magic, preamble->version, preamble->preh_len,
88 			 mgr->size);
89 		return -EINVAL;
90 	}
91 
92 	return 0;
93 }
94 
adf_mstate_preamble_add(struct adf_mstate_mgr * mgr)95 struct adf_mstate_preh *adf_mstate_preamble_add(struct adf_mstate_mgr *mgr)
96 {
97 	struct adf_mstate_preh *pre = (struct adf_mstate_preh *)mgr->buf;
98 
99 	if (adf_mstate_avail_room(mgr) < sizeof(*pre)) {
100 		pr_err("QAT: LM - Not enough space for preamble\n");
101 		return NULL;
102 	}
103 
104 	adf_mstate_preamble_init(pre);
105 	mgr->state += pre->preh_len;
106 
107 	return pre;
108 }
109 
adf_mstate_preamble_update(struct adf_mstate_mgr * mgr)110 int adf_mstate_preamble_update(struct adf_mstate_mgr *mgr)
111 {
112 	struct adf_mstate_preh *preamble = (struct adf_mstate_preh *)mgr->buf;
113 
114 	preamble->size = adf_mstate_state_size(mgr) - preamble->preh_len;
115 	preamble->n_sects = mgr->n_sects;
116 
117 	return 0;
118 }
119 
adf_mstate_dump_sect(struct adf_mstate_sect_h * sect,const char * prefix)120 static void adf_mstate_dump_sect(struct adf_mstate_sect_h *sect,
121 				 const char *prefix)
122 {
123 	pr_debug("QAT: LM - %s QAT state section %s\n", prefix, sect->id);
124 	print_hex_dump_debug("h-", DUMP_PREFIX_OFFSET, 16, 2, sect,
125 			     sizeof(*sect), true);
126 	print_hex_dump_debug("s-", DUMP_PREFIX_OFFSET, 16, 2, sect->state,
127 			     sect->size, true);
128 }
129 
__adf_mstate_sect_update(struct adf_mstate_mgr * mgr,struct adf_mstate_sect_h * sect,u32 size,u32 n_subsects)130 static inline void __adf_mstate_sect_update(struct adf_mstate_mgr *mgr,
131 					    struct adf_mstate_sect_h *sect,
132 					    u32 size,
133 					    u32 n_subsects)
134 {
135 	sect->size += size;
136 	sect->sub_sects += n_subsects;
137 	mgr->n_sects++;
138 	mgr->state += sect->size;
139 
140 	adf_mstate_dump_sect(sect, "Add");
141 }
142 
adf_mstate_sect_update(struct adf_mstate_mgr * p_mgr,struct adf_mstate_mgr * curr_mgr,struct adf_mstate_sect_h * sect)143 void adf_mstate_sect_update(struct adf_mstate_mgr *p_mgr,
144 			    struct adf_mstate_mgr *curr_mgr,
145 			    struct adf_mstate_sect_h *sect)
146 {
147 	__adf_mstate_sect_update(p_mgr, sect, adf_mstate_state_size(curr_mgr),
148 				 curr_mgr->n_sects);
149 }
150 
adf_mstate_sect_add_header(struct adf_mstate_mgr * mgr,const char * id)151 static struct adf_mstate_sect_h *adf_mstate_sect_add_header(struct adf_mstate_mgr *mgr,
152 							    const char *id)
153 {
154 	struct adf_mstate_sect_h *sect = (struct adf_mstate_sect_h *)(mgr->state);
155 
156 	if (adf_mstate_avail_room(mgr) < sizeof(*sect)) {
157 		pr_debug("QAT: LM - Not enough space for header of QAT state sect %s\n", id);
158 		return NULL;
159 	}
160 
161 	strscpy(sect->id, id, sizeof(sect->id));
162 	sect->size = 0;
163 	sect->sub_sects = 0;
164 	mgr->state += sizeof(*sect);
165 
166 	return sect;
167 }
168 
adf_mstate_sect_add_vreg(struct adf_mstate_mgr * mgr,const char * id,struct adf_mstate_vreginfo * info)169 struct adf_mstate_sect_h *adf_mstate_sect_add_vreg(struct adf_mstate_mgr *mgr,
170 						   const char *id,
171 						   struct adf_mstate_vreginfo *info)
172 {
173 	struct adf_mstate_sect_h *sect;
174 
175 	sect = adf_mstate_sect_add_header(mgr, id);
176 	if (!sect)
177 		return NULL;
178 
179 	if (adf_mstate_avail_room(mgr) < info->size) {
180 		pr_debug("QAT: LM - Not enough space for QAT state sect %s, requires %u\n",
181 			 id, info->size);
182 		return NULL;
183 	}
184 
185 	memcpy(sect->state, info->addr, info->size);
186 	__adf_mstate_sect_update(mgr, sect, info->size, 0);
187 
188 	return sect;
189 }
190 
adf_mstate_sect_add(struct adf_mstate_mgr * mgr,const char * id,adf_mstate_populate populate,void * opaque)191 struct adf_mstate_sect_h *adf_mstate_sect_add(struct adf_mstate_mgr *mgr,
192 					      const char *id,
193 					      adf_mstate_populate populate,
194 					      void *opaque)
195 {
196 	struct adf_mstate_mgr sub_sects_mgr;
197 	struct adf_mstate_sect_h *sect;
198 	int avail_room, size;
199 
200 	sect = adf_mstate_sect_add_header(mgr, id);
201 	if (!sect)
202 		return NULL;
203 
204 	if (!populate)
205 		return sect;
206 
207 	avail_room = adf_mstate_avail_room(mgr);
208 	adf_mstate_mgr_init_from_parent(&sub_sects_mgr, mgr);
209 
210 	size = (*populate)(&sub_sects_mgr, sect->state, avail_room, opaque);
211 	if (size < 0)
212 		return NULL;
213 
214 	size += adf_mstate_state_size(&sub_sects_mgr);
215 	if (avail_room < size) {
216 		pr_debug("QAT: LM - Not enough space for QAT state sect %s, requires %u\n",
217 			 id, size);
218 		return NULL;
219 	}
220 	__adf_mstate_sect_update(mgr, sect, size, sub_sects_mgr.n_sects);
221 
222 	return sect;
223 }
224 
adf_mstate_sect_validate(struct adf_mstate_mgr * mgr)225 static int adf_mstate_sect_validate(struct adf_mstate_mgr *mgr)
226 {
227 	struct adf_mstate_sect_h *start = (struct adf_mstate_sect_h *)mgr->state;
228 	struct adf_mstate_sect_h *sect = start;
229 	u64 end;
230 	int i;
231 
232 	end = (uintptr_t)mgr->buf + mgr->size;
233 	for (i = 0; i < mgr->n_sects; i++) {
234 		uintptr_t s_start = (uintptr_t)sect->state;
235 		uintptr_t s_end = s_start + sect->size;
236 
237 		if (s_end < s_start || s_end > end) {
238 			pr_debug("QAT: LM - Corrupted state section (index=%u, size=%u) in state_mgr (size=%u, secs=%u)\n",
239 				 i, sect->size, mgr->size, mgr->n_sects);
240 			return -EINVAL;
241 		}
242 		sect = (struct adf_mstate_sect_h *)s_end;
243 	}
244 
245 	pr_debug("QAT: LM - Scanned section (last child=%s, size=%lu) in state_mgr (size=%u, secs=%u)\n",
246 		 start->id, sizeof(struct adf_mstate_sect_h) * (ulong)(sect - start),
247 		 mgr->size, mgr->n_sects);
248 
249 	return 0;
250 }
251 
adf_mstate_state_size_from_remote(struct adf_mstate_mgr * mgr)252 u32 adf_mstate_state_size_from_remote(struct adf_mstate_mgr *mgr)
253 {
254 	struct adf_mstate_preh *preh = (struct adf_mstate_preh *)mgr->buf;
255 
256 	return preh->preh_len + preh->size;
257 }
258 
adf_mstate_mgr_init_from_remote(struct adf_mstate_mgr * mgr,u8 * buf,u32 size,adf_mstate_preamble_checker pre_checker,void * opaque)259 int adf_mstate_mgr_init_from_remote(struct adf_mstate_mgr *mgr, u8 *buf, u32 size,
260 				    adf_mstate_preamble_checker pre_checker,
261 				    void *opaque)
262 {
263 	struct adf_mstate_preh *pre;
264 	int ret;
265 
266 	adf_mstate_mgr_init(mgr, buf, size);
267 	pre = (struct adf_mstate_preh *)(mgr->buf);
268 
269 	pr_debug("QAT: LM - Dump state preambles\n");
270 	print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 2, pre, pre->preh_len, 0);
271 
272 	if (pre_checker)
273 		ret = (*pre_checker)(pre, opaque);
274 	else
275 		ret = adf_mstate_preamble_def_checker(pre, mgr);
276 	if (ret)
277 		return ret;
278 
279 	mgr->state = mgr->buf + pre->preh_len;
280 	mgr->n_sects = pre->n_sects;
281 
282 	return adf_mstate_sect_validate(mgr);
283 }
284 
adf_mstate_sect_lookup(struct adf_mstate_mgr * mgr,const char * id,adf_mstate_action action,void * opaque)285 struct adf_mstate_sect_h *adf_mstate_sect_lookup(struct adf_mstate_mgr *mgr,
286 						 const char *id,
287 						 adf_mstate_action action,
288 						 void *opaque)
289 {
290 	struct adf_mstate_sect_h *sect = (struct adf_mstate_sect_h *)mgr->state;
291 	struct adf_mstate_mgr sub_sects_mgr;
292 	int i, ret;
293 
294 	for (i = 0; i < mgr->n_sects; i++) {
295 		if (!strncmp(sect->id, id, sizeof(sect->id)))
296 			goto found;
297 
298 		sect = (struct adf_mstate_sect_h *)(sect->state + sect->size);
299 	}
300 
301 	return NULL;
302 
303 found:
304 	adf_mstate_dump_sect(sect, "Found");
305 
306 	adf_mstate_mgr_init_from_psect(&sub_sects_mgr, sect);
307 	if (sect->sub_sects && adf_mstate_sect_validate(&sub_sects_mgr))
308 		return NULL;
309 
310 	if (!action)
311 		return sect;
312 
313 	ret = (*action)(&sub_sects_mgr, sect->state, sect->size, opaque);
314 	if (ret)
315 		return NULL;
316 
317 	return sect;
318 }
319