feat(st): update stm32image tool for header v2

The stm32image tool is updated to manage new header v2.0 for BL2
images.
Add new structure for the header v2.0 management.
Adapt to keep compatibility with v1.0.
Add the header version major and minor in the command line
when executing the tool, as well as binary type (0x10 for BL2).

Change-Id: I70c187e8e7e95b57ab7cfad63df314307a78f1d6
Signed-off-by: Yann Gautier <yann.gautier@st.com>
Signed-off-by: Lionel Debieve <lionel.debieve@st.com>
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index a4c40c4..ddfc5e7 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -28,6 +28,13 @@
 STM32MP_DDR_DUAL_AXI_PORT:=	1
 STM32MP_DDR_32BIT_INTERFACE:=	1
 
+# STM32 image header version v1.0
+STM32_HEADER_VERSION_MAJOR:=	1
+STM32_HEADER_VERSION_MINOR:=	0
+
+# STM32 image header binary type for BL2
+STM32_HEADER_BL2_BINARY_TYPE:=	0x10
+
 ifeq ($(AARCH32_SP),sp_min)
 # Disable Neon support: sp_min runtime may conflict with non-secure world
 TF_CFLAGS		+=	-mfloat-abi=soft
@@ -427,5 +434,8 @@
 	$(eval ENTRY = $(shell cat $(@:.stm32=.map) | grep "__BL2_IMAGE_START" | awk '{print $$1}'))
 	${Q}${STM32IMAGE} -s $(word 2,$^) -d $@ \
 		-l $(LOADADDR) -e ${ENTRY} \
-		-v ${STM32_TF_VERSION}
+		-v ${STM32_TF_VERSION} \
+		-m ${STM32_HEADER_VERSION_MAJOR} \
+		-n ${STM32_HEADER_VERSION_MINOR} \
+		-b ${STM32_HEADER_BL2_BINARY_TYPE}
 	@echo
diff --git a/tools/stm32image/stm32image.c b/tools/stm32image/stm32image.c
index fb1dee0..bd4720c 100644
--- a/tools/stm32image/stm32image.c
+++ b/tools/stm32image/stm32image.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2022, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,16 +22,16 @@
 #define VER_MINOR		1
 #define VER_VARIANT		0
 #define HEADER_VERSION_V1	0x1
-#define TF_BINARY_TYPE		0x10
+#define HEADER_VERSION_V2	0x2
+#define PADDING_HEADER_MAGIC	__be32_to_cpu(0x5354FFFF)
+#define PADDING_HEADER_FLAG	(1 << 31)
+#define PADDING_HEADER_LENGTH	0x180
 
-/* Default option : bit0 => no signature */
-#define HEADER_DEFAULT_OPTION	(__cpu_to_le32(0x00000001))
-
-struct stm32_header {
+struct stm32_header_v1 {
 	uint32_t magic_number;
 	uint8_t image_signature[64];
 	uint32_t image_checksum;
-	uint8_t  header_version[4];
+	uint8_t header_version[4];
 	uint32_t image_length;
 	uint32_t image_entry_point;
 	uint32_t reserved1;
@@ -45,31 +45,50 @@
 	uint8_t binary_type;
 };
 
-static void stm32image_default_header(struct stm32_header *ptr)
+struct stm32_header_v2 {
+	uint32_t magic_number;
+	uint8_t image_signature[64];
+	uint32_t image_checksum;
+	uint8_t header_version[4];
+	uint32_t image_length;
+	uint32_t image_entry_point;
+	uint32_t reserved1;
+	uint32_t load_address;
+	uint32_t reserved2;
+	uint32_t version_number;
+	uint32_t extension_flags;
+	uint32_t extension_headers_length;
+	uint32_t binary_type;
+	uint8_t padding[16];
+	uint32_t extension_header_type;
+	uint32_t extension_header_length;
+	uint8_t extension_padding[376];
+};
+
+static void stm32image_default_header(void *ptr)
 {
-	if (!ptr) {
+	struct stm32_header_v1 *header = (struct stm32_header_v1 *)ptr;
+
+	if (!header) {
 		return;
 	}
 
-	ptr->magic_number = HEADER_MAGIC;
-	ptr->option_flags = HEADER_DEFAULT_OPTION;
-	ptr->ecdsa_algorithm = __cpu_to_le32(1);
-	ptr->version_number = __cpu_to_le32(0);
-	ptr->binary_type = TF_BINARY_TYPE;
+	header->magic_number = HEADER_MAGIC;
+	header->version_number = __cpu_to_le32(0);
 }
 
-static uint32_t stm32image_checksum(void *start, uint32_t len)
+static uint32_t stm32image_checksum(void *start, uint32_t len,
+				    uint32_t header_size)
 {
 	uint32_t csum = 0;
-	uint32_t hdr_len = sizeof(struct stm32_header);
 	uint8_t *p;
 
-	if (len < hdr_len) {
+	if (len < header_size) {
 		return 0;
 	}
 
-	p = (unsigned char *)start + hdr_len;
-	len -= hdr_len;
+	p = (unsigned char *)start + header_size;
+	len -= header_size;
 
 	while (len > 0) {
 		csum += *p;
@@ -82,7 +101,8 @@
 
 static void stm32image_print_header(const void *ptr)
 {
-	struct stm32_header *stm32hdr = (struct stm32_header *)ptr;
+	struct stm32_header_v1 *stm32hdr = (struct stm32_header_v1 *)ptr;
+	struct stm32_header_v2 *stm32hdr_v2 = (struct stm32_header_v2 *)ptr;
 
 	printf("Image Type   : ST Microelectronics STM32 V%d.%d\n",
 	       stm32hdr->header_version[VER_MAJOR],
@@ -95,40 +115,87 @@
 	       __le32_to_cpu(stm32hdr->image_entry_point));
 	printf("Checksum     : 0x%08x\n",
 	       __le32_to_cpu(stm32hdr->image_checksum));
-	printf("Option     : 0x%08x\n",
-	       __le32_to_cpu(stm32hdr->option_flags));
-	printf("Version	   : 0x%08x\n",
+
+	switch (stm32hdr->header_version[VER_MAJOR]) {
+	case HEADER_VERSION_V1:
+		printf("Option     : 0x%08x\n",
+		       __le32_to_cpu(stm32hdr->option_flags));
+		break;
+
+	case HEADER_VERSION_V2:
+		printf("Extension    : 0x%08x\n",
+		       __le32_to_cpu(stm32hdr_v2->extension_flags));
+		break;
+
+	default:
+		printf("Incorrect header version\n");
+	}
+
+	printf("Version	     : 0x%08x\n",
 	       __le32_to_cpu(stm32hdr->version_number));
 }
 
-static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd,
-				  uint32_t loadaddr, uint32_t ep, uint32_t ver,
-				  uint32_t major, uint32_t minor)
+static int stm32image_set_header(void *ptr, struct stat *sbuf, int ifd,
+				 uint32_t loadaddr, uint32_t ep, uint32_t ver,
+				 uint32_t major, uint32_t minor,
+				 uint32_t binary_type, uint32_t header_size)
 {
-	struct stm32_header *stm32hdr = (struct stm32_header *)ptr;
+	struct stm32_header_v1 *stm32hdr = (struct stm32_header_v1 *)ptr;
+	struct stm32_header_v2 *stm32hdr_v2 = (struct stm32_header_v2 *)ptr;
+	uint32_t ext_size = 0U;
+	uint32_t ext_flags = 0U;
 
-	stm32image_default_header(stm32hdr);
+	stm32image_default_header(ptr);
 
 	stm32hdr->header_version[VER_MAJOR] = major;
 	stm32hdr->header_version[VER_MINOR] = minor;
 	stm32hdr->load_address = __cpu_to_le32(loadaddr);
 	stm32hdr->image_entry_point = __cpu_to_le32(ep);
 	stm32hdr->image_length = __cpu_to_le32((uint32_t)sbuf->st_size -
-					     sizeof(struct stm32_header));
+					       header_size);
 	stm32hdr->image_checksum =
-		__cpu_to_le32(stm32image_checksum(ptr, sbuf->st_size));
+		__cpu_to_le32(stm32image_checksum(ptr, sbuf->st_size,
+						  header_size));
+
+	switch (stm32hdr->header_version[VER_MAJOR]) {
+	case HEADER_VERSION_V1:
+		/* Default option for header v1 : bit0 => no signature */
+		stm32hdr->option_flags = __cpu_to_le32(0x00000001);
+		stm32hdr->ecdsa_algorithm = __cpu_to_le32(1);
+		stm32hdr->binary_type = (uint8_t)binary_type;
+		break;
+
+	case HEADER_VERSION_V2:
+		stm32hdr_v2->binary_type = binary_type;
+		ext_size += PADDING_HEADER_LENGTH;
+		ext_flags |= PADDING_HEADER_FLAG;
+		stm32hdr_v2->extension_flags =
+			__cpu_to_le32(ext_flags);
+		stm32hdr_v2->extension_headers_length =
+			__cpu_to_le32(ext_size);
+		stm32hdr_v2->extension_header_type = PADDING_HEADER_MAGIC;
+		stm32hdr_v2->extension_header_length =
+			__cpu_to_le32(PADDING_HEADER_LENGTH);
+		break;
+
+	default:
+		return -1;
+	}
+
 	stm32hdr->version_number = __cpu_to_le32(ver);
+
+	return 0;
 }
 
 static int stm32image_create_header_file(char *srcname, char *destname,
 					 uint32_t loadaddr, uint32_t entry,
 					 uint32_t version, uint32_t major,
-					 uint32_t minor)
+					 uint32_t minor, uint32_t binary_type)
 {
-	int src_fd, dest_fd;
+	int src_fd, dest_fd, header_size;
 	struct stat sbuf;
 	unsigned char *ptr;
-	struct stm32_header stm32image_header;
+	void *stm32image_header;
 
 	dest_fd = open(destname, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666);
 	if (dest_fd == -1) {
@@ -154,15 +221,32 @@
 		return -1;
 	}
 
-	memset(&stm32image_header, 0, sizeof(struct stm32_header));
+	switch (major) {
+	case HEADER_VERSION_V1:
+		stm32image_header = malloc(sizeof(struct stm32_header_v1));
+		header_size = sizeof(struct stm32_header_v1);
+		break;
 
-	if (write(dest_fd, &stm32image_header, sizeof(struct stm32_header)) !=
-	    sizeof(struct stm32_header)) {
-		fprintf(stderr, "Write error %s: %s\n", destname,
-			strerror(errno));
+	case HEADER_VERSION_V2:
+		stm32image_header = malloc(sizeof(struct stm32_header_v2));
+		header_size = sizeof(struct stm32_header_v2);
+		break;
+
+	default:
 		return -1;
 	}
 
+	memset(stm32image_header, 0, header_size);
+	if (write(dest_fd, stm32image_header, header_size) !=
+	    header_size) {
+		fprintf(stderr, "Write error %s: %s\n", destname,
+			strerror(errno));
+		free(stm32image_header);
+		return -1;
+	}
+
+	free(stm32image_header);
+
 	if (write(dest_fd, ptr, sbuf.st_size) != sbuf.st_size) {
 		fprintf(stderr, "Write error on %s: %s\n", destname,
 			strerror(errno));
@@ -184,8 +268,11 @@
 		return -1;
 	}
 
-	stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr, entry, version,
-			      major, minor);
+	if (stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr,
+				  entry, version, major, minor,
+				  binary_type, header_size) != 0) {
+		return -1;
+	}
 
 	stm32image_print_header(ptr);
 
@@ -196,13 +283,22 @@
 
 int main(int argc, char *argv[])
 {
-	int opt, loadaddr = -1, entry = -1, err = 0, version = 0;
-	int major = HEADER_VERSION_V1;
+	int opt;
+	int loadaddr = -1;
+	int entry = -1;
+	int err = 0;
+	int version = 0;
+	int binary_type = -1;
+	int major = HEADER_VERSION_V2;
 	int minor = 0;
-	char *dest = NULL, *src = NULL;
+	char *dest = NULL;
+	char *src = NULL;
 
-	while ((opt = getopt(argc, argv, ":s:d:l:e:v:m:n:")) != -1) {
+	while ((opt = getopt(argc, argv, ":b:s:d:l:e:v:m:n:")) != -1) {
 		switch (opt) {
+		case 'b':
+			binary_type = strtol(optarg, NULL, 0);
+			break;
 		case 's':
 			src = optarg;
 			break;
@@ -226,7 +322,7 @@
 			break;
 		default:
 			fprintf(stderr,
-				"Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point] [-m major] [-n minor]\n",
+				"Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point] [-m major] [-n minor] [-b binary_type]\n",
 					argv[0]);
 			return -1;
 		}
@@ -252,8 +348,14 @@
 		return -1;
 	}
 
+	if (binary_type == -1) {
+		fprintf(stderr, "Missing -b option\n");
+		return -1;
+	}
+
 	err = stm32image_create_header_file(src, dest, loadaddr,
-					    entry, version, major, minor);
+					    entry, version, major, minor,
+					    binary_type);
 
 	return err;
 }