blob: efccb69ae1ce3d0a755067ddbc1bae50219bd69a [file] [log] [blame]
#!/bin/bash
# Copyright 2022 The ChromiumOS Authors.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
# Abort on error and uninitialized variables.
set -eu
declare -A -r REQUIRED_BIT_MASKS=(
# Bit 58 - PSP_S0I3_RESUME_VERSTAGE - Run PSP verstage during S0i3 resume.
# Checks that FW images have not been tampered with when exiting S0i3.
[guybrush]="$((1 << 58))"
[zork]="0x0"
)
declare -A -r FORBIDDEN_BIT_MASKS=(
[guybrush]="0x0"
[zork]="0x0"
)
# Grunt uses an old firmware format that amdfwread cannot read.
# See b/233787191 for skyrim.
BOARD_IGNORE_LIST=(grunt skyrim)
usage() {
echo "$0: Validate AMD PSP soft-fuse flags contained in a ChromeOS image." \
"These flags can have security implications and control debug features."
echo "Usage $0 <board> <image>"
}
main() {
if [[ $# -ne 2 ]]; then
usage
exit 1
fi
local board="$1"
local image="$2"
# Check the ignore list.
if [[ " ${BOARD_IGNORE_LIST[*]} " == *" ${board} "* ]]; then
echo "Skipping ignore-listed board ${board}"
exit 0
fi
# Mount the image.
local loopdev rootfs
if [[ -d "${image}" ]]; then
rootfs="${image}"
else
rootfs="$(make_temp_dir)"
loopdev="$(loopback_partscan "${image}")"
mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
fi
local firmware_bundle shellball_dir
firmware_bundle="${rootfs}/usr/sbin/chromeos-firmwareupdate"
shellball_dir="$(make_temp_dir)"
# Get the board specific bit masks.
local required_bit_mask forbidden_bit_mask
if [[ ! -v "REQUIRED_BIT_MASKS[${board}]" ]]; then
die "Missing PSP required bit mask set for ${board}"
fi
if [[ ! -v "FORBIDDEN_BIT_MASKS[${board}]" ]]; then
die "Missing PSP forbidden bit mask set for ${board}"
fi
required_bit_mask="${REQUIRED_BIT_MASKS[${board}]}"
forbidden_bit_mask="${FORBIDDEN_BIT_MASKS[${board}]}"
# Extract our firmware.
if ! extract_firmware_bundle "${firmware_bundle}" "${shellball_dir}"; then
die "Failed to extract firmware bundle"
fi
# Find our images and check the soft-fuse bits in each.
declare -a images
readarray -t images < <(find "${shellball_dir}" -iname 'bios-*')
local image
for image in "${images[@]}"; do
local soft_fuse soft_fuse_output forbidden_set missing_set
if ! soft_fuse_output="$(amdfwread --soft-fuse "${image}")"; then
die "'amdfwread --soft-fuse ${image}' failed"
fi
# Output format from amdfwread is Soft-fuse:value, where value is in hex.
soft_fuse="$(echo "${soft_fuse_output}" | \
sed -E -n 's/Soft-fuse:(0[xX][0-9a-fA-F]+)/\1/p')"
if [[ -z "${soft_fuse}" ]]; then
die "Could not parse Soft-fuse value from output: '${soft_fuse_output}'"
fi
forbidden_set="$((soft_fuse & forbidden_bit_mask))"
if [[ "${forbidden_set}" != 0 ]]; then
local forbidden_hex
forbidden_hex="$(printf %#x "${forbidden_set}")"
die "${image}: Forbidden AMD PSP soft-fuse bits set: ${forbidden_hex}"
fi
missing_set="$((~soft_fuse & required_bit_mask))"
if [[ "${missing_set}" != 0 ]]; then
local missing_hex
missing_hex="$(printf %#x "${missing_set}")"
die "${image}: Required AMD PSP soft-fuse bits not set: ${missing_hex}"
fi
done
}
main "$@"