aboutsummaryrefslogtreecommitdiffstats
path: root/.gitlab-ci/bare-metal
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2020-05-15 09:57:25 -0700
committerMarge Bot <[email protected]>2020-05-29 16:46:44 +0000
commitc89a749f66527caf72c43b433dc27de1594a87f6 (patch)
treedc277279c87a7949400e757cb0f23158f693464b /.gitlab-ci/bare-metal
parent3a1010e21ac426736fb9af289570d3fbbaaa1884 (diff)
ci: Add scripts for controlling bare-metal chezas.
This will let us: - deploy kernels for testing code depending on new kernel featuers - Ensure a pristine state in the HW before starting our tests - Avoid disk rot on the chezas taking them out (we'd lost 3/9 in a few months). Reviewed-by: Kristian H. Kristensen <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5247>
Diffstat (limited to '.gitlab-ci/bare-metal')
-rw-r--r--.gitlab-ci/bare-metal/README.md88
-rwxr-xr-x.gitlab-ci/bare-metal/cros-servo.sh97
-rwxr-xr-x.gitlab-ci/bare-metal/fastboot.sh54
-rw-r--r--.gitlab-ci/bare-metal/rootfs-setup.sh55
-rwxr-xr-x.gitlab-ci/bare-metal/write-serial.py11
5 files changed, 232 insertions, 73 deletions
diff --git a/.gitlab-ci/bare-metal/README.md b/.gitlab-ci/bare-metal/README.md
index 3bbfab11cfb..843d168c455 100644
--- a/.gitlab-ci/bare-metal/README.md
+++ b/.gitlab-ci/bare-metal/README.md
@@ -3,40 +3,76 @@
Testing Mesa with gitlab-runner running on the devices being tested
(DUTs) proved to be too unstable, so this set of scripts is for
running Mesa testing on bare-metal boards connected to a separate
-system using gitlab-runner. Currently only "fastboot" devices are
-supported.
+system using gitlab-runner. Currently only "fastboot" and "ChromeOS
+Servo" devices are supported.
In comparison with LAVA, this doesn't involve maintaining a separate
webservice with its own job scheduler and replicating jobs between the
two. It also places more of the board support in git, instead of
-webservice configuration. Most importantly, it doesn't download the
-rootfs as artifacts on each job, so we can avoid traffic to
-freedesktop.org. On the other hand, the serial interactions and
-bootloader support are more primitive.
+webservice configuration. On the other hand, the serial interactions
+and bootloader support are more primitive.
-## Requirements
+## Requirements (fastboot)
This testing requires power control of the DUTs by the gitlab-runner
machine, since this is what we use to reset the system and get back to
a pristine state at the start of testing.
-We require access to the console output from the gitlb-runner system,
-since that is how we get the final results back from te tests. You
+We require access to the console output from the gitlab-runner system,
+since that is how we get the final results back from the tests. You
should probably have the console on a serial connection, so that you
can see bootloader progress.
The boards need to be able to have a kernel/initramfs supplied by the
gitlab-runner system, since the initramfs is what contains the Mesa
-testing payload. Currently only "fastboot" devices are supported.
+testing payload.
The boards should have networking, so that (in a future iteration of
this code) we can extract the dEQP .xml results to artifacts on
gitlab.
+## Requirements (servo)
+
+For servo-connected boards, we can use the EC connection for power
+control to reboot the board. However, loading a kernel is not as easy
+as fastboot, so we assume your bootloader can do TFTP, and that your
+gitlab-runner mounts the runner's tftp directory specific to the board
+at /tftp in the container.
+
+Since we're going the TFTP route, we also use NFS root. This avoids
+packing the rootfs and sending it to the board as a ramdisk, which
+means we can support larger rootfses (for piglit or tracie testing),
+at the cost of needing more storage on the runner.
+
+Telling the board about where its TFTP and NFS should come from is
+done using dnsmasq on the runner host. For example, this snippet in
+the dnsmasq.conf.d in the google farm, with the gitlab-runner host we
+call "servo".
+
+```
+dhcp-host=1c:69:7a:0d:a3:d3,10.42.0.10,set:servo
+
+# Fixed dhcp addresses for my sanity, and setting a tag for
+# specializing other DHCP options
+dhcp-host=a0:ce:c8:c8:d9:5d,10.42.0.11,set:cheza1
+dhcp-host=a0:ce:c8:c8:d8:81,10.42.0.12,set:cheza2
+
+# Specify the next server, watch out for the double ',,'. The
+# filename didn't seem to get picked up by the bootloader, so we use
+# tftp-unique-root and mount directories like
+# /srv/tftp/10.42.0.11/jwerner/cheza as /tftp in the job containers.
+tftp-unique-root
+dhcp-boot=tag:cheza1,cheza1/vmlinuz,,10.42.0.10
+dhcp-boot=tag:cheza2,cheza2/vmlinuz,,10.42.0.10
+
+dhcp-option=tag:cheza1,option:root-path,/srv/nfs/cheza1
+dhcp-option=tag:cheza2,option:root-path,/srv/nfs/cheza2
+```
+
## Setup
Each board will be registered in fd.o gitlab. You'll want something
-like this to register:
+like this to register a fastboot board:
```
sudo gitlab-runner register \
@@ -52,27 +88,35 @@ sudo gitlab-runner register \
--non-interactive
```
+For a servo board, you'll need to also volume mount the board's NFS
+root dir at /nfs and TFTP kernel directory at /tftp.
+
The registration token has to come from a fd.o gitlab admin going to
https://gitlab.freedesktop.org/admin/runners
-The name scheme for Google's lab is google-freedreno-boardname-nn, and
-our tag is google-freedreno-db410c. The tag is what identifies a
-board type so that board-specific jobs can be dispatched into that
-pool.
+The name scheme for Google's lab is google-freedreno-boardname-n, and
+our tag is something like google-freedreno-db410c. The tag is what
+identifies a board type so that board-specific jobs can be dispatched
+into that pool.
We need privileged mode and the /dev bind mount in order to get at the
serial console and fastboot USB devices (--device arguments don't
apply to devices that show up after container start, which is the case
-with fastboot). We use host network mode so that we can (in the
-future) spin up a server to collect XML results.
-
-Once you've added your boards, you're going to need to specify the
-board-specific env vars, adding something like this `environment` line
-to each runner in `/etc/gitlab-runner/config.toml`
+with fastboot, and the servo serial devices are acctually links to
+/dev/pts). We use host network mode so that we can (in the future)
+spin up a server to collect XML results for fastboot.
+
+Once you've added your boards, you're going to need to add a little
+more customization in `/etc/gitlab-runner/config.toml`. First, add
+`concurrent = <number of boards>` at the top ("we should have up to
+this many jobs running managed by this gitlab-runner"). Then for each
+board's runner, set `limit = 1` ("only 1 job served by this board at a
+time"). Finally, add the board-specific environment variables
+required by your bare-metal script, something like:
```
[[runners]]
- name = "google-freedreno-db410c-01"
+ name = "google-freedreno-db410c-1"
environment = ["BM_SERIAL=/dev/ttyDB410c8", "BM_POWERUP=google-power-up.sh 8", "BM_FASTBOOT_SERIAL=15e9e390"]
```
diff --git a/.gitlab-ci/bare-metal/cros-servo.sh b/.gitlab-ci/bare-metal/cros-servo.sh
new file mode 100755
index 00000000000..b67c1f2ad65
--- /dev/null
+++ b/.gitlab-ci/bare-metal/cros-servo.sh
@@ -0,0 +1,97 @@
+#!/bin/bash
+
+# Boot script for Chrome OS devices attached to a servo debug connector, using
+# NFS and TFTP to boot.
+
+# We're run from the root of the repo, make a helper var for our paths
+BM=$CI_PROJECT_DIR/.gitlab-ci/bare-metal
+
+# Runner config checks
+if [ -z "$BM_SERIAL" ]; then
+ echo "Must set BM_SERIAL in your gitlab-runner config.toml [[runners]] environment"
+ echo "This is the CPU serial device."
+ exit 1
+fi
+
+if [ -z "$BM_SERIAL_EC" ]; then
+ echo "Must set BM_SERIAL in your gitlab-runner config.toml [[runners]] environment"
+ echo "This is the EC serial device for controlling board power"
+ exit 1
+fi
+
+if [ ! -d /nfs ]; then
+ echo "NFS rootfs directory needs to be mounted at /nfs by the gitlab runner"
+ exit 1
+fi
+
+if [ ! -d /tftp ]; then
+ echo "TFTP directory for this board needs to be mounted at /tftp by the gitlab runner"
+ exit 1
+fi
+
+# job config checks
+if [ -z "$BM_KERNEL" ]; then
+ echo "Must set BM_KERNEL to your board's kernel FIT image"
+ exit 1
+fi
+
+if [ -z "$BM_ROOTFS" ]; then
+ echo "Must set BM_ROOTFS to your board's rootfs directory in the job's variables"
+ exit 1
+fi
+
+if [ -z "$BM_CMDLINE" ]; then
+ echo "Must set BM_CMDLINE to your board's kernel command line arguments"
+ exit 1
+fi
+
+set -ex
+
+# Create the rootfs in the NFS directory. rm to make sure it's in a pristine
+# state, since it's volume-mounted on the host.
+rm -rf /nfs/*
+mkdir -p /nfs/results
+. $BM/rootfs-setup.sh /nfs
+
+# Set up the TFTP kernel/cmdline. When we support more than one board with
+# this method, we'll need to do some check on the runner name or something.
+rm -rf /tftp/*
+cp $BM_KERNEL /tftp/vmlinuz
+echo "$BM_CMDLINE" > /tftp/cmdline
+
+# Start watching serials, and power up the device.
+$BM/serial-buffer.py $BM_SERIAL_EC | tee serial-ec-output.txt | sed -u 's|^|SERIAL-EC> |g' &
+$BM/serial-buffer.py $BM_SERIAL | tee serial-output.txt | sed -u 's|^|SERIAL-CPU> |g' &
+while [ ! -e serial-output.txt ]; do
+ sleep 1
+done
+# Flush any partial commands in the EC's prompt, then ask for a reboot.
+$BM/write-serial.py $BM_SERIAL_EC ""
+$BM/write-serial.py $BM_SERIAL_EC reboot
+
+# This is emitted right when the bootloader pauses to check for input. Emit a
+# ^N character to request network boot, because we don't have a
+# direct-to-netboot firmware on cheza.
+$BM/expect-output.sh serial-output.txt "load_archive: loading locale_en.bin"
+$BM/write-serial.py $BM_SERIAL `printf '\016'`
+
+# Wait for the device to complete the deqp run
+$BM/expect-output.sh serial-output.txt "DEQP RESULT"
+
+# power down the CPU on the device
+$BM/write-serial.py $BM_SERIAL_EC 'power off'
+
+set -ex
+
+# Bring artifacts back from the NFS dir to the build dir where gitlab-runner
+# will look for them. Note that results/ may already exist, so be careful
+# with cp.
+mkdir -p results
+cp -Rp /nfs/results/. results/
+
+set +e
+if grep -q "DEQP RESULT: pass" serial-output.txt; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/.gitlab-ci/bare-metal/fastboot.sh b/.gitlab-ci/bare-metal/fastboot.sh
index 221d8efc26e..124309e8abe 100755
--- a/.gitlab-ci/bare-metal/fastboot.sh
+++ b/.gitlab-ci/bare-metal/fastboot.sh
@@ -44,57 +44,9 @@ fi
set -ex
-# Copy the rootfs to a temporary for our setup, as I believe changes to the
-# container can end up impacting future runs.
-cp -Rp $BM_ROOTFS rootfs
-
-# Set up the init script that brings up the system.
-cp $BM/init.sh rootfs/init
-
-set +x
-# Pass through relevant env vars from the gitlab job to the baremetal init script
-touch rootfs/set-job-env-vars.sh
-chmod +x rootfs/set-job-env-vars.sh
-for var in \
- CI_COMMIT_BRANCH \
- CI_COMMIT_TITLE \
- CI_JOB_ID \
- CI_JOB_URL \
- CI_MERGE_REQUEST_SOURCE_BRANCH_NAME \
- CI_MERGE_REQUEST_TITLE \
- CI_NODE_INDEX \
- CI_NODE_TOTAL \
- CI_PIPELINE_ID \
- CI_RUNNER_DESCRIPTION \
- DEQP_CASELIST_FILTER \
- DEQP_EXPECTED_RENDERER \
- DEQP_NO_SAVE_RESULTS \
- DEQP_PARALLEL \
- DEQP_RUN_SUFFIX \
- DEQP_VER \
- FD_MESA_DEBUG \
- FLAKES_CHANNEL \
- IR3_SHADER_DEBUG \
- NIR_VALIDATE \
- ; do
- val=`echo ${!var} | sed 's|"||g'`
- echo "export $var=\"${val}\"" >> rootfs/set-job-env-vars.sh
-done
-echo "Variables passed through:"
-cat rootfs/set-job-env-vars.sh
-set -x
-
-# Add the Mesa drivers we built, and make a consistent symlink to them.
-mkdir -p rootfs/$CI_PROJECT_DIR
-tar -C rootfs/$CI_PROJECT_DIR/ -xf $CI_PROJECT_DIR/artifacts/install.tar
-ln -sf $CI_PROJECT_DIR/install rootfs/install
-
-# Copy the deqp runner script and metadata.
-cp .gitlab-ci/deqp-runner.sh rootfs/deqp/.
-cp .gitlab-ci/$DEQP_SKIPS rootfs/$CI_PROJECT_DIR/install/deqp-skips.txt
-if [ -n "$DEQP_EXPECTED_FAILS" ]; then
- cp .gitlab-ci/$DEQP_EXPECTED_FAILS rootfs/$CI_PROJECT_DIR/install/deqp-expected-fails.txt
-fi
+# Create the rootfs in a temp dir
+mkdir rootfs
+. .gitlab-ci/bare-metal/rootfs-setup.sh rootfs
# Finally, pack it up into a cpio rootfs.
pushd rootfs
diff --git a/.gitlab-ci/bare-metal/rootfs-setup.sh b/.gitlab-ci/bare-metal/rootfs-setup.sh
new file mode 100644
index 00000000000..f8c9fa42ba0
--- /dev/null
+++ b/.gitlab-ci/bare-metal/rootfs-setup.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+rootfs_dst=$1
+
+# Copy the rootfs to a temporary for our setup, as I believe changes to the
+# container can end up impacting future runs.
+cp -Rp $BM_ROOTFS/. $rootfs_dst
+
+# Set up the init script that brings up the system.
+cp $BM/init.sh $rootfs_dst/init
+
+set +x
+# Pass through relevant env vars from the gitlab job to the baremetal init script
+touch $rootfs_dst/set-job-env-vars.sh
+chmod +x $rootfs_dst/set-job-env-vars.sh
+for var in \
+ CI_COMMIT_BRANCH \
+ CI_COMMIT_TITLE \
+ CI_JOB_ID \
+ CI_JOB_URL \
+ CI_MERGE_REQUEST_SOURCE_BRANCH_NAME \
+ CI_MERGE_REQUEST_TITLE \
+ CI_NODE_INDEX \
+ CI_NODE_TOTAL \
+ CI_PIPELINE_ID \
+ CI_RUNNER_DESCRIPTION \
+ DEQP_CASELIST_FILTER \
+ DEQP_EXPECTED_RENDERER \
+ DEQP_NO_SAVE_RESULTS \
+ DEQP_PARALLEL \
+ DEQP_RUN_SUFFIX \
+ DEQP_VER \
+ FD_MESA_DEBUG \
+ FLAKES_CHANNEL \
+ IR3_SHADER_DEBUG \
+ NIR_VALIDATE \
+ ; do
+ val=`echo ${!var} | sed 's|"||g'`
+ echo "export $var=\"${val}\"" >> $rootfs_dst/set-job-env-vars.sh
+done
+echo "Variables passed through:"
+cat $rootfs_dst/set-job-env-vars.sh
+set -x
+
+# Add the Mesa drivers we built, and make a consistent symlink to them.
+mkdir -p $rootfs_dst/$CI_PROJECT_DIR
+tar -C $rootfs_dst/$CI_PROJECT_DIR/ -xf $CI_PROJECT_DIR/artifacts/install.tar
+ln -sf $CI_PROJECT_DIR/install $rootfs_dst/install
+
+# Copy the deqp runner script and metadata.
+cp .gitlab-ci/deqp-runner.sh $rootfs_dst/deqp/
+cp .gitlab-ci/$DEQP_SKIPS $rootfs_dst/$CI_PROJECT_DIR/install/deqp-skips.txt
+if [ -n "$DEQP_EXPECTED_FAILS" ]; then
+ cp .gitlab-ci/$DEQP_EXPECTED_FAILS $rootfs_dst/$CI_PROJECT_DIR/install/deqp-expected-fails.txt
+fi
diff --git a/.gitlab-ci/bare-metal/write-serial.py b/.gitlab-ci/bare-metal/write-serial.py
new file mode 100755
index 00000000000..6a57ea754af
--- /dev/null
+++ b/.gitlab-ci/bare-metal/write-serial.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python3
+
+import sys
+import serial
+
+dev = sys.argv[1]
+command = sys.argv[2] + '\n'
+
+ser = serial.Serial(dev, 115200, timeout=5)
+ser.write(command.encode())
+ser.close()