blob: 541f344f06172b4c1e5e28229467d1ce680f5202 [file] [log] [blame]
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Distributed under the terms of the GNU General Public License v2
#
# Original Author: The Chromium OS Authors <chromium-os-dev@chromium.org>
# Purpose: Generate shell script containing firmware update bundle.
#
# Skip unibuild if we don't have a board set.
if [[ ${#CROS_BOARDS[@]} -eq 0 ]]; then
CROS_BOARDS=( "none" )
fi
if [[ -z "${EBUILD}" ]]; then
die "This eclass needs EBUILD environment variable."
fi
inherit cros-workon cros-unibuild cros-constants
# @ECLASS-VARIABLE: CROS_FIRMWARE_BCS_OVERLAY
# @DESCRIPTION: (Optional) Name of board overlay on Binary Component Server
: ${CROS_FIRMWARE_BCS_OVERLAY:=$(
# EBUILD will be the full path to the ebuild file.
IFS="/"
set -- ${EBUILD}
# Chop off the ebuild, the $PN dir, and the $CATEGORY dir.
n=$(( $# - 3 ))
echo "${!n}"
)}
# @ECLASS-VARIABLE: CROS_FIRMWARE_MAIN_IMAGE
# @DESCRIPTION: (Optional) Location of system firmware (BIOS) image
: ${CROS_FIRMWARE_MAIN_IMAGE:=}
# @ECLASS-VARIABLE: CROS_FIRMWARE_MAIN_RW_IMAGE
# @DESCRIPTION: (Optional) Location of RW system firmware image
: ${CROS_FIRMWARE_MAIN_RW_IMAGE:=}
# @ECLASS-VARIABLE: CROS_FIRMWARE_EC_IMAGE
# @DESCRIPTION: (Optional) Location of EC firmware image
: ${CROS_FIRMWARE_EC_IMAGE:=}
# @ECLASS-VARIABLE: CROS_FIRMWARE_PD_IMAGE
# @DESCRIPTION: (Optional) Location of PD firmware image
: ${CROS_FIRMWARE_PD_IMAGE:=}
# Check for EAPI 2+
case "${EAPI:-0}" in
0|1) die "unsupported EAPI (${EAPI}) in eclass (${ECLASS})" ;;
*) ;;
esac
# $board-overlay/make.conf may contain these flags to always create "firmware
# from source".
IUSE="bootimage cros_ec cros_ish unibuild generated_cros_config"
# "futility update" is needed when building and running updater package.
COMMON_DEPEND=" chromeos-base/vboot_reference "
# For unibuild we need EAPI 5 for the sub-slot dependency feature.
case "${EAPI:-0}" in
5|6|7)
COMMON_DEPEND+="
unibuild? (
!generated_cros_config? ( chromeos-base/chromeos-config )
generated_cros_config? ( chromeos-base/chromeos-config-bsp:= )
)
"
;;
esac
# Dependency for SFX v1 (needed by both build and run time).
COMMON_DEPEND+="
app-arch/gzip
app-arch/sharutils
app-arch/tar
sys-apps/util-linux
"
# Apply common dependency.
DEPEND="${COMMON_DEPEND}"
RDEPEND="${COMMON_DEPEND}"
# Dependency for run time only (invoked by `futility update`).
RDEPEND+="
chromeos-base/vpd
sys-apps/flashrom
sys-apps/mosys
cros_ish? ( chromeos-base/chromeos-ish )
"
# Maintenance note: The factory install shim downloads and executes
# the firmware updater. Consequently, run time dependencies for the
# updater are also run time dependencies for the install shim.
#
# The contents of RDEPEND must also be present in the
# chromeos-base/factory_installer ebuild in PROVIDED_DEPEND. If you make any
# change to the list above, you may need to make a matching change in the
# factory_installer ebuild.
# Dependency to build firmware from source (build phase only).
DEPEND+="
bootimage? ( sys-boot/chromeos-bootimage )
cros_ec? ( chromeos-base/chromeos-ec )
"
RESTRICT="mirror"
# Local variables.
UPDATE_SCRIPT="chromeos-firmwareupdate"
FW_IMAGE_LOCATION=""
FW_RW_IMAGE_LOCATION=""
EC_IMAGE_LOCATION=""
PD_IMAGE_LOCATION=""
# Output the URI associated with a file to download. This can be added to the
# SRC_URI variable.
# Portage will then take care of downloading these files before the src_unpack
# phase starts.
# Args
# $1: Input file to read, with prefix (e.g. "bcs://Reef.9042.72.0.tbz2")
# $2: Overlay name (e.g. "reef-private")
# $3: Board directory containing file (e.g. "chromeos-firmware-reef")
_add_uri() {
local input="$1"
local overlay="$2"
local board="$3"
local protocol="${input%%://*}"
local uri="${input#*://}"
local user="bcs-${overlay#variant-*-}"
local bcs_url="gs://chromeos-binaries/HOME/${user}/overlay-${overlay}"
# Input without ${protocol} are local files (ex, ${FILESDIR}/file).
case "${protocol}" in
bcs)
echo "${bcs_url}/${CATEGORY}/${board}/${uri}"
;;
http|https|gs)
echo "${input}"
;;
esac
}
# Output a URL for the given firmware variable.
# This calls _add_uri() after setting up the required parameters.
# $1: Variable containing the required filename (e.g. "FW_IMAGE_LOCATION")
_add_source() {
local var="$1"
local src_uri="$2"
local overlay="${CROS_FIRMWARE_BCS_OVERLAY#overlay-}"
local input="${!var}"
_add_uri "${input}" "${overlay}" "${PN}"
}
_unpack_archive() {
local var="$1"
local input="${!var}"
local archive="${input##*/}"
local folder="${S}/.dist/${archive}"
# Remote source files (bcs://, http://, ...) are downloaded into
# ${DISTDIR}, which is the default location for command 'unpack'.
# For any other files (ex, ${FILESDIR}/file), use complete file path.
local unpack_name="${input}"
if [[ "${unpack_name}" =~ "://" ]]; then
input="${DISTDIR}/${archive}"
unpack_name="${archive}"
fi
case "${input##*.}" in
tar|tbz2|tbz|bz|gz|tgz|zip|xz) ;;
*)
eval ${var}="'${input}'"
return
;;
esac
mkdir -p "${folder}" || die "Not able to create ${folder}"
(cd "${folder}" && unpack "${unpack_name}") ||
die "Failed to unpack ${unpack_name}."
local contents=($(ls "${folder}"))
if [[ ${#contents[@]} -gt 1 ]]; then
# Currently we can only serve one file (or directory).
ewarn "WARNING: package ${input} contains multiple files."
fi
eval ${var}="'${folder}/${contents}'"
}
cros-firmware_src_unpack() {
case "${EAPI:-0}" in
1|2|3|4)
use unibuild &&
die "Update your EAPI version to 5 to use unibuild"
;;
esac
cros-workon_src_unpack
local i
if ! use unibuild; then
for i in {FW,FW_RW,EC,PD}_IMAGE_LOCATION; do
_unpack_archive ${i}
done
fi
}
# Add members to an array.
# $1: Array variable to append to.
# $2..: Arguments to append, each to be put in its own array element.
_append_var() {
local var="$1"
shift
eval "${var}+=( \"\$@\" )"
}
# Add a string command-line flag with its value to an array.
# If the value is empty then this function does nothing.
# $1: Array variable to append to.
# $2: Flag (e.g. "-b").
# $3: Value (e.g. "bios.bin").
_add_param() {
local var="$1"
local flag="$2"
local value="$3"
[[ -n "${value}" ]] && _append_var "${var}" "${flag}" "${value}"
}
# Add a string command-line flag with its file argument to an array.
# If the file does not exists then this function does nothing.
# $1: Array variable to append to.
# $2: Flag (e.g. "-b").
# $3: File path (e.g. "bios.bin").
_add_file_param() {
local var="$1"
local flag="$2"
local value="$3"
[[ -e "${value}" ]] && _append_var "${var}" "${flag}" "${value}"
}
# Add a boolean command-line flag to an array.
# If the value is empty then this function does nothing, otherwise it
# appends the flag.
# $1: Array variable to append to.
# $2: Flag (e.g. "--create_bios_rw_image").
# $3: Value (e.g. "${IMAGE}"), only used to determine flag presence.
_add_bool_param() {
local var="$1"
local flag="$2"
local value="$3"
[[ -n "${value}" ]] && _append_var "${var}" "${flag}"
}
cros-firmware_src_compile() {
# image_cmd will be reset when creating local updaters.
# ext_cmd will be reused when creating local updaters.
local image_cmd=() ext_cmd=()
local root="${SYSROOT%/}"
local output="${UPDATE_SCRIPT}"
# We need lddtree from chromite.
export PATH="${CHROMITE_BIN_DIR}:${PATH}"
if use unibuild; then
_add_param ext_cmd -i "${DISTDIR}"
_add_param ext_cmd -c "${root}${UNIBOARD_YAML_CONFIG}"
else
ext_cmd+=(--legacy)
_add_param image_cmd -b "${FW_IMAGE_LOCATION}"
_add_param image_cmd -e "${EC_IMAGE_LOCATION}"
_add_param image_cmd -p "${PD_IMAGE_LOCATION}"
_add_param image_cmd -w "${FW_RW_IMAGE_LOCATION}"
fi
if [ ${#image_cmd[@]} -eq 0 ] && ! use unibuild; then
# Create an empty update script for the generic case
# (no need to update)
einfo "Building empty firmware update script"
echo -n >"${output}"
else
einfo "Build ${BOARD_USE} firmware updater to ${output}:" \
"${image_cmd[*]} ${ext_cmd[*]}"
./pack_firmware.py "${image_cmd[@]}" "${ext_cmd[@]}" \
-o "${output}" || die "Cannot pack firmware updater."
fi
if ! use bootimage; then
if use cros_ec; then
# TODO(hungte) Deal with a platform that has only EC and
# no BIOS, which is usually incorrect configuration. We
# only warn here to allow for BCS based firmware to
# still generate a proper chromeos-firmwareupdate update
# script.
ewarn "WARNING: platform has no local BIOS."
ewarn "EC-only is not supported."
ewarn "Not generating a local updater script."
fi
return
fi
# Create local updaters. image_cmd is cleared and ext_cmd is kept.
image_cmd=()
output="updater.sh"
local local_root="${root}/firmware"
if use unibuild; then
ext_cmd+=(--local)
# Tell pack_firmware.py where to find the files.
# 'BUILD_TARGET' will be replaced with the build-targets config
# from the unified build config file. Since these path do not
# exist, we can't use _add_file_param.
_add_param image_cmd -b "${local_root}/image-BUILD_TARGET.bin"
local_root+="/BUILD_TARGET"
if use cros_ec; then
_add_param image_cmd -e "${local_root}/ec.bin"
_add_param image_cmd -p "${local_root}/pd.bin"
fi
else
_add_param image_cmd -b "${local_root}/image.bin"
_add_file_param image_cmd -e "${local_root}/ec.bin"
_add_file_param image_cmd -p "${local_root}/pd.bin"
fi
einfo "Build ${BOARD_USE} local firmware updater to ${output}:" \
"${image_cmd[*]} ${ext_cmd[*]}"
./pack_firmware.py -o "${output}" "${image_cmd[@]}" "${ext_cmd[@]}" ||
die "Cannot pack firmware updater."
if [[ ! -s "${UPDATE_SCRIPT}" ]]; then
# When no pre-built binaries are available,
# dupe local updater to system updater.
cp -f "${output}" "${UPDATE_SCRIPT}"
fi
}
cros-firmware_src_install() {
# install updaters for firmware-from-source archive.
if use bootimage; then
exeinto /firmware
doexe updater.sh
fi
# skip anything else if no main updater program.
if [[ ! -s "${UPDATE_SCRIPT}" ]]; then
return
fi
# install the main updater program if available.
dosbin "${UPDATE_SCRIPT}"
dosbin "${S}"/sbin/*
# install ${FILESDIR}/sbin/* (usually board-setgoodfirmware).
if [[ -d "${FILESDIR}"/sbin ]]; then
dosbin "${FILESDIR}"/sbin/*
fi
}
# Trigger tests on each firmware build. While there is a chromeos-firmware-1
# ebuild which could be used to run these tests on the host, it doesn't do
# anything at present, and the usual workflow is to build firmware for a
# particular board. This way it is more likely that people will see any
# failures in their normal workflow.
cros-firmware_src_test() {
local fname
# We need lddtree from chromite.
export PATH="${CHROMITE_BIN_DIR}:${PATH}"
for fname in *test.py; do
einfo "Running tests in ${fname}"
python3 "./${fname}" || die "Tests failed at ${fname} (py3)"
done
}
# @FUNCTION: _expand_list
# @USAGE <var> <ifs> <string>
# @DESCRIPTION:
# Internal function to expand a string (separated by ifs) into bash array.
_expand_list() {
local var="$1" ifs="$2"
IFS="${ifs}" read -r -a ${var} <<<"${*:3}"
}
# @FUNCTION: cros-firmware_setup_source
# @DESCRIPTION:
# Configures all firmware binary source files to SRC_URI, and updates local
# destination mapping (*_LOCATION). Must be invoked after CROS_FIRMWARE_*_IMAGE
# are set. This also reads the master configuration if available and adds files
# from there for unified builds. The result is something like:
#
# SRC_URI="!unibuild? ( file1 file2 ) unibuild? ( file3 file3 )"
#
# With this we will end up downloading either the unibuild files or the
# !unibuild files, depending on the 'unibuild' USE flag.
cros-firmware_setup_source() {
# This function is called before FILESDIR is set so figure it out from
# the ebuild filename.
local basedir="${EBUILD%/*}"
local files="${basedir}/files"
local i uris
if [[ -f "${files}/srcuris" ]]; then
mapfile -t uris < "${files}/srcuris"
SRC_URI+=" ${uris[*]}"
return
fi
FW_IMAGE_LOCATION="${CROS_FIRMWARE_MAIN_IMAGE}"
FW_RW_IMAGE_LOCATION="${CROS_FIRMWARE_MAIN_RW_IMAGE}"
EC_IMAGE_LOCATION="${CROS_FIRMWARE_EC_IMAGE}"
PD_IMAGE_LOCATION="${CROS_FIRMWARE_PD_IMAGE}"
# Add these files for use if unibuild is not set.
for i in {FW,FW_RW,EC,PD}_IMAGE_LOCATION; do
uris+=" $(_add_source ${i})"
done
if [[ -n "${uris// }" ]]; then
SRC_URI+="!unibuild? ( ${uris} ) "
fi
}
# If "inherit cros-firmware" appears at end of ebuild file, build source URI
# automatically. Otherwise, you have to put an explicit call to
# "cros-firmware_setup_source" at end of ebuild file.
[[ -n "${CROS_FIRMWARE_MAIN_IMAGE}" ]] && cros-firmware_setup_source
EXPORT_FUNCTIONS src_unpack src_compile src_install src_test