blob: 60fe0acd242bc043f7c36ffc36e7a746aa43b868 [file] [log] [blame] [edit]
#!/usr/bin/env bash
# Copyright 2024 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#### CATEGORY=Other
### Flash Fuchsia onto a Kola board that has an unmodified bootloader.
## usage: fx flash-kola
# Bash strict mode.
set -eo pipefail
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/../lib/vars.sh || exit $?
fx-config-read
# Use the in-tree fastboot.
readonly FASTBOOT="${FUCHSIA_DIR}/prebuilt/third_party/fastboot/fastboot"
# TODO(b/373727276): Change to use `ffx target flash` instead.
FLASH_SOURCE="$(fx-command-run get-flash-source)"
PRODUCT_BUNDLE="$(fx get-build-dir)/${FLASH_SOURCE#product-bundle:}"
ARTIFACTS="${PRODUCT_BUNDLE}/product_bundle.json"
DTBO_PATH="${PRODUCT_BUNDLE}/$(fx-command-run jq --raw-output '.system_a[] | select(.name=="dtbo-a") | .path' "${ARTIFACTS}")"
FVM_PATH="${PRODUCT_BUNDLE}/$(fx-command-run jq --raw-output '.system_a[] | select(.name=="fxfs.fastboot") | .path' "${ARTIFACTS}")"
ZBI_PATH="${PRODUCT_BUNDLE}/$(fx-command-run jq --raw-output '.system_a[] | select(.name=="zircon-a") | .path' "${ARTIFACTS}")"
RECOVERY_PATH=""
if [[ -d "${PRODUCT_BUNDLE}/system_r" ]]; then
RECOVERY_PATH="${PRODUCT_BUNDLE}/$(fx-command-run jq --raw-output '.system_r[] | select(.name=="zircon-a") | .path' "${ARTIFACTS}")"
fi
readonly FVM_PATH ZBI_PATH DTBO_PATH RECOVERY_PATH
if [[ -z $ANDROID_SERIAL ]]; then
readonly DEVICE_COUNT=$(${FASTBOOT} devices | awk NF | wc -l)
if [[ ${DEVICE_COUNT} -gt 1 ]]; then
fx-error "Detected ${DEVICE_COUNT} devices in fastboot mode."
fx-error "Make sure there is only one device or set ANDROID_SERIAL."
exit 1
fi
fi
BOOTLOADER="$(${FASTBOOT} getvar product 2>&1 | grep '^product:' | awk '{print $2}')"
# Only attempt to set bootmode if the bootloader is not 'sorrel' and mode is not 'factory'
if [[ "${BOOTLOADER}" != "sorrel" ]]; then
# Ensure bootmode is set to factory before flashing partitions.
fx-info "Checking current bootmode..."
# Capture output and potential errors. Use awk to extract the value after 'bootmode='.
# Store the exit code separately.
if BOOTMODE_OUTPUT=$(${FASTBOOT} oem get_config bootmode 2>&1); then
BOOTMODE_EXIT_CODE=0
else
BOOTMODE_EXIT_CODE=$?
fi
INITIAL_BOOTMODE="" # Initialize to empty
if [[ ${BOOTMODE_EXIT_CODE} -eq 0 ]]; then
CURRENT_BOOTMODE=$(echo "${BOOTMODE_OUTPUT}" | awk '/bootmode:/ {print $3}')
INITIAL_BOOTMODE="${CURRENT_BOOTMODE}" # Store the initial bootmode
if [[ "${CURRENT_BOOTMODE}" != "factory" ]]; then
fx-info "Current bootmode is '${CURRENT_BOOTMODE}', setting it to 'factory'."
${FASTBOOT} oem set_config bootmode factory || {
fx-warn "Failed to set bootmode to factory. Attempting to flash anyway."
}
else
fx-info "Bootmode: 'factory'."
fi
else
fx-warn "Failed to get current bootmode (Exit code: ${BOOTMODE_EXIT_CODE}). Output: ${BOOTMODE_OUTPUT}"
fx-warn "Proceeding with flashing, but bootmode might not be 'factory'."
fi
else
fx-info "Bootloader is '${BOOTLOADER}'."
fi
${FASTBOOT} flash boot_a "$ZBI_PATH"
${FASTBOOT} flash boot_b "$ZBI_PATH"
${FASTBOOT} flash dtbo_a "$DTBO_PATH"
${FASTBOOT} flash dtbo_b "$DTBO_PATH"
if [[ -n "$RECOVERY_PATH" ]]; then
${FASTBOOT} flash vendor_boot_a "$RECOVERY_PATH"
${FASTBOOT} flash vendor_boot_b "$RECOVERY_PATH"
fi
# Reboot back into the bootloader.
# Some builds put firmware in the boot image, in which case we reboot here to
# pick up the new firmware we just flashed. For builds that don't put firmware
# in boot, this is still fine and just triggers a reboot now rather than at the
# end of flashing.
fx-info "Rebooting to bootloader"
${FASTBOOT} reboot bootloader
# Pause to make sure fastboot actually drops the device; sometimes without this
# the next fastboot command will execute before the host realizes the device is
# gone which causes the command to fail.
sleep 4
# Attempt to flash SSH keys. This is only supported on devices running custom
# Fuchsia firmware, so if it doesn't work just log a warning.
function push_ssh_keys {
AUTH_KEYS="$(get-ssh-authkeys)" || {
fx-warn "Failed to locate host SSH keys"
return 1
}
# Split this into two commands for clarity on which command fails.
# Staging a file failing is very different from the oem command failing
${FASTBOOT} stage "${AUTH_KEYS}" || {
fx-warn "Failed to upload authorized keys"
return 1
}
${FASTBOOT} oem add-staged-bootloader-file ssh.authorized_keys || {
fx-warn "Failed to stage SSH keys to fastboot"
fx-warn "Device bootloader may not support it"
return 1
}
}
if [[ "${BOOTLOADER}" == "sorrel" ]]; then
if push_ssh_keys; then
fx-info "Successfully provisioned SSH keys via bootloader"
else
fx-warn "Skipping bootloader provisioning of SSH keys"
fi
else
fx-info "Skipping bootloader provisioning of SSH keys because bootloader is ${BOOTLOADER}"
fi
# Flash the super partition last; some Kola devices exhibit USB instability
# after flashing large super partition data so we want to do as much as
# possible before this while the USB is more reliable (b/405436515).
${FASTBOOT} flash super "$FVM_PATH"
# Attempt to restore the initial bootmode if it was changed
if [[ -n "${INITIAL_BOOTMODE}" && "${INITIAL_BOOTMODE}" != "factory" ]]; then
fx-info "Attempting to restore initial bootmode to '${INITIAL_BOOTMODE}'..."
# Check the exit status of the set_config command
if ${FASTBOOT} oem set_config bootmode "${INITIAL_BOOTMODE}"; then
fx-info "Successfully restored bootmode to '${INITIAL_BOOTMODE}'."
else
fx-warn "Failed to restore initial bootmode to '${INITIAL_BOOTMODE}'. Device might remain in 'factory' mode."
fi
fi
# SSH keys require `fastboot continue`, since they are stored in RAM and would
# get lost in a reboot. We rebooted earlier to ensure a complete boot chain
# using the new images.
${FASTBOOT} continue || {
fx-warn "Fastboot got a communication error, but this may be OK"
fx-warn "If the device is now booting then flash succeeded (b/405436515)"
}
fx-info "Done flashing Kola device."