From: Andrew Rybchenko <arybchenko@solarflare.com>
To: <dev@dpdk.org>
Cc: Andy Moreton <amoreton@solarflare.com>
Subject: [dpdk-dev] [PATCH 79/80] net/sfc/base: add signed image layout support
Date: Tue, 20 Feb 2018 07:34:37 +0000 [thread overview]
Message-ID: <1519112078-20113-80-git-send-email-arybchenko@solarflare.com> (raw)
In-Reply-To: <1519112078-20113-1-git-send-email-arybchenko@solarflare.com>
From: Andy Moreton <amoreton@solarflare.com>
Signed-off-by: Andy Moreton <amoreton@solarflare.com>
Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
---
drivers/net/sfc/base/ef10_image.c | 867 +++++++++++++++++++++++++++++++++++++-
drivers/net/sfc/base/efx.h | 86 ++++
2 files changed, 952 insertions(+), 1 deletion(-)
diff --git a/drivers/net/sfc/base/ef10_image.c b/drivers/net/sfc/base/ef10_image.c
index e076f40..6fb7e47 100644
--- a/drivers/net/sfc/base/ef10_image.c
+++ b/drivers/net/sfc/base/ef10_image.c
@@ -11,7 +11,872 @@
#if EFSYS_OPT_IMAGE_LAYOUT
-#include "ef10_signed_image_layout.h"
+/*
+ * Utility routines to support limited parsing of ASN.1 tags. This is not a
+ * general purpose ASN.1 parser, but is sufficient to locate the required
+ * objects in a signed image with CMS headers.
+ */
+
+/* DER encodings for ASN.1 tags (see ITU-T X.690) */
+#define ASN1_TAG_INTEGER (0x02)
+#define ASN1_TAG_OCTET_STRING (0x04)
+#define ASN1_TAG_OBJ_ID (0x06)
+#define ASN1_TAG_SEQUENCE (0x30)
+#define ASN1_TAG_SET (0x31)
+
+#define ASN1_TAG_IS_PRIM(tag) ((tag & 0x20) == 0)
+
+#define ASN1_TAG_PRIM_CONTEXT(n) (0x80 + (n))
+#define ASN1_TAG_CONS_CONTEXT(n) (0xA0 + (n))
+
+typedef struct efx_asn1_cursor_s {
+ uint8_t *buffer;
+ uint32_t length;
+
+ uint8_t tag;
+ uint32_t hdr_size;
+ uint32_t val_size;
+} efx_asn1_cursor_t;
+
+
+/* Parse header of DER encoded ASN.1 TLV and match tag */
+static __checkReturn efx_rc_t
+efx_asn1_parse_header_match_tag(
+ __inout efx_asn1_cursor_t *cursor,
+ __in uint8_t tag)
+{
+ efx_rc_t rc;
+
+ if (cursor == NULL || cursor->buffer == NULL || cursor->length < 2) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ cursor->tag = cursor->buffer[0];
+ if (cursor->tag != tag) {
+ /* Tag not matched */
+ rc = ENOENT;
+ goto fail2;
+ }
+
+ if ((cursor->tag & 0x1F) == 0x1F) {
+ /* Long tag format not used in CMS syntax */
+ rc = EINVAL;
+ goto fail3;
+ }
+
+ if ((cursor->buffer[1] & 0x80) == 0) {
+ /* Short form: length is 0..127 */
+ cursor->hdr_size = 2;
+ cursor->val_size = cursor->buffer[1];
+ } else {
+ /* Long form: length encoded as [0x80+nbytes][length bytes] */
+ uint32_t nbytes = cursor->buffer[1] & 0x7F;
+ uint32_t offset;
+
+ if (nbytes == 0) {
+ /* Indefinite length not allowed in DER encoding */
+ rc = EINVAL;
+ goto fail4;
+ }
+ if (2 + nbytes > cursor->length) {
+ /* Header length overflows image buffer */
+ rc = EINVAL;
+ goto fail6;
+ }
+ if (nbytes > sizeof (uint32_t)) {
+ /* Length encoding too big */
+ rc = E2BIG;
+ goto fail5;
+ }
+ cursor->hdr_size = 2 + nbytes;
+ cursor->val_size = 0;
+ for (offset = 2; offset < cursor->hdr_size; offset++) {
+ cursor->val_size =
+ (cursor->val_size << 8) | cursor->buffer[offset];
+ }
+ }
+
+ if ((cursor->hdr_size + cursor->val_size) > cursor->length) {
+ /* Length overflows image buffer */
+ rc = E2BIG;
+ goto fail7;
+ }
+
+ return (0);
+
+fail7:
+ EFSYS_PROBE(fail7);
+fail6:
+ EFSYS_PROBE(fail6);
+fail5:
+ EFSYS_PROBE(fail5);
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+/* Enter nested ASN.1 TLV (contained in value of current TLV) */
+static __checkReturn efx_rc_t
+efx_asn1_enter_tag(
+ __inout efx_asn1_cursor_t *cursor,
+ __in uint8_t tag)
+{
+ efx_rc_t rc;
+
+ if (cursor == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ if (ASN1_TAG_IS_PRIM(tag)) {
+ /* Cannot enter a primitive tag */
+ rc = ENOTSUP;
+ goto fail2;
+ }
+ rc = efx_asn1_parse_header_match_tag(cursor, tag);
+ if (rc != 0) {
+ /* Invalid TLV or wrong tag */
+ goto fail3;
+ }
+
+ /* Limit cursor range to nested TLV */
+ cursor->buffer += cursor->hdr_size;
+ cursor->length = cursor->val_size;
+
+ return (0);
+
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+/*
+ * Check that the current ASN.1 TLV matches the given tag and value.
+ * Advance cursor to next TLV on a successful match.
+ */
+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)
+{
+ efx_rc_t rc;
+
+ if (cursor == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+ rc = efx_asn1_parse_header_match_tag(cursor, tag);
+ if (rc != 0) {
+ /* Invalid TLV or wrong tag */
+ goto fail2;
+ }
+ if (cursor->val_size != val_size) {
+ /* Value size is different */
+ rc = EINVAL;
+ goto fail3;
+ }
+ if (memcmp(cursor->buffer + cursor->hdr_size, valp, val_size) != 0) {
+ /* Value content is different */
+ rc = EINVAL;
+ goto fail4;
+ }
+ cursor->buffer += cursor->hdr_size + cursor->val_size;
+ cursor->length -= cursor->hdr_size + cursor->val_size;
+
+ return (0);
+
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+/* Advance cursor to next TLV */
+static __checkReturn efx_rc_t
+efx_asn1_skip_tag(
+ __inout efx_asn1_cursor_t *cursor,
+ __in uint8_t tag)
+{
+ efx_rc_t rc;
+
+ if (cursor == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ rc = efx_asn1_parse_header_match_tag(cursor, tag);
+ if (rc != 0) {
+ /* Invalid TLV or wrong tag */
+ goto fail2;
+ }
+ cursor->buffer += cursor->hdr_size + cursor->val_size;
+ cursor->length -= cursor->hdr_size + cursor->val_size;
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+/* Return pointer to value octets and value size from current TLV */
+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)
+{
+ efx_rc_t rc;
+
+ if (cursor == NULL || valp == NULL || val_sizep == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+
+ rc = efx_asn1_parse_header_match_tag(cursor, tag);
+ if (rc != 0) {
+ /* Invalid TLV or wrong tag */
+ goto fail2;
+ }
+ *valp = cursor->buffer + cursor->hdr_size;
+ *val_sizep = cursor->val_size;
+
+ return (0);
+
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+
+/*
+ * Utility routines for parsing CMS headers (see RFC2315, PKCS#7)
+ */
+
+/* OID 1.2.840.113549.1.7.2 */
+static const uint8_t PKCS7_SignedData[] =
+{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
+
+/* OID 1.2.840.113549.1.7.1 */
+static const uint8_t PKCS7_Data[] =
+{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
+
+/* SignedData structure version */
+static const uint8_t SignedData_Version[] =
+{ 0x03 };
+
+/*
+ * Check for a valid image in signed image format. This uses CMS syntax
+ * (see RFC2315, PKCS#7) to provide signatures, and certificates required
+ * to validate the signatures. The encapsulated content is in unsigned image
+ * format (reflash header, image code, trailer checksum).
+ */
+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)
+{
+ efx_asn1_cursor_t cursor;
+ uint8_t *valp;
+ uint32_t val_size;
+ efx_rc_t rc;
+
+ if (content_offsetp == NULL || content_lengthp == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+ cursor.buffer = (uint8_t *)bufferp;
+ cursor.length = buffer_size;
+
+ /* ContextInfo */
+ rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
+ if (rc != 0)
+ goto fail2;
+
+ /* ContextInfo.contentType */
+ rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
+ PKCS7_SignedData, sizeof (PKCS7_SignedData));
+ if (rc != 0)
+ goto fail3;
+
+ /* ContextInfo.content */
+ rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
+ if (rc != 0)
+ goto fail4;
+
+ /* SignedData */
+ rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
+ if (rc != 0)
+ goto fail5;
+
+ /* SignedData.version */
+ rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_INTEGER,
+ SignedData_Version, sizeof (SignedData_Version));
+ if (rc != 0)
+ goto fail6;
+
+ /* SignedData.digestAlgorithms */
+ rc = efx_asn1_skip_tag(&cursor, ASN1_TAG_SET);
+ if (rc != 0)
+ goto fail7;
+
+ /* SignedData.encapContentInfo */
+ rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_SEQUENCE);
+ if (rc != 0)
+ goto fail8;
+
+ /* SignedData.encapContentInfo.econtentType */
+ rc = efx_asn1_match_tag_value(&cursor, ASN1_TAG_OBJ_ID,
+ PKCS7_Data, sizeof (PKCS7_Data));
+ if (rc != 0)
+ goto fail9;
+
+ /* SignedData.encapContentInfo.econtent */
+ rc = efx_asn1_enter_tag(&cursor, ASN1_TAG_CONS_CONTEXT(0));
+ if (rc != 0)
+ goto fail10;
+
+ /*
+ * The octet string contains the image header, image code bytes and
+ * image trailer CRC (same as unsigned image layout).
+ */
+ valp = NULL;
+ val_size = 0;
+ rc = efx_asn1_get_tag_value(&cursor, ASN1_TAG_OCTET_STRING,
+ &valp, &val_size);
+ if (rc != 0)
+ goto fail11;
+
+ if ((valp == NULL) || (val_size == 0)) {
+ rc = EINVAL;
+ goto fail12;
+ }
+ if (valp < (uint8_t *)bufferp) {
+ rc = EINVAL;
+ goto fail13;
+ }
+ if ((valp + val_size) > ((uint8_t *)bufferp + buffer_size)) {
+ rc = EINVAL;
+ goto fail14;
+ }
+
+ *content_offsetp = (uint32_t)(valp - (uint8_t *)bufferp);
+ *content_lengthp = val_size;
+
+ return (0);
+
+fail14:
+ EFSYS_PROBE(fail14);
+fail13:
+ EFSYS_PROBE(fail13);
+fail12:
+ EFSYS_PROBE(fail12);
+fail11:
+ EFSYS_PROBE(fail11);
+fail10:
+ EFSYS_PROBE(fail10);
+fail9:
+ EFSYS_PROBE(fail9);
+fail8:
+ EFSYS_PROBE(fail8);
+fail7:
+ EFSYS_PROBE(fail7);
+fail6:
+ EFSYS_PROBE(fail6);
+fail5:
+ EFSYS_PROBE(fail5);
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+static __checkReturn efx_rc_t
+efx_check_unsigned_image(
+ __in void *bufferp,
+ __in uint32_t buffer_size)
+{
+ efx_image_header_t *header;
+ efx_image_trailer_t *trailer;
+ uint32_t crc;
+ efx_rc_t rc;
+
+ EFX_STATIC_ASSERT(sizeof (*header) == EFX_IMAGE_HEADER_SIZE);
+ EFX_STATIC_ASSERT(sizeof (*trailer) == EFX_IMAGE_TRAILER_SIZE);
+
+ /* Must have at least enough space for required image header fields */
+ if (buffer_size < (EFX_FIELD_OFFSET(efx_image_header_t, eih_size) +
+ sizeof (header->eih_size))) {
+ rc = ENOSPC;
+ goto fail1;
+ }
+ header = (efx_image_header_t *)bufferp;
+
+ if (header->eih_magic != EFX_IMAGE_HEADER_MAGIC) {
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ /*
+ * Check image header version is same or higher than lowest required
+ * version.
+ */
+ if (header->eih_version < EFX_IMAGE_HEADER_VERSION) {
+ rc = EINVAL;
+ goto fail3;
+ }
+
+ /* Buffer must have space for image header, code and image trailer. */
+ if (buffer_size < (header->eih_size + header->eih_code_size +
+ EFX_IMAGE_TRAILER_SIZE)) {
+ rc = ENOSPC;
+ goto fail4;
+ }
+
+ /* Check CRC from image buffer matches computed CRC. */
+ trailer = (efx_image_trailer_t *)((uint8_t *)header +
+ header->eih_size + header->eih_code_size);
+
+ crc = efx_crc32_calculate(0, (uint8_t *)header,
+ (header->eih_size + header->eih_code_size));
+
+ if (trailer->eit_crc != crc) {
+ rc = EINVAL;
+ goto fail5;
+ }
+
+ return (0);
+
+fail5:
+ EFSYS_PROBE(fail5);
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_check_reflash_image(
+ __in void *bufferp,
+ __in uint32_t buffer_size,
+ __out efx_image_info_t *infop)
+{
+ efx_image_format_t format = EFX_IMAGE_FORMAT_NO_IMAGE;
+ uint32_t image_offset;
+ uint32_t image_size;
+ void *imagep;
+ efx_rc_t rc;
+
+
+ EFSYS_ASSERT(infop != NULL);
+ if (infop == NULL) {
+ rc = EINVAL;
+ goto fail1;
+ }
+ memset(infop, 0, sizeof (*infop));
+
+ if (bufferp == NULL || buffer_size == 0) {
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ /*
+ * Check if the buffer contains an image in signed format, and if so,
+ * locate the image header.
+ */
+ rc = efx_check_signed_image_header(bufferp, buffer_size,
+ &image_offset, &image_size);
+ if (rc == 0) {
+ /*
+ * Buffer holds signed image format. Check that the encapsulated
+ * content is in unsigned image format.
+ */
+ format = EFX_IMAGE_FORMAT_SIGNED;
+ } else {
+ /* Check if the buffer holds image in unsigned image format */
+ format = EFX_IMAGE_FORMAT_UNSIGNED;
+ image_offset = 0;
+ image_size = buffer_size;
+ }
+ if (image_offset + image_size > buffer_size) {
+ rc = E2BIG;
+ goto fail3;
+ }
+ imagep = (uint8_t *)bufferp + image_offset;
+
+ /* Check unsigned image layout (image header, code, image trailer) */
+ rc = efx_check_unsigned_image(imagep, image_size);
+ if (rc != 0)
+ goto fail4;
+
+ /* Return image details */
+ infop->eii_format = format;
+ infop->eii_imagep = bufferp;
+ infop->eii_image_size = buffer_size;
+ infop->eii_headerp = (efx_image_header_t *)imagep;
+
+ return (0);
+
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+ infop->eii_format = EFX_IMAGE_FORMAT_INVALID;
+ infop->eii_imagep = NULL;
+ infop->eii_image_size = 0;
+
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
+
+ __checkReturn efx_rc_t
+efx_build_signed_image_write_buffer(
+ __out uint8_t *bufferp,
+ __in uint32_t buffer_size,
+ __in efx_image_info_t *infop,
+ __out efx_image_header_t **headerpp)
+{
+ signed_image_chunk_hdr_t chunk_hdr;
+ uint32_t hdr_offset;
+ struct {
+ uint32_t offset;
+ uint32_t size;
+ } cms_header, image_header, code, image_trailer, signature;
+ efx_rc_t rc;
+
+ EFSYS_ASSERT((infop != NULL) && (headerpp != NULL));
+
+ if ((bufferp == NULL) || (buffer_size == 0) ||
+ (infop == NULL) || (headerpp == NULL)) {
+ /* Invalid arguments */
+ rc = EINVAL;
+ goto fail1;
+ }
+ if ((infop->eii_format != EFX_IMAGE_FORMAT_SIGNED) ||
+ (infop->eii_imagep == NULL) ||
+ (infop->eii_headerp == NULL) ||
+ ((uint8_t *)infop->eii_headerp < (uint8_t *)infop->eii_imagep) ||
+ (infop->eii_image_size < EFX_IMAGE_HEADER_SIZE) ||
+ ((size_t)((uint8_t *)infop->eii_headerp - infop->eii_imagep) >
+ (infop->eii_image_size - EFX_IMAGE_HEADER_SIZE))) {
+ /* Invalid image info */
+ rc = EINVAL;
+ goto fail2;
+ }
+
+ /* Locate image chunks in original signed image */
+ cms_header.offset = 0;
+ cms_header.size =
+ (uint32_t)((uint8_t *)infop->eii_headerp - infop->eii_imagep);
+ if ((cms_header.size > buffer_size) ||
+ (cms_header.offset > (buffer_size - cms_header.size))) {
+ rc = EINVAL;
+ goto fail3;
+ }
+
+ image_header.offset = cms_header.offset + cms_header.size;
+ image_header.size = infop->eii_headerp->eih_size;
+ if ((image_header.size > buffer_size) ||
+ (image_header.offset > (buffer_size - image_header.size))) {
+ rc = EINVAL;
+ goto fail4;
+ }
+
+ code.offset = image_header.offset + image_header.size;
+ code.size = infop->eii_headerp->eih_code_size;
+ if ((code.size > buffer_size) ||
+ (code.offset > (buffer_size - code.size))) {
+ rc = EINVAL;
+ goto fail5;
+ }
+
+ image_trailer.offset = code.offset + code.size;
+ image_trailer.size = EFX_IMAGE_TRAILER_SIZE;
+ if ((image_trailer.size > buffer_size) ||
+ (image_trailer.offset > (buffer_size - image_trailer.size))) {
+ rc = EINVAL;
+ goto fail6;
+ }
+
+ signature.offset = image_trailer.offset + image_trailer.size;
+ signature.size = (uint32_t)(infop->eii_image_size - signature.offset);
+ if ((signature.size > buffer_size) ||
+ (signature.offset > (buffer_size - signature.size))) {
+ rc = EINVAL;
+ goto fail7;
+ }
+
+ EFSYS_ASSERT3U(infop->eii_image_size, ==, cms_header.size +
+ image_header.size + code.size + image_trailer.size +
+ signature.size);
+
+ /* BEGIN CSTYLED */
+ /*
+ * Build signed image partition, inserting chunk headers.
+ *
+ * Signed Image: Image in NVRAM partition:
+ *
+ * +-----------------+ +-----------------+
+ * | CMS header | | mcfw.update |<----+
+ * +-----------------+ | | |
+ * | reflash header | +-----------------+ |
+ * +-----------------+ | chunk header: |-->--|-+
+ * | mcfw.update | | REFLASH_TRAILER | | |
+ * | | +-----------------+ | |
+ * +-----------------+ +-->| CMS header | | |
+ * | reflash trailer | | +-----------------+ | |
+ * +-----------------+ | | chunk header: |->-+ | |
+ * | signature | | | REFLASH_HEADER | | | |
+ * +-----------------+ | +-----------------+ | | |
+ * | | reflash header |<--+ | |
+ * | +-----------------+ | |
+ * | | chunk header: |-->--+ |
+ * | | IMAGE | |
+ * | +-----------------+ |
+ * | | reflash trailer |<------+
+ * | +-----------------+
+ * | | chunk header: |
+ * | | SIGNATURE |->-+
+ * | +-----------------+ |
+ * | | signature |<--+
+ * | +-----------------+
+ * | | ...unused... |
+ * | +-----------------+
+ * +-<-| chunk header: |
+ * >-->| CMS_HEADER |
+ * +-----------------+
+ *
+ * Each chunk header gives the partition offset and length of the image
+ * chunk's data. The image chunk data is immediately followed by the
+ * chunk header for the next chunk.
+ *
+ * The data chunk for the firmware code must be at the start of the
+ * partition (needed for the bootloader). The first chunk header in the
+ * chain (for the CMS header) is stored at the end of the partition. The
+ * chain of chunk headers maintains the same logical order of image
+ * chunks as the original signed image file. This set of constraints
+ * results in the layout used for the data chunks and chunk headers.
+ */
+ /* END CSTYLED */
+ memset(bufferp, buffer_size, 0xFF);
+
+ EFX_STATIC_ASSERT(sizeof (chunk_hdr) == SIGNED_IMAGE_CHUNK_HDR_LEN);
+ memset(&chunk_hdr, 0, SIGNED_IMAGE_CHUNK_HDR_LEN);
+
+ /*
+ * CMS header
+ */
+ if (buffer_size < SIGNED_IMAGE_CHUNK_HDR_LEN) {
+ rc = ENOSPC;
+ goto fail8;
+ }
+ hdr_offset = buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN;
+
+ chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
+ chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
+ chunk_hdr.id = SIGNED_IMAGE_CHUNK_CMS_HEADER;
+ chunk_hdr.offset = code.size + SIGNED_IMAGE_CHUNK_HDR_LEN;
+ chunk_hdr.len = cms_header.size;
+
+ memcpy(bufferp + hdr_offset, &chunk_hdr, sizeof (chunk_hdr));
+
+ if ((chunk_hdr.len > buffer_size) ||
+ (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
+ rc = ENOSPC;
+ goto fail9;
+ }
+ memcpy(bufferp + chunk_hdr.offset,
+ infop->eii_imagep + cms_header.offset,
+ cms_header.size);
+
+ /*
+ * Image header
+ */
+ hdr_offset = chunk_hdr.offset + chunk_hdr.len;
+ if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
+ rc = ENOSPC;
+ goto fail10;
+ }
+ chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
+ chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
+ chunk_hdr.id = SIGNED_IMAGE_CHUNK_REFLASH_HEADER;
+ chunk_hdr.offset = hdr_offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
+ chunk_hdr.len = image_header.size;
+
+ memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
+
+ if ((chunk_hdr.len > buffer_size) ||
+ (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
+ rc = ENOSPC;
+ goto fail11;
+ }
+ memcpy(bufferp + chunk_hdr.offset,
+ infop->eii_imagep + image_header.offset,
+ image_header.size);
+
+ *headerpp = (efx_image_header_t *)(bufferp + chunk_hdr.offset);
+
+ /*
+ * Firmware code
+ */
+ hdr_offset = chunk_hdr.offset + chunk_hdr.len;
+ if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
+ rc = ENOSPC;
+ goto fail12;
+ }
+ chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
+ chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
+ chunk_hdr.id = SIGNED_IMAGE_CHUNK_IMAGE;
+ chunk_hdr.offset = 0;
+ chunk_hdr.len = code.size;
+
+ memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
+
+ if ((chunk_hdr.len > buffer_size) ||
+ (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
+ rc = ENOSPC;
+ goto fail13;
+ }
+ memcpy(bufferp + chunk_hdr.offset,
+ infop->eii_imagep + code.offset,
+ code.size);
+
+ /*
+ * Image trailer (CRC)
+ */
+ chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
+ chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
+ chunk_hdr.id = SIGNED_IMAGE_CHUNK_REFLASH_TRAILER;
+ chunk_hdr.offset = hdr_offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
+ chunk_hdr.len = image_trailer.size;
+
+ hdr_offset = code.size;
+ if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
+ rc = ENOSPC;
+ goto fail14;
+ }
+
+ memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
+
+ if ((chunk_hdr.len > buffer_size) ||
+ (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
+ rc = ENOSPC;
+ goto fail15;
+ }
+ memcpy((uint8_t *)bufferp + chunk_hdr.offset,
+ infop->eii_imagep + image_trailer.offset,
+ image_trailer.size);
+
+ /*
+ * Signature
+ */
+ hdr_offset = chunk_hdr.offset + chunk_hdr.len;
+ if (hdr_offset > (buffer_size - SIGNED_IMAGE_CHUNK_HDR_LEN)) {
+ rc = ENOSPC;
+ goto fail16;
+ }
+ chunk_hdr.magic = SIGNED_IMAGE_CHUNK_HDR_MAGIC;
+ chunk_hdr.version = SIGNED_IMAGE_CHUNK_HDR_VERSION;
+ chunk_hdr.id = SIGNED_IMAGE_CHUNK_SIGNATURE;
+ chunk_hdr.offset = chunk_hdr.offset + SIGNED_IMAGE_CHUNK_HDR_LEN;
+ chunk_hdr.len = signature.size;
+
+ memcpy(bufferp + hdr_offset, &chunk_hdr, SIGNED_IMAGE_CHUNK_HDR_LEN);
+
+ if ((chunk_hdr.len > buffer_size) ||
+ (chunk_hdr.offset > (buffer_size - chunk_hdr.len))) {
+ rc = ENOSPC;
+ goto fail17;
+ }
+ memcpy(bufferp + chunk_hdr.offset,
+ infop->eii_imagep + signature.offset,
+ signature.size);
+
+ return (0);
+
+fail17:
+ EFSYS_PROBE(fail17);
+fail16:
+ EFSYS_PROBE(fail16);
+fail15:
+ EFSYS_PROBE(fail15);
+fail14:
+ EFSYS_PROBE(fail14);
+fail13:
+ EFSYS_PROBE(fail13);
+fail12:
+ EFSYS_PROBE(fail12);
+fail11:
+ EFSYS_PROBE(fail11);
+fail10:
+ EFSYS_PROBE(fail10);
+fail9:
+ EFSYS_PROBE(fail9);
+fail8:
+ EFSYS_PROBE(fail8);
+fail7:
+ EFSYS_PROBE(fail7);
+fail6:
+ EFSYS_PROBE(fail6);
+fail5:
+ EFSYS_PROBE(fail5);
+fail4:
+ EFSYS_PROBE(fail4);
+fail3:
+ EFSYS_PROBE(fail3);
+fail2:
+ EFSYS_PROBE(fail2);
+fail1:
+ EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+ return (rc);
+}
diff --git a/drivers/net/sfc/base/efx.h b/drivers/net/sfc/base/efx.h
index 0d84108..088a896 100644
--- a/drivers/net/sfc/base/efx.h
+++ b/drivers/net/sfc/base/efx.h
@@ -1567,6 +1567,92 @@ efx_bootcfg_write(
#endif /* EFSYS_OPT_BOOTCFG */
+#if EFSYS_OPT_IMAGE_LAYOUT
+
+#include "ef10_signed_image_layout.h"
+
+/*
+ * Image header used in unsigned and signed image layouts (see SF-102785-PS).
+ *
+ * NOTE:
+ * The image header format is extensible. However, older drivers require an
+ * exact match of image header version and header length when validating and
+ * writing firmware images.
+ *
+ * To avoid breaking backward compatibility, we use the upper bits of the
+ * controller version fields to contain an extra version number used for
+ * combined bootROM and UEFI ROM images on EF10 and later (to hold the UEFI ROM
+ * version). See bug39254 and SF-102785-PS for details.
+ */
+typedef struct efx_image_header_s {
+ uint32_t eih_magic;
+ uint32_t eih_version;
+ uint32_t eih_type;
+ uint32_t eih_subtype;
+ uint32_t eih_code_size;
+ uint32_t eih_size;
+ union {
+ uint32_t eih_controller_version_min;
+ struct {
+ uint16_t eih_controller_version_min_short;
+ uint8_t eih_extra_version_a;
+ uint8_t eih_extra_version_b;
+ };
+ };
+ union {
+ uint32_t eih_controller_version_max;
+ struct {
+ uint16_t eih_controller_version_max_short;
+ uint8_t eih_extra_version_c;
+ uint8_t eih_extra_version_d;
+ };
+ };
+ uint16_t eih_code_version_a;
+ uint16_t eih_code_version_b;
+ uint16_t eih_code_version_c;
+ uint16_t eih_code_version_d;
+} efx_image_header_t;
+
+#define EFX_IMAGE_HEADER_SIZE (40)
+#define EFX_IMAGE_HEADER_VERSION (4)
+#define EFX_IMAGE_HEADER_MAGIC (0x106F1A5)
+
+
+typedef struct efx_image_trailer_s {
+ uint32_t eit_crc;
+} efx_image_trailer_t;
+
+#define EFX_IMAGE_TRAILER_SIZE (4)
+
+typedef enum efx_image_format_e {
+ EFX_IMAGE_FORMAT_NO_IMAGE,
+ EFX_IMAGE_FORMAT_INVALID,
+ EFX_IMAGE_FORMAT_UNSIGNED,
+ EFX_IMAGE_FORMAT_SIGNED,
+} efx_image_format_t;
+
+typedef struct efx_image_info_s {
+ efx_image_format_t eii_format;
+ uint8_t * eii_imagep;
+ size_t eii_image_size;
+ efx_image_header_t * eii_headerp;
+} efx_image_info_t;
+
+extern __checkReturn efx_rc_t
+efx_check_reflash_image(
+ __in void *bufferp,
+ __in uint32_t buffer_size,
+ __out efx_image_info_t *infop);
+
+extern __checkReturn efx_rc_t
+efx_build_signed_image_write_buffer(
+ __out uint8_t *bufferp,
+ __in uint32_t buffer_size,
+ __in efx_image_info_t *infop,
+ __out efx_image_header_t **headerpp);
+
+#endif /* EFSYS_OPT_IMAGE_LAYOUT */
+
#if EFSYS_OPT_DIAG
typedef enum efx_pattern_type_t {
--
2.7.4
next prev parent reply other threads:[~2018-02-20 7:35 UTC|newest]
Thread overview: 82+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-20 7:33 [dpdk-dev] [PATCH 00/80] net/sfc/base: update base driver Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 01/80] net/sfc: add missing defines for SAL annotation Andrew Rybchenko
2018-03-05 20:47 ` Ferruh Yigit
2018-02-20 7:33 ` [dpdk-dev] [PATCH 02/80] net/sfc/base: regenerate files with genfwdef after ID update Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 03/80] net/sfc/base: update autogenerated headers from firmwaresrc Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 04/80] net/sfc/base: add 3.3V and 12.0V current sensors Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 05/80] net/sfc/base: add Medford2 PCI IDs Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 06/80] net/sfc/base: add efsys option for Medford2 Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 07/80] net/sfc/base: add Medford2 support to NIC module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 08/80] net/sfc/base: correct PIO buffer dimensions for Medford2 Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 09/80] net/sfc/base: move RxDP config get to EF10 NIC code Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 10/80] net/sfc/base: add Medford2 support to EV module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 11/80] net/sfc/base: add Medford2 support to FILTER module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 12/80] net/sfc/base: add Medford2 support to INTR module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 13/80] net/sfc/base: add Medford2 support to MAC module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 14/80] net/sfc/base: add Medford2 support to MCDI module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 15/80] net/sfc/base: add Medford2 support to PHY module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 16/80] net/sfc/base: add Medford2 support to Rx module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 17/80] net/sfc/base: add Medford2 support to Tx module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 18/80] net/sfc/base: add Medford2 support to NVRAM module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 19/80] net/sfc/base: add Medford2 support to SRAM module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 20/80] net/sfc/base: add Medford2 support to BOOTCFG module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 21/80] net/sfc/base: add Medford2 support to VPD module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 22/80] net/sfc/base: add Medford2 support to MON module Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 23/80] net/sfc/base: support runtime VI window size Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 24/80] net/sfc/base: improve comments for EF10 ext port mapping Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 25/80] net/sfc/base: add method to make checksum option descriptors Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 26/80] net/sfc/base: update hardware headers for Medford2 Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 27/80] net/sfc/base: refactoring eliminating code analysis warnings Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 28/80] net/sfc/base: fix too long line Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 29/80] net/sfc/base: update notes on interrupt testing on VFs Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 30/80] net/sfc/base: report memory BAR number Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 31/80] net/sfc/base: simplify loopback type checking Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 32/80] net/sfc/base: add support new link modes Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 33/80] net/sfc/base: add new loopback modes Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 34/80] net/sfc/base: add efsys macro to get memory region size Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 35/80] net/sfc/base: handle new speeds in linkchange events Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 36/80] net/sfc/base: refactor EF10 get datapath capabilities Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 37/80] net/sfc/base: retrieve number of MAC stats from NIC Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 38/80] net/sfc/base: improve robustness of MAC stats get via MCDI Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 39/80] net/sfc/base: use MAC stats DMA buffer size from caps Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 40/80] net/sfc/base: use MAC stats DMA buffer size when decoding Andrew Rybchenko
2018-02-20 7:33 ` [dpdk-dev] [PATCH 41/80] net/sfc/base: run mkconfig.py to add FEC MAC stats Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 42/80] net/sfc/base: decode Medford2 FEC stats if available Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 43/80] net/sfc/base: resolve code analysis warnings Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 44/80] net/sfc: size MAC stats DMA buffer to support Medford2 Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 45/80] net/sfc/base: remove MAC stats size define Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 46/80] net/sfc/base: use correct name for frame truncation event Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 47/80] net/sfc/base: add ef10 NIC board config method Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 48/80] net/sfc/base: move port config to ef10 NIC board config Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 49/80] net/sfc/base: move PF/VF " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 50/80] net/sfc/base: move MAC address config to ef10 NIC board cfg Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 51/80] net/sfc/base: move legacy board " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 52/80] net/sfc/base: move PHY/link " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 53/80] net/sfc/base: move datapath " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 54/80] net/sfc/base: move Rx config to ef10 NIC board config Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 55/80] net/sfc/base: move Tx " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 56/80] net/sfc/base: move limits " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 57/80] net/sfc/base: move vector " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 58/80] net/sfc/base: move privilege " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 59/80] net/sfc/base: move VI window size config to ef10 NIC board Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 60/80] net/sfc/base: remove obsolete comments Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 61/80] net/sfc/base: support FEC mode settings Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 62/80] net/sfc/base: support Medford2 event timer semantics Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 63/80] net/sfc/base: clarify port mode names and masks Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 64/80] net/sfc/base: group Medford external port mapping entries Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 65/80] net/sfc/base: add Medford2 support for external port numbers Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 66/80] net/sfc/base: add Medford2 support for licencing Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 67/80] net/sfc/base: add Medford2 support for tunnel encapsulations Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 68/80] net/sfc/base: provide a flag for controlling CTPIO mode Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 69/80] net/sfc/base: add 1.3V voltage and current sensors Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 70/80] net/sfc/base: document the event type for CTPIO sends Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 71/80] net/sfc/base: run genfwdef to update headers Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 72/80] net/sfc/base: add CTPIO statistics Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 73/80] net/sfc/base: add bit to indicate CTPIO availability Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 74/80] net/sfc/base: regenerate headers to pick up CTPIO stats Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 75/80] net/sfc/base: support " Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 76/80] net/sfc/base: add encapsulated TSOv2 capability Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 77/80] net/sfc/base: add outer IP ID parameter to TSOv2 descriptor Andrew Rybchenko
2018-02-20 7:34 ` [dpdk-dev] [PATCH 78/80] net/sfc/base: add firmware image layout option Andrew Rybchenko
2018-02-20 7:34 ` Andrew Rybchenko [this message]
2018-02-20 7:34 ` [dpdk-dev] [PATCH 80/80] net/sfc/base: sync MCDI headers and TLV layout Andrew Rybchenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1519112078-20113-80-git-send-email-arybchenko@solarflare.com \
--to=arybchenko@solarflare.com \
--cc=amoreton@solarflare.com \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).