[PATCH 0/5] Support for dumping capsule headers and empty capsules

These set of patches are intended for two tasks. The first set of patches are adding support for dumping capsule header information, which is then being used in the binman test framework for testing the capsule generation. This replaces the current hardcoding of offsets used for verifying the capsule contents in the binman tests.
Patch 1 introduces this functionality in the mkeficapsule tool. Patch 3 is using this functionality in the binman tests for capsules.
The other set of patches, 4 and 5 are for adding support for generation of empty capsules in binman. The empty capsules are used for the FWU A/B update functionality.
Sughosh Ganu (5): tools: mkeficapsule: Add support to print capsule headers doc: capsule: Add documentation for the capsule dump feature binman: capsule: Use dumped capsule header contents for verification btool: mkeficapsule: Add support for EFI empty capsule generation binman: capsule: Add support for generating EFI empty capsules
doc/develop/uefi/uefi.rst | 17 ++ tools/binman/btool/mkeficapsule.py | 29 +++ tools/binman/etype/efi_empty_capsule.py | 91 +++++++ tools/binman/ftest.py | 145 ++++++++--- tools/binman/test/319_capsule_accept.dts | 16 ++ tools/binman/test/320_capsule_revert.dts | 14 ++ .../test/321_capsule_accept_missing_guid.dts | 14 ++ .../binman/test/322_capsule_accept_revert.dts | 17 ++ tools/eficapsule.h | 2 + tools/mkeficapsule.c | 229 +++++++++++++++++- 10 files changed, 533 insertions(+), 41 deletions(-) create mode 100644 tools/binman/etype/efi_empty_capsule.py create mode 100644 tools/binman/test/319_capsule_accept.dts create mode 100644 tools/binman/test/320_capsule_revert.dts create mode 100644 tools/binman/test/321_capsule_accept_missing_guid.dts create mode 100644 tools/binman/test/322_capsule_accept_revert.dts

Add support to dump the contents of capsule headers. This is useful as a debug feature for checking the contents of the capsule headers, and can also be used in capsule verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- tools/eficapsule.h | 2 + tools/mkeficapsule.c | 229 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 230 insertions(+), 1 deletion(-)
diff --git a/tools/eficapsule.h b/tools/eficapsule.h index 2099a2e9b8..6efd07d2eb 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -22,6 +22,8 @@ #define __aligned(x) __attribute__((__aligned__(x))) #endif
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + typedef struct { uint8_t b[16]; } efi_guid_t __aligned(8); diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 52be1f122e..28126e018b 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:p:c:m:o:dhARD";
enum { CAPSULE_NORMAL_BLOB = 0, @@ -49,6 +49,7 @@ static struct option options[] = { {"fw-accept", no_argument, NULL, 'A'}, {"fw-revert", no_argument, NULL, 'R'}, {"capoemflag", required_argument, NULL, 'o'}, + {"dump-capsule", no_argument, NULL, 'D'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -69,6 +70,7 @@ static void print_usage(void) "\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-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n" + "\t-D, --dump-capsule dump the contents of the capsule headers\n" "\t-h, --help print a help message\n", tool_name); } @@ -647,6 +649,217 @@ err: return ret; }
+static void print_guid(void *ptr) +{ + int i; + efi_guid_t *guid = ptr; + const uint8_t seq[] = { + 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, + '-', 8, 9, '-', 10, 11, 12, 13, 14, 15 }; + + for (i = 0; i < ARRAY_SIZE(seq); i++) { + if (seq[i] == '-') + putchar(seq[i]); + else + printf("%02X", guid->b[seq[i]]); + } + + printf("\n"); +} + +static uint32_t dump_fmp_payload_header( + struct fmp_payload_header *fmp_payload_hdr) +{ + uint32_t hdr_size = 0; + + if (fmp_payload_hdr->signature == FMP_PAYLOAD_HDR_SIGNATURE) { + printf("--------\n"); + printf("FMP_PAYLOAD_HDR.SIGNATURE\t\t\t: %08X\n", + FMP_PAYLOAD_HDR_SIGNATURE); + printf("FMP_PAYLOAD_HDR.HEADER_SIZE\t\t\t: %08X\n", + fmp_payload_hdr->header_size); + printf("FMP_PAYLOAD_HDR.FW_VERSION\t\t\t: %08X\n", + fmp_payload_hdr->fw_version); + printf("FMP_PAYLOAD_HDR.LOWEST_SUPPORTED_VERSION\t: %08X\n", + fmp_payload_hdr->lowest_supported_version); + hdr_size = fmp_payload_hdr->header_size; + } + + return hdr_size; +} + +static void dump_capsule_auth_header( + struct efi_firmware_image_authentication *capsule_auth_hdr) +{ + printf("EFI_FIRMWARE_IMAGE_AUTH.MONOTONIC_COUNT\t\t: %08lX\n", + capsule_auth_hdr->monotonic_count); + printf("EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.dwLENGTH\t: %08X\n", + capsule_auth_hdr->auth_info.hdr.dwLength); + printf("EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION\t: %08X\n", + capsule_auth_hdr->auth_info.hdr.wRevision); + printf("EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE\t: %08X\n", + capsule_auth_hdr->auth_info.hdr.wCertificateType); + printf("EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE\t: "); + print_guid(&capsule_auth_hdr->auth_info.cert_type); +} + +static void dump_fmp_capsule_image_header( + struct efi_firmware_management_capsule_image_header *image_hdr) +{ + void *capsule_auth_hdr; + void *fmp_payload_hdr; + uint64_t signature_size = 0; + uint32_t payload_size = 0; + uint32_t fmp_payload_hdr_size = 0; + struct efi_firmware_image_authentication *auth_hdr; + + printf("--------\n"); + printf("FMP_CAPSULE_IMAGE_HDR.VERSION\t\t\t: %08X\n", + image_hdr->version); + printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID\t: "); + print_guid(&image_hdr->update_image_type_id); + printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX\t: %08X\n", + image_hdr->update_image_index); + printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_SIZE\t\t: %08X\n", + image_hdr->update_image_size); + printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_VENDOR_CODE_SIZE\t: %08X\n", + image_hdr->update_vendor_code_size); + printf("FMP_CAPSULE_IMAGE_HDR.UPDATE_HARDWARE_INSTANCE\t: %08lX\n", + image_hdr->update_hardware_instance); + printf("FMP_CAPSULE_IMAGE_HDR.IMAGE_CAPSULE_SUPPORT\t: %08lX\n", + image_hdr->image_capsule_support); + + printf("--------\n"); + if (image_hdr->image_capsule_support & CAPSULE_SUPPORT_AUTHENTICATION) { + capsule_auth_hdr = (char *)image_hdr + sizeof(*image_hdr); + dump_capsule_auth_header(capsule_auth_hdr); + + auth_hdr = capsule_auth_hdr; + signature_size = sizeof(auth_hdr->monotonic_count) + + auth_hdr->auth_info.hdr.dwLength; + fmp_payload_hdr = (char *)capsule_auth_hdr + signature_size; + } else { + printf("Capsule Authentication Not Enabled\n"); + fmp_payload_hdr = (char *)image_hdr + sizeof(*image_hdr); + } + + fmp_payload_hdr_size = dump_fmp_payload_header(fmp_payload_hdr); + + payload_size = image_hdr->update_image_size - signature_size - + fmp_payload_hdr_size; + printf("--------\n"); + printf("Payload Image Size\t\t\t\t: %08X\n", payload_size); +} + +static void dump_fmp_header( + struct efi_firmware_management_capsule_header *fmp_hdr) +{ + int i; + void *capsule_image_hdr; + + printf("EFI_FMP_HDR.VERSION\t\t\t\t: %08X\n", fmp_hdr->version); + printf("EFI_FMP_HDR.EMBEDDED_DRIVER_COUNT\t\t: %08X\n", + fmp_hdr->embedded_driver_count); + printf("EFI_FMP_HDR.PAYLOAD_ITEM_COUNT\t\t\t: %08X\n", + fmp_hdr->payload_item_count); + + /* + * We currently don't support Embedded Drivers. + * Only worry about the payload items. + */ + for (i = 0; i < fmp_hdr->payload_item_count; i++) { + capsule_image_hdr = (char *)fmp_hdr + + fmp_hdr->item_offset_list[i]; + dump_fmp_capsule_image_header(capsule_image_hdr); + } +} + +static void dump_capsule_header(struct efi_capsule_header *capsule_hdr) +{ + printf("EFI_CAPSULE_HDR.CAPSULE_GUID\t\t\t: "); + print_guid((void *)&capsule_hdr->capsule_guid); + printf("EFI_CAPSULE_HDR.HEADER_SIZE\t\t\t: %08X\n", + capsule_hdr->header_size); + printf("EFI_CAPSULE_HDR.FLAGS\t\t\t\t: %08X\n", capsule_hdr->flags); + printf("EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE\t\t: %08X\n", + capsule_hdr->capsule_image_size); +} + +static void normal_capsule_dump(void *capsule_buf) +{ + void *fmp_hdr; + struct efi_capsule_header *hdr = capsule_buf; + + dump_capsule_header(hdr); + printf("--------\n"); + + fmp_hdr = (char *)capsule_buf + sizeof(*hdr); + dump_fmp_header(fmp_hdr); +} + +static void empty_capsule_dump(void *capsule_buf) +{ + efi_guid_t *accept_image_guid; + struct efi_capsule_header *hdr = capsule_buf; + efi_guid_t efi_empty_accept_capsule = FW_ACCEPT_OS_GUID; + + dump_capsule_header(hdr); + + if (!memcmp(&efi_empty_accept_capsule, &hdr->capsule_guid, + sizeof(efi_guid_t))) { + accept_image_guid = (void *)(char *)capsule_buf + + sizeof(struct efi_capsule_header); + printf("--------\n"); + printf("ACCEPT_IMAGE_GUID\t\t\t\t: "); + print_guid(accept_image_guid); + } +} + +static void dump_capsule_contents(char *capsule_file) +{ + int fd; + char *ptr; + efi_guid_t efi_fmp_guid = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; + efi_guid_t efi_empty_accept_capsule = FW_ACCEPT_OS_GUID; + efi_guid_t efi_empty_revert_capsule = FW_REVERT_OS_GUID; + struct stat sbuf; + + if (!capsule_file) { + fprintf(stderr, "No capsule file provided\n"); + exit(EXIT_FAILURE); + } + + if ((fd = open(capsule_file, O_RDONLY)) < 0) { + fprintf(stderr, "Error opening capsule file: %s\n", + capsule_file); + exit(EXIT_FAILURE); + } + + if (fstat(fd, &sbuf) < 0) { + fprintf(stderr, "Can't stat capsule file: %s\n", capsule_file); + exit(EXIT_FAILURE); + } + + if ((ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) + == MAP_FAILED) { + fprintf(stderr, "Can't mmap capsule file: %s\n", capsule_file); + exit(EXIT_FAILURE); + } + + if (!memcmp(&efi_fmp_guid, ptr, sizeof(efi_guid_t))) { + normal_capsule_dump(ptr); + } else if (!memcmp(&efi_empty_accept_capsule, ptr, + sizeof(efi_guid_t)) || + !memcmp(&efi_empty_revert_capsule, ptr, + sizeof(efi_guid_t))) { + empty_capsule_dump(ptr); + } else { + fprintf(stderr, "Unable to decode the capsule file: %s\n", + capsule_file); + exit(EXIT_FAILURE); + } +} + /** * main - main entry function of mkeficapsule * @argc: Number of arguments @@ -666,6 +879,7 @@ int main(int argc, char **argv) unsigned long index, instance; uint64_t mcount; unsigned long oemflags; + bool capsule_dump; char *privkey_file, *cert_file; int c, idx; struct fmp_payload_header_params fmp_ph_params = { 0 }; @@ -676,6 +890,7 @@ int main(int argc, char **argv) mcount = 0; privkey_file = NULL; cert_file = NULL; + capsule_dump = false; dump_sig = 0; capsule_type = CAPSULE_NORMAL_BLOB; oemflags = 0; @@ -754,12 +969,24 @@ int main(int argc, char **argv) exit(1); } break; + case 'D': + capsule_dump = true; + break; default: print_usage(); exit(EXIT_SUCCESS); } }
+ if (capsule_dump) { + if (argc != optind + 1) { + fprintf(stderr, "Must provide the capsule file to parse\n"); + exit(EXIT_FAILURE); + } + dump_capsule_contents(argv[argc - 1]); + exit(EXIT_SUCCESS); + } + /* check necessary parameters */ if ((capsule_type == CAPSULE_NORMAL_BLOB && ((argc != optind + 2) || !guid ||

On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add support to dump the contents of capsule headers. This is useful as a debug feature for checking the contents of the capsule headers, and can also be used in capsule verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/eficapsule.h | 2 + tools/mkeficapsule.c | 229 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 230 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

Add documentation to explain the printing of the capsule headers through the mkeficapsule tool.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- doc/develop/uefi/uefi.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index 68f9b332d1..f16580e169 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -385,6 +385,23 @@ capsules. Refer :ref:`etype_efi_capsule` for documentation about the efi-capsule binman entry type, which describes all the properties that can be specified.
+Dumping capsule headers +*********************** + +The mkeficapsule tool also provides a command-line option to dump the +contents of the capsule header. This is a useful functionality when +trying to understand the structure of a capsule and is also used in +capsule verification. This feature is used in testing the capsule +contents in binman's test framework. + +To check the contents of the capsule headers, the mkeficapsule command +can be used. + +.. code-block:: console + + $ mkeficapsule --dump-capsule \ + <capsule_file_name> + Performing the update *********************

On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add documentation to explain the printing of the capsule headers through the mkeficapsule tool.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
doc/develop/uefi/uefi.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

The various fields of a generated capsule are currently verified through hard-coded offsets. Use the dump-capsule feature for dumping the capsule header contents and use those for capsule verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- tools/binman/ftest.py | 95 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 41 deletions(-)
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 8e419645a6..2b8871ab7e 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -121,9 +121,11 @@ COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd'] TEE_ADDR = 0x5678
# Firmware Management Protocol(FMP) GUID -FW_MGMT_GUID = 'edd5cb6d2de8444cbda17194199ad92a' +FW_MGMT_GUID = '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' # Image GUID specified in the DTS -CAPSULE_IMAGE_GUID = '52cfd7092007104791d108469b7fe9c8' +CAPSULE_IMAGE_GUID = '09D7CF52-0720-4710-91D1-08469B7FE9C8' +# Windows cert GUID +WIN_CERT_TYPE_EFI_GUID = '4AAFD29D-68DF-49EE-8AA9-347D375665A7'
class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -7223,52 +7225,63 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertRegex(err, "Image 'image'.*missing bintools.*: bootgen")
+ def _GetCapsuleHeaders(self, data): + capsule_file = os.path.join(self._indir, 'test.capsule') + tools.write_file(capsule_file, data) + + out = tools.run('mkeficapsule', '--dump-capsule', capsule_file) + lines = out.splitlines() + + re_line = re.compile(r'^([^:-\t]*)(?:\t*\s*:\s*(.*))?$') + vals = collections.defaultdict(list) + for line in lines: + mat = re_line.match(line) + if mat: + vals[mat.group(1)] = mat.group(2) + + return vals + def _CheckCapsule(self, data, signed_capsule=False, version_check=False, capoemflags=False): - fmp_signature = "4d535331" # 'M', 'S', 'S', '1' - fmp_size = "10" - fmp_fw_version = "02" - oemflag = "0080" + fmp_signature = "3153534D" # 'M', 'S', 'S', '1' + fmp_size = "00000010" + fmp_fw_version = "00000002" + capsule_image_index = "00000001" + oemflag = "00018000" + auth_hdr_revision = "00000200" + auth_hdr_cert_type = "00000EF1"
- payload_data = EFI_CAPSULE_DATA + payload_data_len = len(EFI_CAPSULE_DATA)
- # TODO - Currently, these offsets for capsule fields are hardcoded. - # There are plans to add support to the mkeficapsule tool to dump - # the capsule contents which can then be used for capsule - # verification. + hdr = self._GetCapsuleHeaders(data)
- # Firmware Management Protocol(FMP) GUID - offset(0 - 32) - self.assertEqual(FW_MGMT_GUID, data.hex()[:32]) - # Image GUID - offset(96 - 128) - self.assertEqual(CAPSULE_IMAGE_GUID, data.hex()[96:128]) + self.assertEqual(FW_MGMT_GUID, hdr['EFI_CAPSULE_HDR.CAPSULE_GUID']) + + self.assertEqual(CAPSULE_IMAGE_GUID, + hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID']) + self.assertEqual(capsule_image_index, + hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
if capoemflags: - # OEM Flags - offset(40 - 44) - self.assertEqual(oemflag, data.hex()[40:44]) - if signed_capsule and version_check: - # FMP header signature - offset(4770 - 4778) - self.assertEqual(fmp_signature, data.hex()[4770:4778]) - # FMP header size - offset(4778 - 4780) - self.assertEqual(fmp_size, data.hex()[4778:4780]) - # firmware version - offset(4786 - 4788) - self.assertEqual(fmp_fw_version, data.hex()[4786:4788]) - # payload offset signed capsule(4802 - 4808) - self.assertEqual(payload_data.hex(), data.hex()[4802:4808]) - elif signed_capsule: - # payload offset signed capsule(4770 - 4776) - self.assertEqual(payload_data.hex(), data.hex()[4770:4776]) - elif version_check: - # FMP header signature - offset(184 - 192) - self.assertEqual(fmp_signature, data.hex()[184:192]) - # FMP header size - offset(192 - 194) - self.assertEqual(fmp_size, data.hex()[192:194]) - # firmware version - offset(200 - 202) - self.assertEqual(fmp_fw_version, data.hex()[200:202]) - # payload offset for non-signed capsule with version header(216 - 222) - self.assertEqual(payload_data.hex(), data.hex()[216:222]) - else: - # payload offset for non-signed capsule with no version header(184 - 190) - self.assertEqual(payload_data.hex(), data.hex()[184:190]) + self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS']) + + if signed_capsule: + self.assertEqual(auth_hdr_revision, + hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION']) + self.assertEqual(auth_hdr_cert_type, + hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE']) + self.assertEqual(WIN_CERT_TYPE_EFI_GUID, + hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE']) + + if version_check: + self.assertEqual(fmp_signature, + hdr['FMP_PAYLOAD_HDR.SIGNATURE']) + self.assertEqual(fmp_size, + hdr['FMP_PAYLOAD_HDR.HEADER_SIZE']) + self.assertEqual(fmp_fw_version, + hdr['FMP_PAYLOAD_HDR.FW_VERSION']) + + self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
def testCapsuleGen(self): """Test generation of EFI capsule"""

Hi Sughosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The various fields of a generated capsule are currently verified through hard-coded offsets. Use the dump-capsule feature for dumping the capsule header contents and use those for capsule verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/ftest.py | 95 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 41 deletions(-)
This looks good apart from a few nits below. However, the tests fail for me.
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 8e419645a6..2b8871ab7e 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -121,9 +121,11 @@ COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd'] TEE_ADDR = 0x5678
# Firmware Management Protocol(FMP) GUID -FW_MGMT_GUID = 'edd5cb6d2de8444cbda17194199ad92a' +FW_MGMT_GUID = '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' # Image GUID specified in the DTS -CAPSULE_IMAGE_GUID = '52cfd7092007104791d108469b7fe9c8' +CAPSULE_IMAGE_GUID = '09D7CF52-0720-4710-91D1-08469B7FE9C8' +# Windows cert GUID +WIN_CERT_TYPE_EFI_GUID = '4AAFD29D-68DF-49EE-8AA9-347D375665A7'
Please use lower-case hex
class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -7223,52 +7225,63 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertRegex(err, "Image 'image'.*missing bintools.*: bootgen")
- def _GetCapsuleHeaders(self, data):
This should have a function comment so it is clear what it is doing, returning.
capsule_file = os.path.join(self._indir, 'test.capsule')
tools.write_file(capsule_file, data)
out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
lines = out.splitlines()
re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
vals = collections.defaultdict(list)
for line in lines:
mat = re_line.match(line)
if mat:
vals[mat.group(1)] = mat.group(2)
return vals
[..]
Regards, Simon

hi Simon,
On Sun, 8 Oct 2023 at 04:41, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The various fields of a generated capsule are currently verified through hard-coded offsets. Use the dump-capsule feature for dumping the capsule header contents and use those for capsule verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/ftest.py | 95 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 41 deletions(-)
This looks good apart from a few nits below. However, the tests fail for me.
Can you please specify which tests fail, and the way to reproduce the failures? I ran the tests before sending the patches, and they ran fine, including the coverage which is 100%. Ci too did not complain.
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 8e419645a6..2b8871ab7e 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -121,9 +121,11 @@ COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd'] TEE_ADDR = 0x5678
# Firmware Management Protocol(FMP) GUID -FW_MGMT_GUID = 'edd5cb6d2de8444cbda17194199ad92a' +FW_MGMT_GUID = '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' # Image GUID specified in the DTS -CAPSULE_IMAGE_GUID = '52cfd7092007104791d108469b7fe9c8' +CAPSULE_IMAGE_GUID = '09D7CF52-0720-4710-91D1-08469B7FE9C8' +# Windows cert GUID +WIN_CERT_TYPE_EFI_GUID = '4AAFD29D-68DF-49EE-8AA9-347D375665A7'
Please use lower-case hex
Okay
class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -7223,52 +7225,63 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertRegex(err, "Image 'image'.*missing bintools.*: bootgen")
- def _GetCapsuleHeaders(self, data):
This should have a function comment so it is clear what it is doing, returning.
Will add
-sughosh
capsule_file = os.path.join(self._indir, 'test.capsule')
tools.write_file(capsule_file, data)
out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
lines = out.splitlines()
re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
vals = collections.defaultdict(list)
for line in lines:
mat = re_line.match(line)
if mat:
vals[mat.group(1)] = mat.group(2)
return vals
[..]
Regards, Simon

Hi Sughosh,
On Mon, 9 Oct 2023 at 01:46, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Sun, 8 Oct 2023 at 04:41, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org
wrote:
The various fields of a generated capsule are currently verified through hard-coded offsets. Use the dump-capsule feature for dumping the capsule header contents and use those for capsule verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/ftest.py | 95
++++++++++++++++++++++++-------------------
1 file changed, 54 insertions(+), 41 deletions(-)
This looks good apart from a few nits below. However, the tests fail
for me.
Can you please specify which tests fail, and the way to reproduce the failures? I ran the tests before sending the patches, and they ran fine, including the coverage which is 100%. Ci too did not complain.
Sure, for example:
$ binman test testCapsuleGen ======================== Running binman tests ======================== /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used return io.open(fd, mode, buffering, encoding, *args, **kwargs) /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used return io.open(fd, mode, buffering, encoding, *args, **kwargs) F ====================================================================== FAIL: binman.ftest.TestFunctional.testCapsuleGen (subunit.RemotedTestCase) binman.ftest.TestFunctional.testCapsuleGen ---------------------------------------------------------------------- testtools.testresult.real._StringException: Traceback (most recent call last): AssertionError: '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' != []
---------------------------------------------------------------------- Ran 1 test in 0.147s
FAILED (failures=1)
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 8e419645a6..2b8871ab7e 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -121,9 +121,11 @@ COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4',
'lzma_alone', 'lzop', 'xz', 'zstd']
TEE_ADDR = 0x5678
# Firmware Management Protocol(FMP) GUID -FW_MGMT_GUID = 'edd5cb6d2de8444cbda17194199ad92a' +FW_MGMT_GUID = '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' # Image GUID specified in the DTS -CAPSULE_IMAGE_GUID = '52cfd7092007104791d108469b7fe9c8' +CAPSULE_IMAGE_GUID = '09D7CF52-0720-4710-91D1-08469B7FE9C8' +# Windows cert GUID +WIN_CERT_TYPE_EFI_GUID = '4AAFD29D-68DF-49EE-8AA9-347D375665A7'
Please use lower-case hex
Okay
class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -7223,52 +7225,63 @@ fdt fdtmap Extract the
devicetree blob from the fdtmap
self.assertRegex(err, "Image 'image'.*missing bintools.*:
bootgen")
- def _GetCapsuleHeaders(self, data):
This should have a function comment so it is clear what it is doing,
returning.
Will add
-sughosh
capsule_file = os.path.join(self._indir, 'test.capsule')
tools.write_file(capsule_file, data)
out = tools.run('mkeficapsule', '--dump-capsule',
capsule_file)
lines = out.splitlines()
re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
vals = collections.defaultdict(list)
for line in lines:
mat = re_line.match(line)
if mat:
vals[mat.group(1)] = mat.group(2)
return vals
[..]
Regards, Simon
Regards, SImon

hi Simon,
On Mon, 9 Oct 2023 at 23:27, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Mon, 9 Oct 2023 at 01:46, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Sun, 8 Oct 2023 at 04:41, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The various fields of a generated capsule are currently verified through hard-coded offsets. Use the dump-capsule feature for dumping the capsule header contents and use those for capsule verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/ftest.py | 95 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 41 deletions(-)
This looks good apart from a few nits below. However, the tests fail for me.
Can you please specify which tests fail, and the way to reproduce the failures? I ran the tests before sending the patches, and they ran fine, including the coverage which is 100%. Ci too did not complain.
Sure, for example:
$ binman test testCapsuleGen ======================== Running binman tests ======================== /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used return io.open(fd, mode, buffering, encoding, *args, **kwargs) /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used return io.open(fd, mode, buffering, encoding, *args, **kwargs) F ====================================================================== FAIL: binman.ftest.TestFunctional.testCapsuleGen (subunit.RemotedTestCase) binman.ftest.TestFunctional.testCapsuleGen
testtools.testresult.real._StringException: Traceback (most recent call last): AssertionError: '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' != []
Ran 1 test in 0.147s
FAILED (failures=1)
That is interesting. When I run the tests, they run just fine. I had tested them before sending the patches. For e.g.
./tools/binman/binman test testCapsuleGen ======================== Running binman tests ======================== . ---------------------------------------------------------------------- Ran 1 test in 0.375s
OK
-sughosh
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 8e419645a6..2b8871ab7e 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -121,9 +121,11 @@ COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd'] TEE_ADDR = 0x5678
# Firmware Management Protocol(FMP) GUID -FW_MGMT_GUID = 'edd5cb6d2de8444cbda17194199ad92a' +FW_MGMT_GUID = '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' # Image GUID specified in the DTS -CAPSULE_IMAGE_GUID = '52cfd7092007104791d108469b7fe9c8' +CAPSULE_IMAGE_GUID = '09D7CF52-0720-4710-91D1-08469B7FE9C8' +# Windows cert GUID +WIN_CERT_TYPE_EFI_GUID = '4AAFD29D-68DF-49EE-8AA9-347D375665A7'
Please use lower-case hex
Okay
class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -7223,52 +7225,63 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertRegex(err, "Image 'image'.*missing bintools.*: bootgen")
- def _GetCapsuleHeaders(self, data):
This should have a function comment so it is clear what it is doing, returning.
Will add
-sughosh
capsule_file = os.path.join(self._indir, 'test.capsule')
tools.write_file(capsule_file, data)
out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
lines = out.splitlines()
re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
vals = collections.defaultdict(list)
for line in lines:
mat = re_line.match(line)
if mat:
vals[mat.group(1)] = mat.group(2)
return vals
[..]
Regards, Simon
Regards, SImon

Hi Sughosh,
On Mon, 9 Oct 2023 at 13:41, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Mon, 9 Oct 2023 at 23:27, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Mon, 9 Oct 2023 at 01:46, Sughosh Ganu sughosh.ganu@linaro.org
wrote:
hi Simon,
On Sun, 8 Oct 2023 at 04:41, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org
wrote:
The various fields of a generated capsule are currently verified through hard-coded offsets. Use the dump-capsule feature for
dumping
the capsule header contents and use those for capsule
verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/ftest.py | 95
++++++++++++++++++++++++-------------------
1 file changed, 54 insertions(+), 41 deletions(-)
This looks good apart from a few nits below. However, the tests
fail for me.
Can you please specify which tests fail, and the way to reproduce the failures? I ran the tests before sending the patches, and they ran fine, including the coverage which is 100%. Ci too did not complain.
Sure, for example:
$ binman test testCapsuleGen ======================== Running binman tests ======================== /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering
(buffering=1) isn't supported in binary mode, the default buffer size will be used
return io.open(fd, mode, buffering, encoding, *args, **kwargs) /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering
(buffering=1) isn't supported in binary mode, the default buffer size will be used
return io.open(fd, mode, buffering, encoding, *args, **kwargs) F ====================================================================== FAIL: binman.ftest.TestFunctional.testCapsuleGen
(subunit.RemotedTestCase)
binman.ftest.TestFunctional.testCapsuleGen
testtools.testresult.real._StringException: Traceback (most recent call
last):
AssertionError: '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' != []
Ran 1 test in 0.147s
FAILED (failures=1)
That is interesting. When I run the tests, they run just fine. I had tested them before sending the patches. For e.g.
./tools/binman/binman test testCapsuleGen ======================== Running binman tests ======================== .
Ran 1 test in 0.375s
OK
Yes, I'm not sure what that is. Perhaps you have a required tool in your path? But in that case I would expect to get some sort of error.
[..]
Regards, Simon

hi Simon,
On Tue, 10 Oct 2023 at 20:27, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Mon, 9 Oct 2023 at 13:41, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Mon, 9 Oct 2023 at 23:27, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Mon, 9 Oct 2023 at 01:46, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Sun, 8 Oct 2023 at 04:41, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The various fields of a generated capsule are currently verified through hard-coded offsets. Use the dump-capsule feature for dumping the capsule header contents and use those for capsule verification.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/ftest.py | 95 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 41 deletions(-)
This looks good apart from a few nits below. However, the tests fail for me.
Can you please specify which tests fail, and the way to reproduce the failures? I ran the tests before sending the patches, and they ran fine, including the coverage which is 100%. Ci too did not complain.
Sure, for example:
$ binman test testCapsuleGen ======================== Running binman tests ======================== /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used return io.open(fd, mode, buffering, encoding, *args, **kwargs) /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used return io.open(fd, mode, buffering, encoding, *args, **kwargs) F ====================================================================== FAIL: binman.ftest.TestFunctional.testCapsuleGen (subunit.RemotedTestCase) binman.ftest.TestFunctional.testCapsuleGen
testtools.testresult.real._StringException: Traceback (most recent call last): AssertionError: '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' != []
Ran 1 test in 0.147s
FAILED (failures=1)
That is interesting. When I run the tests, they run just fine. I had tested them before sending the patches. For e.g.
./tools/binman/binman test testCapsuleGen ======================== Running binman tests ======================== .
Ran 1 test in 0.375s
OK
Yes, I'm not sure what that is. Perhaps you have a required tool in your path? But in that case I would expect to get some sort of error.
I don't have any special tool in my path. Just that I build tools before invoking the tests, since the mkeficapsule tool needs to have been present. Moreover, the tests are also passing in the CI run. So it seems to be something specific in your setup I guess.
-sughosh

Hi Sughosh,
On Tue, 10 Oct 2023 at 09:01, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Tue, 10 Oct 2023 at 20:27, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Mon, 9 Oct 2023 at 13:41, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Mon, 9 Oct 2023 at 23:27, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Mon, 9 Oct 2023 at 01:46, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Sun, 8 Oct 2023 at 04:41, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote: > > The various fields of a generated capsule are currently verified > through hard-coded offsets. Use the dump-capsule feature for dumping > the capsule header contents and use those for capsule verification. > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > --- > tools/binman/ftest.py | 95 ++++++++++++++++++++++++------------------- > 1 file changed, 54 insertions(+), 41 deletions(-)
This looks good apart from a few nits below. However, the tests fail for me.
Can you please specify which tests fail, and the way to reproduce the failures? I ran the tests before sending the patches, and they ran fine, including the coverage which is 100%. Ci too did not complain.
Sure, for example:
$ binman test testCapsuleGen ======================== Running binman tests ======================== /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used return io.open(fd, mode, buffering, encoding, *args, **kwargs) /usr/lib/python3.10/os.py:1030: RuntimeWarning: line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used return io.open(fd, mode, buffering, encoding, *args, **kwargs) F ====================================================================== FAIL: binman.ftest.TestFunctional.testCapsuleGen (subunit.RemotedTestCase) binman.ftest.TestFunctional.testCapsuleGen
testtools.testresult.real._StringException: Traceback (most recent call last): AssertionError: '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' != []
Ran 1 test in 0.147s
FAILED (failures=1)
That is interesting. When I run the tests, they run just fine. I had tested them before sending the patches. For e.g.
./tools/binman/binman test testCapsuleGen ======================== Running binman tests ======================== .
Ran 1 test in 0.375s
OK
Yes, I'm not sure what that is. Perhaps you have a required tool in your path? But in that case I would expect to get some sort of error.
I don't have any special tool in my path. Just that I build tools before invoking the tests, since the mkeficapsule tool needs to have been present. Moreover, the tests are also passing in the CI run. So it seems to be something specific in your setup I guess.
Yes, I suppose so...I'll try the new version and try to figure it out.
Regards, Simon

Add a method to the mkeficapsule bintool to generate empty capsules. These are capsules needed for the FWU A/B update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- tools/binman/btool/mkeficapsule.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/tools/binman/btool/mkeficapsule.py b/tools/binman/btool/mkeficapsule.py index 61179747ff..89c0adfc9f 100644 --- a/tools/binman/btool/mkeficapsule.py +++ b/tools/binman/btool/mkeficapsule.py @@ -80,6 +80,35 @@ class Bintoolmkeficapsule(bintool.Bintool):
return self.run_cmd(*args)
+ def generate_empty_capsule(self, accept, revert, image_guid, + output_fname): + """Generate empty capsules for FWU A/B updates + + Args: + accept (int): Generate an accept capsule + revert (int): Generate a revert capsule + image_guid (str): GUID used for identifying the image + output_fname (str): Path to the output capsule file + + Returns: + str: Tool output + """ + if accept: + args = [ + f'--guid={image_guid}', + '--fw-accept' + ] + elif revert: + args = [ + '--fw-revert' + ] + + args += [ + output_fname + ] + + return self.run_cmd(*args) + def fetch(self, method): """Fetch handler for mkeficapsule

Hi Sugosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add a method to the mkeficapsule bintool to generate empty capsules. These are capsules needed for the FWU A/B update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/btool/mkeficapsule.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/tools/binman/btool/mkeficapsule.py b/tools/binman/btool/mkeficapsule.py index 61179747ff..89c0adfc9f 100644 --- a/tools/binman/btool/mkeficapsule.py +++ b/tools/binman/btool/mkeficapsule.py @@ -80,6 +80,35 @@ class Bintoolmkeficapsule(bintool.Bintool):
return self.run_cmd(*args)
- def generate_empty_capsule(self, accept, revert, image_guid,
Instead of two separate bools, how about an 'operation' param, a string which is either accept or revert? Or perhaps just have 'accept' and pass True or False?
output_fname):
"""Generate empty capsules for FWU A/B updates
Args:
accept (int): Generate an accept capsule
revert (int): Generate a revert capsule
image_guid (str): GUID used for identifying the image
output_fname (str): Path to the output capsule file
Returns:
str: Tool output
"""
if accept:
args = [
f'--guid={image_guid}',
'--fw-accept'
]
elif revert:
args = [
'--fw-revert'
]
That can be on none line
args += [
output_fname
]
Same here
return self.run_cmd(*args)
- def fetch(self, method): """Fetch handler for mkeficapsule
-- 2.34.1
Regards, Simon

hi Simon,
On Sun, 8 Oct 2023 at 04:42, Simon Glass sjg@chromium.org wrote:
Hi Sugosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add a method to the mkeficapsule bintool to generate empty capsules. These are capsules needed for the FWU A/B update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/btool/mkeficapsule.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/tools/binman/btool/mkeficapsule.py b/tools/binman/btool/mkeficapsule.py index 61179747ff..89c0adfc9f 100644 --- a/tools/binman/btool/mkeficapsule.py +++ b/tools/binman/btool/mkeficapsule.py @@ -80,6 +80,35 @@ class Bintoolmkeficapsule(bintool.Bintool):
return self.run_cmd(*args)
- def generate_empty_capsule(self, accept, revert, image_guid,
Instead of two separate bools, how about an 'operation' param, a string which is either accept or revert? Or perhaps just have 'accept' and pass True or False?
Okay incorporate this and the other two review comments on this patch. Thanks.
-sughosh
output_fname):
"""Generate empty capsules for FWU A/B updates
Args:
accept (int): Generate an accept capsule
revert (int): Generate a revert capsule
image_guid (str): GUID used for identifying the image
output_fname (str): Path to the output capsule file
Returns:
str: Tool output
"""
if accept:
args = [
f'--guid={image_guid}',
'--fw-accept'
]
elif revert:
args = [
'--fw-revert'
]
That can be on none line
args += [
output_fname
]
Same here
return self.run_cmd(*args)
- def fetch(self, method): """Fetch handler for mkeficapsule
-- 2.34.1
Regards, Simon

Add support in binman for generating EFI empty capsules. These capsules are used in the FWU A/B update feature. Also add test cases in binman for the corresponding code coverage.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- tools/binman/etype/efi_empty_capsule.py | 91 +++++++++++++++++++ tools/binman/ftest.py | 52 +++++++++++ tools/binman/test/319_capsule_accept.dts | 16 ++++ tools/binman/test/320_capsule_revert.dts | 14 +++ .../test/321_capsule_accept_missing_guid.dts | 14 +++ .../binman/test/322_capsule_accept_revert.dts | 17 ++++ 6 files changed, 204 insertions(+) create mode 100644 tools/binman/etype/efi_empty_capsule.py create mode 100644 tools/binman/test/319_capsule_accept.dts create mode 100644 tools/binman/test/320_capsule_revert.dts create mode 100644 tools/binman/test/321_capsule_accept_missing_guid.dts create mode 100644 tools/binman/test/322_capsule_accept_revert.dts
diff --git a/tools/binman/etype/efi_empty_capsule.py b/tools/binman/etype/efi_empty_capsule.py new file mode 100644 index 0000000000..d2c781627b --- /dev/null +++ b/tools/binman/etype/efi_empty_capsule.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Linaro Limited +# +# Entry-type module for producing an empty EFI capsule +# + +import os + +from binman.entry import Entry +from binman.etype.section import Entry_section +from dtoc import fdt_util +from u_boot_pylib import tools + +class Entry_efi_empty_capsule(Entry_section): + """Generate EFI empty capsules + + The parameters needed for generation of the empty capsules can + be provided as properties in the entry. + + Properties / Entry arguments: + - image-guid: Image GUID which will be used for identifying the + updatable image on the board. Mandatory for accept capsule. + - accept-capsule - Boolean property to generate an accept capsule. + image-type-id + - revert-capsule - Boolean property to generate a revert capsule + + For more details on the description of the capsule format, and the capsule + update functionality, refer Section 8.5 and Chapter 23 in the `UEFI + specification`_. For more information on the empty capsule, refer the + sections 2.3.2 and 2.3.3 in the `Dependable Boot specification`_. + + A typical accept empty capsule entry node would then look something like this + + empty-capsule { + type = "efi-empty-capsule"; + /* Image GUID for testing capsule update */ + image-type-id = SANDBOX_UBOOT_IMAGE_GUID; + accept-capsule; + }; + + A typical revert empty capsule entry node would then look something like this + + empty-capsule { + type = "efi-empty-capsule"; + revert-capsule; + }; + + The empty capsules do not have any input payload image. + + .. _`UEFI specification`: https://uefi.org/sites/default/files/resources/UEFI_Spec_2_10_Aug29.pdf + .. _`Dependable Boot specification`: https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e... + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + self.accept = 0 + self.revert = 0 + + def ReadNode(self): + super().ReadNode() + + self.image_guid = fdt_util.GetString(self._node, 'image-guid') + self.accept = fdt_util.GetBool(self._node, 'accept-capsule') + self.revert = fdt_util.GetBool(self._node, 'revert-capsule') + + if self.accept and not self.image_guid: + self.Raise('Image GUID needed for generating accept capsule') + + if self.accept and self.revert: + self.Raise('Need to enable either Accept or Revert capsule') + + def BuildSectionData(self, required): + def get_binman_test_guid(type_str): + TYPE_TO_GUID = { + 'binman-test' : '09d7cf52-0720-4710-91d1-08469b7fe9c8' + } + return TYPE_TO_GUID[type_str] + + uniq = self.GetUniqueName() + outfile = self._filename if self._filename else 'capsule.%s' % uniq + capsule_fname = tools.get_output_filename(outfile) + guid = self.image_guid + if self.image_guid == "binman-test": + guid = get_binman_test_guid('binman-test') + + ret = self.mkeficapsule.generate_empty_capsule(self.accept, self.revert, + guid, capsule_fname) + if ret is not None: + return tools.read_file(capsule_fname) + + def AddBintools(self, btools): + self.mkeficapsule = self.AddBintool(btools, 'mkeficapsule') diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 2b8871ab7e..9286de28e4 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -126,6 +126,9 @@ FW_MGMT_GUID = '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' CAPSULE_IMAGE_GUID = '09D7CF52-0720-4710-91D1-08469B7FE9C8' # Windows cert GUID WIN_CERT_TYPE_EFI_GUID = '4AAFD29D-68DF-49EE-8AA9-347D375665A7' +# Empty capsule GUIDs +EMPTY_CAPSULE_ACCEPT_GUID = '0C996046-BCC0-4D04-85EC-E1FCEDF1C6F8' +EMPTY_CAPSULE_REVERT_GUID = 'ACD58B4B-C0E8-475F-99B5-6B3F7E07AAF0'
class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -7283,6 +7286,27 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
+ def _CheckEmptyCapsule(self, data, accept_capsule=False): + if accept_capsule: + capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID + else: + capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID + + hdr = self._GetCapsuleHeaders(data) + + self.assertEqual(capsule_hdr_guid, + hdr['EFI_CAPSULE_HDR.CAPSULE_GUID']) + + if accept_capsule: + capsule_size = "0000002C" + else: + capsule_size = "0000001C" + self.assertEqual(capsule_size, + hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE']) + + if accept_capsule: + self.assertEqual(CAPSULE_IMAGE_GUID, hdr['ACCEPT_IMAGE_GUID']) + def testCapsuleGen(self): """Test generation of EFI capsule""" data = self._DoReadFile('311_capsule.dts') @@ -7347,5 +7371,33 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertIn("entry is missing properties: image-guid", str(e.exception))
+ def testCapsuleGenAcceptCapsule(self): + """Test generationg of accept EFI capsule""" + data = self._DoReadFile('319_capsule_accept.dts') + + self._CheckEmptyCapsule(data, accept_capsule=True) + + def testCapsuleGenRevertCapsule(self): + """Test generationg of revert EFI capsule""" + data = self._DoReadFile('320_capsule_revert.dts') + + self._CheckEmptyCapsule(data) + + def testCapsuleGenAcceptGuidMissing(self): + """Test that binman errors out on missing image GUID for accept capsule""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('321_capsule_accept_missing_guid.dts') + + self.assertIn("Image GUID needed for generating accept capsule", + str(e.exception)) + + def testCapsuleGenAcceptOrRevert(self): + """Test that both accept and revert capsule are not specified""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('322_capsule_accept_revert.dts') + + self.assertIn("Need to enable either Accept or Revert capsule", + str(e.exception)) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/319_capsule_accept.dts b/tools/binman/test/319_capsule_accept.dts new file mode 100644 index 0000000000..4d6c005019 --- /dev/null +++ b/tools/binman/test/319_capsule_accept.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + efi-empty-capsule { + /* Image GUID for testing capsule update */ + image-guid = "binman-test"; + accept-capsule; + }; + }; +}; diff --git a/tools/binman/test/320_capsule_revert.dts b/tools/binman/test/320_capsule_revert.dts new file mode 100644 index 0000000000..eeaa2793a5 --- /dev/null +++ b/tools/binman/test/320_capsule_revert.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + efi-empty-capsule { + revert-capsule; + }; + }; +}; diff --git a/tools/binman/test/321_capsule_accept_missing_guid.dts b/tools/binman/test/321_capsule_accept_missing_guid.dts new file mode 100644 index 0000000000..6f7062e83e --- /dev/null +++ b/tools/binman/test/321_capsule_accept_missing_guid.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + efi-empty-capsule { + accept-capsule; + }; + }; +}; diff --git a/tools/binman/test/322_capsule_accept_revert.dts b/tools/binman/test/322_capsule_accept_revert.dts new file mode 100644 index 0000000000..c68e76a669 --- /dev/null +++ b/tools/binman/test/322_capsule_accept_revert.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + efi-empty-capsule { + /* Image GUID for testing capsule update */ + image-guid = "binman-test"; + accept-capsule; + revert-capsule; + }; + }; +};

Hi Sugosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add support in binman for generating EFI empty capsules. These capsules are used in the FWU A/B update feature. Also add test cases in binman for the corresponding code coverage.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/etype/efi_empty_capsule.py | 91 +++++++++++++++++++ tools/binman/ftest.py | 52 +++++++++++ tools/binman/test/319_capsule_accept.dts | 16 ++++ tools/binman/test/320_capsule_revert.dts | 14 +++ .../test/321_capsule_accept_missing_guid.dts | 14 +++ .../binman/test/322_capsule_accept_revert.dts | 17 ++++ 6 files changed, 204 insertions(+) create mode 100644 tools/binman/etype/efi_empty_capsule.py create mode 100644 tools/binman/test/319_capsule_accept.dts create mode 100644 tools/binman/test/320_capsule_revert.dts create mode 100644 tools/binman/test/321_capsule_accept_missing_guid.dts create mode 100644 tools/binman/test/322_capsule_accept_revert.dts
diff --git a/tools/binman/etype/efi_empty_capsule.py b/tools/binman/etype/efi_empty_capsule.py new file mode 100644 index 0000000000..d2c781627b --- /dev/null +++ b/tools/binman/etype/efi_empty_capsule.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Linaro Limited +# +# Entry-type module for producing an empty EFI capsule +#
+import os
+from binman.entry import Entry +from binman.etype.section import Entry_section +from dtoc import fdt_util +from u_boot_pylib import tools
+class Entry_efi_empty_capsule(Entry_section):
Do you think this could subclass Entry_efi_capsule? They seem to do similar things. You could call generate_capsule() or generate_empty_capsule(). depending on whether any data is present (and perhaps require an operation if no data).
I'm not sure about this, just an idea.
- """Generate EFI empty capsules
- The parameters needed for generation of the empty capsules can
- be provided as properties in the entry.
- Properties / Entry arguments:
- image-guid: Image GUID which will be used for identifying the
updatable image on the board. Mandatory for accept capsule.
- accept-capsule - Boolean property to generate an accept capsule.
image-type-id
- revert-capsule - Boolean property to generate a revert capsule
- For more details on the description of the capsule format, and the capsule
- update functionality, refer Section 8.5 and Chapter 23 in the `UEFI
- specification`_. For more information on the empty capsule, refer the
- sections 2.3.2 and 2.3.3 in the `Dependable Boot specification`_.
- A typical accept empty capsule entry node would then look something like this
- empty-capsule {
type = "efi-empty-capsule";
/* Image GUID for testing capsule update */
image-type-id = SANDBOX_UBOOT_IMAGE_GUID;
accept-capsule;
- };
- A typical revert empty capsule entry node would then look something like this
- empty-capsule {
type = "efi-empty-capsule";
revert-capsule;
- };
- The empty capsules do not have any input payload image.
- .. _`UEFI specification`: https://uefi.org/sites/default/files/resources/UEFI_Spec_2_10_Aug29.pdf
- .. _`Dependable Boot specification`: https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e...
- """
- def __init__(self, section, etype, node):
super().__init__(section, etype, node)
self.accept = 0
self.revert = 0
- def ReadNode(self):
super().ReadNode()
self.image_guid = fdt_util.GetString(self._node, 'image-guid')
self.accept = fdt_util.GetBool(self._node, 'accept-capsule')
self.revert = fdt_util.GetBool(self._node, 'revert-capsule')
Perhaps it should be
operation = "accept" / "revert" ?
Using two conflicting bools is not great.
if self.accept and not self.image_guid:
self.Raise('Image GUID needed for generating accept capsule')
if self.accept and self.revert:
self.Raise('Need to enable either Accept or Revert capsule')
- def BuildSectionData(self, required):
def get_binman_test_guid(type_str):
TYPE_TO_GUID = {
'binman-test' : '09d7cf52-0720-4710-91d1-08469b7fe9c8'
Can you put this in a shared file somewhere, used by this and the efi_capsule.py module?
}
return TYPE_TO_GUID[type_str]
uniq = self.GetUniqueName()
outfile = self._filename if self._filename else 'capsule.%s' % uniq
capsule_fname = tools.get_output_filename(outfile)
guid = self.image_guid
if self.image_guid == "binman-test":
guid = get_binman_test_guid('binman-test')
ret = self.mkeficapsule.generate_empty_capsule(self.accept, self.revert,
guid, capsule_fname)
if ret is not None:
return tools.read_file(capsule_fname)
- def AddBintools(self, btools):
self.mkeficapsule = self.AddBintool(btools, 'mkeficapsule')
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 2b8871ab7e..9286de28e4 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -126,6 +126,9 @@ FW_MGMT_GUID = '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' CAPSULE_IMAGE_GUID = '09D7CF52-0720-4710-91D1-08469B7FE9C8' # Windows cert GUID WIN_CERT_TYPE_EFI_GUID = '4AAFD29D-68DF-49EE-8AA9-347D375665A7' +# Empty capsule GUIDs +EMPTY_CAPSULE_ACCEPT_GUID = '0C996046-BCC0-4D04-85EC-E1FCEDF1C6F8' +EMPTY_CAPSULE_REVERT_GUID = 'ACD58B4B-C0E8-475F-99B5-6B3F7E07AAF0'
class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -7283,6 +7286,27 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
- def _CheckEmptyCapsule(self, data, accept_capsule=False):
if accept_capsule:
capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
else:
capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
hdr = self._GetCapsuleHeaders(data)
self.assertEqual(capsule_hdr_guid,
hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
if accept_capsule:
capsule_size = "0000002C"
else:
capsule_size = "0000001C"
self.assertEqual(capsule_size,
hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
if accept_capsule:
self.assertEqual(CAPSULE_IMAGE_GUID, hdr['ACCEPT_IMAGE_GUID'])
- def testCapsuleGen(self): """Test generation of EFI capsule""" data = self._DoReadFile('311_capsule.dts')
@@ -7347,5 +7371,33 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertIn("entry is missing properties: image-guid", str(e.exception))
- def testCapsuleGenAcceptCapsule(self):
"""Test generationg of accept EFI capsule"""
data = self._DoReadFile('319_capsule_accept.dts')
self._CheckEmptyCapsule(data, accept_capsule=True)
- def testCapsuleGenRevertCapsule(self):
"""Test generationg of revert EFI capsule"""
data = self._DoReadFile('320_capsule_revert.dts')
self._CheckEmptyCapsule(data)
- def testCapsuleGenAcceptGuidMissing(self):
"""Test that binman errors out on missing image GUID for accept capsule"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('321_capsule_accept_missing_guid.dts')
self.assertIn("Image GUID needed for generating accept capsule",
str(e.exception))
- def testCapsuleGenAcceptOrRevert(self):
"""Test that both accept and revert capsule are not specified"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('322_capsule_accept_revert.dts')
self.assertIn("Need to enable either Accept or Revert capsule",
str(e.exception))
if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/319_capsule_accept.dts b/tools/binman/test/319_capsule_accept.dts new file mode 100644 index 0000000000..4d6c005019 --- /dev/null +++ b/tools/binman/test/319_capsule_accept.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
efi-empty-capsule {
/* Image GUID for testing capsule update */
image-guid = "binman-test";
accept-capsule;
};
};
+}; diff --git a/tools/binman/test/320_capsule_revert.dts b/tools/binman/test/320_capsule_revert.dts new file mode 100644 index 0000000000..eeaa2793a5 --- /dev/null +++ b/tools/binman/test/320_capsule_revert.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
efi-empty-capsule {
revert-capsule;
};
};
+}; diff --git a/tools/binman/test/321_capsule_accept_missing_guid.dts b/tools/binman/test/321_capsule_accept_missing_guid.dts new file mode 100644 index 0000000000..6f7062e83e --- /dev/null +++ b/tools/binman/test/321_capsule_accept_missing_guid.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+/ {
#address-cells = <1>;
#size-cells = <1>;
I wonder if those two lines are needed? Perhaps it generates a warning?
binman {
efi-empty-capsule {
accept-capsule;
};
};
+}; diff --git a/tools/binman/test/322_capsule_accept_revert.dts b/tools/binman/test/322_capsule_accept_revert.dts new file mode 100644 index 0000000000..c68e76a669 --- /dev/null +++ b/tools/binman/test/322_capsule_accept_revert.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
efi-empty-capsule {
/* Image GUID for testing capsule update */
image-guid = "binman-test";
accept-capsule;
revert-capsule;
};
};
+};
2.34.1
Regards, Simon

hi Simon,
On Sun, 8 Oct 2023 at 04:41, Simon Glass sjg@chromium.org wrote:
Hi Sugosh,
On Wed, 4 Oct 2023 at 05:27, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add support in binman for generating EFI empty capsules. These capsules are used in the FWU A/B update feature. Also add test cases in binman for the corresponding code coverage.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
tools/binman/etype/efi_empty_capsule.py | 91 +++++++++++++++++++ tools/binman/ftest.py | 52 +++++++++++ tools/binman/test/319_capsule_accept.dts | 16 ++++ tools/binman/test/320_capsule_revert.dts | 14 +++ .../test/321_capsule_accept_missing_guid.dts | 14 +++ .../binman/test/322_capsule_accept_revert.dts | 17 ++++ 6 files changed, 204 insertions(+) create mode 100644 tools/binman/etype/efi_empty_capsule.py create mode 100644 tools/binman/test/319_capsule_accept.dts create mode 100644 tools/binman/test/320_capsule_revert.dts create mode 100644 tools/binman/test/321_capsule_accept_missing_guid.dts create mode 100644 tools/binman/test/322_capsule_accept_revert.dts
diff --git a/tools/binman/etype/efi_empty_capsule.py b/tools/binman/etype/efi_empty_capsule.py new file mode 100644 index 0000000000..d2c781627b --- /dev/null +++ b/tools/binman/etype/efi_empty_capsule.py @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Linaro Limited +# +# Entry-type module for producing an empty EFI capsule +#
+import os
+from binman.entry import Entry +from binman.etype.section import Entry_section +from dtoc import fdt_util +from u_boot_pylib import tools
+class Entry_efi_empty_capsule(Entry_section):
Do you think this could subclass Entry_efi_capsule? They seem to do similar things. You could call generate_capsule() or generate_empty_capsule(). depending on whether any data is present (and perhaps require an operation if no data).
I'm not sure about this, just an idea.
Okay, let me try this out. If it is getting too confusing or unclear, I will keep the two entry types separate.
- """Generate EFI empty capsules
- The parameters needed for generation of the empty capsules can
- be provided as properties in the entry.
- Properties / Entry arguments:
- image-guid: Image GUID which will be used for identifying the
updatable image on the board. Mandatory for accept capsule.
- accept-capsule - Boolean property to generate an accept capsule.
image-type-id
- revert-capsule - Boolean property to generate a revert capsule
- For more details on the description of the capsule format, and the capsule
- update functionality, refer Section 8.5 and Chapter 23 in the `UEFI
- specification`_. For more information on the empty capsule, refer the
- sections 2.3.2 and 2.3.3 in the `Dependable Boot specification`_.
- A typical accept empty capsule entry node would then look something like this
- empty-capsule {
type = "efi-empty-capsule";
/* Image GUID for testing capsule update */
image-type-id = SANDBOX_UBOOT_IMAGE_GUID;
accept-capsule;
- };
- A typical revert empty capsule entry node would then look something like this
- empty-capsule {
type = "efi-empty-capsule";
revert-capsule;
- };
- The empty capsules do not have any input payload image.
- .. _`UEFI specification`: https://uefi.org/sites/default/files/resources/UEFI_Spec_2_10_Aug29.pdf
- .. _`Dependable Boot specification`: https://git.codelinaro.org/linaro/dependable-boot/mbfw/uploads/6f7ddfe3be24e...
- """
- def __init__(self, section, etype, node):
super().__init__(section, etype, node)
self.accept = 0
self.revert = 0
- def ReadNode(self):
super().ReadNode()
self.image_guid = fdt_util.GetString(self._node, 'image-guid')
self.accept = fdt_util.GetBool(self._node, 'accept-capsule')
self.revert = fdt_util.GetBool(self._node, 'revert-capsule')
Perhaps it should be
operation = "accept" / "revert" ?
Using two conflicting bools is not great.
Will change
if self.accept and not self.image_guid:
self.Raise('Image GUID needed for generating accept capsule')
if self.accept and self.revert:
self.Raise('Need to enable either Accept or Revert capsule')
- def BuildSectionData(self, required):
def get_binman_test_guid(type_str):
TYPE_TO_GUID = {
'binman-test' : '09d7cf52-0720-4710-91d1-08469b7fe9c8'
Can you put this in a shared file somewhere, used by this and the efi_capsule.py module?
Okay. I will put this in a separate global function, and use it in the other module.
}
return TYPE_TO_GUID[type_str]
uniq = self.GetUniqueName()
outfile = self._filename if self._filename else 'capsule.%s' % uniq
capsule_fname = tools.get_output_filename(outfile)
guid = self.image_guid
if self.image_guid == "binman-test":
guid = get_binman_test_guid('binman-test')
ret = self.mkeficapsule.generate_empty_capsule(self.accept, self.revert,
guid, capsule_fname)
if ret is not None:
return tools.read_file(capsule_fname)
- def AddBintools(self, btools):
self.mkeficapsule = self.AddBintool(btools, 'mkeficapsule')
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 2b8871ab7e..9286de28e4 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -126,6 +126,9 @@ FW_MGMT_GUID = '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A' CAPSULE_IMAGE_GUID = '09D7CF52-0720-4710-91D1-08469B7FE9C8' # Windows cert GUID WIN_CERT_TYPE_EFI_GUID = '4AAFD29D-68DF-49EE-8AA9-347D375665A7' +# Empty capsule GUIDs +EMPTY_CAPSULE_ACCEPT_GUID = '0C996046-BCC0-4D04-85EC-E1FCEDF1C6F8' +EMPTY_CAPSULE_REVERT_GUID = 'ACD58B4B-C0E8-475F-99B5-6B3F7E07AAF0'
class TestFunctional(unittest.TestCase): """Functional tests for binman @@ -7283,6 +7286,27 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
- def _CheckEmptyCapsule(self, data, accept_capsule=False):
if accept_capsule:
capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
else:
capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
hdr = self._GetCapsuleHeaders(data)
self.assertEqual(capsule_hdr_guid,
hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
if accept_capsule:
capsule_size = "0000002C"
else:
capsule_size = "0000001C"
self.assertEqual(capsule_size,
hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
if accept_capsule:
self.assertEqual(CAPSULE_IMAGE_GUID, hdr['ACCEPT_IMAGE_GUID'])
- def testCapsuleGen(self): """Test generation of EFI capsule""" data = self._DoReadFile('311_capsule.dts')
@@ -7347,5 +7371,33 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertIn("entry is missing properties: image-guid", str(e.exception))
- def testCapsuleGenAcceptCapsule(self):
"""Test generationg of accept EFI capsule"""
data = self._DoReadFile('319_capsule_accept.dts')
self._CheckEmptyCapsule(data, accept_capsule=True)
- def testCapsuleGenRevertCapsule(self):
"""Test generationg of revert EFI capsule"""
data = self._DoReadFile('320_capsule_revert.dts')
self._CheckEmptyCapsule(data)
- def testCapsuleGenAcceptGuidMissing(self):
"""Test that binman errors out on missing image GUID for accept capsule"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('321_capsule_accept_missing_guid.dts')
self.assertIn("Image GUID needed for generating accept capsule",
str(e.exception))
- def testCapsuleGenAcceptOrRevert(self):
"""Test that both accept and revert capsule are not specified"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('322_capsule_accept_revert.dts')
self.assertIn("Need to enable either Accept or Revert capsule",
str(e.exception))
if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/319_capsule_accept.dts b/tools/binman/test/319_capsule_accept.dts new file mode 100644 index 0000000000..4d6c005019 --- /dev/null +++ b/tools/binman/test/319_capsule_accept.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
efi-empty-capsule {
/* Image GUID for testing capsule update */
image-guid = "binman-test";
accept-capsule;
};
};
+}; diff --git a/tools/binman/test/320_capsule_revert.dts b/tools/binman/test/320_capsule_revert.dts new file mode 100644 index 0000000000..eeaa2793a5 --- /dev/null +++ b/tools/binman/test/320_capsule_revert.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
efi-empty-capsule {
revert-capsule;
};
};
+}; diff --git a/tools/binman/test/321_capsule_accept_missing_guid.dts b/tools/binman/test/321_capsule_accept_missing_guid.dts new file mode 100644 index 0000000000..6f7062e83e --- /dev/null +++ b/tools/binman/test/321_capsule_accept_missing_guid.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+/ {
#address-cells = <1>;
#size-cells = <1>;
I wonder if those two lines are needed? Perhaps it generates a warning?
Tbh, I just copied them from another file which I was using as a reference when I introduced the capsule changes. I will check if removing them causes any issues.
-sughosh
binman {
efi-empty-capsule {
accept-capsule;
};
};
+}; diff --git a/tools/binman/test/322_capsule_accept_revert.dts b/tools/binman/test/322_capsule_accept_revert.dts new file mode 100644 index 0000000000..c68e76a669 --- /dev/null +++ b/tools/binman/test/322_capsule_accept_revert.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+/ {
#address-cells = <1>;
#size-cells = <1>;
binman {
efi-empty-capsule {
/* Image GUID for testing capsule update */
image-guid = "binman-test";
accept-capsule;
revert-capsule;
};
};
+};
2.34.1
Regards, Simon
participants (2)
-
Simon Glass
-
Sughosh Ganu