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