1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2019 Mellanox Technologies. All rights reserved */
3 
4 #define pr_fmt(fmt) "mlxfw_mfa2: " fmt
5 
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/netlink.h>
9 #include <linux/xz.h>
10 #include "mlxfw_mfa2.h"
11 #include "mlxfw_mfa2_file.h"
12 #include "mlxfw_mfa2_tlv.h"
13 #include "mlxfw_mfa2_format.h"
14 #include "mlxfw_mfa2_tlv_multi.h"
15 
16 /*               MFA2 FILE
17  *  +----------------------------------+
18  *  |        MFA2 finger print         |
19  *  +----------------------------------+
20  *  |   package descriptor multi_tlv   |
21  *  | +------------------------------+ |     +-----------------+
22  *  | |    package descriptor tlv    +-----> |num_devices=n    |
23  *  | +------------------------------+ |     |num_components=m |
24  *  +----------------------------------+     |CB offset        |
25  *  |    device descriptor multi_tlv   |     |...              |
26  *  | +------------------------------+ |     |                 |
27  *  | |           PSID tlv           | |     +-----------------+
28  *  | +------------------------------+ |
29  *  | |     component index tlv      | |
30  *  | +------------------------------+ |
31  *  +----------------------------------+
32  *  |  component descriptor multi_tlv  |
33  *  | +------------------------------+ |     +-----------------+
34  *  | |  component descriptor tlv    +-----> |Among others:    |
35  *  | +------------------------------+ |     |CB offset=o      |
36  *  +----------------------------------+     |comp index=i     |
37  *  |                                  |     |...              |
38  *  |                                  |     |                 |
39  *  |                                  |     +-----------------+
40  *  |        COMPONENT BLOCK (CB)      |
41  *  |                                  |
42  *  |                                  |
43  *  |                                  |
44  *  +----------------------------------+
45  *
46  * On the top level, an MFA2 file contains:
47  *  - Fingerprint
48  *  - Several multi_tlvs (TLVs of type MLXFW_MFA2_TLV_MULTI, as defined in
49  *    mlxfw_mfa2_format.h)
50  *  - Compresses content block
51  *
52  * The first multi_tlv
53  * -------------------
54  * The first multi TLV is treated as package descriptor, and expected to have a
55  * first TLV child of type MLXFW_MFA2_TLV_PACKAGE_DESCRIPTOR which contains all
56  * the global information needed to parse the file. Among others, it contains
57  * the number of device descriptors and component descriptor following this
58  * multi TLV.
59  *
60  * The device descriptor multi_tlv
61  * -------------------------------
62  * The multi TLVs following the package descriptor are treated as device
63  * descriptor, and are expected to have the following children:
64  *  - PSID TLV child of type MLXFW_MFA2_TLV_PSID containing that device PSID.
65  *  - Component index of type MLXFW_MFA2_TLV_COMPONENT_PTR that contains that
66  *    device component index.
67  *
68  * The component descriptor multi_tlv
69  * ----------------------------------
70  * The multi TLVs following the device descriptor multi TLVs are treated as
71  * component descriptor, and are expected to have a first child of type
72  * MLXFW_MFA2_TLV_COMPONENT_DESCRIPTOR that contains mostly the component index,
73  * needed for the flash process and the offset to the binary within the
74  * component block.
75  */
76 
77 static const u8 mlxfw_mfa2_fingerprint[] = "MLNX.MFA2.XZ.00!";
78 static const int mlxfw_mfa2_fingerprint_len =
79 			sizeof(mlxfw_mfa2_fingerprint) - 1;
80 
81 static const u8 mlxfw_mfa2_comp_magic[] = "#BIN.COMPONENT!#";
82 static const int mlxfw_mfa2_comp_magic_len = sizeof(mlxfw_mfa2_comp_magic) - 1;
83 
84 bool mlxfw_mfa2_check(const struct firmware *fw)
85 {
86 	if (fw->size < sizeof(mlxfw_mfa2_fingerprint))
87 		return false;
88 
89 	return memcmp(fw->data, mlxfw_mfa2_fingerprint,
90 		      mlxfw_mfa2_fingerprint_len) == 0;
91 }
92 
93 static bool
94 mlxfw_mfa2_tlv_multi_validate(const struct mlxfw_mfa2_file *mfa2_file,
95 			      const struct mlxfw_mfa2_tlv_multi *multi)
96 {
97 	const struct mlxfw_mfa2_tlv *tlv;
98 	u16 idx;
99 
100 	/* Check that all children are valid */
101 	mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) {
102 		if (!tlv) {
103 			pr_err("Multi has invalid child");
104 			return false;
105 		}
106 	}
107 	return true;
108 }
109 
110 static bool
111 mlxfw_mfa2_file_dev_validate(const struct mlxfw_mfa2_file *mfa2_file,
112 			     const struct mlxfw_mfa2_tlv *dev_tlv,
113 			     u16 dev_idx)
114 {
115 	const struct mlxfw_mfa2_tlv_component_ptr *cptr;
116 	const struct mlxfw_mfa2_tlv_multi *multi;
117 	const struct mlxfw_mfa2_tlv_psid *psid;
118 	const struct mlxfw_mfa2_tlv *tlv;
119 	u16 cptr_count;
120 	u16 cptr_idx;
121 	int err;
122 
123 	pr_debug("Device %d\n", dev_idx);
124 
125 	multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
126 	if (!multi) {
127 		pr_err("Device %d is not a valid TLV error\n", dev_idx);
128 		return false;
129 	}
130 
131 	if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
132 		return false;
133 
134 	/* Validate the device has PSID tlv */
135 	tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
136 					      MLXFW_MFA2_TLV_PSID, 0);
137 	if (!tlv) {
138 		pr_err("Device %d does not have PSID\n", dev_idx);
139 		return false;
140 	}
141 
142 	psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
143 	if (!psid) {
144 		pr_err("Device %d PSID TLV is not valid\n", dev_idx);
145 		return false;
146 	}
147 
148 	print_hex_dump_debug("  -- Device PSID ", DUMP_PREFIX_NONE, 16, 16,
149 			     psid->psid, be16_to_cpu(tlv->len), true);
150 
151 	/* Validate the device has COMPONENT_PTR */
152 	err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, multi,
153 					       MLXFW_MFA2_TLV_COMPONENT_PTR,
154 					       &cptr_count);
155 	if (err)
156 		return false;
157 
158 	if (cptr_count == 0) {
159 		pr_err("Device %d has no components\n", dev_idx);
160 		return false;
161 	}
162 
163 	for (cptr_idx = 0; cptr_idx < cptr_count; cptr_idx++) {
164 		tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
165 						      MLXFW_MFA2_TLV_COMPONENT_PTR,
166 						      cptr_idx);
167 		if (!tlv)
168 			return false;
169 
170 		cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, tlv);
171 		if (!cptr) {
172 			pr_err("Device %d COMPONENT_PTR TLV is not valid\n",
173 			       dev_idx);
174 			return false;
175 		}
176 
177 		pr_debug("  -- Component index %d\n",
178 			 be16_to_cpu(cptr->component_index));
179 	}
180 	return true;
181 }
182 
183 static bool
184 mlxfw_mfa2_file_comp_validate(const struct mlxfw_mfa2_file *mfa2_file,
185 			      const struct mlxfw_mfa2_tlv *comp_tlv,
186 			      u16 comp_idx)
187 {
188 	const struct mlxfw_mfa2_tlv_component_descriptor *cdesc;
189 	const struct mlxfw_mfa2_tlv_multi *multi;
190 	const struct mlxfw_mfa2_tlv *tlv;
191 
192 	pr_debug("Component %d\n", comp_idx);
193 
194 	multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
195 	if (!multi) {
196 		pr_err("Component %d is not a valid TLV error\n", comp_idx);
197 		return false;
198 	}
199 
200 	if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
201 		return false;
202 
203 	/* Check that component have COMPONENT_DESCRIPTOR as first child */
204 	tlv = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
205 	if (!tlv) {
206 		pr_err("Component descriptor %d multi TLV error\n", comp_idx);
207 		return false;
208 	}
209 
210 	cdesc = mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, tlv);
211 	if (!cdesc) {
212 		pr_err("Component %d does not have a valid descriptor\n",
213 		       comp_idx);
214 		return false;
215 	}
216 	pr_debug("  -- Component type %d\n", be16_to_cpu(cdesc->identifier));
217 	pr_debug("  -- Offset 0x%llx and size %d\n",
218 		 ((u64) be32_to_cpu(cdesc->cb_offset_h) << 32)
219 		 | be32_to_cpu(cdesc->cb_offset_l), be32_to_cpu(cdesc->size));
220 
221 	return true;
222 }
223 
224 static bool mlxfw_mfa2_file_validate(const struct mlxfw_mfa2_file *mfa2_file)
225 {
226 	const struct mlxfw_mfa2_tlv *tlv;
227 	u16 idx;
228 
229 	pr_debug("Validating file\n");
230 
231 	/* check that all the devices exist */
232 	mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_dev,
233 			       mfa2_file->dev_count) {
234 		if (!tlv) {
235 			pr_err("Device TLV error\n");
236 			return false;
237 		}
238 
239 		/* Check each device */
240 		if (!mlxfw_mfa2_file_dev_validate(mfa2_file, tlv, idx))
241 			return false;
242 	}
243 
244 	/* check that all the components exist */
245 	mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_component,
246 			       mfa2_file->component_count) {
247 		if (!tlv) {
248 			pr_err("Device TLV error\n");
249 			return false;
250 		}
251 
252 		/* Check each component */
253 		if (!mlxfw_mfa2_file_comp_validate(mfa2_file, tlv, idx))
254 			return false;
255 	}
256 	return true;
257 }
258 
259 struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw)
260 {
261 	const struct mlxfw_mfa2_tlv_package_descriptor *pd;
262 	const struct mlxfw_mfa2_tlv_multi *multi;
263 	const struct mlxfw_mfa2_tlv *multi_child;
264 	const struct mlxfw_mfa2_tlv *first_tlv;
265 	struct mlxfw_mfa2_file *mfa2_file;
266 	const void *first_tlv_ptr;
267 	const void *cb_top_ptr;
268 
269 	mfa2_file = kcalloc(1, sizeof(*mfa2_file), GFP_KERNEL);
270 	if (!mfa2_file)
271 		return ERR_PTR(-ENOMEM);
272 
273 	mfa2_file->fw = fw;
274 	first_tlv_ptr = fw->data + NLA_ALIGN(mlxfw_mfa2_fingerprint_len);
275 	first_tlv = mlxfw_mfa2_tlv_get(mfa2_file, first_tlv_ptr);
276 	if (!first_tlv) {
277 		pr_err("Could not parse package descriptor TLV\n");
278 		goto err_out;
279 	}
280 
281 	multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, first_tlv);
282 	if (!multi) {
283 		pr_err("First TLV is not of valid multi type\n");
284 		goto err_out;
285 	}
286 
287 	multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
288 	if (!multi_child)
289 		goto err_out;
290 
291 	pd = mlxfw_mfa2_tlv_package_descriptor_get(mfa2_file, multi_child);
292 	if (!pd) {
293 		pr_err("Could not parse package descriptor TLV\n");
294 		goto err_out;
295 	}
296 
297 	mfa2_file->first_dev = mlxfw_mfa2_tlv_next(mfa2_file, first_tlv);
298 	if (!mfa2_file->first_dev) {
299 		pr_err("First device TLV is not valid\n");
300 		goto err_out;
301 	}
302 
303 	mfa2_file->dev_count = be16_to_cpu(pd->num_devices);
304 	mfa2_file->first_component = mlxfw_mfa2_tlv_advance(mfa2_file,
305 							    mfa2_file->first_dev,
306 							    mfa2_file->dev_count);
307 	mfa2_file->component_count = be16_to_cpu(pd->num_components);
308 	mfa2_file->cb = fw->data + NLA_ALIGN(be32_to_cpu(pd->cb_offset));
309 	if (!mlxfw_mfa2_valid_ptr(mfa2_file, mfa2_file->cb)) {
310 		pr_err("Component block is out side the file\n");
311 		goto err_out;
312 	}
313 	mfa2_file->cb_archive_size = be32_to_cpu(pd->cb_archive_size);
314 	cb_top_ptr = mfa2_file->cb + mfa2_file->cb_archive_size - 1;
315 	if (!mlxfw_mfa2_valid_ptr(mfa2_file, cb_top_ptr)) {
316 		pr_err("Component block size is too big\n");
317 		goto err_out;
318 	}
319 
320 	if (!mlxfw_mfa2_file_validate(mfa2_file))
321 		goto err_out;
322 	return mfa2_file;
323 err_out:
324 	kfree(mfa2_file);
325 	return ERR_PTR(-EINVAL);
326 }
327 
328 static const struct mlxfw_mfa2_tlv_multi *
329 mlxfw_mfa2_tlv_dev_get(const struct mlxfw_mfa2_file *mfa2_file,
330 		       const char *psid, u16 psid_size)
331 {
332 	const struct mlxfw_mfa2_tlv_psid *tlv_psid;
333 	const struct mlxfw_mfa2_tlv_multi *dev_multi;
334 	const struct mlxfw_mfa2_tlv *dev_tlv;
335 	const struct mlxfw_mfa2_tlv *tlv;
336 	u32 idx;
337 
338 	/* for each device tlv */
339 	mlxfw_mfa2_tlv_foreach(mfa2_file, dev_tlv, idx, mfa2_file->first_dev,
340 			       mfa2_file->dev_count) {
341 		if (!dev_tlv)
342 			return NULL;
343 
344 		dev_multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
345 		if (!dev_multi)
346 			return NULL;
347 
348 		/* find psid child and compare */
349 		tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
350 						      MLXFW_MFA2_TLV_PSID, 0);
351 		if (!tlv)
352 			return NULL;
353 		if (be16_to_cpu(tlv->len) != psid_size)
354 			continue;
355 
356 		tlv_psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
357 		if (!tlv_psid)
358 			return NULL;
359 
360 		if (memcmp(psid, tlv_psid->psid, psid_size) == 0)
361 			return dev_multi;
362 	}
363 
364 	return NULL;
365 }
366 
367 int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file,
368 				    const char *psid, u32 psid_size,
369 				    u32 *p_count)
370 {
371 	const struct mlxfw_mfa2_tlv_multi *dev_multi;
372 	u16 count;
373 	int err;
374 
375 	dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
376 	if (!dev_multi)
377 		return -EINVAL;
378 
379 	err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, dev_multi,
380 					       MLXFW_MFA2_TLV_COMPONENT_PTR,
381 					       &count);
382 	if (err)
383 		return err;
384 
385 	*p_count = count;
386 	return 0;
387 }
388 
389 static int mlxfw_mfa2_xz_dec_run(struct xz_dec *xz_dec, struct xz_buf *xz_buf,
390 				 bool *finished)
391 {
392 	enum xz_ret xz_ret;
393 
394 	xz_ret = xz_dec_run(xz_dec, xz_buf);
395 
396 	switch (xz_ret) {
397 	case XZ_STREAM_END:
398 		*finished = true;
399 		return 0;
400 	case XZ_OK:
401 		*finished = false;
402 		return 0;
403 	case XZ_MEM_ERROR:
404 		pr_err("xz no memory\n");
405 		return -ENOMEM;
406 	case XZ_DATA_ERROR:
407 		pr_err("xz file corrupted\n");
408 		return -EINVAL;
409 	case XZ_FORMAT_ERROR:
410 		pr_err("xz format not found\n");
411 		return -EINVAL;
412 	case XZ_OPTIONS_ERROR:
413 		pr_err("unsupported xz option\n");
414 		return -EINVAL;
415 	case XZ_MEMLIMIT_ERROR:
416 		pr_err("xz dictionary too small\n");
417 		return -EINVAL;
418 	default:
419 		pr_err("xz error %d\n", xz_ret);
420 		return -EINVAL;
421 	}
422 }
423 
424 static int mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file *mfa2_file,
425 					off_t off, size_t size, u8 *buf)
426 {
427 	struct xz_dec *xz_dec;
428 	struct xz_buf dec_buf;
429 	off_t curr_off = 0;
430 	bool finished;
431 	int err;
432 
433 	xz_dec = xz_dec_init(XZ_DYNALLOC, (u32) -1);
434 	if (!xz_dec)
435 		return -EINVAL;
436 
437 	dec_buf.in_size = mfa2_file->cb_archive_size;
438 	dec_buf.in = mfa2_file->cb;
439 	dec_buf.in_pos = 0;
440 	dec_buf.out = buf;
441 
442 	/* decode up to the offset */
443 	do {
444 		dec_buf.out_pos = 0;
445 		dec_buf.out_size = min_t(size_t, size, off - curr_off);
446 		if (dec_buf.out_size == 0)
447 			break;
448 
449 		err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
450 		if (err)
451 			goto out;
452 		if (finished) {
453 			pr_err("xz section too short\n");
454 			err = -EINVAL;
455 			goto out;
456 		}
457 		curr_off += dec_buf.out_pos;
458 	} while (curr_off != off);
459 
460 	/* decode the needed section */
461 	dec_buf.out_pos = 0;
462 	dec_buf.out_size = size;
463 	err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
464 out:
465 	xz_dec_end(xz_dec);
466 	return err;
467 }
468 
469 static const struct mlxfw_mfa2_tlv_component_descriptor *
470 mlxfw_mfa2_file_component_tlv_get(const struct mlxfw_mfa2_file *mfa2_file,
471 				  u16 comp_index)
472 {
473 	const struct mlxfw_mfa2_tlv_multi *multi;
474 	const struct mlxfw_mfa2_tlv *multi_child;
475 	const struct mlxfw_mfa2_tlv *comp_tlv;
476 
477 	if (comp_index > mfa2_file->component_count)
478 		return NULL;
479 
480 	comp_tlv = mlxfw_mfa2_tlv_advance(mfa2_file, mfa2_file->first_component,
481 					  comp_index);
482 	if (!comp_tlv)
483 		return NULL;
484 
485 	multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
486 	if (!multi)
487 		return NULL;
488 
489 	multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
490 	if (!multi_child)
491 		return NULL;
492 
493 	return mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, multi_child);
494 }
495 
496 struct mlxfw_mfa2_comp_data {
497 	struct mlxfw_mfa2_component comp;
498 	u8 buff[0];
499 };
500 
501 static const struct mlxfw_mfa2_tlv_component_descriptor *
502 mlxfw_mfa2_file_component_find(const struct mlxfw_mfa2_file *mfa2_file,
503 			       const char *psid, int psid_size,
504 			       int component_index)
505 {
506 	const struct mlxfw_mfa2_tlv_component_ptr *cptr;
507 	const struct mlxfw_mfa2_tlv_multi *dev_multi;
508 	const struct mlxfw_mfa2_tlv *cptr_tlv;
509 	u16 comp_idx;
510 
511 	dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
512 	if (!dev_multi)
513 		return NULL;
514 
515 	cptr_tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
516 						   MLXFW_MFA2_TLV_COMPONENT_PTR,
517 						   component_index);
518 	if (!cptr_tlv)
519 		return NULL;
520 
521 	cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, cptr_tlv);
522 	if (!cptr)
523 		return NULL;
524 
525 	comp_idx = be16_to_cpu(cptr->component_index);
526 	return mlxfw_mfa2_file_component_tlv_get(mfa2_file, comp_idx);
527 }
528 
529 struct mlxfw_mfa2_component *
530 mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file,
531 			      const char *psid, int psid_size,
532 			      int component_index)
533 {
534 	const struct mlxfw_mfa2_tlv_component_descriptor *comp;
535 	struct mlxfw_mfa2_comp_data *comp_data;
536 	u32 comp_buf_size;
537 	off_t cb_offset;
538 	u32 comp_size;
539 	int err;
540 
541 	comp = mlxfw_mfa2_file_component_find(mfa2_file, psid, psid_size,
542 					      component_index);
543 	if (!comp)
544 		return ERR_PTR(-EINVAL);
545 
546 	cb_offset = (u64) be32_to_cpu(comp->cb_offset_h) << 32 |
547 		    be32_to_cpu(comp->cb_offset_l);
548 	comp_size = be32_to_cpu(comp->size);
549 	comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len;
550 
551 	comp_data = kmalloc(sizeof(*comp_data) + comp_buf_size, GFP_KERNEL);
552 	if (!comp_data)
553 		return ERR_PTR(-ENOMEM);
554 	comp_data->comp.data_size = comp_size;
555 	comp_data->comp.index = be16_to_cpu(comp->identifier);
556 	err = mlxfw_mfa2_file_cb_offset_xz(mfa2_file, cb_offset, comp_buf_size,
557 					   comp_data->buff);
558 	if (err) {
559 		pr_err("Component could not be reached in CB\n");
560 		goto err_out;
561 	}
562 
563 	if (memcmp(comp_data->buff, mlxfw_mfa2_comp_magic,
564 		   mlxfw_mfa2_comp_magic_len) != 0) {
565 		pr_err("Component has wrong magic\n");
566 		err = -EINVAL;
567 		goto err_out;
568 	}
569 
570 	comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len;
571 	return &comp_data->comp;
572 err_out:
573 	kfree(comp_data);
574 	return ERR_PTR(err);
575 }
576 
577 void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *comp)
578 {
579 	const struct mlxfw_mfa2_comp_data *comp_data;
580 
581 	comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp);
582 	kfree(comp_data);
583 }
584 
585 void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
586 {
587 	kfree(mfa2_file);
588 }
589