Files
lbmk/script/vendor/inject
T
Leah Rowe 2e779a5495 handle errors on exits from subshells
most of these are probably redundant, and will never
be called, but lbmk needs to be as safe as possible
under fault conditions. fail early, fail hard.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2023-12-11 05:21:27 +00:00

264 lines
7.3 KiB
Bash
Executable File

#!/usr/bin/env sh
# SPDX-License-Identifier: GPL-3.0-only
# SPDX-FileCopyrightText: 2022 Caleb La Grange <thonkpeasant@protonmail.com>
# SPDX-FileCopyrightText: 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com>
# SPDX-FileCopyrightText: 2023 Leah Rowe <leah@libreboot.org>
. "include/err.sh"
. "include/option.sh"
nvmutil="util/nvmutil/nvm"
eval "$(setvars "" archive rom modifygbe nukemode release new_mac)"
main()
{
[ $# -lt 1 ] && err "No options specified."
if [ "${1}" = "listboards" ]; then
items config/coreboot || :
exit 0
fi
archive="${1}"
while getopts n:r:b:m: option; do
case "${option}" in
n) nukemode="${OPTARG}" ;;
r) rom=${OPTARG} ;;
b) board=${OPTARG} ;;
m) modifygbe=true
new_mac=${OPTARG} ;;
esac
done
check_board
build_dependencies
inject_vendorfiles
[ "${nukemode}" = "nuke" ] && return 0
printf "Friendly reminder (this is *not* an error message):\n"
printf "Please always ensure that the files were inserted correctly.\n"
}
check_board()
{
failcheck="n"
check_release "${archive}" || failcheck="y"
if [ "${failcheck}" = "y" ]; then
[ -f "${rom}" ] || \
err "check_board: \"${rom}\" is not a valid path"
[ -z "${rom+x}" ] && \
err "check_board: no rom specified"
[ ! -z ${board+x} ] || \
board=$(detect_board "${rom}")
else
release="y"
board=$(detect_board "${archive}")
fi
boarddir="${cbcfgsdir}/${board}"
[ -d "${boarddir}" ] && return 0
err "check_board: board ${board} not found"
}
check_release()
{
[ -f "${archive}" ] || return 1
[ "${archive##*.}" = "xz" ] || return 1
printf "%s\n" "Release archive ${archive} detected"
}
# This function tries to determine the board from the filename of the rom.
# It will only succeed if the filename is not changed from the build/download
detect_board()
{
path="${1}"
filename=$(basename ${path})
case ${filename} in
grub_*)
board=$(echo "${filename}" | cut -d '_' -f2-3) ;;
seabios_withgrub_*)
board=$(echo "${filename}" | cut -d '_' -f3-4) ;;
*.tar.xz)
_stripped_prefix=${filename#*_}
board="${_stripped_prefix%.tar.xz}" ;;
*)
err "detect_board $filename: could not detect board type"
esac
[ -d "${boarddir}/" ] || \
err "detect_board: dir, ${boarddir}, doesn't exist"
printf "%s\n" "${board}"
}
build_dependencies()
{
[ -d "${cbdir}" ] || x_ ./update trees -f coreboot default
if [ ! -f "${cbfstool}" ] || [ ! -f "${ifdtool}" ]; then
x_ ./update trees -b coreboot utils default
fi
[ -z "${new_mac}" ] || [ -f "${nvmutil}" ] || x_ make -C util/nvmutil
[ "${nukemode}" = "nuke" ] && return 0
x_ ./vendor download ${board}
}
inject_vendorfiles()
{
if [ "${release}" != "y" ]; then
patch_rom "${rom}"
return 0
fi
printf "patching release images\n"
patch_release_roms
}
patch_release_roms()
{
_tmpdir="tmp/romdir"
x_ rm -Rf "${_tmpdir}"
x_ mkdir -p "${_tmpdir}"
tar -xf "${archive}" -C "${_tmpdir}" || \
err "patch_release_roms: !tar -xf \"${archive}\" -C \"${_tmpdir}\""
for x in "${_tmpdir}"/bin/*/*.rom ; do
printf "patching rom: %s\n" "$x"
patch_rom "${x}"
done
for x in "${_tmpdir}"/bin/*/*_nomicrocode.rom ; do
[ -f "${x}" ] || continue
[ -f "${x%_nomicrocode.rom}.rom" ] || continue
cp "${x%_nomicrocode.rom}.rom" "${x}" || \
err "patch_r: !cp \"${x%_nomicrocode.rom}.rom\" \"${x}\""
x_ "${cbfstool}" "${x}" remove -n cpu_microcode_blob.bin
done
(
x_ cd "${_tmpdir}/bin/"* # TODO: very dodgy, re-write accordingly
# NOTE: For compatibility with older rom releases, defer to sha1
[ "${nukemode}" = "nuke" ] || \
sha512sum --status -c vendorhashes || \
sha1sum --status -c vendorhashes || \
sha512sum --status -c blobhashes || \
sha1sum --status -c blobhashes || \
err "patch_release_roms: ROMs did not match expected hashes"
) || err "can't verify vendor hashes"
if [ "${modifygbe}" = "true" ]; then
for x in "${_tmpdir}"/bin/*/*.rom ; do
modify_gbe "${x}"
done
fi
[ -d bin/release ] || x_ mkdir -p bin/release
x_ mv "${_tmpdir}"/bin/* bin/release/
printf "Success! Your ROMs are in bin/release\n"
x_ rm -Rf "${_tmpdir}"
}
patch_rom()
{
rom="${1}"
# we don't process no-microcode roms; these are
# instead re-created at the end, after re-inserting
# on roms with microcode, by copying and then removing,
# so that the hashes will match (otherwise, cbfstool
# may sometimes insert certain vendor files at the wrong offset)
# (unless nomicrocode is the only config provided)
[ "${rom}" != "${rom%_nomicrocode.rom}.rom" ] && \
[ -f "${rom%_nomicrocode.rom}.rom" ] && \
[ "${release}" = "y" ] && return 0
x_ check_defconfig "${boarddir}"
set -- "${boarddir}/config/"*
. "${1}" 2>/dev/null
[ "$CONFIG_HAVE_MRC" = "y" ] && \
inject "mrc.bin" "${CONFIG_MRC_FILE}" "mrc" "0xfffa0000"
[ "${CONFIG_HAVE_ME_BIN}" = "y" ] && \
inject "IFD" "${CONFIG_ME_BIN_PATH}" "me"
[ "${CONFIG_KBC1126_FIRMWARE}" = "y" ] && \
inject "ecfw1.bin" "$CONFIG_KBC1126_FW1" "raw" \
"${CONFIG_KBC1126_FW1_OFFSET}" && \
inject "ecfw2.bin" "$CONFIG_KBC1126_FW2" "raw" \
"${CONFIG_KBC1126_FW2_OFFSET}"
[ ! -z "${CONFIG_VGA_BIOS_FILE}" ] && \
[ ! -z "${CONFIG_VGA_BIOS_ID}" ] && \
inject "pci${CONFIG_VGA_BIOS_ID}.rom" \
"${CONFIG_VGA_BIOS_FILE}" "optionrom"
[ "${CONFIG_INCLUDE_SMSC_SCH5545_EC_FW}" = "y" ] && \
[ ! -z "${CONFIG_SMSC_SCH5545_EC_FW_FILE}" ] && \
inject "sch5545_ecfw.bin" "$CONFIG_SMSC_SCH5545_EC_FW_FILE" raw
[ "${modifygbe}" = "true" ] && ! [ "${release}" = "y" ] && \
inject "IFD" "${CONFIG_GBE_BIN_PATH}" "GbE"
printf "ROM image successfully patched: %s\n" "${rom}"
}
inject()
{
[ $# -lt 3 ] && \
err "inject $@, $rom: usage: inject name path type (offset)"
eval "$(setvars "" cbfsname _dest _t _offset)"
cbfsname="${1}"
_dest="${2##*../}"
_t="${3}"
[ $# -gt 3 ] && _offset="-b ${4}" && [ -z "${4}" ] && \
err "inject $@, $rom: offset passed, but empty (not defined)"
[ -z "${_dest}" ] && err "inject $@, ${rom}: empty destination path"
[ ! -f "${_dest}" ] && [ "${nukemode}" != "nuke" ] && \
err "inject_${dl_type}: file missing, ${_dest}"
[ "$nukemode" = "nuke" ] || \
printf "Inserting %s/%s into file: %s\n" \
"${cbfsname}" "${_t}" "$rom"
if [ "${_t}" = "GbE" ]; then
x_ mkdir -p tmp
cp "${_dest}" "tmp/gbe.bin" || \
err "inject: !cp \"${_dest}\" \"tmp/gbe.bin\""
_dest="tmp/gbe.bin"
"${nvmutil}" "${_dest}" setmac "${new_mac}" || \
err "inject ${_dest}: can't change mac address"
fi
if [ "${cbfsname}" = "IFD" ]; then
if [ "${nukemode}" != "nuke" ]; then
"${ifdtool}" -i ${_t}:${_dest} "${rom}" -O "$rom" || \
err "inject: can't insert $_t ($dest) into $rom"
else
"${ifdtool}" --nuke ${_t} "${rom}" -O "${rom}" || \
err "inject ${rom}: can't nuke ${_t} in IFD"
fi
else
if [ "${nukemode}" != "nuke" ]; then
"${cbfstool}" "${rom}" add -f "${_dest}" \
-n "${cbfsname}" -t ${_t} ${_offset} || \
err "inject $rom: can't insert $_t file $_dest"
else
"${cbfstool}" "${rom}" remove -n "${cbfsname}" || \
err "inject $rom: can't remove ${cbfsname}"
fi
fi
}
usage()
{
cat <<- EOF
USAGE: ./vendor inject -r [rom path] -b [boardname] -m [macaddress]
Example: ./vendor inject -r x230_12mb.rom -b x230_12mb
Adding a macadress to the gbe is optional.
If the [-m] parameter is left blank, the gbe will not be touched.
Type './vendor inject listboards' to get a list of valid boards
EOF
}
main $@