binman: capsule: Add support for generating EFI capsules

Add support in binman for generating EFI capsules. The capsule
parameters can be specified through the capsule binman entry. Also add
test cases in binman for testing capsule generation.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Sughosh Ganu
2023-08-22 23:09:59 +05:30
committed by Tom Rini
parent 3bd6fb980b
commit b617611b27
11 changed files with 498 additions and 0 deletions

View File

@@ -48,6 +48,7 @@ U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
BLOB_DATA = b'89'
ME_DATA = b'0abcd'
VGA_DATA = b'vga'
EFI_CAPSULE_DATA = b'efi'
U_BOOT_DTB_DATA = b'udtb'
U_BOOT_SPL_DTB_DATA = b'spldtb'
U_BOOT_TPL_DTB_DATA = b'tpldtb'
@@ -119,6 +120,11 @@ COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
TEE_ADDR = 0x5678
# Firmware Management Protocol(FMP) GUID
FW_MGMT_GUID = 'edd5cb6d2de8444cbda17194199ad92a'
# Image GUID specified in the DTS
CAPSULE_IMAGE_GUID = '52cfd7092007104791d108469b7fe9c8'
class TestFunctional(unittest.TestCase):
"""Functional tests for binman
@@ -215,6 +221,7 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
# Add a few .dtb files for testing
TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
@@ -7216,5 +7223,116 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self.assertRegex(err,
"Image 'image'.*missing bintools.*: bootgen")
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"
payload_data = 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.
# 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])
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])
def testCapsuleGen(self):
"""Test generation of EFI capsule"""
data = self._DoReadFile('311_capsule.dts')
self._CheckCapsule(data)
def testSignedCapsuleGen(self):
"""Test generation of EFI capsule"""
data = tools.read_file(self.TestFile("key.key"))
self._MakeInputFile("key.key", data)
data = tools.read_file(self.TestFile("key.pem"))
self._MakeInputFile("key.crt", data)
data = self._DoReadFile('312_capsule_signed.dts')
self._CheckCapsule(data, signed_capsule=True)
def testCapsuleGenVersionSupport(self):
"""Test generation of EFI capsule with version support"""
data = self._DoReadFile('313_capsule_version.dts')
self._CheckCapsule(data, version_check=True)
def testCapsuleGenSignedVer(self):
"""Test generation of signed EFI capsule with version information"""
data = tools.read_file(self.TestFile("key.key"))
self._MakeInputFile("key.key", data)
data = tools.read_file(self.TestFile("key.pem"))
self._MakeInputFile("key.crt", data)
data = self._DoReadFile('314_capsule_signed_ver.dts')
self._CheckCapsule(data, signed_capsule=True, version_check=True)
def testCapsuleGenCapOemFlags(self):
"""Test generation of EFI capsule with OEM Flags set"""
data = self._DoReadFile('315_capsule_oemflags.dts')
self._CheckCapsule(data, capoemflags=True)
def testCapsuleGenKeyMissing(self):
"""Test that binman errors out on missing key"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('316_capsule_missing_key.dts')
self.assertIn("Both private key and public key certificate need to be provided",
str(e.exception))
def testCapsuleGenIndexMissing(self):
"""Test that binman errors out on missing image index"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('317_capsule_missing_index.dts')
self.assertIn("entry is missing properties: image-index",
str(e.exception))
def testCapsuleGenGuidMissing(self):
"""Test that binman errors out on missing image GUID"""
with self.assertRaises(ValueError) as e:
self._DoReadFile('318_capsule_missing_guid.dts')
self.assertIn("entry is missing properties: image-guid",
str(e.exception))
if __name__ == "__main__":
unittest.main()