mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 13:43:28 +00:00
binman: capsule: Add support for generating EFI empty capsules
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> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
f1c8fc5e67
commit
74aae507bc
8 changed files with 247 additions and 0 deletions
|
@ -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
|
||||
|
|
86
tools/binman/etype/efi_empty_capsule.py
Normal file
86
tools/binman/etype/efi_empty_capsule.py
Normal file
|
@ -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')
|
|
@ -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
|
||||
|
@ -7293,6 +7296,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.upper(),
|
||||
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.upper(), hdr['ACCEPT_IMAGE_GUID'])
|
||||
|
||||
def testCapsuleGen(self):
|
||||
"""Test generation of EFI capsule"""
|
||||
data = self._DoReadFile('311_capsule.dts')
|
||||
|
@ -7357,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()
|
||||
|
|
13
tools/binman/test/319_capsule_accept.dts
Normal file
13
tools/binman/test/319_capsule_accept.dts
Normal file
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
11
tools/binman/test/320_capsule_revert.dts
Normal file
11
tools/binman/test/320_capsule_revert.dts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
efi-empty-capsule {
|
||||
capsule-type = "revert";
|
||||
};
|
||||
};
|
||||
};
|
11
tools/binman/test/321_capsule_accept_missing_guid.dts
Normal file
11
tools/binman/test/321_capsule_accept_missing_guid.dts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
binman {
|
||||
efi-empty-capsule {
|
||||
capsule-type = "accept";
|
||||
};
|
||||
};
|
||||
};
|
12
tools/binman/test/322_empty_capsule_type_missing.dts
Normal file
12
tools/binman/test/322_empty_capsule_type_missing.dts
Normal file
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
13
tools/binman/test/323_capsule_accept_revert_missing.dts
Normal file
13
tools/binman/test/323_capsule_accept_revert_missing.dts
Normal file
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
Loading…
Reference in a new issue