blob: ad054f7834b217a65e63f365e13260976ce8889c [file] [log] [blame]
#!/bin/bash
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# A simple script to run SAFT unit tests and possibly start the SAFT.
#
# The only expected optional command line parameter is the name of the file
# containing the firmware image to test. If the parameter is not provided,
# SAFT is not started, just the unit tests get to run.
rm -rf /tmp/tmp*/var/.fw_test 2> /dev/null
umount -d /tmp/tmp* 2> /dev/null
TMPD_PATTERN='/tmp/tmp_saft.XXXX'
set -e
this_prog=$(readlink -f $0)
if [ -n "$1" ]; then
new_firmware=$(readlink -f $1)
else
new_firmware=''
fi
case "$(crossystem arch)" in
(x86)
ARCH='x86'
DEFAULT_FLASH_DEVICE="${FLASH_DEVICE:=sdb}"
DEFAULT_DISK_DEVICE="${DISK_DEVICE:=sda}"
;;
(arm)
ARCH='arm'
DEFAULT_FLASH_DEVICE="${FLASH_DEVICE:=sda}"
DEFAULT_DISK_DEVICE="${DISK_DEVICE:=mmcblk0}"
;;
(*)
echo "Failed to auto detect architecture."
exit 1
;;
esac
join_part() {
local dev="$1"
local part="$2"
# Test the dev is mmcblk0 or sda style
if [ "${dev}" != "${dev/mmcblk/}" ]; then
echo "$1p$2"
else
echo "$1$2"
fi
}
# This hack has been borrowed from src/scripts/common.sh
enable_rw_mount() {
local rootfs="$1"
local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte
printf '\000' |
sudo dd of="$rootfs" seek=${ro_compat_offset} \
conv=notrunc count=1 bs=1
}
target_hosted () {
python -c 'import chromeos_interface;\
crosif = chromeos_interface.ChromeOSInterface(True);\
print "%d" % crosif.target_hosted()'
}
on_removable_device() {
# Check if the code is running off a removable device or not.
# Print '1' or '0' respectively on the console.
rootd=$(df "${this_prog}" | grep '^/dev' | awk '{ print $1 }')
if [ "${rootd}" == '/dev/root' ]; then
rootd=$(rootdev -s)
fi
blockd=$(echo "${rootd}" | sed 's/.*\(sd[a-z]\+\|mmcblk[0-9]\+\).*/\1/')
removable="/sys/block/"${blockd}"/removable"
if [ -f "${removable}" ]; then
cat "${removable}"
else
echo '0'
fi
}
move_to_removable_device() {
# Move ourselves to the removable device and run off it.
# For simplicity, hardcode the removable device to be
# $DEFAULT_FLASH_DEVICE which was assigned at the beginning.
flash_device="${DEFAULT_FLASH_DEVICE}"
fname="/sys/block/${flash_device}/removable"
# Confirm SDB exists and is indeed removable.
if [ ! -f "${fname}" -o "$(cat $fname)" != "1" ]; then
echo "No removable device found"
exit 1
fi
# Determine userland partition on the removable device.
dev_num=$(cgpt show /dev/"${flash_device}" | \
grep '"ROOT-A"' | awk '{ print $3 }')
if [ -z "${dev_num}" ]; then
echo "/dev/${flash_device} does not contain a valid file system"
exit 1
fi
flash_root_partition=$(join_part "/dev/${flash_device}" "${dev_num}")
enable_rw_mount "${flash_root_partition}"
# Find its mountpoint, or mount it if not yet mounted.
mp=$(mount | grep "${flash_root_partition}" | awk '{print $3}')
if [ "${mp}" == "" ]; then
mp=$(mktemp -d "${TMPD_PATTERN}")
mount "${flash_root_partition}" "${mp}"
else
mount -o remount,exec "${mp}"
fi
# Copy the two directories SAFT test requires to the removable device to
# the same path we are in on the root device now.
my_root=$(readlink -f .)
dest="${mp}${my_root}"
if [ ! -d "${dest}" ]; then
mkdir -p "${dest}"
fi
cp -rp "${my_root}"/* "${dest}"
# Start it running off the removable device. We don't expect to come back
# from this invocation in case this is a full mode SAFT. If this is a
# unittest run, some post processing can be added after unit tests return.
echo "starting as ${mp}${this_prog} ${new_firmware}"
"${mp}${this_prog}" "${new_firmware}"
}
configure_gpt_settings() {
# Let's keep it simple for now, partition 2 is the one to boot.
cgpt add -i 2 -T 5 -P 9 -S 1 "/dev/${DEFAULT_DISK_DEVICE}"
cgpt add -i 4 -T 5 -P 5 -S 1 "/dev/${DEFAULT_DISK_DEVICE}"
}
run_tests() {
./test_chromeos_interface.py
if [ "$(target_hosted)" == "0" ]; then
return
fi
./test_flashrom_handler.py "${new_firmware}"
./test_saft_utility.py
./test_kernel_handler.py
./test_cgpt_handler.py
./test_tpm_handler.py
./test_cgpt_state.py
if [ -n "${new_firmware}" ]; then
configure_gpt_settings
./saft_utility.py --ima="${new_firmware}"
fi
}
check_and_set_saft_environment() {
# Does the other side contain a valid kernel?
tmpd=$(mktemp -d "${TMPD_PATTERN}")
this_root=$(rootdev -s)
this_kern=$(echo "${this_root}" | tr '35' '24')
other_kern=$(echo "${this_kern}" | tr '24' '42')
other_kern_file="${tmpd}/kernel"
dd if="${other_kern}" of="${other_kern_file}"
if ! vbutil_kernel --verify "${other_kern_file}" > /dev/null 2>&1
then
# The "other side" is not valid, let's set it up
echo "setting up kernel in ${other_kern}"
dd if="${this_kern}" of="${other_kern}" bs=4M
other_root=$(echo "${this_root}" | tr '35' '53')
echo "setting up root fs in ${other_root}"
dd if="${this_root}" of="${other_root}" bs=4M
fi
# Is flash device kernel configured to run with verified root fs?
flash_kernel_dev=$(join_part "/dev/${DEFAULT_FLASH_DEVICE}" '2')
dd if="${flash_kernel_dev}" of="${other_kern_file}"
cmd_line=$(vbutil_kernel --verify "${other_kern_file}" --verbose | tail -1)
if echo "${cmd_line}" | grep -q 'root=/dev/dm'; then
echo 'Disabling rootfs verification on the flash device kernel'
new_cmd_line_file="${tmpd}/cmdline"
echo "${cmd_line}" | sed '
s/ ro / rw /
s/dm_verity[^ ]\+//g
s|verity /dev/sd%D%P /dev/sd%D%P ||
s| root=/dev/dm-0 | root=/dev/sd%D%P |
s/dm="[^"]\+" //' > "${new_cmd_line_file}"
vbutil_kernel --repack "${other_kern_file}.new" \
--config "${new_cmd_line_file}" \
--signprivate recovery_kernel_data_key.vbprivk \
--oldblob "${other_kern_file}"
dd if="${other_kern_file}.new" of="${flash_kernel_dev}" bs=4M
fi
}
cd $(dirname ${this_prog})
if [ "$(on_removable_device)" == "0" -a "$(target_hosted)" == "1" ]; then
check_and_set_saft_environment
move_to_removable_device
exit 0
fi
run_tests