1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2021 Xilinx, Inc. 4 * Copyright(c) 2017-2019 Solarflare Communications Inc. 5 */ 6 7 #include "efx.h" 8 #include "efx_impl.h" 9 10 #include "ef10_firmware_ids.h" 11 12 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 13 14 #if EFSYS_OPT_IMAGE_LAYOUT 15 16 /* 17 * Utility routines to support limited parsing of ASN.1 tags. This is not a 18 * general purpose ASN.1 parser, but is sufficient to locate the required 19 * objects in a signed image with CMS headers. 20 */ 21 22 /* DER encodings for ASN.1 tags (see ITU-T X.690) */ 23 #define ASN1_TAG_INTEGER (0x02) 24 #define ASN1_TAG_OCTET_STRING (0x04) 25 #define ASN1_TAG_OBJ_ID (0x06) 26 #define ASN1_TAG_SEQUENCE (0x30) 27 #define ASN1_TAG_SET (0x31) 28 29 #define ASN1_TAG_IS_PRIM(tag) ((tag & 0x20) == 0) 30 31 #define ASN1_TAG_PRIM_CONTEXT(n) (0x80 + (n)) 32 #define ASN1_TAG_CONS_CONTEXT(n) (0xA0 + (n)) 33 34 typedef struct efx_asn1_cursor_s { 35 uint8_t *buffer; 36 uint32_t length; 37 38 uint8_t tag; 39 uint32_t hdr_size; 40 uint32_t val_size; 41 } efx_asn1_cursor_t; 42 43 44 /* Parse header of DER encoded ASN.1 TLV and match tag */ 45 static __checkReturn efx_rc_t 46 efx_asn1_parse_header_match_tag( 47 __inout efx_asn1_cursor_t *cursor, 48 __in uint8_t tag) 49 { 50 efx_rc_t rc; 51 52 if (cursor == NULL || cursor->buffer == NULL || cursor->length < 2) { 53 rc = EINVAL; 54 goto fail1; 55 } 56 57 cursor->tag = cursor->buffer[0]; 58 if (cursor->tag != tag) { 59 /* Tag not matched */ 60 rc = ENOENT; 61 goto fail2; 62 } 63 64 if ((cursor->tag & 0x1F) == 0x1F) { 65 /* Long tag format not used in CMS syntax */ 66 rc = EINVAL; 67 goto fail3; 68 } 69 70 if ((cursor->buffer[1] & 0x80) == 0) { 71 /* Short form: length is 0..127 */ 72 cursor->hdr_size = 2; 73 cursor->val_size = cursor->buffer[1]; 74 } else { 75 /* Long form: length encoded as [0x80+nbytes][length bytes] */ 76 uint32_t nbytes = cursor->buffer[1] & 0x7F; 77 uint32_t offset; 78 79 if (nbytes == 0) { 80 /* Indefinite length not allowed in DER encoding */ 81 rc = EINVAL; 82 goto fail4; 83 } 84 if (2 + nbytes > cursor->length) { 85 /* Header length overflows image buffer */ 86 rc = EINVAL; 87 goto fail6; 88 } 89 if (nbytes > sizeof (uint32_t)) { 90 /* Length encoding too big */ 91 rc = E2BIG; 92 goto fail5; 93 } 94 cursor->hdr_size = 2 + nbytes; 95 cursor->val_size = 0; 96 for (offset = 2; offset < cursor->hdr_size; offset++) { 97 cursor->val_size = 98 (cursor->val_size << 8) | cursor->buffer[offset]; 99 } 100 } 101 102 if ((cursor->hdr_size + cursor->val_size) > cursor->length) { 103 /* Length overflows image buffer */ 104 rc = E2BIG; 105 goto fail7; 106 } 107 108 return (0); 109 110 fail7: 111 EFSYS_PROBE(fail7); 112 fail6: 113 EFSYS_PROBE(fail6); 114 fail5: 115 EFSYS_PROBE(fail5); 116 fail4: 117 EFSYS_PROBE(fail4); 118 fail3: 119 EFSYS_PROBE(fail3); 120 fail2: 121 EFSYS_PROBE(fail2); 122 fail1: 123 EFSYS_PROBE1(fail1, efx_rc_t, rc); 124 125 return (rc); 126 } 127 128 /* Enter nested ASN.1 TLV (contained in value of current TLV) */ 129 static __checkReturn efx_rc_t 130 efx_asn1_enter_tag( 131 __inout efx_asn1_cursor_t *cursor, 132 __in uint8_t tag) 133 { 134 efx_rc_t rc; 135 136 if (cursor == NULL) { 137 rc = EINVAL; 138 goto fail1; 139 } 140 141 if (ASN1_TAG_IS_PRIM(tag)) { 142 /* Cannot enter a primitive tag */ 143 rc = ENOTSUP; 144 goto fail2; 145 } 146 rc = efx_asn1_parse_header_match_tag(cursor, tag); 147 if (rc != 0) { 148 /* Invalid TLV or wrong tag */ 149 goto fail3; 150 } 151 152 /* Limit cursor range to nested TLV */ 153 cursor->buffer += cursor->hdr_size; 154 cursor->length = cursor->val_size; 155 156 return (0); 157 158 fail3: 159 EFSYS_PROBE(fail3); 160 fail2: 161 EFSYS_PROBE(fail2); 162 fail1: 163 EFSYS_PROBE1(fail1, efx_rc_t, rc); 164 165 return (rc); 166 } 167 168 /* 169 * Check that the current ASN.1 TLV matches the given tag and value. 170 * Advance cursor to next TLV on a successful match. 171 */ 172 static __checkReturn efx_rc_t 173 efx_asn1_match_tag_value( 174 __inout efx_asn1_cursor_t *cursor, 175 __in uint8_t tag, 176 __in const void *valp, 177 __in uint32_t val_size) 178 { 179 efx_rc_t rc; 180 181 if (cursor == NULL) { 182 rc = EINVAL; 183 goto fail1; 184 } 185 rc = efx_asn1_parse_header_match_tag(cursor, tag); 186 if (rc != 0) { 187 /* Invalid TLV or wrong tag */ 188 goto fail2; 189 } 190 if (cursor->val_size != val_size) { 191 /* Value size is different */ 192 rc = EINVAL; 193 goto fail3; 194 } 195 if (memcmp(cursor->buffer + cursor->hdr_size, valp, val_size) != 0) { 196 /* Value content is different */ 197 rc = EINVAL; 198 goto fail4; 199 } 200 cursor->buffer += cursor->hdr_size + cursor->val_size; 201 cursor->length -= cursor->hdr_size + cursor->val_size; 202 203 return (0); 204 205 fail4: 206 EFSYS_PROBE(fail4); 207 fail3: 208 EFSYS_PROBE(fail3); 209 fail2: 210 EFSYS_PROBE(fail2); 211 fail1: 212 EFSYS_PROBE1(fail1, efx_rc_t, rc); 213 214 return (rc); 215 } 216 217 /* Advance cursor to next TLV */ 218 static __checkReturn efx_rc_t 219 efx_asn1_skip_tag( 220 __inout efx_asn1_cursor_t *cursor, 221 __in uint8_t tag) 222 { 223 efx_rc_t rc; 224 225 if (cursor == NULL) { 226 rc = EINVAL; 227 goto fail1; 228 } 229 230 rc = efx_asn1_parse_header_match_tag(cursor, tag); 231 if (rc != 0) { 232 /* Invalid TLV or wrong tag */ 233 goto fail2; 234 } 235 cursor->buffer += cursor->hdr_size + cursor->val_size; 236 cursor->length -= cursor->hdr_size + cursor->val_size; 237 238 return (0); 239 240 fail2: 241 EFSYS_PROBE(fail2); 242 fail1: 243 EFSYS_PROBE1(fail1, efx_rc_t, rc); 244 245 return (rc); 246 } 247 248 /* Return pointer to value octets and value size from current TLV */ 249 static __checkReturn efx_rc_t 250 efx_asn1_get_tag_value( 251 __inout efx_asn1_cursor_t *cursor, 252 __in uint8_t tag, 253 __out uint8_t **valp, 254 __out uint32_t *val_sizep) 255 { 256 efx_rc_t rc; 257 258 if (cursor == NULL || valp == NULL || val_sizep == NULL) { 259 rc = EINVAL; 260 goto fail1; 261 } 262 263 rc = efx_asn1_parse_header_match_tag(cursor, tag); 264 if (rc != 0) { 265 /* Invalid TLV or wrong tag */ 266 goto fail2; 267 } 268 *valp = cursor->buffer + cursor->hdr_size; 269 *val_sizep = cursor->val_size; 270 271 return (0); 272 273 fail2: 274 EFSYS_PROBE(fail2); 275 fail1: 276 EFSYS_PROBE1(fail1, efx_rc_t, rc); 277 278 return (rc); 279 } 280 281 282 /* 283 * Utility routines for parsing CMS headers (see RFC2315, PKCS#7) 284 */ 285 286 /* OID 1.2.840.113549.1.7.2 */ 287 static const uint8_t PKCS7_SignedData[] = 288 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 }; 289 290 /* OID 1.2.840.113549.1.7.1 */ 291 static const uint8_t PKCS7_Data[] = 292 { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 }; 293 294 /* SignedData structure version */ 295 static const uint8_t SignedData_Version[] = 296 { 0x03 }; 297 298 /* 299 * Check for a valid image in signed image format. This uses CMS syntax 300 * (see RFC2315, PKCS#7) to provide signatures, and certificates required 301 * to validate the signatures. The encapsulated content is in unsigned image 302 * format (reflash header, image code, trailer checksum). 303 */ 304 static __checkReturn efx_rc_t 305 efx_check_signed_image_header( 306 __in void *bufferp, 307 __in uint32_t buffer_size, 308 __out uint32_t *content_offsetp, 309 __out uint32_t *content_lengthp) 310 { 311 efx_asn1_cursor_t cursor; 312 uint8_t *valp; 313 uint32_t val_size; 314 efx_rc_t rc; 315 316 if (content_offsetp == NULL || content_lengthp == NULL) { 317 rc = EINVAL; 318 goto fail1; 319 } 320 cursor.buffer = (uint8_t *)bufferp; 321 cursor.length = buffer_size; 322 323 /* ContextInfo */ 324 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE); 325 if (rc != 0) 326 goto fail2; 327 328 /* ContextInfo.contentType */ 329 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID, 330 PKCS7_SignedData, sizeof (PKCS7_SignedData)); 331 if (rc != 0) 332 goto fail3; 333 334 /* ContextInfo.content */ 335 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0)); 336 if (rc != 0) 337 goto fail4; 338 339 /* SignedData */ 340 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE); 341 if (rc != 0) 342 goto fail5; 343 344 /* SignedData.version */ 345 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_INTEGER, 346 SignedData_Version, sizeof (SignedData_Version)); 347 if (rc != 0) 348 goto fail6; 349 350 /* SignedData.digestAlgorithms */ 351 rc = efx_asn1_skip_tag(&cursor, ASN1_TAG_SET); 352 if (rc != 0) 353 goto fail7; 354 355 /* SignedData.encapContentInfo */ 356 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE); 357 if (rc != 0) 358 goto fail8; 359 360 /* SignedData.encapContentInfo.econtentType */ 361 rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID, 362 PKCS7_Data, sizeof (PKCS7_Data)); 363 if (rc != 0) 364 goto fail9; 365 366 /* SignedData.encapContentInfo.econtent */ 367 rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0)); 368 if (rc != 0) 369 goto fail10; 370 371 /* 372 * The octet string contains the image header, image code bytes and 373 * image trailer CRC (same as unsigned image layout). 374 */ 375 valp = NULL; 376 val_size = 0; 377 rc = efx_asn1_get_tag_value(&cursor, ASN1_TAG_OCTET_STRING, 378 &valp, &val_size); 379 if (rc != 0) 380 goto fail11; 381 382 if ((valp == NULL) || (val_size == 0)) { 383 rc = EINVAL; 384 goto fail12; 385 } 386 if (valp < (uint8_t *)bufferp) { 387 rc = EINVAL; 388 goto fail13; 389 } 390 if ((valp + val_size) > ((uint8_t *)bufferp + buffer_size)) { 391 rc = EINVAL; 392 goto fail14; 393 } 394 395 *content_offsetp = (uint32_t)(valp - (uint8_t *)bufferp); 396 *content_lengthp = val_size; 397 398 return (0); 399 400 fail14: 401 EFSYS_PROBE(fail14); 402 fail13: 403 EFSYS_PROBE(fail13); 404 fail12: 405 EFSYS_PROBE(fail12); 406 fail11: 407 EFSYS_PROBE(fail11); 408 fail10: 409 EFSYS_PROBE(fail10); 410 fail9: 411 EFSYS_PROBE(fail9); 412 fail8: 413 EFSYS_PROBE(fail8); 414 fail7: 415 EFSYS_PROBE(fail7); 416 fail6: 417 EFSYS_PROBE(fail6); 418 fail5: 419 EFSYS_PROBE(fail5); 420 fail4: 421 EFSYS_PROBE(fail4); 422 fail3: 423 EFSYS_PROBE(fail3); 424 fail2: 425 EFSYS_PROBE(fail2); 426 fail1: 427 EFSYS_PROBE1(fail1, efx_rc_t, rc); 428 429 return (rc); 430 } 431 432 static __checkReturn efx_rc_t 433 efx_check_unsigned_image( 434 __in void *bufferp, 435 __in uint32_t buffer_size, 436 __out efx_image_header_t **headerpp, 437 __out efx_image_trailer_t **trailerpp) 438 { 439 efx_image_header_t *headerp; 440 efx_image_trailer_t *trailerp; 441 uint32_t crc; 442 efx_rc_t rc; 443 444 EFX_STATIC_ASSERT(sizeof (*headerp) == EFX_IMAGE_HEADER_SIZE); 445 EFX_STATIC_ASSERT(sizeof (*trailerp) == EFX_IMAGE_TRAILER_SIZE); 446 447 /* Must have at least enough space for required image header fields */ 448 if (buffer_size < (EFX_FIELD_OFFSET(efx_image_header_t, eih_size) + 449 sizeof (headerp->eih_size))) { 450 rc = ENOSPC; 451 goto fail1; 452 } 453 headerp = (efx_image_header_t *)bufferp; 454 455 /* Buffer must have space for image header, code and image trailer. */ 456 if (buffer_size < (headerp->eih_size + headerp->eih_code_size + 457 EFX_IMAGE_TRAILER_SIZE)) { 458 rc = ENOSPC; 459 goto fail2; 460 } 461 462 trailerp = (efx_image_trailer_t *)((uint8_t *)headerp + 463 headerp->eih_size + headerp->eih_code_size); 464 465 *headerpp = headerp; 466 *trailerpp = trailerp; 467 468 if (headerp->eih_magic != EFX_IMAGE_HEADER_MAGIC) { 469 rc = EINVAL; 470 goto fail3; 471 } 472 473 /* 474 * Check image header version is same or higher than lowest required 475 * version. 476 */ 477 if (headerp->eih_version < EFX_IMAGE_HEADER_VERSION) { 478 rc = EINVAL; 479 goto fail4; 480 } 481 482 /* Check CRC from image buffer matches computed CRC. */ 483 crc = efx_crc32_calculate(0, (uint8_t *)headerp, 484 (headerp->eih_size + headerp->eih_code_size)); 485 486 if (trailerp->eit_crc != crc) { 487 rc = EINVAL; 488 goto fail5; 489 } 490 491 return (0); 492 493 fail5: 494 EFSYS_PROBE(fail5); 495 fail4: 496 EFSYS_PROBE(fail4); 497 fail3: 498 EFSYS_PROBE(fail3); 499 fail2: 500 EFSYS_PROBE(fail2); 501 fail1: 502 EFSYS_PROBE1(fail1, efx_rc_t, rc); 503 504 return (rc); 505 } 506 507 __checkReturn efx_rc_t 508 efx_check_reflash_image( 509 __in void *bufferp, 510 __in uint32_t buffer_size, 511 __out efx_image_info_t *infop) 512 { 513 efx_image_format_t format = EFX_IMAGE_FORMAT_NO_IMAGE; 514 uint32_t image_offset; 515 uint32_t image_size; 516 void *imagep; 517 efx_image_header_t *headerp; 518 efx_image_trailer_t *trailerp; 519 efx_rc_t rc; 520 521 EFSYS_ASSERT(infop != NULL); 522 if (infop == NULL) { 523 rc = EINVAL; 524 goto fail1; 525 } 526 memset(infop, 0, sizeof (*infop)); 527 528 if (bufferp == NULL || buffer_size == 0) { 529 rc = EINVAL; 530 goto fail2; 531 } 532 533 /* 534 * Check if the buffer contains an image in signed format, and if so, 535 * locate the image header. 536 */ 537 rc = efx_check_signed_image_header(bufferp, buffer_size, 538 &image_offset, &image_size); 539 if (rc == 0) { 540 /* 541 * Buffer holds signed image format. Check that the encapsulated 542 * content contains an unsigned image format header. 543 */ 544 format = EFX_IMAGE_FORMAT_SIGNED; 545 } else { 546 /* Check if the buffer holds image in unsigned image format */ 547 format = EFX_IMAGE_FORMAT_UNSIGNED; 548 image_offset = 0; 549 image_size = buffer_size; 550 } 551 if (image_offset + image_size > buffer_size) { 552 rc = E2BIG; 553 goto fail3; 554 } 555 imagep = (uint8_t *)bufferp + image_offset; 556 557 /* Check image layout (image header, code, image trailer) */ 558 rc = efx_check_unsigned_image(imagep, image_size, &headerp, &trailerp); 559 if (rc != 0) 560 goto fail4; 561 562 /* 563 * Signed images are packages consumed directly by the firmware, 564 * with the exception of MC firmware, where the image must be 565 * rearranged for booting purposes. 566 */ 567 if (format == EFX_IMAGE_FORMAT_SIGNED) { 568 if (headerp->eih_type != FIRMWARE_TYPE_MCFW) 569 format = EFX_IMAGE_FORMAT_SIGNED_PACKAGE; 570 } 571 572 /* Return image details */ 573 infop->eii_format = format; 574 infop->eii_imagep = bufferp; 575 infop->eii_image_size = buffer_size; 576 infop->eii_headerp = (efx_image_header_t *)imagep; 577 578 return (0); 579 580 fail4: 581 EFSYS_PROBE(fail4); 582 fail3: 583 EFSYS_PROBE(fail3); 584 fail2: 585 EFSYS_PROBE(fail2); 586 infop->eii_format = EFX_IMAGE_FORMAT_INVALID; 587 infop->eii_imagep = NULL; 588 infop->eii_image_size = 0; 589 590 fail1: 591 EFSYS_PROBE1(fail1, efx_rc_t, rc); 592 593 return (rc); 594 } 595 596 __checkReturn efx_rc_t 597 efx_build_signed_image_write_buffer( 598 __out_bcount(buffer_size) 599 uint8_t *bufferp, 600 __in uint32_t buffer_size, 601 __in efx_image_info_t *infop, 602 __out efx_image_header_t **headerpp) 603 { 604 signed_image_chunk_hdr_t chunk_hdr; 605 uint32_t hdr_offset; 606 struct { 607 uint32_t offset; 608 uint32_t size; 609 } cms_header, image_header, code, image_trailer, signature; 610 efx_rc_t rc; 611 612 EFSYS_ASSERT((infop != NULL) && (headerpp != NULL)); 613 614 if ((bufferp == NULL) || (buffer_size == 0) || 615 (infop == NULL) || (headerpp == NULL)) { 616 /* Invalid arguments */ 617 rc = EINVAL; 618 goto fail1; 619 } 620 if ((infop->eii_format != EFX_IMAGE_FORMAT_SIGNED) || 621 (infop->eii_imagep == NULL) || 622 (infop->eii_headerp == NULL) || 623 ((uint8_t *)infop->eii_headerp < (uint8_t *)infop->eii_imagep) || 624 (infop->eii_image_size < EFX_IMAGE_HEADER_SIZE) || 625 ((size_t)((uint8_t *)infop->eii_headerp - infop->eii_imagep) > 626 (infop->eii_image_size - EFX_IMAGE_HEADER_SIZE))) { 627 /* Invalid image info */ 628 rc = EINVAL; 629 goto fail2; 630 } 631 632 /* Locate image chunks in original signed image */ 633 cms_header.offset = 0; 634 cms_header.size = 635 (uint32_t)((uint8_t *)infop->eii_headerp - infop->eii_imagep); 636 if ((cms_header.size > buffer_size) || 637 (cms_header.offset > (buffer_size - cms_header.size))) { 638 rc = EINVAL; 639 goto fail3; 640 } 641 642 image_header.offset = cms_header.offset + cms_header.size; 643 image_header.size = infop->eii_headerp->eih_size; 644 if ((image_header.size > buffer_size) || 645 (image_header.offset > (buffer_size - image_header.size))) { 646 rc = EINVAL; 647 goto fail4; 648 } 649 650 code.offset = image_header.offset + image_header.size; 651 code.size = infop->eii_headerp->eih_code_size; 652 if ((code.size > buffer_size) || 653 (code.offset > (buffer_size - code.size))) { 654 rc = EINVAL; 655 goto fail5; 656 } 657 658 image_trailer.offset = code.offset + code.size; 659 image_trailer.size = EFX_IMAGE_TRAILER_SIZE; 660 if ((image_trailer.size > buffer_size) || 661 (image_trailer.offset > (buffer_size - image_trailer.size))) { 662 rc = EINVAL; 663 goto fail6; 664 } 665 666 signature.offset = image_trailer.offset + image_trailer.size; 667 signature.size = (uint32_t)(infop->eii_image_size - signature.offset); 668 if ((signature.size > buffer_size) || 669 (signature.offset > (buffer_size - signature.size))) { 670 rc = EINVAL; 671 goto fail7; 672 } 673 674 EFSYS_ASSERT3U(infop->eii_image_size, ==, cms_header.size + 675 image_header.size + code.size + image_trailer.size + 676 signature.size); 677 678 /* BEGIN CSTYLED */ 679 /* 680 * Build signed image partition, inserting chunk headers. 681 * 682 * Signed Image: Image in NVRAM partition: 683 * 684 * +-----------------+ +-----------------+ 685 * | CMS header | | mcfw.update |<----+ 686 * +-----------------+ | | | 687 * | reflash header | +-----------------+ | 688 * +-----------------+ | chunk header: |-->--|-+ 689 * | mcfw.update | | REFLASH_TRAILER | | | 690 * | | +-----------------+ | | 691 * +-----------------+ +-->| CMS header | | | 692 * | reflash trailer | | +-----------------+ | | 693 * +-----------------+ | | chunk header: |->-+ | | 694 * | signature | | | REFLASH_HEADER | | | | 695 * +-----------------+ | +-----------------+ | | | 696 * | | reflash header |<--+ | | 697 * | +-----------------+ | | 698 * | | chunk header: |-->--+ | 699 * | | IMAGE | | 700 * | +-----------------+ | 701 * | | reflash trailer |<------+ 702 * | +-----------------+ 703 * | | chunk header: | 704 * | | SIGNATURE |->-+ 705 * | +-----------------+ | 706 * | | signature |<--+ 707 * | +-----------------+ 708 * | | ...unused... | 709 * | +-----------------+ 710 * +-<-| chunk header: | 711 * >-->| CMS_HEADER | 712 * +-----------------+ 713 * 714 * Each chunk header gives the partition offset and length of the image 715 * chunk's data. The image chunk data is immediately followed by the 716 * chunk header for the next chunk. 717 * 718 * The data chunk for the firmware code must be at the start of the 719 * partition (needed for the bootloader). The first chunk header in the 720 * chain (for the CMS header) is stored at the end of the partition. The 721 * chain of chunk headers maintains the same logical order of image 722 * chunks as the original signed image file. This set of constraints 723 * results in the layout used for the data chunks and chunk headers. 724 */ 725 /* END CSTYLED */ 726 memset(bufferp, 0xFF, buffer_size); 727 728 EFX_STATIC_ASSERT(sizeof (chunk_hdr) == SIGNED_IMAGE_CHUNK_HDR_LEN); 729 memset(&chunk_hdr, 0, SIGNED_IMAGE_CHUNK_HDR_LEN); 730 731 /* 732 * CMS header 733 */ 734 if (buffer_size < SIGNED_IMAGE_CHUNK_HDR_LEN) { 735 rc = ENOSPC; 736 goto fail8; 737 } 738 hdr_offset = buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN; 739 740 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC; 741 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION; 742 chunk_hdr.id = SIGNED_IMAGE_CHUNK_CMS_HEADER; 743 chunk_hdr.offset = code.size + SIGNED_IMAGE_CHUNK_HDR_LEN; 744 chunk_hdr.len = cms_header.size; 745 746 memcpy(bufferp + hdr_offset, &chunk_hdr, sizeof (chunk_hdr)); 747 748 if ((chunk_hdr.len > buffer_size) || 749 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) { 750 rc = ENOSPC; 751 goto fail9; 752 } 753 memcpy(bufferp + chunk_hdr.offset, 754 infop->eii_imagep + cms_header.offset, 755 cms_header.size); 756 757 /* 758 * Image header 759 */ 760 hdr_offset = chunk_hdr.offset + chunk_hdr.len; 761 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) { 762 rc = ENOSPC; 763 goto fail10; 764 } 765 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC; 766 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION; 767 chunk_hdr.id = SIGNED_IMAGE_CHUNK_REFLASH_HEADER; 768 chunk_hdr.offset = hdr_offset + SIGNED_IMAGE_CHUNK_HDR_LEN; 769 chunk_hdr.len = image_header.size; 770 771 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN); 772 773 if ((chunk_hdr.len > buffer_size) || 774 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) { 775 rc = ENOSPC; 776 goto fail11; 777 } 778 memcpy(bufferp + chunk_hdr.offset, 779 infop->eii_imagep + image_header.offset, 780 image_header.size); 781 782 *headerpp = (efx_image_header_t *)(bufferp + chunk_hdr.offset); 783 784 /* 785 * Firmware code 786 */ 787 hdr_offset = chunk_hdr.offset + chunk_hdr.len; 788 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) { 789 rc = ENOSPC; 790 goto fail12; 791 } 792 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC; 793 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION; 794 chunk_hdr.id = SIGNED_IMAGE_CHUNK_IMAGE; 795 chunk_hdr.offset = 0; 796 chunk_hdr.len = code.size; 797 798 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN); 799 800 if ((chunk_hdr.len > buffer_size) || 801 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) { 802 rc = ENOSPC; 803 goto fail13; 804 } 805 memcpy(bufferp + chunk_hdr.offset, 806 infop->eii_imagep + code.offset, 807 code.size); 808 809 /* 810 * Image trailer (CRC) 811 */ 812 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC; 813 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION; 814 chunk_hdr.id = SIGNED_IMAGE_CHUNK_REFLASH_TRAILER; 815 chunk_hdr.offset = hdr_offset + SIGNED_IMAGE_CHUNK_HDR_LEN; 816 chunk_hdr.len = image_trailer.size; 817 818 hdr_offset = code.size; 819 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) { 820 rc = ENOSPC; 821 goto fail14; 822 } 823 824 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN); 825 826 if ((chunk_hdr.len > buffer_size) || 827 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) { 828 rc = ENOSPC; 829 goto fail15; 830 } 831 memcpy((uint8_t *)bufferp + chunk_hdr.offset, 832 infop->eii_imagep + image_trailer.offset, 833 image_trailer.size); 834 835 /* 836 * Signature 837 */ 838 hdr_offset = chunk_hdr.offset + chunk_hdr.len; 839 if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) { 840 rc = ENOSPC; 841 goto fail16; 842 } 843 chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC; 844 chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION; 845 chunk_hdr.id = SIGNED_IMAGE_CHUNK_SIGNATURE; 846 chunk_hdr.offset = chunk_hdr.offset + SIGNED_IMAGE_CHUNK_HDR_LEN; 847 chunk_hdr.len = signature.size; 848 849 memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN); 850 851 if ((chunk_hdr.len > buffer_size) || 852 (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) { 853 rc = ENOSPC; 854 goto fail17; 855 } 856 memcpy(bufferp + chunk_hdr.offset, 857 infop->eii_imagep + signature.offset, 858 signature.size); 859 860 return (0); 861 862 fail17: 863 EFSYS_PROBE(fail17); 864 fail16: 865 EFSYS_PROBE(fail16); 866 fail15: 867 EFSYS_PROBE(fail15); 868 fail14: 869 EFSYS_PROBE(fail14); 870 fail13: 871 EFSYS_PROBE(fail13); 872 fail12: 873 EFSYS_PROBE(fail12); 874 fail11: 875 EFSYS_PROBE(fail11); 876 fail10: 877 EFSYS_PROBE(fail10); 878 fail9: 879 EFSYS_PROBE(fail9); 880 fail8: 881 EFSYS_PROBE(fail8); 882 fail7: 883 EFSYS_PROBE(fail7); 884 fail6: 885 EFSYS_PROBE(fail6); 886 fail5: 887 EFSYS_PROBE(fail5); 888 fail4: 889 EFSYS_PROBE(fail4); 890 fail3: 891 EFSYS_PROBE(fail3); 892 fail2: 893 EFSYS_PROBE(fail2); 894 fail1: 895 EFSYS_PROBE1(fail1, efx_rc_t, rc); 896 897 return (rc); 898 } 899 900 901 902 #endif /* EFSYS_OPT_IMAGE_LAYOUT */ 903 904 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 905