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