On 07.07.23 14:34, Neha Malcom Francis wrote: > The ti-board-config entry loads and validates a given YAML config file > against a given schema, and generates the board config binary. K3 > devices require these binaries to be packed into the final system > firmware images. > > Signed-off-by: Neha Malcom Francis <n-fran...@ti.com> > Reviewed-by: Simon Glass <s...@chromium.org> > --- > tools/binman/entries.rst | 48 ++++ > tools/binman/etype/ti_board_config.py | 259 ++++++++++++++++++ > tools/binman/ftest.py | 20 ++ > tools/binman/test/277_ti_board_cfg.dts | 14 + > .../binman/test/278_ti_board_cfg_combined.dts | 25 ++ > .../binman/test/279_ti_board_cfg_no_type.dts | 11 + > tools/binman/test/yaml/config.yaml | 19 ++ > tools/binman/test/yaml/schema.yaml | 51 ++++ > tools/binman/test/yaml/schema_notype.yaml | 40 +++ > 9 files changed, 487 insertions(+) > create mode 100644 tools/binman/etype/ti_board_config.py > create mode 100644 tools/binman/test/277_ti_board_cfg.dts > create mode 100644 tools/binman/test/278_ti_board_cfg_combined.dts > create mode 100644 tools/binman/test/279_ti_board_cfg_no_type.dts > create mode 100644 tools/binman/test/yaml/config.yaml > create mode 100644 tools/binman/test/yaml/schema.yaml > create mode 100644 tools/binman/test/yaml/schema_notype.yaml > > diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst > index b71af801fd..14a2d03fad 100644 > --- a/tools/binman/entries.rst > +++ b/tools/binman/entries.rst > @@ -1658,6 +1658,54 @@ by setting the size of the entry to something larger > than the text. > > > > +.. _etype_ti_board_config: > + > +Entry: ti-board-config: An entry containing a TI schema validated board > config binary > +------------------------------------------------------------------------------------- > + > +This etype supports generation of two kinds of board configuration > +binaries: singular board config binary as well as combined board config > +binary. > + > +Properties / Entry arguments: > + - config-file: File containing board configuration data in YAML > + - schema-file: File containing board configuration YAML schema against > + which the config file is validated > + > +Output files: > + - board config binary: File containing board configuration binary > + > +These above parameters are used only when the generated binary is > +intended to be a single board configuration binary. Example:: > + > + my-ti-board-config { > + ti-board-config { > + config = "board-config.yaml"; > + schema = "schema.yaml"; > + }; > + }; > + > +To generate a combined board configuration binary, we pack the > +needed individual binaries into a ti-board-config binary. In this case, > +the available supported subnode names are board-cfg, pm-cfg, sec-cfg and > +rm-cfg. The final binary is prepended with a header containing details about > +the included board config binaries. Example:: > + > + my-combined-ti-board-config { > + ti-board-config { > + board-cfg { > + config = "board-cfg.yaml"; > + schema = "schema.yaml"; > + }; > + sec-cfg { > + config = "sec-cfg.yaml"; > + schema = "schema.yaml"; > + }; > + } > + } > + > + > + > .. _etype_u_boot: > > Entry: u-boot: U-Boot flat binary > diff --git a/tools/binman/etype/ti_board_config.py > b/tools/binman/etype/ti_board_config.py > new file mode 100644 > index 0000000000..0799e5dc59 > --- /dev/null > +++ b/tools/binman/etype/ti_board_config.py > @@ -0,0 +1,259 @@ > +# SPDX-License-Identifier: GPL-2.0+ > +# Copyright (c) 2022 Texas Instruments Incorporated - https://www.ti.com/ > +# Written by Neha Malcom Francis <n-fran...@ti.com> > +# > +# Entry-type module for generating schema validated TI board > +# configuration binary > +# > + > +import os > +import struct > +import yaml > + > +from collections import OrderedDict > +from jsonschema import validate > +from shutil import copyfileobj > + > +from binman.entry import Entry > +from binman.etype.section import Entry_section > +from dtoc import fdt_util > +from u_boot_pylib import tools > + > +BOARDCFG = 0xB > +BOARDCFG_SEC = 0xD > +BOARDCFG_PM = 0xE > +BOARDCFG_RM = 0xC > +BOARDCFG_NUM_ELEMS = 4 > + > +class Entry_ti_board_config(Entry_section): > + """An entry containing a TI schema validated board config binary > + > + This etype supports generation of two kinds of board configuration > + binaries: singular board config binary as well as combined board config > + binary. > + > + Properties / Entry arguments: > + - config-file: File containing board configuration data in YAML > + - schema-file: File containing board configuration YAML schema > against > + which the config file is validated > + > + Output files: > + - board config binary: File containing board configuration binary > + > + These above parameters are used only when the generated binary is > + intended to be a single board configuration binary. Example:: > + > + my-ti-board-config { > + ti-board-config { > + config = "board-config.yaml"; > + schema = "schema.yaml"; > + }; > + }; > + > + To generate a combined board configuration binary, we pack the > + needed individual binaries into a ti-board-config binary. In this case, > + the available supported subnode names are board-cfg, pm-cfg, sec-cfg and > + rm-cfg. The final binary is prepended with a header containing details > about > + the included board config binaries. Example:: > + > + my-combined-ti-board-config { > + ti-board-config { > + board-cfg { > + config = "board-cfg.yaml"; > + schema = "schema.yaml"; > + }; > + sec-cfg { > + config = "sec-cfg.yaml"; > + schema = "schema.yaml"; > + }; > + } > + } > + """ > + def __init__(self, section, etype, node): > + super().__init__(section, etype, node) > + self._config = None > + self._schema = None > + self._entries = OrderedDict() > + self._num_elems = BOARDCFG_NUM_ELEMS > + self._fmt = '<HHHBB' > + self._index = 0 > + self._binary_offset = 0 > + self._sw_rev = 1 > + self._devgrp = 0 > + > + def ReadNode(self): > + super().ReadNode() > + self._config = fdt_util.GetString(self._node, 'config') > + self._schema = fdt_util.GetString(self._node, 'schema') > + # Depending on whether config file is present in node, we determine > + # whether it is a combined board config binary or not > + if self._config is None: > + self.ReadEntries() > + else: > + self._config_file = tools.get_input_filename(self._config) > + self._schema_file = tools.get_input_filename(self._schema) > + > + def ReadEntries(self): > + """Read the subnodes to find out what should go in this image > + """ > + for node in self._node.subnodes: > + if 'type' not in node.props: > + entry = Entry.Create(self, node, 'ti-board-config') > + entry.ReadNode() > + cfg_data = entry.BuildSectionData(True) > + entry._cfg_data = cfg_data > + self._entries[entry.name] = entry > + self._num_elems = len(self._node.subnodes) > + > + def _convert_to_byte_chunk(self, val, data_type): > + """Convert value into byte array > + > + Args: > + val: value to convert into byte array > + data_type: data type used in schema, supported data types are u8, > + u16 and u32 > + > + Returns: > + array of bytes representing value > + """ > + size = 0 > + if (data_type == '#/definitions/u8'): > + size = 1 > + elif (data_type == '#/definitions/u16'): > + size = 2 > + else: > + size = 4 > + if type(val) == int: > + br = val.to_bytes(size, byteorder='little') > + return br > + > + def _compile_yaml(self, schema_yaml, file_yaml): > + """Convert YAML file into byte array based on YAML schema > + > + Args: > + schema_yaml: file containing YAML schema > + file_yaml: file containing config to compile > + > + Returns: > + array of bytes repesenting YAML file against YAML schema > + """ > + br = bytearray() > + for key, node in file_yaml.items(): > + node_schema = schema_yaml['properties'][key] > + node_type = node_schema.get('type') > + if not 'type' in node_schema: > + br += self._convert_to_byte_chunk(node, > + node_schema.get('$ref')) > + elif node_type == 'object': > + br += self._compile_yaml(node_schema, node) > + elif node_type == 'array': > + for item in node: > + if not isinstance(item, dict): > + br += self._convert_to_byte_chunk( > + item, > schema_yaml['properties'][key]['items']['$ref']) > + else: > + br += self._compile_yaml(node_schema.get('items'), > item) > + return br > + > + def _generate_binaries(self): > + """Generate config binary artifacts from the loaded YAML > configuration file > + > + Returns: > + byte array containing config binary artifacts > + or None if generation fails > + """ > + cfg_binary = bytearray() > + for key, node in self.file_yaml.items(): > + node_schema = self.schema_yaml['properties'][key] > + br = self._compile_yaml(node_schema, node) > + cfg_binary += br > + return cfg_binary > + > + def _add_boardcfg(self, bcfgtype, bcfgdata): > + """Add board config to combined board config binary > + > + Args: > + bcfgtype (int): board config type > + bcfgdata (byte array): board config data > + """ > + size = len(bcfgdata) > + desc = struct.pack(self._fmt, bcfgtype, > + self._binary_offset, size, self._devgrp, 0) > + with open(self.descfile, 'ab+') as desc_fh: > + desc_fh.write(desc) > + with open(self.bcfgfile, 'ab+') as bcfg_fh: > + bcfg_fh.write(bcfgdata) > + self._binary_offset += size > + self._index += 1 > + > + def _finalize(self): > + """Generate final combined board config binary > + > + Returns: > + byte array containing combined board config data > + or None if unable to generate > + """ > + with open(self.descfile, 'rb') as desc_fh: > + with open(self.bcfgfile, 'rb') as bcfg_fh: > + with open(self.fh_file, 'ab+') as fh: > + copyfileobj(desc_fh, fh) > + copyfileobj(bcfg_fh, fh) > + data = tools.read_file(self.fh_file) > + return data > + > + def BuildSectionData(self, required): > + if self._config is None: > + self._binary_offset = 0 > + uniq = self.GetUniqueName() > + self.fh_file = tools.get_output_filename('fh.%s' % uniq) > + self.descfile = tools.get_output_filename('desc.%s' % uniq) > + self.bcfgfile = tools.get_output_filename('bcfg.%s' % uniq) > + > + # when binman runs again make sure we start clean > + if os.path.exists(self.fh_file): > + os.remove(self.fh_file) > + if os.path.exists(self.descfile): > + os.remove(self.descfile) > + if os.path.exists(self.bcfgfile): > + os.remove(self.bcfgfile) > + > + with open(self.fh_file, 'wb') as f: > + t_bytes = f.write(struct.pack( > + '<BB', self._num_elems, self._sw_rev)) > + self._binary_offset += t_bytes > + self._binary_offset += self._num_elems * > struct.calcsize(self._fmt) > + > + if 'board-cfg' in self._entries: > + self._add_boardcfg(BOARDCFG, > self._entries['board-cfg']._cfg_data) > + > + if 'sec-cfg' in self._entries: > + self._add_boardcfg(BOARDCFG_SEC, > self._entries['sec-cfg']._cfg_data) > + > + if 'pm-cfg' in self._entries: > + self._add_boardcfg(BOARDCFG_PM, > self._entries['pm-cfg']._cfg_data) > + > + if 'rm-cfg' in self._entries: > + self._add_boardcfg(BOARDCFG_RM, > self._entries['rm-cfg']._cfg_data) > + > + data = self._finalize() > + return data > + > + else: > + with open(self._config_file, 'r') as f: > + self.file_yaml = yaml.safe_load(f) > + with open(self._schema_file, 'r') as sch: > + self.schema_yaml = yaml.safe_load(sch) > + > + try: > + validate(self.file_yaml, self.schema_yaml) > + except Exception as e: > + self.Raise(f"Schema validation error: {e}") > + > + data = self._generate_binaries() > + return data > + > + def SetImagePos(self, image_pos): > + Entry.SetImagePos(self, image_pos) > + > + def CheckEntries(self): > + Entry.CheckEntries(self) > diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py > index 43b4f850a6..b9a490a5bd 100644 > --- a/tools/binman/ftest.py > +++ b/tools/binman/ftest.py > @@ -97,6 +97,7 @@ ENV_DATA = b'var1=1\nvar2="2"' > PRE_LOAD_MAGIC = b'UBSH' > PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big') > PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big') > +TI_BOARD_CONFIG_DATA = > b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' > > # Subdirectory of the input dir to use to put test FDTs > TEST_FDT_SUBDIR = 'fdts' > @@ -199,6 +200,9 @@ class TestFunctional(unittest.TestCase): > shutil.copytree(cls.TestFile('files'), > os.path.join(cls._indir, 'files')) > > + shutil.copytree(cls.TestFile('yaml'), > + os.path.join(cls._indir, 'yaml')) > + > TestFunctional._MakeInputFile('compress', COMPRESS_DATA) > TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG) > TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA) > @@ -6676,6 +6680,22 @@ fdt fdtmap Extract the > devicetree blob from the fdtmap > ['fit']) > self.assertIn("Node '/fit': Missing tool: 'mkimage'", > str(e.exception)) > > + def testTIBoardConfig(self): > + """Test that a schema validated board config file can be generated""" > + data = self._DoReadFile('277_ti_board_cfg.dts') > + self.assertEqual(TI_BOARD_CONFIG_DATA, data) > + > + def testTIBoardConfigCombined(self): > + """Test that a schema validated combined board config file can be > generated""" > + data = self._DoReadFile('278_ti_board_cfg_combined.dts') > + configlen_noheader = TI_BOARD_CONFIG_DATA * 4 > + self.assertGreater(data, configlen_noheader) > + > + def testTIBoardConfigNoDataType(self): > + """Test that error is thrown when data type is not supported""" > + with self.assertRaises(ValueError) as e: > + data = self._DoReadFile('279_ti_board_cfg_no_type.dts') > + self.assertIn("Schema validation error", str(e.exception)) > > if __name__ == "__main__": > unittest.main() > diff --git a/tools/binman/test/277_ti_board_cfg.dts > b/tools/binman/test/277_ti_board_cfg.dts > new file mode 100644 > index 0000000000..cda024c1b8 > --- /dev/null > +++ b/tools/binman/test/277_ti_board_cfg.dts > @@ -0,0 +1,14 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/dts-v1/; > + > +/ { > + #address-cells = <1>; > + #size-cells = <1>; > + > + binman { > + ti-board-config { > + config = "yaml/config.yaml"; > + schema = "yaml/schema.yaml"; > + }; > + }; > +}; > diff --git a/tools/binman/test/278_ti_board_cfg_combined.dts > b/tools/binman/test/278_ti_board_cfg_combined.dts > new file mode 100644 > index 0000000000..95ef449cbf > --- /dev/null > +++ b/tools/binman/test/278_ti_board_cfg_combined.dts > @@ -0,0 +1,25 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/dts-v1/; > + > +/ { > + binman { > + ti-board-config { > + board-cfg { > + config = "yaml/config.yaml"; > + schema = "yaml/schema.yaml"; > + }; > + sec-cfg { > + config = "yaml/config.yaml"; > + schema = "yaml/schema.yaml"; > + }; > + rm-cfg { > + config = "yaml/config.yaml"; > + schema = "yaml/schema.yaml"; > + }; > + pm-cfg { > + config = "yaml/config.yaml"; > + schema = "yaml/schema.yaml"; > + }; > + }; > + }; > +}; > diff --git a/tools/binman/test/279_ti_board_cfg_no_type.dts > b/tools/binman/test/279_ti_board_cfg_no_type.dts > new file mode 100644 > index 0000000000..584b7acc5a > --- /dev/null > +++ b/tools/binman/test/279_ti_board_cfg_no_type.dts > @@ -0,0 +1,11 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/dts-v1/; > + > +/ { > + binman { > + ti-board-config { > + config = "yaml/config.yaml"; > + schema = "yaml/schema_notype.yaml"; > + }; > + }; > +}; > diff --git a/tools/binman/test/yaml/config.yaml > b/tools/binman/test/yaml/config.yaml > new file mode 100644 > index 0000000000..79fd67c7f4 > --- /dev/null > +++ b/tools/binman/test/yaml/config.yaml > @@ -0,0 +1,19 @@ > +# SPDX-License-Identifier: GPL-2.0+ > +# Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ > +# > +# Test config > +# > +--- > + > +main-branch: > + obj: > + a: 0x0 > + b: 0 > + arr: [0, 0, 0, 0] > + another-arr: > + - #1 > + c: 0 > + d: 0 > + - #2 > + c: 0 > + d: 0 > diff --git a/tools/binman/test/yaml/schema.yaml > b/tools/binman/test/yaml/schema.yaml > new file mode 100644 > index 0000000000..60bf56f671 > --- /dev/null > +++ b/tools/binman/test/yaml/schema.yaml > @@ -0,0 +1,51 @@ > +# SPDX-License-Identifier: GPL-2.0+ > +# Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ > +# > +# Test schema > +# > +--- > + > +definitions: > + u8: > + type: integer > + minimum: 0 > + maximum: 0xff > + u16: > + type: integer > + minimum: 0 > + maximum: 0xffff > + u32: > + type: integer > + minimum: 0 > + maximum: 0xffffffff > + > +type: object > +properties: > + main-branch: > + type: object > + properties: > + obj: > + type: object > + properties: > + a: > + $ref: "#/definitions/u32" > + b: > + $ref: "#/definitions/u16" > + arr: > + type: array > + minItems: 4 > + maxItems: 4 > + items: > + $ref: "#/definitions/u8" > + another-arr: > + type: array > + minItems: 2 > + maxItems: 2 > + items: > + type: object > + properties: > + c: > + $ref: "#/definitions/u8" > + d: > + $ref: "#/definitions/u8" > + > diff --git a/tools/binman/test/yaml/schema_notype.yaml > b/tools/binman/test/yaml/schema_notype.yaml > new file mode 100644 > index 0000000000..d45d6cdf7e > --- /dev/null > +++ b/tools/binman/test/yaml/schema_notype.yaml > @@ -0,0 +1,40 @@ > +# SPDX-License-Identifier: GPL-2.0+ > +# Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/ > +# > +# Test schema > +# > +--- > + > +definitions: > + u8: > + type: integer > + minimum: 0 > + maximum: 0xff > + u16: > + type: integer > + minimum: 0 > + maximum: 0xffff > + u32: > + type: integer > + minimum: 0 > + maximum: 0xffffffff > + > +type: object > +properties: > + main-branch: > + type: object > + properties: > + obj: > + type: object > + properties: > + a: > + $ref: "#/definitions/u4" > + b: > + $ref: "#/definitions/u16" > + arr: > + type: array > + minItems: 4 > + maxItems: 4 > + items: > + $ref: "#/definitions/u8" > +
... Applying: binman: ti-board-config: Add support for TI board config binaries .git/rebase-apply/patch:538: new blank line at EOF. + .git/rebase-apply/patch:584: new blank line at EOF. + warning: 2 lines add whitespace errors. Jan -- Siemens AG, Technology Competence Center Embedded Linux