OSDN Git Service

544344ac4894cb5d24335940afd703fe2fcd0d9a
[tomoyo/tomoyo-test1.git] / drivers / net / ethernet / mellanox / mlxfw / mlxfw_mfa2.c
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 }