1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2019-2021 Xilinx, Inc.
4 * Copyright(c) 2017-2019 Solarflare Communications Inc.
5 */
6
7 #include "efx.h"
8 #include "efx_impl.h"
9
10 #include "ef10_firmware_ids.h"
11
12 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
13
14 #if EFSYS_OPT_IMAGE_LAYOUT
15
16 /*
17 * Utility routines to support limited parsing of ASN.1 tags. This is not a
18 * general purpose ASN.1 parser, but is sufficient to locate the required
19 * objects in a signed image with CMS headers.
20 */
21
22 /* DER encodings for ASN.1 tags (see ITU-T X.690) */
23 #define ASN1_TAG_INTEGER (0x02)
24 #define ASN1_TAG_OCTET_STRING (0x04)
25 #define ASN1_TAG_OBJ_ID (0x06)
26 #define ASN1_TAG_SEQUENCE (0x30)
27 #define ASN1_TAG_SET (0x31)
28
29 #define ASN1_TAG_IS_PRIM(tag) ((tag & 0x20) == 0)
30
31 #define ASN1_TAG_PRIM_CONTEXT(n) (0x80 + (n))
32 #define ASN1_TAG_CONS_CONTEXT(n) (0xA0 + (n))
33
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
efx_asn1_parse_header_match_tag(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag)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
efx_asn1_enter_tag(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag)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
efx_asn1_match_tag_value(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag,__in const void * valp,__in uint32_t val_size)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
efx_asn1_skip_tag(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag)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
efx_asn1_get_tag_value(__inout efx_asn1_cursor_t * cursor,__in uint8_t tag,__out uint8_t ** valp,__out uint32_t * val_sizep)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
efx_check_signed_image_header(__in void * bufferp,__in uint32_t buffer_size,__out uint32_t * content_offsetp,__out uint32_t * content_lengthp)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
efx_check_unsigned_image(__in void * bufferp,__in uint32_t buffer_size,__out efx_image_header_t ** headerpp,__out efx_image_trailer_t ** trailerpp)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
efx_check_reflash_image(__in void * bufferp,__in uint32_t buffer_size,__out efx_image_info_t * infop)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
efx_build_signed_image_write_buffer(__out_bcount (buffer_size)uint8_t * bufferp,__in uint32_t buffer_size,__in efx_image_info_t * infop,__out efx_image_header_t ** headerpp)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 */
905