blobutil/inject: massively improved coding style

top-down function order, with specific functions for
each type of blob. startup logic moved into main(),
also split into smaller functions

"write one program that does one thing well"

blobutil is like that, and has this added philosophy:

"write one function that does one thing well"

during the course of this re-factoring, several bugs
and issues were found, that are pre-existing. these
will be corrected in follow-up revisions
fsdg20230625
Leah Rowe 2023-05-14 05:42:59 +01:00
parent 75ad8b0d46
commit ee0b200fbe
1 changed files with 281 additions and 176 deletions

View File

@ -5,54 +5,107 @@
# SPDX-FileCopyrightText: 2023 Leah Rowe <info@minifree.org> # SPDX-FileCopyrightText: 2023 Leah Rowe <info@minifree.org>
# SPDX-License-Identifier: GPL-3.0-only # SPDX-License-Identifier: GPL-3.0-only
Fail(){ archive=""
if [ ! -z ${@+x} ]; then _filetype=""
printf "\nERROR: ${@}\n" rom=""
board=""
modifygbe=""
new_mac=""
release=""
releasearchive=""
cbdir="coreboot/default"
cbcfgsdir="resources/coreboot"
ifdtool="${cbdir}/util/ifdtool/ifdtool"
cbfstool="${cbdir}/util/cbfstool/cbfstool"
nvmutil="util/nvmutil/nvm"
boarddir=""
pciromsdir="pciroms"
CONFIG_HAVE_MRC=""
CONFIG_HAVE_ME_BIN=""
CONFIG_ME_BIN_PATH=""
CONFIG_KBC1126_FIRMWARE=""
CONFIG_KBC1126_FW1=""
CONFIG_KBC1126_FW1_OFFSET=""
CONFIG_KBC1126_FW2=""
CONFIG_KBC1126_FW2_OFFSET=""
CONFIG_VGA_BIOS_FILE=""
CONFIG_VGA_BIOS_ID=""
CONFIG_GBE_BIN_PATH=""
main()
{
if [ $# -lt 1 ]; then
fail "No options specified."
elif [ "${1}" = "listboards" ]; then
listboards
exit 0
fi fi
cat <<- EOF archive="${1}"
USAGE: ./blobutil inject -r [/path/to/rom] -b [boardname] -m [macaddress] echo "TEST: $archive"
Example: ./blobutil inject -r x230_12mb.rom -b x230_12mb
Adding a macadress to the gbe is optional. while getopts r:b:m: option
If the [-m] parameter is left blank, the gbe will not be touched. do
case "${option}"
Type './blobutil inject listboards' to get a list of valid boards in
EOF r)rom=${OPTARG};;
b)board=${OPTARG};;
exit 1 m)
} modifygbe=true
new_mac=${OPTARG}
Modify_gbe(){ ;;
rom=${1} esac
printf "changing mac address in gbe to ${new_mac}\n"
_gbe_location=${CONFIG_GBE_BIN_PATH#../../}
if [ ! -f util/nvmutil/nvm ]; then
make -C util/nvmutil || Fail 'failed to build nvmutil'
fi
_gbe_tmp=$(mktemp -t gbeXXXX.bin)
cp ${_gbe_location} ${_gbe_tmp}
./util/nvmutil/nvm ${_gbe_tmp} setmac ${new_mac} || Fail 'failed to modify mac address\nmake sure the mac address in the correct format'
./coreboot/default/util/ifdtool/ifdtool -i GbE:${_gbe_tmp} ${rom} -O ${rom} || exit 1
rm ${_gbe_tmp}
}
listboards() {
for boarddir in resources/coreboot/*; do
if [ ! -d "${boarddir}" ]; then continue; fi
board="${boarddir##resources/coreboot/}"
board="${board%/}"
printf '%s\n' "${board##*/}"
done done
check_board
build_dependencies
inject_blobs
}
check_board()
{
if ! check_release ${archive} ; then
if [ ! -f "${rom}" ]; then
fail "${rom} is not a valid path"
elif [ -z ${rom+x} ]; then
fail 'no rom specified'
elif [ -z ${board+x} ]; then
board=$(detect_board ${rom}) \
|| fail 'no board specified'
fi
else
release=true
releasearchive="${archive}"
board=$(detect_board ${archive}) \
|| fail 'Could not detect board type'
fi
boarddir="${cbcfgsdir}/${board}"
if [ ! -d "${boarddir}" ]; then
fail "board ${board} not found"
fi
}
check_release()
{
if [ ! -f "${archive}" ]; then
return 1
fi
if [ "${archive##*.}" = "xz" ]; then
printf "%s\n" "Release archive ${archive} detected"
return 0
else
return 1
fi
} }
# This function tries to determine the board from the filename of the rom. # 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 # It will only succeed if the filename is not changed from the build/download
Detect_board(){ detect_board()
{
path=${1} path=${1}
filename=$(basename ${path}) filename=$(basename ${path})
case ${filename} in case ${filename} in
@ -70,102 +123,69 @@ Detect_board(){
return 1 return 1
esac esac
if [ -d "resources/coreboot/${board}/" ]; then if [ -d "${boarddir}/" ]; then
printf '%s\n' "${board}" printf '%s\n' "${board}"
return 0
else else
return 1 return 1
fi fi
} }
Patch(){ build_dependencies()
rom="${1}" {
set -- "resources/coreboot/${board}/config/*" if [ ! -d ${cbdir} ]; then
. ${1} 2>/dev/null printf "downloading coreboot\n"
. "resources/coreboot/${board}/board.cfg" ./download coreboot default
if [ "$CONFIG_HAVE_MRC" = "y" ]; then
printf 'adding mrc\n'
./coreboot/default/util/cbfstool/cbfstool ${rom} add -f mrc/haswell/mrc.bin -n mrc.bin -t mrc -b 0x78fe00 || exit 1
fi fi
if [ "${CONFIG_HAVE_ME_BIN}" = "y" ]; then if [ ! -f "${ifdtool}" ]; then
_me_location=${CONFIG_ME_BIN_PATH#../../} printf "building ifdtool from coreboot\n"
printf 'adding intel management engine\n' ./build module cbutils default \
./coreboot/default/util/ifdtool/ifdtool -i me:${_me_location} ${rom} -O ${rom} || exit 1 || fail 'could not build ifdtool'
fi fi
if [ "${CONFIG_KBC1126_FIRMWARE}" = "y" ]; then if [ ! -f "${cbfstool}" ]; then
_ec1_location="${CONFIG_KBC1126_FW1#../../}" printf "building cbfstool from coreboot\n"
_ec1_offset="${CONFIG_KBC1126_FW1_OFFSET}" ./build module cbutils default \
_ec2_location="${CONFIG_KBC1126_FW2#../../}" || fail 'could not build cbfstool'
_ec2_offset="${CONFIG_KBC1126_FW2_OFFSET}"
printf "adding hp kbc1126 ec firmware\n"
if [ "${_ec1_offset}" = "" ] || [ "${_ec1_offset}" = "" ];
then
printf "EC offsets not declared for board: %s\n" \
"${board}"
exit 1
fi
if [ "${_ec1_location}" = "" ] || [ "${_ec2_location}" = "" ];
then
printf "EC firmware path not declared for board: %s\n" \
"${board}"
fi
if [ ! -f "${_ec1_location}" ] || [ ! -f "${_ec2_location}" ];
then
printf "EC firmware not downloaded for board: %s\n" \
"${board}"
exit 1
fi
./coreboot/default/util/cbfstool/cbfstool "${rom}" add -f ${_ec1_location} -n ecfw1.bin -b ${_ec1_offset} -t raw || exit 1
./coreboot/default/util/cbfstool/cbfstool "${rom}" add -f ${_ec2_location} -n ecfw2.bin -b ${_ec2_offset} -t raw || exit 1
fi fi
if [ "${CONFIG_VGA_BIOS_FILE}" != "" ] \ ./blobutil download ${board} || \
&& [ "${CONFIG_VGA_BIOS_ID}" != "" ]; then fail "Could not download blobs for ${board}"
_vga_location="${CONFIG_VGA_BIOS_FILE#../../}" }
_vga_dir="${_vga_location%/*}"
_vga_filename="${_vga_location##*/}"
printf "adding pci option rom\n"
if [ "${_vga_dir}" != "pciroms" ]; then
printf "Invalid PCI ROM directory: %s\n" ${_vga_dir}
exit 1
fi
if [ ! -f "${_vga_location}" ]; then
printf "No such file exists: %s\n" ${_vga_location}
exit 1
fi
./coreboot/default/util/cbfstool/cbfstool ${rom} \
add -f "${_vga_location}" \
-n "pci${CONFIG_VGA_BIOS_ID}.rom" \
-t optionrom || exit 1
fi
if [ "${modifygbe}" = "true" ] && ! [ "${release}" = "true" ]; then inject_blobs()
Modify_gbe ${rom} {
if [ "${release}" = "true" ]; then
echo 'patching release file'
patch_release_roms
else
patch_rom ${rom}
fi fi
} }
Patch_release(){ patch_release_roms()
{
_tmpdir=$(mktemp -d "/tmp/${board}_tmpXXXX") _tmpdir=$(mktemp -d "/tmp/${board}_tmpXXXX")
tar xf "${releasearchive}" -C "${_tmpdir}" || \ tar xf "${releasearchive}" -C "${_tmpdir}" || \
Fail 'could not extract release archive' fail 'could not extract release archive'
for rom in ${_tmpdir}/bin/*/*.rom ; do for x in ${_tmpdir}/bin/*/*.rom ; do
echo "patching rom $rom" echo "TEST"
Patch ${rom} || \ echo "patching rom $x"
Fail "could not patch ${rom}" patch_rom ${x} || fail "could not patch ${x}"
echo "FOO"
done done
( cd ${_tmpdir}/bin/* (
cd ${_tmpdir}/bin/*
sha1sum --status -c blobhashes || \ sha1sum --status -c blobhashes || \
Fail 'ROMs did not match expected hashes' fail 'ROMs did not match expected hashes'
) )
if [ "${modifygbe}" = "true" ]; then if [ "${modifygbe}" = "true" ]; then
for rom in ${_tmpdir}/bin/*/*.rom ; do for x in ${_tmpdir}/bin/*/*.rom ; do
Modify_gbe ${rom} modify_gbe ${x}
done done
fi fi
@ -179,83 +199,168 @@ Patch_release(){
rm -r "${_tmpdir}" rm -r "${_tmpdir}"
} }
Check_release(){ patch_rom()
if ! [ -f ${1} ]; then {
return 1 rom="${1}"
fi
_filetype=$(file -b "${1}") set -- "${boarddir}/config/"*
. ${1} 2>/dev/null
. "${boarddir}/board.cfg"
if [ "${_filetype%%,*}" = "XZ compressed data" ]; then if [ "$CONFIG_HAVE_MRC" = "y" ]; then
printf "%s\n" "Release archive ${1} detected" inject_blob_intel_mrc "${rom}"
else fi
return 1
fi if [ "${CONFIG_HAVE_ME_BIN}" = "y" ]; then
inject_blob_intel_me "${rom}"
fi
if [ "${CONFIG_KBC1126_FIRMWARE}" = "y" ]; then
inject_blob_hp_kbc1126_ec "${rom}"
fi
if [ "${CONFIG_VGA_BIOS_FILE}" != "" ] \
&& [ "${CONFIG_VGA_BIOS_ID}" != "" ]; then
inject_blob_dell_e6400_vgarom_nvidia
fi
if [ "${modifygbe}" = "true" ] && ! [ "${release}" = "true" ]; then
modify_gbe ${rom}
fi
} }
if [ "${1}" = "listboards" ]; then inject_blob_intel_mrc()
listboards {
exit 0 rom="${1}"
fi
# Implementing parameter parsing now so more options can be added later printf 'adding mrc\n'
while getopts r:b:m: option
do
case "${option}"
in
r)rom=${OPTARG};;
b)board=${OPTARG};;
m)
modifygbe=true
new_mac=${OPTARG}
;;
esac
done
# TODO: use offset defined in coreboot configs (don't hardcode)
${cbfstool} ${rom} add -f mrc/haswell/mrc.bin -n mrc.bin -t mrc \
-b 0x78fe00 || exit 1
}
inject_blob_intel_me()
{
rom="${1}"
if ! Check_release ${1} ; then # TODO: check if CONFIG_ME_BIN_PATH is empty
if [ ! -f "${rom}" ]; then _me_location=${CONFIG_ME_BIN_PATH#../../}
Fail "${rom} is not a valid path" printf 'adding intel management engine\n'
elif [ -z ${rom+x} ]; then ${ifdtool} -i me:${_me_location} ${rom} -O ${rom} || exit 1
Fail 'no rom specified' }
elif [ -z ${board+x} ]; then
board=$(Detect_board ${rom}) || \ inject_blob_hp_kbc1126_ec()
Fail 'no board specified' {
rom="${1}"
_ec1_location="${CONFIG_KBC1126_FW1#../../}"
_ec1_offset="${CONFIG_KBC1126_FW1_OFFSET}"
_ec2_location="${CONFIG_KBC1126_FW2#../../}"
_ec2_offset="${CONFIG_KBC1126_FW2_OFFSET}"
printf "adding hp kbc1126 ec firmware\n"
if [ "${_ec1_offset}" = "" ] || [ "${_ec1_offset}" = "" ]; then
printf "EC offsets not declared for board: %s\n" \
"${board}"
exit 1
fi
if [ "${_ec1_location}" = "" ] || [ "${_ec2_location}" = "" ]; then
printf "EC firmware path not declared for board: %s\n" \
"${board}"
fi
if [ ! -f "${_ec1_location}" ] || [ ! -f "${_ec2_location}" ]; then
printf "EC firmware not downloaded for board: %s\n" \
"${board}"
exit 1
fi fi
else
release=true
releasearchive="${1}"
board=$(Detect_board ${1}) || \
Fail 'Could not detect board type'
fi
${cbfstool} "${rom}" add -f ${_ec1_location} -n ecfw1.bin \
-b ${_ec1_offset} -t raw || exit 1
${cbfstool} "${rom}" add -f ${_ec2_location} -n ecfw2.bin \
-b ${_ec2_offset} -t raw || exit 1
}
if [ ! -d "resources/coreboot/${board}/" ]; then inject_blob_dell_e6400_vgarom_nvidia()
Fail "board ${board} not found" {
fi rom="${1}"
if [ ! -d coreboot/default ]; then _vga_location="${CONFIG_VGA_BIOS_FILE#../../}"
printf "downloading coreboot\n" _vga_dir="${_vga_location%/*}"
./download coreboot default _vga_filename="${_vga_location##*/}"
fi
if [ ! -f "coreboot/default/util/ifdtool/ifdtool" ]; then printf "adding pci option rom\n"
printf "building ifdtool from coreboot\n"
./build module cbutils default || Fail 'could not build ifdtool'
fi
if [ ! -f "coreboot/default/util/cbfstool/cbfstool" ]; then if [ "${_vga_dir}" != "${pciromsdir}" ]; then
printf "building cbfstool from coreboot\n" printf "Invalid PCI ROM directory: %s\n" ${_vga_dir}
./build module cbutils default || Fail 'could not build cbfstool' exit 1
fi fi
if [ ! -f "${_vga_location}" ]; then
printf "No such file exists: %s\n" ${_vga_location}
exit 1
fi
./blobutil download ${board} || \ ${cbfstool} ${rom} add -f "${_vga_location}" \
Fail "Could not download blobs for ${board}, check network connection" -n "pci${CONFIG_VGA_BIOS_ID}.rom" \
-t optionrom || exit 1
}
if [ "${release}" = "true" ]; then modify_gbe()
echo 'patching release file' {
Patch_release printf "changing mac address in gbe to ${new_mac}\n"
else
Patch ${rom} rom=${1}
fi # TODO: check if CONFIG_GBE_BIN_PATH is empty
# TODO: check that the gbe file actually exists
_gbe_location=${CONFIG_GBE_BIN_PATH#../../}
if [ ! -f ${nvmutil} ]; then
make -C util/nvmutil || fail 'failed to build nvmutil'
fi
_gbe_tmp=$(mktemp -t gbeXXXX.bin)
cp ${_gbe_location} ${_gbe_tmp}
${nvmutil} "${_gbe_tmp}" setmac ${new_mac} \
|| fail 'failed to modify mac address'
${ifdtool} -i GbE:${_gbe_tmp} "${rom}" \
-O "${rom}" || exit 1
rm -f ${_gbe_tmp}
}
listboards()
{
for boarddir in ${cbcfgsdir}/*; do
if [ ! -d "${boarddir}" ]; then continue; fi
board="${boarddir##${cbcfgsdir}/}"
board="${board%/}"
printf '%s\n' "${board##*/}"
done
}
fail()
{
if [ ! -z ${@+x} ]; then
printf "\nERROR: ${@}\n"
fi
usage
exit 1
}
usage()
{
cat <<- EOF
USAGE: ./blobutil inject -r [rom path] -b [boardname] -m [macaddress]
Example: ./blobutil 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 './blobutil inject listboards' to get a list of valid boards
EOF
}
main $@