diff --git a/include/dts-functions.sh b/include/dts-functions.sh index 75cb86ad..7cbf70d5 100644 --- a/include/dts-functions.sh +++ b/include/dts-functions.sh @@ -688,6 +688,80 @@ set_flashrom_update_params() { fi } +# Does combined check to assess whether the board has region and if its locked. +is_region_locked() { + local region="$1" + local has_var rw_var + + # Uppercase + region="${region^^}" + + has_var="BOARD_HAS_${region}_REGION" + rw_var="BOARD_${region}_REGION_RW" + + [[ "${!has_var}" -eq 1 && "${!rw_var}" -eq 0 ]] +} + +# Helper function to check whether a certain region is to be flashed. +# 0 if found, 1 otherwise. +flashrom_check_for_region() { + local region="$1" + shift + local -a args=("$@") + + # Iterate only up to length-1 since we inspect pairs (i, i+1) + for ((i = 0; i < ${#args[@]} - 1; i++)); do + if [[ "${args[i]}" == "-i" && "${args[i + 1]}" == "$region" ]]; then + return 0 + fi + done + + return 1 +} + +# Does a final check for all flashrom parameters if FD or ME are to be flashed +# and if they're locked. Decide whether we can proceed if any regions are locked. +flashrom_region_check() { + local -a args=("$@") + local locked_regions=() + local region_list verb + + # If switching to heads, always check the region, otherwise check region only + # if specified in params. + # The reason is we want to handle both "overwrites" form metadata as well as + # dynamically added params from set_intel_regions_update_params() + if (flashrom_check_for_region fd "${args[@]}" || [[ "$SWITCHING_TO" == "heads" ]]) && + is_region_locked fd; then + locked_regions+=("FD") + fi + + if (flashrom_check_for_region me "${args[@]}" || [[ "$SWITCHING_TO" == "heads" ]]) && + is_region_locked me; then + locked_regions+=("ME") + fi + + if [ "${#locked_regions[@]}" -eq 0 ]; then + return 0 + fi + + if [ "${#locked_regions[@]}" -eq 1 ]; then + region_list="${locked_regions[0]}" + verb="is" + else + region_list="${locked_regions[0]} and ${locked_regions[1]}" + verb="are" + fi + + if [[ "$SWITCHING_TO" == "heads" ]]; then + print_error "Cannot proceed with heads update when $region_list $verb locked!" + print_error "Refer to: https://docs.dasharo.com/guides/firmware-update/#known-issues" + return 1 + fi + + print_warning "Proceeding without $region_list flashing, as it is not critical." + return 0 +} + set_intel_regions_update_params() { local fd_me_locked="no" if [ $BOARD_HAS_FD_REGION -eq 0 ]; then diff --git a/scripts/dasharo-deploy.sh b/scripts/dasharo-deploy.sh index acb2f282..25b97577 100644 --- a/scripts/dasharo-deploy.sh +++ b/scripts/dasharo-deploy.sh @@ -880,9 +880,11 @@ deploy_firmware() { local _mode local _jobs=() # List of scheduled job indices local _messages=() # List of error messages - # _job_args_ # List of flashrom params per job indice + # _job_args_ # List of flashrom params per job indice # These are created dynamically in schedule_job() and referenced via nameref. local _jobs_total=0 + local _all_flashrom_args=() # An array for all flashrom args from all jobs + local n i # Loop iterators _mode="$1" # Helper function to schedule a flashrom job @@ -909,23 +911,6 @@ deploy_firmware() { args_ref=("$@") } - # Helper function to check whether fd flashing is among arguments - # 0 if found, 1 otherwise. - check_for_fd() { - local -n _args="$1" - local i - - # Scan argument array for the exact flashrom region selector "-i fd". - # Iterate only up to length-1 since we always inspect pairs (i, i+1). - for ((i = 0; i < ${#_args[@]} - 1; i++)); do - if [[ "${_args[i]}" == "-i" && "${_args[i + 1]}" == "fd" ]]; then - return 0 - fi - done - - return 1 - } - if [ "$_mode" == "update" ]; then echo "Updating Dasharo firmware..." print_warning "This may take several minutes. Please be patient and do not" @@ -1033,7 +1018,7 @@ deploy_firmware() { # shellcheck disable=SC2178 local -n args_ref="_job_args_$i" - if check_for_fd args_ref; then + if flashrom_check_for_region fd "${args_ref[@]}"; then echo "Scheduling dedicated FD update..." schedule_job "Failed to flash FD" \ -p "$PROGRAMMER_BIOS" \ @@ -1050,6 +1035,22 @@ deploy_firmware() { fi done + # Create array of all flashrom params to call flashrom_region_check only once + for n in "${!_jobs[@]}"; do + i="${_jobs[$n]}" + # _job_args_$i is a dynamically named (runtime-created) global array holding + # flashrom arguments for a single job. + # shellcheck disable=SC2178 + local -n args_ref="_job_args_$i" + + _all_flashrom_args+=("${args_ref[@]}") + done + + # Last resort check before flashing + if ! flashrom_region_check "${_all_flashrom_args[@]}"; then + return 1 + fi + _jobs_total=${#_jobs[@]} # Execute scheduled tasks @@ -1245,7 +1246,10 @@ update_workflow() { display_warning fi - deploy_firmware update + # Check if update succeeded + if ! deploy_firmware update; then + return 1 + fi # TODO: Could it be placed somewhere else? if [ ! -z "$SWITCHING_TO" ]; then