From 2309e4fa778e9e85406a0abb65b91443b9f8aa71 Mon Sep 17 00:00:00 2001 From: Daniil Klimuk Date: Mon, 9 Sep 2024 18:32:04 +0200 Subject: [PATCH] WIP Signed-off-by: Daniil Klimuk --- include/dts-environment.sh | 13 + include/dts-functions.sh | 76 ++-- scripts/dasharo-deploy | 820 +++++++++++++++++++++++-------------- 3 files changed, 576 insertions(+), 333 deletions(-) diff --git a/include/dts-environment.sh b/include/dts-environment.sh index efd653ce..dd979fa2 100644 --- a/include/dts-environment.sh +++ b/include/dts-environment.sh @@ -108,6 +108,9 @@ declare DASHARO_REL_VER_DPP declare HEADS_REL_VER_DPP declare DASHARO_REL_VER_DPP_SEABIOS declare COMPATIBLE_EC_FW_VERSION +# and for capsules: +declare DASHARO_REL_VER_CAP +declare DASHARO_REL_VER_DPP_CAP # Links to files: declare BIOS_LINK_COMM declare BIOS_HASH_LINK_COMM @@ -122,6 +125,16 @@ declare EC_LINK_COMM declare EC_HASH_LINK_COMM declare EC_SIGN_LINK_COMM declare HEADS_LINK_DPP +# and for capsules: +declare BIOS_LINK_COMM_CAP +declare BIOS_HASH_LINK_COMM_CAP +declare BIOS_SIGN_LINK_COMM_CAP +declare BIOS_LINK_DPP_CAP +declare BIOS_HASH_LINK_DPP_CAP +declare BIOS_SIGN_LINK_DPP_CAP +declare EC_LINK_COMM_CAP +declare EC_HASH_LINK_COMM_CAP +declare EC_SIGN_LINK_COMM_CAP # Configs, are used in dasharo-deploy script: CAN_INSTALL_BIOS="false" HAVE_HEADS_FW="false" diff --git a/include/dts-functions.sh b/include/dts-functions.sh index 4052870d..bcc4cfe6 100644 --- a/include/dts-functions.sh +++ b/include/dts-functions.sh @@ -626,6 +626,7 @@ board_config() { DASHARO_REL_VER="q35/v0.2.0" # TODO: wait till the binaries will be uploaded to the server. BIOS_LINK_COMM="${FW_STORE_URL}/${DASHARO_REL_NAME}/${DASHARO_REL_VER}/" + BIOS_LINK_COMM_CAP="${FW_STORE_URL}/${DASHARO_REL_NAME}/${DASHARO_REL_VER}/" ;; *) print_error "Board model $BOARD_MODEL is currently not supported" @@ -654,6 +655,14 @@ board_config() { [ -z "$BIOS_SIGN_LINK_DPP_SEABIOS" ] && BIOS_SIGN_LINK_DPP_SEABIOS="${BIOS_HASH_LINK_DPP_SEABIOS}.sig" [ -z "$EC_HASH_LINK_COMM" ] && EC_HASH_LINK_COMM="${EC_LINK_COMM}.sha256" [ -z "$EC_SIGN_LINK_COMM" ] && EC_SIGN_LINK_COMM="${EC_HASH_LINK_COMM}.sig" + + # And for capsules as well: + [ -z "$BIOS_HASH_LINK_COMM_CAP" ] && BIOS_HASH_LINK_COMM_CAP="${BIOS_LINK_COMM_CAP}.sha256" + [ -z "$BIOS_SIGN_LINK_COMM_CAP" ] && BIOS_SIGN_LINK_COMM_CAP="${BIOS_SIGN_LINK_COMM_CAP}.sig" + [ -z "$BIOS_HASH_LINK_DPP_CAP" ] && BIOS_HASH_LINK_DPP_CAP="${BIOS_LINK_DPP_CAP}.sha256" + [ -z "$BIOS_SIGN_LINK_DPP_CAP" ] && BIOS_SIGN_LINK_DPP_CAP="${BIOS_HASH_LINK_DPP_CAP}.sig" + [ -z "$EC_HASH_LINK_COMM_CAP" ] && EC_HASH_LINK_COMM_CAP="${EC_LINK_COMM_CAP}.sha256" + [ -z "$EC_SIGN_LINK_COMM_CAP" ] && EC_SIGN_LINK_COMM_CAP="${EC_HASH_LINK_COMM_CAP}.sig" } check_flash_lock() { @@ -812,6 +821,13 @@ get_signing_keys() { } verify_artifacts() { +# This function checks downloaded files, the files that are being downloaded +# should have hashes provided on the server too. The hashes will ben downloaded +# and the binaries will be verified upon them. +# +# In case of .rom files it will be enough but capsules have additional +# protection layer built in, the binaries they provide will be verified by +# drivers, so no need to implement it here. local _type="$1" local _update_file="" local _hash_file="" @@ -819,33 +835,41 @@ verify_artifacts() { local _name="" local _sig_result="" - case ${_type} in - ec) - _update_file=$EC_UPDATE_FILE - _hash_file=$EC_HASH_FILE - _sign_file=$EC_SIGN_FILE - _name="Dasharo EC" - ;; - bios) - _update_file=$BIOS_UPDATE_FILE - _hash_file=$BIOS_HASH_FILE - _sign_file=$BIOS_SIGN_FILE - _name="Dasharo" - ;; - *) - ;; - esac - echo -n "Checking $_name firmware checksum... " - sha256sum --check <(echo "$(cat $_hash_file | cut -d ' ' -f 1)" $_update_file) >> $ERR_LOG_FILE 2>&1 - error_check "Failed to verify $_name firmware checksum" - print_ok "Verified." - if [ -n "$PLATFORM_SIGN_KEY" ]; then - echo -n "Checking $_name firmware signature... " - _sig_result="$(cat $_hash_file | gpg --verify $_sign_file - >> $ERR_LOG_FILE 2>&1)" - error_check "Failed to verify $_name firmware signature.$'\n'$_sig_result" + while [[ $# -gt 0 ]]; do + case ${_type} in + ec) + _update_file=$EC_UPDATE_FILE + _hash_file=$EC_HASH_FILE + _sign_file=$EC_SIGN_FILE + _name="Dasharo EC" + shift + ;; + bios) + _update_file=$BIOS_UPDATE_FILE + _hash_file=$BIOS_HASH_FILE + _sign_file=$BIOS_SIGN_FILE + _name="Dasharo" + shift + ;; + *) + ;; + esac + + echo -n "Checking $_name firmware checksum... " + sha256sum --check <(echo "$(cat $_hash_file | cut -d ' ' -f 1)" $_update_file) >> $ERR_LOG_FILE 2>&1 + error_check "Failed to verify $_name firmware checksum" print_ok "Verified." - fi - echo "$_sig_result" + + if [ -n "$PLATFORM_SIGN_KEY" ]; then + echo -n "Checking $_name firmware signature... " + _sig_result="$(cat $_hash_file | gpg --verify $_sign_file - >> $ERR_LOG_FILE 2>&1)" + error_check "Failed to verify $_name firmware signature.$'\n'$_sig_result" + print_ok "Verified." + fi + echo "$_sig_result" + done + + return 0 } check_intel_regions() { diff --git a/scripts/dasharo-deploy b/scripts/dasharo-deploy index eb4daa7f..83fb9484 100755 --- a/scripts/dasharo-deploy +++ b/scripts/dasharo-deploy @@ -12,82 +12,145 @@ source $DTS_FUNCS [ -z "$SYSTEM_VENDOR" ] && error_exit "SYSTEM_VENDOR not given" [ -z "$SYSTEM_MODEL" ] && error_exit "SYSTEM_MODEL not given" +# Variables used in this script: +# Currently following firmware versions are available: community, community_cap, +# dpp, dpp_cap, seabios, and heads: +declare FIRMWARE_VERSION +declare CAN_SWITCH_TO_HEADS CMD="$1" FUM="$2" +check_for_firmware_access() { +# DPP credentials are being provided outside of this script, this script only +# has to check whether the credentials give access to appropriate firmware. The +# appropriate firmware are defined by FIRMWARE_VERSION variable. + + local _firm_ver_to_check + _firm_ver_to_check=$1 + + case ${_firm_ver_to_check} in + community) + # Always available. + ;; + community_cap) + # Always available. + ;; + dpp) + # This firmware type require user to provide creds: + [ "$DPP_IS_LOGGED" == "true" ] || return 1 + + curl -sfI -u "$USER_DETAILS" -H "$CLOUD_REQUEST" "$BIOS_LINK_DPP" -o /dev/null + + [ $? -ne 0 ] && return 1 + ;; + dpp_cap) + # This firmware type require user to provide creds: + [ "$DPP_IS_LOGGED" == "true" ] || return 1 + + curl -sfI -u "$USER_DETAILS" -H "$CLOUD_REQUEST" "$BIOS_LINK_DPP_CAP" -o /dev/null + + [ $? -ne 0 ] && return 1 + ;; + seabios) + # This firmware type require user to provide creds: + [ "$DPP_IS_LOGGED" == "true" ] || return 1 + + curl -sfI -u "$USER_DETAILS" -H "$CLOUD_REQUEST" "$BIOS_LINK_DPP_SEABIOS" -o /dev/null + + [ $? -ne 0 ] && return 1 + ;; + heads) + # This firmware type require user to provide creds: + [ "$DPP_IS_LOGGED" == "true" ] || return 1 + + curl -sfI -u "$USER_DETAILS" -H "$CLOUD_REQUEST" "$HEADS_LINK_DPP" -o /dev/null + + [ $? -ne 0 ] && return 1 + ;; + esac + + return 0 +} + ask_for_version() { +# Available firmware versions are defined by FIRMWARE_VERSION variable. There +# are community and DPP ofrmwares with UEFI Capsule Update support, but they are +# for firmware updates only, but this function is being called during +# installation, so no need to mention them here. + local _option + local _might_be_comm + local _might_be_dpp + local _might_be_seabios + while : ; do echo - echo "Please, select Dasharo firmware version to install" - - # -v: True if the shell variable varname is set (has been assigned a value). + echo "Please, select Dasharo firmware version to install:" + + # Here we check if user has access to a certain version of Dasharo Firmware. + # The check consists of two stages: + # * does user platform support the fimware - BIOS_LINK_* variables are being + # checked; + # * does user has access rights to the blobs of the supported fimware - a + # call to the server with binaries is done, to check if user can download + # the blobs. if [ -n "$BIOS_LINK_COMM" ]; then - echo " c) Community version" + if check_for_firmware_access community; then + echo " c) Community version" + _might_be_comm="true" + fi fi + if [ -n "$BIOS_LINK_DPP" ]; then - if [ -n "$DPP_IS_LOGGED" ]; then + if check_for_firmware_access dpp; then echo " d) DPP version (coreboot + UEFI)" + _might_be_dpp="true" else - echo " DPP version (coreboot + UEFI) available, if you are interested, please visit https://shop.3mdeb.com/product-category/dasharo-entry-subscription/" + echo " DPP version (coreboot + UEFI) available but you don't have access" + echo " to it, if you are interested, please visit" + echo " https://shop.3mdeb.com/product-category/dasharo-pro-package/" fi fi + if [ -n "$BIOS_LINK_DPP_SEABIOS" ]; then - if [ -n "$DPP_IS_LOGGED" ]; then + if check_for_firmware_access seabios; then echo " s) DPP version (coreboot + SeaBIOS)" + _might_be_seabios="true" else - echo " DPP version (coreboot + SeaBIOS) available, if you are interested, please visit https://shop.3mdeb.com/product-category/dasharo-entry-subscription/" + echo " DPP version (coreboot + SeaBIOS) available but you don't have access" + echo " to it, if you are interested, please visit" + echo " https://shop.3mdeb.com/product-category/dasharo-pro-package/" fi fi + echo " b) Back to main menu" echo - read -r -p "Enter an option: " OPTION + read -r -p "Enter an option: " _option echo - case ${OPTION} in + # In case of several Dasharo Firmware versions supported we leave the + # decision to user: + case ${_option} in c|C|comm|community|COMMUNITY|COMM|Community) - if [ -n "$BIOS_LINK_COMM" ]; then - BIOS_LINK=$BIOS_LINK_COMM - BIOS_HASH_LINK=$BIOS_HASH_LINK_COMM - BIOS_SIGN_LINK=$BIOS_SIGN_LINK_COMM - if [ -n "$EC_LINK_COMM" ]; then - EC_LINK=$EC_LINK_COMM - EC_HASH_LINK=$EC_HASH_LINK_COMM - EC_SIGN_LINK=$EC_SIGN_LINK_COMM - fi - echo "Community version selected" - break - else - error_exit "Bad option or resignation. Returning to main menu..." - fi - ;; + if [ -n "$_might_be_comm" ]; then + print_ok "Community (Coreboot + EDK2) version selected" + FIRMWARE_VERSION="community" + break + fi + ;; d|D|dpp|DPP|Dpp) - if [ -n "$BIOS_LINK_DPP" ]; then - BIOS_LINK=$BIOS_LINK_DPP - BIOS_HASH_LINK=$BIOS_HASH_LINK_DPP - BIOS_SIGN_LINK=$BIOS_SIGN_LINK_DPP - if [ -n "$EC_LINK_DPP" ]; then - EC_LINK=$EC_LINK_DPP - EC_HASH_LINK=$EC_HASH_LINK_DPP - # shellcheck disable=SC2034 - EC_SIGN_LINK=$EC_SIGN_LINK_DPP - fi - echo "Dasharo Entry Subscription (coreboot + edk2) version selected" - break - else - error_exit "Bad option. Returning to main menu..." - fi - ;; + if [ -n "$_might_be_dpp" ]; then + print_ok "Subscription version (cooreboot + EDK2) selected" + FIRMWARE_VERSION="dpp" + break + fi + ;; s|S|sea|seabios|SeaBIOS) - if [ -n "$BIOS_LINK_DPP_SEABIOS" ]; then - BIOS_LINK=$BIOS_LINK_DPP_SEABIOS - BIOS_HASH_LINK=$BIOS_HASH_LINK_DPP_SEABIOS - BIOS_SIGN_LINK=$BIOS_SIGN_LINK_DPP_SEABIOS - echo "Dasharo Entry Subscription (coreboot + SeaBIOS) version selected" - break - else - error_exit "Bad option. Returning to main menu..." - fi - ;; + if [ -n "$_might_be_seabios" ]; then + print_ok "Subscription version (coreboot + SeaBIOS) selected" + FIRMWARE_VERSION="seabios" + break + fi + ;; b|B) echo "Returning to main menu..." exit 0 @@ -96,9 +159,178 @@ ask_for_version() { ;; esac done + + return 0 +} + +choose_version(){ +# This function is used for determining Dasharo firmware update version and is +# being used during updates only. We do not ask user to choose firmware update +# versions compared to installation workflow (check ask_for_version function), +# instead we have some priorities: +# 1) Check if Dasharo Heads Firmware available, use it if yes; +# 2) Check if Dasharo EDK2 Firmware available, use it if yes; +# 3) Use Dasharo Community Firmware; +# +# Capsules have higher priority over simple binaries. +# +# TODO: Currently we do not have clear and concise update mechanisms (e.g. what +# and when a specific firmware version can be used, how to handle revisions of +# firmware). + + if [ -n "$HAVE_HEADS_FW" ]; then + if $(check_for_firmware_access heads); then + CAN_SWITCH_TO_HEADS="true" + FIRMWARE_VERSION="heads" + + return 0 + else + print_warning "Dasharo Heads firmware version is available, but your" + print_warning "subscription does not give you the access to this firmware." + print_warning "If you are interested, please visit https://shop.3mdeb.com/product-category/dasharo-pro-package/" + fi + fi + + if [ -n "$DASHARO_REL_VER_DPP_CAP" ]; then + if $(check_for_firmware_access dpp_cap); then + FIRMWARE_VERSION="dpp_cap" + + return 0 + else + print_warning "Dasharo Subscription firmware version with UEFI Capsule Update" + print_warning "is available, but your subscription does not give you the access" + print_warning "to this firmware." + print_warning "If you are interested, please visit https://shop.3mdeb.com/product-category/dasharo-pro-package/" + fi + fi + + if [ -n "$DASHARO_REL_VER_DPP" ]; then + if $(check_for_firmware_access dpp); then + FIRMWARE_VERSION="dpp" + + return 0 + else + print_warning "Dasharo Subscription firmware version is available, but your" + print_warning "subscription does not give you the access to this firmware." + print_warning "If you are interested, please visit https://shop.3mdeb.com/product-category/dasharo-pro-package/" + fi + fi + + if [ -n "$DASHARO_REL_VER_CAP" ]; then + FIRMWARE_VERSION="community_cap" + + return 0 + fi + + # Last resort: + FIRMWARE_VERSION="community" + + return 0 +} + +prepare_env() { +# This function sets all needed variables after user have answered all needed +# questions and before script does any work. This includes: + local _prepare_for + _prepare_for="$1" + + # If firmware is being installed - user should choose what to install, if + # firmware is being updated - final version is being choosed algorit + if [ "$_prepare_for" == "update" ]; then + choose_version + elif [ "$_prepare_for" == "install" ]; then + ask_for_version + fi + + # This is the key variable for this function, should be set either by + # choose_version or by ask_for_version: + if [ -z "$FIRMWARE_VERSION" ]; then + return 1 + fi + + # When board_config returns, we have a set of *_LINK_* variables holding links + # to artifacts for our board. Now we need to decide which links to use (some + # platforms may support several firmware types). The links being used are + # determined bising on FIRMWARE_VERSION: + if [ "$FIRMWARE_VERSION" == "community" ]; then + BIOS_LINK=$BIOS_LINK_COMM + BIOS_HASH_LINK=$BIOS_HASH_LINK_COMM + BIOS_SIGN_LINK=$BIOS_SIGN_LINK_COMM + + UPDATE_VERSION="$DASHARO_REL_VER" + + # Check EC link additionally, not all platforms have Embedded Controllers: + if [ -n $"EC_LINK_COMM" ]; then + EC_LINK=$EC_LINK_COMM + EC_HASH_LINK=$EC_HASH_LINK_COMM + EC_SIGN_LINK=$EC_SIGN_LINK_COMM + fi + + return 0 + elif [ "$FIRMWARE_VERSION" == "community_cap" ]; then + BIOS_LINK=$BIOS_LINK_COMM_CAP + BIOS_HASH_LINK=$BIOS_HASH_LINK_COMM_CAP + BIOS_SIGN_LINK=$BIOS_SIGN_LINK_COMM_CAP + + UPDATE_VERSION="$DASHARO_REL_VER_CAP" + + # Check EC link additionally, not all platforms have Embedded Controllers: + if [ -n "$EC_LINK_COMM" ]; then + EC_LINK=$EC_LINK_COMM_CAP + EC_HASH_LINK=$EC_HASH_LINK_COMM_CAP + EC_SIGN_LINK=$EC_SIGN_LINK_COMM_CAP + fi + + return 0 + elif [ "$FIRMWARE_VERSION" == "dpp" ]; then + BIOS_LINK=$BIOS_LINK_DPP + BIOS_HASH_LINK=$BIOS_HASH_LINK_DPP + BIOS_SIGN_LINK=$BIOS_SIGN_LINK_DPP + + UPDATE_VERSION="$DASHARO_REL_VER_DPP" + + # Check EC link additionally, not all platforms have Embedded Controllers: + if [ -n "$EC_LINK_DPP" ]; then + EC_LINK=$EC_LINK_DPP + EC_HASH_LINK=$EC_HASH_LINK_DPP + EC_SIGN_LINK=$EC_SIGN_LINK_DPP + fi + + return 0 + elif [ "$FIRMWARE_VERSION" == "dpp_cap" ]; then + BIOS_LINK=$BIOS_LINK_DPP_CAP + BIOS_HASH_LINK=$BIOS_HASH_LINK_DPP_CAP + BIOS_SIGN_LINK=$BIOS_SIGN_LINK_DPP_CAP + + UPDATE_VERSION="$DASHARO_REL_VER_DPP_CAP" + + # Check EC link additionally, not all platforms have Embedded Controllers: + if [ -n "$EC_LINK_DPP" ]; then + EC_LINK=$EC_LINK_DPP_CAP + EC_HASH_LINK=$EC_HASH_LINK_DPP_CAP + EC_SIGN_LINK=$EC_SIGN_LINK_DPP_CAP + fi + + return 0 + elif [ "$FIRMWARE_VERSION" == "seabios" ]; the + BIOS_LINK=$BIOS_LINK_DPP_SEABIOS + BIOS_HASH_LINK=$BIOS_HASH_LINK_DPP_SEABIOS + BIOS_SIGN_LINK=$BIOS_SIGN_LINK_DPP_SEABIOS + + return 0 + fi + + # Must not get here. If it gets here - the above variables are empty and + # script will not be able to continue. + return 1 } -display_flashing_warning() { +display_warning() { +# This function shows user some inf. about platform and binaries and asks if the +# deployment process should be continued. + local _option + _option="$1" + while : ; do echo print_warning "Please verify detected hardware!" @@ -113,15 +345,16 @@ display_flashing_warning() { if [ -n "$BOARD_MODEL" ]; then echo "Board model: $BOARD_MODEL" fi + echo - read -r -p "Does it match your actual specification? (Y|n) " OPTION + read -r -p "Does it match your actual specification? (Y|n) " _option echo - case ${OPTION} in + case ${_option} in yes|y|Y|Yes|YES) break ;; - n|N) + n|N|no|NO|No) echo "Returning to main menu..." exit 0 ;; @@ -131,7 +364,8 @@ display_flashing_warning() { done while : ; do - echo "Following firmware will be used to install Dasharo" + echo "Following firmware will be used to deploy Dasharo:" + if [ -n "$BIOS_LINK" ]; then local _bios_hash _bios_hash="$(cat $BIOS_HASH_FILE | cut -d ' ' -f 1)" @@ -139,6 +373,7 @@ display_flashing_warning() { echo " - link: $BIOS_LINK" echo " - hash: $_bios_hash" fi + if [ -n "$EC_LINK" ]; then local _ec_hash _ec_hash="$(cat $EC_HASH_FILE | cut -d ' ' -f 1)" @@ -146,29 +381,24 @@ display_flashing_warning() { echo " - link: $EC_LINK" echo " - hash: $_ec_hash" fi + echo echo "You can learn more about this release on: https://docs.dasharo.com/" - if check_if_dasharo; then - echo - read -r -p "Do you want to update Dasharo firmware on your hardware? (Y|n) " OPTION - echo - else - echo - if [ "$CAN_INSTALL_BIOS" == "false" ] && [ "$SYSTEM_VENDOR" == "Notebook" ]; then - echo "Notebook supports installation of only EC firmware!" - echo "Dasharo BIOS will have to be flashed manually. More on:" - echo "https://docs.dasharo.com/unified/novacustom/initial-deployment/" - fi - read -r -p "Do you want to install Dasharo firmware on your hardware? (Y|n) " OPTION - echo + if ! check_if_dasharo && \ + [ "$CAN_INSTALL_BIOS" == "false" ] \ + && [ "$SYSTEM_VENDOR" == "Notebook" ] \ + && [ "$SYSTEM_MODEL" == "V54x_6x_TU" ]; then + print_warning "$SYSTEM_VENDOR $SYSTEM_MODEL supports only EC firmware deployment!" + print_warning "Dasharo BIOS will have to be flashed manually. More on:" + print_warning "https://docs.dasharo.com/unified/novacustom/initial-deployment/" fi - case ${OPTION} in + case ${_option} in yes|y|Y|Yes|YES) break ;; - n|N) + n|N|no|NO|No) echo "Returning to main menu..." exit 0 ;; @@ -176,6 +406,8 @@ display_flashing_warning() { ;; esac done + + return 0 } backup() { @@ -386,68 +618,174 @@ blob_transmission() { fi } -install_ec() { - verify_artifacts ec - echo "Installing EC..." - $FLASHROM -p "$PROGRAMMER_EC" ${FLASH_CHIP_SELECT} -w "$EC_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE - error_check "Failed to install Dasharo EC firmware" - echo "Successfully installed Dasharo EC firmware" -} - -install() { - ask_for_version - if [ "$CAN_INSTALL_BIOS" == "false" ]; then - download_ec - unset BIOS_HASH_LINK - display_flashing_warning - else - download_artifacts - display_flashing_warning +predeployment_routine() { + # Preinstallation routine: + if ! [ "$CAN_INSTALL_BIOS" == "false" && "$HAVE_EC" == "true" ]; then check_flash_lock - verify_artifacts bios - check_intel_regions check_blobs_in_binary $BIOS_UPDATE_FILE check_if_me_disabled set_intel_regions_update_params "-N --ifd -i bios" fi - if [ "$HAVE_EC" == "true" ]; then + cbfstool "$BIOS_UPDATE_FILE" extract -r COREBOOT -n config -f "$BIOS_UPDATE_CONFIG_FILE" + grep "CONFIG_VBOOT=y" "$BIOS_UPDATE_CONFIG_FILE" + HAVE_VBOOT="$?" + + if [ "$NEED_ROMHOLE_MIGRATION" = "true" ]; then + romhole_migration + fi + + if [ "$NEED_BOOTSPLASH_MIGRATION" = "true" ]; then + bootsplash_migration + fi + + if [ "$NEED_SMBIOS_MIGRATION" = "true" ]; then + smbios_migration + resign_binary + fi + + if [ "$NEED_BLOB_TRANSMISSION" = "true" ]; then + blob_transmission + fi + + + + +} + +deploy_ec_firmware() { +# This function deploys (installs or updates) downloaded EC firmware either UEFI +# capsules (updates only) and binaries. Parameters: update, install. + local _mode + _mode="$1" + + if [ "$_mode" == "update" ]; then + echo "Updating EC..." + if [ "$UPDATE_TYPE" == "capsule" ]; then + cat "$EC_UPDATE_FILE" > "$CAP_UPD_DEVICE" + else + # Following command will reset device, so the function will not quit: + $DASHARO_ECTOOL flash "$EC_UPDATE_FILE" &>> $ERR_LOG_FILE + fi + error_check "Failed to update EC firmware" + elif [ "$_mode" == "install" ]; then echo "Checking for Open Source Embedded Controller firmware" $DASHARO_ECTOOL info >> $ERR_LOG_FILE 2>&1 + if [ $? -eq 0 ]; then echo "Device has already Open Source Embedded Controller firmware, do not flash EC..." else _ec_fw_version=$($FLASHROM -p "$PROGRAMMER_EC" ${FLASH_CHIP_SELECT} | grep "Mainboard EC Version" | tr -d ' ' | cut -d ':' -f 2) + if [ "$_ec_fw_version" != "$COMPATIBLE_EC_FW_VERSION" ]; then - print_warning "EC version: $_ec_fw_version is not supported, update required" - install_ec + echo "Installing EC..." + $FLASHROM -p "$PROGRAMMER_EC" ${FLASH_CHIP_SELECT} -w "$EC_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE + error_check "Failed to install Dasharo EC firmware" + print_ok "Successfully installed Dasharo EC firmware" fi fi fi - if [ "$CAN_INSTALL_BIOS" == "true" ]; then - cbfstool "$BIOS_UPDATE_FILE" extract -r COREBOOT -n config -f "$BIOS_UPDATE_CONFIG_FILE" - grep "CONFIG_VBOOT=y" "$BIOS_UPDATE_CONFIG_FILE" - HAVE_VBOOT="$?" + return 0 +} + +deploy_firmware(){ +# This function deploys (installs or updates) downloaded firmware either UEFI +# capsules (updates only) and binaries. Parameters: update, install. + local _mode + _mode="$1" + + if [ "$_mode" == "update" ]; then + echo "Updating Dasharo firmware..." + print_warning "This may take several minutes. Please be patient and do not" + print_warning "power off your computer or touch the keyboard!" + + # Firstly we need to check, whether it is possible to use UEFI Capsule + # Update, this is the preffered way of updating: + if []; then + + # Return after updating. The below code is for flashrom updates (using + # binaries) only + return 0 + fi - if [ "$NEED_ROMHOLE_MIGRATION" = "true" ]; then - romhole_migration + # Preupdating routine: + check_flash_lock + + if [ "$HAVE_EC" == "true" ]; then + $DASHARO_ECTOOL info >> $ERR_LOG_FILE 2>&1 + error_check "Device does not have Dasharo EC firmware - cannot continue update!" + fi + + if [ "$NEED_SMMSTORE_MIGRATION" = "true" ]; then + smmstore_migration fi if [ "$NEED_BOOTSPLASH_MIGRATION" = "true" ]; then bootsplash_migration fi - if [ "$NEED_SMBIOS_MIGRATION" = "true" ]; then - smbios_migration - resign_binary + cbfstool "$BIOS_UPDATE_FILE" extract -r COREBOOT -n config -f "$BIOS_UPDATE_CONFIG_FILE" + grep -q "CONFIG_VBOOT=y" "$BIOS_UPDATE_CONFIG_FILE" + HAVE_VBOOT="$?" + + check_intel_regions + check_blobs_in_binary $BIOS_UPDATE_FILE + check_if_me_disabled + set_flashrom_update_params $BIOS_UPDATE_FILE + set_intel_regions_update_params "-N --ifd" + check_vboot_keys + + # FLASHROM_ADD_OPT_UPDATE_OVERRIDE takes priority over auto-detected update params. + # It set only by platform-specific and firmware version-specific conditions + if [ -n "$FLASHROM_ADD_OPT_UPDATE_OVERRIDE" ]; then + # To standardize the operation of the FLASHROM_ADD_OPT_UPDATE_OVERRIDE flag, + # by default it contains only the bios section, below we verify the + # downloaded binary and add more sections when they were detected after + # using the `check_blobs_in_binary` function. + set_intel_regions_update_params "$FLASHROM_ADD_OPT_UPDATE_OVERRIDE" + FLASHROM_ADD_OPT_UPDATE_OVERRIDE="$FLASHROM_ADD_OPT_REGIONS" + $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} ${FLASHROM_ADD_OPT_UPDATE_OVERRIDE} -w "$BIOS_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE + error_check "Failed to update Dasharo firmware" + else + $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} ${FLASHROM_ADD_OPT_UPDATE} -w "$BIOS_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE + error_check "Failed to update Dasharo firmware" + + if [ $BINARY_HAS_RW_B -eq 0 ]; then + echo "Updating second firmware partition..." + $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} --fmap -N -i RW_SECTION_B -w "$BIOS_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE + error_check "Failed to update second firmware partition" + fi fi - if [ "$NEED_BLOB_TRANSMISSION" = "true" ]; then - blob_transmission + # We use FLASHROM_ADD_OPT_REGIONS for updating ME and IFD. + # If FLASHROM_ADD_OPT_REGIONS remains the same after + # set_intel_regions_update_params or is cleared, it means + # we either cannot update any region, or were not allowed to, + # or platform has no descriptor. + if [ "$FLASHROM_ADD_OPT_REGIONS" != "-N --ifd" ] && [ "$FLASHROM_ADD_OPT_REGIONS" != "" ]; then + UPDATE_STRING="" + grep -q "\-i fd" <<< "$FLASHROM_ADD_OPT_REGIONS" + UPDATE_IFD=$? + grep -q "\-i me" <<< "$FLASHROM_ADD_OPT_REGIONS" + UPDATE_ME=$? + if [ $UPDATE_IFD -eq 0 ]; then + UPDATE_STRING+="Flash Descriptor" + if [ $UPDATE_ME -eq 0 ]; then + UPDATE_STRING+=" and " + fi + fi + if [ $UPDATE_ME -eq 0 ]; then + UPDATE_STRING+="Management Engine" + fi + echo "Updating $UPDATE_STRING" + $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} ${FLASHROM_ADD_OPT_REGIONS} -w "$BIOS_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE + error_check "Failed to update $UPDATE_STRING" fi + return 0 + elif [ "$_mode" == "install" ]; then echo "Installing Dasharo firmware..." # FIXME: It seems we do not have an easy way to add some flasrhom extra args # globally for specific platform and variant @@ -457,14 +795,57 @@ install() { fi $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} ${FLASHROM_ADD_OPT_REGIONS} -w "$BIOS_UPDATE_FILE" ${_flashrom_extra_args} >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE error_check "Failed to install Dasharo firmware" - print_ok "Successfully installed Dasharo firmware" + + return 0 fi + # Must not get here. + return 1 +} + +install_workflow() { +# Installation workflow. The installation of firmware is possible only via +# flashrom, capsules cannot do the installation because they need initial +# support inside firmware. + sync_clocks + + # Verify that the device is not using battery as a power source: + check_if_ac + error_check "Firmware update process interrupted on user request." + + # Set all global variables needed for installation: + prepare_env install + + # Download and verify firmware: + if [ "$CAN_INSTALL_BIOS" == "false" && "$HAVE_EC" == "true" ]; then + download_ec + verify_artifacts ec + else + download_artifacts + verify_artifacts ec bios + fi + + # Ask user for confirmation: + display_warning + + predeployment_routine + + # Deploy EC firmware + if [ "$HAVE_EC" == "true" ]; then + deploy_ec_firmware install + fi + + # Deploy BIOS firmware + if [ "$CAN_INSTALL_BIOS" == "true" ]; then + deploy_firmware install + fi + + # Post installation routine: echo -n "Syncing disks... " sync echo "Done." - if [ "$NEED_EC_RESET" = "true" ]; then + if [ "$NEED_EC_RESET" == "true" ]; then echo "The computer will shut down automatically in 5 seconds" else echo "The computer will reboot automatically in 5 seconds" @@ -483,122 +864,33 @@ install() { sleep 0.5 echo "Rebooting" sleep 1 - if [ "$NEED_EC_RESET" = "true" ]; then + if [ "$NEED_EC_RESET" == "true" ]; then it5570_shutdown else ${CMD_REBOOT} fi } -update_ec() { - verify_artifacts ec - echo "Updating EC..." - $DASHARO_ECTOOL flash "$EC_UPDATE_FILE" &>> $ERR_LOG_FILE - error_check "Failed to update EC firmware" -} - -update() { - local _can_switch_to_heads="false" - +update_workflow() { +# Update workflow. Supported firmware formats: binary, UEFI capsule. sync_clocks + + # Verify that the device is not using battery as a power source: check_if_ac error_check "Firmware update process interrupted on user request." - echo "Checking for the latest Dasharo update available..." - echo "Current Dasharo version: $DASHARO_VERSION" - if [ -n "$DPP_IS_LOGGED" ]; then - if [ -n "$DASHARO_REL_VER_DPP" ]; then - if [ "$DASHARO_FLAVOR" != "Dasharo (coreboot+heads)" ]; then - echo "Latest available Dasharo version: $DASHARO_REL_VER_DPP" - fi - curl -sfI -u "$USER_DETAILS" -H "$CLOUD_REQUEST" "$BIOS_LINK_DPP" -o /dev/null - if [ $? -ne 0 ]; then - echo "Current DPP credentials do not match the current platform/firmware flavor." - echo "Latest possible and available update is $DASHARO_REL_VER" - BIOS_HASH_LINK=$BIOS_HASH_LINK_COMM - BIOS_SIGN_LINK=$BIOS_SIGN_LINK_COMM - BIOS_LINK=$BIOS_LINK_COMM - if [ "$HAVE_EC" == "true" ]; then - EC_HASH_LINK=$EC_HASH_LINK_COMM - EC_SIGN_LINK=$EC_SIGN_LINK_COMM - EC_LINK=$EC_LINK_COMM - fi - UPDATE_VERSION=$DASHARO_REL_VER - else - BIOS_HASH_LINK=$BIOS_HASH_LINK_DPP - BIOS_SIGN_LINK=$BIOS_SIGN_LINK_DPP - BIOS_LINK=$BIOS_LINK_DPP - if [ "$HAVE_EC" == "true" ]; then - EC_HASH_LINK=$EC_HASH_LINK_DPP - EC_SIGN_LINK=$EC_SIGN_LINK_DPP - EC_LINK=$EC_LINK_DPP - fi - UPDATE_VERSION=$DASHARO_REL_VER_DPP - fi - else - if [ "$DASHARO_FLAVOR" != "Dasharo (coreboot+heads)" ]; then - echo "Latest available Dasharo version: $DASHARO_REL_VER" - fi - BIOS_HASH_LINK=$BIOS_HASH_LINK_COMM - BIOS_SIGN_LINK=$BIOS_SIGN_LINK_COMM - BIOS_LINK=$BIOS_LINK_COMM - if [ "$HAVE_EC" == "true" ]; then - EC_HASH_LINK=$EC_HASH_LINK_COMM - EC_SIGN_LINK=$EC_SIGN_LINK_COMM - EC_LINK=$EC_LINK_COMM - fi - UPDATE_VERSION=$DASHARO_REL_VER - fi - if [ -n "$HAVE_HEADS_FW" ] && [ "$DASHARO_FLAVOR" != "Dasharo (coreboot+heads)" ]; then - # Check if given DPP credentials give access to heads, if not, - # then it means DPP is for regular releases - curl -sfI -u "$USER_DETAILS" -H "$CLOUD_REQUEST" "$HEADS_LINK_DPP" -o /dev/null - if [ $? -ne 0 ]; then - print_warning "Dasharo Heads firmware version is available, but your" - print_warning "subscription does not give you the access to this firmware." - print_warning "If you are interested, please visit https://shop.3mdeb.com/product-category/dasharo-entry-subscription/" - else - # Access to the heads FW is possible, allow to switch to heads - _can_switch_to_heads="true" - print_ok "Dasharo Heads firmware version is available and your subscription" - print_ok "gives you access to this firmware." - fi - elif [ -n "$HAVE_HEADS_FW" ] && [ "$DASHARO_FLAVOR" == "Dasharo (coreboot+heads)" ]; then - # Set the switch flag to offer switch back - echo "Latest available Dasharo version: $HEADS_REL_VER_DPP" - _can_switch_to_heads="true" - fi - else - if [ -n "$DASHARO_REL_VER_DPP" ]; then - print_green "DPP version (coreboot + UEFI) available, if you are interested" - print_ok "please visit https://shop.3mdeb.com/product-category/dasharo-entry-subscription/" - fi - if [ "$DASHARO_FLAVOR" != "Dasharo (coreboot+heads)" ]; then - echo "Latest available Dasharo version: $DASHARO_REL_VER" - fi - BIOS_HASH_LINK=$BIOS_HASH_LINK_COMM - # shellcheck disable=SC2034 - BIOS_SIGN_LINK=$BIOS_SIGN_LINK_COMM - BIOS_LINK=$BIOS_LINK_COMM - if [ "$HAVE_EC" == "true" ]; then - EC_HASH_LINK=$EC_HASH_LINK_COMM - # shellcheck disable=SC2034 - EC_SIGN_LINK=$EC_SIGN_LINK_COMM - EC_LINK=$EC_LINK_COMM - fi - UPDATE_VERSION=$DASHARO_REL_VER - if [ -n "$HAVE_HEADS_FW" ] && [ "$DASHARO_FLAVOR" != "Dasharo (coreboot+heads)" ]; then - print_ok "Dasharo heads firmware version is available. If you are interested," - print_ok "please provide your subscription credentials in the main DTS menu" - print_ok "and select 'Update Dasharo firmware' again to check if you are eligible." - elif [ -n "$HAVE_HEADS_FW" ] && [ "$DASHARO_FLAVOR" == "Dasharo (coreboot+heads)" ]; then - # Set the switch flag to offer switch back - _can_switch_to_heads="true" - fi - fi + # Set all global variables needed for installation: + prepare_env update - handle_fw_switching $_can_switch_to_heads + print_ok "Current Dasharo version: $DASHARO_VERSION" + print_ok "Latest available Dasharo version: $UPDATE_VERSION" + # TODO: Why do we separate Heads firmware-related code from other code? A + # common way to handle this should be found. + handle_fw_switching $CAN_SWITCH_TO_HEADS + + # TODO: It is not a good practice to do some target specific work in the code + # of a scallable product, this should be handled in a more scallable way: if [[ "$UPDATE_VERSION" == "1.1.1" && \ ( "$BOARD_MODEL" == "PRO Z690-A WIFI DDR4(MS-7D25)" || \ "$BOARD_MODEL" == "PRO Z690-A DDR4(MS-7D25)" || \ @@ -612,107 +904,20 @@ update() { echo "That version does not support gen 13 and above CPU. Therefore we cannot continue with flashing." error_exit "Aborting update process..." fi - fi - while : ; do - echo - read -r -p "Are you sure you want to proceed with update? (Y|n) " OPTION - echo - - case ${OPTION} in - yes|y|Y|Yes|YES) - break - ;; - n|N) - error_exit "Aborting update process..." - ;; - *) - ;; - esac - done - download_artifacts - if [ ! "$FUM" == "fum" ]; then - display_flashing_warning - fi - check_flash_lock - verify_artifacts bios - if [ "$HAVE_EC" == "true" ]; then - $DASHARO_ECTOOL info >> $ERR_LOG_FILE 2>&1 - error_check "Device does not have Dasharo EC firmware - cannot continue update!" - fi - - if [ "$NEED_SMMSTORE_MIGRATION" = "true" ]; then - smmstore_migration - fi - - if [ "$NEED_BOOTSPLASH_MIGRATION" = "true" ]; then - bootsplash_migration + # Warning must be displayed after the artifacts have been downloaded, because + # we check their hashes inside display_warning function: + if [ ! "$FUM" == "fum" ]; then + display_warning fi - cbfstool "$BIOS_UPDATE_FILE" extract -r COREBOOT -n config -f "$BIOS_UPDATE_CONFIG_FILE" - grep -q "CONFIG_VBOOT=y" "$BIOS_UPDATE_CONFIG_FILE" - HAVE_VBOOT="$?" + predeployment_routine - check_intel_regions - check_blobs_in_binary $BIOS_UPDATE_FILE - check_if_me_disabled - set_flashrom_update_params $BIOS_UPDATE_FILE - set_intel_regions_update_params "-N --ifd" - check_vboot_keys - - echo "Updating Dasharo firmware..." - print_warning "This may take several minutes. Please be patient and do not power off your computer or touch the keyboard!" - - # FLASHROM_ADD_OPT_UPDATE_OVERRIDE takes priority over auto-detected update params. - # It set only by platform-specific and firmware version-specific conditions - if [ -n "$FLASHROM_ADD_OPT_UPDATE_OVERRIDE" ]; then - # To standardize the operation of the FLASHROM_ADD_OPT_UPDATE_OVERRIDE flag, - # by default it contains only the bios section, below we verify the - # downloaded binary and add more sections when they were detected after - # using the `check_blobs_in_binary` function. - set_intel_regions_update_params "$FLASHROM_ADD_OPT_UPDATE_OVERRIDE" - FLASHROM_ADD_OPT_UPDATE_OVERRIDE="$FLASHROM_ADD_OPT_REGIONS" - $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} ${FLASHROM_ADD_OPT_UPDATE_OVERRIDE} -w "$BIOS_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE - error_check "Failed to update Dasharo firmware" - else - $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} ${FLASHROM_ADD_OPT_UPDATE} -w "$BIOS_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE - error_check "Failed to update Dasharo firmware" - - if [ $BINARY_HAS_RW_B -eq 0 ]; then - echo "Updating second firmware partition..." - $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} --fmap -N -i RW_SECTION_B -w "$BIOS_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE - error_check "Failed to update second firmware partition" - fi - fi - - # We use FLASHROM_ADD_OPT_REGIONS for updating ME and IFD. - # If FLASHROM_ADD_OPT_REGIONS remains the same after - # set_intel_regions_update_params or is cleared, it means - # we either cannot update any region, or were not allowed to, - # or platform has no descriptor. - if [ "$FLASHROM_ADD_OPT_REGIONS" != "-N --ifd" ] && [ "$FLASHROM_ADD_OPT_REGIONS" != "" ]; then - UPDATE_STRING="" - grep -q "\-i fd" <<< "$FLASHROM_ADD_OPT_REGIONS" - UPDATE_IFD=$? - grep -q "\-i me" <<< "$FLASHROM_ADD_OPT_REGIONS" - UPDATE_ME=$? - if [ $UPDATE_IFD -eq 0 ]; then - UPDATE_STRING+="Flash Descriptor" - if [ $UPDATE_ME -eq 0 ]; then - UPDATE_STRING+=" and " - fi - fi - if [ $UPDATE_ME -eq 0 ]; then - UPDATE_STRING+="Management Engine" - fi - echo "Updating $UPDATE_STRING" - $FLASHROM -p "$PROGRAMMER_BIOS" ${FLASH_CHIP_SELECT} ${FLASHROM_ADD_OPT_REGIONS} -w "$BIOS_UPDATE_FILE" >> $FLASHROM_LOG_FILE 2>> $ERR_LOG_FILE - error_check "Failed to update $UPDATE_STRING" - fi + deploy_firmware update if [ ! -z "$SWITCHING_TO" ]; then # Any post-branch-switch messaging should go here @@ -733,9 +938,10 @@ update() { print_ok "Successfully updated Dasharo firmware." fi + # Post update routine: if [ "$HAVE_EC" == "true" ]; then echo "Updating Embedded Controller firmware. Your computer will power off automatically when done." - update_ec # Ends in a reset, does not exit + deploy_ec_firmware update # Ends in a reset, does not exit. else echo -n "Syncing disks... " sync @@ -881,7 +1087,7 @@ usage() { echo " $0 restore - Restore from a previously saved backup" } -# for FUM we start in dasharo-deploy so we need to verify that we have internet +# For FUM we start in dasharo-deploy so we need to verify that we have internet # connection to download shasums in board_config if [ "$FUM" == "fum" ]; then wait_for_network_connection @@ -900,7 +1106,7 @@ case "$CMD" in initial deployment of Dasharo Firmware. Aborting..." fi backup - install + install_workflow ;; update) if [ "$FUM" == "fum" ]; then @@ -917,7 +1123,7 @@ case "$CMD" in echo "1..." sleep 0.5 fi - update + update_workflow ;; backup) backup