• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/bash
2# Copyright 2022 The ChromiumOS Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6# Load common constants and variables.
7. "$(dirname "$0")/common.sh"
8
9# Abort on error and uninitialized variables.
10set -eu
11
12declare -A -r REQUIRED_BIT_MASKS=(
13  # Bit 58 - PSP_S0I3_RESUME_VERSTAGE - Run PSP verstage during S0i3 resume.
14  # Checks that FW images have not been tampered with when exiting S0i3.
15  [guybrush]="$((1 << 58))"
16  [zork]="0x0"
17)
18
19declare -A -r FORBIDDEN_BIT_MASKS=(
20  [guybrush]="0x0"
21  [zork]="0x0"
22)
23
24# Grunt uses an old firmware format that amdfwread cannot read.
25# See b/233787191 for skyrim.
26BOARD_IGNORE_LIST=(grunt skyrim)
27
28usage() {
29  echo "$0: Validate AMD PSP soft-fuse flags contained in a ChromeOS image." \
30    "These flags can have security implications and control debug features."
31  echo "Usage $0 <image> <board>"
32}
33
34main() {
35  if [[ $# -ne 2 ]]; then
36    usage
37    exit 1
38  fi
39
40  local image="$1"
41  local board="$2"
42
43  # Check the ignore list.
44  if [[ " ${BOARD_IGNORE_LIST[*]} " == *" ${board} "* ]]; then
45   echo "Skipping ignore-listed board ${board}"
46   exit 0
47  fi
48
49  # Mount the image.
50  local loopdev rootfs
51  if [[ -d "${image}" ]]; then
52    rootfs="${image}"
53  else
54    rootfs="$(make_temp_dir)"
55    loopdev="$(loopback_partscan "${image}")"
56    mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
57  fi
58
59  local firmware_bundle shellball_dir
60  firmware_bundle="${rootfs}/usr/sbin/chromeos-firmwareupdate"
61  shellball_dir="$(make_temp_dir)"
62
63  # Extract our firmware.
64  if ! extract_firmware_bundle "${firmware_bundle}" "${shellball_dir}"; then
65    die "Failed to extract firmware bundle"
66  fi
67
68  # Find our images.
69  declare -a images
70  readarray -t images < <(find "${shellball_dir}" -iname 'bios-*')
71
72  # Validate that all our AP FW images are AMD images.
73  local image
74  for image in "${images[@]}"; do
75    # With no args, amdfwread will just attempt to validate the FW header.
76    # On non-AMD FW this will fail, allowing us to skip non-AMD FW images.
77    if ! amdfwread "${image}" &> /dev/null; then
78      if [[ ! -v "REQUIRED_BIT_MASKS[${board}]" &&
79            ! -v "FORBIDDEN_BIT_MASKS[${board}]" ]]; then
80        # If we have an invalid FW image and don't have bitsets for this board
81        # then this isn't an AMD board, exit successfully.
82        exit 0
83      else
84        die "Found invalid AMD AP FW image"
85      fi
86    fi
87  done
88
89  # Get the board specific bit masks.
90  local required_bit_mask forbidden_bit_mask
91
92  if [[ ! -v "REQUIRED_BIT_MASKS[${board}]" ]]; then
93    die "Missing PSP required bit mask set for ${board}"
94  fi
95
96  if [[ ! -v "FORBIDDEN_BIT_MASKS[${board}]" ]]; then
97    die "Missing PSP forbidden bit mask set for ${board}"
98  fi
99
100  required_bit_mask="${REQUIRED_BIT_MASKS[${board}]}"
101  forbidden_bit_mask="${FORBIDDEN_BIT_MASKS[${board}]}"
102
103  # Check the soft-fuse bits
104  for image in "${images[@]}"; do
105    local soft_fuse soft_fuse_output forbidden_set missing_set
106    if ! soft_fuse_output="$(amdfwread --soft-fuse "${image}")"; then
107      die "'amdfwread --soft-fuse ${image}' failed"
108    fi
109
110    # Output format from amdfwread is Soft-fuse:value, where value is in hex.
111    soft_fuse="$(echo "${soft_fuse_output}" | \
112      sed -E -n 's/Soft-fuse:(0[xX][0-9a-fA-F]+)/\1/p')"
113    if [[ -z "${soft_fuse}" ]]; then
114      die "Could not parse Soft-fuse value from output: '${soft_fuse_output}'"
115    fi
116
117    forbidden_set="$((soft_fuse & forbidden_bit_mask))"
118    if [[ "${forbidden_set}" != 0 ]]; then
119      local forbidden_hex
120      forbidden_hex="$(printf %#x "${forbidden_set}")"
121      die "${image}: Forbidden AMD PSP soft-fuse bits set: ${forbidden_hex}"
122    fi
123
124    missing_set="$((~soft_fuse & required_bit_mask))"
125    if [[ "${missing_set}" != 0 ]]; then
126      local missing_hex
127      missing_hex="$(printf %#x "${missing_set}")"
128      die "${image}: Required AMD PSP soft-fuse bits not set: ${missing_hex}"
129    fi
130  done
131}
132main "$@"
133