Skip to content

Commit

Permalink
doc: Add documentation for U-Boot integration [v2]
Browse files Browse the repository at this point in the history
Cover the drivers, scripts, pytest and the Gitlab information.

Note: This implementation is the result of working through what is
needed in Labgrid to support U-Boot labs. I did initially file quite
a few issues[1] but there has not been a lot of traction and I got
feedback that I have overwhelmed people with too many. So I have
stopped filing issues on the things I hit along the way. I have carried
on with the implementation in the hope that this can be a better basis
for discussion.

Note that all of these patches are work-in-progress. Feedback on any or
all may change the implementation and documentation substantially.

Changes in v4:
- Support for Beagleplay, which needs files from two separate U-Boot
  builds
- Support for a 'recovery' button needed to boot the image
- Tidy up the internal-console support
- Fix pytest behaviour with an unpatched U-Boot (that doesn't have lab
  mode)

Changes in v3:
- Rebase on top of grpc branch
- Don't mess with terminal setting unless stdin is a terminal
- Don't show an error if there are no resources when auto-acquiring
- Support QEMU in UBootWriter

Some changes in v2:
- Rationalise the flags for the U-Boot scripts
- Support tracing with em100
- Support an internal terminal instead of microcom
- Add a -D flag for debugging
- Support send-only boards
- Add a way to build the U-Boot config
- Add a control for buildman's process-limit
- allow the build-dir to be specified in a variable
- add documentation about U-Boot-pytest integration
- add source_dir and config_file to UBootProviderDriver
- add an internal terminal
- expand the U-Boot scripts
- significantly improve the U-Boot-pytest integration

The approximate diffstat is:
 contrib/sync-places.py                |  23 +-
 contrib/u-boot/.gitignore             |   1 +
 contrib/u-boot/_ub-bisect-try         |  47 ++
 contrib/u-boot/conftest.py            |  21 +
 contrib/u-boot/get_args.sh            | 128 +++++
 contrib/u-boot/index.rst              | 232 +++++++++
 contrib/u-boot/lg-client              |  11 +
 contrib/u-boot/lg-env                 |  10 +
 contrib/u-boot/test_smoke.py          |   3 +
 contrib/u-boot/ub-bisect              |  44 ++
 contrib/u-boot/ub-cli                 |  39 ++
 contrib/u-boot/ub-int                 |  41 ++
 contrib/u-boot/ub-pyt                 |  69 +++
 contrib/u-boot/ub-smoke               |  48 ++
 doc/configuration.rst                 | 611 ++++++++++++++++++++++-
 doc/usage.rst                         | 288 +++++++++++
 labgrid/driver/__init__.py            |  10 +-
 labgrid/driver/common.py              |  11 +
 labgrid/driver/consoleexpectmixin.py  |   7 +
 labgrid/driver/powerdriver.py         |  29 ++
 labgrid/driver/qemudriver.py          |  84 ++--
 labgrid/driver/recoverydriver.py      |  25 +
 labgrid/driver/resetdriver.py         |   7 +
 labgrid/driver/servodriver.py         | 157 ++++++
 labgrid/driver/sfemulatordriver.py    | 102 ++++
 labgrid/driver/ubootdriver.py         |  27 +-
 labgrid/driver/ubootproviderdriver.py | 323 ++++++++++++
 labgrid/driver/ubootwriterdriver.py   | 160 ++++++
 labgrid/driver/usbhidrelay.py         |   7 +-
 labgrid/driver/usbloader.py           | 170 ++++++-
 labgrid/driver/usbstoragedriver.py    |  18 +-
 labgrid/factory.py                    |   4 +-
 labgrid/protocol/__init__.py          |   1 +
 labgrid/protocol/bootstrapprotocol.py |   8 +-
 labgrid/protocol/recoveryprotocol.py  |  14 +
 labgrid/protocol/resetprotocol.py     |  12 +
 labgrid/pytestplugin/fixtures.py      |  21 +-
 labgrid/pytestplugin/hooks.py         |   8 +
 labgrid/remote/client.py              | 351 ++++++++-----
 labgrid/remote/config.py              |   7 +-
 labgrid/remote/exporter.py            | 122 ++++-
 labgrid/resource/__init__.py          |   6 +
 labgrid/resource/remote.py            |  24 +
 labgrid/resource/servo.py             | 485 ++++++++++++++++++
 labgrid/resource/sfemulator.py        |  33 ++
 labgrid/resource/suggest.py           |   6 +
 labgrid/resource/udev.py              |  33 ++
 labgrid/strategy/ubootstrategy.py     | 151 +++++-
 labgrid/target.py                     | 120 ++++-
 labgrid/util/helper.py                | 220 ++++----
 labgrid/util/ssh.py                   |   3 +-
 labgrid/util/term.py                  | 184 +++++++
 labgrid/var_dict.py                   |   8 +
 man/labgrid-client.1                  |   6 +
 man/labgrid-client.rst                |   4 +
 man/labgrid-device-config.5           |   4 +
 56 files changed, 4267 insertions(+), 321 deletions(-)

[1] https://github.com/labgrid-project/labgrid/issues/created_by/sjg20

Signed-off-by: Simon Glass <[email protected]>
  • Loading branch information
sjg20 committed Jul 29, 2024
1 parent 841f14d commit 743e46d
Show file tree
Hide file tree
Showing 2 changed files with 288 additions and 0 deletions.
11 changes: 11 additions & 0 deletions doc/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,8 @@ Arguments:
- login_timeout (int, default=60): timeout for password/login prompt detection
- for other arguments, see `UBootDriver`_

.. _UBootProviderInfo:

UBootProviderDriver
~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -2064,6 +2066,11 @@ Variables:
specified in the environment file
- do-clean (str): If set to "1" this cleans the build before starting,
otherwise it does an incremental build
- build-dir (str): If set, this is used as the build directory for U-Boot
- process-limit (int): Limits the number of buildman processes which can
be running jobs at once. Set this to 1 to avoid over-taxing your
CPU. Buildman does its own multithreading, so each process will use
all available CPUs anyway.

Environment variables:
- U_BOOT_BUILD_DIR (str): If present, this is used as the build directory for
Expand Down Expand Up @@ -2115,6 +2122,8 @@ Tools:
tools:
buildman: "buildman.stable"
.. _UBootWriterInfo:

UBootWriterDriver
~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -3875,6 +3884,8 @@ the "shell" state:
This command would transition directly into a Linux shell and
activate the `ShellDriver`_.

.. _UBootStrategyInfo:

UBootStrategy
~~~~~~~~~~~~~
A :any:`UBootStrategy` has five states:
Expand Down
277 changes: 277 additions & 0 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -883,3 +883,280 @@ like this:
$ labgrid-client -p example allow sirius/john
To remove the allow it is currently necessary to unlock and lock the place.

U-Boot Integration
------------------

.. note::
See status_ for current status and development branches.

Most ARM boards (and some others) use U-Boot as their bootloader. Labgrid
provides various features to help with development and testing on these boards.
Together these features allow interactive use of Labgrid to build U-Boot from
source, write it to a board and boot it. Support is provided for U-Boot's pytest
and Gitlab setup.

This section describes the various features which contribute to the overall
functionality. The names of contributed scripts (in *contrib/u-boot*) are shown
in brackets.

Interactive use
~~~~~~~~~~~~~~~

Labgrid provides a 'console' command which can be used to connect to a board.
The :ref:`UBootStrategyInfo` driver provides a way to power cycle (or reset)
the board so that U-Boot starts. It also provides two useful states:

- `start` which starts up U-Boot and lets it boot (*ub-int*)
- `uboot` which starts up U-Boot and stops it at the CLI prompt (*ub-cli*)

Both of these are useful in development.

Building U-Boot
~~~~~~~~~~~~~~~

Labgrid intentionally
`doesn't include <https://github.com/labgrid-project/labgrid/issues/1068>`_
build functionality as usually the software-under-test already comes with a
build system and it wants to test the artifacts as built by the "real" build
system.

U-Boot is no exception and it provides the
`buildman <https://docs.u-boot.org/en/latest/build/buildman.html>`_ for this
purpose.

Still, for interactive use some sort of build is needed. The
:ref:`UBootProviderInfo` provides an interface to buildman and a way of dealing
with board-specific binary blobs. The buildman tool works automatically provided
that you have set it up with suitable toolchains. See
`buildman <https://docs.u-boot.org/en/latest/build/buildman.html>`_ for more
information.

Writing U-Boot
~~~~~~~~~~~~~~

Writing U-Boot to a board can be complicated, because each SoC uses its own
means of booting. The other problem is that special lab hardware is generally
needed to update the boot device, e.g.
`SD-wire <https://wiki.tizen.org/SD_MUX>`_.

Fortunately Labgrid provides the means for manipulating the lab hardware. All
that is needed is a driver which understands where to write images, which files
to use and the sequence to use in each case. The :ref:`UBootWriterInfo` driver
handles this. It picks out the necessary files from a build directory and writes
them to the selected boot media, or sends them using the SoC-specific bootrom.
Combined with :ref:`UBootStrategyInfo` it provides automated updating of U-Boot
on suported SoCs regardless of the lab setup.

Run labgrid tests
~~~~~~~~~~~~~~~~~

Labgrid provides integration with pytest. As part of the U-Boot integration, a
conftest.py file is provided which can build and smoke-test U-Boot on a board
(*ub-smoke*).

Run U-Boot tests
~~~~~~~~~~~~~~~~~

It is also possible to run the U-Boot tests (*ub-pyt*). To do this you will need
to set up Labgrid integration with the
`U-Boot test hooks <https://source.denx.de/u-boot/u-boot-test-hooks>`_.
To do this, create the directory `u-boot-test-hooks/bin/$hostname` and add an
executable file called `common.labgrid` which sets the crossbar and environment
information:

.. code-block:: bash
export LG_CROSSBAR="ws://kea:20408/ws"
export LG_ENV="/path/to/env.cfg"
flash_impl=none
reset_impl=none
console_impl=labgrid
release_impl=labgrid
The last four lines tell the hooks to use labgrid.

Then create another executable file (in the same directory) called 'conf.all',
containing:

.. code-block:: bash
. "${bin_dir}/${hostname}/common-labgrid"
Bisecting
~~~~~~~~~

It is possible to use the *ub-pyt* or *ub-smoke* scripts with `git bisect run`
to bisect a problem on a particular board. However there is a slightly more
powerful script which supports applying a commit each time (*ub-bisect*).

Setting up pytest
~~~~~~~~~~~~~~~~~

To set up the U-Boot pytest integration:

#. Copy the `contrib/u-boot` directory to somewhere suitable and add it to your
path. For example:

.. code-block:: bash
cp -a contrib/u-boot ~/bin/u-boot
echo 'PATH="$PATH:~/bin/u-boot"' >> ~/.bashrc
#. Edit the `lg-env` file to set the lab parameters according to your setup.
#. Start a new terminal, or login again, so the path updates. You can now use
the scripts as documented below.

Gitlab Integration
~~~~~~~~~~~~~~~~~~

U-Boot uses `Gitlab <https://gitlab.com>`_ as the basis for its Continuous
Integration (CI) system (`U-Boot instance <https://source.denx.de/u-boot>`_).
It is possible to set up your own lab which integrates with Gitlab, with your
own Git lab 'runner' which can control Labgrid. This allows pushing branches to
Gitlab and running tests on real hardware, similarly to how QEMU is used in
Gitlab.

To set this up:

#. Install `gitlab-runner` using these
`instructions <https://docs.gitlab.com/runner/install/linux-repository.html>`_.

#. Register a
`new runner <https://docs.gitlab.com/ee/tutorials/create_register_first_runner>`_
following the instructions using your custodian CI settings (i.e. do this at
`https://source.denx.de`).

Select Linux and with tags set to `lab`. Click `Create runner` and use the
command line to register the runner. Use `<hostname>-lab` (for example
`kea-lab`) as your host name and select `shell` as the executor:

.. code-block:: console
$ gitlab-runner register --url https://source.denx.de --token glrt-xxx
Enter the GitLab instance URL (for example, https://gitlab.com/):
[https://source.denx.de]:
Verifying runner... is valid runner=yyy
Enter a name for the runner. This is stored only in the local config.toml file:
[<hostname>]: <hostname>-lab
Enter an executor: ssh, parallels, docker-windows, docker+machine, kubernetes, instance, custom, shell, virtualbox, docker, docker-autoscaler:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
#. Edit the resulting `/etc/gitlab-runner/config.toml` file to allow more than
one job at a time by adding 'concurrent = x' where x is the number of jobs.
Here we use concurrent = 8 (this is just an example; don't replace your file
with this):

.. code-block:: toml
concurrent = 8
check_interval = 0
shutdown_timeout = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "ellesmere-lab"
url = "https://source.denx.de"
id = 130
token = "..."
token_obtained_at = 2024-05-15T20:41:29Z
token_expires_at = 0001-01-01T00:00:00Z
executor = "shell"
[runners.custom_build_dir]
#. Gitlab will run tests as the 'gitlab-runner' user. Make sure your labgrid
installation is installed such that it is visible to that user. One way is:

.. code-block:: bash
sudo su - gitlab-runner
cd /path/to/labgrid
pip install .
#. Add the following to U-Boot's `.gitlab-ci.yml`, adjusting the variables as
needed. For trying it out initially you might want to disable all the other
rules by changing `when: always` to `when: never`:

.. code-block:: yaml
.lab_template: &lab_dfn
stage: lab
tags: [ 'lab' ]
script:
# Environment:
# SRC - source tree
# ROOT - directory above that
# OUT - output directory for builds
- export SRC="$(pwd)"
- ROOT="$(dirname ${SRC})"
- export OUT="${ROOT}/out"
- export PATH=$PATH:~/bin
- export PATH=$PATH:/vid/software/devel/ubtest/u-boot-test-hooks/bin
# Load it on the device
- ret=0
- echo "board ${BOARD} id ${ID}"
- ${SRC}/test/py/test.py -B "${BOARD}" --id ${ID} --configure
--build-dir "${OUT}/current/${BOARD}" -k "not bootstd"|| ret=$?
- if [[ $ret -ne 0 ]]; then
exit $ret;
fi
rpi3:
variables:
BOARD: rpi_3_32b ## This is a U-Boot board name
ID: rpi3 ## This is the corresponding role/target
<<: *lab_dfn
#. Commit your changes and push to your custodian tree. This example shows the
driver model tree at a remote called 'dm':

.. code-block:: bash
$ git remote -v |grep dm
dm [email protected]:u-boot/custodians/u-boot-dm.git (fetch)
dm [email protected]:u-boot/custodians/u-boot-dm.git (push)
$ git push dm HEAD:try
#. Navigate to the pipelines and you should see your tests running. You can
debug things from there, e.g. using the `ub-int` or `ub-pyt` scripts on an
individual board. An example may be visible
`here <https://source.denx.de/u-boot/custodians/u-boot-dm/-/pipelines/20769>`_.

Scripts
~~~~~~~

Various scripts are provided in the `contrib/` directory, specifically targeted
at U-Boot testing and development.

.. include:: ../contrib/u-boot/index.rst


.. _status:

U-Boot Integration Status
~~~~~~~~~~~~~~~~~~~~~~~~~

Date: May '24
Overall status: Ready for early testing

Required pieces:

- `Labgrid WIP PR <https://github.com/sjg20/labgrid/tree/u-boot-integration>`_
- `U-Boot test hooks branch <https://github.com/sjg20/uboot-test-hooks/tree/labgrid>`_
- `U-Boot branch <https://github.com/sjg20/u-boot/tree/labgrid>`_ (needed for
U-Boot pytest integration)

Testing has been very limited, basically a set of 21 boards, including sunxi,
rpi, RK3399, ODroid-C4, pine64, Orange Pi PC, various Chromebooks and Intel
Minnowboard Max.

Some U-Boot pytests fails on some hardware:
- TPM tests fail on boards with a TPM
- test_log_format fails on several (perhaps all?) boards

There are likely many other problems.

0 comments on commit 743e46d

Please sign in to comment.