dpdk/drivers/common/sfc_efx/base/ef10_image.c
<<
>>
Prefs
   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
  34typedef 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 */
  45static  __checkReturn   efx_rc_t
  46efx_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
 110fail7:
 111        EFSYS_PROBE(fail7);
 112fail6:
 113        EFSYS_PROBE(fail6);
 114fail5:
 115        EFSYS_PROBE(fail5);
 116fail4:
 117        EFSYS_PROBE(fail4);
 118fail3:
 119        EFSYS_PROBE(fail3);
 120fail2:
 121        EFSYS_PROBE(fail2);
 122fail1:
 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) */
 129static  __checkReturn   efx_rc_t
 130efx_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
 158fail3:
 159        EFSYS_PROBE(fail3);
 160fail2:
 161        EFSYS_PROBE(fail2);
 162fail1:
 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 */
 172static  __checkReturn   efx_rc_t
 173efx_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
 205fail4:
 206        EFSYS_PROBE(fail4);
 207fail3:
 208        EFSYS_PROBE(fail3);
 209fail2:
 210        EFSYS_PROBE(fail2);
 211fail1:
 212        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 213
 214        return (rc);
 215}
 216
 217/* Advance cursor to next TLV */
 218static  __checkReturn   efx_rc_t
 219efx_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
 240fail2:
 241        EFSYS_PROBE(fail2);
 242fail1:
 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 */
 249static  __checkReturn   efx_rc_t
 250efx_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
 273fail2:
 274        EFSYS_PROBE(fail2);
 275fail1:
 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 */
 287static 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 */
 291static const uint8_t PKCS7_Data[] =
 292{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
 293
 294/* SignedData structure version */
 295static 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 */
 304static  __checkReturn   efx_rc_t
 305efx_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
 400fail14:
 401        EFSYS_PROBE(fail14);
 402fail13:
 403        EFSYS_PROBE(fail13);
 404fail12:
 405        EFSYS_PROBE(fail12);
 406fail11:
 407        EFSYS_PROBE(fail11);
 408fail10:
 409        EFSYS_PROBE(fail10);
 410fail9:
 411        EFSYS_PROBE(fail9);
 412fail8:
 413        EFSYS_PROBE(fail8);
 414fail7:
 415        EFSYS_PROBE(fail7);
 416fail6:
 417        EFSYS_PROBE(fail6);
 418fail5:
 419        EFSYS_PROBE(fail5);
 420fail4:
 421        EFSYS_PROBE(fail4);
 422fail3:
 423        EFSYS_PROBE(fail3);
 424fail2:
 425        EFSYS_PROBE(fail2);
 426fail1:
 427        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 428
 429        return (rc);
 430}
 431
 432static  __checkReturn   efx_rc_t
 433efx_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
 493fail5:
 494        EFSYS_PROBE(fail5);
 495fail4:
 496        EFSYS_PROBE(fail4);
 497fail3:
 498        EFSYS_PROBE(fail3);
 499fail2:
 500        EFSYS_PROBE(fail2);
 501fail1:
 502        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 503
 504        return (rc);
 505}
 506
 507        __checkReturn   efx_rc_t
 508efx_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
 580fail4:
 581        EFSYS_PROBE(fail4);
 582fail3:
 583        EFSYS_PROBE(fail3);
 584fail2:
 585        EFSYS_PROBE(fail2);
 586        infop->eii_format = EFX_IMAGE_FORMAT_INVALID;
 587        infop->eii_imagep = NULL;
 588        infop->eii_image_size = 0;
 589
 590fail1:
 591        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 592
 593        return (rc);
 594}
 595
 596        __checkReturn   efx_rc_t
 597efx_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
 862fail17:
 863        EFSYS_PROBE(fail17);
 864fail16:
 865        EFSYS_PROBE(fail16);
 866fail15:
 867        EFSYS_PROBE(fail15);
 868fail14:
 869        EFSYS_PROBE(fail14);
 870fail13:
 871        EFSYS_PROBE(fail13);
 872fail12:
 873        EFSYS_PROBE(fail12);
 874fail11:
 875        EFSYS_PROBE(fail11);
 876fail10:
 877        EFSYS_PROBE(fail10);
 878fail9:
 879        EFSYS_PROBE(fail9);
 880fail8:
 881        EFSYS_PROBE(fail8);
 882fail7:
 883        EFSYS_PROBE(fail7);
 884fail6:
 885        EFSYS_PROBE(fail6);
 886fail5:
 887        EFSYS_PROBE(fail5);
 888fail4:
 889        EFSYS_PROBE(fail4);
 890fail3:
 891        EFSYS_PROBE(fail3);
 892fail2:
 893        EFSYS_PROBE(fail2);
 894fail1:
 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