1#!/bin/sh
2# Copyright (c) 2022-2024 Intel Corporation
3# SPDX-License-Identifier: Apache-2.0
4set -e
5
6# Twister integration tool for a remote ssh-accessible cAVS audio DSP
7# host (e.g. an Up Squared board running Linux). Can be used as the
8# hook for both --device-serial-pty and --west-flash, for example:
9#
10#  export CAVS_OLD_FLASHER=1
11#  export CAVS_HOST=tgl2
12#  export CAVS_KEY=$HOME/otc_private_key_3k.pem
13#  export CAVS_RIMAGE=$HOME/rimage
14#
15#  twister -p intel_adsp/cavs25 --device-testing \
16#     --device-serial-pty=$ZEPHYR_BASE/soc/intel/intel_adsp/tools/cavstwist.sh \
17#     --west-flash=$ZEPHYR_BASE/soc/intel/intel_adsp/tools/cavstwist.sh
18#
19# The CAVS_OLD_FLASHER is necessary because now the client-server-based
20# cavstool works by default. This is to tell the build system to use
21# the misc-flasher as the runner. Please remember to do the command
22# "unset CAVS_OLD_FLASHER" when you are going to switch to the
23# client-server-based intel_adsp runner.
24#
25# The device at CAVS_HOST must be accessible via non-interactive ssh
26# access and the remote account must have password-free sudo ability.
27# (The intent is that isolating the host like this to be a CAVS test
28# unit means that simple device access at root is acceptable.)
29#
30# The signing key must be correct for your device.  In general we want
31# to be using the SOF-curated "community" keys.  Note that cAVS 2.5
32# uses a different (longer) key than the earlier platforms.
33#
34# CAVS_RIMAGE must be the path to a current, checked out and built (!)
35# rimage tool from SOF: https://github.com/thesofproject/rimage
36#
37# Alternatively, pass a built "zephyr.elf" file (in a complete build
38# tree, not just a standalone file) as the single argument and the
39# script will synchronously flash the device and begin emitting its
40# logs to standard output.
41#
42# Implementation notes:
43#
44# Twister has frustrating runtime behavior with this device.  The
45# flash tool is run via west as part of the build, has a working
46# directory in the build tree, and is passed the build directory as
47# its command line argument.  The console/serial tool is run globally
48# in $ZEPHYR_BASE.  But the console script has no arguments, and thus
49# can't find the test directory!  And worse, the scripts are
50# asynchronous and may start in either order, but our console script
51# can't be allowed to run until after the flash.  If it does, it will
52# pull old data (from the last test run!)  out of the buffer and
53# confuse twister.
54#
55# So the solution here is to have the console script do the trace
56# reading AND the flashing.  The flash script merely signs the binary
57# and places it into ZEPHYR_BASE for the console script to find.  The
58# console script then just has to wait for the binary to appear (which
59# solves the ordering problem), flash it, delete it (so as not to
60# confuse the next test run), and emit the adsplog output as expected.
61#
62# And notice the race protection: it's possible twister will run a
63# signing script IMMEDIATELY, simultaneous with the last flash script.
64# This may thus clobber the version that the other script hasn't seen
65# yet.  So we add an extra wait step in the signing path for the
66# loader to "accept" the file.
67#
68########################################################################
69
70# Three configuration variables to set.  Have to be passed via the
71# environment because this script is launched from twister.
72
73if [ -z "$CAVS_HOST" -o -z "$CAVS_KEY" -o -z "$CAVS_RIMAGE" ]; then
74    echo "Missing cavstwist.sh configuration, must have:" 1>&2
75    echo "  export CAVS_HOST=ssh_host_name[:port]" 1>&2
76    echo "  export CAVS_KEY=/path/to/signing_key.pem" 1>&2
77    echo "  export CAVS_RIMAGE=/path/to/built/rimage/dir" 1>&2
78    exit 1
79fi
80
81########################################################################
82
83CAVSTOOL=$ZEPHYR_BASE/soc/intel/intel_adsp/tools/cavstool.py
84IMAGE=$ZEPHYR_BASE/_cavstmp.ri
85IMAGE2=$ZEPHYR_BASE/_cavstmp2.ri
86
87if [ "$1" = "" ]; then
88    # Twister --device-serial-pty mode
89    DO_LOAD=1
90elif [ "$(basename $1)" = "zephyr.elf" ]; then
91    # Standalone mode (argument is a path to zephyr.elf)
92    BLDDIR=$(dirname $(dirname $1))
93    DO_SIGN=1
94    DO_LOAD=1
95else
96    # Twister --west-flash mode
97    BLDDIR=$1
98    DO_SIGN=1
99fi
100
101if [ "$DO_SIGN" = "1" ]; then
102    # Wait for the last flasher to accept the old file
103    while [ -e $IMAGE ]; do
104	sleep 0.1
105    done
106
107    ELF=$BLDDIR/zephyr/zephyr.elf.mod
108    BOOT=$BLDDIR/zephyr/bootloader.elf.mod
109    (cd $BLDDIR;
110     west sign --tool-data=$CAVS_RIMAGE/config -t rimage -- -k $CAVS_KEY)
111    cp $BLDDIR/zephyr/zephyr.ri $IMAGE
112fi
113
114if [ "$DO_LOAD" = "1" ]; then
115    while [ ! -e $IMAGE ]; do
116	sleep 0.1
117    done
118
119    # Must "accept" the file so the next signing script knows it's OK
120    # to write a new one
121    mv $IMAGE $IMAGE2
122    scp $IMAGE2 $CAVSTOOL scp://$CAVS_HOST
123    rm -f $IMAGE2
124
125    # Twister seems to overlap tests by a tiny bit, and of course the
126    # remote system might have other junk running from manual testing.
127    # If something is doing log reading at the moment of firmware
128    # load, it tends fairly reliably to hang the DSP.  Kill it.
129    ssh ssh://$CAVS_HOST "sudo pkill -9 -f cavstool" ||:
130
131    exec ssh ssh://$CAVS_HOST "sudo ./$(basename $CAVSTOOL) $(basename $IMAGE2)"
132fi
133