diff mbox series

[v3,4/4] mkeficapsule: add FMP Payload Header

Message ID 20230320055448.12439-5-masahisa.kojima@linaro.org
State Superseded
Headers show
Series FMP versioning support | expand

Commit Message

Masahisa Kojima March 20, 2023, 5:54 a.m. UTC
Current mkeficapsule tool does not provide firmware
version management. EDK2 reference implementation inserts
the FMP Payload Header right before the payload.
It coutains the fw_version and lowest supported version.

This commit adds two new parameters required to generate
the FMP Payload Header for mkeficapsule tool.
 '-v' indicates the firmware version.
 '-l' indicates the lowest supported version.

When mkeficapsule tool is invoked with neither '-v' nor '-l' option,
FMP Payload Header is not inserted, the behavior is same as
current implementation.

Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org>
---
Changes in v3:
- remove '-f' option
- move some definitions into tools/eficapsule.h
- add dependency check of fw_version and lowest_supported_version
- remove unexpected modification of existing fprintf() call
- add documentation

Newly created in v2

 doc/mkeficapsule.1   | 16 ++++++++++++++
 tools/eficapsule.h   | 32 +++++++++++++++++++++++++++
 tools/mkeficapsule.c | 51 +++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 94 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
index 1ca245a10f..7c62b03c73 100644
--- a/doc/mkeficapsule.1
+++ b/doc/mkeficapsule.1
@@ -61,6 +61,22 @@  Specify an image index
 .BI "-I\fR,\fB --instance " instance
 Specify a hardware instance
 
+.PP
+FMP Payload Header is inserted right before the payload if
+.BR --fw-version
+or
+.BR --lsv
+are specified
+
+
+.TP
+.BI "-v\fR,\fB --fw-version " firmware-version
+Specify a firmware version, 0 if omitted
+
+.TP
+.BI "-l\fR,\fB --lsv " lowest-supported-version
+Specify a lowest supported version, 0 if omitted
+
 .PP
 For generation of firmware accept empty capsule
 .BR --guid
diff --git a/tools/eficapsule.h b/tools/eficapsule.h
index 072a4b5598..72500d1f84 100644
--- a/tools/eficapsule.h
+++ b/tools/eficapsule.h
@@ -113,4 +113,36 @@  struct efi_firmware_image_authentication {
 	struct win_certificate_uefi_guid auth_info;
 } __packed;
 
+
+/* fmp payload header */
+#define SIGNATURE_16(A, B)	((A) | ((B) << 8))
+#define SIGNATURE_32(A, B, C, D)	\
+	(SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16))
+
+#define FMP_PAYLOAD_HDR_SIGNATURE	SIGNATURE_32('M', 'S', 'S', '1')
+
+/**
+ * struct fmp_payload_header - EDK2 header for the FMP payload
+ *
+ * This structure describes the header which is preprended to the
+ * FMP payload by the edk2 capsule generation scripts.
+ *
+ * @signature:			Header signature used to identify the header
+ * @header_size:		Size of the structure
+ * @fw_version:			Firmware versions used
+ * @lowest_supported_version:	Lowest supported version
+ */
+struct fmp_payload_header {
+	uint32_t signature;
+	uint32_t header_size;
+	uint32_t fw_version;
+	uint32_t lowest_supported_version;
+};
+
+struct fmp_payload_header_params {
+	bool have_header;
+	uint32_t fw_version;
+	uint32_t lowest_supported_version;
+};
+
 #endif /* _EFI_CAPSULE_H */
diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
index b71537beee..e50e6a8ed7 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -29,7 +29,7 @@  static const char *tool_name = "mkeficapsule";
 efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
 efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
 
-static const char *opts_short = "g:i:I:v:p:c:m:o:dhAR";
+static const char *opts_short = "g:i:I:v:l:p:c:m:o:dhAR";
 
 enum {
 	CAPSULE_NORMAL_BLOB = 0,
@@ -41,6 +41,8 @@  static struct option options[] = {
 	{"guid", required_argument, NULL, 'g'},
 	{"index", required_argument, NULL, 'i'},
 	{"instance", required_argument, NULL, 'I'},
+	{"fw-version", required_argument, NULL, 'v'},
+	{"lsv", required_argument, NULL, 'l'},
 	{"private-key", required_argument, NULL, 'p'},
 	{"certificate", required_argument, NULL, 'c'},
 	{"monotonic-count", required_argument, NULL, 'm'},
@@ -60,6 +62,8 @@  static void print_usage(void)
 		"\t-g, --guid <guid string>    guid for image blob type\n"
 		"\t-i, --index <index>         update image index\n"
 		"\t-I, --instance <instance>   update hardware instance\n"
+		"\t-v, --fw-version <version>  firmware version\n"
+		"\t-l, --lsv <version>         lowest supported version\n"
 		"\t-p, --private-key <privkey file>  private key file\n"
 		"\t-c, --certificate <cert file>     signer's certificate file\n"
 		"\t-m, --monotonic-count <count>     monotonic count\n"
@@ -402,6 +406,7 @@  static void free_sig_data(struct auth_context *ctx)
  */
 static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
 			unsigned long index, unsigned long instance,
+			struct fmp_payload_header_params *fmp_ph_params,
 			uint64_t mcount, char *privkey_file, char *cert_file,
 			uint16_t oemflags)
 {
@@ -410,10 +415,11 @@  static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
 	struct efi_firmware_management_capsule_image_header image;
 	struct auth_context auth_context;
 	FILE *f;
-	uint8_t *data;
+	uint8_t *data, *new_data, *buf;
 	off_t bin_size;
 	uint64_t offset;
 	int ret;
+	struct fmp_payload_header payload_header;
 
 #ifdef DEBUG
 	fprintf(stderr, "For output: %s\n", path);
@@ -423,6 +429,7 @@  static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
 	auth_context.sig_size = 0;
 	f = NULL;
 	data = NULL;
+	new_data = NULL;
 	ret = -1;
 
 	/*
@@ -431,12 +438,31 @@  static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
 	if (read_bin_file(bin, &data, &bin_size))
 		goto err;
 
+	buf = data;
+
+	/* insert fmp payload header right before the payload */
+	if (fmp_ph_params->have_header) {
+		new_data = malloc(bin_size + sizeof(payload_header));
+		if (!new_data)
+			goto err;
+
+		payload_header.signature = FMP_PAYLOAD_HDR_SIGNATURE;
+		payload_header.header_size = sizeof(payload_header);
+		payload_header.fw_version = fmp_ph_params->fw_version;
+		payload_header.lowest_supported_version =
+			fmp_ph_params->lowest_supported_version;
+		memcpy(new_data, &payload_header, sizeof(payload_header));
+		memcpy(new_data + sizeof(payload_header), data, bin_size);
+		buf = new_data;
+		bin_size += sizeof(payload_header);
+	}
+
 	/* first, calculate signature to determine its size */
 	if (privkey_file && cert_file) {
 		auth_context.key_file = privkey_file;
 		auth_context.cert_file = cert_file;
 		auth_context.auth.monotonic_count = mcount;
-		auth_context.image_data = data;
+		auth_context.image_data = buf;
 		auth_context.image_size = bin_size;
 
 		if (create_auth_data(&auth_context)) {
@@ -536,7 +562,7 @@  static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
 	/*
 	 * firmware binary
 	 */
-	if (write_capsule_file(f, data, bin_size, "Firmware binary"))
+	if (write_capsule_file(f, buf, bin_size, "Firmware binary"))
 		goto err;
 
 	ret = 0;
@@ -545,6 +571,7 @@  err:
 		fclose(f);
 	free_sig_data(&auth_context);
 	free(data);
+	free(new_data);
 
 	return ret;
 }
@@ -644,6 +671,7 @@  int main(int argc, char **argv)
 	unsigned long oemflags;
 	char *privkey_file, *cert_file;
 	int c, idx;
+	struct fmp_payload_header_params fmp_ph_params = { 0 };
 
 	guid = NULL;
 	index = 0;
@@ -679,6 +707,14 @@  int main(int argc, char **argv)
 		case 'I':
 			instance = strtoul(optarg, NULL, 0);
 			break;
+		case 'v':
+			fmp_ph_params.fw_version = strtoul(optarg, NULL, 0);
+			fmp_ph_params.have_header = true;
+			break;
+		case 'l':
+			fmp_ph_params.lowest_supported_version = strtoul(optarg, NULL, 0);
+			fmp_ph_params.have_header = true;
+			break;
 		case 'p':
 			if (privkey_file) {
 				fprintf(stderr,
@@ -744,6 +780,11 @@  int main(int argc, char **argv)
 		exit(EXIT_FAILURE);
 	}
 
+	if (fmp_ph_params.fw_version < fmp_ph_params.lowest_supported_version) {
+		fprintf(stderr, "fw_version is lower than lowest_supported_version\n");
+		exit(EXIT_FAILURE);
+	}
+
 	if (capsule_type != CAPSULE_NORMAL_BLOB) {
 		if (create_empty_capsule(argv[argc - 1], guid,
 					 capsule_type == CAPSULE_ACCEPT) < 0) {
@@ -751,7 +792,7 @@  int main(int argc, char **argv)
 			exit(EXIT_FAILURE);
 		}
 	} else 	if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
-				 index, instance, mcount, privkey_file,
+				 index, instance, &fmp_ph_params, mcount, privkey_file,
 				 cert_file, (uint16_t)oemflags) < 0) {
 		fprintf(stderr, "Creating firmware capsule failed\n");
 		exit(EXIT_FAILURE);