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