mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
Merge tag 'dm-pull-29jul24' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm
qconfig minor improvement binman support for alternate entries
This commit is contained in:
3
Makefile
3
Makefile
@@ -1388,9 +1388,12 @@ cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
|
||||
-a rockchip-tpl-path=$(ROCKCHIP_TPL) \
|
||||
-a spl-bss-pad=$(if $(CONFIG_SPL_SEPARATE_BSS),,1) \
|
||||
-a tpl-bss-pad=$(if $(CONFIG_TPL_SEPARATE_BSS),,1) \
|
||||
-a vpl-bss-pad=$(if $(CONFIG_VPL_SEPARATE_BSS),,1) \
|
||||
-a spl-dtb=$(CONFIG_SPL_OF_REAL) \
|
||||
-a tpl-dtb=$(CONFIG_TPL_OF_REAL) \
|
||||
-a vpl-dtb=$(CONFIG_VPL_OF_REAL) \
|
||||
-a pre-load-key-path=${PRE_LOAD_KEY_PATH} \
|
||||
-a of-spl-remove-props=$(CONFIG_OF_SPL_REMOVE_PROPS) \
|
||||
$(BINMAN_$(@F))
|
||||
|
||||
OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex
|
||||
|
||||
@@ -85,6 +85,20 @@ example, to find boards which enabled CONFIG_SCSI but not CONFIG_BLK::
|
||||
3 matches
|
||||
pg_wcom_seli8_defconfig highbank_defconfig pg_wcom_expu1_defconfig
|
||||
|
||||
It is also possible to search for particular values. For example, this finds all
|
||||
boards with an empty string for `CONFIG_DEFAULT_FDT_FILE`::
|
||||
|
||||
./tools/qconfig.py -f DEFAULT_FDT_FILE=\"\"
|
||||
1092 matches
|
||||
...
|
||||
|
||||
This finds boards which have a value for SYS_MAXARGS other than 64::
|
||||
|
||||
./tools/qconfig.py -f ~SYS_MAXARGS=64
|
||||
cfg CONFIG_SYS_MAXARGS
|
||||
281 matches
|
||||
...
|
||||
|
||||
|
||||
Finding implied CONFIGs
|
||||
-----------------------
|
||||
|
||||
@@ -121,6 +121,8 @@ Use `spl_phase()` to find the current U-Boot phase, e.g. `PHASE_SPL`. You can
|
||||
also find the previous and next phase and get the phase name.
|
||||
|
||||
|
||||
.. _fdtgrep_filter:
|
||||
|
||||
Device tree
|
||||
-----------
|
||||
The U-Boot device tree is filtered by the fdtgrep tools during the build
|
||||
|
||||
@@ -421,6 +421,8 @@ int main(int argc, char *argv[])
|
||||
strcpy(tmp_buf, "SPL_");
|
||||
else if (!strncmp(target, "tpl/", 4))
|
||||
strcpy(tmp_buf, "TPL_");
|
||||
else if (!strncmp(target, "vpl/", 4))
|
||||
strcpy(tmp_buf, "VPL_");
|
||||
/* end U-Boot hack */
|
||||
|
||||
xprintf("cmd_%s := %s\n\n", target, cmdline);
|
||||
|
||||
@@ -1211,7 +1211,7 @@ Templates provide a simple way to handle this::
|
||||
|
||||
spi-image {
|
||||
filename = "image-spi.bin";
|
||||
insert-template = <&fit>;
|
||||
insert-template = <&common_part>;
|
||||
|
||||
/* things specific to SPI follow */
|
||||
footer {
|
||||
@@ -1224,7 +1224,7 @@ Templates provide a simple way to handle this::
|
||||
|
||||
mmc-image {
|
||||
filename = "image-mmc.bin";
|
||||
insert-template = <&fit>;
|
||||
insert-template = <&common_part>;
|
||||
|
||||
/* things specific to MMC follow */
|
||||
footer {
|
||||
|
||||
@@ -10,6 +10,15 @@ binaries. It is fairly easy to create new bintools. Just add a new file to the
|
||||
|
||||
|
||||
|
||||
Bintool: bootgen: Generate bootable fsbl image for zynq/zynqmp
|
||||
--------------------------------------------------------------
|
||||
|
||||
This bintools supports running Xilinx "bootgen" in order
|
||||
to generate a bootable, authenticated image form an SPL.
|
||||
|
||||
|
||||
|
||||
|
||||
Bintool: bzip2: Compression/decompression using the bzip2 algorithm
|
||||
-------------------------------------------------------------------
|
||||
|
||||
@@ -37,6 +46,33 @@ Documentation about CBFS is at https://www.coreboot.org/CBFS
|
||||
|
||||
|
||||
|
||||
Bintool: cst: Image generation for U-Boot
|
||||
-----------------------------------------
|
||||
|
||||
This bintool supports running `cst` with some basic parameters as
|
||||
needed by binman.
|
||||
|
||||
|
||||
|
||||
Bintool: fdt_add_pubkey: Add public key to control dtb (spl or u-boot proper)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
This bintool supports running `fdt_add_pubkey`.
|
||||
|
||||
Normally mkimage adds signature information to the control dtb. However
|
||||
binman images are built independent from each other. Thus it is required
|
||||
to add the public key separately from mkimage.
|
||||
|
||||
|
||||
|
||||
Bintool: fdtgrep: Handles the 'fdtgrep' tool
|
||||
--------------------------------------------
|
||||
|
||||
This bintool supports running `fdtgrep` with parameters suitable for
|
||||
producing SPL devicetrees from the main one.
|
||||
|
||||
|
||||
|
||||
Bintool: fiptool: Image generation for ARM Trusted Firmware
|
||||
-----------------------------------------------------------
|
||||
|
||||
@@ -143,11 +179,20 @@ Documentation is available via::
|
||||
|
||||
|
||||
|
||||
Bintool: mkeficapsule: Handles the 'mkeficapsule' tool
|
||||
------------------------------------------------------
|
||||
|
||||
This bintool is used for generating the EFI capsules. The
|
||||
capsule generation parameters can either be specified through
|
||||
commandline, or through a config file.
|
||||
|
||||
|
||||
|
||||
Bintool: mkimage: Image generation for U-Boot
|
||||
---------------------------------------------
|
||||
|
||||
This bintool supports running `mkimage` with some basic parameters as
|
||||
neeed by binman.
|
||||
needed by binman.
|
||||
|
||||
Normally binman uses the mkimage built by U-Boot. But when run outside the
|
||||
U-Boot build system, binman can use the version installed in your system.
|
||||
@@ -194,25 +239,3 @@ Documentation is available via::
|
||||
|
||||
|
||||
|
||||
Bintool: fdt_add_pubkey: Add public key to device tree
|
||||
------------------------------------------------------
|
||||
|
||||
This bintool supports running `fdt_add_pubkey` in order to add a public
|
||||
key coming from a certificate to a device-tree.
|
||||
|
||||
Normally signing is done using `mkimage` in context of `binman sign`. However,
|
||||
in this process the public key is not added to the stage before u-boot proper.
|
||||
Using `fdt_add_pubkey` the key can be injected to the SPL independent of
|
||||
`mkimage`
|
||||
|
||||
|
||||
|
||||
Bintool: bootgen: Sign ZynqMP FSBL image
|
||||
----------------------------------------
|
||||
|
||||
This bintool supports running `bootgen` in order to sign a SPL for ZynqMP
|
||||
devices.
|
||||
|
||||
The bintool automatically creates an appropriate input image file (.bif) for
|
||||
bootgen based on the passed arguments. The output is a bootable,
|
||||
authenticated `boot.bin` file.
|
||||
|
||||
@@ -32,6 +32,10 @@ class Bintoolfdt_add_pubkey(bintool.Bintool):
|
||||
verified for the image / configuration to be considered valid.
|
||||
algo (str): Cryptographic algorithm. Optional parameter,
|
||||
default value: sha1,rsa2048
|
||||
|
||||
Returns:
|
||||
CommandResult: Resulting output from the bintool, or None if the
|
||||
tool is not present
|
||||
"""
|
||||
args = []
|
||||
if algo:
|
||||
|
||||
137
tools/binman/btool/fdtgrep.py
Normal file
137
tools/binman/btool/fdtgrep.py
Normal file
@@ -0,0 +1,137 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright 2022 Google LLC
|
||||
#
|
||||
"""Bintool implementation for fdtgrep
|
||||
|
||||
fdtgrepprovides a way to grep devicetree-binary files to extract or remove
|
||||
certain elements.
|
||||
|
||||
Usage: fdtgrep - extract portions from device tree
|
||||
|
||||
Usage:
|
||||
fdtgrep <options> <dt file>|-
|
||||
|
||||
Output formats are:
|
||||
dts - device tree soure text
|
||||
dtb - device tree blob (sets -Hmt automatically)
|
||||
bin - device tree fragment (may not be a valid .dtb)
|
||||
|
||||
Options: -[haAc:b:C:defg:G:HIlLmn:N:o:O:p:P:rRsStTvhV]
|
||||
-a, --show-address Display address
|
||||
-A, --colour Show all nodes/tags, colour those that match
|
||||
-b, --include-node-with-prop <arg> Include contains containing property
|
||||
-c, --include-compat <arg> Compatible nodes to include in grep
|
||||
-C, --exclude-compat <arg> Compatible nodes to exclude in grep
|
||||
-d, --diff Diff: Mark matching nodes with +, others with -
|
||||
-e, --enter-node Enter direct subnode names of matching nodes
|
||||
-f, --show-offset Display offset
|
||||
-g, --include-match <arg> Node/property/compatible string to include in grep
|
||||
-G, --exclude-match <arg> Node/property/compatible string to exclude in grep
|
||||
-H, --show-header Output a header
|
||||
-I, --show-version Put "/dts-v1/;" on first line of dts output
|
||||
-l, --list-regions Output a region list
|
||||
-L, --list-strings List strings in string table
|
||||
-m, --include-mem Include mem_rsvmap section in binary output
|
||||
-n, --include-node <arg> Node to include in grep
|
||||
-N, --exclude-node <arg> Node to exclude in grep
|
||||
-p, --include-prop <arg> Property to include in grep
|
||||
-P, --exclude-prop <arg> Property to exclude in grep
|
||||
-r, --remove-strings Remove unused strings from string table
|
||||
-R, --include-root Include root node and all properties
|
||||
-s, --show-subnodes Show all subnodes matching nodes
|
||||
-S, --skip-supernodes Don't include supernodes of matching nodes
|
||||
-t, --show-stringtab Include string table in binary output
|
||||
-T, --show-aliases Include matching aliases in output
|
||||
-o, --out <arg> -o <output file>
|
||||
-O, --out-format <arg> -O <output format>
|
||||
-v, --invert-match Invert the sense of matching (select non-matching lines)
|
||||
-h, --help Print this help and exit
|
||||
-V, --version Print version and exit
|
||||
"""
|
||||
|
||||
import tempfile
|
||||
|
||||
from u_boot_pylib import tools
|
||||
from binman import bintool
|
||||
|
||||
class Bintoolfdtgrep(bintool.Bintool):
|
||||
"""Handles the 'fdtgrep' tool
|
||||
|
||||
This bintool supports running `fdtgrep` with parameters suitable for
|
||||
producing SPL devicetrees from the main one.
|
||||
"""
|
||||
def __init__(self, name):
|
||||
super().__init__(name, 'Grep devicetree files')
|
||||
|
||||
def create_for_phase(self, infile, phase, outfile, remove_props):
|
||||
"""Create the FDT for a particular phase
|
||||
|
||||
Args:
|
||||
infile (str): Input filename containing the full FDT contents (with
|
||||
all nodes and properties)
|
||||
phase (str): Phase to generate for ('tpl', 'vpl', 'spl')
|
||||
outfile (str): Output filename to write the grepped FDT contents to
|
||||
(with only neceesary nodes and properties)
|
||||
|
||||
Returns:
|
||||
CommandResult: Resulting output from the bintool, or None if the
|
||||
tool is not present
|
||||
"""
|
||||
if phase == 'tpl':
|
||||
tag = 'bootph-pre-sram'
|
||||
elif phase == 'vpl':
|
||||
tag = 'bootph-verify'
|
||||
elif phase == 'spl':
|
||||
tag = 'bootph-pre-ram'
|
||||
else:
|
||||
raise ValueError(f"Invalid U-Boot phase '{phase}': Use tpl/vpl/spl")
|
||||
|
||||
# These args mirror those in cmd_fdtgrep in scripts/Makefile.lib
|
||||
# First do the first stage
|
||||
with tempfile.NamedTemporaryFile(prefix='fdtgrep.tmp',
|
||||
dir=tools.get_output_dir()) as tmp:
|
||||
args = [
|
||||
infile,
|
||||
'-o', tmp.name,
|
||||
'-b', 'bootph-all',
|
||||
'-b', tag,
|
||||
'-u',
|
||||
'-RT',
|
||||
'-n', '/chosen',
|
||||
'-n', '/config',
|
||||
'-O', 'dtb',
|
||||
]
|
||||
self.run_cmd(*args)
|
||||
args = [
|
||||
tmp.name,
|
||||
'-o', outfile,
|
||||
'-r',
|
||||
'-O', 'dtb',
|
||||
'-P', 'bootph-all',
|
||||
'-P', 'bootph-pre-ram',
|
||||
'-P', 'bootph-pre-sram',
|
||||
'-P', 'bootph-verify',
|
||||
]
|
||||
for prop_name in remove_props:
|
||||
args += ['-P', prop_name]
|
||||
return self.run_cmd(*args)
|
||||
|
||||
def fetch(self, method):
|
||||
"""Fetch handler for fdtgrep
|
||||
|
||||
This installs fdtgrep using the apt utility, which assumes that it is
|
||||
packaged in u-boot tools, which it is not.
|
||||
|
||||
Args:
|
||||
method (FETCH_...): Method to use
|
||||
|
||||
Returns:
|
||||
True if the file was fetched and now installed, None if a method
|
||||
other than FETCH_BIN was requested
|
||||
|
||||
Raises:
|
||||
Valuerror: Fetching could not be completed
|
||||
"""
|
||||
if method != bintool.FETCH_BIN:
|
||||
return None
|
||||
return self.apt_install('u-boot-tools')
|
||||
@@ -617,6 +617,50 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded):
|
||||
dtb_item.Flush()
|
||||
return images
|
||||
|
||||
def CheckForProblems(image):
|
||||
"""Check for problems with image generation
|
||||
|
||||
Shows warning about missing, faked or optional external blobs, as well as
|
||||
missing bintools.
|
||||
|
||||
Args:
|
||||
image (Image): Image to process
|
||||
|
||||
Returns:
|
||||
bool: True if there are any problems which result in a non-functional
|
||||
image
|
||||
"""
|
||||
missing_list = []
|
||||
image.CheckMissing(missing_list)
|
||||
if missing_list:
|
||||
tout.error("Image '%s' is missing external blobs and is non-functional: %s\n" %
|
||||
(image.name, ' '.join([e.name for e in missing_list])))
|
||||
_ShowHelpForMissingBlobs(tout.ERROR, missing_list)
|
||||
|
||||
faked_list = []
|
||||
image.CheckFakedBlobs(faked_list)
|
||||
if faked_list:
|
||||
tout.warning(
|
||||
"Image '%s' has faked external blobs and is non-functional: %s\n" %
|
||||
(image.name, ' '.join([os.path.basename(e.GetDefaultFilename())
|
||||
for e in faked_list])))
|
||||
|
||||
optional_list = []
|
||||
image.CheckOptional(optional_list)
|
||||
if optional_list:
|
||||
tout.warning(
|
||||
"Image '%s' is missing optional external blobs but is still functional: %s\n" %
|
||||
(image.name, ' '.join([e.name for e in optional_list])))
|
||||
_ShowHelpForMissingBlobs(tout.WARNING, optional_list)
|
||||
|
||||
missing_bintool_list = []
|
||||
image.check_missing_bintools(missing_bintool_list)
|
||||
if missing_bintool_list:
|
||||
tout.warning(
|
||||
"Image '%s' has missing bintools and is non-functional: %s\n" %
|
||||
(image.name, ' '.join([os.path.basename(bintool.name)
|
||||
for bintool in missing_bintool_list])))
|
||||
return any([missing_list, faked_list, missing_bintool_list])
|
||||
|
||||
def ProcessImage(image, update_fdt, write_map, get_contents=True,
|
||||
allow_resize=True, allow_missing=False,
|
||||
@@ -689,38 +733,11 @@ def ProcessImage(image, update_fdt, write_map, get_contents=True,
|
||||
if write_map:
|
||||
image.WriteMap()
|
||||
|
||||
missing_list = []
|
||||
image.CheckMissing(missing_list)
|
||||
if missing_list:
|
||||
tout.error("Image '%s' is missing external blobs and is non-functional: %s\n" %
|
||||
(image.name, ' '.join([e.name for e in missing_list])))
|
||||
_ShowHelpForMissingBlobs(tout.ERROR, missing_list)
|
||||
has_problems = CheckForProblems(image)
|
||||
|
||||
faked_list = []
|
||||
image.CheckFakedBlobs(faked_list)
|
||||
if faked_list:
|
||||
tout.warning(
|
||||
"Image '%s' has faked external blobs and is non-functional: %s\n" %
|
||||
(image.name, ' '.join([os.path.basename(e.GetDefaultFilename())
|
||||
for e in faked_list])))
|
||||
|
||||
optional_list = []
|
||||
image.CheckOptional(optional_list)
|
||||
if optional_list:
|
||||
tout.warning(
|
||||
"Image '%s' is missing optional external blobs but is still functional: %s\n" %
|
||||
(image.name, ' '.join([e.name for e in optional_list])))
|
||||
_ShowHelpForMissingBlobs(tout.WARNING, optional_list)
|
||||
|
||||
missing_bintool_list = []
|
||||
image.check_missing_bintools(missing_bintool_list)
|
||||
if missing_bintool_list:
|
||||
tout.warning(
|
||||
"Image '%s' has missing bintools and is non-functional: %s\n" %
|
||||
(image.name, ' '.join([os.path.basename(bintool.name)
|
||||
for bintool in missing_bintool_list])))
|
||||
return any([missing_list, faked_list, missing_bintool_list])
|
||||
image.WriteAlternates()
|
||||
|
||||
return has_problems
|
||||
|
||||
def Binman(args):
|
||||
"""The main control code for binman
|
||||
|
||||
@@ -275,7 +275,7 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
|
||||
return 0
|
||||
base = syms.get(base_sym)
|
||||
if not base and not is_elf:
|
||||
tout.debug('LookupAndWriteSymbols: no base')
|
||||
tout.debug(f'LookupAndWriteSymbols: no base: elf_fname={elf_fname}, base_sym={base_sym}, is_elf={is_elf}')
|
||||
return 0
|
||||
base_addr = 0 if is_elf else base.address
|
||||
count = 0
|
||||
|
||||
@@ -11,6 +11,48 @@ features to produce new behaviours.
|
||||
|
||||
|
||||
|
||||
.. _etype_alternates_fdt:
|
||||
|
||||
Entry: alternates-fdt: Entry that generates alternative sections for each devicetree provided
|
||||
---------------------------------------------------------------------------------------------
|
||||
|
||||
When creating an image designed to boot on multiple models, each model
|
||||
requires its own devicetree. This entry deals with selecting the correct
|
||||
devicetree from a directory containing them. Each one is read in turn, then
|
||||
used to produce section contents which are written to a file. This results
|
||||
in a number of images, one for each model.
|
||||
|
||||
For example this produces images for each .dtb file in the 'dtb' directory::
|
||||
|
||||
alternates-fdt {
|
||||
fdt-list-dir = "dtb";
|
||||
filename-pattern = "NAME.bin";
|
||||
fdt-phase = "tpl";
|
||||
|
||||
section {
|
||||
u-boot-tpl {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Each output file is named based on its input file, so an input file of
|
||||
`model1.dtb` results in an output file of `model1.bin` (i.e. the `NAME` in
|
||||
the `filename-pattern` property is replaced with the .dtb basename).
|
||||
|
||||
Note that this entry type still produces contents for the 'main' image, in
|
||||
that case using the normal dtb provided to Binman, e.g. `u-boot-tpl.dtb`.
|
||||
But that image is unlikely to be useful, since it relates to whatever dtb
|
||||
happened to be the default when U-Boot builds
|
||||
(i.e. `CONFIG_DEFAULT_DEVICE_TREE`). However, Binman ensures that the size
|
||||
of each of the alternates is the same as the 'default' one, so they can in
|
||||
principle be 'slotted in' to the appropriate place in the main image.
|
||||
|
||||
The optional `fdt-phase` property indicates the phase to build. In this
|
||||
case, it etype runs fdtgrep to obtain the devicetree subset for that phase,
|
||||
respecting the `bootph-xxx` tags in the devicetree.
|
||||
|
||||
|
||||
|
||||
.. _etype_atf_bl31:
|
||||
|
||||
Entry: atf-bl31: ARM Trusted Firmware (ATF) BL31 blob
|
||||
@@ -815,6 +857,13 @@ The top-level 'fit' node supports the following special properties:
|
||||
|
||||
fit,fdt-list-val = "dtb1", "dtb2";
|
||||
|
||||
fit,fdt-list-dir
|
||||
As an alternative to fit,fdt-list the list of device tree files
|
||||
can be provided as a directory. Each .dtb file in the directory is
|
||||
processed, , e.g.::
|
||||
|
||||
fit,fdt-list-dir = "arch/arm/dts
|
||||
|
||||
Substitutions
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
@@ -890,6 +939,7 @@ You can create config nodes in a similar way::
|
||||
firmware = "atf";
|
||||
loadables = "uboot";
|
||||
fdt = "fdt-SEQ";
|
||||
fit,compatible; // optional
|
||||
};
|
||||
};
|
||||
|
||||
@@ -899,6 +949,39 @@ for each of your two files.
|
||||
Note that if no devicetree files are provided (with '-a of-list' as above)
|
||||
then no nodes will be generated.
|
||||
|
||||
The 'fit,compatible' property (if present) is replaced with the compatible
|
||||
string from the root node of the devicetree, so that things work correctly
|
||||
with FIT's configuration-matching algortihm.
|
||||
|
||||
Dealing with phases
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
FIT can be used to load firmware. In this case it may be necessary to run
|
||||
the devicetree for each model through fdtgrep to remove unwanted properties.
|
||||
The 'fit,fdt-phase' property can be provided to indicate the phase for which
|
||||
the devicetree is intended.
|
||||
|
||||
For example this indicates that the FDT should be processed for VPL::
|
||||
|
||||
images {
|
||||
@fdt-SEQ {
|
||||
description = "fdt-NAME";
|
||||
type = "flat_dt";
|
||||
compression = "none";
|
||||
fit,fdt-phase = "vpl";
|
||||
};
|
||||
};
|
||||
|
||||
Using this mechanism, it is possible to generate a FIT which can provide VPL
|
||||
images for multiple models, with TPL selecting the correct model to use. The
|
||||
same approach can of course be used for SPL images.
|
||||
|
||||
Note that the `of-spl-remove-props` entryarg can be used to indicate
|
||||
additional properties to remove. It is often used to remove properties like
|
||||
`clock-names` and `pinctrl-names` which are not needed in SPL builds.
|
||||
|
||||
See :ref:`fdtgrep_filter` for more information.
|
||||
|
||||
Generating nodes from an ELF file (split-elf)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -2290,8 +2373,6 @@ u-boot-spl-dtb
|
||||
|
||||
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the SPL binary.
|
||||
|
||||
@@ -2480,8 +2561,6 @@ u-boot-tpl-dtb
|
||||
|
||||
TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the TPL binary.
|
||||
|
||||
@@ -2571,6 +2650,9 @@ in the binman README for more information.
|
||||
The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the VPL binary.
|
||||
|
||||
Note that this entry is automatically replaced with u-boot-vpl-expanded
|
||||
unless --no-expanded is used or the node has a 'no-expanded' property.
|
||||
|
||||
|
||||
|
||||
.. _etype_u_boot_vpl_bss_pad:
|
||||
@@ -2659,8 +2741,8 @@ Properties / Entry arguments:
|
||||
|
||||
This is the U-Boot VPL binary, It does not include a device tree blob at
|
||||
the end of it so may not be able to work without it, assuming VPL needs
|
||||
a device tree to operate on your platform. You can add a u_boot_vpl_dtb
|
||||
entry after this one, or use a u_boot_vpl entry instead, which normally
|
||||
a device tree to operate on your platform. You can add a u-boot-vpl-dtb
|
||||
entry after this one, or use a u-boot-vpl entry instead, which normally
|
||||
expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
|
||||
u-boot-vpl-dtb
|
||||
|
||||
|
||||
@@ -1199,6 +1199,9 @@ features to produce new behaviours.
|
||||
self.uncomp_size = len(indata)
|
||||
if self.comp_bintool.is_present():
|
||||
data = self.comp_bintool.compress(indata)
|
||||
uniq = self.GetUniqueName()
|
||||
fname = tools.get_output_filename(f'comp.{uniq}')
|
||||
tools.write_file(fname, data)
|
||||
else:
|
||||
self.record_missing_bintool(self.comp_bintool)
|
||||
data = tools.get_bytes(0, 1024)
|
||||
@@ -1383,3 +1386,17 @@ features to produce new behaviours.
|
||||
|
||||
def UpdateSignatures(self, privatekey_fname, algo, input_fname):
|
||||
self.Raise('Updating signatures is not supported with this entry type')
|
||||
|
||||
def FdtContents(self, fdt_etype):
|
||||
"""Get the contents of an FDT for a particular phase
|
||||
|
||||
Args:
|
||||
fdt_etype (str): Filename of the phase of the FDT to return, e.g.
|
||||
'u-boot-tpl-dtb'
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
fname (str): Filename of .dtb
|
||||
bytes: Contents of FDT (possibly run through fdtgrep)
|
||||
"""
|
||||
return self.section.FdtContents(fdt_etype)
|
||||
|
||||
132
tools/binman/etype/alternates_fdt.py
Normal file
132
tools/binman/etype/alternates_fdt.py
Normal file
@@ -0,0 +1,132 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright 2024 Google LLC
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
"""Entry-type module for producing multiple alternate sections"""
|
||||
|
||||
import glob
|
||||
import os
|
||||
|
||||
from binman.entry import EntryArg
|
||||
from binman.etype.section import Entry_section
|
||||
from dtoc import fdt_util
|
||||
from u_boot_pylib import tools
|
||||
|
||||
class Entry_alternates_fdt(Entry_section):
|
||||
"""Entry that generates alternative sections for each devicetree provided
|
||||
|
||||
When creating an image designed to boot on multiple models, each model
|
||||
requires its own devicetree. This entry deals with selecting the correct
|
||||
devicetree from a directory containing them. Each one is read in turn, then
|
||||
used to produce section contents which are written to a file. This results
|
||||
in a number of images, one for each model.
|
||||
|
||||
For example this produces images for each .dtb file in the 'dtb' directory::
|
||||
|
||||
alternates-fdt {
|
||||
fdt-list-dir = "dtb";
|
||||
filename-pattern = "NAME.bin";
|
||||
fdt-phase = "tpl";
|
||||
|
||||
section {
|
||||
u-boot-tpl {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Each output file is named based on its input file, so an input file of
|
||||
`model1.dtb` results in an output file of `model1.bin` (i.e. the `NAME` in
|
||||
the `filename-pattern` property is replaced with the .dtb basename).
|
||||
|
||||
Note that this entry type still produces contents for the 'main' image, in
|
||||
that case using the normal dtb provided to Binman, e.g. `u-boot-tpl.dtb`.
|
||||
But that image is unlikely to be useful, since it relates to whatever dtb
|
||||
happened to be the default when U-Boot builds
|
||||
(i.e. `CONFIG_DEFAULT_DEVICE_TREE`). However, Binman ensures that the size
|
||||
of each of the alternates is the same as the 'default' one, so they can in
|
||||
principle be 'slotted in' to the appropriate place in the main image.
|
||||
|
||||
The optional `fdt-phase` property indicates the phase to build. In this
|
||||
case, it etype runs fdtgrep to obtain the devicetree subset for that phase,
|
||||
respecting the `bootph-xxx` tags in the devicetree.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
super().__init__(section, etype, node)
|
||||
self.fdt_list_dir = None
|
||||
self.filename_pattern = None
|
||||
self.required_props = ['fdt-list-dir']
|
||||
self._cur_fdt = None
|
||||
self._fdt_phase = None
|
||||
self.fdtgrep = None
|
||||
self._fdt_dir = None
|
||||
self._fdts = None
|
||||
self._fname_pattern = None
|
||||
self._remove_props = None
|
||||
self.alternates = None
|
||||
|
||||
def ReadNode(self):
|
||||
"""Read properties from the node"""
|
||||
super().ReadNode()
|
||||
self._fdt_dir = fdt_util.GetString(self._node, 'fdt-list-dir')
|
||||
fname = tools.get_input_filename(self._fdt_dir)
|
||||
fdts = glob.glob('*.dtb', root_dir=fname)
|
||||
self._fdts = [os.path.splitext(f)[0] for f in fdts]
|
||||
|
||||
self._fdt_phase = fdt_util.GetString(self._node, 'fdt-phase')
|
||||
|
||||
# This is used by Image.WriteAlternates()
|
||||
self.alternates = self._fdts
|
||||
|
||||
self._fname_pattern = fdt_util.GetString(self._node, 'filename-pattern')
|
||||
|
||||
self._remove_props = []
|
||||
props, = self.GetEntryArgsOrProps(
|
||||
[EntryArg('of-spl-remove-props', str)], required=False)
|
||||
if props:
|
||||
self._remove_props = props.split()
|
||||
|
||||
def FdtContents(self, fdt_etype):
|
||||
# If there is no current FDT, just use the normal one
|
||||
if not self._cur_fdt:
|
||||
return self.section.FdtContents(fdt_etype)
|
||||
|
||||
# Find the file to use
|
||||
fname = os.path.join(self._fdt_dir, f'{self._cur_fdt}.dtb')
|
||||
infile = tools.get_input_filename(fname)
|
||||
|
||||
# Run fdtgrep if needed, to remove unwanted nodes and properties
|
||||
if self._fdt_phase:
|
||||
uniq = self.GetUniqueName()
|
||||
outfile = tools.get_output_filename(
|
||||
f'{uniq}.{self._cur_fdt}-{self._fdt_phase}.dtb')
|
||||
self.fdtgrep.create_for_phase(infile, self._fdt_phase, outfile,
|
||||
self._remove_props)
|
||||
return outfile, tools.read_file(outfile)
|
||||
return fname, tools.read_file(infile)
|
||||
|
||||
def ProcessWithFdt(self, alt):
|
||||
"""Produce the contents of this entry, using a particular FDT blob
|
||||
|
||||
Args:
|
||||
alt (str): Name of the alternate
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
str: Filename to use for the alternate's .bin file
|
||||
bytes: Contents of this entry's section, using the selected FDT
|
||||
"""
|
||||
pattern = self._fname_pattern or 'NAME.bin'
|
||||
fname = pattern.replace('NAME', alt)
|
||||
|
||||
data = b''
|
||||
try:
|
||||
self._cur_fdt = alt
|
||||
self.ProcessContents()
|
||||
data = self.GetPaddedData()
|
||||
finally:
|
||||
self._cur_fdt = None
|
||||
return fname, data
|
||||
|
||||
def AddBintools(self, btools):
|
||||
super().AddBintools(btools)
|
||||
self.fdtgrep = self.AddBintool(btools, 'fdtgrep')
|
||||
@@ -41,12 +41,12 @@ class Entry_blob_dtb(Entry_blob):
|
||||
def ObtainContents(self, fake_size=0):
|
||||
"""Get the device-tree from the list held by the 'state' module"""
|
||||
self._filename = self.GetDefaultFilename()
|
||||
self._pathname, _ = state.GetFdtContents(self.GetFdtEtype())
|
||||
self._pathname, _ = self.FdtContents(self.GetFdtEtype())
|
||||
return super().ReadBlobContents()
|
||||
|
||||
def ProcessContents(self):
|
||||
"""Re-read the DTB contents so that we get any calculated properties"""
|
||||
_, indata = state.GetFdtContents(self.GetFdtEtype())
|
||||
_, indata = self.FdtContents(self.GetFdtEtype())
|
||||
|
||||
if self.compress == 'zstd' and self.prepend != 'length':
|
||||
self.Raise('The zstd compression requires a length header')
|
||||
@@ -57,7 +57,9 @@ class Entry_blob_dtb(Entry_blob):
|
||||
def GetFdtEtype(self):
|
||||
"""Get the entry type of this device tree
|
||||
|
||||
This can be 'u-boot-dtb', 'u-boot-spl-dtb' or 'u-boot-tpl-dtb'
|
||||
This can be 'u-boot-dtb', 'u-boot-spl-dtb', 'u-boot-tpl-dtb' or
|
||||
'u-boot-vpl-dtb'
|
||||
|
||||
Returns:
|
||||
Entry type if any, e.g. 'u-boot-dtb'
|
||||
"""
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
"""Entry-type module for producing a FIT"""
|
||||
|
||||
import glob
|
||||
import libfdt
|
||||
import os
|
||||
|
||||
from binman.entry import Entry, EntryArg
|
||||
from binman.etype.section import Entry_section
|
||||
@@ -87,6 +89,13 @@ class Entry_fit(Entry_section):
|
||||
|
||||
fit,fdt-list-val = "dtb1", "dtb2";
|
||||
|
||||
fit,fdt-list-dir
|
||||
As an alternative to fit,fdt-list the list of device tree files
|
||||
can be provided as a directory. Each .dtb file in the directory is
|
||||
processed, , e.g.::
|
||||
|
||||
fit,fdt-list-dir = "arch/arm/dts
|
||||
|
||||
Substitutions
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
@@ -162,6 +171,7 @@ class Entry_fit(Entry_section):
|
||||
firmware = "atf";
|
||||
loadables = "uboot";
|
||||
fdt = "fdt-SEQ";
|
||||
fit,compatible; // optional
|
||||
};
|
||||
};
|
||||
|
||||
@@ -171,6 +181,40 @@ class Entry_fit(Entry_section):
|
||||
Note that if no devicetree files are provided (with '-a of-list' as above)
|
||||
then no nodes will be generated.
|
||||
|
||||
The 'fit,compatible' property (if present) is replaced with the compatible
|
||||
string from the root node of the devicetree, so that things work correctly
|
||||
with FIT's configuration-matching algortihm.
|
||||
|
||||
Dealing with phases
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
FIT can be used to load firmware. In this case it may be necessary to run
|
||||
the devicetree for each model through fdtgrep to remove unwanted properties.
|
||||
The 'fit,fdt-phase' property can be provided to indicate the phase for which
|
||||
the devicetree is intended.
|
||||
|
||||
For example this indicates that the FDT should be processed for VPL::
|
||||
|
||||
images {
|
||||
@fdt-SEQ {
|
||||
description = "fdt-NAME";
|
||||
type = "flat_dt";
|
||||
compression = "none";
|
||||
fit,fdt-phase = "vpl";
|
||||
};
|
||||
};
|
||||
|
||||
Using this mechanism, it is possible to generate a FIT which can provide VPL
|
||||
images for multiple models, with TPL selecting the correct model to use. The
|
||||
same approach can of course be used for SPL images.
|
||||
|
||||
Note that the `of-spl-remove-props` entryarg can be used to indicate
|
||||
additional properties to remove. It is often used to remove properties like
|
||||
`clock-names` and `pinctrl-names` which are not needed in SPL builds. This
|
||||
value is automatically passed to binman by the U-Boot build.
|
||||
|
||||
See :ref:`fdtgrep_filter` for more information.
|
||||
|
||||
Generating nodes from an ELF file (split-elf)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -352,9 +396,16 @@ class Entry_fit(Entry_section):
|
||||
self._fit = None
|
||||
self._fit_props = {}
|
||||
self._fdts = None
|
||||
self._fdt_dir = None
|
||||
self.mkimage = None
|
||||
self.fdtgrep = None
|
||||
self._priv_entries = {}
|
||||
self._loadables = []
|
||||
self._remove_props = []
|
||||
props, = self.GetEntryArgsOrProps(
|
||||
[EntryArg('of-spl-remove-props', str)], required=False)
|
||||
if props:
|
||||
self._remove_props = props.split()
|
||||
|
||||
def ReadNode(self):
|
||||
super().ReadNode()
|
||||
@@ -368,7 +419,14 @@ class Entry_fit(Entry_section):
|
||||
if fdts is not None:
|
||||
self._fdts = fdts.split()
|
||||
else:
|
||||
self._fdts = fdt_util.GetStringList(self._node, 'fit,fdt-list-val')
|
||||
self._fdt_dir = fdt_util.GetString(self._node, 'fit,fdt-list-dir')
|
||||
if self._fdt_dir:
|
||||
indir = tools.get_input_filename(self._fdt_dir)
|
||||
fdts = glob.glob('*.dtb', root_dir=indir)
|
||||
self._fdts = [os.path.splitext(f)[0] for f in sorted(fdts)]
|
||||
else:
|
||||
self._fdts = fdt_util.GetStringList(self._node,
|
||||
'fit,fdt-list-val')
|
||||
|
||||
self._fit_default_dt = self.GetEntryArgsOrProps([EntryArg('default-dt',
|
||||
str)])[0]
|
||||
@@ -483,6 +541,19 @@ class Entry_fit(Entry_section):
|
||||
rel_path = node.path[len(self._node.path) + 1:]
|
||||
self.Raise(f"subnode '{rel_path}': {msg}")
|
||||
|
||||
def _run_fdtgrep(self, infile, phase, outfile):
|
||||
"""Run fdtgrep to create the dtb for a phase
|
||||
|
||||
Args:
|
||||
infile (str): Input filename containing the full FDT contents (with
|
||||
all nodes and properties)
|
||||
phase (str): Phase to generate for ('tpl', 'vpl', 'spl')
|
||||
outfile (str): Output filename to write the grepped FDT contents to
|
||||
(with only neceesary nodes and properties)
|
||||
"""
|
||||
return self.fdtgrep.create_for_phase(infile, phase, outfile,
|
||||
self._remove_props)
|
||||
|
||||
def _build_input(self):
|
||||
"""Finish the FIT by adding the 'data' properties to it
|
||||
|
||||
@@ -584,6 +655,7 @@ class Entry_fit(Entry_section):
|
||||
for seq, fdt_fname in enumerate(self._fdts):
|
||||
node_name = node.name[1:].replace('SEQ', str(seq + 1))
|
||||
fname = tools.get_input_filename(fdt_fname + '.dtb')
|
||||
fdt_phase = None
|
||||
with fsw.add_node(node_name):
|
||||
for pname, prop in node.props.items():
|
||||
if pname == 'fit,firmware':
|
||||
@@ -594,6 +666,15 @@ class Entry_fit(Entry_section):
|
||||
fsw.property('loadables', val.encode('utf-8'))
|
||||
elif pname == 'fit,operation':
|
||||
pass
|
||||
elif pname == 'fit,compatible':
|
||||
fdt_phase = fdt_util.GetString(node, pname)
|
||||
data = tools.read_file(fname)
|
||||
fdt = Fdt.FromData(data)
|
||||
fdt.Scan()
|
||||
prop = fdt.GetRoot().props['compatible']
|
||||
fsw.property('compatible', prop.bytes)
|
||||
elif pname == 'fit,fdt-phase':
|
||||
fdt_phase = fdt_util.GetString(node, pname)
|
||||
elif pname.startswith('fit,'):
|
||||
self._raise_subnode(
|
||||
node, f"Unknown directive '{pname}'")
|
||||
@@ -606,7 +687,14 @@ class Entry_fit(Entry_section):
|
||||
|
||||
# Add data for 'images' nodes (but not 'config')
|
||||
if depth == 1 and in_images:
|
||||
fsw.property('data', tools.read_file(fname))
|
||||
if fdt_phase:
|
||||
phase_fname = tools.get_output_filename(
|
||||
f'{fdt_fname}-{fdt_phase}.dtb')
|
||||
self._run_fdtgrep(fname, fdt_phase, phase_fname)
|
||||
data = tools.read_file(phase_fname)
|
||||
else:
|
||||
data = tools.read_file(fname)
|
||||
fsw.property('data', data)
|
||||
|
||||
for subnode in node.subnodes:
|
||||
with fsw.add_node(subnode.name):
|
||||
@@ -834,6 +922,7 @@ class Entry_fit(Entry_section):
|
||||
def AddBintools(self, btools):
|
||||
super().AddBintools(btools)
|
||||
self.mkimage = self.AddBintool(btools, 'mkimage')
|
||||
self.fdtgrep = self.AddBintool(btools, 'fdtgrep')
|
||||
|
||||
def CheckMissing(self, missing_list):
|
||||
# We must use our private entry list for this since generator nodes
|
||||
|
||||
@@ -23,8 +23,6 @@ class Entry_u_boot_spl_nodtb(Entry_blob):
|
||||
|
||||
SPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
The ELF file 'spl/u-boot-spl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the SPL binary.
|
||||
"""
|
||||
|
||||
@@ -23,8 +23,6 @@ class Entry_u_boot_tpl_nodtb(Entry_blob):
|
||||
|
||||
TPL can access binman symbols at runtime. See :ref:`binman_fdt`.
|
||||
|
||||
in the binman README for more information.
|
||||
|
||||
The ELF file 'tpl/u-boot-tpl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the TPL binary.
|
||||
"""
|
||||
|
||||
@@ -27,6 +27,9 @@ class Entry_u_boot_vpl(Entry_blob):
|
||||
|
||||
The ELF file 'vpl/u-boot-vpl' must also be available for this to work, since
|
||||
binman uses that to look up symbols to write into the VPL binary.
|
||||
|
||||
Note that this entry is automatically replaced with u-boot-vpl-expanded
|
||||
unless --no-expanded is used or the node has a 'no-expanded' property.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
super().__init__(section, etype, node, auto_write_symbols=True)
|
||||
|
||||
@@ -16,8 +16,8 @@ class Entry_u_boot_vpl_nodtb(Entry_blob):
|
||||
|
||||
This is the U-Boot VPL binary, It does not include a device tree blob at
|
||||
the end of it so may not be able to work without it, assuming VPL needs
|
||||
a device tree to operate on your platform. You can add a u_boot_vpl_dtb
|
||||
entry after this one, or use a u_boot_vpl entry instead, which normally
|
||||
a device tree to operate on your platform. You can add a u-boot-vpl-dtb
|
||||
entry after this one, or use a u-boot-vpl entry instead, which normally
|
||||
expands to a section containing u-boot-vpl-dtb, u-boot-vpl-bss-pad and
|
||||
u-boot-vpl-dtb
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# python -m unittest func_test.TestFunctional.testHelp
|
||||
|
||||
import collections
|
||||
import glob
|
||||
import gzip
|
||||
import hashlib
|
||||
from optparse import OptionParser
|
||||
@@ -546,7 +547,7 @@ class TestFunctional(unittest.TestCase):
|
||||
dtb_data = self._SetupDtb(fname)
|
||||
|
||||
# For testing purposes, make a copy of the DT for SPL and TPL. Add
|
||||
# a node indicating which it is, so aid verification.
|
||||
# a node indicating which it is, to aid verification.
|
||||
for name in ['spl', 'tpl', 'vpl']:
|
||||
dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
|
||||
outfile = os.path.join(self._indir, dtb_fname)
|
||||
@@ -4180,8 +4181,8 @@ class TestFunctional(unittest.TestCase):
|
||||
data = self._DoReadFile('172_scp.dts')
|
||||
self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
|
||||
|
||||
def testFitFdt(self):
|
||||
"""Test an image with an FIT with multiple FDT images"""
|
||||
def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True):
|
||||
"""Check an image with an FIT with multiple FDT images"""
|
||||
def _CheckFdt(seq, expected_data):
|
||||
"""Check the FDT nodes
|
||||
|
||||
@@ -4220,11 +4221,12 @@ class TestFunctional(unittest.TestCase):
|
||||
self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
|
||||
|
||||
entry_args = {
|
||||
'of-list': 'test-fdt1 test-fdt2',
|
||||
'default-dt': 'test-fdt2',
|
||||
}
|
||||
if use_fdt_list:
|
||||
entry_args['of-list'] = 'test-fdt1 test-fdt2'
|
||||
data = self._DoReadFileDtb(
|
||||
'170_fit_fdt.dts',
|
||||
dts,
|
||||
entry_args=entry_args,
|
||||
extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
|
||||
self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
|
||||
@@ -4243,6 +4245,10 @@ class TestFunctional(unittest.TestCase):
|
||||
_CheckConfig(1, TEST_FDT1_DATA)
|
||||
_CheckConfig(2, TEST_FDT2_DATA)
|
||||
|
||||
def testFitFdt(self):
|
||||
"""Test an image with an FIT with multiple FDT images"""
|
||||
self.CheckFitFdt()
|
||||
|
||||
def testFitFdtMissingList(self):
|
||||
"""Test handling of a missing 'of-list' entry arg"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
@@ -7175,27 +7181,24 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
|
||||
|
||||
|
||||
def testSplPubkeyDtb(self):
|
||||
"""Test u_boot_spl_pubkey_dtb etype"""
|
||||
data = tools.read_file(self.TestFile("key.pem"))
|
||||
self._MakeInputFile("key.crt", data)
|
||||
self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
dtb_entry = entries['u-boot-spl-pubkey-dtb']
|
||||
dtb_data = dtb_entry.GetData()
|
||||
dtb = fdt.Fdt.FromData(dtb_data)
|
||||
dtb.Scan()
|
||||
"""Test u_boot_spl_pubkey_dtb etype"""
|
||||
data = tools.read_file(self.TestFile("key.pem"))
|
||||
self._MakeInputFile("key.crt", data)
|
||||
self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
|
||||
image = control.images['image']
|
||||
entries = image.GetEntries()
|
||||
dtb_entry = entries['u-boot-spl-pubkey-dtb']
|
||||
dtb_data = dtb_entry.GetData()
|
||||
dtb = fdt.Fdt.FromData(dtb_data)
|
||||
dtb.Scan()
|
||||
|
||||
signature_node = dtb.GetNode('/signature')
|
||||
self.assertIsNotNone(signature_node)
|
||||
key_node = signature_node.FindNode("key-key")
|
||||
self.assertIsNotNone(key_node)
|
||||
self.assertEqual(fdt_util.GetString(key_node, "required"),
|
||||
"conf")
|
||||
self.assertEqual(fdt_util.GetString(key_node, "algo"),
|
||||
"sha384,rsa4096")
|
||||
self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
|
||||
"key")
|
||||
signature_node = dtb.GetNode('/signature')
|
||||
self.assertIsNotNone(signature_node)
|
||||
key_node = signature_node.FindNode("key-key")
|
||||
self.assertIsNotNone(key_node)
|
||||
self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
|
||||
self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
|
||||
self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
|
||||
|
||||
def testXilinxBootgenSigning(self):
|
||||
"""Test xilinx-bootgen etype"""
|
||||
@@ -7487,6 +7490,206 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
|
||||
err,
|
||||
"Image '.*' is missing external blobs and is non-functional: .*")
|
||||
|
||||
def SetupAlternateDts(self):
|
||||
"""Compile the .dts test files for alternative-fdt
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
str: Test directory created
|
||||
list of str: '.bin' files which we expect Binman to create
|
||||
"""
|
||||
testdir = TestFunctional._MakeInputDir('dtb')
|
||||
dtb_list = []
|
||||
for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
|
||||
tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
|
||||
base = os.path.splitext(os.path.basename(fname))[0]
|
||||
dtb_list.append(base + '.bin')
|
||||
shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
|
||||
|
||||
return testdir, dtb_list
|
||||
|
||||
def CheckAlternates(self, dts, phase, xpl_data):
|
||||
"""Run the test for the alterative-fdt etype
|
||||
|
||||
Args:
|
||||
dts (str): Devicetree file to process
|
||||
phase (str): Phase to process ('spl', 'tpl' or 'vpl')
|
||||
xpl_data (bytes): Expected data for the phase's binary
|
||||
|
||||
Returns:
|
||||
dict of .dtb files produced
|
||||
key: str filename
|
||||
value: Fdt object
|
||||
"""
|
||||
dtb_list = self.SetupAlternateDts()[1]
|
||||
|
||||
entry_args = {
|
||||
f'{phase}-dtb': '1',
|
||||
f'{phase}-bss-pad': 'y',
|
||||
'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
|
||||
}
|
||||
data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
|
||||
use_expanded=True, entry_args=entry_args)[0]
|
||||
self.assertEqual(xpl_data, data[:len(xpl_data)])
|
||||
rest = data[len(xpl_data):]
|
||||
pad_len = 10
|
||||
self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
|
||||
|
||||
# Check the dtb is using the test file
|
||||
dtb_data = rest[pad_len:]
|
||||
dtb = fdt.Fdt.FromData(dtb_data)
|
||||
dtb.Scan()
|
||||
fdt_size = dtb.GetFdtObj().totalsize()
|
||||
self.assertEqual('model-not-set',
|
||||
fdt_util.GetString(dtb.GetRoot(), 'compatible'))
|
||||
|
||||
pad_len = 10
|
||||
|
||||
# Check the other output files
|
||||
dtbs = {}
|
||||
for fname in dtb_list:
|
||||
pathname = tools.get_output_filename(fname)
|
||||
self.assertTrue(os.path.exists(pathname))
|
||||
|
||||
data = tools.read_file(pathname)
|
||||
self.assertEqual(xpl_data, data[:len(xpl_data)])
|
||||
rest = data[len(xpl_data):]
|
||||
|
||||
self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
|
||||
rest = rest[pad_len:]
|
||||
|
||||
dtb = fdt.Fdt.FromData(rest)
|
||||
dtb.Scan()
|
||||
dtbs[fname] = dtb
|
||||
|
||||
expected = 'one' if '1' in fname else 'two'
|
||||
self.assertEqual(f'u-boot,model-{expected}',
|
||||
fdt_util.GetString(dtb.GetRoot(), 'compatible'))
|
||||
|
||||
# Make sure the FDT is the same size as the 'main' one
|
||||
rest = rest[fdt_size:]
|
||||
|
||||
self.assertEqual(b'', rest)
|
||||
return dtbs
|
||||
|
||||
def testAlternatesFdt(self):
|
||||
"""Test handling of alternates-fdt etype"""
|
||||
self._SetupTplElf()
|
||||
dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
|
||||
U_BOOT_TPL_NODTB_DATA)
|
||||
for dtb in dtbs.values():
|
||||
# Check for the node with the tag
|
||||
node = dtb.GetNode('/node')
|
||||
self.assertIsNotNone(node)
|
||||
self.assertEqual(5, len(node.props.keys()))
|
||||
|
||||
# Make sure the other node is still there
|
||||
self.assertIsNotNone(dtb.GetNode('/node/other-node'))
|
||||
|
||||
def testAlternatesFdtgrep(self):
|
||||
"""Test handling of alternates-fdt etype using fdtgrep"""
|
||||
self._SetupTplElf()
|
||||
dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
|
||||
U_BOOT_TPL_NODTB_DATA)
|
||||
for dtb in dtbs.values():
|
||||
# Check for the node with the tag
|
||||
node = dtb.GetNode('/node')
|
||||
self.assertIsNotNone(node)
|
||||
self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
|
||||
node.props.keys())
|
||||
|
||||
# Make sure the other node is gone
|
||||
self.assertIsNone(dtb.GetNode('/node/other-node'))
|
||||
|
||||
def testAlternatesFdtgrepVpl(self):
|
||||
"""Test handling of alternates-fdt etype using fdtgrep with vpl"""
|
||||
self._SetupVplElf()
|
||||
dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
|
||||
U_BOOT_VPL_NODTB_DATA)
|
||||
|
||||
def testAlternatesFdtgrepSpl(self):
|
||||
"""Test handling of alternates-fdt etype using fdtgrep with spl"""
|
||||
self._SetupSplElf()
|
||||
dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
|
||||
U_BOOT_SPL_NODTB_DATA)
|
||||
|
||||
def testAlternatesFdtgrepInval(self):
|
||||
"""Test alternates-fdt etype using fdtgrep with invalid phase"""
|
||||
self._SetupSplElf()
|
||||
with self.assertRaises(ValueError) as e:
|
||||
dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
|
||||
U_BOOT_SPL_NODTB_DATA)
|
||||
self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
|
||||
str(e.exception))
|
||||
|
||||
def testFitFdtListDir(self):
|
||||
"""Test an image with an FIT with FDT images using fit,fdt-list-dir"""
|
||||
self.CheckFitFdt('333_fit_fdt_dir.dts', False)
|
||||
|
||||
def testFitFdtCompat(self):
|
||||
"""Test an image with an FIT with compatible in the config nodes"""
|
||||
entry_args = {
|
||||
'of-list': 'model1 model2',
|
||||
'default-dt': 'model2',
|
||||
}
|
||||
testdir, dtb_list = self.SetupAlternateDts()
|
||||
data = self._DoReadFileDtb(
|
||||
'334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
|
||||
entry_args=entry_args, extra_indirs=[testdir])[0]
|
||||
|
||||
fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
|
||||
|
||||
fit = fdt.Fdt.FromData(fit_data)
|
||||
fit.Scan()
|
||||
|
||||
cnode = fit.GetNode('/configurations')
|
||||
self.assertIn('default', cnode.props)
|
||||
self.assertEqual('config-2', cnode.props['default'].value)
|
||||
|
||||
for seq in range(1, 2):
|
||||
name = f'config-{seq}'
|
||||
fnode = fit.GetNode('/configurations/%s' % name)
|
||||
self.assertIsNotNone(fnode)
|
||||
self.assertIn('compatible', fnode.props.keys())
|
||||
expected = 'one' if seq == 1 else 'two'
|
||||
self.assertEqual(f'u-boot,model-{expected}',
|
||||
fnode.props['compatible'].value)
|
||||
|
||||
def testFitFdtPhase(self):
|
||||
"""Test an image with an FIT with fdt-phase in the fdt nodes"""
|
||||
phase = 'tpl'
|
||||
entry_args = {
|
||||
f'{phase}-dtb': '1',
|
||||
f'{phase}-bss-pad': 'y',
|
||||
'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
|
||||
'of-list': 'model1 model2',
|
||||
'default-dt': 'model2',
|
||||
}
|
||||
testdir, dtb_list = self.SetupAlternateDts()
|
||||
data = self._DoReadFileDtb(
|
||||
'335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
|
||||
entry_args=entry_args, extra_indirs=[testdir])[0]
|
||||
fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
|
||||
fit = fdt.Fdt.FromData(fit_data)
|
||||
fit.Scan()
|
||||
|
||||
# Check that each FDT has only the expected properties for the phase
|
||||
for seq in range(1, 2):
|
||||
fnode = fit.GetNode(f'/images/fdt-{seq}')
|
||||
self.assertIsNotNone(fnode)
|
||||
dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
|
||||
dtb.Scan()
|
||||
|
||||
# Make sure that the 'bootph-pre-sram' tag in /node protects it from
|
||||
# removal
|
||||
node = dtb.GetNode('/node')
|
||||
self.assertIsNotNone(node)
|
||||
self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
|
||||
node.props.keys())
|
||||
|
||||
# Make sure the other node is gone
|
||||
self.assertIsNone(dtb.GetNode('/node/other-node'))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -21,6 +21,9 @@ from dtoc import fdt_util
|
||||
from u_boot_pylib import tools
|
||||
from u_boot_pylib import tout
|
||||
|
||||
# This is imported if needed
|
||||
state = None
|
||||
|
||||
class Image(section.Entry_section):
|
||||
"""A Image, representing an output from binman
|
||||
|
||||
@@ -75,6 +78,10 @@ class Image(section.Entry_section):
|
||||
def __init__(self, name, node, copy_to_orig=True, test=False,
|
||||
ignore_missing=False, use_expanded=False, missing_etype=False,
|
||||
generate=True):
|
||||
# Put this here to allow entry-docs and help to work without libfdt
|
||||
global state
|
||||
from binman import state
|
||||
|
||||
super().__init__(None, 'section', node, test=test)
|
||||
self.copy_to_orig = copy_to_orig
|
||||
self.name = name
|
||||
@@ -186,6 +193,19 @@ class Image(section.Entry_section):
|
||||
os.remove(sname)
|
||||
os.symlink(fname, sname)
|
||||
|
||||
def WriteAlternates(self):
|
||||
"""Write out alternative devicetree blobs, each in its own file"""
|
||||
alt_entry = self.FindEntryType('alternates-fdt')
|
||||
if not alt_entry:
|
||||
return
|
||||
|
||||
for alt in alt_entry.alternates:
|
||||
fname, data = alt_entry.ProcessWithFdt(alt)
|
||||
pathname = tools.get_output_filename(fname)
|
||||
tout.info(f"Writing alternate '{alt}' to '{pathname}'")
|
||||
tools.write_file(pathname, data)
|
||||
tout.info("Wrote %#x bytes" % len(data))
|
||||
|
||||
def WriteMap(self):
|
||||
"""Write a map of the image to a .map file
|
||||
|
||||
@@ -418,3 +438,7 @@ class Image(section.Entry_section):
|
||||
super().AddBintools(bintools)
|
||||
self.bintools = bintools
|
||||
return bintools
|
||||
|
||||
def FdtContents(self, fdt_etype):
|
||||
"""This base-class implementation simply calls the state function"""
|
||||
return state.GetFdtContents(fdt_etype)
|
||||
|
||||
@@ -122,6 +122,8 @@ def RunBinman(args):
|
||||
ret_code = RunTests(args.debug, args.verbosity, args.processes,
|
||||
args.test_preserve_dirs, args.tests,
|
||||
args.toolpath)
|
||||
if args.debug and not test_util.use_concurrent:
|
||||
print('Tests can run in parallel: pip install concurrencytest')
|
||||
|
||||
elif args.cmd == 'bintool-docs':
|
||||
control.write_bintool_docs(bintool.Bintool.get_tool_list())
|
||||
|
||||
28
tools/binman/test/328_alternates_fdt.dts
Normal file
28
tools/binman/test/328_alternates_fdt.dts
Normal file
@@ -0,0 +1,28 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright 2024 Google LLC
|
||||
// Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
compatible = "model-not-set";
|
||||
|
||||
binman {
|
||||
alternates-fdt {
|
||||
fdt-list-dir = "dtb";
|
||||
filename-pattern = "NAME.bin";
|
||||
|
||||
section {
|
||||
u-boot-tpl {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
blob {
|
||||
filename = "blobfile";
|
||||
};
|
||||
};
|
||||
};
|
||||
29
tools/binman/test/329_alternates_fdtgrep.dts
Normal file
29
tools/binman/test/329_alternates_fdtgrep.dts
Normal file
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright 2024 Google LLC
|
||||
// Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
compatible = "model-not-set";
|
||||
|
||||
binman {
|
||||
alternates-fdt {
|
||||
fdt-list-dir = "dtb";
|
||||
filename-pattern = "NAME.bin";
|
||||
fdt-phase = "tpl";
|
||||
|
||||
section {
|
||||
u-boot-tpl {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
blob {
|
||||
filename = "blobfile";
|
||||
};
|
||||
};
|
||||
};
|
||||
29
tools/binman/test/330_alternates_vpl.dts
Normal file
29
tools/binman/test/330_alternates_vpl.dts
Normal file
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright 2024 Google LLC
|
||||
// Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
compatible = "model-not-set";
|
||||
|
||||
binman {
|
||||
alternates-fdt {
|
||||
fdt-list-dir = "dtb";
|
||||
filename-pattern = "NAME.bin";
|
||||
fdt-phase = "vpl";
|
||||
|
||||
section {
|
||||
u-boot-vpl {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
blob {
|
||||
filename = "blobfile";
|
||||
};
|
||||
};
|
||||
};
|
||||
29
tools/binman/test/331_alternates_spl.dts
Normal file
29
tools/binman/test/331_alternates_spl.dts
Normal file
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright 2024 Google LLC
|
||||
// Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
compatible = "model-not-set";
|
||||
|
||||
binman {
|
||||
alternates-fdt {
|
||||
fdt-list-dir = "dtb";
|
||||
filename-pattern = "NAME.bin";
|
||||
fdt-phase = "spl";
|
||||
|
||||
section {
|
||||
u-boot-spl {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
blob {
|
||||
filename = "blobfile";
|
||||
};
|
||||
};
|
||||
};
|
||||
29
tools/binman/test/332_alternates_inval.dts
Normal file
29
tools/binman/test/332_alternates_inval.dts
Normal file
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright 2024 Google LLC
|
||||
// Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
compatible = "model-not-set";
|
||||
|
||||
binman {
|
||||
alternates-fdt {
|
||||
fdt-list-dir = "dtb";
|
||||
filename-pattern = "NAME.bin";
|
||||
fdt-phase = "bad-phase";
|
||||
|
||||
section {
|
||||
u-boot-spl {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
blob {
|
||||
filename = "blobfile";
|
||||
};
|
||||
};
|
||||
};
|
||||
58
tools/binman/test/333_fit_fdt_dir.dts
Normal file
58
tools/binman/test/333_fit_fdt_dir.dts
Normal file
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
};
|
||||
fit {
|
||||
description = "test-desc";
|
||||
#address-cells = <1>;
|
||||
fit,fdt-list-dir = "fdts";
|
||||
|
||||
images {
|
||||
kernel {
|
||||
description = "Vanilla Linux kernel";
|
||||
type = "kernel";
|
||||
arch = "ppc";
|
||||
os = "linux";
|
||||
compression = "gzip";
|
||||
load = <00000000>;
|
||||
entry = <00000000>;
|
||||
hash-1 {
|
||||
algo = "crc32";
|
||||
};
|
||||
hash-2 {
|
||||
algo = "sha1";
|
||||
};
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
@fdt-SEQ {
|
||||
description = "fdt-NAME.dtb";
|
||||
type = "flat_dt";
|
||||
compression = "none";
|
||||
hash {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configurations {
|
||||
default = "@config-DEFAULT-SEQ";
|
||||
@config-SEQ {
|
||||
description = "conf-NAME.dtb";
|
||||
firmware = "uboot";
|
||||
loadables = "atf";
|
||||
fdt = "fdt-SEQ";
|
||||
};
|
||||
};
|
||||
};
|
||||
u-boot-nodtb {
|
||||
};
|
||||
};
|
||||
};
|
||||
60
tools/binman/test/334_fit_fdt_compat.dts
Normal file
60
tools/binman/test/334_fit_fdt_compat.dts
Normal file
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
};
|
||||
fit {
|
||||
description = "test-desc";
|
||||
#address-cells = <1>;
|
||||
fit,fdt-list = "of-list";
|
||||
|
||||
images {
|
||||
kernel {
|
||||
description = "Vanilla Linux kernel";
|
||||
type = "kernel";
|
||||
arch = "ppc";
|
||||
os = "linux";
|
||||
compression = "gzip";
|
||||
load = <00000000>;
|
||||
entry = <00000000>;
|
||||
hash-1 {
|
||||
algo = "crc32";
|
||||
};
|
||||
hash-2 {
|
||||
algo = "sha1";
|
||||
};
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
@fdt-SEQ {
|
||||
description = "fdt-NAME.dtb";
|
||||
type = "flat_dt";
|
||||
compression = "none";
|
||||
hash {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configurations {
|
||||
default = "@config-DEFAULT-SEQ";
|
||||
@config-SEQ {
|
||||
description = "conf-NAME.dtb";
|
||||
firmware = "uboot";
|
||||
loadables = "atf";
|
||||
fdt = "fdt-SEQ";
|
||||
fit,firmware = "vpl";
|
||||
fit,compatible;
|
||||
};
|
||||
};
|
||||
};
|
||||
u-boot-nodtb {
|
||||
};
|
||||
};
|
||||
};
|
||||
61
tools/binman/test/335_fit_fdt_phase.dts
Normal file
61
tools/binman/test/335_fit_fdt_phase.dts
Normal file
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u-boot {
|
||||
};
|
||||
fit {
|
||||
description = "test-desc";
|
||||
#address-cells = <1>;
|
||||
fit,fdt-list = "of-list";
|
||||
|
||||
images {
|
||||
kernel {
|
||||
description = "Vanilla Linux kernel";
|
||||
type = "kernel";
|
||||
arch = "ppc";
|
||||
os = "linux";
|
||||
compression = "gzip";
|
||||
load = <00000000>;
|
||||
entry = <00000000>;
|
||||
hash-1 {
|
||||
algo = "crc32";
|
||||
};
|
||||
hash-2 {
|
||||
algo = "sha1";
|
||||
};
|
||||
u-boot {
|
||||
};
|
||||
};
|
||||
@fdt-SEQ {
|
||||
description = "fdt-NAME.dtb";
|
||||
type = "flat_dt";
|
||||
compression = "none";
|
||||
fit,fdt-phase = "tpl";
|
||||
hash {
|
||||
algo = "sha256";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configurations {
|
||||
default = "@config-DEFAULT-SEQ";
|
||||
@config-SEQ {
|
||||
description = "conf-NAME.dtb";
|
||||
firmware = "uboot";
|
||||
loadables = "atf";
|
||||
fdt = "fdt-SEQ";
|
||||
fit,firmware = "tpl";
|
||||
fit,compatible;
|
||||
};
|
||||
};
|
||||
};
|
||||
u-boot-nodtb {
|
||||
};
|
||||
};
|
||||
};
|
||||
24
tools/binman/test/alt_dts/model1.dts
Normal file
24
tools/binman/test/alt_dts/model1.dts
Normal file
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright 2024 Google LLC
|
||||
// Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
model = "Model One";
|
||||
compatible = "u-boot,model-one";
|
||||
|
||||
/* this node remains due to bootph-pre-sram tag */
|
||||
node {
|
||||
some-prop;
|
||||
prop-to-remove;
|
||||
another-prop-to-get-rid-of;
|
||||
not-a-prop-to-remove;
|
||||
bootph-pre-sram;
|
||||
|
||||
/* this node get removed by fdtgrep */
|
||||
other-node {
|
||||
another-prop;
|
||||
};
|
||||
};
|
||||
};
|
||||
24
tools/binman/test/alt_dts/model2.dts
Normal file
24
tools/binman/test/alt_dts/model2.dts
Normal file
@@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright 2024 Google LLC
|
||||
// Written by Simon Glass <sjg@chromium.org>
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
model = "Model Two";
|
||||
compatible = "u-boot,model-two";
|
||||
|
||||
/* this node remains due to bootph-pre-sram tag */
|
||||
node {
|
||||
some-prop;
|
||||
prop-to-remove;
|
||||
another-prop-to-get-rid-of;
|
||||
not-a-prop-to-remove;
|
||||
bootph-pre-sram;
|
||||
|
||||
/* this node get removed by fdtgrep */
|
||||
other-node {
|
||||
another-prop;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1079,7 +1079,7 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added,
|
||||
for linenum in sorted(linenums, reverse=True):
|
||||
add_imply_rule(config[CONFIG_LEN:], fname, linenum)
|
||||
|
||||
def defconfig_matches(configs, re_match):
|
||||
def defconfig_matches(configs, re_match, re_val):
|
||||
"""Check if any CONFIG option matches a regex
|
||||
|
||||
The match must be complete, i.e. from the start to end of the CONFIG option.
|
||||
@@ -1089,16 +1089,18 @@ def defconfig_matches(configs, re_match):
|
||||
key: CONFIG option
|
||||
value: Value of option
|
||||
re_match (re.Pattern): Match to check
|
||||
re_val (re.Pattern): Regular expression to check against value (or None)
|
||||
|
||||
Returns:
|
||||
bool: True if any CONFIG matches the regex
|
||||
"""
|
||||
for cfg in configs:
|
||||
for cfg, val in configs.items():
|
||||
if re_match.fullmatch(cfg):
|
||||
return True
|
||||
if not re_val or re_val.fullmatch(val):
|
||||
return True
|
||||
return False
|
||||
|
||||
def do_find_config(config_list):
|
||||
def do_find_config(config_list, list_format):
|
||||
"""Find boards with a given combination of CONFIGs
|
||||
|
||||
Args:
|
||||
@@ -1106,6 +1108,8 @@ def do_find_config(config_list):
|
||||
consisting of a config option, with or without a CONFIG_ prefix. If
|
||||
an option is preceded by a tilde (~) then it must be false,
|
||||
otherwise it must be true)
|
||||
list_format (bool): True to write in 'list' format, one board name per
|
||||
line
|
||||
|
||||
Returns:
|
||||
int: exit code (0 for success)
|
||||
@@ -1123,6 +1127,11 @@ def do_find_config(config_list):
|
||||
if cfg[0] == '~':
|
||||
want = False
|
||||
cfg = cfg[1:]
|
||||
val = None
|
||||
re_val = None
|
||||
if '=' in cfg:
|
||||
cfg, val = cfg.split('=', maxsplit=1)
|
||||
re_val = re.compile(val)
|
||||
|
||||
# Search everything that is still in the running. If it has a config
|
||||
# that we want, or doesn't have one that we don't, add it into the
|
||||
@@ -1131,11 +1140,13 @@ def do_find_config(config_list):
|
||||
out = set()
|
||||
re_match = re.compile(cfg)
|
||||
for defc in in_list:
|
||||
has_cfg = defconfig_matches(config_db[defc], re_match)
|
||||
has_cfg = defconfig_matches(config_db[defc], re_match, re_val)
|
||||
if has_cfg == want:
|
||||
out.add(defc)
|
||||
print(f'{len(out)} matches')
|
||||
print(' '.join(item.split('_defconfig')[0] for item in out))
|
||||
if not list_format:
|
||||
print(f'{len(out)} matches')
|
||||
sep = '\n' if list_format else ' '
|
||||
print(sep.join(item.split('_defconfig')[0] for item in sorted(list(out))))
|
||||
return 0
|
||||
|
||||
|
||||
@@ -1528,6 +1539,8 @@ doc/develop/moveconfig.rst for documentation.'''
|
||||
help='Find boards with a given config combination')
|
||||
parser.add_argument('-i', '--imply', action='store_true', default=False,
|
||||
help='find options which imply others')
|
||||
parser.add_argument('-l', '--list', action='store_true', default=False,
|
||||
help='Show a sorted list of board names, one per line')
|
||||
parser.add_argument('-I', '--imply-flags', type=str, default='',
|
||||
help="control the -i option ('help' for help")
|
||||
parser.add_argument('-j', '--jobs', type=int, default=cpu_count,
|
||||
@@ -1681,7 +1694,7 @@ def main():
|
||||
sys.exit(1)
|
||||
return 0
|
||||
if args.find:
|
||||
return do_find_config(args.configs)
|
||||
return do_find_config(args.configs, args.list)
|
||||
|
||||
config_db, progress = move_config(args)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user