
Hi Sughosh,
On Mon, 17 Jul 2023 at 04:44, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Sun, 16 Jul 2023 at 05:12, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Sat, 15 Jul 2023 at 07:46, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add support in binman for generating capsules. The capsule parameters can be specified either through a config file or through the capsule binman entry. Also add test cases in binman for capsule generation, and enable this testing on the sandbox_spl variant.
Can you use sandbox instead, or perhaps sandbox_spl? SPL is really for SPL testing.
Er, I am actually using the sandbox_spl variant.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V3:
- Add test cases for covering the various capsule generation scenarios.
- Add function comments in the mkeficapsule bintool.
- Fix the fetch method of the mkeficapsule bintool to enable building the tool.
- Add more details about the capsule parameters in the documentation as well as the code.
- Fix order of module imports, and addition of blank lines in the capsule.py file.
- Use SetContents in the ObtainContents method.
configs/sandbox_spl_defconfig | 1 + tools/binman/btool/mkeficapsule.py | 158 ++++++++++++++++++ tools/binman/entries.rst | 37 ++++ tools/binman/etype/capsule.py | 132 +++++++++++++++ tools/binman/ftest.py | 127 ++++++++++++++ tools/binman/test/282_capsule.dts | 18 ++ tools/binman/test/283_capsule_signed.dts | 20 +++ tools/binman/test/284_capsule_conf.dts | 14 ++ tools/binman/test/285_capsule_missing_key.dts | 19 +++ .../binman/test/286_capsule_missing_index.dts | 17 ++ .../binman/test/287_capsule_missing_guid.dts | 17 ++ .../test/288_capsule_missing_payload.dts | 17 ++ tools/binman/test/289_capsule_missing.dts | 17 ++ tools/binman/test/290_capsule_version.dts | 19 +++ tools/binman/test/capsule_cfg.txt | 6 + 15 files changed, 619 insertions(+) create mode 100644 tools/binman/btool/mkeficapsule.py create mode 100644 tools/binman/etype/capsule.py create mode 100644 tools/binman/test/282_capsule.dts create mode 100644 tools/binman/test/283_capsule_signed.dts create mode 100644 tools/binman/test/284_capsule_conf.dts create mode 100644 tools/binman/test/285_capsule_missing_key.dts create mode 100644 tools/binman/test/286_capsule_missing_index.dts create mode 100644 tools/binman/test/287_capsule_missing_guid.dts create mode 100644 tools/binman/test/288_capsule_missing_payload.dts create mode 100644 tools/binman/test/289_capsule_missing.dts create mode 100644 tools/binman/test/290_capsule_version.dts create mode 100644 tools/binman/test/capsule_cfg.txt
This looks pretty good to me. Some nits below
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index dd848c57c6..2fcc789347 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -248,3 +248,4 @@ CONFIG_UNIT_TEST=y CONFIG_SPL_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y +CONFIG_TOOLS_MKEFICAPSULE=y
Why enabling this here? I don't think it is needed in sandbox_spl, but in any case it should be in a different patch if needed.
The binman tests run on the sandbox_spl variant. When running the capsule generation tests, the mkeficapsule tool should be present on the board variant no?
Can we run this on the 'sandbox' variant instead?
[..]
- def ReadNode(self):
super().ReadNode()
self.cfg_file = fdt_util.GetString(self._node, 'cfg-file')
if not self.cfg_file:
self.image_index = fdt_util.GetInt(self._node, 'image-index')
if not self.image_index:
self.Raise('mkeficapsule must be provided an Image Index')
self.image_guid = fdt_util.GetString(self._node, 'image-type-id')
if not self.image_guid:
self.Raise('mkeficapsule must be provided an Image GUID')
Use self.required_props = ['image-type-id', ...] in your __init__(). Then this is automatic
I should have clarified this during the earlier version itself. So these parameters are mandatory only when not using the config file. In the scenario of generating the capsules through config files, all these parameters are provided through the config file. Hence these explicit checks.
Hmm, I think we should consider having two different etypes, then. It seems in fact that your entry type is doing 2-3 different things?
[..]
What if some of the inputs are missing? Does this handle missing blobs?
Any missing input parameters are checked earlier itself.
if self.cfg_file:
return self.mkeficapsule.capsule_cfg_file(self.cfg_file)
elif self.auth:
return self.mkeficapsule.cmdline_auth_capsule(self.image_index,
self.image_guid,
self.hardware_instance,
self.monotonic_count,
self.private_key,
self.pub_key_cert,
self.payload,
self.capsule_fname,
self.fw_version)
else:
return self.mkeficapsule.cmdline_capsule(self.image_index,
self.image_guid,
self.hardware_instance,
self.payload,
self.capsule_fname,
self.fw_version)
Here is where I wonder whether you are putting too much in a single etype. Here there are three different cases. Should we have 3 etypes?
[..]
We really should not have GUIDs in the code...they are a mess.
You want the UEFI capsule generation to happen through binman, and not mention GUIDs. That ain't happening :)
I just don't want them open-coded. They are meaningless gibberish that no one can understand. Use #define or some other way to give them a name.
If I wrote:
writel(0x09812374, 0x8723728)
you would have the same comment.
# Image GUID specified in the DTS
self.image_guid = "52cfd7092007104791d108469b7fe9c8"
self.fmp_signature = "4d535331"
self.fmp_size = "10"
self.fmp_fw_version = "02"
These should really be local vars, not members.
Okay
self.capsule_data = tools.read_file(self.capsule_fname)
Pass the data in here and then you don't need to read the file
So the file needs to be read here since the actual capsule generation tool(tools/mkeficapsule) does not return any capsule data. Instead, the data gets written to the capsule file, and the tool just returns a pass/fail status.
Sure, but you can read that data in the caller to this functoin.
self.assertEqual(self.capsule_guid, self.capsule_data.hex()[:32])
self.assertEqual(self.image_guid, self.capsule_data.hex()[96:128])
if version_check:
self.assertEqual(self.fmp_signature, self.capsule_data.hex()[184:192])
self.assertEqual(self.fmp_size, self.capsule_data.hex()[192:194])
self.assertEqual(self.fmp_fw_version, self.capsule_data.hex()[200:202])
if signed_capsule:
self.assertEqual(self.payload_data.hex(), self.capsule_data.hex()[4770:4778])
Where do these integer offsets come from? Please add a comment
So, these are simply offsets in the output capsule file, which get impacted based on the contents being put in the capsule, like presence/absence of optional headers. I don't think putting a comment really wll add any value, because these offsets are variable.
OK then please add a comment to that effect, as well as how to figure them out when things change.
elif version_check:
self.assertEqual(self.payload_data.hex(), self.capsule_data.hex()[216:224])
else:
self.assertEqual(self.payload_data.hex(), self.capsule_data.hex()[184:192])
- def _GenCapsuleCfgPayload(self, fname, contents):
capsule_dir = '/tmp/capsules/'
You can't write to /tmp
Please use self._indir for input files - see how other tests do it
For all other tests, I am indeed using _indir and outdir. But for generation of capsules through a config file, we need to specify the location where the output capsule file will be written to. Which is the reason for the /tmp/capsules/. We are using this directory for collating all capsule related files.
Well, sorry, you can't do that. I think you should provide a relative path, rather than absolute...that should solve the problem
[..]
Please can you use your own test data, like EFI_DATA ? Also if you declare it as a binary string you can drop the call.
For example:
EFI_DATA = b'efi'
I don't know why text_data cannot be used, but I will add the EFI_DATA.
Well firstly it is not a 'bytes' string. Secondly you may as well have your own as we have done with other etypes.
TestFunctional._MakeInputFile('payload.txt', self.payload_data)
self._DoReadFile('282_capsule.dts')
data = self...
Please see above. We need to read the capsule file. This applies for all the related comments about using the data = self._DoReadFile...
That needs to be fixed, since the output file should be the capsule. Why would the output file be anything else??
[..]
Regards, Simon