1#!/bin/bash 2 3# Copyright 2019 The Chromium OS Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7set -e 8 9# nocturne does not support unibuild, so the cros_config command will exit 10# with error and not print a board. 11readonly _BOARD="$(cros_config /fingerprint board || true)" 12 13# TODO(b/149590275): remove once fixed 14if [[ "${_BOARD}" == "bloonchipper" ]]; then 15 readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED="$(cat <<SETVAR 16Flash protect flags: 0x0000040f wp_gpio_asserted ro_at_boot ro_now rollback_now all_now 17Valid flags: 0x0000083f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT UNKNOWN_ERROR 18Writable flags: 0x00000000 19SETVAR 20 )" 21else 22 readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED="$(cat <<SETVAR 23Flash protect flags: 0x0000000b wp_gpio_asserted ro_at_boot ro_now 24Valid flags: 0x0000083f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT UNKNOWN_ERROR 25Writable flags: 0x00000004 all_now 26SETVAR 27 )" 28fi 29 30readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED_RO="$(cat <<SETVAR 31Flash protect flags: 0x0000000b wp_gpio_asserted ro_at_boot ro_now 32Valid flags: 0x0000003f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT 33Writable flags: 0x00000004 all_now 34SETVAR 35)" 36 37readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_DISABLED="$(cat <<SETVAR 38Flash protect flags: 0x00000000 39Valid flags: 0x0000083f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT UNKNOWN_ERROR 40Writable flags: 0x00000001 ro_at_boot 41SETVAR 42)" 43 44# TODO(b/149590275): remove once fixed 45if [[ "${_BOARD}" == "bloonchipper" ]]; then 46 readonly _FLASHPROTECT_OUTPUT_HW_WRITE_PROTECT_DISABLED_AND_SW_WRITE_PROTECT_ENABLED="$(cat <<SETVAR 47Flash protect flags: 0x00000407 ro_at_boot ro_now rollback_now all_now 48Valid flags: 0x0000083f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT UNKNOWN_ERROR 49Writable flags: 0x00000000 50SETVAR 51)" 52else 53 readonly _FLASHPROTECT_OUTPUT_HW_WRITE_PROTECT_DISABLED_AND_SW_WRITE_PROTECT_ENABLED="$(cat <<SETVAR 54Flash protect flags: 0x00000003 ro_at_boot ro_now 55Valid flags: 0x0000083f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT UNKNOWN_ERROR 56Writable flags: 0x00000000 57SETVAR 58 )" 59fi 60 61# SYSTEM_IS_LOCKED 62# SYSTEM_JUMP_ENABLED 63# SYSTEM_JUMPED_TO_CURRENT_IMAGE 64# See https://chromium.googlesource.com/chromiumos/platform/ec/+/10fe09bf9aaf59213d141fc1d479ed259f786049/include/ec_commands.h#1865 65readonly _SYSINFO_SYSTEM_IS_LOCKED_FLAGS="0x0000000d" 66 67if [[ "${_BOARD}" == "bloonchipper" ]]; then 68 readonly _ROLLBACK_FLASH_OFFSET="0x20000" 69else 70 readonly _ROLLBACK_FLASH_OFFSET="0xe0000" 71fi 72 73readonly _FP_FRAME_RAW_ACCESS_DENIED_ERROR="$(cat <<SETVAR 74EC result 4 (ACCESS_DENIED) 75Failed to get FP sensor frame 76SETVAR 77)" 78 79readonly _FP_FRAME_RAW_ACCESS_DENIED_ERROR2="$(cat <<SETVAR 80ioctl -1, errno 13 (Permission denied), EC result 255 (<unknown>) 81ioctl -1, errno 13 (Permission denied), EC result 255 (<unknown>) 82ioctl -1, errno 13 (Permission denied), EC result 255 (<unknown>) 83Failed to get FP sensor frame 84SETVAR 85)" 86 87readonly _FW_NAMES="rb0 rb1 rb9 dev" 88readonly _FW_TYPES="ro rw" 89 90flash_rw_firmware() { 91 local fw_file="${1}" 92 check_file_exists "${fw_file}" 93 flashrom --noverify-all -V -p ec:type=fp -i EC_RW -w "${fw_file}" 94} 95 96get_ectool_output_val() { 97 local key="${1}" 98 local ectool_output="${2}" 99 echo "${ectool_output}" | grep "${key}" | sed "s#${key}:[[:space:]]*\.*##" 100} 101 102run_ectool_cmd() { 103 local ectool_output 104 ectool_output="$(ectool --name=cros_fp "${@}")" 105 if [[ $? -ne 0 ]]; then 106 echo "Failed to run ectool cmd: ${@}" 107 exit 1 108 fi 109 echo "${ectool_output}" 110} 111 112run_ectool_cmd_ignoring_error() { 113 ectool --name=cros_fp "${@}" || true 114} 115 116add_entropy() { 117 run_ectool_cmd "addentropy" "${@}" 118} 119 120reboot_ec() { 121 # TODO(b/116396469): The reboot_ec command returns an error even on success. 122 run_ectool_cmd_ignoring_error "reboot_ec" 123 sleep 2 124} 125 126reboot_ec_to_ro() { 127 # TODO(b/116396469): The reboot_ec command returns an error even on success. 128 run_ectool_cmd_ignoring_error "reboot_ec" 129 sleep 0.5 130 run_ectool_cmd "rwsigaction" "abort" 131 sleep 2 132} 133 134get_raw_fpframe() { 135 run_ectool_cmd "fpframe" "raw" 136} 137 138check_raw_fpframe_fails() { 139 local stderr_output_file="$(mktemp)" 140 # Using sub-shell since we have "set -e" enabled 141 if (get_raw_fpframe 2> "${stderr_output_file}"); then 142 echo "Firmware should not allow getting raw fpframe" 143 exit 1 144 fi 145 146 local stderr_output="$(cat "${stderr_output_file}")" 147 if [[ "${stderr_output}" != "${_FP_FRAME_RAW_ACCESS_DENIED_ERROR}" && \ 148 "${stderr_output}" != "${_FP_FRAME_RAW_ACCESS_DENIED_ERROR2}" ]]; then 149 echo "raw fpframe command returned unexpected value" 150 echo "stderr_output: ${stderr_output}" 151 exit 1 152 fi 153} 154 155read_from_flash() { 156 local output_file="${1}" 157 run_ectool_cmd "flashread" "${_ROLLBACK_FLASH_OFFSET}" "0x1000" "${output_file}" 158} 159 160read_from_flash_in_bootloader_mode_without_modifying_RDP_level() { 161 local output_file="${1}" 162 flash_fp_mcu --noservices --read --noremove_flash_read_protect \ 163 "${output_file}" 164} 165 166read_from_flash_in_bootloader_mode_while_setting_RDP_to_level_0() { 167 local output_file="${1}" 168 flash_fp_mcu --noservices --read "${output_file}" 169} 170 171 172get_sysinfo_flags() { 173 run_ectool_cmd "sysinfo" "flags" 174} 175 176get_running_firmware_copy() { 177 local ectool_output 178 ectool_output="$(run_ectool_cmd "version")" 179 get_ectool_output_val "Firmware copy" "${ectool_output}" 180} 181 182_get_firmware_version() { 183 local fw_type="${1}" 184 local ectool_output 185 ectool_output="$(run_ectool_cmd "version")" 186 get_ectool_output_val "${fw_type} version" "${ectool_output}" 187} 188 189get_rw_firmware_version() { 190 _get_firmware_version "RW" 191} 192 193get_ro_firmware_version() { 194 _get_firmware_version "RO" 195} 196 197_get_rollback_info() { 198 run_ectool_cmd "rollbackinfo" 199} 200 201get_rollback_block_id() { 202 get_ectool_output_val "Rollback block id" "$(_get_rollback_info)" 203} 204 205get_rollback_min_version() { 206 get_ectool_output_val "Rollback min version" "$(_get_rollback_info)" 207} 208 209get_rollback_rw_version() { 210 get_ectool_output_val "RW rollback version" "$(_get_rollback_info)" 211} 212 213_check_rollback_matches() { 214 local rb_type="${1}" 215 local expected="${2}" 216 local rb_info 217 rb_info="$(get_rollback_${rb_type})" 218 if [[ "${rb_info}" != "${expected}" ]]; then 219 echo "Rollback ${rb_type} does not match, expected: ${expected}, actual: ${rb_info}" 220 exit 1 221 fi 222} 223 224check_rollback_block_id_matches() { 225 _check_rollback_matches "block_id" "${1}" 226} 227 228check_rollback_min_version_matches() { 229 _check_rollback_matches "min_version" "${1}" 230} 231 232check_rollback_rw_version_matches() { 233 _check_rollback_matches "rw_version" "${1}" 234} 235 236check_is_rollback_set_to_initial_val() { 237 check_rollback_block_id_matches "1" 238 check_rollback_min_version_matches "0" 239 check_rollback_rw_version_matches "0" 240} 241 242check_rollback_is_unset() { 243 check_rollback_block_id_matches "0" 244 check_rollback_min_version_matches "0" 245 check_rollback_rw_version_matches "0" 246} 247 248check_file_exists() { 249 if [[ ! -f "${1}" ]]; then 250 echo "Cannot find file: ${1}" 251 exit 1 252 fi 253} 254 255check_running_rw_firmware() { 256 local fw_copy 257 fw_copy="$(get_running_firmware_copy)" 258 if [[ "${fw_copy}" != "RW" ]]; then 259 echo "Not running RW copy of firmware" 260 exit 1 261 fi 262} 263 264check_running_ro_firmware() { 265 local fw_copy 266 fw_copy="$(get_running_firmware_copy)" 267 if [[ "${fw_copy}" != "RO" ]]; then 268 echo "Not running RO copy of firmware" 269 exit 1 270 fi 271} 272 273_check_has_mp_firmware_type() { 274 local fw_type="${1}" 275 local fw_version 276 fw_version="$(get_${fw_type}_firmware_version)" 277 278 # The MP version string is not "special", so we compare against all the 279 # "special" version strings and only succeed if it doesn't match any of them. 280 for fw_name in ${_FW_NAMES}; do 281 if [[ "${fw_version}" == *.${fw_name} ]]; then 282 echo "Not running MP ${fw_type} firmware: ${fw_version}" 283 exit 1 284 fi 285 done 286} 287 288check_has_mp_ro_firmware() { 289 _check_has_mp_firmware_type "ro" 290} 291 292check_has_mp_rw_firmware() { 293 _check_has_mp_firmware_type "rw" 294} 295 296# generate check_has_dev_rw_firmware/check_has_dev_ro_firmware, etc 297for fw_name in ${_FW_NAMES}; do 298 for fw_type in ${_FW_TYPES}; do 299 eval " 300 check_has_${fw_name}_${fw_type}_firmware() { 301 local fw_version 302 fw_version=\"\$(get_${fw_type}_firmware_version)\" 303 if [[ \"\${fw_version}\" != *.${fw_name} ]]; then 304 echo \"Not running ${fw_name} ${fw_type} firmware: \${fw_version}\" 305 exit 1 306 fi 307 } 308 " 309 done 310done 311 312get_flashprotect_status() { 313 run_ectool_cmd "flashprotect" 314} 315 316enable_sw_write_protect() { 317 # TODO(b/116396469): The reboot_ec command returns an error even on success. 318 run_ectool_cmd_ignoring_error "flashprotect" "enable" 319 320 # TODO(b/116396469): "flashprotect enable" command is slow, so wait for 321 # it to complete before attempting to reboot. 322 sleep 2 323 324 reboot_ec 325} 326 327disable_sw_write_protect() { 328 run_ectool_cmd "flashprotect" "disable" 329} 330 331_get_hw_write_protect_state() { 332 local output 333 # NOTE: "wspw_cur" stands for "write protect switch current" 334 output="$(crossystem wpsw_cur)" 335 if [[ $? -ne 0 ]]; then 336 echo "Error getting hardware write protect state" 337 exit 1 338 fi 339 echo "${output}" 340} 341 342check_hw_write_protect_enabled() { 343 local output 344 output="$(_get_hw_write_protect_state)" 345 if [[ "${output}" -ne 1 ]]; then 346 echo "Expected HW write protect to be enabled, but it is not" 347 exit 1 348 fi 349} 350 351check_hw_write_protect_disabled() { 352 local output 353 output="$(_get_hw_write_protect_state)" 354 echo "output: ${output}" 355 if [[ "${output}" -ne 0 ]]; then 356 echo "Expected HW write protect to be disabled, but it is not" 357 exit 1 358 fi 359} 360 361check_hw_and_sw_write_protect_enabled() { 362 local output 363 output="$(get_flashprotect_status)" 364 365 if [[ "${output}" != "${_FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED}" ]]; then 366 echo "Incorrect flashprotect state: ${output}" 367 echo "Make sure HW write protect is enabled (wp_gpio_asserted)" 368 exit 1 369 fi 370} 371 372check_hw_and_sw_write_protect_enabled_ro() { 373 local output 374 output="$(get_flashprotect_status)" 375 376 if [[ "${output}" != "${_FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED_RO}" ]]; then 377 echo "Incorrect flashprotect state: ${output}" 378 echo "Make sure HW write protect is enabled (wp_gpio_asserted)" 379 exit 1 380 fi 381} 382 383check_hw_and_sw_write_protect_disabled() { 384 local output 385 output="$(get_flashprotect_status)" 386 387 if [[ "${output}" != "${_FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_DISABLED}" ]]; then 388 echo "Incorrect flashprotect state: ${output}" 389 echo "Make sure HW write protect is disabled" 390 exit 1 391 fi 392} 393 394check_hw_write_protect_disabled_and_sw_write_protect_enabled() { 395 local output 396 output="$(get_flashprotect_status)" 397 398 if [[ "${output}" != \ 399 "${_FLASHPROTECT_OUTPUT_HW_WRITE_PROTECT_DISABLED_AND_SW_WRITE_PROTECT_ENABLED}" ]]; then 400 echo "Incorrect flashprotect state: ${output}" 401 echo "Make sure HW write protect is disabled and SW write protect is enabled" 402 exit 1 403 fi 404} 405 406check_fingerprint_task_is_running() { 407 run_ectool_cmd "fpinfo" 408} 409 410check_fingerprint_task_is_not_running() { 411 if (check_fingerprint_task_is_running) ; then 412 echo "Fingerprint task should not be running" 413 exit 1 414 fi 415} 416 417check_firmware_is_functional() { 418 run_ectool_cmd "version" 419} 420 421check_firmware_is_not_functional() { 422 if (check_firmware_is_functional); then 423 echo "Firmware should not be responding to commands" 424 exit 1 425 fi 426} 427 428check_files_match() { 429 cmp $1 $2 430 if [[ $? -ne 0 ]]; then 431 echo "Expected files to match, but they do not" 432 exit 1 433 fi 434} 435 436check_files_do_not_match() { 437 if (check_files_match); then 438 echo "Expected files to not match, but they do" 439 exit 1 440 fi 441} 442 443get_file_size() { 444 stat --printf %s "${1}" 445} 446 447check_file_size_equals_zero() { 448 local file_size="$(get_file_size ${1})" 449 if [[ "${file_size}" -ne 0 ]]; then 450 echo "File is not empty" 451 exit 1 452 fi 453} 454 455check_file_contains_all_0xFF_bytes() { 456 local tmp_file="all_0xff.bin" 457 local file_to_compare="$1" 458 local file_expected_byte_size="$2" 459 # create file full of zeros and then replace with 0xFF 460 dd if='/dev/zero' bs=1 count="${file_expected_byte_size}" | \ 461 sed 's#\x00#\xFF#g' > "${tmp_file}" 462 463 check_files_match "${file_to_compare}" "${tmp_file}" 464 465 rm -rf "${tmp_file}" 466} 467 468check_system_is_locked() { 469 local flags 470 flags="$(get_sysinfo_flags)" 471 if [[ "${flags}" != "${_SYSINFO_SYSTEM_IS_LOCKED_FLAGS}" ]]; then 472 echo "sysinfo flags do not match. expected: "\ 473 "${_SYSINFO_SYSTEM_IS_LOCKED_FLAGS}, actual: ${flags}" 474 exit 1 475 fi 476} 477