xref: /dpdk/drivers/common/sfc_efx/base/ef10_image.c (revision 672386c1e9e1f64f7aa3b1360ad22dc737ea8d72)
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