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