Message ID | 20230323110906.23783-5-masahisa.kojima@linaro.org |
---|---|
State | New |
Headers | show |
Series | FMP versioning support | expand |
On Thu, 23 Mar 2023 at 13:09, Masahisa Kojima <masahisa.kojima@linaro.org> wrote: > > Current mkeficapsule tool does not provide firmware > version management. EDK II 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> > --- > No update since v3 > > 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 | 31 +++++++++++++++++++++++++++ > tools/mkeficapsule.c | 51 +++++++++++++++++++++++++++++++++++++++----- > 3 files changed, 93 insertions(+), 5 deletions(-) > > 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..e5fa3398b6 100644 > --- a/tools/eficapsule.h > +++ b/tools/eficapsule.h > @@ -113,4 +113,35 @@ 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); > -- > 2.17.1 > Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
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..e5fa3398b6 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -113,4 +113,35 @@ 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);
Current mkeficapsule tool does not provide firmware version management. EDK II 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> --- No update since v3 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 | 31 +++++++++++++++++++++++++++ tools/mkeficapsule.c | 51 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 93 insertions(+), 5 deletions(-)