arch/arm64: Support FEAT_CCIDX
[coreboot2.git] / util / board_status / board_status.sh
blobda199406693e4983fc45e066574cbdbe6d5b7fd2
1 #!/usr/bin/env sh
4 # See README and https://www.coreboot.org/Board_Status for instructions.
6 EXIT_SUCCESS=0
7 EXIT_FAILURE=1
9 # Stuff from command-line switches
10 COREBOOT_IMAGE="build/coreboot.rom"
11 REMOTE_HOST=""
12 REMOTE_PORT_OPTION=""
13 CLOBBER_OUTPUT=0
14 UPLOAD_RESULTS=0
15 SERIAL_PORT_SPEED=115200
17 # Used to specify whether a command should always be run locally or
18 # if command should be run remoteley when a remote host is specified.
19 LOCAL=0
20 REMOTE=1
21 FATAL=0
22 NONFATAL=1
24 # Used if cbmem is not in default $PATH, e.g. not installed or when using `sudo`
25 CBMEM_PATH=""
27 # Used if nvramtool is not in default $PATH, e.g. not installed or when using `sudo`
28 NVRAMTOOL_PATH=""
30 case $(uname) in
31 FreeBSD)
32 if [ ! -x /usr/local/bin/gmake ]; then
33 echo "Please install gmake, or build and install devel/gmake from ports."
34 exit $EXIT_FAILURE
35 else
36 MAKE='gmake'
40 MAKE='make'
42 esac
44 # test a command
46 # $1: 0 ($LOCAL) to run command locally,
47 # 1 ($REMOTE) to run remotely if remote host defined
48 # $2: command to test
49 # $3: 0 ($FATAL) Exit with an error if the command fails
50 # 1 ($NONFATAL) Don't exit on command test failure
51 test_cmd()
53 local rc
55 if [ -e "$2" ]; then
56 return
59 if [ "$1" -eq "$REMOTE" ] && [ -n "$REMOTE_HOST" ]; then
60 ssh $REMOTE_PORT_OPTION root@${REMOTE_HOST} command -v "$2" > /dev/null
61 rc=$?
62 else
63 command -v "$2" >/dev/null
64 rc=$?
67 if [ $rc -eq 0 ]; then
68 return 0
71 if [ "$3" = "1" ]; then
72 return 1
75 echo "$2 not found"
76 exit $EXIT_FAILURE
79 _cmd()
81 if [ -e "$2" ]; then
82 return $EXIT_FAILURE
85 if [ -n "$3" ]; then
86 pipe_location="${3}"
87 else
88 pipe_location="/dev/null"
91 if [ "$1" -eq "$REMOTE" ] && [ -n "$REMOTE_HOST" ]; then
92 ssh $REMOTE_PORT_OPTION "root@${REMOTE_HOST}" "$2" > "$pipe_location" 2>&1
93 else
94 $2 > "$pipe_location" 2>&1
97 return $?
100 # run a command
102 # $1: 0 ($LOCAL) to run command locally,
103 # 1 ($REMOTE) to run remotely if remote host defined
104 # $2: command
105 # $3: filename to direct output of command into
106 cmd()
108 _cmd $1 "$2" "$3"
110 if [ $? -eq 0 ]; then
111 return
114 echo "Failed to run \"$2\", aborting"
115 rm -f "$3" # don't leave an empty file
116 exit $EXIT_FAILURE
119 # run a command where failure is considered to be non-fatal
121 # $1: 0 ($LOCAL) to run command locally,
122 # 1 ($REMOTE) to run remotely if remote host defined
123 # $2: command
124 # $3: filename to direct output of command into
125 cmd_nonfatal()
127 _cmd $1 "$2" "$3"
129 if [ $? -eq 0 ]; then
130 return
133 echo "Failed to run \"$2\", ignoring"
134 rm -f "$3" # don't leave an empty file
137 # read from a serial port device
139 # $1: serial device to read from
140 # $2: serial port speed
141 # $3: filename to direct output of command into
142 get_serial_bootlog () {
144 local TTY=$1
145 local SPEED=$2
146 local FILENAME=$3
148 if [ ! -c "$TTY" ]; then
149 echo "$TTY is not a valid serial device"
150 exit $EXIT_FAILURE
153 # make the text more noticible
154 test_cmd $LOCAL "tput" $NONFATAL
155 tput_not_available=$?
156 if [ $tput_not_available -eq 0 ]; then
157 tput bold
158 tput setaf 10 # set bright green
161 echo
162 echo "Waiting to receive boot log from $TTY"
163 echo "Press [Enter] when the boot is complete."
164 echo
166 if [ $tput_not_available -eq 0 ]; then
167 tput sgr0
170 # set up the serial port
171 stty -F $TTY $SPEED cs8 -cstopb -parenb clocal
173 # read from the serial port - user must press enter when complete
174 test_cmd $LOCAL "tee"
175 while read LINE; do
176 echo "$LINE" | tee -a "$FILENAME"
177 done < "$SERIAL_DEVICE" &
178 PID=$!
180 read foo
181 kill "$PID" 2>/dev/null
183 echo "Finished reading boot log."
186 show_help() {
187 echo "Usage:
188 ${0} <option>
190 Options
191 -c, --cbmem
192 Path to cbmem on device under test (DUT).
193 -n, --nvramtool
194 Path to nvramtool on device under test (DUT).
195 -C, --clobber
196 Clobber temporary output when finished. Useful for debugging.
197 -h, --help
198 Show this message.
199 -i, --image <image>
200 Path to coreboot image (Default is $COREBOOT_IMAGE).
201 -r, --remote-host <host>
202 Obtain machine information from remote host (using ssh).
203 -s, --serial-device </dev/xxx>
204 Obtain boot log via serial device.
205 -S, --serial-speed <speed>
206 Set the port speed for the serial device (Default is $SERIAL_PORT_SPEED).
207 -u, --upload-results
208 Upload results to coreboot.org.
210 Long options:
211 --ssh-port <port>
212 Use a specific SSH port.
216 case $(uname) in
217 FreeBSD)
218 if [ ! -x /usr/local/bin/getopt ]; then
219 echo "Please install getopt, or build and install misc/getopt from ports."
220 exit $EXIT_FAILURE
221 else
222 GETOPT=/usr/local/bin/getopt
226 GETOPT=/usr/bin/getopt
228 esac
230 $GETOPT -T
231 if [ $? -ne 4 ]; then
232 echo "GNU-compatible getopt(1) required."
233 exit $EXIT_FAILURE
236 LONGOPTS="cbmem:,clobber,help,image:,remote-host:,upload-results"
237 LONGOPTS="${LONGOPTS},serial-device:,serial-speed:"
238 LONGOPTS="${LONGOPTS},ssh-port:"
240 ARGS=$($GETOPT -o c:n:Chi:r:s:S:u -l "$LONGOPTS" -n "$0" -- "$@");
241 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
242 eval set -- "$ARGS"
243 while true ; do
244 case "$1" in
245 # generic options
246 -c|--cbmem)
247 shift
248 CBMEM_PATH="$1"
250 -n|--nvramtool)
251 shift
252 NVRAMTOOL_PATH="$1"
254 -C|--clobber)
255 CLOBBER_OUTPUT=1
257 -h|--help)
258 show_help
259 exit $EXIT_SUCCESS
261 -i|--image)
262 shift
263 COREBOOT_IMAGE="$1"
265 -r|--remote-host)
266 shift
267 REMOTE_HOST="$1"
269 -u|--upload-results)
270 UPLOAD_RESULTS=1
273 # serial port options
274 -s|--serial-device)
275 shift
276 SERIAL_DEVICE="$1"
278 -S|--serial-speed)
279 shift
280 SERIAL_PORT_SPEED="$1"
283 # ssh options
284 --ssh-port)
285 shift
286 REMOTE_PORT_OPTION="-p $1"
289 # error handling
291 shift
292 if [ -n "$*" ]; then
293 echo "Non-option parameters detected: '$*'"
294 exit $EXIT_FAILURE
296 break
299 echo "error processing options at '$1'"
300 exit $EXIT_FAILURE
301 esac
302 shift
303 done
305 grep -rH 'coreboot.org' .git/config >/dev/null 2>&1
306 if [ $? -ne 0 ]; then
307 echo "Script must be run from root of coreboot directory"
308 exit $EXIT_FAILURE
311 if [ ! -e "$COREBOOT_IMAGE" ]; then
312 echo "board_status needs $COREBOOT_IMAGE, but it does not exist."
313 echo "Use \"-i IMAGE_FILE\" to select a different image, or \"--help\" for more options."
314 exit $EXIT_FAILURE
317 # Results will be placed in a temporary location until we're ready to upload.
318 # If the user does not wish to upload, results will remain in /tmp.
319 case $(uname) in
320 FreeBSD)
321 tmpdir=$(mktemp -d -t coreboot_board_status)
324 tmpdir=$(mktemp -d --tmpdir coreboot_board_status.XXXXXXXX)
326 esac
328 # Obtain coreboot config by running cbfstool on the ROM image. cbfstool may
329 # already exist in build/ or util/cbfstool/, but if not then we'll build it
330 # now and clean it when we're done.
331 cbfstool_cmd="build/cbfstool"
332 do_clean_cbfstool=0
333 if [ ! -x $cbfstool_cmd ]; then
334 cbfstool_cmd="util/cbfstool/cbfstool"
335 if [ -e $cbfstool_cmd ]; then
336 if test ! -x $cbfstool_cmd; then
337 echo "Cannot execute $cbfstool_cmd."
338 exit $EXIT_FAILURE
340 else
341 $MAKE -C util/cbfstool/
342 do_clean_cbfstool=1
345 test_cmd $LOCAL "$cbfstool_cmd"
347 tmpcfg=$(mktemp coreboot_config.XXXXXX)
348 echo "Extracting config.txt from $COREBOOT_IMAGE"
349 $cbfstool_cmd "$COREBOOT_IMAGE" extract -n config -f "${tmpdir}/config.txt" >/dev/null 2>&1
350 mv "${tmpdir}/config.txt" "${tmpdir}/config.short.txt"
351 cp "${tmpdir}/config.short.txt" "${tmpcfg}"
352 yes "" | $MAKE "DOTCONFIG=${tmpcfg}" oldconfig 2>/dev/null >/dev/null
353 mv "${tmpcfg}" "${tmpdir}/config.txt"
354 rm -f "${tmpcfg}.old"
355 $cbfstool_cmd "$COREBOOT_IMAGE" print > "${tmpdir}/cbfs.txt"
356 rom_contents=$($cbfstool_cmd "$COREBOOT_IMAGE" print 2>&1)
357 if [ -n "$(echo $rom_contents | grep payload_config)" ]; then
358 echo "Extracting payload_config from $COREBOOT_IMAGE"
359 $cbfstool_cmd "$COREBOOT_IMAGE" extract -n payload_config -f "${tmpdir}/payload_config.txt" >/dev/null 2>&1
361 if [ -n "$(echo $rom_contents | grep payload_version)" ]; then
362 echo "Extracting payload_version from $COREBOOT_IMAGE"
363 $cbfstool_cmd "$COREBOOT_IMAGE" extract -n payload_version -f "${tmpdir}/payload_version.txt" >/dev/null 2>&1
365 case $(uname) in
366 FreeBSD)
367 md5 "$COREBOOT_IMAGE" > "${tmpdir}/rom_checksum.txt"
370 md5sum -b "$COREBOOT_IMAGE" > "${tmpdir}/rom_checksum.txt"
372 esac
374 if test $do_clean_cbfstool -eq 1; then
375 $MAKE -C util/cbfstool clean
378 # Obtain board and revision info to form the directory structure:
379 # <vendor>/<board>/<revision>/<timestamp>
380 mainboard_dir="$(grep CONFIG_MAINBOARD_DIR "${tmpdir}/config.txt" | awk -F '"' '{ print $2 }')"
381 vendor=$(echo "$mainboard_dir" | awk -F '/' '{ print $1 }')
382 mainboard=$(echo "$mainboard_dir" | awk -F '/' '{ print $2 }')
384 getrevision="util/board_status/getrevision.sh"
385 test_cmd $LOCAL $getrevision
386 tagged_version=$($getrevision -T)
387 timestamp=$($getrevision -t)
389 results="${vendor}/${mainboard}/${tagged_version}/${timestamp}"
391 if [ -n "$(echo $tagged_version | grep dirty)" ]; then
392 echo "The repository is in a dirty state. Please see the output of"
393 echo "'git status' below."
394 git status
395 exit $EXIT_FAILURE
398 echo "Temporarily placing output in ${tmpdir}/${results}"
399 mkdir -p "${tmpdir}/${results}"
401 mv "${tmpdir}/config.txt" "${tmpdir}/${results}"
402 test -f "${tmpdir}/payload_config.txt" && mv "${tmpdir}/payload_config.txt" "${tmpdir}/${results}"
403 test -f "${tmpdir}/payload_version.txt" && mv "${tmpdir}/payload_version.txt" "${tmpdir}/${results}"
404 mv "${tmpdir}/config.short.txt" "${tmpdir}/${results}"
405 mv "${tmpdir}/cbfs.txt" "${tmpdir}/${results}"
406 mv "${tmpdir}/rom_checksum.txt" "${tmpdir}/${results}"
408 touch "${tmpdir}/${results}/revision.txt"
409 printf "Local revision: %s\n" "$($getrevision -l)" >> "${tmpdir}/${results}/revision.txt"
410 printf "Tagged revision: %s\n" "${tagged_version}" >> "${tmpdir}/${results}/revision.txt"
411 printf "Upstream revision: %s\n" "$($getrevision -u)" >> "${tmpdir}/${results}/revision.txt"
412 printf "Upstream URL: %s\n" "$($getrevision -U)" >> "${tmpdir}/${results}/revision.txt"
413 printf "Timestamp: %s\n" "$timestamp" >> "${tmpdir}/${results}/revision.txt"
415 if [ -n "$CBMEM_PATH" ]; then
416 cbmem_cmd="$CBMEM_PATH"
417 else
418 cbmem_cmd="cbmem"
421 cmos_enabled=0
422 if grep -q "CONFIG_USE_OPTION_TABLE=y" "${tmpdir}/${results}/config.short.txt" > /dev/null; then
423 cmos_enabled=1
426 if [ -n "$NVRAMTOOL_PATH" ]; then
427 nvramtool_cmd="$NVRAMTOOL_PATH"
428 else
429 nvramtool_cmd="nvramtool"
432 if [ -n "$SERIAL_DEVICE" ]; then
433 get_serial_bootlog "$SERIAL_DEVICE" "$SERIAL_PORT_SPEED" "${tmpdir}/${results}/coreboot_console.txt"
434 elif [ -n "$REMOTE_HOST" ]; then
435 echo "Verifying that CBMEM is available on remote device"
436 test_cmd $REMOTE "$cbmem_cmd"
437 echo "Getting coreboot boot log"
438 cmd $REMOTE "$cbmem_cmd -1" "${tmpdir}/${results}/coreboot_console.txt"
439 echo "Getting timestamp data"
440 cmd_nonfatal $REMOTE "$cbmem_cmd -t" "${tmpdir}/${results}/coreboot_timestamps.txt"
442 if [ "$cmos_enabled" -eq 1 ]; then
443 echo "Verifying that nvramtool is available on remote device"
444 test_cmd $REMOTE "$nvramtool_cmd"
445 echo "Getting all CMOS values"
446 cmd $REMOTE "$nvramtool_cmd -a" "${tmpdir}/${results}/cmos_values.txt"
449 echo "Getting remote dmesg"
450 cmd $REMOTE dmesg "${tmpdir}/${results}/kernel_log.txt"
451 else
452 echo "Verifying that CBMEM is available"
453 if [ $(id -u) -ne 0 ]; then
454 command -v "$cbmem_cmd" >/dev/null
455 if [ $? -ne 0 ]; then
456 echo "Failed to run $cbmem_cmd. Check \$PATH or" \
457 "use -c to specify path to cbmem binary."
458 exit $EXIT_FAILURE
459 else
460 cbmem_cmd="sudo $cbmem_cmd"
462 else
463 test_cmd $LOCAL "$cbmem_cmd"
466 echo "Getting coreboot boot log"
467 cmd $LOCAL "$cbmem_cmd -1" "${tmpdir}/${results}/coreboot_console.txt"
469 echo "Getting timestamp data"
470 cmd_nonfatal $LOCAL "$cbmem_cmd -t" "${tmpdir}/${results}/coreboot_timestamps.txt"
472 if [ "$cmos_enabled" -eq 1 ]; then
473 echo "Verifying that nvramtool is available"
474 if [ $(id -u) -ne 0 ]; then
475 command -v "$nvramtool_cmd" >/dev/null
476 if [ $? -ne 0 ]; then
477 echo "Failed to run $nvramtool_cmd. Check \$PATH or" \
478 "use -n to specify path to nvramtool binary."
479 exit $EXIT_FAILURE
480 else
481 nvramtool_cmd="sudo $nvramtool_cmd"
483 else
484 test_cmd $LOCAL "$nvramtool_cmd"
487 echo "Getting all CMOS values"
488 cmd $LOCAL "$nvramtool_cmd -a" "${tmpdir}/${results}/cmos_values.txt"
491 echo "Getting local dmesg"
492 cmd $LOCAL "sudo dmesg" "${tmpdir}/${results}/kernel_log.txt"
496 # Check files
498 if [ $(grep -- -dirty "${tmpdir}/${results}/coreboot_console.txt") ]; then
499 echo "coreboot or the payload are built from a source tree in a" \
500 "dirty state, making it hard to reproduce the result. Please" \
501 "check in your source tree with 'git status'."
502 exit $EXIT_FAILURE
505 if [ $(grep -- unknown "${tmpdir}/${results}/coreboot_timestamps.txt" >/dev/null 2>&1) ]; then
506 echo "Unknown timestamps found in 'coreboot_timestamps.txt'." \
507 "Please rebuild the 'cbmem' utility and try again."
508 exit $EXIT_FAILURE
512 # Finish up.
514 coreboot_dir=$(pwd)
515 if [ $UPLOAD_RESULTS -eq 1 ]; then
516 # extract username from ssh://<username>@review.coreboot.org/blah
517 bsrepo=$(git config --get remote.origin.url | sed "s,\(.*\)/coreboot,\1/board-status,")
519 cd "util/board_status/"
520 if [ ! -e "board-status" ]; then
521 # FIXME: the board-status directory might get big over time.
522 # Is there a way we can push the results without fetching the
523 # whole repo?
524 git clone "$bsrepo"
525 if [ $? -ne 0 ]; then
526 echo "Error cloning board-status repo, aborting."
527 exit $EXIT_FAILURE
531 cd "board-status"
533 echo "Checking for duplicate results"
534 # get any updates to board-status
535 git pull
537 echo "${tagged_version}" | grep dirty >/dev/null 2>&1
538 clean_version=$?
539 existing_results=$(git ls-files "${mainboard_dir}/${tagged_version}")
541 # reject duplicate results of non-dirty versions
542 if [ "${clean_version}" -eq 1 ] && [ -n "${existing_results}" ] ; then
543 echo "Result is a duplicate, aborting"
544 exit $EXIT_FAILURE
547 echo "Copying results to $(pwd)/${results}"
549 # Note: Result directory should be unique due to the timestamp.
550 cp -R "${tmpdir}/${vendor}" .
552 echo "Uploading results"
553 git add "${vendor}"
554 git commit -a -m "${mainboard_dir}/${tagged_version}/${timestamp}"
555 count=0
556 until git push origin main || test $count -eq 3; do
557 git pull --rebase
558 count=$((count + 1))
559 done
561 # Results have been uploaded so it's pointless to keep the
562 # temporary files around.
563 rm -rf "${tmpdir}"
564 if test $count -eq 3; then
565 echo "Error uploading to board-status repo, aborting."
566 exit $EXIT_FAILURE
569 cd "$coreboot_dir"
571 if [ $CLOBBER_OUTPUT -eq 1 ]; then
572 rm -rf "${tmpdir}"
573 else
574 if [ $UPLOAD_RESULTS -eq 1 ]; then
575 echo
576 echo "output files are in $(dirname $0)/board-status/${mainboard_dir}/${tagged_version}/${timestamp}"
577 else
578 echo
579 echo "output files are in ${tmpdir}/${results}"
583 exit $EXIT_SUCCESS