summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2023-10-14 10:50:20 -0400
committerTom Rini <[email protected]>2023-10-14 10:50:20 -0400
commit3c3f1626919cd93cbe6c56e3849937de5be18dbb (patch)
tree97483e691431094e5a668fcc9ac1cc96032ef543 /tools
parent25edd247a84a31298c22a34ec5cf2851cbf61f70 (diff)
parent74aae507bc4d5726308c191d3191d9cd624ba0d2 (diff)
Merge tag 'dm-pull-13oct23' of https://source.denx.de/u-boot/custodians/u-boot-dm
improvements with dev_read_addr_..._ptr() scan all entries in multi-device boot_targets EFI empty-capsule support
Diffstat (limited to 'tools')
-rw-r--r--tools/binman/btool/bootgen.py2
-rw-r--r--tools/binman/btool/fiptool.py2
-rw-r--r--tools/binman/btool/futility.py2
-rw-r--r--tools/binman/btool/mkeficapsule.py26
-rw-r--r--tools/binman/entries.rst44
-rw-r--r--tools/binman/etype/efi_capsule.py24
-rw-r--r--tools/binman/etype/efi_empty_capsule.py86
-rw-r--r--tools/binman/ftest.py160
-rw-r--r--tools/binman/test/311_capsule.dts3
-rw-r--r--tools/binman/test/312_capsule_signed.dts3
-rw-r--r--tools/binman/test/313_capsule_version.dts3
-rw-r--r--tools/binman/test/314_capsule_signed_ver.dts3
-rw-r--r--tools/binman/test/315_capsule_oemflags.dts3
-rw-r--r--tools/binman/test/316_capsule_missing_key.dts3
-rw-r--r--tools/binman/test/317_capsule_missing_index.dts3
-rw-r--r--tools/binman/test/318_capsule_missing_guid.dts3
-rw-r--r--tools/binman/test/319_capsule_accept.dts13
-rw-r--r--tools/binman/test/320_capsule_revert.dts11
-rw-r--r--tools/binman/test/321_capsule_accept_missing_guid.dts11
-rw-r--r--tools/binman/test/322_empty_capsule_type_missing.dts12
-rw-r--r--tools/binman/test/323_capsule_accept_revert_missing.dts13
-rw-r--r--tools/eficapsule.h2
-rw-r--r--tools/mkeficapsule.c227
23 files changed, 585 insertions, 74 deletions
diff --git a/tools/binman/btool/bootgen.py b/tools/binman/btool/bootgen.py
index f2ca552dc28..1bc9f0aa96f 100644
--- a/tools/binman/btool/bootgen.py
+++ b/tools/binman/btool/bootgen.py
@@ -132,6 +132,6 @@ class Bintoolbootgen(bintool.Bintool):
result = self.build_from_git(
'https://github.com/Xilinx/bootgen',
- 'all',
+ ['all'],
'bootgen')
return result
diff --git a/tools/binman/btool/fiptool.py b/tools/binman/btool/fiptool.py
index c80f8275c4c..34002f54af9 100644
--- a/tools/binman/btool/fiptool.py
+++ b/tools/binman/btool/fiptool.py
@@ -109,6 +109,6 @@ class Bintoolfiptool(bintool.Bintool):
return None
result = self.build_from_git(
'https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git',
- 'fiptool',
+ ['fiptool'],
'tools/fiptool/fiptool')
return result
diff --git a/tools/binman/btool/futility.py b/tools/binman/btool/futility.py
index 04c9aefe9b4..0d3980d071d 100644
--- a/tools/binman/btool/futility.py
+++ b/tools/binman/btool/futility.py
@@ -170,7 +170,7 @@ class Bintoolfutility(bintool.Bintool):
# .gitcookies file. So use a mirror instead.
result = self.build_from_git(
'https://github.com/sjg20/vboot_reference.git',
- 'all',
+ ['all'],
'build/futility/futility',
flags=['USE_FLASHROM=0'])
return result
diff --git a/tools/binman/btool/mkeficapsule.py b/tools/binman/btool/mkeficapsule.py
index 61179747ffa..ef1da638df1 100644
--- a/tools/binman/btool/mkeficapsule.py
+++ b/tools/binman/btool/mkeficapsule.py
@@ -80,6 +80,32 @@ class Bintoolmkeficapsule(bintool.Bintool):
return self.run_cmd(*args)
+ def generate_empty_capsule(self, image_guid, output_fname,
+ accept=True):
+ """Generate empty capsules for FWU A/B updates
+
+ Args:
+ image_guid (str): GUID used for identifying the image
+ in case of an accept capsule
+ output_fname (str): Path to the output capsule file
+ accept (bool): Generate an accept capsule,
+ else a revert capsule
+
+ Returns:
+ str: Tool output
+ """
+ if accept:
+ args = [
+ f'--guid={image_guid}',
+ '--fw-accept'
+ ]
+ else:
+ args = [ '--fw-revert' ]
+
+ args += [ output_fname ]
+
+ return self.run_cmd(*args)
+
def fetch(self, method):
"""Fetch handler for mkeficapsule
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index 801bd946742..e7b4e9380e2 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -532,6 +532,50 @@ payload using the blob-ext subnode.
+.. _etype_efi_empty_capsule:
+
+Entry: efi-empty-capsule: Entry for generating EFI Empty Capsule files
+----------------------------------------------------------------------
+
+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.
+ - capsule-type - String to indicate type of capsule to generate. Valid
+ values are 'accept' and 'revert'.
+
+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";
+ /* GUID of the image being accepted */
+ image-type-id = SANDBOX_UBOOT_IMAGE_GUID;
+ capsule-type = "accept";
+ };
+
+A typical revert empty capsule entry node would then look something
+like this::
+
+ empty-capsule {
+ type = "efi-empty-capsule";
+ capsule-type = "revert";
+ };
+
+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/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
+
+
+
.. _etype_encrypted:
Entry: encrypted: Externally built encrypted binary blob
diff --git a/tools/binman/etype/efi_capsule.py b/tools/binman/etype/efi_capsule.py
index 006eb630adb..e3203717822 100644
--- a/tools/binman/etype/efi_capsule.py
+++ b/tools/binman/etype/efi_capsule.py
@@ -11,6 +11,24 @@ from binman.etype.section import Entry_section
from dtoc import fdt_util
from u_boot_pylib import tools
+def get_binman_test_guid(type_str):
+ """Get the test image GUID for binman
+
+ Based on the string passed to the function, return
+ the corresponding GUID.
+
+ Args:
+ type_str: Key value of the type of GUID to look for
+
+ Returns:
+ The actual GUID value (str)
+ """
+ TYPE_TO_GUID = {
+ 'binman-test' : '09d7cf52-0720-4710-91d1-08469b7fe9c8'
+ }
+
+ return TYPE_TO_GUID[type_str]
+
class Entry_efi_capsule(Entry_section):
"""Generate EFI capsules
@@ -104,12 +122,6 @@ class Entry_efi_capsule(Entry_section):
self.auth = 1
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]
-
private_key = ''
public_key_cert = ''
if self.auth:
diff --git a/tools/binman/etype/efi_empty_capsule.py b/tools/binman/etype/efi_empty_capsule.py
new file mode 100644
index 00000000000..064bf9a77f0
--- /dev/null
+++ b/tools/binman/etype/efi_empty_capsule.py
@@ -0,0 +1,86 @@
+# 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.efi_capsule import get_binman_test_guid
+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.
+ - capsule-type - String to indicate type of capsule to generate. Valid
+ values are 'accept' and 'revert'.
+
+ 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";
+ /* GUID of image being accepted */
+ image-type-id = SANDBOX_UBOOT_IMAGE_GUID;
+ capsule-type = "accept";
+ };
+
+ A typical revert empty capsule entry node would then look something like this
+
+ empty-capsule {
+ type = "efi-empty-capsule";
+ capsule-type = "revert";
+ };
+
+ 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/6f7ddfe3be24e18d4319e108a758d02e/mbfw.pdf
+ """
+ def __init__(self, section, etype, node):
+ super().__init__(section, etype, node)
+ self.required_props = ['capsule-type']
+ self.accept = 0
+ self.revert = 0
+
+ def ReadNode(self):
+ super().ReadNode()
+
+ self.image_guid = fdt_util.GetString(self._node, 'image-guid')
+ self.capsule_type = fdt_util.GetString(self._node, 'capsule-type')
+
+ if self.capsule_type != 'accept' and self.capsule_type != 'revert':
+ self.Raise('capsule-type should be either \'accept\' or \'revert\'')
+
+ if self.capsule_type == 'accept' and not self.image_guid:
+ self.Raise('Image GUID needed for generating accept capsule')
+
+ def BuildSectionData(self, required):
+ uniq = self.GetUniqueName()
+ outfile = self._filename if self._filename else 'capsule.%s' % uniq
+ capsule_fname = tools.get_output_filename(outfile)
+ accept = True if self.capsule_type == 'accept' else False
+ guid = self.image_guid
+ if self.image_guid == "binman-test":
+ guid = get_binman_test_guid('binman-test')
+
+ ret = self.mkeficapsule.generate_empty_capsule(guid, capsule_fname,
+ accept)
+ 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 8e419645a6d..16156b74105 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -121,9 +121,14 @@ 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'
+# 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
@@ -7223,52 +7228,94 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self.assertRegex(err,
"Image 'image'.*missing bintools.*: bootgen")
+ def _GetCapsuleHeaders(self, data):
+ """Get the capsule header contents
+
+ Args:
+ data: Capsule file contents
+
+ Returns:
+ Dict:
+ key: Capsule Header name (str)
+ value: Header field value (str)
+ """
+ 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 = {}
+ 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.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
+
+ self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
+ 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])
+ 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.upper(),
+ 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 _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.upper(),
+ hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
+
+ if accept_capsule:
+ capsule_size = "0000002C"
else:
- # payload offset for non-signed capsule with no version header(184 - 190)
- self.assertEqual(payload_data.hex(), data.hex()[184:190])
+ capsule_size = "0000001C"
+ self.assertEqual(capsule_size,
+ hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
+
+ if accept_capsule:
+ self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
def testCapsuleGen(self):
"""Test generation of EFI capsule"""
@@ -7334,5 +7381,38 @@ 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 testCapsuleGenEmptyCapsuleTypeMissing(self):
+ """Test that capsule-type is specified"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('322_empty_capsule_type_missing.dts')
+
+ self.assertIn("entry is missing properties: capsule-type",
+ str(e.exception))
+
+ def testCapsuleGenAcceptOrRevertMissing(self):
+ """Test that both accept and revert capsule are not specified"""
+ with self.assertRaises(ValueError) as e:
+ self._DoReadFile('323_capsule_accept_revert_missing.dts')
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/test/311_capsule.dts b/tools/binman/test/311_capsule.dts
index 8eb4250b14b..0a62ef81dd2 100644
--- a/tools/binman/test/311_capsule.dts
+++ b/tools/binman/test/311_capsule.dts
@@ -3,9 +3,6 @@
/dts-v1/;
/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
binman {
efi-capsule {
image-index = <0x1>;
diff --git a/tools/binman/test/312_capsule_signed.dts b/tools/binman/test/312_capsule_signed.dts
index d1c76e269c7..4ab838efedd 100644
--- a/tools/binman/test/312_capsule_signed.dts
+++ b/tools/binman/test/312_capsule_signed.dts
@@ -3,9 +3,6 @@
/dts-v1/;
/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
binman {
efi-capsule {
image-index = <0x1>;
diff --git a/tools/binman/test/313_capsule_version.dts b/tools/binman/test/313_capsule_version.dts
index bafef3609e0..19e7e833480 100644
--- a/tools/binman/test/313_capsule_version.dts
+++ b/tools/binman/test/313_capsule_version.dts
@@ -3,9 +3,6 @@
/dts-v1/;
/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
binman {
efi-capsule {
image-index = <0x1>;
diff --git a/tools/binman/test/314_capsule_signed_ver.dts b/tools/binman/test/314_capsule_signed_ver.dts
index 85c784bba43..649b8ccb2df 100644
--- a/tools/binman/test/314_capsule_signed_ver.dts
+++ b/tools/binman/test/314_capsule_signed_ver.dts
@@ -3,9 +3,6 @@
/dts-v1/;
/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
binman {
efi-capsule {
image-index = <0x1>;
diff --git a/tools/binman/test/315_capsule_oemflags.dts b/tools/binman/test/315_capsule_oemflags.dts
index f736e8758fd..45853f69c31 100644
--- a/tools/binman/test/315_capsule_oemflags.dts
+++ b/tools/binman/test/315_capsule_oemflags.dts
@@ -3,9 +3,6 @@
/dts-v1/;
/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
binman {
efi-capsule {
image-index = <0x1>;
diff --git a/tools/binman/test/316_capsule_missing_key.dts b/tools/binman/test/316_capsule_missing_key.dts
index 2080b50e3dd..a14a74ee779 100644
--- a/tools/binman/test/316_capsule_missing_key.dts
+++ b/tools/binman/test/316_capsule_missing_key.dts
@@ -3,9 +3,6 @@
/dts-v1/;
/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
binman {
efi-capsule {
image-index = <0x1>;
diff --git a/tools/binman/test/317_capsule_missing_index.dts b/tools/binman/test/317_capsule_missing_index.dts
index aadb61f6477..99a54d55c33 100644
--- a/tools/binman/test/317_capsule_missing_index.dts
+++ b/tools/binman/test/317_capsule_missing_index.dts
@@ -3,9 +3,6 @@
/dts-v1/;
/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
binman {
efi-capsule {
/* Image GUID for testing capsule update */
diff --git a/tools/binman/test/318_capsule_missing_guid.dts b/tools/binman/test/318_capsule_missing_guid.dts
index d76afba853e..85d3317ecb5 100644
--- a/tools/binman/test/318_capsule_missing_guid.dts
+++ b/tools/binman/test/318_capsule_missing_guid.dts
@@ -3,9 +3,6 @@
/dts-v1/;
/ {
- #address-cells = <1>;
- #size-cells = <1>;
-
binman {
efi-capsule {
image-index = <0x1>;
diff --git a/tools/binman/test/319_capsule_accept.dts b/tools/binman/test/319_capsule_accept.dts
new file mode 100644
index 00000000000..d48e59f859b
--- /dev/null
+++ b/tools/binman/test/319_capsule_accept.dts
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ binman {
+ efi-empty-capsule {
+ /* Image GUID for testing capsule update */
+ image-guid = "binman-test";
+ capsule-type = "accept";
+ };
+ };
+};
diff --git a/tools/binman/test/320_capsule_revert.dts b/tools/binman/test/320_capsule_revert.dts
new file mode 100644
index 00000000000..bd141ef2924
--- /dev/null
+++ b/tools/binman/test/320_capsule_revert.dts
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ binman {
+ efi-empty-capsule {
+ capsule-type = "revert";
+ };
+ };
+};
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 00000000000..a0088b174c5
--- /dev/null
+++ b/tools/binman/test/321_capsule_accept_missing_guid.dts
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ binman {
+ efi-empty-capsule {
+ capsule-type = "accept";
+ };
+ };
+};
diff --git a/tools/binman/test/322_empty_capsule_type_missing.dts b/tools/binman/test/322_empty_capsule_type_missing.dts
new file mode 100644
index 00000000000..d356168e775
--- /dev/null
+++ b/tools/binman/test/322_empty_capsule_type_missing.dts
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ binman {
+ efi-empty-capsule {
+ /* Image GUID for testing capsule update */
+ image-guid = "binman-test";
+ };
+ };
+};
diff --git a/tools/binman/test/323_capsule_accept_revert_missing.dts b/tools/binman/test/323_capsule_accept_revert_missing.dts
new file mode 100644
index 00000000000..31268b20b88
--- /dev/null
+++ b/tools/binman/test/323_capsule_accept_revert_missing.dts
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ binman {
+ efi-empty-capsule {
+ /* Image GUID for testing capsule update */
+ image-guid = "binman-test";
+ capsule-type = "foo";
+ };
+ };
+};
diff --git a/tools/eficapsule.h b/tools/eficapsule.h
index 2099a2e9b88..6efd07d2eb6 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 52be1f122ee..b8fc6069b58 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,215 @@ 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)
+{
+ 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);
+ return fmp_payload_hdr->header_size;
+ }
+
+ return 0;
+}
+
+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 +877,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 +888,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 +967,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 ||