All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: U-Boot Mailing List <u-boot@lists.denx.de>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>,
	Heinrich Schuchardt <xypron.glpk@gmx.de>,
	Bin Meng <bmeng.cn@gmail.com>, Tom Rini <trini@konsulko.com>,
	Christian Melki <christian.melki@t2data.com>,
	Simon Glass <sjg@chromium.org>
Subject: [PATCH 20/35] binman: Support updating the dtb in an ELF file
Date: Wed,  8 Sep 2021 07:33:50 -0600	[thread overview]
Message-ID: <20210908073355.20.I2b1675c2579620723b75726bc184469aed0e0f44@changeid> (raw)
In-Reply-To: <20210908133405.696481-1-sjg@chromium.org>

WIth EFI we must embed the devicetree in an ELF image so that it is loaded
as part of the executable file. We want it to include the binman
definition in there also, which in some cases cannot be created until the
ELF (u-boot) is built. Add an option to binman to support writing the
updated dtb to the ELF file u-boot.out

This is useful with the EFI app, which is always packaged as an ELF file.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 tools/binman/binman.rst                    | 36 ++++++++++
 tools/binman/cmdline.py                    |  2 +
 tools/binman/control.py                    | 11 +++
 tools/binman/elf.py                        | 21 ++++++
 tools/binman/ftest.py                      | 83 +++++++++++++++++++++-
 tools/binman/test/Makefile                 | 10 ++-
 tools/binman/test/u_boot_binman_embed.c    | 13 ++++
 tools/binman/test/u_boot_binman_embed.lds  | 29 ++++++++
 tools/binman/test/u_boot_binman_embed_sm.c | 13 ++++
 9 files changed, 216 insertions(+), 2 deletions(-)
 create mode 100644 tools/binman/test/u_boot_binman_embed.c
 create mode 100644 tools/binman/test/u_boot_binman_embed.lds
 create mode 100644 tools/binman/test/u_boot_binman_embed_sm.c

diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 09e7b571982..e2c7083722d 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -822,6 +822,42 @@ the 'warning' line in scripts/Makefile.lib to see what it has found::
    # u_boot_dtsi_options_debug = $(u_boot_dtsi_options_raw)
 
 
+Updating an ELF file
+====================
+
+For the EFI app, where U-Boot is loaded from UEFI and runs as an app, there is
+no way to update the devicetree after U-Boot is built. Normally this works by
+creating a new u-boot.dtb.out with he updated devicetree, which is automatically
+built into the output image. With ELF this is not possible since the ELF is
+not part of an image, just a stand-along file. We must create an updated ELF
+file with the new devicetree.
+
+This is handled by the --update-fdt-in-elf option. It takes four arguments,
+separated by comma:
+
+   infile     - filename of input ELF file, e.g. 'u-boot's
+   outfile    - filename of output ELF file, e.g. 'u-boot.out'
+   begin_sym - symbol at the start of the embedded devicetree, e.g.
+   '__dtb_dt_begin'
+   end_sym   - symbol at the start of the embedded devicetree, e.g.
+   '__dtb_dt_end'
+
+When this flag is used, U-Boot does all the normal packaging, but as an
+additional step, it creates a new ELF file with the new devicetree embedded in
+it.
+
+If logging is enabled you will see a message like this::
+
+   Updating file 'u-boot' with data length 0x400a (16394) between symbols
+   '__dtb_dt_begin' and '__dtb_dt_end'
+
+There must be enough space for the updated devicetree. If not, an error like
+the following is produced::
+
+   ValueError: Not enough space in 'u-boot' for data length 0x400a (16394);
+   size is 0x1744 (5956)
+
+
 Entry Documentation
 ===================
 
diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py
index d6156df408b..23729f16dcc 100644
--- a/tools/binman/cmdline.py
+++ b/tools/binman/cmdline.py
@@ -71,6 +71,8 @@ controlled by a description in the board device tree.'''
              'given')
     build_parser.add_argument('-u', '--update-fdt', action='store_true',
         default=False, help='Update the binman node with offset/size info')
+    build_parser.add_argument('--update-fdt-in-elf', type=str,
+        help='Update an ELF file with the output dtb: infile,outfile,begin_sym,end_sym')
 
     entry_parser = subparsers.add_parser('entry-docs',
         help='Write out entry documentation (see entries.rst)')
diff --git a/tools/binman/control.py b/tools/binman/control.py
index dcba02ff7f8..e73bc55252c 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -598,6 +598,13 @@ def Binman(args):
             tools.FinaliseOutputDir()
         return 0
 
+    elf_params = None
+    if args.update_fdt_in_elf:
+        elf_params = args.update_fdt_in_elf.split(',')
+        if len(elf_params) != 4:
+            raise ValueError('Invalid args %s to --update-fdt-in-elf: expected infile,outfile,begin_sym,end_sym' %
+                             elf_params)
+
     # Try to figure out which device tree contains our image description
     if args.dt:
         dtb_fname = args.dt
@@ -644,6 +651,10 @@ def Binman(args):
             for dtb_item in state.GetAllFdts():
                 tools.WriteFile(dtb_item._fname, dtb_item.GetContents())
 
+            if elf_params:
+                data = state.GetFdtForEtype('u-boot-dtb').GetContents()
+                elf.UpdateFile(*elf_params, data)
+
             if missing:
                 tout.Warning("\nSome images are invalid")
 
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index 4aca4f847ce..de2bb4651fa 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -348,3 +348,24 @@ def DecodeElf(data, location):
                 segment.data()[offset:])
     return ElfInfo(output, data_start, elf.header['e_entry'] + virt_to_phys,
                    mem_end - data_start)
+
+def UpdateFile(infile, outfile, start_sym, end_sym, insert):
+    tout.Notice("Creating file '%s' with data length %#x (%d) between symbols '%s' and '%s'" %
+                (outfile, len(insert), len(insert), start_sym, end_sym))
+    syms = GetSymbolFileOffset(infile, [start_sym, end_sym])
+    if len(syms) != 2:
+        raise ValueError("Expected two symbols '%s' and '%s': got %d: %s" %
+                         (start_sym, end_sym, len(syms),
+                          ','.join(syms.keys())))
+
+    size = syms[end_sym].offset - syms[start_sym].offset
+    if len(insert) > size:
+        raise ValueError("Not enough space in '%s' for data length %#x (%d); size is %#x (%d)" %
+                         (infile, len(insert), len(insert), size, size))
+
+    data = tools.ReadFile(infile)
+    newdata = data[:syms[start_sym].offset]
+    newdata += insert + tools.GetBytes(0, size - len(insert))
+    newdata += data[syms[end_sym].offset:]
+    tools.WriteFile(outfile, newdata)
+    tout.Info('Written to offset %#x' % syms[start_sym].offset)
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 39a4b94cd0b..6be003786e8 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -309,7 +309,7 @@ class TestFunctional(unittest.TestCase):
                     entry_args=None, images=None, use_real_dtb=False,
                     use_expanded=False, verbosity=None, allow_missing=False,
                     extra_indirs=None, threads=None,
-                    test_section_timeout=False):
+                    test_section_timeout=False, update_fdt_in_elf=None):
         """Run binman with a given test file
 
         Args:
@@ -336,6 +336,7 @@ class TestFunctional(unittest.TestCase):
                 single-threaded)
             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
 
         Returns:
             int return code, 0 on success
@@ -368,6 +369,8 @@ class TestFunctional(unittest.TestCase):
                 args.append('-a%s=%s' % (arg, value))
         if allow_missing:
             args.append('-M')
+        if update_fdt_in_elf:
+            args += ['--update-fdt-in-elf', update_fdt_in_elf]
         if images:
             for image in images:
                 args += ['-i', image]
@@ -4580,6 +4583,84 @@ class TestFunctional(unittest.TestCase):
         self.assertIn('read:', stdout.getvalue())
         self.assertIn('compress:', stdout.getvalue())
 
+    def testUpdateFdtInElf(self):
+        """Test that we can update the devicetree in an ELF file"""
+        infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
+        outfile = os.path.join(self._indir, 'u-boot.out')
+        begin_sym = 'dtb_embed_begin'
+        end_sym = 'dtb_embed_end'
+        retcode = self._DoTestFile(
+            '060_fdt_update.dts', update_dtb=True,
+            update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
+        self.assertEqual(0, retcode)
+
+        # Check that the output file does in fact contact a dtb with the binman
+        # definition in the correct place
+        syms = elf.GetSymbolFileOffset(infile,
+                                       ['dtb_embed_begin', 'dtb_embed_end'])
+        data = tools.ReadFile(outfile)
+        dtb_data = data[syms['dtb_embed_begin'].offset:
+                        syms['dtb_embed_end'].offset]
+
+        dtb = fdt.Fdt.FromData(dtb_data)
+        dtb.Scan()
+        props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
+        self.assertEqual({
+            'image-pos': 0,
+            'offset': 0,
+            '_testing:offset': 32,
+            '_testing:size': 2,
+            '_testing:image-pos': 32,
+            'section@0/u-boot:offset': 0,
+            'section@0/u-boot:size': len(U_BOOT_DATA),
+            'section@0/u-boot:image-pos': 0,
+            'section@0:offset': 0,
+            'section@0:size': 16,
+            'section@0:image-pos': 0,
+
+            'section@1/u-boot:offset': 0,
+            'section@1/u-boot:size': len(U_BOOT_DATA),
+            'section@1/u-boot:image-pos': 16,
+            'section@1:offset': 16,
+            'section@1:size': 16,
+            'section@1:image-pos': 16,
+            'size': 40
+        }, props)
+
+    def testUpdateFdtInElfInvalid(self):
+        """Test that invalid args are detected with --update-fdt-in-elf"""
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
+        self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
+                      str(e.exception))
+
+    def testUpdateFdtInElfNoSyms(self):
+        """Test that missing symbols are detected with --update-fdt-in-elf"""
+        infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
+        outfile = ''
+        begin_sym = 'wrong_begin'
+        end_sym = 'wrong_end'
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile(
+                '060_fdt_update.dts',
+                update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
+        self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
+                      str(e.exception))
+
+    def testUpdateFdtInElfTooSmall(self):
+        """Test that an over-large dtb is detected with --update-fdt-in-elf"""
+        infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
+        outfile = os.path.join(self._indir, 'u-boot.out')
+        begin_sym = 'dtb_embed_begin'
+        end_sym = 'dtb_embed_end'
+        with self.assertRaises(ValueError) as e:
+            self._DoTestFile(
+                '060_fdt_update.dts', update_dtb=True,
+                update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
+        self.assertRegex(
+            str(e.exception),
+            "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile
index 6e6cc6de491..387ba163353 100644
--- a/tools/binman/test/Makefile
+++ b/tools/binman/test/Makefile
@@ -28,10 +28,12 @@ LDS_UCODE := -T $(SRC)u_boot_ucode_ptr.lds
 LDS_BINMAN := -T $(SRC)u_boot_binman_syms.lds
 LDS_BINMAN_BAD := -T $(SRC)u_boot_binman_syms_bad.lds
 LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds
+LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
 
 TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \
 	u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \
-	u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data
+	u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \
+	u_boot_binman_embed u_boot_binman_embed_sm
 
 all: $(TARGETS)
 
@@ -62,6 +64,12 @@ u_boot_binman_syms_bad: u_boot_binman_syms_bad.c
 u_boot_binman_syms_size: CFLAGS += $(LDS_BINMAN)
 u_boot_binman_syms_size: u_boot_binman_syms_size.c
 
+u_boot_binman_embed: CFLAGS += $(LDS_BINMAN_EMBED)
+u_boot_binman_embed: u_boot_binman_embed.c
+
+u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED)
+u_boot_binman_embed_sm: u_boot_binman_embed_sm.c
+
 clean:
 	rm -f $(TARGETS)
 
diff --git a/tools/binman/test/u_boot_binman_embed.c b/tools/binman/test/u_boot_binman_embed.c
new file mode 100644
index 00000000000..75874bb6e23
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_embed.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Simple program to embed a devicetree. This is used by binman tests.
+ */
+
+int __attribute__((section(".mydtb"))) dtb_data[4096];
+
+int main(void)
+{
+	return 0;
+}
diff --git a/tools/binman/test/u_boot_binman_embed.lds b/tools/binman/test/u_boot_binman_embed.lds
new file mode 100644
index 00000000000..e213fa8a84c
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_embed.lds
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2016 Google, Inc
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0x00000000;
+	_start = .;
+
+	. = ALIGN(4);
+	.text :
+	{
+		*(.text*)
+	}
+
+	. = ALIGN(4);
+	.data : {
+		dtb_embed_begin = .;
+		KEEP(*(.mydtb));
+		dtb_embed_end = .;
+	}
+	.interp : { *(.interp*) }
+
+}
diff --git a/tools/binman/test/u_boot_binman_embed_sm.c b/tools/binman/test/u_boot_binman_embed_sm.c
new file mode 100644
index 00000000000..ae245d78a6a
--- /dev/null
+++ b/tools/binman/test/u_boot_binman_embed_sm.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Simple program to embed a devicetree. This is used by binman tests.
+ */
+
+int __attribute__((section(".mydtb"))) dtb_data[16];
+
+int main(void)
+{
+	return 0;
+}
-- 
2.33.0.153.gba50c8fa24-goog


  parent reply	other threads:[~2021-09-08 13:38 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-08 13:33 [PATCH 00/35] efi: Improvements to U-Boot running on top of UEFI Simon Glass
2021-09-08 13:33 ` [PATCH 01/35] x86: Keep symbol information in u-boot ELF file Simon Glass
2021-09-08 13:33 ` [PATCH 02/35] x86: Create a new header for EFI Simon Glass
2021-09-08 17:22   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-09  9:25       ` Heinrich Schuchardt
2021-09-09 19:57         ` Simon Glass
2021-09-08 13:33 ` [PATCH 03/35] x86: Show some EFI info with the bdinfo command Simon Glass
2021-09-08 17:29   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-09  9:29       ` Heinrich Schuchardt
2021-09-09 20:08         ` Simon Glass
2021-09-08 13:33 ` [PATCH 04/35] x86: Tidy up global_data pointer for 64-bit Simon Glass
2021-09-08 17:30   ` Heinrich Schuchardt
2021-09-08 13:33 ` [PATCH 05/35] efi: Add a script for building and testing U-Boot on UEFI Simon Glass
2021-09-08 13:33 ` [PATCH 06/35] x86: Create a 32/64-bit selection for the app Simon Glass
2021-09-08 17:35   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-08 13:33 ` [PATCH 07/35] efi: Create a 64-bit app Simon Glass
2021-09-08 17:37   ` Heinrich Schuchardt
2021-09-08 13:33 ` [PATCH 08/35] x86: Don't duplicate global_ptr in 64-bit EFI app Simon Glass
2021-09-08 13:33 ` [PATCH 09/35] efi: Add a way to obtain boot services in the app Simon Glass
2021-09-08 13:33 ` [PATCH 10/35] efi: Add video support to " Simon Glass
2021-09-08 17:40   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-08 13:33 ` [PATCH 11/35] RFC: efi: Drop code that doesn't work with driver model Simon Glass
2021-09-08 17:44   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-09  9:21       ` Heinrich Schuchardt
2021-09-09 19:57         ` Simon Glass
2021-09-09 20:14           ` Tom Rini
2021-09-09 20:15           ` Mark Kettenis
2021-09-09 20:23             ` Tom Rini
2021-09-09 21:45               ` Mark Kettenis
2021-09-09 22:06                 ` Tom Rini
2021-09-24  2:48                 ` Simon Glass
2021-09-24 10:36                   ` Mark Kettenis
2021-09-24 12:32         ` Simon Glass
2021-09-08 13:33 ` [PATCH 12/35] efi: Add EFI uclass for media Simon Glass
2021-09-08 17:50   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-08 13:33 ` [PATCH 13/35] efi: Add a media/block driver for EFI block devices Simon Glass
2021-09-08 17:59   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-09 10:35       ` Heinrich Schuchardt
2021-09-09 19:58         ` Simon Glass
2021-09-08 13:33 ` [PATCH 14/35] efi: Locate all block devices in the app Simon Glass
2021-09-08 18:14   ` Heinrich Schuchardt
2021-09-09  1:11     ` AKASHI Takahiro
2021-09-09 20:09       ` Simon Glass
2021-09-10  0:50         ` AKASHI Takahiro
2021-09-09 20:09     ` Simon Glass
2021-09-08 13:33 ` [PATCH 15/35] patman: Use a ValueError exception if tools.Run() fails Simon Glass
2021-09-08 13:33 ` [PATCH 16/35] binman: Report an error if test files fail to compile Simon Glass
2021-09-08 13:33 ` [PATCH 17/35] binman: Support reading the offset of an ELF-file symbol Simon Glass
2021-09-08 13:33 ` [PATCH 18/35] binman: Allow timeout to occur in the image or its section Simon Glass
2021-09-08 13:33 ` [PATCH 19/35] binman: Tidy up comments on _DoTestFile() Simon Glass
2021-09-08 13:33 ` Simon Glass [this message]
2021-09-08 13:33 ` [PATCH 21/35] efi: serial: Support arrow keys Simon Glass
2021-09-08 13:33 ` [PATCH 22/35] bloblist: Move to rST format Simon Glass
2021-09-08 18:18   ` Heinrich Schuchardt
2021-09-08 13:33 ` [PATCH 23/35] bloblist: Support allocating the bloblist Simon Glass
2021-09-08 13:33 ` [PATCH 24/35] x86: Allow booting a kernel from the EFI app Simon Glass
2021-09-08 18:22   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-08 13:33 ` [PATCH 25/35] x86: Don't process the kernel command line unless enabled Simon Glass
2021-09-08 13:33 ` [PATCH 26/35] x86: efi: Add room for the binman definition in the dtb Simon Glass
2021-09-08 13:33 ` [PATCH 27/35] efi: Add comments to struct efi_priv Simon Glass
2021-09-08 13:33 ` [PATCH 28/35] efi: Fix ll_boot_init() operation with the app Simon Glass
2021-09-08 13:33 ` [PATCH 29/35] efi: Add a few comments to the stub Simon Glass
2021-09-08 13:34 ` [PATCH 30/35] efi: Share struct efi_priv between the app and stub code Simon Glass
2021-09-08 13:34 ` [PATCH 31/35] efi: Move exit_boot_services into a function Simon Glass
2021-09-08 13:34 ` [PATCH 32/35] efi: Check for failure when initing the app Simon Glass
2021-09-08 13:34 ` [PATCH 33/35] efi: Mention that efi_info_get() is only used in the stub Simon Glass
2021-09-08 13:34 ` [PATCH 34/35] efi: Show when allocated pages are used Simon Glass
2021-09-08 18:25   ` Heinrich Schuchardt
2021-09-09  8:57     ` Simon Glass
2021-09-09 10:39       ` Heinrich Schuchardt
2021-09-09 19:58         ` Simon Glass
2021-09-08 13:34 ` [PATCH 35/35] efi: Allow easy selection of serial-only operation Simon Glass
2021-09-09 16:29 ` [PATCH 00/35] efi: Improvements to U-Boot running on top of UEFI Bin Meng
2021-09-09 16:34   ` Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210908073355.20.I2b1675c2579620723b75726bc184469aed0e0f44@changeid \
    --to=sjg@chromium.org \
    --cc=bmeng.cn@gmail.com \
    --cc=christian.melki@t2data.com \
    --cc=ilias.apalodimas@linaro.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=xypron.glpk@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.