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