| #!/bin/bash |
| |
| # Copyright 2019 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. |
| |
| set -e |
| |
| # nocturne does not support unibuild, so the cros_config command will exit |
| # with error and not print a board. |
| readonly _BOARD="$(cros_config /fingerprint board || true)" |
| |
| # TODO(b/149590275): remove once fixed |
| if [[ "${_BOARD}" == "bloonchipper" ]]; then |
| readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED="$(cat <<SETVAR |
| Flash protect flags: 0x0000040f wp_gpio_asserted ro_at_boot ro_now rollback_now all_now |
| Valid flags: 0x0000003f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT |
| Writable flags: 0x00000000 |
| SETVAR |
| )" |
| else |
| readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED="$(cat <<SETVAR |
| Flash protect flags: 0x0000000b wp_gpio_asserted ro_at_boot ro_now |
| Valid flags: 0x0000003f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT |
| Writable flags: 0x00000004 all_now |
| SETVAR |
| )" |
| fi |
| |
| if [[ "${_BOARD}" == "bloonchipper" ]]; then |
| readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED_RO="$(cat <<SETVAR |
| Flash protect flags: 0x0000000b wp_gpio_asserted ro_at_boot ro_now |
| Valid flags: 0x0000003f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT |
| Writable flags: 0x00000004 all_now |
| SETVAR |
| )" |
| else |
| readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED_RO="${_FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED}" |
| fi |
| |
| readonly _FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_DISABLED="$(cat <<SETVAR |
| Flash protect flags: 0x00000000 |
| Valid flags: 0x0000003f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT |
| Writable flags: 0x00000001 ro_at_boot |
| SETVAR |
| )" |
| |
| # TODO(b/149590275): remove once fixed |
| if [[ "${_BOARD}" == "bloonchipper" ]]; then |
| readonly _FLASHPROTECT_OUTPUT_HW_WRITE_PROTECT_DISABLED_AND_SW_WRITE_PROTECT_ENABLED="$(cat <<SETVAR |
| Flash protect flags: 0x00000407 ro_at_boot ro_now rollback_now all_now |
| Valid flags: 0x0000003f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT |
| Writable flags: 0x00000000 |
| SETVAR |
| )" |
| else |
| readonly _FLASHPROTECT_OUTPUT_HW_WRITE_PROTECT_DISABLED_AND_SW_WRITE_PROTECT_ENABLED="$(cat <<SETVAR |
| Flash protect flags: 0x00000003 ro_at_boot ro_now |
| Valid flags: 0x0000003f wp_gpio_asserted ro_at_boot ro_now all_now STUCK INCONSISTENT |
| Writable flags: 0x00000000 |
| SETVAR |
| )" |
| fi |
| |
| # SYSTEM_IS_LOCKED |
| # SYSTEM_JUMP_ENABLED |
| # SYSTEM_JUMPED_TO_CURRENT_IMAGE |
| # See https://chromium.googlesource.com/chromiumos/platform/ec/+/10fe09bf9aaf59213d141fc1d479ed259f786049/include/ec_commands.h#1865 |
| readonly _SYSINFO_SYSTEM_IS_LOCKED_FLAGS="0x0000000d" |
| |
| if [[ "${_BOARD}" == "bloonchipper" ]]; then |
| readonly _ROLLBACK_FLASH_OFFSET="0x20000" |
| else |
| readonly _ROLLBACK_FLASH_OFFSET="0xe0000" |
| fi |
| |
| readonly _FP_FRAME_RAW_ACCESS_DENIED_ERROR="$(cat <<SETVAR |
| EC result 4 (ACCESS_DENIED) |
| Failed to get FP sensor frame |
| SETVAR |
| )" |
| |
| readonly _FW_NAMES="rb0 rb1 rb9 dev" |
| readonly _FW_TYPES="ro rw" |
| |
| flash_rw_firmware() { |
| local fw_file="${1}" |
| check_file_exists "${fw_file}" |
| flashrom --noverify-all -V -p ec:type=fp -i EC_RW -w "${fw_file}" |
| } |
| |
| get_ectool_output_val() { |
| local key="${1}" |
| local ectool_output="${2}" |
| echo "${ectool_output}" | grep "${key}" | sed "s#${key}:[[:space:]]*\.*##" |
| } |
| |
| run_ectool_cmd() { |
| local ectool_output |
| ectool_output="$(ectool --name=cros_fp "${@}")" |
| if [[ $? -ne 0 ]]; then |
| echo "Failed to run ectool cmd: ${@}" |
| exit 1 |
| fi |
| echo "${ectool_output}" |
| } |
| |
| run_ectool_cmd_ignoring_error() { |
| ectool --name=cros_fp "${@}" || true |
| } |
| |
| add_entropy() { |
| run_ectool_cmd "addentropy" "${@}" |
| } |
| |
| reboot_ec() { |
| # TODO(b/116396469): The reboot_ec command returns an error even on success. |
| run_ectool_cmd_ignoring_error "reboot_ec" |
| sleep 2 |
| } |
| |
| reboot_ec_to_ro() { |
| # TODO(b/116396469): The reboot_ec command returns an error even on success. |
| run_ectool_cmd_ignoring_error "reboot_ec" |
| sleep 0.5 |
| run_ectool_cmd "rwsigaction" "abort" |
| sleep 2 |
| } |
| |
| get_raw_fpframe() { |
| run_ectool_cmd "fpframe" "raw" |
| } |
| |
| check_raw_fpframe_fails() { |
| local stderr_output_file="$(mktemp)" |
| # Using sub-shell since we have "set -e" enabled |
| if (get_raw_fpframe 2> "${stderr_output_file}"); then |
| echo "Firmware should not allow getting raw fpframe" |
| exit 1 |
| fi |
| |
| local stderr_output="$(cat "${stderr_output_file}")" |
| if [[ "${stderr_output}" != "${_FP_FRAME_RAW_ACCESS_DENIED_ERROR}" ]]; then |
| echo "raw fpframe command returned unexpected value" |
| echo "stderr_output: ${stderr_output}" |
| exit 1 |
| fi |
| } |
| |
| read_from_flash() { |
| local output_file="${1}" |
| run_ectool_cmd "flashread" "${_ROLLBACK_FLASH_OFFSET}" "0x1000" "${output_file}" |
| } |
| |
| read_from_flash_in_bootloader_mode_without_modifying_RDP_level() { |
| local output_file="${1}" |
| flash_fp_mcu --noservices --read --noremove_flash_read_protect \ |
| "${output_file}" |
| } |
| |
| read_from_flash_in_bootloader_mode_while_setting_RDP_to_level_0() { |
| local output_file="${1}" |
| flash_fp_mcu --noservices --read "${output_file}" |
| } |
| |
| |
| get_sysinfo_flags() { |
| run_ectool_cmd "sysinfo" "flags" |
| } |
| |
| get_running_firmware_copy() { |
| local ectool_output |
| ectool_output="$(run_ectool_cmd "version")" |
| get_ectool_output_val "Firmware copy" "${ectool_output}" |
| } |
| |
| _get_firmware_version() { |
| local fw_type="${1}" |
| local ectool_output |
| ectool_output="$(run_ectool_cmd "version")" |
| get_ectool_output_val "${fw_type} version" "${ectool_output}" |
| } |
| |
| get_rw_firmware_version() { |
| _get_firmware_version "RW" |
| } |
| |
| get_ro_firmware_version() { |
| _get_firmware_version "RO" |
| } |
| |
| _get_rollback_info() { |
| run_ectool_cmd "rollbackinfo" |
| } |
| |
| get_rollback_block_id() { |
| get_ectool_output_val "Rollback block id" "$(_get_rollback_info)" |
| } |
| |
| get_rollback_min_version() { |
| get_ectool_output_val "Rollback min version" "$(_get_rollback_info)" |
| } |
| |
| get_rollback_rw_version() { |
| get_ectool_output_val "RW rollback version" "$(_get_rollback_info)" |
| } |
| |
| _check_rollback_matches() { |
| local rb_type="${1}" |
| local expected="${2}" |
| local rb_info |
| rb_info="$(get_rollback_${rb_type})" |
| if [[ "${rb_info}" != "${expected}" ]]; then |
| echo "Rollback ${rb_type} does not match, expected: ${expected}, actual: ${rb_info}" |
| exit 1 |
| fi |
| } |
| |
| check_rollback_block_id_matches() { |
| _check_rollback_matches "block_id" "${1}" |
| } |
| |
| check_rollback_min_version_matches() { |
| _check_rollback_matches "min_version" "${1}" |
| } |
| |
| check_rollback_rw_version_matches() { |
| _check_rollback_matches "rw_version" "${1}" |
| } |
| |
| check_is_rollback_set_to_initial_val() { |
| check_rollback_block_id_matches "1" |
| check_rollback_min_version_matches "0" |
| check_rollback_rw_version_matches "0" |
| } |
| |
| check_rollback_is_unset() { |
| check_rollback_block_id_matches "0" |
| check_rollback_min_version_matches "0" |
| check_rollback_rw_version_matches "0" |
| } |
| |
| check_file_exists() { |
| if [[ ! -f "${1}" ]]; then |
| echo "Cannot find file: ${1}" |
| exit 1 |
| fi |
| } |
| |
| check_running_rw_firmware() { |
| local fw_copy |
| fw_copy="$(get_running_firmware_copy)" |
| if [[ "${fw_copy}" != "RW" ]]; then |
| echo "Not running RW copy of firmware" |
| exit 1 |
| fi |
| } |
| |
| check_running_ro_firmware() { |
| local fw_copy |
| fw_copy="$(get_running_firmware_copy)" |
| if [[ "${fw_copy}" != "RO" ]]; then |
| echo "Not running RO copy of firmware" |
| exit 1 |
| fi |
| } |
| |
| _check_has_mp_firmware_type() { |
| local fw_type="${1}" |
| local fw_version |
| fw_version="$(get_${fw_type}_firmware_version)" |
| |
| # The MP version string is not "special", so we compare against all the |
| # "special" version strings and only succeed if it doesn't match any of them. |
| for fw_name in ${_FW_NAMES}; do |
| if [[ "${fw_version}" == *.${fw_name} ]]; then |
| echo "Not running MP ${fw_type} firmware: ${fw_version}" |
| exit 1 |
| fi |
| done |
| } |
| |
| check_has_mp_ro_firmware() { |
| _check_has_mp_firmware_type "ro" |
| } |
| |
| check_has_mp_rw_firmware() { |
| _check_has_mp_firmware_type "rw" |
| } |
| |
| # generate check_has_dev_rw_firmware/check_has_dev_ro_firmware, etc |
| for fw_name in ${_FW_NAMES}; do |
| for fw_type in ${_FW_TYPES}; do |
| eval " |
| check_has_${fw_name}_${fw_type}_firmware() { |
| local fw_version |
| fw_version=\"\$(get_${fw_type}_firmware_version)\" |
| if [[ \"\${fw_version}\" != *.${fw_name} ]]; then |
| echo \"Not running ${fw_name} ${fw_type} firmware: \${fw_version}\" |
| exit 1 |
| fi |
| } |
| " |
| done |
| done |
| |
| get_flashprotect_status() { |
| run_ectool_cmd "flashprotect" |
| } |
| |
| enable_sw_write_protect() { |
| # TODO(b/116396469): The reboot_ec command returns an error even on success. |
| run_ectool_cmd_ignoring_error "flashprotect" "enable" |
| |
| # TODO(b/116396469): "flashprotect enable" command is slow, so wait for |
| # it to complete before attempting to reboot. |
| sleep 2 |
| |
| reboot_ec |
| } |
| |
| disable_sw_write_protect() { |
| run_ectool_cmd "flashprotect" "disable" |
| } |
| |
| _get_hw_write_protect_state() { |
| local output |
| # NOTE: "wspw_cur" stands for "write protect switch current" |
| output="$(crossystem wpsw_cur)" |
| if [[ $? -ne 0 ]]; then |
| echo "Error getting hardware write protect state" |
| exit 1 |
| fi |
| echo "${output}" |
| } |
| |
| check_hw_write_protect_enabled() { |
| local output |
| output="$(_get_hw_write_protect_state)" |
| if [[ "${output}" -ne 1 ]]; then |
| echo "Expected HW write protect to be enabled, but it is not" |
| exit 1 |
| fi |
| } |
| |
| check_hw_write_protect_disabled() { |
| local output |
| output="$(_get_hw_write_protect_state)" |
| echo "output: ${output}" |
| if [[ "${output}" -ne 0 ]]; then |
| echo "Expected HW write protect to be disabled, but it is not" |
| exit 1 |
| fi |
| } |
| |
| check_hw_and_sw_write_protect_enabled() { |
| local output |
| output="$(get_flashprotect_status)" |
| |
| if [[ "${output}" != "${_FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED}" ]]; then |
| echo "Incorrect flashprotect state: ${output}" |
| echo "Make sure HW write protect is enabled (wp_gpio_asserted)" |
| exit 1 |
| fi |
| } |
| |
| check_hw_and_sw_write_protect_enabled_ro() { |
| local output |
| output="$(get_flashprotect_status)" |
| |
| if [[ "${output}" != "${_FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_ENABLED_RO}" ]]; then |
| echo "Incorrect flashprotect state: ${output}" |
| echo "Make sure HW write protect is enabled (wp_gpio_asserted)" |
| exit 1 |
| fi |
| } |
| |
| check_hw_and_sw_write_protect_disabled() { |
| local output |
| output="$(get_flashprotect_status)" |
| |
| if [[ "${output}" != "${_FLASHPROTECT_OUTPUT_HW_AND_SW_WRITE_PROTECT_DISABLED}" ]]; then |
| echo "Incorrect flashprotect state: ${output}" |
| echo "Make sure HW write protect is disabled" |
| exit 1 |
| fi |
| } |
| |
| check_hw_write_protect_disabled_and_sw_write_protect_enabled() { |
| local output |
| output="$(get_flashprotect_status)" |
| |
| if [[ "${output}" != \ |
| "${_FLASHPROTECT_OUTPUT_HW_WRITE_PROTECT_DISABLED_AND_SW_WRITE_PROTECT_ENABLED}" ]]; then |
| echo "Incorrect flashprotect state: ${output}" |
| echo "Make sure HW write protect is disabled and SW write protect is enabled" |
| exit 1 |
| fi |
| } |
| |
| check_fingerprint_task_is_running() { |
| run_ectool_cmd "fpinfo" |
| } |
| |
| check_fingerprint_task_is_not_running() { |
| if (check_fingerprint_task_is_running) ; then |
| echo "Fingerprint task should not be running" |
| exit 1 |
| fi |
| } |
| |
| check_firmware_is_functional() { |
| run_ectool_cmd "version" |
| } |
| |
| check_firmware_is_not_functional() { |
| if (check_firmware_is_functional); then |
| echo "Firmware should not be responding to commands" |
| exit 1 |
| fi |
| } |
| |
| check_files_match() { |
| cmp $1 $2 |
| if [[ $? -ne 0 ]]; then |
| echo "Expected files to match, but they do not" |
| exit 1 |
| fi |
| } |
| |
| check_files_do_not_match() { |
| if (check_files_match); then |
| echo "Expected files to not match, but they do" |
| exit 1 |
| fi |
| } |
| |
| get_file_size() { |
| stat --printf %s "${1}" |
| } |
| |
| check_file_size_equals_zero() { |
| local file_size="$(get_file_size ${1})" |
| if [[ "${file_size}" -ne 0 ]]; then |
| echo "File is not empty" |
| exit 1 |
| fi |
| } |
| |
| check_file_contains_all_0xFF_bytes() { |
| local tmp_file="all_0xff.bin" |
| local file_to_compare="$1" |
| local file_expected_byte_size="$2" |
| # create file full of zeros and then replace with 0xFF |
| dd if='/dev/zero' bs=1 count="${file_expected_byte_size}" | \ |
| sed 's#\x00#\xFF#g' > "${tmp_file}" |
| |
| check_files_match "${file_to_compare}" "${tmp_file}" |
| |
| rm -rf "${tmp_file}" |
| } |
| |
| check_system_is_locked() { |
| local flags |
| flags="$(get_sysinfo_flags)" |
| if [[ "${flags}" != "${_SYSINFO_SYSTEM_IS_LOCKED_FLAGS}" ]]; then |
| echo "sysinfo flags do not match. expected: "\ |
| "${_SYSINFO_SYSTEM_IS_LOCKED_FLAGS}, actual: ${flags}" |
| exit 1 |
| fi |
| } |