diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/board/coreboot/coreboot.rst | 14 | ||||
-rw-r--r-- | doc/develop/binman_tests.rst | 734 | ||||
-rw-r--r-- | doc/develop/cedit.rst | 7 | ||||
-rw-r--r-- | doc/develop/expo.rst | 26 | ||||
-rw-r--r-- | doc/develop/index.rst | 1 | ||||
-rw-r--r-- | doc/usage/cmd/cedit.rst | 15 | ||||
-rw-r--r-- | doc/usage/cmd/cpuid.rst | 68 | ||||
-rw-r--r-- | doc/usage/cmd/font.rst | 6 | ||||
-rw-r--r-- | doc/usage/cmd/msr.rst | 61 | ||||
-rw-r--r-- | doc/usage/index.rst | 2 |
10 files changed, 911 insertions, 23 deletions
diff --git a/doc/board/coreboot/coreboot.rst b/doc/board/coreboot/coreboot.rst index 7154f59c374..a177265c16e 100644 --- a/doc/board/coreboot/coreboot.rst +++ b/doc/board/coreboot/coreboot.rst @@ -181,16 +181,4 @@ coreboot in CI CI runs tests using a pre-built coreboot image. This ensures that U-Boot can boot as a coreboot payload, based on a known-good build of coreboot. -To update the `coreboot.rom` file which is used: - -#. Build coreboot with `CONFIG_GENERIC_LINEAR_FRAMEBUFFER=y`. If using - `make menuconfig`, this is under - `Devices->Display->Framebuffer mode->Linear "high resolution" framebuffer`. - -#. Compress the resulting `coreboot.rom`:: - - xz -c /path/to/coreboot/build/coreboot.rom > coreboot.rom.xz - -#. Upload the file to Google drive - -#. Send a patch to change the file ID used by wget in the CI yaml files. +To update the `coreboot.rom` file which is used, see ``tools/Dockerfile`` diff --git a/doc/develop/binman_tests.rst b/doc/develop/binman_tests.rst new file mode 100644 index 00000000000..a632694a6fe --- /dev/null +++ b/doc/develop/binman_tests.rst @@ -0,0 +1,734 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +.. toctree:: + :maxdepth: 1 + +Binman Tests +============ + +.. contents:: + :depth: 2 + :local: + +There is some material on writing tests in the main Binman documentation +(see :doc:`package/index`). This short guide is separate so people don't +feel they have to read as much. + +Code and output is mostly included verbatim, which makes the doc longer, but +avoids its becoming confusing when the output or referenced code changes in the +future. + +Purpose +------- + +The main purpose of tests in Binman is to make sure that Binman actually does +what it is supposed to. Various people contribute code, refactoring is done +over time, but U-Boot users (developers, SoC vendors, board vendors) rely on +Binman producing images which function correctly. Without tests, a one-line +change could unintentionally break a corner-case and the problem might not be +noticed for months. Debugging an image-generation problem with a board you +don't have can be very hard. + +A secondary purpose is productivity. U-Boot contributors are busy and often +have too much on their plate. Trying to figure out why their patch broke +some other vendor's workflow can be very time-consuming and frustrating. By +building in tests from the start, this is largely avoided. If your change has +full test coverage and doesn't break any test, all is well and no one can +complain. + +A lessor purpose is to document what Binman actually does. If a test covers a +feature, it works. If there is no test coverage, no one can say for sure +whether it works in all expected situations, certainly not wihout manual +effort. + +In fact, strictly speaking it isn't completely clear what 'works' even means in +the case where these is no test to cover the code. We are often left guessing +as to what the documentation means, what was actually intended, etc. + +Finally, code-coverage helps to remove 'zombie code', copied from elsewhere +because it looks reasonable, but not actually needed. The same situation arises +in silicon-chip design, where a part of the chip is not validated. If it isn't +validated, it can be assumed not to work, either now or later, so it is best to +remove that logic to avoid it causing problems. + +Setting up +---------- + +Binman tests use various utility programs. Most of these are documented in +:doc:`../build/gcc`. But some are SoC-specific. To fetch these, tell Binman to +fetch or build any missing tools: + +.. code-block:: bash + + $ binman tool -f missing + +When this completes successfully, you can list the tools. You should see +something like this: + +.. code-block:: bash + + $ binman tool -l + Name Version Description Path + --------------- ----------- ------------------------- ------------------------------ + bootgen ****** Bootg Xilinx Bootgen /home/sglass/.binman-tools/bootgen + bzip2 1.0.8 bzip2 compression /usr/bin/bzip2 + cbfstool unknown Manipulate CBFS files /home/sglass/bin/cbfstool + fdt_add_pubkey unknown Generate image for U-Boot /home/sglass/bin/fdt_add_pubkey + fdtgrep unknown Grep devicetree files /home/sglass/bin/fdtgrep + fiptool v2.11.0(rele Manipulate ATF FIP files /home/sglass/.binman-tools/fiptool + futility v0.0.1-9f2e9 Chromium OS firmware utili /home/sglass/.binman-tools/futility + gzip 1.12 gzip compression /usr/bin/gzip + ifwitool unknown Manipulate Intel IFWI file /home/sglass/.binman-tools/ifwitool + lz4 v1.9.4 lz4 compression /usr/bin/lz4 + lzma_alone 9.22 beta lzma_alone compression /usr/bin/lzma_alone + lzop v1.04 lzo compression /usr/bin/lzop + mkeficapsule 2024.10-rc5- mkeficapsule tool for gene /home/sglass/bin/mkeficapsule + mkimage 2024.10-rc5- Generate image for U-Boot /home/sglass/bin/mkimage + openssl 3.0.13 30 Ja openssl cryptography toolk /usr/bin/openssl + xz 5.4.5 xz compression /usr/bin/xz + zstd v1.5.5 zstd compression /usr/bin/zstd + +The tools are written to ``~/.binman-tools`` so add that to your ``PATH``. +It's fine to have some of the tools elsewhere (e.g. ``~/bin``) so long as they +are up-to-date. This allows you use the version of the tools intended for +running tests. + +Now you should be able to actually run the tests: + +.. code-block:: bash + + $ binman test + ======================== Running binman tests ======================== + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ........ + ---------------------------------------------------------------------- + Ran 568 tests in 2.578s + + OK + +If this doesn't work, see if you can have some missing tools. Check that the +dependencies are all there as above. If it is very slow, try installing +concurrencytest so that the tests run in parallel. + +The next thing to set up is code coverage, using the -T flag: + +.. code-block:: bash + + $ binman test -T + ======================== Running binman tests ======================== + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ...................................................................... + ........ + ---------------------------------------------------------------------- + Ran 568 tests in 17.367s + + OK + + 99% + Name Stmts Miss Cover + --------------------------------------------------------------------------- + tools/binman/__init__.py 0 0 100% + tools/binman/bintool.py 263 0 100% + tools/binman/btool/bootgen.py 21 0 100% + tools/binman/btool/btool_gzip.py 5 0 100% + tools/binman/btool/bzip2.py 5 0 100% + tools/binman/btool/cbfstool.py 24 0 100% + tools/binman/btool/cst.py 15 4 73% + tools/binman/btool/fdt_add_pubkey.py 21 0 100% + tools/binman/btool/fdtgrep.py 26 0 100% + tools/binman/btool/fiptool.py 19 0 100% + tools/binman/btool/futility.py 19 0 100% + tools/binman/btool/ifwitool.py 22 0 100% + tools/binman/btool/lz4.py 22 0 100% + tools/binman/btool/lzma_alone.py 34 0 100% + tools/binman/btool/lzop.py 5 0 100% + tools/binman/btool/mkeficapsule.py 27 0 100% + tools/binman/btool/mkimage.py 23 0 100% + tools/binman/btool/openssl.py 42 0 100% + tools/binman/btool/xz.py 5 0 100% + tools/binman/btool/zstd.py 5 0 100% + tools/binman/cbfs_util.py 376 0 100% + tools/binman/cmdline.py 90 0 100% + tools/binman/control.py 409 0 100% + tools/binman/elf.py 241 0 100% + tools/binman/entry.py 548 0 100% + tools/binman/etype/alternates_fdt.py 58 0 100% + tools/binman/etype/atf_bl31.py 5 0 100% + tools/binman/etype/atf_fip.py 67 0 100% + tools/binman/etype/blob.py 49 0 100% + tools/binman/etype/blob_dtb.py 46 0 100% + tools/binman/etype/blob_ext.py 9 0 100% + tools/binman/etype/blob_ext_list.py 32 0 100% + tools/binman/etype/blob_named_by_arg.py 9 0 100% + tools/binman/etype/blob_phase.py 22 0 100% + tools/binman/etype/cbfs.py 101 0 100% + tools/binman/etype/collection.py 30 0 100% + tools/binman/etype/cros_ec_rw.py 5 0 100% + tools/binman/etype/efi_capsule.py 59 0 100% + tools/binman/etype/efi_empty_capsule.py 33 0 100% + tools/binman/etype/encrypted.py 34 0 100% + tools/binman/etype/fdtmap.py 62 0 100% + tools/binman/etype/files.py 35 0 100% + tools/binman/etype/fill.py 13 0 100% + tools/binman/etype/fit.py 311 0 100% + tools/binman/etype/fmap.py 37 0 100% + tools/binman/etype/gbb.py 37 0 100% + tools/binman/etype/image_header.py 53 0 100% + tools/binman/etype/intel_cmc.py 4 0 100% + tools/binman/etype/intel_descriptor.py 39 0 100% + tools/binman/etype/intel_fit.py 12 0 100% + tools/binman/etype/intel_fit_ptr.py 17 0 100% + tools/binman/etype/intel_fsp.py 4 0 100% + tools/binman/etype/intel_fsp_m.py 4 0 100% + tools/binman/etype/intel_fsp_s.py 4 0 100% + tools/binman/etype/intel_fsp_t.py 4 0 100% + tools/binman/etype/intel_ifwi.py 67 0 100% + tools/binman/etype/intel_me.py 4 0 100% + tools/binman/etype/intel_mrc.py 6 0 100% + tools/binman/etype/intel_refcode.py 6 0 100% + tools/binman/etype/intel_vbt.py 4 0 100% + tools/binman/etype/intel_vga.py 4 0 100% + tools/binman/etype/mkimage.py 84 0 100% + tools/binman/etype/null.py 9 0 100% + tools/binman/etype/nxp_imx8mcst.py 78 59 24% + tools/binman/etype/nxp_imx8mimage.py 38 6 84% + tools/binman/etype/opensbi.py 5 0 100% + tools/binman/etype/powerpc_mpc85xx_bootpg_resetvec.py 6 0 100% + tools/binman/etype/pre_load.py 76 0 100% + tools/binman/etype/rockchip_tpl.py 5 0 100% + tools/binman/etype/scp.py 5 0 100% + tools/binman/etype/section.py 418 0 100% + tools/binman/etype/tee_os.py 31 0 100% + tools/binman/etype/text.py 21 0 100% + tools/binman/etype/ti_board_config.py 139 0 100% + tools/binman/etype/ti_dm.py 5 0 100% + tools/binman/etype/ti_secure.py 65 0 100% + tools/binman/etype/ti_secure_rom.py 117 0 100% + tools/binman/etype/u_boot.py 7 0 100% + tools/binman/etype/u_boot_dtb.py 9 0 100% + tools/binman/etype/u_boot_dtb_with_ucode.py 51 0 100% + tools/binman/etype/u_boot_elf.py 19 0 100% + tools/binman/etype/u_boot_env.py 27 0 100% + tools/binman/etype/u_boot_expanded.py 4 0 100% + tools/binman/etype/u_boot_img.py 7 0 100% + tools/binman/etype/u_boot_nodtb.py 7 0 100% + tools/binman/etype/u_boot_spl.py 8 0 100% + tools/binman/etype/u_boot_spl_bss_pad.py 14 0 100% + tools/binman/etype/u_boot_spl_dtb.py 9 0 100% + tools/binman/etype/u_boot_spl_elf.py 8 0 100% + tools/binman/etype/u_boot_spl_expanded.py 12 0 100% + tools/binman/etype/u_boot_spl_nodtb.py 8 0 100% + tools/binman/etype/u_boot_spl_pubkey_dtb.py 32 0 100% + tools/binman/etype/u_boot_spl_with_ucode_ptr.py 8 0 100% + tools/binman/etype/u_boot_tpl.py 8 0 100% + tools/binman/etype/u_boot_tpl_bss_pad.py 14 0 100% + tools/binman/etype/u_boot_tpl_dtb.py 9 0 100% + tools/binman/etype/u_boot_tpl_dtb_with_ucode.py 8 0 100% + tools/binman/etype/u_boot_tpl_elf.py 8 0 100% + tools/binman/etype/u_boot_tpl_expanded.py 12 0 100% + tools/binman/etype/u_boot_tpl_nodtb.py 8 0 100% + tools/binman/etype/u_boot_tpl_with_ucode_ptr.py 12 0 100% + tools/binman/etype/u_boot_ucode.py 33 0 100% + tools/binman/etype/u_boot_vpl.py 8 0 100% + tools/binman/etype/u_boot_vpl_bss_pad.py 14 0 100% + tools/binman/etype/u_boot_vpl_dtb.py 9 0 100% + tools/binman/etype/u_boot_vpl_elf.py 8 0 100% + tools/binman/etype/u_boot_vpl_expanded.py 12 0 100% + tools/binman/etype/u_boot_vpl_nodtb.py 8 0 100% + tools/binman/etype/u_boot_with_ucode_ptr.py 42 0 100% + tools/binman/etype/vblock.py 38 0 100% + tools/binman/etype/x86_reset16.py 7 0 100% + tools/binman/etype/x86_reset16_spl.py 7 0 100% + tools/binman/etype/x86_reset16_tpl.py 7 0 100% + tools/binman/etype/x86_start16.py 7 0 100% + tools/binman/etype/x86_start16_spl.py 7 0 100% + tools/binman/etype/x86_start16_tpl.py 7 0 100% + tools/binman/etype/x509_cert.py 71 0 100% + tools/binman/etype/xilinx_bootgen.py 72 0 100% + tools/binman/fip_util.py 202 0 100% + tools/binman/fmap_util.py 49 0 100% + tools/binman/image.py 181 0 100% + tools/binman/state.py 201 0 100% + --------------------------------------------------------------------------- + TOTAL 5954 69 99% + + To get a report in 'htmlcov/index.html', type: python3-coverage html + Coverage error: 99%, but should be 100% + ValueError: Test coverage failure + +Unfortunately the run failed. As it suggests, create a report: + +.. code-block:: bash + + $ python3-coverage html + Wrote HTML report to htmlcov/index.html + +If you open that file in the browser, you can see which files are not reaching +100% and click on them. Here is ``nxp_imx8mimage.py``, for example: + +.. code-block:: python + + 43 # Generate mkimage configuration file similar to imx8mimage.cfg + 44 # and pass it to mkimage to generate SPL image for us here. + 45 cfg_fname = tools.get_output_filename('nxp.imx8mimage.cfg.%s' % uniq) + 46 with open(cfg_fname, 'w') as outf: + 47 print('ROM_VERSION v%d' % self.rom_version, file=outf) + 48 print('BOOT_FROM %s' % self.boot_from, file=outf) + 49 print('LOADER %s %#x' % (input_fname, self.loader_address), file=outf) + 50 + 51 output_fname = tools.get_output_filename(f'cfg-out.{uniq}') + 52 args = ['-d', input_fname, '-n', cfg_fname, '-T', 'imx8mimage', + 53 output_fname] + 54 if self.mkimage.run_cmd(*args) is not None: + 55 return tools.read_file(output_fname) + 56 else: + 57 # Bintool is missing; just use the input data as the output + 58 x self.record_missing_bintool(self.mkimage) + 59 x return data + 60 + 61 def SetImagePos(self, image_pos): + 62 # Customized SoC specific SetImagePos which skips the mkimage etype + 63 # implementation and removes the 0x48 offset introduced there. That + 64 # offset is only used for uImage/fitImage, which is not the case in + 65 # here. + 66 upto = 0x00 + 67 for entry in super().GetEntries().values(): + 68 x entry.SetOffsetSize(upto, None) + 69 + 70 # Give up if any entries lack a size + 71 x if entry.size is None: + 72 x return + 73 x upto += entry.size + 74 + 75 Entry_section.SetImagePos(self, image_pos) + +Most of the file is covered, but the lines marked with ``x`` indicate missing +coverage. The will show up red in your browser. + +What is a test? +--------------- + +A test is a function in ``ftest.py`` which uses an image description in +``tools/binman/test`` to perform some operations and exercise the code. Some +tests are just a few lines; some are more complicated. + +Here is a simple test: + +.. code-block:: python + + def testSimple(self): + """Test a simple binman with a single file""" + data = self._DoReadFile('005_simple.dts') + self.assertEqual(U_BOOT_DATA, data) + +This test tells Binman to build an image using the description. Then it checks +that the resulting image looks correct. The image description is: + +.. code-block:: devicetree + + /dts-v1/; + + / { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + }; + }; + +As you will know from the Binman documentation, this says that there is +one image and it contains the U-Boot binary. So this test builds an image +consisting of a U-Boot binary, then checks that it does indeed have just a +U-Boot binary in it. + +Test data +--------- + +Using real binaries (like ``u-boot.bin``) to test Binman would be quite tedious. +Every output file would be large and it would be hard to tell by looking at the +output (e.g. with a hex dump) if a particular entry contains ``u-boot.bin`` or +``u-boot-spl.bin`` or something else. + +Binman gets around this by using simple placeholders. Here is the placeholder +for u-boot.bin: + +.. code-block:: python + + U_BOOT_DATA = b'1234' + +This is just bytes. So the test above checks that the output image contains +these four bytes. This makes verification fast for Binman and very easy for +humans. + +Even the devicetree is a placeholder: + +.. code-block:: python + + U_BOOT_DTB_DATA = b'udtb' + +But for some tests you need to use the real devicetree. In that case you can +use ``_DoReadFileRealDtb()``. See ``testUpdateFdtAll()`` for an example of how +to check the devicetree updated by Binman. + +Test structure +-------------- + +Each test is designed to test just one thing. Binman tests are named according +to what they are testing. Individually they don't do very much, but as a whole +they test every line of code in Binman. + +So ``testSimple()`` is designed to check that Binman can build the +simplest-possible image that isn't completely empty. + +Another type of test is one which checks error-handling, for example: + +.. code-block:: python + + def testFillNoSize(self): + """Test for an fill entry type with no size""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('070_fill_no_size.dts') + self.assertIn("'fill' entry is missing properties: size", + str(e.exception)) + +This test deliberately tries to provoke an error. The image description is: + +.. code-block:: devicetree + + // SPDX-License-Identifier: GPL-2.0+ + /dts-v1/; + + / { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <16>; + fill { + fill-byte = [ff]; + }; + }; + }; + +You can see that there is no size for the 'fill' entry, so we would expect +Binman to complain. The test checks that it actually does. It also checks the +error message produced by Binman. Sometimes you need to add several tests, each +with their own broken image description, in order to check all the error cases. + +Sometimes you need to capture the console output of Binman, to check it is +correct. You can to this with ``test_util.capture_sys_output()``, for example: + +.. code-block:: python + + with test_util.capture_sys_output() as (_, stderr): + self._DoTestFile('071_gbb.dts', force_missing_bintools='futility', + entry_args=entry_args) + err = stderr.getvalue() + self.assertRegex(err, "Image 'image'.*missing bintools.*: futility") + +The test collects the output and checks it with a regular expression. If you +need to see the test output (e.g. to debug it), you will have to remove that +capture line. + +How to add a new test +--------------------- + +This section explains the process of writing a new test. It uses an example to +help with this, but your code will be different. + +Generally you are adding a test because you are adding a new entry type +('etype'). So start by creating the shortest and simplest image-description you +can, which contains the new etype. Put it in a numbered file in +``tool/binman/test`` so that it comes last. All the numbers are unique and there +are no gaps. + +Example from ``tools/binman/test/339_nxp_imx8.dts``: + +.. code-block:: devicetree + + // 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>; + }; + }; + }; + +Note that you should use tabs in the file, not spaces. You can see that this has +been cut down to the bare minimum, just enough to include the etype and the +arguments it needs. This is of course not a real image. It will not boot on +anything. But that's fine; we are just trying to test this one etype. Try not +to add any other sections and etypes unless they are absolutely essential for +your test to work. This helps others too: they don't need to understand the full +complexity of your etype just to read your test. + +Then create your test by adding a new function at the end of ``ftest.py``: + +.. code-block:: python + + def testNxpImx8Image(self): + """Test that binman can produce an iMX8 image""" + self._DoTestFile('339_nxp_imx8.dts') + +This uses the test file that you created. It doesn't check anything, it just +runs the image description through binman. + +Let's run it: + +.. code-block:: bash + + $ binman test testNxpImx8Image + ======================== Running binman tests ======================== + . + ---------------------------------------------------------------------- + Ran 1 test in 0.242s + + OK + +So the test passes. It doesn't really do a lot, but it does exercise the etype. +The next step is to update it to actually check the output: + +.. code-block:: python + + def testNxpImx8Image(self): + """Test that binman can produce an iMX8 image""" + data = self._DoReadFile('339_nxp_imx8.dts') + print('data', len(data)) + +The ``_DoReadFile()`` function is documented in the code. It returns the image +contents as the first part of a tuple. + +Running this we see: + +.. code-block:: bash + + data 2200 + +So it is producing a little over 8K of data. Your etype will be different, but +in any case you can add Python code to check that this data is actually correct, +based on your knowledge of your etype. Note that you should not be checking +whether the external tools (called 'bintools' in Binman) are actually working, +since presumably they have their own tests. You just need to check that the +image seems reasonable, e.g. is not empty, contains the expected sections, etc. + +When your etype does use a bintool, it also needs tests, but generally it will +be tested by virtue of the etype test. This is because your etype must call the +bintool to create the image. Sometimes you might need to add a test for a +bintool error-condition, though. + +Finishing code coverage +----------------------- + +The objective is to have test-coverage for every line of code that you add to +Binman. So how can you tell? First, get a coverage report as described above. +Look through the output for any files which are not at 100%. Add more test cases +(image descriptions and new functions in ``ftest.py``) until you have covered +each line. + +In the above example, here are some possible steps: + +#. The first red bit is where the ``mkimage`` call returns None. This can be + traced to ``Bintoolmkimage.mkimage()`` which calls + ``Bintool.run_cmd_result()`` and ``None`` means that ``mkimage`` is missing. + So the etype has code to handle that case, but it is never used. You can + look for other examples of ``self.mkimage`` returning ``None`` - e.g. + ``Entry_mkimage.BuildSectionData()`` does this. The clue for finding this is + that the ``nxp-imx8mimage`` etype is based on ``Entry_mkimage``: + + .. code-block:: python + + class Entry_nxp_imx8mimage(Entry_mkimage): + + It must be tested somewhere...in this case ``testMkimage()`` doesn't do it, + but ``testMkimageMissing()`` immediately below that does. So you can create a + similar test, e.g.: + + .. code-block:: python + + def testNxpImx8ImageMkimageMissing(self): + """Test that binman can produce an iMX8 image""" + with test_util.capture_sys_output() as (_, stderr): + self._DoTestFile('339_nxp_imx8.dts', + force_missing_bintools='mkimage') + err = stderr.getvalue() + self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage") + + Note that this uses exactly the same image description as the first test. + It just checks what happens when the tool is missing. Checking the coverage + again, you will see that the first red bit has gone: + + .. code-block:: bash + + $ binman test -T + $ python3-coverage html + +#. The second red bit is for ``SetImagePos()``. You can see that it is iterating + through the sub-entries inside the ``nxp-imx8mimage`` entry. In the case of + the 339 file, there are no such entries, so this code inside the for() loop + isn't used: + + .. code-block:: python + + def SetImagePos(self, image_pos): + # Customized SoC specific SetImagePos which skips the mkimage etype + # implementation and removes the 0x48 offset introduced there. That + # offset is only used for uImage/fitImage, which is not the case in + # here. + upto = 0x00 + for entry in super().GetEntries().values(): + entry.SetOffsetSize(upto, None) + + # Give up if any entries lack a size + if entry.size is None: + return + upto += entry.size + + Entry_section.SetImagePos(self, image_pos) + + The solution is to add an entry, e.g. in ``340_nxp_imx8_non_empty.dts``: + + .. code-block:: devicetree + + // 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>; + + u-boot { + }; + }; + }; + }; + + Now write a little test to use it: + + .. code-block:: python + + def testNxpImx8ImageNonEmpty(self): + """Test that binman can produce an iMX8 image with something in it""" + data = self._DoReadFile('340_nxp_imx8_non_empty.dts') + # check data here + + With that, the second red bit goes away, because the for() loop is now used. + +#. There is one more red bit left, the ``return`` in ``SetImagePos()``. The + above effort got the for() loop to be executed, but it doesn't cover the + ``return``. It might have been copied from some other etype, e.g. the mkimage + one. See ``Entry_mkimage.SetImagePos()`` which contains the code: + + .. code-block:: python + + for entry in self.GetEntries().values(): + entry.SetOffsetSize(upto, None) + + # Give up if any entries lack a size + if entry.size is None: + return + upto += entry.size + + But which test covers that code for mkimage? By figuring that out, you could + use a similar technique. One way to find out is to delete the two lines in + ``Entry_mkimage`` which check for entry.size being None and returning, then + see what breaks with ``binman test``: + + .. code-block:: bash + + ERROR: binman.ftest.TestFunctional.testMkimageCollection (subunit.RemotedTestCase) + binman.ftest.TestFunctional.testMkimageCollection + ---------------------------------------------------------------------- + testtools.testresult.real._StringException: Traceback (most recent call last): + TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType' + + ====================================================================== + ERROR: binman.ftest.TestFunctional.testMkimageImage (subunit.RemotedTestCase) + binman.ftest.TestFunctional.testMkimageImage + ---------------------------------------------------------------------- + testtools.testresult.real._StringException: Traceback (most recent call last): + TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType' + + ====================================================================== + ERROR: binman.ftest.TestFunctional.testMkimageSpecial (subunit.RemotedTestCase) + binman.ftest.TestFunctional.testMkimageSpecial + ---------------------------------------------------------------------- + testtools.testresult.real._StringException: Traceback (most recent call last): + TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType' + + We can verify that you got the right test, by putting the lines back in and + getting coverage for just that test: + + .. code-block:: bash + + binman test -T testMkimageCollection + python3-coverage html + + You will see a lot of red since we are seeing test coverage just for one + test, but if you look in ``mkimage.py`` at ``SetImagePos()`` you will see + that the ``return`` is covered (i.e. it is marked green). + + Looking at the ``.dts`` files for each of these tests, none jumps out as + being relevant to our case. It seems that this code just isn't needed, so the + best solution is to delete those two lines from the function: + + .. code-block:: python + + def SetImagePos(self, image_pos): + # Customized SoC specific SetImagePos which skips the mkimage etype + # implementation and removes the 0x48 offset introduced there. That + # offset is only used for uImage/fitImage, which is not the case in + # here. + upto = 0x00 + for entry in super().GetEntries().values(): + entry.SetOffsetSize(upto, None) + upto += entry.size + + Entry_section.SetImagePos(self, image_pos) + +We should check the updated code on a real build, to make sure it really +isn't needed, of course. + +Now, the test coverage is complete! + +If we later discover a case where those lines are needed, we can add the +lines back, along with a test for this case. + +Getting help +------------ + +If you are stuck and cannot work out how to add test coverage for your entry +type, ask on the U-Boot mailing list, cc ``Simon Glass <sjg@chromium.org>`` or +on irc ``sjg1`` diff --git a/doc/develop/cedit.rst b/doc/develop/cedit.rst index 82305b921f0..310be889240 100644 --- a/doc/develop/cedit.rst +++ b/doc/develop/cedit.rst @@ -94,7 +94,7 @@ them. Expo supports doing this with an enum, where every ID is listed in the enum:: enum { - ZERO, + ID_PROMPT = EXPOID_BASE_ID, ID_PROMPT, @@ -130,6 +130,11 @@ that means that something is wrong with your syntax, or perhaps you have an ID in the `.dts` file that is not mentioned in your enum. Check both files and try again. +Note that the first ID in your file must be no less that `EXPOID_BASE_ID` since +IDs before that are reserved. The `expo.py` tool automatically obtains this +value from the `expo.h` header file, but you must set the first ID to this +enum value. + Use the command interface ------------------------- diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst index c87b6ec8128..cc7c36173db 100644 --- a/doc/develop/expo.rst +++ b/doc/develop/expo.rst @@ -88,8 +88,13 @@ or even the IDs of objects. Programmatic creation of many items in a loop can be handled by allocating space in the enum for a maximum number of items, then adding the loop count to the enum values to obtain unique IDs. -Where dynamic IDs are need, use expo_set_dynamic_start() to set the start value, -so that they are allocated above the starting (enum) IDs. +Some standard IDs are reserved for certain purposes. These are defined by +`enum expo_id_t` and start at 1. `EXPOID_BASE_ID` defines the first ID which +can be used for an expo. + +An ID of 0 is invalid. If this is specified in an expo call then a valid +'dynamic IDs is allocated. Use expo_set_dynamic_start() to set the start +value, so that they are allocated above the starting (enum) IDs. All text strings are stored in a structure attached to the expo, referenced by a text ID. This makes it easier at some point to implement multiple languages or @@ -176,6 +181,10 @@ menu-inset menuitem-gap-y Number of pixels between menu items +menu-title-margin-x + Number of pixels between right side of menu title to the left size of the + menu labels + Pop-up mode ----------- @@ -352,6 +361,13 @@ item-id Specifies the ID for each menu item. These are used for checking which item has been selected. +item-value + type: u32 list, optional + + Specifies the value for each menu item. These are used for saving and + loading. If this is omitted the value is its position in the menu (0..n-1). + Valid values are positive and negative integers INT_MIN...(INT_MAX - 1). + item-label / item-label-id type: string list / u32 list, required @@ -413,8 +429,7 @@ strings are provided inline in the nodes where they are used. /* this comment is parsed by the expo.py tool to insert the values below enum { - ZERO, - ID_PROMPT, + ID_PROMPT = EXPOID_BASE_ID, ID_SCENE1, ID_SCENE1_TITLE, @@ -466,6 +481,9 @@ strings are provided inline in the nodes where they are used. /* IDs for the menu items */ item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2 ID_CPU_SPEED_3>; + + /* values for the menu items */ + item-value = <(-1) 3 6>; }; power-loss { diff --git a/doc/develop/index.rst b/doc/develop/index.rst index c23192c2770..30f7fdb8847 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -83,6 +83,7 @@ Testing py_testing tests_writing tests_sandbox + binman_tests Refactoring ----------- diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index 5670805a00e..f29f1b3f388 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -107,8 +107,10 @@ That results in:: / { cedit-values { cpu-speed = <0x00000006>; + cpu-speed-value = <0x00000003>; cpu-speed-str = "2 GHz"; power-loss = <0x0000000a>; + power-loss-value = <0x00000000>; power-loss-str = "Always Off"; }; } @@ -118,16 +120,23 @@ That results in:: This shows settings being stored in the environment:: => cedit write_env -v - c.cpu-speed=7 + c.cpu-speed=11 c.cpu-speed-str=2.5 GHz - c.power-loss=12 - c.power-loss-str=Memory + c.cpu-speed-value=3 + c.power-loss=14 + c.power-loss-str=Always Off + c.power-loss-value=0 + c.machine-name=my-machine + c.cpu-speed=11 + c.power-loss=14 + c.machine-name=my-machine => print ... c.cpu-speed=6 c.cpu-speed-str=2 GHz c.power-loss=10 c.power-loss-str=Always Off + c.machine-name=my-machine ... => cedit read_env -v diff --git a/doc/usage/cmd/cpuid.rst b/doc/usage/cmd/cpuid.rst new file mode 100644 index 00000000000..cccf9262ed4 --- /dev/null +++ b/doc/usage/cmd/cpuid.rst @@ -0,0 +1,68 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +.. index:: + single: cpuid (command) + +cpuid command +============= + +Synopsis +-------- + +:: + + cpuid <op> + +Description +----------- + +The cpuid command requests CPU-identification information on x86 CPUs. The +operation <op> selects what information is returned. Up to four 32-bit registers +can be update (eax-edx) depending on the operation. + +Configuration +------------- + +The cpuid command is only available on x86. + +Return value +------------ + +The return value $? is 0 (true). + +Example +------- + +:: + + => cpuid 1 + eax 00060fb1 + ebx 00040800 + ecx 80002001 + edx 178bfbfd + +This shows checking for 64-bit 'long' mode:: + + => cpuid 80000000 + eax 8000000a + ebx 68747541 + ecx 444d4163 + edx 69746e65 + => cpuid 80000001 + eax 00060fb1 + ebx 00000000 + ecx 00000007 + edx 2193fbfd # Bit 29 is set in edx, so long mode is available + +On a 32-bit-only CPU:: + + => cpuid 80000000 + eax 80000004 + ebx 756e6547 + ecx 6c65746e + edx 49656e69 + => cpuid 80000001 + eax 00000663 + ebx 00000000 + ecx 00000000 + edx 00000000 # Bit 29 is not set in edx, so long mode is not available diff --git a/doc/usage/cmd/font.rst b/doc/usage/cmd/font.rst index a8782546333..44a04f5d075 100644 --- a/doc/usage/cmd/font.rst +++ b/doc/usage/cmd/font.rst @@ -13,7 +13,7 @@ Synopsis font list font select <name> [<size>] - font size <size> + font size [<size>] Description ----------- @@ -34,7 +34,7 @@ This selects a new font and optionally changes the size. font size ~~~~~~~~~ -This changes the font size only. +This changes the font size only. With no argument it shows the current size. Examples -------- @@ -44,6 +44,8 @@ Examples => font list nimbus_sans_l_regular cantoraone_regular + => font size + 30 => font size 40 => font select cantoraone_regular 20 => diff --git a/doc/usage/cmd/msr.rst b/doc/usage/cmd/msr.rst new file mode 100644 index 00000000000..04ee52cc1c7 --- /dev/null +++ b/doc/usage/cmd/msr.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +.. index:: + single: msr (command) + +msr command +=========== + +Synopsis +-------- + +:: + + msr read <op> + msr write <op> <hi> <lo> + +Description +----------- + +The msr command reads and writes machine-status registers (MSRs) on x86 CPUs. +The information is a 64-bit value split into two parts, <hi> for the top 32 +bits and <lo> for the bottom 32 bits. + +The operation <op> selects what information is read or written. + +msr read +~~~~~~~~ + +This reads an MSR and displays the value obtained. + +msr write +~~~~~~~~~ + +This writes a value to an MSR. + +Configuration +------------- + +The msr command is only available on x86. + +Return value +------------ + +The return value $? is 0 (true). + +Example +------- + +This shows reading msr 0x194 which is MSR_FLEX_RATIO on Intel CPUs:: + + => msr read 194 + 00000000 00011200 # Bits 16 (flex ratio enable) and 20 (lock) are set + +This shows adjusting the energy-performance bias on an Intel CPU:: + + => msr read 1b0 + 00000000 00000006 # 6 means 'normal' + + => msr write 1b0 0 f # change to power-save + => msr read 1b0 + 00000000 0000000f diff --git a/doc/usage/index.rst b/doc/usage/index.rst index fcce125a611..b84d8ee909f 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -52,6 +52,7 @@ Shell commands cmd/conitrace cmd/cp cmd/cpu + cmd/cpuid cmd/cyclic cmd/dm cmd/ebtupdate @@ -86,6 +87,7 @@ Shell commands cmd/mbr cmd/md cmd/mmc + cmd/msr cmd/mtest cmd/mtrr cmd/panic |