aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2024-10-07 09:06:49 -0600
committerTom Rini <trini@konsulko.com>2024-10-07 09:06:49 -0600
commitc530f6079c70219e01022142b404bf8a6b572366 (patch)
tree7696586afaf4c0ae8a94ef811abd7d4a2276eb64 /tools
parentf919c3a889f0ec7d63a48b5d0ed064386b0980bd (diff)
parent28dc47038edc4e93f32d75a357131bcf01a18d85 (diff)
downloadu-boot-c530f6079c70219e01022142b404bf8a6b572366.tar.gz
Merge branch 'next'
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile8
-rw-r--r--tools/binman/binman.rst19
-rw-r--r--tools/binman/btool/fdtgrep.py3
-rw-r--r--tools/binman/elf.py14
-rw-r--r--tools/binman/elf_test.py4
-rw-r--r--tools/binman/entry.py25
-rw-r--r--tools/binman/etype/atf_fip.py2
-rw-r--r--tools/binman/etype/blob_phase.py5
-rw-r--r--tools/binman/etype/cbfs.py2
-rw-r--r--tools/binman/etype/efi_capsule.py4
-rw-r--r--tools/binman/etype/fit.py116
-rw-r--r--tools/binman/etype/nxp_imx8mimage.py3
-rw-r--r--tools/binman/etype/section.py31
-rw-r--r--tools/binman/ftest.py154
-rw-r--r--tools/binman/image.py21
-rw-r--r--tools/binman/image_test.py8
-rw-r--r--tools/binman/test/336_symbols_base.dts23
-rw-r--r--tools/binman/test/337_symbols_base_expand.dts24
-rw-r--r--tools/binman/test/338_symbols_comp.dts26
-rw-r--r--tools/binman/test/339_nxp_imx8.dts17
-rw-r--r--tools/buildman/bsettings.py3
-rw-r--r--tools/buildman/builder.py27
-rw-r--r--tools/buildman/builderthread.py12
-rw-r--r--tools/buildman/buildman.rst3
-rw-r--r--tools/buildman/cmdline.py2
-rw-r--r--tools/buildman/control.py3
-rw-r--r--tools/buildman/kconfiglib.py10
-rw-r--r--tools/buildman/test.py162
-rw-r--r--tools/buildman/toolchain.py37
-rw-r--r--tools/eficapsule.h2
-rw-r--r--tools/image-sig-host.c7
-rw-r--r--tools/mkeficapsule.c208
32 files changed, 800 insertions, 185 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 6a4280e3668..ee08a9675df 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -246,12 +246,12 @@ HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
HOSTCFLAGS_mkeficapsule.o += \
$(shell pkg-config --cflags gnutls 2> /dev/null || echo "")
-HOSTCFLAGS_mkeficapsule.o += \
- $(shell pkg-config --cflags uuid 2> /dev/null || echo "")
HOSTLDLIBS_mkeficapsule += \
$(shell pkg-config --libs gnutls 2> /dev/null || echo "-lgnutls")
-HOSTLDLIBS_mkeficapsule += \
- $(shell pkg-config --libs uuid 2> /dev/null || echo "-luuid")
+mkeficapsule-objs := generated/lib/uuid.o \
+ generated/lib/sha1.o \
+ $(LIBFDT_OBJS) \
+ mkeficapsule.o
hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
mkfwumdata-objs := mkfwumdata.o generated/lib/crc32.o
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 0cafc36bdcb..f9a3a42183b 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -494,12 +494,18 @@ point into the image.
For example, say SPL is at the start of the image and linked to start at address
80108000. If U-Boot's image-pos is 0x8000 then binman will write an image-pos
for U-Boot of 80110000 into the SPL binary, since it assumes the image is loaded
-to 80108000, with SPL at 80108000 and U-Boot at 80110000.
+to 80108000, with SPL at 80108000 and U-Boot at 80110000. In other words, the
+positions are calculated relative to the start address of the image to which
+they are being written.
For x86 devices (with the end-at-4gb property) this base address is not added
since it is assumed that images are XIP and the offsets already include the
address.
+For non-x86 cases where the symbol is used as a flash offset, the symbols-base
+property can be set to that offset (e.g. 0), so that the unadjusted image-pos
+is written into the image.
+
While U-Boot's symbol updating is handled automatically by the u-boot-spl
entry type (and others), it is possible to use this feature with any blob. To
do this, add a `write-symbols` (boolean) property to the node, set the ELF
@@ -741,6 +747,17 @@ insert-template:
properties are brought into the target node. See Templates_ below for
more information.
+symbols-base:
+ When writing symbols into a binary, the value of that symbol is assumed to
+ be relative to the base address of the binary. This allow the binary to be
+ loaded in memory at its base address, so that symbols point into the binary
+ correctly. In some cases the binary is in fact not yet in memory, but must
+ be read from storage. In this case there is no base address for the symbols.
+ This property can be set to 0 to indicate this. Other values for
+ symbols-base are allowed, but care must be taken that the code which uses
+ the symbol is aware of the base being used. If omitted, the binary's base
+ address is used.
+
The attributes supported for images and sections are described below. Several
are similar to those for entries.
diff --git a/tools/binman/btool/fdtgrep.py b/tools/binman/btool/fdtgrep.py
index da1f8c7bf4e..446b2f4144b 100644
--- a/tools/binman/btool/fdtgrep.py
+++ b/tools/binman/btool/fdtgrep.py
@@ -74,8 +74,7 @@ class Bintoolfdtgrep(bintool.Bintool):
(with only neceesary nodes and properties)
Returns:
- CommandResult: Resulting output from the bintool, or None if the
- tool is not present
+ str or bytes: Resulting stdout from the bintool
"""
if phase == 'tpl':
tag = 'bootph-pre-sram'
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index a4694056391..c75f4478813 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -234,7 +234,7 @@ def GetSymbolOffset(elf_fname, sym_name, base_sym=None):
return val - base
def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
- base_sym=None):
+ base_sym=None, base_addr=None):
"""Replace all symbols in an entry with their correct values
The entry contents is updated so that values for referenced symbols will be
@@ -247,7 +247,10 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
entry
entry: Entry to process
section: Section which can be used to lookup symbol values
- base_sym: Base symbol marking the start of the image
+ base_sym: Base symbol marking the start of the image (__image_copy_start
+ by default)
+ base_addr (int): Base address to use for the entry being written. If
+ None then the value of base_sym is used
Returns:
int: Number of symbols written
@@ -277,7 +280,8 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
if not base and not is_elf:
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
+ if base_addr is None:
+ base_addr = 0 if is_elf else base.address
count = 0
for name, sym in syms.items():
if name.startswith('_binman'):
@@ -301,8 +305,8 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
value = BINMAN_SYM_MAGIC_VALUE
else:
# Look up the symbol in our entry tables.
- value = section.GetImage().LookupImageSymbol(name, sym.weak,
- msg, base_addr)
+ value = section.GetImage().GetImageSymbolValue(name, sym.weak,
+ msg, base_addr)
if value is None:
value = -1
pack_string = pack_string.lower()
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py
index b64134123c1..2f22639dffc 100644
--- a/tools/binman/elf_test.py
+++ b/tools/binman/elf_test.py
@@ -37,7 +37,7 @@ class FakeSection:
"""A fake Section object, used for testing
This has the minimum feature set needed to support testing elf functions.
- A LookupSymbol() function is provided which returns a fake value for amu
+ A GetSymbolValue() function is provided which returns a fake value for any
symbol requested.
"""
def __init__(self, sym_value=1):
@@ -46,7 +46,7 @@ class FakeSection:
def GetPath(self):
return 'section_path'
- def LookupImageSymbol(self, name, weak, msg, base_addr):
+ def GetImageSymbolValue(self, name, weak, msg, base_addr):
"""Fake implementation which returns the same value for all symbols"""
return self.sym_value
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 6d2f3789940..68f8d62bba9 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -108,6 +108,9 @@ class Entry(object):
not need to be done again. This is only used with 'binman replace',
to stop sections from being rebuilt if their entries have not been
replaced
+ symbols_base (int): Use this value as the assumed load address of the
+ target entry, when calculating the symbol value. If None, this is
+ 0 for blobs and the image-start address for ELF files
"""
fake_dir = None
@@ -159,6 +162,7 @@ class Entry(object):
self.preserve = False
self.build_done = False
self.no_write_symbols = False
+ self.symbols_base = None
@staticmethod
def FindEntryClass(etype, expanded):
@@ -324,6 +328,7 @@ class Entry(object):
self.preserve = fdt_util.GetBool(self._node, 'preserve')
self.no_write_symbols = fdt_util.GetBool(self._node, 'no-write-symbols')
+ self.symbols_base = fdt_util.GetInt(self._node, 'symbols-base')
def GetDefaultFilename(self):
return None
@@ -576,8 +581,16 @@ class Entry(object):
def GetEntryArgsOrProps(self, props, required=False):
"""Return the values of a set of properties
+ Looks up the named entryargs and returns the value for each. If any
+ required ones are missing, the error is reported to the user.
+
Args:
- props: List of EntryArg objects
+ props (list of EntryArg): List of entry arguments to look up
+ required (bool): True if these entry arguments are required
+
+ Returns:
+ list of values: one for each item in props, the type is determined
+ by the EntryArg's 'datatype' property (str or int)
Raises:
ValueError if a property is not found
@@ -698,14 +711,22 @@ class Entry(object):
def WriteSymbols(self, section):
"""Write symbol values into binary files for access at run time
+ As a special case, if symbols_base is not specified and this is an
+ end-at-4gb image, a symbols_base of 0 is used
+
Args:
section: Section containing the entry
"""
if self.auto_write_symbols and not self.no_write_symbols:
# Check if we are writing symbols into an ELF file
is_elf = self.GetDefaultFilename() == self.elf_fname
+
+ symbols_base = self.symbols_base
+ if symbols_base is None and self.GetImage()._end_4gb:
+ symbols_base = 0
+
elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(),
- is_elf, self.elf_base_sym)
+ is_elf, self.elf_base_sym, symbols_base)
def CheckEntries(self):
"""Check that the entry offsets are correct
diff --git a/tools/binman/etype/atf_fip.py b/tools/binman/etype/atf_fip.py
index 3da0dfcfc12..636e073afc8 100644
--- a/tools/binman/etype/atf_fip.py
+++ b/tools/binman/etype/atf_fip.py
@@ -248,7 +248,7 @@ class Entry_atf_fip(Entry_section):
fent = entry._fip_entry
entry.size = fent.size
entry.offset = fent.offset
- entry.image_pos = self.image_pos + entry.offset
+ entry.SetImagePos(image_pos + self.offset)
def ReadChildData(self, child, decomp=True, alt_format=None):
if not self.reader:
diff --git a/tools/binman/etype/blob_phase.py b/tools/binman/etype/blob_phase.py
index 951d9934050..09bb89b3b78 100644
--- a/tools/binman/etype/blob_phase.py
+++ b/tools/binman/etype/blob_phase.py
@@ -57,3 +57,8 @@ class Entry_blob_phase(Entry_section):
if self.no_write_symbols:
for entry in self._entries.values():
entry.no_write_symbols = True
+
+ # Propagate the symbols-base property
+ if self.symbols_base is not None:
+ for entry in self._entries.values():
+ entry.symbols_base = self.symbols_base
diff --git a/tools/binman/etype/cbfs.py b/tools/binman/etype/cbfs.py
index 575aa624f6c..124fa1e4ffc 100644
--- a/tools/binman/etype/cbfs.py
+++ b/tools/binman/etype/cbfs.py
@@ -245,7 +245,7 @@ class Entry_cbfs(Entry):
cfile = entry._cbfs_file
entry.size = cfile.data_len
entry.offset = cfile.calced_cbfs_offset
- entry.image_pos = self.image_pos + entry.offset
+ entry.SetImagePos(image_pos + self.offset)
if entry._cbfs_compress:
entry.uncomp_size = cfile.memlen
diff --git a/tools/binman/etype/efi_capsule.py b/tools/binman/etype/efi_capsule.py
index 5941545d0b2..9f06cc88e6e 100644
--- a/tools/binman/etype/efi_capsule.py
+++ b/tools/binman/etype/efi_capsule.py
@@ -24,7 +24,7 @@ def get_binman_test_guid(type_str):
The actual GUID value (str)
"""
TYPE_TO_GUID = {
- 'binman-test' : '09d7cf52-0720-4710-91d1-08469b7fe9c8'
+ 'binman-test' : '985f2937-7c2e-5e9a-8a5e-8e063312964b'
}
return TYPE_TO_GUID[type_str]
@@ -151,6 +151,8 @@ class Entry_efi_capsule(Entry_section):
return tools.read_file(capsule_fname)
else:
# Bintool is missing; just use the input data as the output
+ if not self.GetAllowMissing():
+ self.Raise("Missing tool: 'mkeficapsule'")
self.record_missing_bintool(self.mkeficapsule)
return data
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index ee44e5a1cd6..0abe1c78c43 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -6,9 +6,10 @@
"""Entry-type module for producing a FIT"""
import glob
-import libfdt
import os
+import libfdt
+
from binman.entry import Entry, EntryArg
from binman.etype.section import Entry_section
from binman import elf
@@ -23,6 +24,7 @@ OPERATIONS = {
'split-elf': OP_SPLIT_ELF,
}
+# pylint: disable=invalid-name
class Entry_fit(Entry_section):
"""Flat Image Tree (FIT)
@@ -94,7 +96,10 @@ class Entry_fit(Entry_section):
can be provided as a directory. Each .dtb file in the directory is
processed, , e.g.::
- fit,fdt-list-dir = "arch/arm/dts
+ fit,fdt-list-dir = "arch/arm/dts";
+
+ In this case the input directories are ignored and all devicetree
+ files must be in that directory.
Substitutions
~~~~~~~~~~~~~
@@ -381,31 +386,46 @@ class Entry_fit(Entry_section):
def __init__(self, section, etype, node):
"""
Members:
- _fit: FIT file being built
- _entries: dict from Entry_section:
+ _fit (str): FIT file being built
+ _fit_props (list of str): 'fit,...' properties found in the
+ top-level node
+ _fdts (list of str): Filenames of .dtb files to process
+ _fdt_dir (str): Directory to scan to find .dtb files, or None
+ _fit_list_prop (str): Name of the EntryArg containing a list of .dtb
+ files
+ _fit_default_dt (str): Name of the EntryArg containing the default
+ .dtb file
+ _entries (dict of entries): from Entry_section:
key: relative path to entry Node (from the base of the FIT)
value: Entry_section object comprising the contents of this
node
- _priv_entries: Internal copy of _entries which includes 'generator'
- entries which are used to create the FIT, but should not be
- processed as real entries. This is set up once we have the
- entries
- _loadables: List of generated split-elf nodes, each a node name
+ _priv_entries (dict of entries): Internal copy of _entries which
+ includes 'generator' entries which are used to create the FIT,
+ but should not be processed as real entries. This is set up once
+ we have the entries
+ _loadables (list of str): List of generated split-elf nodes, each
+ a node name
+ _remove_props (list of str): Value of of-spl-remove-props EntryArg,
+ the list of properties to remove with fdtgrep
+ mkimage (Bintool): mkimage tool
+ fdtgrep (Bintool): fdtgrep tool
"""
super().__init__(section, etype, node)
self._fit = None
self._fit_props = {}
self._fdts = None
self._fdt_dir = None
- self.mkimage = None
- self.fdtgrep = None
+ self._fit_list_prop = None
+ self._fit_default_dt = None
self._priv_entries = {}
self._loadables = []
self._remove_props = []
- props, = self.GetEntryArgsOrProps(
- [EntryArg('of-spl-remove-props', str)], required=False)
+ props = self.GetEntryArgsOrProps(
+ [EntryArg('of-spl-remove-props', str)], required=False)[0]
if props:
self._remove_props = props.split()
+ self.mkimage = None
+ self.fdtgrep = None
def ReadNode(self):
super().ReadNode()
@@ -414,8 +434,8 @@ class Entry_fit(Entry_section):
self._fit_props[pname] = prop
self._fit_list_prop = self._fit_props.get('fit,fdt-list')
if self._fit_list_prop:
- fdts, = self.GetEntryArgsOrProps(
- [EntryArg(self._fit_list_prop.value, str)])
+ fdts = self.GetEntryArgsOrProps(
+ [EntryArg(self._fit_list_prop.value, str)])[0]
if fdts is not None:
self._fdts = fdts.split()
else:
@@ -431,7 +451,7 @@ class Entry_fit(Entry_section):
self._fit_default_dt = self.GetEntryArgsOrProps([EntryArg('default-dt',
str)])[0]
- def _get_operation(self, base_node, node):
+ def _get_operation(self, node):
"""Get the operation referenced by a subnode
Args:
@@ -550,6 +570,9 @@ class Entry_fit(Entry_section):
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:
+ str or bytes: Resulting stdout from fdtgrep
"""
return self.fdtgrep.create_for_phase(infile, phase, outfile,
self._remove_props)
@@ -557,9 +580,6 @@ class Entry_fit(Entry_section):
def _build_input(self):
"""Finish the FIT by adding the 'data' properties to it
- Arguments:
- fdt: FIT to update
-
Returns:
bytes: New fdt contents
"""
@@ -580,13 +600,17 @@ class Entry_fit(Entry_section):
if val.startswith('@'):
if not self._fdts:
return
- if not self._fit_default_dt:
+ default_dt = self._fit_default_dt
+ if not default_dt:
self.Raise("Generated 'default' node requires default-dt entry argument")
- if self._fit_default_dt not in self._fdts:
- self.Raise(
- f"default-dt entry argument '{self._fit_default_dt}' "
- f"not found in fdt list: {', '.join(self._fdts)}")
- seq = self._fdts.index(self._fit_default_dt)
+ if default_dt not in self._fdts:
+ if self._fdt_dir:
+ default_dt = os.path.basename(default_dt)
+ if default_dt not in self._fdts:
+ self.Raise(
+ f"default-dt entry argument '{self._fit_default_dt}' "
+ f"not found in fdt list: {', '.join(self._fdts)}")
+ seq = self._fdts.index(default_dt)
val = val[1:].replace('DEFAULT-SEQ', str(seq + 1))
fsw.property_string(pname, val)
return
@@ -634,7 +658,7 @@ class Entry_fit(Entry_section):
result.append(name)
return firmware, result
- def _gen_fdt_nodes(base_node, node, depth, in_images):
+ def _gen_fdt_nodes(node, depth, in_images):
"""Generate FDT nodes
This creates one node for each member of self._fdts using the
@@ -654,7 +678,10 @@ class Entry_fit(Entry_section):
# Generate nodes for each FDT
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')
+ if self._fdt_dir:
+ fname = os.path.join(self._fdt_dir, fdt_fname + '.dtb')
+ else:
+ fname = tools.get_input_filename(fdt_fname + '.dtb')
fdt_phase = None
with fsw.add_node(node_name):
for pname, prop in node.props.items():
@@ -688,8 +715,9 @@ class Entry_fit(Entry_section):
# Add data for 'images' nodes (but not 'config')
if depth == 1 and in_images:
if fdt_phase:
+ leaf = os.path.basename(fdt_fname)
phase_fname = tools.get_output_filename(
- f'{fdt_fname}-{fdt_phase}.dtb')
+ f'{leaf}-{fdt_phase}.dtb')
self._run_fdtgrep(fname, fdt_phase, phase_fname)
data = tools.read_file(phase_fname)
else:
@@ -707,11 +735,10 @@ class Entry_fit(Entry_section):
else:
self.Raise("Generator node requires 'fit,fdt-list' property")
- def _gen_split_elf(base_node, node, depth, segments, entry_addr):
+ def _gen_split_elf(node, depth, segments, entry_addr):
"""Add nodes for the ELF file, one per group of contiguous segments
Args:
- base_node (Node): Template node from the binman definition
node (Node): Node to replace (in the FIT being built)
depth: Current node depth (0 is the base 'fit' node)
segments (list): list of segments, each:
@@ -742,7 +769,7 @@ class Entry_fit(Entry_section):
with fsw.add_node(subnode.name):
_add_node(node, depth + 1, subnode)
- def _gen_node(base_node, node, depth, in_images, entry):
+ def _gen_node(node, depth, in_images, entry):
"""Generate nodes from a template
This creates one or more nodes depending on the fit,operation being
@@ -758,8 +785,6 @@ class Entry_fit(Entry_section):
If the file is missing, nothing is generated.
Args:
- base_node (Node): Base Node of the FIT (with 'description'
- property)
node (Node): Generator node to process
depth (int): Current node depth (0 is the base 'fit' node)
in_images (bool): True if this is inside the 'images' node, so
@@ -767,13 +792,12 @@ class Entry_fit(Entry_section):
entry (entry_Section): Entry for the section containing the
contents of this node
"""
- oper = self._get_operation(base_node, node)
+ oper = self._get_operation(node)
if oper == OP_GEN_FDT_NODES:
- _gen_fdt_nodes(base_node, node, depth, in_images)
+ _gen_fdt_nodes(node, depth, in_images)
elif oper == OP_SPLIT_ELF:
# Entry_section.ObtainContents() either returns True or
# raises an exception.
- data = None
missing_opt_list = []
entry.ObtainContents()
entry.Pack(0)
@@ -795,7 +819,7 @@ class Entry_fit(Entry_section):
self._raise_subnode(
node, f'Failed to read ELF file: {str(exc)}')
- _gen_split_elf(base_node, node, depth, segments, entry_addr)
+ _gen_split_elf(node, depth, segments, entry_addr)
def _add_node(base_node, depth, node):
"""Add nodes to the output FIT
@@ -826,7 +850,6 @@ class Entry_fit(Entry_section):
fsw.property('data', bytes(data))
for subnode in node.subnodes:
- subnode_path = f'{rel_path}/{subnode.name}'
if has_images and not self.IsSpecialSubnode(subnode):
# This subnode is a content node not meant to appear in
# the FIT (e.g. "/images/kernel/u-boot"), so don't call
@@ -834,7 +857,7 @@ class Entry_fit(Entry_section):
pass
elif self.GetImage().generate and subnode.name.startswith('@'):
entry = self._priv_entries.get(subnode.name)
- _gen_node(base_node, subnode, depth, in_images, entry)
+ _gen_node(subnode, depth, in_images, entry)
# This is a generator (template) entry, so remove it from
# the list of entries used by PackEntries(), etc. Otherwise
# it will appear in the binman output
@@ -876,7 +899,10 @@ class Entry_fit(Entry_section):
"""
if self.build_done:
return
- super().SetImagePos(image_pos)
+
+ # Skip the section processing, since we do that below. Just call the
+ # entry method
+ Entry.SetImagePos(self, image_pos)
# If mkimage is missing we'll have empty data,
# which will cause a FDT_ERR_BADMAGIC error
@@ -886,7 +912,7 @@ class Entry_fit(Entry_section):
fdt = Fdt.FromData(self.GetData())
fdt.Scan()
- for image_name, section in self._entries.items():
+ for image_name, entry in self._entries.items():
path = f"/images/{image_name}"
node = fdt.GetNode(path)
@@ -914,10 +940,12 @@ class Entry_fit(Entry_section):
# This should never happen
else: # pragma: no cover
+ offset = None
+ size = None
self.Raise(f'{path}: missing data properties')
- section.SetOffsetSize(offset, size)
- section.SetImagePos(self.image_pos)
+ entry.SetOffsetSize(offset, size)
+ entry.SetImagePos(image_pos + self.offset)
def AddBintools(self, btools):
super().AddBintools(btools)
@@ -947,7 +975,7 @@ class Entry_fit(Entry_section):
if input_fname:
fname = input_fname
else:
- fname = tools.get_output_filename('%s.fit' % uniq)
+ fname = tools.get_output_filename(f'{uniq}.fit')
tools.write_file(fname, self.GetData())
args.append(fname)
diff --git a/tools/binman/etype/nxp_imx8mimage.py b/tools/binman/etype/nxp_imx8mimage.py
index 3585120b79b..8ad177b3b65 100644
--- a/tools/binman/etype/nxp_imx8mimage.py
+++ b/tools/binman/etype/nxp_imx8mimage.py
@@ -27,7 +27,8 @@ class Entry_nxp_imx8mimage(Entry_mkimage):
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
- self.required_props = ['nxp,boot-from', 'nxp,rom-version', 'nxp,loader-address']
+ self.required_props = ['nxp,boot-from', 'nxp,rom-version',
+ 'nxp,loader-address']
def ReadNode(self):
super().ReadNode()
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index 30c1041c7e8..f4f48c00e87 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -563,13 +563,13 @@ class Entry_section(Entry):
return entry.GetData(required)
def LookupEntry(self, entries, sym_name, msg):
- """Look up the entry for an ENF symbol
+ """Look up the entry for a binman symbol
Args:
entries (dict): entries to search:
key: entry name
value: Entry object
- sym_name: Symbol name in the ELF file to look up in the format
+ sym_name: Symbol name to look up in the format
_binman_<entry>_prop_<property> where <entry> is the name of
the entry and <property> is the property to find (e.g.
_binman_u_boot_prop_offset). As a special case, you can append
@@ -606,11 +606,10 @@ class Entry_section(Entry):
entry = entries[name]
return entry, entry_name, prop_name
- def LookupSymbol(self, sym_name, optional, msg, base_addr, entries=None):
- """Look up a symbol in an ELF file
+ def GetSymbolValue(self, sym_name, optional, msg, base_addr, entries=None):
+ """Get the value of a Binman symbol
- Looks up a symbol in an ELF file. Only entry types which come from an
- ELF image can be used by this function.
+ Look up a Binman symbol and obtain its value.
At present the only entry properties supported are:
offset
@@ -618,7 +617,7 @@ class Entry_section(Entry):
size
Args:
- sym_name: Symbol name in the ELF file to look up in the format
+ sym_name: Symbol name to look up in the format
_binman_<entry>_prop_<property> where <entry> is the name of
the entry and <property> is the property to find (e.g.
_binman_u_boot_prop_offset). As a special case, you can append
@@ -628,12 +627,10 @@ class Entry_section(Entry):
optional: True if the symbol is optional. If False this function
will raise if the symbol is not found
msg: Message to display if an error occurs
- base_addr: Base address of image. This is added to the returned
- image_pos in most cases so that the returned position indicates
- where the targetted entry/binary has actually been loaded. But
- if end-at-4gb is used, this is not done, since the binary is
- already assumed to be linked to the ROM position and using
- execute-in-place (XIP).
+ base_addr (int): Base address of image. This is added to the
+ returned value of image-pos so that the returned position
+ indicates where the targeted entry/binary has actually been
+ loaded
Returns:
Value that should be assigned to that symbol, or None if it was
@@ -656,10 +653,10 @@ class Entry_section(Entry):
if prop_name == 'offset':
return entry.offset
elif prop_name == 'image_pos':
- value = entry.image_pos
- if not self.GetImage()._end_4gb:
- value += base_addr
- return value
+ if not entry.image_pos:
+ tout.info(f'Symbol-writing: no value for {entry._node.path}')
+ return None
+ return base_addr + entry.image_pos
if prop_name == 'size':
return entry.size
else:
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 93f3d22cf57..e3f231e4bcc 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -125,7 +125,7 @@ TEE_ADDR = 0x5678
# Firmware Management Protocol(FMP) GUID
FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
# Image GUID specified in the DTS
-CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
+CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
# Windows cert GUID
WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
# Empty capsule GUIDs
@@ -403,8 +403,10 @@ class TestFunctional(unittest.TestCase):
test_section_timeout: True to force the first time to timeout, as
used in testThreadTimeout()
update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
- force_missing_tools (str): comma-separated list of bintools to
+ force_missing_bintools (str): comma-separated list of bintools to
regard as missing
+ ignore_missing (bool): True to return success even if there are
+ missing blobs or bintools
output_dir: Specific output directory to use for image using -O
Returns:
@@ -503,8 +505,9 @@ class TestFunctional(unittest.TestCase):
return dtb.GetContents()
def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
- map=False, update_dtb=False, entry_args=None,
- reset_dtbs=True, extra_indirs=None, threads=None):
+ verbosity=None, map=False, update_dtb=False,
+ entry_args=None, reset_dtbs=True, extra_indirs=None,
+ threads=None):
"""Run binman and return the resulting image
This runs binman with a given test file and then reads the resulting
@@ -521,6 +524,7 @@ class TestFunctional(unittest.TestCase):
But in some test we need the real contents.
use_expanded: True to use expanded entries where available, e.g.
'u-boot-expanded' instead of 'u-boot'
+ verbosity: Verbosity level to use (0-3, None=don't set it)
map: True to output map files for the images
update_dtb: Update the offset and size of each entry in the device
tree before packing it into the image
@@ -557,7 +561,8 @@ class TestFunctional(unittest.TestCase):
try:
retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
entry_args=entry_args, use_real_dtb=use_real_dtb,
- use_expanded=use_expanded, extra_indirs=extra_indirs,
+ use_expanded=use_expanded, verbosity=verbosity,
+ extra_indirs=extra_indirs,
threads=threads)
self.assertEqual(0, retcode)
out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
@@ -1498,18 +1503,22 @@ class TestFunctional(unittest.TestCase):
self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
- use_expanded=False, no_write_symbols=False):
+ use_expanded=False, no_write_symbols=False,
+ symbols_base=None):
"""Check the image contains the expected symbol values
Args:
dts: Device tree file to use for test
base_data: Data before and after 'u-boot' section
- u_boot_offset: Offset of 'u-boot' section in image
+ u_boot_offset (int): Offset of 'u-boot' section in image, or None if
+ the offset not available due to it being in a compressed section
entry_args: Dict of entry args to supply to binman
key: arg name
value: value of that arg
use_expanded: True to use expanded entries where available, e.g.
'u-boot-expanded' instead of 'u-boot'
+ symbols_base (int): Value to expect for symbols-base in u-boot-spl,
+ None if none
"""
elf_fname = self.ElfTestFile('u_boot_binman_syms')
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
@@ -1520,22 +1529,64 @@ class TestFunctional(unittest.TestCase):
self._SetupSplElf('u_boot_binman_syms')
data = self._DoReadFileDtb(dts, entry_args=entry_args,
- use_expanded=use_expanded)[0]
+ use_expanded=use_expanded,
+ verbosity=None if u_boot_offset else 3)[0]
+
+ # The lz4-compressed version of the U-Boot data is 19 bytes long
+ comp_uboot_len = 19
+
# The image should contain the symbols from u_boot_binman_syms.c
# Note that image_pos is adjusted by the base address of the image,
# which is 0x10 in our test image
- sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
- 0x00, u_boot_offset + len(U_BOOT_DATA),
- 0x10 + u_boot_offset, 0x04)
+ # If u_boot_offset is None, Binman should write -1U into the image
+ vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
+ u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
+ len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
+ 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
+
+ # u-boot-spl has a symbols-base property, so take that into account if
+ # required. The caller must supply the value
+ vals = list(vals2)
+ if symbols_base is not None:
+ vals[3] = symbols_base + u_boot_offset
+ vals = tuple(vals)
+
+ sym_values = struct.pack('<LLQLL', *vals)
+ sym_values2 = struct.pack('<LLQLL', *vals2)
if no_write_symbols:
- expected = (base_data +
- tools.get_bytes(0xff, 0x38 - len(base_data)) +
- U_BOOT_DATA + base_data)
+ self.assertEqual(
+ base_data +
+ tools.get_bytes(0xff, 0x38 - len(base_data)) +
+ U_BOOT_DATA + base_data, data)
else:
- expected = (sym_values + base_data[24:] +
- tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
- base_data[24:])
- self.assertEqual(expected, data)
+ got_vals = struct.unpack('<LLQLL', data[:24])
+
+ # For debugging:
+ #print('expect:', list(f'{v:x}' for v in vals))
+ #print(' got:', list(f'{v:x}' for v in got_vals))
+
+ self.assertEqual(vals, got_vals)
+ self.assertEqual(sym_values, data[:24])
+
+ blen = len(base_data)
+ self.assertEqual(base_data[24:], data[24:blen])
+ self.assertEqual(0xff, data[blen])
+
+ if u_boot_offset:
+ ofs = blen + 1 + len(U_BOOT_DATA)
+ self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
+ else:
+ ofs = blen + 1 + comp_uboot_len
+
+ self.assertEqual(sym_values2, data[ofs:ofs + 24])
+ self.assertEqual(base_data[24:], data[ofs + 24:])
+
+ # Just repeating the above asserts all at once, for clarity
+ if u_boot_offset:
+ expected = (sym_values + base_data[24:] +
+ tools.get_bytes(0xff, 1) + U_BOOT_DATA +
+ sym_values2 + base_data[24:])
+ self.assertEqual(expected, data)
def testSymbols(self):
"""Test binman can assign symbols embedded in U-Boot"""
@@ -4181,7 +4232,8 @@ class TestFunctional(unittest.TestCase):
data = self._DoReadFile('172_scp.dts')
self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
- def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True):
+ def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
+ default_dt=None):
"""Check an image with an FIT with multiple FDT images"""
def _CheckFdt(seq, expected_data):
"""Check the FDT nodes
@@ -4225,6 +4277,8 @@ class TestFunctional(unittest.TestCase):
}
if use_fdt_list:
entry_args['of-list'] = 'test-fdt1 test-fdt2'
+ if default_dt:
+ entry_args['default-dt'] = default_dt
data = self._DoReadFileDtb(
dts,
entry_args=entry_args,
@@ -7624,7 +7678,22 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
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)
+ old_dir = os.getcwd()
+ try:
+ os.chdir(self._indir)
+ self.CheckFitFdt('333_fit_fdt_dir.dts', False)
+ finally:
+ os.chdir(old_dir)
+
+ def testFitFdtListDirDefault(self):
+ """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
+ old_dir = os.getcwd()
+ try:
+ os.chdir(self._indir)
+ self.CheckFitFdt('333_fit_fdt_dir.dts', False,
+ default_dt='rockchip/test-fdt2')
+ finally:
+ os.chdir(old_dir)
def testFitFdtCompat(self):
"""Test an image with an FIT with compatible in the config nodes"""
@@ -7690,6 +7759,51 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
# Make sure the other node is gone
self.assertIsNone(dtb.GetNode('/node/other-node'))
+ def testMkeficapsuleMissing(self):
+ """Test that binman complains if mkeficapsule is missing"""
+ with self.assertRaises(ValueError) as e:
+ self._DoTestFile('311_capsule.dts',
+ force_missing_bintools='mkeficapsule')
+ self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
+ str(e.exception))
+
+ def testMkeficapsuleMissingOk(self):
+ """Test that binman deals with mkeficapsule being missing"""
+ with test_util.capture_sys_output() as (stdout, stderr):
+ ret = self._DoTestFile('311_capsule.dts',
+ force_missing_bintools='mkeficapsule',
+ allow_missing=True)
+ self.assertEqual(103, ret)
+ err = stderr.getvalue()
+ self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
+
+ def testSymbolsBase(self):
+ """Test handling of symbols-base"""
+ self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
+ symbols_base=0)
+
+ def testSymbolsBaseExpanded(self):
+ """Test handling of symbols-base with expanded entries"""
+ entry_args = {
+ 'spl-dtb': '1',
+ }
+ self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
+ U_BOOT_SPL_DTB_DATA, 0x38,
+ entry_args=entry_args, use_expanded=True,
+ symbols_base=0)
+
+ def testSymbolsCompressed(self):
+ """Test binman complains about symbols from a compressed section"""
+ with test_util.capture_sys_output() as (stdout, stderr):
+ self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
+ out = stdout.getvalue()
+ self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
+ out)
+
+ def testNxpImx8Image(self):
+ """Test that binman can produce an iMX8 image"""
+ self._DoTestFile('339_nxp_imx8.dts')
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/image.py b/tools/binman/image.py
index 702c9055585..24ce0af7c72 100644
--- a/tools/binman/image.py
+++ b/tools/binman/image.py
@@ -381,11 +381,10 @@ class Image(section.Entry_section):
selected_entries.append(entry)
return selected_entries, lines, widths
- def LookupImageSymbol(self, sym_name, optional, msg, base_addr):
- """Look up a symbol in an ELF file
+ def GetImageSymbolValue(self, sym_name, optional, msg, base_addr):
+ """Get the value of a Binman symbol
- Looks up a symbol in an ELF file. Only entry types which come from an
- ELF image can be used by this function.
+ Look up a Binman symbol and obtain its value.
This searches through this image including all of its subsections.
@@ -405,12 +404,10 @@ class Image(section.Entry_section):
optional: True if the symbol is optional. If False this function
will raise if the symbol is not found
msg: Message to display if an error occurs
- base_addr: Base address of image. This is added to the returned
- image_pos in most cases so that the returned position indicates
- where the targeted entry/binary has actually been loaded. But
- if end-at-4gb is used, this is not done, since the binary is
- already assumed to be linked to the ROM position and using
- execute-in-place (XIP).
+ base_addr (int): Base address of image. This is added to the
+ returned value of image-pos so that the returned position
+ indicates where the targeted entry/binary has actually been
+ loaded
Returns:
Value that should be assigned to that symbol, or None if it was
@@ -423,8 +420,8 @@ class Image(section.Entry_section):
entries = OrderedDict()
entries_by_name = {}
self._CollectEntries(entries, entries_by_name, self)
- return self.LookupSymbol(sym_name, optional, msg, base_addr,
- entries_by_name)
+ return self.GetSymbolValue(sym_name, optional, msg, base_addr,
+ entries_by_name)
def CollectBintools(self):
"""Collect all the bintools used by this image
diff --git a/tools/binman/image_test.py b/tools/binman/image_test.py
index bd51c1e55d1..7d65e2d589a 100644
--- a/tools/binman/image_test.py
+++ b/tools/binman/image_test.py
@@ -13,7 +13,7 @@ class TestImage(unittest.TestCase):
def testInvalidFormat(self):
image = Image('name', 'node', test=True)
with self.assertRaises(ValueError) as e:
- image.LookupSymbol('_binman_something_prop_', False, 'msg', 0)
+ image.GetSymbolValue('_binman_something_prop_', False, 'msg', 0)
self.assertIn(
"msg: Symbol '_binman_something_prop_' has invalid format",
str(e.exception))
@@ -22,7 +22,7 @@ class TestImage(unittest.TestCase):
image = Image('name', 'node', test=True)
image._entries = {}
with self.assertRaises(ValueError) as e:
- image.LookupSymbol('_binman_type_prop_pname', False, 'msg', 0)
+ image.GetSymbolValue('_binman_type_prop_pname', False, 'msg', 0)
self.assertIn("msg: Entry 'type' not found in list ()",
str(e.exception))
@@ -30,7 +30,7 @@ class TestImage(unittest.TestCase):
image = Image('name', 'node', test=True)
image._entries = {}
with capture_sys_output() as (stdout, stderr):
- val = image.LookupSymbol('_binman_type_prop_pname', True, 'msg', 0)
+ val = image.GetSymbolValue('_binman_type_prop_pname', True, 'msg', 0)
self.assertEqual(val, None)
self.assertEqual("Warning: msg: Entry 'type' not found in list ()\n",
stderr.getvalue())
@@ -40,5 +40,5 @@ class TestImage(unittest.TestCase):
image = Image('name', 'node', test=True)
image._entries = {'u-boot': 1}
with self.assertRaises(ValueError) as e:
- image.LookupSymbol('_binman_u_boot_prop_bad', False, 'msg', 0)
+ image.GetSymbolValue('_binman_u_boot_prop_bad', False, 'msg', 0)
self.assertIn("msg: No such property 'bad", str(e.exception))
diff --git a/tools/binman/test/336_symbols_base.dts b/tools/binman/test/336_symbols_base.dts
new file mode 100644
index 00000000000..e4dccd38c22
--- /dev/null
+++ b/tools/binman/test/336_symbols_base.dts
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0xff>;
+ u-boot-spl {
+ symbols-base = <0>;
+ };
+
+ u-boot {
+ offset = <0x1c>;
+ };
+
+ u-boot-spl2 {
+ type = "u-boot-spl";
+ };
+ };
+};
diff --git a/tools/binman/test/337_symbols_base_expand.dts b/tools/binman/test/337_symbols_base_expand.dts
new file mode 100644
index 00000000000..5a777ae63b8
--- /dev/null
+++ b/tools/binman/test/337_symbols_base_expand.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0xff>;
+ u-boot-spl {
+ symbols-base = <0>;
+ };
+
+ u-boot {
+ offset = <0x38>;
+ no-expanded;
+ };
+
+ u-boot-spl2 {
+ type = "u-boot-spl";
+ };
+ };
+};
diff --git a/tools/binman/test/338_symbols_comp.dts b/tools/binman/test/338_symbols_comp.dts
new file mode 100644
index 00000000000..15008507cfd
--- /dev/null
+++ b/tools/binman/test/338_symbols_comp.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0xff>;
+ u-boot-spl {
+ };
+
+ section {
+ offset = <0x1c>;
+ compress = "lz4";
+
+ u-boot {
+ };
+ };
+
+ u-boot-spl2 {
+ type = "u-boot-spl";
+ };
+ };
+};
diff --git a/tools/binman/test/339_nxp_imx8.dts b/tools/binman/test/339_nxp_imx8.dts
new file mode 100644
index 00000000000..cb512ae9aa2
--- /dev/null
+++ b/tools/binman/test/339_nxp_imx8.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ nxp-imx8mimage {
+ args; /* TODO: Needed by mkimage etype superclass */
+ nxp,boot-from = "sd";
+ nxp,rom-version = <1>;
+ nxp,loader-address = <0x10>;
+ };
+ };
+};
diff --git a/tools/buildman/bsettings.py b/tools/buildman/bsettings.py
index aea724fc559..a7358cfc08a 100644
--- a/tools/buildman/bsettings.py
+++ b/tools/buildman/bsettings.py
@@ -31,6 +31,9 @@ def setup(fname=''):
def add_file(data):
settings.read_file(io.StringIO(data))
+def add_section(name):
+ settings.add_section(name)
+
def get_items(section):
"""Get the items from a section of the config.
diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py
index c4384f53e8d..4090d328b30 100644
--- a/tools/buildman/builder.py
+++ b/tools/buildman/builder.py
@@ -22,6 +22,7 @@ from buildman import toolchain
from patman import gitutil
from u_boot_pylib import command
from u_boot_pylib import terminal
+from u_boot_pylib import tools
from u_boot_pylib.terminal import tprint
# This indicates an new int or hex Kconfig property with no default
@@ -263,7 +264,8 @@ class Builder:
adjust_cfg=None, allow_missing=False, no_lto=False,
reproducible_builds=False, force_build=False,
force_build_failures=False, force_reconfig=False,
- in_tree=False, force_config_on_failure=False, make_func=None):
+ in_tree=False, force_config_on_failure=False, make_func=None,
+ dtc_skip=False):
"""Create a new Builder object
Args:
@@ -312,6 +314,7 @@ class Builder:
force_config_on_failure (bool): Reconfigure the build before
retrying a failed build
make_func (function): Function to call to run 'make'
+ dtc_skip (bool): True to skip building dtc and use the system one
"""
self.toolchains = toolchains
self.base_dir = base_dir
@@ -354,6 +357,12 @@ class Builder:
self.in_tree = in_tree
self.force_config_on_failure = force_config_on_failure
self.fallback_mrproper = fallback_mrproper
+ if dtc_skip:
+ self.dtc = shutil.which('dtc')
+ if not self.dtc:
+ raise ValueError('Cannot find dtc')
+ else:
+ self.dtc = None
if not self.squash_config_y:
self.config_filenames += EXTRA_CONFIG_FILENAMES
@@ -407,6 +416,22 @@ class Builder:
def signal_handler(self, signal, frame):
sys.exit(1)
+ def make_environment(self, toolchain):
+ """Create the environment to use for building
+
+ Args:
+ toolchain (Toolchain): Toolchain to use for building
+
+ Returns:
+ dict:
+ key (str): Variable name
+ value (str): Variable value
+ """
+ env = toolchain.MakeEnvironment(self.full_path)
+ if self.dtc:
+ env[b'DTC'] = tools.to_bytes(self.dtc)
+ return env
+
def set_display_options(self, show_errors=False, show_sizes=False,
show_detail=False, show_bloat=False,
list_error_boards=False, show_config=False,
diff --git a/tools/buildman/builderthread.py b/tools/buildman/builderthread.py
index bbe2f6f0d24..b5afee61aff 100644
--- a/tools/buildman/builderthread.py
+++ b/tools/buildman/builderthread.py
@@ -406,7 +406,7 @@ class BuilderThread(threading.Thread):
the next incremental build
"""
# Set up the environment and command line
- env = self.toolchain.MakeEnvironment(self.builder.full_path)
+ env = self.builder.make_environment(self.toolchain)
mkdir(out_dir)
args, cwd, src_dir = self._build_args(brd, out_dir, out_rel_dir,
@@ -574,7 +574,7 @@ class BuilderThread(threading.Thread):
outf.write(f'{result.return_code}')
# Write out the image and function size information and an objdump
- env = result.toolchain.MakeEnvironment(self.builder.full_path)
+ env = self.builder.make_environment(self.toolchain)
with open(os.path.join(build_dir, 'out-env'), 'wb') as outf:
for var in sorted(env.keys()):
outf.write(b'%s="%s"' % (var, env[var]))
@@ -755,6 +755,14 @@ class BuilderThread(threading.Thread):
self.mrproper, self.builder.config_only, True,
self.builder.force_build_failures, job.work_in_output,
job.adjust_cfg)
+ failed = result.return_code or result.stderr
+ if failed and not self.mrproper:
+ result, request_config = self.run_commit(None, brd, work_dir,
+ True, self.builder.fallback_mrproper,
+ self.builder.config_only, True,
+ self.builder.force_build_failures,
+ job.work_in_output, job.adjust_cfg)
+
result.commit_upto = 0
self._write_result(result, job.keep_outputs, job.work_in_output)
self._send_result(result)
diff --git a/tools/buildman/buildman.rst b/tools/buildman/buildman.rst
index b8ff3bf1ab2..e873611e596 100644
--- a/tools/buildman/buildman.rst
+++ b/tools/buildman/buildman.rst
@@ -1030,6 +1030,9 @@ of the source tree, thus allowing rapid tested evolution of the code::
./tools/buildman/buildman -Pr tegra
+Note also the `--dtc-skip` option which uses the system device-tree compiler to
+avoid needing to build it for each board. This can save 10-20% of build time.
+An alternative is to set DTC=/path/to/dtc when running buildman.
Checking configuration
----------------------
diff --git a/tools/buildman/cmdline.py b/tools/buildman/cmdline.py
index 544a391a464..7573e5bdfe8 100644
--- a/tools/buildman/cmdline.py
+++ b/tools/buildman/cmdline.py
@@ -46,6 +46,8 @@ def add_upto_m(parser):
help='Show detailed size delta for each board in the -S summary')
parser.add_argument('-D', '--debug', action='store_true',
help='Enabling debugging (provides a full traceback on error)')
+ parser.add_argument('--dtc-skip', action='store_true', default=False,
+ help='Skip building of dtc and use the system version')
parser.add_argument('-e', '--show_errors', action='store_true',
default=False, help='Show errors and warnings')
parser.add_argument('-E', '--warnings-as-errors', action='store_true',
diff --git a/tools/buildman/control.py b/tools/buildman/control.py
index d3d027f02ab..55d4d770c5c 100644
--- a/tools/buildman/control.py
+++ b/tools/buildman/control.py
@@ -809,7 +809,8 @@ def do_buildman(args, toolchains=None, make_func=None, brds=None,
force_build = args.force_build,
force_build_failures = args.force_build_failures,
force_reconfig = args.force_reconfig, in_tree = args.in_tree,
- force_config_on_failure=not args.quick, make_func=make_func)
+ force_config_on_failure=not args.quick, make_func=make_func,
+ dtc_skip=args.dtc_skip)
TEST_BUILDER = builder
diff --git a/tools/buildman/kconfiglib.py b/tools/buildman/kconfiglib.py
index b9f37567559..27abbf9a7a1 100644
--- a/tools/buildman/kconfiglib.py
+++ b/tools/buildman/kconfiglib.py
@@ -6,7 +6,7 @@ Overview
========
Kconfiglib is a Python 2/3 library for scripting and extracting information
-from Kconfig (https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt)
+from Kconfig (https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.rst)
configuration systems.
See the homepage at https://github.com/ulfalizer/Kconfiglib for a longer
@@ -709,7 +709,7 @@ class Kconfig(object):
mainmenu_text:
The prompt (title) of the top menu (top_node). Defaults to "Main menu".
- Can be changed with the 'mainmenu' statement (see kconfig-language.txt).
+ Can be changed with the 'mainmenu' statement (see kconfig-language.rst).
variables:
A dictionary with all preprocessor variables, indexed by name. See the
@@ -3562,7 +3562,7 @@ class Kconfig(object):
#
# - Propagates dependencies from parent to child nodes
#
- # - Creates implicit menus (see kconfig-language.txt)
+ # - Creates implicit menus (see kconfig-language.rst)
#
# - Removes 'if' nodes
#
@@ -5030,7 +5030,7 @@ class Choice(object):
0 (n) - The choice is disabled and no symbols can be selected. For
visible choices, this mode is only possible for choices with
- the 'optional' flag set (see kconfig-language.txt).
+ the 'optional' flag set (see kconfig-language.rst).
1 (m) - Any number of choice symbols can be set to m, the rest will
be n.
@@ -5498,7 +5498,7 @@ class MenuNode(object):
Choices and menus naturally have children, but Symbols can also have
children because of menus created automatically from dependencies (see
- kconfig-language.txt).
+ kconfig-language.rst).
parent:
The parent menu node. None if there is no parent.
diff --git a/tools/buildman/test.py b/tools/buildman/test.py
index bfad3093030..15801f6097f 100644
--- a/tools/buildman/test.py
+++ b/tools/buildman/test.py
@@ -36,6 +36,16 @@ main: /usr/sbin
x86: i386 x86_64
'''
+settings_data_wrapper = '''
+# Buildman settings file
+
+[toolchain]
+main: /usr/sbin
+
+[toolchain-wrapper]
+wrapper = ccache
+'''
+
migration = '''===================== WARNING ======================
This board does not use CONFIG_DM. CONFIG_DM will be
compulsory starting with the v2020.01 release.
@@ -148,6 +158,7 @@ class TestBuild(unittest.TestCase):
self.toolchains.Add('arm-linux-gcc', test=False)
self.toolchains.Add('sparc-linux-gcc', test=False)
self.toolchains.Add('powerpc-linux-gcc', test=False)
+ self.toolchains.Add('/path/to/aarch64-linux-gcc', test=False)
self.toolchains.Add('gcc', test=False)
# Avoid sending any output
@@ -605,6 +616,9 @@ class TestBuild(unittest.TestCase):
tc.GetEnvArgs(toolchain.VAR_ARCH))
self.assertEqual('', tc.GetEnvArgs(toolchain.VAR_MAKE_ARGS))
+ tc = self.toolchains.Select('sandbox')
+ self.assertEqual('', tc.GetEnvArgs(toolchain.VAR_CROSS_COMPILE))
+
self.toolchains.Add('/path/to/x86_64-linux-gcc', test=False)
tc = self.toolchains.Select('x86')
self.assertEqual('/path/to',
@@ -613,6 +627,39 @@ class TestBuild(unittest.TestCase):
self.assertEqual('HOSTCC=clang CC=clang',
tc.GetEnvArgs(toolchain.VAR_MAKE_ARGS))
+ # Test config with ccache wrapper
+ bsettings.setup(None)
+ bsettings.add_file(settings_data_wrapper)
+
+ tc = self.toolchains.Select('arm')
+ self.assertEqual('ccache arm-linux-',
+ tc.GetEnvArgs(toolchain.VAR_CROSS_COMPILE))
+
+ tc = self.toolchains.Select('sandbox')
+ self.assertEqual('', tc.GetEnvArgs(toolchain.VAR_CROSS_COMPILE))
+
+ def testMakeEnvironment(self):
+ """Test the MakeEnvironment function"""
+ tc = self.toolchains.Select('arm')
+ env = tc.MakeEnvironment(False)
+ self.assertEqual(env[b'CROSS_COMPILE'], b'arm-linux-')
+
+ tc = self.toolchains.Select('sandbox')
+ env = tc.MakeEnvironment(False)
+ self.assertTrue(b'CROSS_COMPILE' not in env)
+
+ # Test config with ccache wrapper
+ bsettings.setup(None)
+ bsettings.add_file(settings_data_wrapper)
+
+ tc = self.toolchains.Select('arm')
+ env = tc.MakeEnvironment(False)
+ self.assertEqual(env[b'CROSS_COMPILE'], b'ccache arm-linux-')
+
+ tc = self.toolchains.Select('sandbox')
+ env = tc.MakeEnvironment(False)
+ self.assertTrue(b'CROSS_COMPILE' not in env)
+
def testPrepareOutputSpace(self):
def _Touch(fname):
tools.write_file(os.path.join(base_dir, fname), b'')
@@ -779,6 +826,7 @@ class TestBuild(unittest.TestCase):
tmpdir = self.base_dir
with (patch('time.time', side_effect=self.get_time),
+ patch('time.monotonic', side_effect=self.get_time),
patch('time.sleep', side_effect=self.inc_time),
patch('os.kill', side_effect=self.kill)):
# Grab the process. Since there is no other profcess, this should
@@ -868,6 +916,120 @@ class TestBuild(unittest.TestCase):
self.assertEqual([4, 5], control.read_procs(tmpdir))
self.assertEqual(self.finish_time, self.cur_time)
+ def call_make_environment(self, tchn, full_path, in_env=None):
+ """Call Toolchain.MakeEnvironment() and process the result
+
+ Args:
+ tchn (Toolchain): Toolchain to use
+ full_path (bool): True to return the full path in CROSS_COMPILE
+ rather than adding it to the PATH variable
+ in_env (dict): Input environment to use, None to use current env
+
+ Returns:
+ tuple:
+ dict: Changes that MakeEnvironment has made to the environment
+ key: Environment variable that was changed
+ value: New value (for PATH this only includes components
+ which were added)
+ str: Full value of the new PATH variable
+ """
+ env = tchn.MakeEnvironment(full_path, env=in_env)
+
+ # Get the original environment
+ orig_env = dict(os.environb if in_env is None else in_env)
+ orig_path = orig_env[b'PATH'].split(b':')
+
+ # Find new variables
+ diff = dict((k, env[k]) for k in env if orig_env.get(k) != env[k])
+
+ # Find new / different path components
+ diff_path = None
+ new_path = None
+ if b'PATH' in diff:
+ new_path = diff[b'PATH'].split(b':')
+ diff_paths = [p for p in new_path if p not in orig_path]
+ diff_path = b':'.join(p for p in new_path if p not in orig_path)
+ if diff_path:
+ diff[b'PATH'] = diff_path
+ else:
+ del diff[b'PATH']
+ return diff, new_path
+
+ def test_toolchain_env(self):
+ """Test PATH and other environment settings for toolchains"""
+ # Use a toolchain which has a path, so that full_path makes a difference
+ tchn = self.toolchains.Select('aarch64')
+
+ # Normal cases
+ diff = self.call_make_environment(tchn, full_path=False)[0]
+ self.assertEqual(
+ {b'CROSS_COMPILE': b'aarch64-linux-', b'LC_ALL': b'C',
+ b'PATH': b'/path/to'}, diff)
+
+ diff = self.call_make_environment(tchn, full_path=True)[0]
+ self.assertEqual(
+ {b'CROSS_COMPILE': b'/path/to/aarch64-linux-', b'LC_ALL': b'C'},
+ diff)
+
+ # When overriding the toolchain, only LC_ALL should be set
+ tchn.override_toolchain = True
+ diff = self.call_make_environment(tchn, full_path=True)[0]
+ self.assertEqual({b'LC_ALL': b'C'}, diff)
+
+ # Test that virtualenv is handled correctly
+ tchn.override_toolchain = False
+ sys.prefix = '/some/venv'
+ env = dict(os.environb)
+ env[b'PATH'] = b'/some/venv/bin:other/things'
+ tchn.path = '/my/path'
+ diff, diff_path = self.call_make_environment(tchn, False, env)
+
+ self.assertIn(b'PATH', diff)
+ self.assertEqual([b'/some/venv/bin', b'/my/path', b'other/things'],
+ diff_path)
+ self.assertEqual(
+ {b'CROSS_COMPILE': b'aarch64-linux-', b'LC_ALL': b'C',
+ b'PATH': b'/my/path'}, diff)
+
+ # Handle a toolchain wrapper
+ tchn.path = ''
+ bsettings.add_section('toolchain-wrapper')
+ bsettings.set_item('toolchain-wrapper', 'my-wrapper', 'fred')
+ diff = self.call_make_environment(tchn, full_path=True)[0]
+ self.assertEqual(
+ {b'CROSS_COMPILE': b'fred aarch64-linux-', b'LC_ALL': b'C'}, diff)
+
+ def test_skip_dtc(self):
+ """Test skipping building the dtc tool"""
+ old_path = os.getenv('PATH')
+ try:
+ os.environ['PATH'] = self.base_dir
+
+ # Check a missing tool
+ with self.assertRaises(ValueError) as exc:
+ builder.Builder(self.toolchains, self.base_dir, None, 0, 2,
+ dtc_skip=True)
+ self.assertIn('Cannot find dtc', str(exc.exception))
+
+ # Create a fake tool to use
+ dtc = os.path.join(self.base_dir, 'dtc')
+ tools.write_file(dtc, b'xx')
+ os.chmod(dtc, 0o777)
+
+ build = builder.Builder(self.toolchains, self.base_dir, None, 0, 2,
+ dtc_skip=True)
+ toolchain = self.toolchains.Select('arm')
+ env = build.make_environment(toolchain)
+ self.assertIn(b'DTC', env)
+
+ # Try the normal case, i.e. not skipping the dtc build
+ build = builder.Builder(self.toolchains, self.base_dir, None, 0, 2)
+ toolchain = self.toolchains.Select('arm')
+ env = build.make_environment(toolchain)
+ self.assertNotIn(b'DTC', env)
+ finally:
+ os.environ['PATH'] = old_path
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/buildman/toolchain.py b/tools/buildman/toolchain.py
index 324ad0e0821..a7d7883b851 100644
--- a/tools/buildman/toolchain.py
+++ b/tools/buildman/toolchain.py
@@ -159,6 +159,8 @@ class Toolchain:
if which == VAR_CROSS_COMPILE:
wrapper = self.GetWrapper()
base = '' if self.arch == 'sandbox' else self.path
+ if (base == '' and self.cross == ''):
+ return ''
return wrapper + os.path.join(base, self.cross)
elif which == VAR_PATH:
return self.path
@@ -172,13 +174,14 @@ class Toolchain:
else:
raise ValueError('Unknown arg to GetEnvArgs (%d)' % which)
- def MakeEnvironment(self, full_path):
+ def MakeEnvironment(self, full_path, env=None):
"""Returns an environment for using the toolchain.
This takes the current environment and adds CROSS_COMPILE so that
the tool chain will operate correctly. This also disables localized
output and possibly Unicode encoded output of all build tools by
- adding LC_ALL=C.
+ adding LC_ALL=C. For the case where full_path is False, it prepends
+ the toolchain to PATH
Note that os.environb is used to obtain the environment, since in some
cases the environment many contain non-ASCII characters and we see
@@ -187,26 +190,48 @@ class Toolchain:
UnicodeEncodeError: 'utf-8' codec can't encode characters in position
569-570: surrogates not allowed
+ When running inside a Python venv, care is taken not to put the
+ toolchain path before the venv path, so that builds initiated by
+ buildman will still respect the venv.
+
Args:
full_path: Return the full path in CROSS_COMPILE and don't set
PATH
+ env (dict of bytes): Original environment, used for testing
Returns:
Dict containing the (bytes) environment to use. This is based on the
current environment, with changes as needed to CROSS_COMPILE, PATH
and LC_ALL.
"""
- env = dict(os.environb)
+ env = dict(env or os.environb)
+
wrapper = self.GetWrapper()
if self.override_toolchain:
# We'll use MakeArgs() to provide this
pass
- elif full_path:
+ elif full_path and self.cross:
env[b'CROSS_COMPILE'] = tools.to_bytes(
wrapper + os.path.join(self.path, self.cross))
- else:
+ elif self.cross:
env[b'CROSS_COMPILE'] = tools.to_bytes(wrapper + self.cross)
- env[b'PATH'] = tools.to_bytes(self.path) + b':' + env[b'PATH']
+
+ # Detect a Python virtualenv and avoid defeating it
+ if sys.prefix != sys.base_prefix:
+ paths = env[b'PATH'].split(b':')
+ new_paths = []
+ to_insert = tools.to_bytes(self.path)
+ insert_after = tools.to_bytes(sys.prefix)
+ for path in paths:
+ new_paths.append(path)
+ if to_insert and path.startswith(insert_after):
+ new_paths.append(to_insert)
+ to_insert = None
+ if to_insert:
+ new_paths.append(to_insert)
+ env[b'PATH'] = b':'.join(new_paths)
+ else:
+ env[b'PATH'] = tools.to_bytes(self.path) + b':' + env[b'PATH']
env[b'LC_ALL'] = b'C'
diff --git a/tools/eficapsule.h b/tools/eficapsule.h
index 6efd07d2eb6..97d077536d5 100644
--- a/tools/eficapsule.h
+++ b/tools/eficapsule.h
@@ -24,7 +24,7 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-typedef struct {
+typedef struct efi_guid {
uint8_t b[16];
} efi_guid_t __aligned(8);
diff --git a/tools/image-sig-host.c b/tools/image-sig-host.c
index d0133aec4c8..21b4fa5d39d 100644
--- a/tools/image-sig-host.c
+++ b/tools/image-sig-host.c
@@ -76,6 +76,13 @@ struct crypto_algo crypto_algos[] = {
.add_verify_data = ecdsa_add_verify_data,
.verify = ecdsa_verify,
},
+ {
+ .name = "secp521r1",
+ .key_len = ECDSA521_BYTES,
+ .sign = ecdsa_sign,
+ .add_verify_data = ecdsa_add_verify_data,
+ .verify = ecdsa_verify,
+ },
};
struct padding_algo padding_algos[] = {
diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
index 1b53151d41a..49f5b7849e4 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -16,16 +16,20 @@
#include <sys/stat.h>
#include <sys/types.h>
-#include <uuid/uuid.h>
#include <gnutls/gnutls.h>
#include <gnutls/pkcs7.h>
#include <gnutls/abstract.h>
#include <version.h>
+#include <libfdt.h>
+#include <u-boot/uuid.h>
#include "eficapsule.h"
+// Matches CONFIG_EFI_CAPSULE_NAMESPACE_GUID
+#define DEFAULT_NAMESPACE_GUID "8c9f137e-91dc-427b-b2d6-b420faebaf2a"
+
static const char *tool_name = "mkeficapsule";
efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
@@ -56,9 +60,20 @@ static struct option options[] = {
{NULL, 0, NULL, 0},
};
-static void print_usage(void)
+static void print_usage_guidgen(void)
{
- fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n"
+ fprintf(stderr, "%s guidgen [GUID] DTB IMAGE_NAME...\n"
+ "Options:\n"
+
+ "\tGUID Namespace GUID (default: %s)\n"
+ "\tDTB Device Tree Blob\n"
+ "\tIMAGE_NAME... One or more names of fw_images to generate GUIDs for\n",
+ tool_name, DEFAULT_NAMESPACE_GUID);
+}
+
+static void print_usage_mkeficapsule(void)
+{
+ fprintf(stderr, "Usage:\n\n%s [options] <image blob> <output file>\n"
"Options:\n"
"\t-g, --guid <guid string> guid for image blob type\n"
@@ -74,8 +89,9 @@ static void print_usage(void)
"\t-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n"
"\t-D, --dump-capsule dump the contents of the capsule headers\n"
"\t-V, --version show version number\n"
- "\t-h, --help print a help message\n",
+ "\t-h, --help print a help message\n\n",
tool_name);
+ print_usage_guidgen();
}
/**
@@ -578,37 +594,6 @@ err:
return ret;
}
-/**
- * convert_uuid_to_guid() - convert UUID to GUID
- * @buf: UUID binary
- *
- * UUID and GUID have the same data structure, but their binary
- * formats are different due to the endianness. See lib/uuid.c.
- * Since uuid_parse() can handle only UUID, this function must
- * be called to get correct data for GUID when parsing a string.
- *
- * The correct data will be returned in @buf.
- */
-void convert_uuid_to_guid(unsigned char *buf)
-{
- unsigned char c;
-
- c = buf[0];
- buf[0] = buf[3];
- buf[3] = c;
- c = buf[1];
- buf[1] = buf[2];
- buf[2] = c;
-
- c = buf[4];
- buf[4] = buf[5];
- buf[5] = c;
-
- c = buf[6];
- buf[6] = buf[7];
- buf[7] = c;
-}
-
static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept)
{
struct efi_capsule_header header = { 0 };
@@ -654,20 +639,10 @@ err:
static void print_guid(void *ptr)
{
- int i;
- efi_guid_t *guid = ptr;
- const uint8_t seq[] = {
- 3, 2, 1, 0, '-', 5, 4, '-', 7, 6,
- '-', 8, 9, '-', 10, 11, 12, 13, 14, 15 };
-
- for (i = 0; i < ARRAY_SIZE(seq); i++) {
- if (seq[i] == '-')
- putchar(seq[i]);
- else
- printf("%02X", guid->b[seq[i]]);
- }
+ static char buf[37] = { 0 };
- printf("\n");
+ uuid_bin_to_str(ptr, buf, UUID_STR_FORMAT_GUID | UUID_STR_UPPER_CASE);
+ printf("%s\n", buf);
}
static uint32_t dump_fmp_payload_header(
@@ -861,6 +836,129 @@ static void dump_capsule_contents(char *capsule_file)
}
}
+static struct fdt_header *load_dtb(const char *path)
+{
+ struct fdt_header *dtb;
+ ssize_t dtb_size;
+ FILE *f;
+
+ /* Open and parse DTB */
+ f = fopen(path, "r");
+ if (!f) {
+ fprintf(stderr, "Cannot open %s\n", path);
+ return NULL;
+ }
+
+ if (fseek(f, 0, SEEK_END)) {
+ fprintf(stderr, "Cannot seek to the end of %s: %s\n",
+ path, strerror(errno));
+ return NULL;
+ }
+
+ dtb_size = ftell(f);
+ if (dtb_size < 0) {
+ fprintf(stderr, "Cannot ftell %s: %s\n",
+ path, strerror(errno));
+ return NULL;
+ }
+
+ fseek(f, 0, SEEK_SET);
+
+ dtb = malloc(dtb_size);
+ if (!dtb) {
+ fprintf(stderr, "Can't allocated %ld\n", dtb_size);
+ return NULL;
+ }
+
+ if (fread(dtb, dtb_size, 1, f) != 1) {
+ fprintf(stderr, "Can't read %ld bytes from %s\n",
+ dtb_size, path);
+ free(dtb);
+ return NULL;
+ }
+
+ fclose(f);
+
+ return dtb;
+}
+
+#define MAX_IMAGE_NAME_LEN 128
+static int genguid(int argc, char **argv)
+{
+ int idx = 2, ret;
+ unsigned char namespace[16];
+ struct efi_guid image_type_id;
+ const char *dtb_path;
+ struct fdt_header *dtb;
+ const char *compatible;
+ int compatlen, namelen;
+ uint16_t fw_image[MAX_IMAGE_NAME_LEN];
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: ");
+ print_usage_guidgen();
+ return -1;
+ }
+
+ if (uuid_str_to_bin(argv[1], namespace, UUID_STR_FORMAT_GUID)) {
+ uuid_str_to_bin(DEFAULT_NAMESPACE_GUID, namespace, UUID_STR_FORMAT_GUID);
+ dtb_path = argv[1];
+ } else {
+ dtb_path = argv[2];
+ idx = 3;
+ }
+
+ if (idx == argc) {
+ fprintf(stderr, "Usage: ");
+ print_usage_guidgen();
+ return -1;
+ }
+
+ dtb = load_dtb(dtb_path);
+ if (!dtb)
+ return -1;
+
+ ret = fdt_check_header(dtb);
+ if (ret) {
+ fprintf(stderr, "Invalid DTB header: %d\n", ret);
+ return -1;
+ }
+
+ compatible = fdt_getprop(dtb, 0, "compatible", &compatlen);
+ if (!compatible) {
+ fprintf(stderr, "No compatible string found in DTB\n");
+ return -1;
+ }
+ if (strnlen(compatible, compatlen) >= compatlen) {
+ fprintf(stderr, "Compatible string not null-terminated\n");
+ return -1;
+ }
+
+ printf("Generating GUIDs for %s with namespace %s:\n",
+ compatible, DEFAULT_NAMESPACE_GUID);
+ for (; idx < argc; idx++) {
+ memset(fw_image, 0, sizeof(fw_image));
+ namelen = strlen(argv[idx]);
+ if (namelen > MAX_IMAGE_NAME_LEN) {
+ fprintf(stderr, "Image name too long: %s\n", argv[idx]);
+ return -1;
+ }
+
+ for (int i = 0; i < namelen; i++)
+ fw_image[i] = (uint16_t)argv[idx][i];
+
+ gen_v5_guid((struct uuid *)&namespace, &image_type_id,
+ compatible, strlen(compatible),
+ fw_image, namelen * sizeof(uint16_t),
+ NULL);
+
+ printf("%s: ", argv[idx]);
+ print_guid(&image_type_id);
+ }
+
+ return 0;
+}
+
/**
* main - main entry function of mkeficapsule
* @argc: Number of arguments
@@ -885,6 +983,13 @@ int main(int argc, char **argv)
int c, idx;
struct fmp_payload_header_params fmp_ph_params = { 0 };
+ /* Generate dynamic GUIDs */
+ if (argc > 1 && !strcmp(argv[1], "guidgen")) {
+ if (genguid(argc - 1, argv + 1))
+ exit(EXIT_FAILURE);
+ exit(EXIT_SUCCESS);
+ }
+
guid = NULL;
index = 0;
instance = 0;
@@ -907,11 +1012,10 @@ int main(int argc, char **argv)
"Image type already specified\n");
exit(EXIT_FAILURE);
}
- if (uuid_parse(optarg, uuid_buf)) {
+ if (uuid_str_to_bin(optarg, uuid_buf, UUID_STR_FORMAT_GUID)) {
fprintf(stderr, "Wrong guid format\n");
exit(EXIT_FAILURE);
}
- convert_uuid_to_guid(uuid_buf);
guid = (efi_guid_t *)uuid_buf;
break;
case 'i':
@@ -977,7 +1081,7 @@ int main(int argc, char **argv)
printf("mkeficapsule version %s\n", PLAIN_VERSION);
exit(EXIT_SUCCESS);
default:
- print_usage();
+ print_usage_mkeficapsule();
exit(EXIT_FAILURE);
}
}
@@ -1000,7 +1104,7 @@ int main(int argc, char **argv)
((argc != optind + 1) ||
((capsule_type == CAPSULE_ACCEPT) && !guid) ||
((capsule_type == CAPSULE_REVERT) && guid)))) {
- print_usage();
+ print_usage_mkeficapsule();
exit(EXIT_FAILURE);
}