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