| #!/bin/bash |
| # bios-helper.sh will be system dependent either TTF or non-TTF. |
| # It is selected/installed during build time based on whether it |
| # supports OOB msvfud updates. |
| source /usr/libexec/bios-helper.sh |
| |
| ############################################################## |
| # Initialize BIOS Staged/Activated Version/State during bootup |
| # |
| # Staged Version: |
| # - Verify the staged version/state in the metadata and |
| # compare it against the actual image. |
| # |
| # Activated Version: |
| # - Use the bios_validator output version to update the BIOS |
| # active version. This make sure the active version is not stale. |
| # |
| # Staged State: |
| # - The BIOS state is set to UPDATED if the bios_validator output is valid. |
| # If not, it will be set to CORRUPTED |
| # |
| # Return: |
| # 0 if staged/active version/active is updated, nonzero otherwise |
| ############################################################ |
| bios_init(){ |
| local bios_version_file="$1" |
| |
| # Staged Version: |
| # |
| # Validate the secondary partition via CR51 |
| # if metadata stage version matches stage partition version |
| # - No changes, return 0 |
| # if metadata version does not matches stage partition version |
| # - make the metadata state verison equal to stage partition version |
| # - if stage partition version is invalid |
| # - mark state as CORRUPTED |
| # - else, Mark state as STAGED |
| flashupdate verify_staging --config bios > /dev/null 2>&1 |
| |
| # Activated Version: |
| final_state="CORRUPTED" |
| active_version="$(cat ${bios_version_file})" |
| if [[ "$?" == "0" ]]; then |
| flashupdate update_version --config bios "${active_version}" primary |
| final_state="UPDATED" |
| else |
| flashupdate update_version --config bios "0.0.0.0" primary |
| fi |
| |
| # Check to see if we want to force_powercycle to retry BIOS update |
| retry_bios_update "${active_version}" |
| |
| flashupdate update_state --config bios "${final_state}" |
| } |
| |
| ################################################## |
| # [Deprecated] Use bios_init directly instead |
| # |
| # Initialize BIOS Staged Version/State during bootup |
| # |
| # Verify the staged version/state in the metadata and |
| # compare it against the actual image. |
| # |
| # Return: |
| # 0 if staged version/active is updated, nonzero otherwise |
| ################################################## |
| bios_init_stage(){ |
| # Validate the secondary partition via CR51 |
| # if metadata stage version matches stage partition version |
| # - No changes, return 0 |
| # if metadata version does not matches stage partition version |
| # - make the metadata state verison equal to stage partition version |
| # - if stage partition version is invalid |
| # - mark state as CORRUPTED |
| # - else, Mark state as STAGED |
| flashupdate verify_staging --config bios || return $? |
| |
| # Check the BIOS status to see if it is ACTIVATED. |
| # the state will only be ACTIVATED after a powercycle when the expected BIOS update failed. |
| local state="$(flashupdate info --config bios --stage_state --clean_output)" |
| if [[ "${state}" == "ACTIVATED" ]]; then |
| systemctl start gbmc-psu-hardreset.target |
| fi |
| } |
| |
| ################################################## |
| # [Deprecated] Use bios_init directly instead |
| # |
| # Initialize BIOS Active Version/State during bootup |
| # |
| # Use the bios_validate output version to update the BIOS |
| # active version. This make sure the active version is not stale. |
| # The BIOS state is set to UPDATED to indicate that the version in |
| # $bios_version_file is the running BIOS version. |
| # |
| # Return: |
| # 0 if active version/active is updated, nonzero otherwise |
| ################################################## |
| bios_init_active(){ |
| local bios_version_file="$1" |
| |
| active_version="$(cat ${bios_version_file})" |
| if [[ "$?" == "0" ]]; then |
| flashupdate update_version --config bios "${active_version}" primary |
| flashupdate update_state --config bios UPDATED |
| else |
| flashupdate update_version --config bios "0.0.0.0" primary |
| flashupdate update_state --config bios CORRUPTED |
| return 1 |
| fi |
| } |
| |
| ################################################## |
| # Check if the BIOS update is required |
| # Return: |
| # 0 if we should update the BIOS, nonzero otherwise |
| ################################################## |
| need_bios_update(){ |
| # Check to see if BIOS status is ACTIVATED. |
| # Check staged BIOS version and if it differs from running version. |
| local state="$(flashupdate info --config bios --stage_state --clean_output)" |
| if [[ "${state}" != "ACTIVATED" ]]; then |
| return 1 |
| fi |
| |
| local active_version="$(flashupdate info --config bios --active_version --clean_output)" |
| local staged_version="$(flashupdate info --config bios --staged_version --clean_output)" |
| if [[ "${active_version}" == "${staged_version}" ]]; then |
| # At this point, the state is ACTIVATED and should be UPDATED instead if |
| # staged/activated version is the same. |
| echo "Does not need to update BIOS. Mark as UPDATED state" |
| flashupdate update_state --config bios UPDATED |
| return 1 |
| fi |
| |
| return 0 |
| } |
| |
| ######################################################### |
| # Flash the BIOS EEPROM, if a staged image is on the BMC |
| # Return: |
| # 0 if success, non-zero if error |
| ######################################################### |
| bios_update(){ |
| local state="$(flashupdate info --config bios --stage_state --clean_output)" |
| if [[ "${state}" != "ACTIVATED" ]]; then |
| return 0 |
| fi |
| |
| # The staged index points to the secondary partition that was last |
| # staged. |
| local staged_index="$(flashupdate info --config bios --staged_index --clean_output)" |
| |
| # Verify the staging partition |
| # Set the state to `CORRUPTED` if we cannot fetch the staged image |
| # With RAM based BIOS update, the staged image will not be available after |
| # powercycle. If BIOS update retry is triggered, it will loop forever. |
| flashupdate verify_staging --config bios || \ |
| return $? |
| |
| host_poweroff.sh || return $? |
| |
| # Host is off. BMC should keep the mux. |
| # Update the BIOS state to UPDATED |
| # Write to the primary flash only if the staged_index matches what |
| # we expected the staged partition is. |
| flashupdate copy_partition --config bios "secondary/${staged_index}" \ |
| primary --keep_mux |
| |
| # Only BIOS validation errors will set the state to `CORRUPTED` |
| # Flash write failure will enable retries. |
| local status=$? |
| if [[ "${status}" == "1" ]]; then |
| # Flashupdate has a logical error |
| # The BIOS update is not expected, reset the BIOS stage state. |
| flashupdate invalidate --config bios primary |
| return ${status} |
| fi |
| if [[ "${status}" != "0" ]]; then |
| echo "Failed to update the BIOS" |
| return ${status} |
| fi |
| |
| echo "Updated the BIOS" |
| } |
| |
| ################################################## |
| # Read the BIOS active or staged version |
| # |
| # Print out the active/staged version |
| # Return: |
| # 0 if reading the BIOS version was successful, nonzero otherwise |
| ################################################## |
| bios_version(){ |
| local vtype="$1" |
| |
| local state="$(flashupdate info --config bios --stage_state --clean_output)" |
| # The active/staged version is not guaranteed to be valid if the state |
| # is CORRUPTED |
| if [[ "${state}" == "CORRUPTED" ]]; then |
| echo "" |
| return 0 |
| fi |
| |
| if [[ "${vtype}" == "active" ]]; then |
| # Fetch the active version from the metadata |
| # Active version is assumed to be always valid and no need to |
| # verify again |
| flashupdate info --config bios --active_version --clean_output |
| else |
| # Verifing the Staged version to make sure the BIOS update |
| # stage/version is correct. State need to be STAGED to be considered |
| # valid for BIOS activate package. |
| flashupdate verify_staging --config bios || (echo ""; return 0) |
| |
| # Fetch the staged version from the metadata |
| flashupdate info --config bios --staged_version --clean_output |
| fi |
| } |
| |
| ################################################## |
| # Check if the BIOS activation is required |
| # Return: |
| # 0 if we should activate the BIOS, nonzero otherwise |
| ################################################## |
| need_bios_activation(){ |
| local active_version="$(flashupdate info --config bios --active_version --clean_output)" |
| local staged_version="$(flashupdate info --config bios --staged_version --clean_output)" |
| if [[ "${active_version}" == "${staged_version}" ]]; then |
| flashupdate update_state --config bios "UPDATED" |
| return 1 |
| fi |
| return 0 |
| } |
| |
| ################################################## |
| # Activate the BIOS Stage Partition |
| # |
| # Update the BIOS Status to ACTIVATED if it is STAGED. |
| # Skip if it is already ACTIVATED |
| # |
| # Return: |
| # 0 if the Stage partition was Actived, nonzero otherwise |
| ################################################## |
| bios_activate(){ |
| # Only active the BIOS if the staged/activated version are different. |
| need_bios_activation || return 0 |
| |
| local image="${1:-missing_image}" |
| |
| state="$(flashupdate info --config bios --stage_state --clean_output)" |
| if [[ "${state}" == "ACTIVATED" ]]; then |
| return 0 |
| fi |
| |
| if [[ "${state}" != "STAGED" && "${image}" != "missing_image" ]]; then |
| echo "Stage to RAM before trying to activate again" |
| bios_stage "ram" "${image}" && bios_activate_only |
| return $? |
| fi |
| flashupdate update_state --config bios "ACTIVATED" |
| } |
| |
| bios_activate_only(){ |
| # Only active the BIOS if the staged/activated version are different. |
| need_bios_activation || return 0 |
| |
| state="$(flashupdate info --config bios --stage_state --clean_output)" |
| if [[ "${state}" == "ACTIVATED" ]]; then |
| return 0 |
| fi |
| |
| if [[ "${state}" != "STAGED" ]]; then |
| return 1 |
| fi |
| flashupdate update_state --config bios "ACTIVATED" |
| } |
| |
| ################################################## |
| # Stage the BIOS Stage Partition |
| # |
| # Write the BIOS image to stage partition and mark the BIOS |
| # state as STAGED if the write is successful. |
| # Skip if it is already STAGED or ACTIVATED |
| # |
| # Return: |
| # 0 if the Staged partition was activated, nonzero otherwise |
| ################################################## |
| bios_stage(){ |
| local update_type="$1" |
| local image="$2" |
| # Need to skip the third arg because we used to pass path for the image |
| # to staged in. That is not used anymore, however, that will disable eMMC |
| # staging on older BIOS packages. |
| local try_emmc="${4:-true}" |
| |
| # stage_index=1 means the update method is non-volatile memory based |
| stage_index=1 |
| if [[ "${update_type}" == "ram" ]]; |
| then |
| # Update the BIOS state to RAM based update and update the staged version. |
| # Use the secondary storage region that is linked to $BURN_IMAGE. |
| # Create empty file with image size. |
| stage_index=0 |
| |
| # eMMC Available. Try to stage to persistent region instead. |
| [[ "${try_emmc}" == "true" ]] && \ |
| SYSTEMD_IGNORE_CHROOT=1 systemctl status emmc-available.target \ |
| && stage_index=1 |
| fi |
| |
| # Stage the BIOS to the BMC Secondary Storage |
| # Writing to the secondary parition automatically updates the BIOS |
| # State to STAGED after succefully staging the BIOS |
| if ! flashupdate write --config bios "${image}" "secondary/${stage_index}" ; |
| then |
| echo "bios image verify failure. Staging BIOS image failed." |
| if [[ "${stage_index}" != "0" ]]; |
| then |
| echo "Currently targeting persistent staging... trying RAM based update instead." |
| bios_stage "ram" "${image}" "skip_arg" "false" |
| return |
| fi |
| |
| rm -f "${image}" |
| return 1 |
| fi |
| rm -f "${image}" |
| } |