0001
0002
0003
0004 #define pr_fmt(fmt) "mlxfw_mfa2: " fmt
0005
0006 #include <linux/kernel.h>
0007 #include <linux/module.h>
0008 #include <linux/netlink.h>
0009 #include <linux/vmalloc.h>
0010 #include <linux/xz.h>
0011 #include "mlxfw_mfa2.h"
0012 #include "mlxfw_mfa2_file.h"
0013 #include "mlxfw_mfa2_tlv.h"
0014 #include "mlxfw_mfa2_format.h"
0015 #include "mlxfw_mfa2_tlv_multi.h"
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078 static const u8 mlxfw_mfa2_fingerprint[] = "MLNX.MFA2.XZ.00!";
0079 static const int mlxfw_mfa2_fingerprint_len =
0080 sizeof(mlxfw_mfa2_fingerprint) - 1;
0081
0082 static const u8 mlxfw_mfa2_comp_magic[] = "#BIN.COMPONENT!#";
0083 static const int mlxfw_mfa2_comp_magic_len = sizeof(mlxfw_mfa2_comp_magic) - 1;
0084
0085 bool mlxfw_mfa2_check(const struct firmware *fw)
0086 {
0087 if (fw->size < sizeof(mlxfw_mfa2_fingerprint))
0088 return false;
0089
0090 return memcmp(fw->data, mlxfw_mfa2_fingerprint,
0091 mlxfw_mfa2_fingerprint_len) == 0;
0092 }
0093
0094 static bool
0095 mlxfw_mfa2_tlv_multi_validate(const struct mlxfw_mfa2_file *mfa2_file,
0096 const struct mlxfw_mfa2_tlv_multi *multi)
0097 {
0098 const struct mlxfw_mfa2_tlv *tlv;
0099 u16 idx;
0100
0101
0102 mlxfw_mfa2_tlv_multi_foreach(mfa2_file, tlv, idx, multi) {
0103 if (!tlv) {
0104 pr_err("Multi has invalid child");
0105 return false;
0106 }
0107 }
0108 return true;
0109 }
0110
0111 static bool
0112 mlxfw_mfa2_file_dev_validate(const struct mlxfw_mfa2_file *mfa2_file,
0113 const struct mlxfw_mfa2_tlv *dev_tlv,
0114 u16 dev_idx)
0115 {
0116 const struct mlxfw_mfa2_tlv_component_ptr *cptr;
0117 const struct mlxfw_mfa2_tlv_multi *multi;
0118 const struct mlxfw_mfa2_tlv_psid *psid;
0119 const struct mlxfw_mfa2_tlv *tlv;
0120 u16 cptr_count;
0121 u16 cptr_idx;
0122 int err;
0123
0124 pr_debug("Device %d\n", dev_idx);
0125
0126 multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
0127 if (!multi) {
0128 pr_err("Device %d is not a valid TLV error\n", dev_idx);
0129 return false;
0130 }
0131
0132 if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
0133 return false;
0134
0135
0136 tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
0137 MLXFW_MFA2_TLV_PSID, 0);
0138 if (!tlv) {
0139 pr_err("Device %d does not have PSID\n", dev_idx);
0140 return false;
0141 }
0142
0143 psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
0144 if (!psid) {
0145 pr_err("Device %d PSID TLV is not valid\n", dev_idx);
0146 return false;
0147 }
0148
0149 print_hex_dump_debug(" -- Device PSID ", DUMP_PREFIX_NONE, 16, 16,
0150 psid->psid, be16_to_cpu(tlv->len), true);
0151
0152
0153 err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, multi,
0154 MLXFW_MFA2_TLV_COMPONENT_PTR,
0155 &cptr_count);
0156 if (err)
0157 return false;
0158
0159 if (cptr_count == 0) {
0160 pr_err("Device %d has no components\n", dev_idx);
0161 return false;
0162 }
0163
0164 for (cptr_idx = 0; cptr_idx < cptr_count; cptr_idx++) {
0165 tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, multi,
0166 MLXFW_MFA2_TLV_COMPONENT_PTR,
0167 cptr_idx);
0168 if (!tlv)
0169 return false;
0170
0171 cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, tlv);
0172 if (!cptr) {
0173 pr_err("Device %d COMPONENT_PTR TLV is not valid\n",
0174 dev_idx);
0175 return false;
0176 }
0177
0178 pr_debug(" -- Component index %d\n",
0179 be16_to_cpu(cptr->component_index));
0180 }
0181 return true;
0182 }
0183
0184 static bool
0185 mlxfw_mfa2_file_comp_validate(const struct mlxfw_mfa2_file *mfa2_file,
0186 const struct mlxfw_mfa2_tlv *comp_tlv,
0187 u16 comp_idx)
0188 {
0189 const struct mlxfw_mfa2_tlv_component_descriptor *cdesc;
0190 const struct mlxfw_mfa2_tlv_multi *multi;
0191 const struct mlxfw_mfa2_tlv *tlv;
0192
0193 pr_debug("Component %d\n", comp_idx);
0194
0195 multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
0196 if (!multi) {
0197 pr_err("Component %d is not a valid TLV error\n", comp_idx);
0198 return false;
0199 }
0200
0201 if (!mlxfw_mfa2_tlv_multi_validate(mfa2_file, multi))
0202 return false;
0203
0204
0205 tlv = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
0206 if (!tlv) {
0207 pr_err("Component descriptor %d multi TLV error\n", comp_idx);
0208 return false;
0209 }
0210
0211 cdesc = mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, tlv);
0212 if (!cdesc) {
0213 pr_err("Component %d does not have a valid descriptor\n",
0214 comp_idx);
0215 return false;
0216 }
0217 pr_debug(" -- Component type %d\n", be16_to_cpu(cdesc->identifier));
0218 pr_debug(" -- Offset 0x%llx and size %d\n",
0219 ((u64) be32_to_cpu(cdesc->cb_offset_h) << 32)
0220 | be32_to_cpu(cdesc->cb_offset_l), be32_to_cpu(cdesc->size));
0221
0222 return true;
0223 }
0224
0225 static bool mlxfw_mfa2_file_validate(const struct mlxfw_mfa2_file *mfa2_file)
0226 {
0227 const struct mlxfw_mfa2_tlv *tlv;
0228 u16 idx;
0229
0230 pr_debug("Validating file\n");
0231
0232
0233 mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_dev,
0234 mfa2_file->dev_count) {
0235 if (!tlv) {
0236 pr_err("Device TLV error\n");
0237 return false;
0238 }
0239
0240
0241 if (!mlxfw_mfa2_file_dev_validate(mfa2_file, tlv, idx))
0242 return false;
0243 }
0244
0245
0246 mlxfw_mfa2_tlv_foreach(mfa2_file, tlv, idx, mfa2_file->first_component,
0247 mfa2_file->component_count) {
0248 if (!tlv) {
0249 pr_err("Device TLV error\n");
0250 return false;
0251 }
0252
0253
0254 if (!mlxfw_mfa2_file_comp_validate(mfa2_file, tlv, idx))
0255 return false;
0256 }
0257 return true;
0258 }
0259
0260 struct mlxfw_mfa2_file *mlxfw_mfa2_file_init(const struct firmware *fw)
0261 {
0262 const struct mlxfw_mfa2_tlv_package_descriptor *pd;
0263 const struct mlxfw_mfa2_tlv_multi *multi;
0264 const struct mlxfw_mfa2_tlv *multi_child;
0265 const struct mlxfw_mfa2_tlv *first_tlv;
0266 struct mlxfw_mfa2_file *mfa2_file;
0267 const void *first_tlv_ptr;
0268 const void *cb_top_ptr;
0269
0270 mfa2_file = kzalloc(sizeof(*mfa2_file), GFP_KERNEL);
0271 if (!mfa2_file)
0272 return ERR_PTR(-ENOMEM);
0273
0274 mfa2_file->fw = fw;
0275 first_tlv_ptr = fw->data + NLA_ALIGN(mlxfw_mfa2_fingerprint_len);
0276 first_tlv = mlxfw_mfa2_tlv_get(mfa2_file, first_tlv_ptr);
0277 if (!first_tlv) {
0278 pr_err("Could not parse package descriptor TLV\n");
0279 goto err_out;
0280 }
0281
0282 multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, first_tlv);
0283 if (!multi) {
0284 pr_err("First TLV is not of valid multi type\n");
0285 goto err_out;
0286 }
0287
0288 multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
0289 if (!multi_child)
0290 goto err_out;
0291
0292 pd = mlxfw_mfa2_tlv_package_descriptor_get(mfa2_file, multi_child);
0293 if (!pd) {
0294 pr_err("Could not parse package descriptor TLV\n");
0295 goto err_out;
0296 }
0297
0298 mfa2_file->first_dev = mlxfw_mfa2_tlv_next(mfa2_file, first_tlv);
0299 if (!mfa2_file->first_dev) {
0300 pr_err("First device TLV is not valid\n");
0301 goto err_out;
0302 }
0303
0304 mfa2_file->dev_count = be16_to_cpu(pd->num_devices);
0305 mfa2_file->first_component = mlxfw_mfa2_tlv_advance(mfa2_file,
0306 mfa2_file->first_dev,
0307 mfa2_file->dev_count);
0308 mfa2_file->component_count = be16_to_cpu(pd->num_components);
0309 mfa2_file->cb = fw->data + NLA_ALIGN(be32_to_cpu(pd->cb_offset));
0310 if (!mlxfw_mfa2_valid_ptr(mfa2_file, mfa2_file->cb)) {
0311 pr_err("Component block is out side the file\n");
0312 goto err_out;
0313 }
0314 mfa2_file->cb_archive_size = be32_to_cpu(pd->cb_archive_size);
0315 cb_top_ptr = mfa2_file->cb + mfa2_file->cb_archive_size - 1;
0316 if (!mlxfw_mfa2_valid_ptr(mfa2_file, cb_top_ptr)) {
0317 pr_err("Component block size is too big\n");
0318 goto err_out;
0319 }
0320
0321 if (!mlxfw_mfa2_file_validate(mfa2_file))
0322 goto err_out;
0323 return mfa2_file;
0324 err_out:
0325 kfree(mfa2_file);
0326 return ERR_PTR(-EINVAL);
0327 }
0328
0329 static const struct mlxfw_mfa2_tlv_multi *
0330 mlxfw_mfa2_tlv_dev_get(const struct mlxfw_mfa2_file *mfa2_file,
0331 const char *psid, u16 psid_size)
0332 {
0333 const struct mlxfw_mfa2_tlv_psid *tlv_psid;
0334 const struct mlxfw_mfa2_tlv_multi *dev_multi;
0335 const struct mlxfw_mfa2_tlv *dev_tlv;
0336 const struct mlxfw_mfa2_tlv *tlv;
0337 u32 idx;
0338
0339
0340 mlxfw_mfa2_tlv_foreach(mfa2_file, dev_tlv, idx, mfa2_file->first_dev,
0341 mfa2_file->dev_count) {
0342 if (!dev_tlv)
0343 return NULL;
0344
0345 dev_multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, dev_tlv);
0346 if (!dev_multi)
0347 return NULL;
0348
0349
0350 tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
0351 MLXFW_MFA2_TLV_PSID, 0);
0352 if (!tlv)
0353 return NULL;
0354 if (be16_to_cpu(tlv->len) != psid_size)
0355 continue;
0356
0357 tlv_psid = mlxfw_mfa2_tlv_psid_get(mfa2_file, tlv);
0358 if (!tlv_psid)
0359 return NULL;
0360
0361 if (memcmp(psid, tlv_psid->psid, psid_size) == 0)
0362 return dev_multi;
0363 }
0364
0365 return NULL;
0366 }
0367
0368 int mlxfw_mfa2_file_component_count(const struct mlxfw_mfa2_file *mfa2_file,
0369 const char *psid, u32 psid_size,
0370 u32 *p_count)
0371 {
0372 const struct mlxfw_mfa2_tlv_multi *dev_multi;
0373 u16 count;
0374 int err;
0375
0376 dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
0377 if (!dev_multi)
0378 return -EINVAL;
0379
0380 err = mlxfw_mfa2_tlv_multi_child_count(mfa2_file, dev_multi,
0381 MLXFW_MFA2_TLV_COMPONENT_PTR,
0382 &count);
0383 if (err)
0384 return err;
0385
0386 *p_count = count;
0387 return 0;
0388 }
0389
0390 static int mlxfw_mfa2_xz_dec_run(struct xz_dec *xz_dec, struct xz_buf *xz_buf,
0391 bool *finished)
0392 {
0393 enum xz_ret xz_ret;
0394
0395 xz_ret = xz_dec_run(xz_dec, xz_buf);
0396
0397 switch (xz_ret) {
0398 case XZ_STREAM_END:
0399 *finished = true;
0400 return 0;
0401 case XZ_OK:
0402 *finished = false;
0403 return 0;
0404 case XZ_MEM_ERROR:
0405 pr_err("xz no memory\n");
0406 return -ENOMEM;
0407 case XZ_DATA_ERROR:
0408 pr_err("xz file corrupted\n");
0409 return -EINVAL;
0410 case XZ_FORMAT_ERROR:
0411 pr_err("xz format not found\n");
0412 return -EINVAL;
0413 case XZ_OPTIONS_ERROR:
0414 pr_err("unsupported xz option\n");
0415 return -EINVAL;
0416 case XZ_MEMLIMIT_ERROR:
0417 pr_err("xz dictionary too small\n");
0418 return -EINVAL;
0419 default:
0420 pr_err("xz error %d\n", xz_ret);
0421 return -EINVAL;
0422 }
0423 }
0424
0425 static int mlxfw_mfa2_file_cb_offset_xz(const struct mlxfw_mfa2_file *mfa2_file,
0426 off_t off, size_t size, u8 *buf)
0427 {
0428 struct xz_dec *xz_dec;
0429 struct xz_buf dec_buf;
0430 off_t curr_off = 0;
0431 bool finished;
0432 int err;
0433
0434 xz_dec = xz_dec_init(XZ_DYNALLOC, (u32) -1);
0435 if (!xz_dec)
0436 return -EINVAL;
0437
0438 dec_buf.in_size = mfa2_file->cb_archive_size;
0439 dec_buf.in = mfa2_file->cb;
0440 dec_buf.in_pos = 0;
0441 dec_buf.out = buf;
0442
0443
0444 do {
0445 dec_buf.out_pos = 0;
0446 dec_buf.out_size = min_t(size_t, size, off - curr_off);
0447 if (dec_buf.out_size == 0)
0448 break;
0449
0450 err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
0451 if (err)
0452 goto out;
0453 if (finished) {
0454 pr_err("xz section too short\n");
0455 err = -EINVAL;
0456 goto out;
0457 }
0458 curr_off += dec_buf.out_pos;
0459 } while (curr_off != off);
0460
0461
0462 dec_buf.out_pos = 0;
0463 dec_buf.out_size = size;
0464 err = mlxfw_mfa2_xz_dec_run(xz_dec, &dec_buf, &finished);
0465 out:
0466 xz_dec_end(xz_dec);
0467 return err;
0468 }
0469
0470 static const struct mlxfw_mfa2_tlv_component_descriptor *
0471 mlxfw_mfa2_file_component_tlv_get(const struct mlxfw_mfa2_file *mfa2_file,
0472 u16 comp_index)
0473 {
0474 const struct mlxfw_mfa2_tlv_multi *multi;
0475 const struct mlxfw_mfa2_tlv *multi_child;
0476 const struct mlxfw_mfa2_tlv *comp_tlv;
0477
0478 if (comp_index > mfa2_file->component_count)
0479 return NULL;
0480
0481 comp_tlv = mlxfw_mfa2_tlv_advance(mfa2_file, mfa2_file->first_component,
0482 comp_index);
0483 if (!comp_tlv)
0484 return NULL;
0485
0486 multi = mlxfw_mfa2_tlv_multi_get(mfa2_file, comp_tlv);
0487 if (!multi)
0488 return NULL;
0489
0490 multi_child = mlxfw_mfa2_tlv_multi_child(mfa2_file, multi);
0491 if (!multi_child)
0492 return NULL;
0493
0494 return mlxfw_mfa2_tlv_component_descriptor_get(mfa2_file, multi_child);
0495 }
0496
0497 struct mlxfw_mfa2_comp_data {
0498 struct mlxfw_mfa2_component comp;
0499 u8 buff[];
0500 };
0501
0502 static const struct mlxfw_mfa2_tlv_component_descriptor *
0503 mlxfw_mfa2_file_component_find(const struct mlxfw_mfa2_file *mfa2_file,
0504 const char *psid, int psid_size,
0505 int component_index)
0506 {
0507 const struct mlxfw_mfa2_tlv_component_ptr *cptr;
0508 const struct mlxfw_mfa2_tlv_multi *dev_multi;
0509 const struct mlxfw_mfa2_tlv *cptr_tlv;
0510 u16 comp_idx;
0511
0512 dev_multi = mlxfw_mfa2_tlv_dev_get(mfa2_file, psid, psid_size);
0513 if (!dev_multi)
0514 return NULL;
0515
0516 cptr_tlv = mlxfw_mfa2_tlv_multi_child_find(mfa2_file, dev_multi,
0517 MLXFW_MFA2_TLV_COMPONENT_PTR,
0518 component_index);
0519 if (!cptr_tlv)
0520 return NULL;
0521
0522 cptr = mlxfw_mfa2_tlv_component_ptr_get(mfa2_file, cptr_tlv);
0523 if (!cptr)
0524 return NULL;
0525
0526 comp_idx = be16_to_cpu(cptr->component_index);
0527 return mlxfw_mfa2_file_component_tlv_get(mfa2_file, comp_idx);
0528 }
0529
0530 struct mlxfw_mfa2_component *
0531 mlxfw_mfa2_file_component_get(const struct mlxfw_mfa2_file *mfa2_file,
0532 const char *psid, int psid_size,
0533 int component_index)
0534 {
0535 const struct mlxfw_mfa2_tlv_component_descriptor *comp;
0536 struct mlxfw_mfa2_comp_data *comp_data;
0537 u32 comp_buf_size;
0538 off_t cb_offset;
0539 u32 comp_size;
0540 int err;
0541
0542 comp = mlxfw_mfa2_file_component_find(mfa2_file, psid, psid_size,
0543 component_index);
0544 if (!comp)
0545 return ERR_PTR(-EINVAL);
0546
0547 cb_offset = (u64) be32_to_cpu(comp->cb_offset_h) << 32 |
0548 be32_to_cpu(comp->cb_offset_l);
0549 comp_size = be32_to_cpu(comp->size);
0550 comp_buf_size = comp_size + mlxfw_mfa2_comp_magic_len;
0551
0552 comp_data = vzalloc(sizeof(*comp_data) + comp_buf_size);
0553 if (!comp_data)
0554 return ERR_PTR(-ENOMEM);
0555 comp_data->comp.data_size = comp_size;
0556 comp_data->comp.index = be16_to_cpu(comp->identifier);
0557 err = mlxfw_mfa2_file_cb_offset_xz(mfa2_file, cb_offset, comp_buf_size,
0558 comp_data->buff);
0559 if (err) {
0560 pr_err("Component could not be reached in CB\n");
0561 goto err_out;
0562 }
0563
0564 if (memcmp(comp_data->buff, mlxfw_mfa2_comp_magic,
0565 mlxfw_mfa2_comp_magic_len) != 0) {
0566 pr_err("Component has wrong magic\n");
0567 err = -EINVAL;
0568 goto err_out;
0569 }
0570
0571 comp_data->comp.data = comp_data->buff + mlxfw_mfa2_comp_magic_len;
0572 return &comp_data->comp;
0573 err_out:
0574 vfree(comp_data);
0575 return ERR_PTR(err);
0576 }
0577
0578 void mlxfw_mfa2_file_component_put(struct mlxfw_mfa2_component *comp)
0579 {
0580 const struct mlxfw_mfa2_comp_data *comp_data;
0581
0582 comp_data = container_of(comp, struct mlxfw_mfa2_comp_data, comp);
0583 vfree(comp_data);
0584 }
0585
0586 void mlxfw_mfa2_file_fini(struct mlxfw_mfa2_file *mfa2_file)
0587 {
0588 kfree(mfa2_file);
0589 }