mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
mkeficapsule: Add support for generating empty capsules
The Dependable Boot specification[1] describes the structure of the firmware accept and revert capsules. These are empty capsules which are used for signalling the acceptance or rejection of the updated firmware by the OS. Add support for generating these empty capsules. [1] - https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org> Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
This commit is contained in:
parent
873cf8ac70
commit
6da9271af1
3 changed files with 119 additions and 14 deletions
|
@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot
|
||||||
|
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B mkeficapsule
|
.B mkeficapsule
|
||||||
.RI [ options "] " image-blob " " capsule-file
|
.RI [ options ] " " [ image-blob ] " " capsule-file
|
||||||
|
|
||||||
.SH "DESCRIPTION"
|
.SH "DESCRIPTION"
|
||||||
.B mkeficapsule
|
.B mkeficapsule
|
||||||
|
@ -23,8 +23,13 @@ Optionally, a capsule file can be signed with a given private key.
|
||||||
In this case, the update will be authenticated by verifying the signature
|
In this case, the update will be authenticated by verifying the signature
|
||||||
before applying.
|
before applying.
|
||||||
|
|
||||||
|
Additionally, an empty capsule file can be generated for acceptance or
|
||||||
|
rejection of firmware images by a governing component like an Operating
|
||||||
|
System. The empty capsules do not require an image-blob input file.
|
||||||
|
|
||||||
|
|
||||||
.B mkeficapsule
|
.B mkeficapsule
|
||||||
takes any type of image files, including:
|
takes any type of image files when generating non empty capsules, including:
|
||||||
.TP
|
.TP
|
||||||
.I raw image
|
.I raw image
|
||||||
format is a single binary blob of any type of firmware.
|
format is a single binary blob of any type of firmware.
|
||||||
|
@ -36,18 +41,16 @@ multiple binary blobs in a single capsule file.
|
||||||
This type of image file can be generated by
|
This type of image file can be generated by
|
||||||
.BR mkimage .
|
.BR mkimage .
|
||||||
|
|
||||||
.PP
|
|
||||||
If you want to use other types than above two, you should explicitly
|
|
||||||
specify a guid for the FMP driver.
|
|
||||||
|
|
||||||
.SH "OPTIONS"
|
.SH "OPTIONS"
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "-g\fR,\fB --guid " guid-string
|
.BI "-g\fR,\fB --guid " guid-string
|
||||||
Specify guid for image blob type. The format is:
|
Specify guid for image blob type. The format is:
|
||||||
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
|
||||||
The first three elements are in little endian, while the rest
|
The first three elements are in little endian, while the rest
|
||||||
is in big endian.
|
is in big endian. The option must be specified for all non empty and
|
||||||
|
image acceptance capsules
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "-i\fR,\fB --index " index
|
.BI "-i\fR,\fB --index " index
|
||||||
|
@ -57,6 +60,18 @@ Specify an image index
|
||||||
.BI "-I\fR,\fB --instance " instance
|
.BI "-I\fR,\fB --instance " instance
|
||||||
Specify a hardware instance
|
Specify a hardware instance
|
||||||
|
|
||||||
|
.PP
|
||||||
|
For generation of firmware accept empty capsule
|
||||||
|
.BR --guid
|
||||||
|
is mandatory
|
||||||
|
.TP
|
||||||
|
.BI "-A\fR,\fB --fw-accept "
|
||||||
|
Generate a firmware acceptance empty capsule
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "-R\fR,\fB --fw-revert "
|
||||||
|
Generate a firmware revert empty capsule
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR -h ", " --help
|
.BR -h ", " --help
|
||||||
Print a help message
|
Print a help message
|
||||||
|
|
|
@ -41,6 +41,14 @@ typedef struct {
|
||||||
EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
|
EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
|
||||||
0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
|
0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
|
||||||
|
|
||||||
|
#define FW_ACCEPT_OS_GUID \
|
||||||
|
EFI_GUID(0x0c996046, 0xbcc0, 0x4d04, 0x85, 0xec, \
|
||||||
|
0xe1, 0xfc, 0xed, 0xf1, 0xc6, 0xf8)
|
||||||
|
|
||||||
|
#define FW_REVERT_OS_GUID \
|
||||||
|
EFI_GUID(0xacd58b4b, 0xc0e8, 0x475f, 0x99, 0xb5, \
|
||||||
|
0x6b, 0x3f, 0x7e, 0x07, 0xaa, 0xf0)
|
||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000
|
#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,13 @@ static const char *tool_name = "mkeficapsule";
|
||||||
efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
|
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;
|
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:dh";
|
static const char *opts_short = "g:i:I:v:p:c:m:dhAR";
|
||||||
|
|
||||||
|
enum {
|
||||||
|
CAPSULE_NORMAL_BLOB = 0,
|
||||||
|
CAPSULE_ACCEPT,
|
||||||
|
CAPSULE_REVERT,
|
||||||
|
} capsule_type;
|
||||||
|
|
||||||
static struct option options[] = {
|
static struct option options[] = {
|
||||||
{"guid", required_argument, NULL, 'g'},
|
{"guid", required_argument, NULL, 'g'},
|
||||||
|
@ -39,6 +45,8 @@ static struct option options[] = {
|
||||||
{"certificate", required_argument, NULL, 'c'},
|
{"certificate", required_argument, NULL, 'c'},
|
||||||
{"monotonic-count", required_argument, NULL, 'm'},
|
{"monotonic-count", required_argument, NULL, 'm'},
|
||||||
{"dump-sig", no_argument, NULL, 'd'},
|
{"dump-sig", no_argument, NULL, 'd'},
|
||||||
|
{"fw-accept", no_argument, NULL, 'A'},
|
||||||
|
{"fw-revert", no_argument, NULL, 'R'},
|
||||||
{"help", no_argument, NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
{NULL, 0, NULL, 0},
|
{NULL, 0, NULL, 0},
|
||||||
};
|
};
|
||||||
|
@ -55,6 +63,8 @@ static void print_usage(void)
|
||||||
"\t-c, --certificate <cert file> signer's certificate file\n"
|
"\t-c, --certificate <cert file> signer's certificate file\n"
|
||||||
"\t-m, --monotonic-count <count> monotonic count\n"
|
"\t-m, --monotonic-count <count> monotonic count\n"
|
||||||
"\t-d, --dump_sig dump signature (*.p7)\n"
|
"\t-d, --dump_sig dump signature (*.p7)\n"
|
||||||
|
"\t-A, --fw-accept firmware accept capsule, requires GUID, no image blob\n"
|
||||||
|
"\t-R, --fw-revert firmware revert capsule, takes no GUID, no image blob\n"
|
||||||
"\t-h, --help print a help message\n",
|
"\t-h, --help print a help message\n",
|
||||||
tool_name);
|
tool_name);
|
||||||
}
|
}
|
||||||
|
@ -564,6 +574,49 @@ void convert_uuid_to_guid(unsigned char *buf)
|
||||||
buf[7] = c;
|
buf[7] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
|
||||||
|
{
|
||||||
|
struct efi_capsule_header header = { 0 };
|
||||||
|
FILE *f = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
efi_guid_t fw_accept_guid = FW_ACCEPT_OS_GUID;
|
||||||
|
efi_guid_t fw_revert_guid = FW_REVERT_OS_GUID;
|
||||||
|
efi_guid_t capsule_guid;
|
||||||
|
|
||||||
|
f = fopen(path, "w");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "cannot open %s\n", path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsule_guid = fw_accept ? fw_accept_guid : fw_revert_guid;
|
||||||
|
|
||||||
|
memcpy(&header.capsule_guid, &capsule_guid, sizeof(efi_guid_t));
|
||||||
|
header.header_size = sizeof(header);
|
||||||
|
header.flags = 0;
|
||||||
|
|
||||||
|
header.capsule_image_size = fw_accept ?
|
||||||
|
sizeof(header) + sizeof(efi_guid_t) : sizeof(header);
|
||||||
|
|
||||||
|
if (write_capsule_file(f, &header, sizeof(header),
|
||||||
|
"Capsule header"))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (fw_accept) {
|
||||||
|
if (write_capsule_file(f, guid, sizeof(*guid),
|
||||||
|
"FW Accept Capsule Payload"))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* main - main entry function of mkeficapsule
|
* main - main entry function of mkeficapsule
|
||||||
* @argc: Number of arguments
|
* @argc: Number of arguments
|
||||||
|
@ -592,6 +645,7 @@ int main(int argc, char **argv)
|
||||||
privkey_file = NULL;
|
privkey_file = NULL;
|
||||||
cert_file = NULL;
|
cert_file = NULL;
|
||||||
dump_sig = 0;
|
dump_sig = 0;
|
||||||
|
capsule_type = CAPSULE_NORMAL_BLOB;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
c = getopt_long(argc, argv, opts_short, options, &idx);
|
c = getopt_long(argc, argv, opts_short, options, &idx);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
|
@ -639,22 +693,50 @@ int main(int argc, char **argv)
|
||||||
case 'd':
|
case 'd':
|
||||||
dump_sig = 1;
|
dump_sig = 1;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'A':
|
||||||
|
if (capsule_type) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Select either of Accept or Revert capsule generation\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
capsule_type = CAPSULE_ACCEPT;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
if (capsule_type) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Select either of Accept or Revert capsule generation\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
capsule_type = CAPSULE_REVERT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
print_usage();
|
print_usage();
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check necessary parameters */
|
/* check necessary parameters */
|
||||||
if ((argc != optind + 2) || !guid ||
|
if ((capsule_type == CAPSULE_NORMAL_BLOB &&
|
||||||
((privkey_file && !cert_file) ||
|
((argc != optind + 2) || !guid ||
|
||||||
(!privkey_file && cert_file))) {
|
((privkey_file && !cert_file) ||
|
||||||
|
(!privkey_file && cert_file)))) ||
|
||||||
|
(capsule_type != CAPSULE_NORMAL_BLOB &&
|
||||||
|
((argc != optind + 1) ||
|
||||||
|
((capsule_type == CAPSULE_ACCEPT) && !guid) ||
|
||||||
|
((capsule_type == CAPSULE_REVERT) && guid)))) {
|
||||||
print_usage();
|
print_usage();
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance,
|
if (capsule_type != CAPSULE_NORMAL_BLOB) {
|
||||||
mcount, privkey_file, cert_file) < 0) {
|
if (create_empty_capsule(argv[argc - 1], guid,
|
||||||
|
capsule_type == CAPSULE_ACCEPT) < 0) {
|
||||||
|
fprintf(stderr, "Creating empty capsule failed\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
} else if (create_fwbin(argv[argc - 1], argv[argc - 2], guid,
|
||||||
|
index, instance, mcount, privkey_file,
|
||||||
|
cert_file) < 0) {
|
||||||
fprintf(stderr, "Creating firmware capsule failed\n");
|
fprintf(stderr, "Creating firmware capsule failed\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue