From 06c92d4a4aa58e554b52283a7154b6e69c5b82e5 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sat, 27 May 2023 12:00:04 +0100 Subject: blobutil: merge with main script make blobutil a symlink. Example of command changes: ./blobutil download x220_8mb is now: ./update blobs download x220_8mb The old command still works, for compatibility. Signed-off-by: Leah Rowe --- blobutil | 50 +--- lbmk | 6 +- resources/scripts/blobs/download | 455 -------------------------------- resources/scripts/blobs/extract | 150 ----------- resources/scripts/blobs/inject | 398 ---------------------------- resources/scripts/update/blobs/download | 455 ++++++++++++++++++++++++++++++++ resources/scripts/update/blobs/extract | 150 +++++++++++ resources/scripts/update/blobs/inject | 398 ++++++++++++++++++++++++++++ 8 files changed, 1009 insertions(+), 1053 deletions(-) mode change 100755 => 120000 blobutil delete mode 100755 resources/scripts/blobs/download delete mode 100755 resources/scripts/blobs/extract delete mode 100755 resources/scripts/blobs/inject create mode 100755 resources/scripts/update/blobs/download create mode 100755 resources/scripts/update/blobs/extract create mode 100755 resources/scripts/update/blobs/inject diff --git a/blobutil b/blobutil deleted file mode 100755 index 2a14bb0b..00000000 --- a/blobutil +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -# SPDX-FileCopyrightText: 2022 Caleb La Grange -# SPDX-FileCopyrightText: 2023 Leah Rowe -# SPDX-License-Identifier: GPL-3.0-only - -script_dir="resources/scripts/blobs" -modes=$(ls -1 ${script_dir}) - -main() -{ - if [ $# -lt 1 ]; then - printf "%s: Error: you must specify a mode\n" $0 - usage - exit 1 - fi - - ./.gitcheck - - mode=${1} - shift - args=$@ - - if [ ! -f "${script_dir}/${mode}" ]; then - printf "Error: No mode ${mode}\n" - usage - exit 1 - fi - - ./${script_dir}/${mode} ${args} || exit 1 - - ./.gitcheck clean -} - -usage(){ - cat <<- EOF - Usage: ./blobutil [mode] - Example: ./blobutil download x230_12mb - - Possible options for mode are - ${modes} - - Mode descriptions: - download: Try to automatically generate blobs for specified board - inject: Inject blobs for specified board into specified rom - extract: Extract blobs from specified rom for specified board - EOF -} - -main $@ diff --git a/blobutil b/blobutil new file mode 120000 index 00000000..012b4ec0 --- /dev/null +++ b/blobutil @@ -0,0 +1 @@ +lbmk \ No newline at end of file diff --git a/lbmk b/lbmk index 16f479c4..e86190ed 100755 --- a/lbmk +++ b/lbmk @@ -34,7 +34,11 @@ main() if [ "${0##*/}" = "lbmk" ]; then die "Do not run the lbmk script directly!" elif [ "${0##*/}" = "download" ]; then - ./update module $@ + ./update module $@ || exit 1 + exit 0 + elif [ "${0##*/}" = "blobutil" ]; then + ./update blobs $@ || exit 1 + exit 0 elif [ $# -lt 2 ]; then die "Too few arguments. Try: ${0} help" fi diff --git a/resources/scripts/blobs/download b/resources/scripts/blobs/download deleted file mode 100755 index 57bdfe62..00000000 --- a/resources/scripts/blobs/download +++ /dev/null @@ -1,455 +0,0 @@ -#!/usr/bin/env bash - -# SPDX-FileCopyrightText: 2022 Caleb La Grange -# SPDX-FileCopyrightText: 2023 Leah Rowe -# SPDX-License-Identifier: GPL-3.0-only - -ec_url="" -ec_url_bkup="" -ec_hash="" -dl_hash="" -dl_url="" -dl_url_bkup="" -e6400_vga_dl_hash="" -e6400_vga_dl_url="" -e6400_vga_dl_url_bkup="" -e6400_vga_offset="" -e6400_vga_romname="" - -cbdir="coreboot/default" -cbcfgsdir="resources/coreboot" -boarddir="" -blobdir="blobs" -dl_path="${blobdir}/vendorupdate" -appdir="${blobdir}/app" -_7ztest="a" -mecleaner="$(pwd)/me_cleaner/me_cleaner.py" -e6400_unpack="$(pwd)/bios_extract/dell_inspiron_1100_unpacker.py" -me7updateparser="$(pwd)/resources/blobs/me7_update_parser.py" -kbc1126_ec_dump="$(pwd)/${cbdir}/util/kbc1126/kbc1126_ec_dump" -board="" -_b="" # board shorthand without e.g. _4mb (avoid duplication per flash size) - -CONFIG_HAVE_MRC="" -CONFIG_HAVE_IFD_BIN="" -CONFIG_HAVE_ME_BIN="" -CONFIG_HAVE_GBE_BIN="" -CONFIG_KBC1126_FIRMWARE="" -CONFIG_BOARD_DELL_E6400="" -CONFIG_VGA_BIOS_FILE="" - -main() -{ - board="${1}" - boarddir="${cbcfgsdir}/${board}" - - if [ ! -d "${boarddir}" ]; then - fail "Target not defined" - elif [ ! -f "${boarddir}/board.cfg" ]; then - fail "Target missing board.cfg" - fi - - detect_firmware || exit 0 - scan_sources_config - - build_dependencies - download_blobs -} - -detect_firmware() -{ - set -- "${boarddir}/config/"* - . ${1} 2>/dev/null - . "${boarddir}/board.cfg" - - if [ "${CONFIG_HAVE_MRC}" = "y" ]; then - needs+=" MRC" - fi - if [ "${CONFIG_HAVE_IFD_BIN}" = "y" ]; then - needs+=" IFD" - fi - if [ "${CONFIG_HAVE_ME_BIN}" = "y" ]; then - needs+=" ME" - fi - if [ "${CONFIG_HAVE_GBE_BIN}" = "y" ]; then - needs+=" GBE" - fi - if [ "${CONFIG_KBC1126_FIRMWARE}" = "y" ]; then - needs+=" EC" - fi - if [ "${CONFIG_BOARD_DELL_E6400}" = "y" ] \ - && [ "${CONFIG_VGA_BIOS_FILE}" != "" ]; then - needs+=" E6400VGA" - fi - if [ -z ${needs+x} ]; then - printf 'No binary blobs needed for this board\n' - return 1 - fi - printf "Firmware needed for board %s: %s\n" ${board} ${needs} -} - -scan_sources_config() -{ - # Shorthand (avoid duplicating configs per flash size) - _b=${board%%_*mb} - - awkstr=" /\{.*${_b}.*}{/ {flag=1;next} /\}/{flag=0} flag { print }" - - while read -r line ; do - case ${line} in - EC_url*) - set ${line} - ec_url=${2} - ;; - EC_url_bkup*) - set ${line} - ec_url_bkup=${2} - ;; - EC_hash*) - set ${line} - ec_hash=${2} - ;; - DL_hash*) - set ${line} - dl_hash=${2} - ;; - DL_url*) - set ${line} - dl_url=${2} - ;; - DL_url_bkup*) - set ${line} - dl_url_bkup=${2} - ;; - E6400_VGA_DL_hash*) - set ${line} - e6400_vga_dl_hash=${2} - ;; - E6400_VGA_DL_url*) - set ${line} - e6400_vga_dl_url=${2} - ;; - E6400_VGA_DL_url_bkup*) - set ${line} - e6400_vga_dl_url_bkup=${2} - ;; - E6400_VGA_offset*) - set ${line} - e6400_vga_offset=${2} - ;; - E6400_VGA_romname*) - set ${line} - e6400_vga_romname=${2} - ;; - esac - done <<< $(eval "awk '${awkstr}' resources/blobs/sources") -} - -build_dependencies() -{ - if [ ! -d me_cleaner ]; then - printf "downloading me_cleaner\n" - ./download me_cleaner || fail "could not download me_cleaner" - fi - if [ ! -d ${cbdir} ]; then - printf "downloading coreboot\n" - ./download coreboot default \ - || fail "could not download coreboot" - fi - if [ ! -d bios_extract ]; then - printf "downloading bios_extract\n" - ./download bios_extract \ - || fail "could not download bios_extract" - fi - if [ ! -f ${cbdir}/util/kbc1126/kbc1126_ec_dump ]; then - printf "Building kbc1126_ec_dump from coreboot\n" - make -BC ${cbdir}/util/kbc1126 \ - || fail "could not build kbc1126_ec_dump" - fi - if [ ! -f "${cbdir}/util/ifdtool/ifdtool" ]; then - printf "building ifdtool from coreboot\n" - make -C ${cbdir}/util/ifdtool \ - || fail 'could not build ifdtool' - fi -} - -download_blobs() -{ - for need in ${needs}; do - case ${need} in - *ME*) - download_blob_intel_me || _failed+=" me" - ;; - *EC*) - download_ec || _failed+=" ec" - ;; - *E6400VGA*) - download_e6400vga || _failed+=" e6400vga" - ;; - *MRC*) - ./download mrc || _failed+=" mrc" - ;; - esac - done - - if [ ! -z ${_failed+x} ]; then - fail "failed to obtain ${_failed}\nTry manual extraction?" - fi -} - -download_blob_intel_me() -{ - printf "Downloading neutered ME for board: %s\n" ${board} - - fetch_update me || return 1 - extract_blob_intel_me || return 1 -} - -extract_blob_intel_me() -{ - printf "Extracting neutered ME for ${board}\n" - - _me_destination=${CONFIG_ME_BIN_PATH#../../} - - if [ ! -d "${_me_destination%/*}" ]; then - mkdir -p ${_me_destination%/*} - fi - if [ -d "${appdir}" ]; then - rm -r ${appdir} - fi - if [ -f "${_me_destination}" ]; then - printf 'me already downloaded\n' - return 0 - fi - - printf "Extracting and stripping Intel ME firmware\n" - - innoextract ${dl_path} -d ${blobdir} \ - || 7z x ${dl_path} -o${appdir} \ - || fail 'Could not extract vendor update' - - bruteforce_extract_blob_intel_me "$(pwd)/${_me_destination}" \ - "$(pwd)/${appdir}" \ - || fail "Could not extract Intel ME firmware" - - printf "Truncated and cleaned me output to ${_me_destination}\n" -} - -# cursed, carcinogenic code. TODO rewrite it better -bruteforce_extract_blob_intel_me() -{ - _me_destination="${1}" - cdir="${2}" # must be an absolute path, not relative - - if [ -f "${_me_destination}" ]; then - return 0 - fi - - sdir="$(mktemp -d)" - mkdir -p "${sdir}" || return 1 - - ( - printf "Entering %s\n" "${cdir}" - cd "${cdir}" || exit 1 - for i in *; do - if [ -f "${_me_destination}" ]; then - # me.bin found, so avoid needless further traversal - break - elif [ -L "${i}" ]; then - # symlinks are a security risk, in this context - continue - elif [ -f "${i}" ]; then - "${mecleaner}" -r -t -O "${sdir}/vendorfile" \ - -M "${_me_destination}" "${i}" \ - && break # (we found me.bin) - "${mecleaner}" -r -t -O "${_me_destination}" "${i}" \ - && break # (we found me.bin) - "${me7updateparser}" -O ${_me_destination} "${i}" \ - && break # (we found me.bin) - _7ztest="${_7ztest}a" - 7z x "${i}" -o${_7ztest} || continue - bruteforce_extract_blob_intel_me "${_me_destination}" \ - "${cdir}/${_7ztest}" - cdir="${1}" - cd "${cdir}" - elif [ -d "$i" ]; then - bruteforce_extract_blob_intel_me "${_me_destination}" \ - "${cdir}/${i}" - cdir="${1}" - cd "${cdir}" - else - printf "SKIPPING: %s\n" "${i}" - fi - done - ) - - rm -Rf "${sdir}" - - if [ ! -f "${_me_destination}" ]; then - printf "me.bin not found in vendor update for: %s\n" ${board} - return 1 - fi -} - -download_ec() -{ - printf "Downloading KBC1126 EC firmware for HP laptop\n" - - fetch_update ec || return 1 - extract_ec || return 1 -} - -extract_ec() -{ - printf "Extracting KBC1126 EC firmware for board: %s\n" ${board} - - _ec_destination=${CONFIG_KBC1126_FW1#../../} - - if [ ! -d "${_ec_destination%/*}" ]; then - mkdir -p "${_ec_destination%/*}" - fi - if [ -d "${appdir}" ]; then - rm -Rf "${appdir}" - fi - if [ -f "${_ec_destination}" ]; then - printf "ec already downloaded\n" - return 0 - fi - - unar "${dl_path}" -o "${appdir}" - - ( - cd "${appdir}/${dl_path##*/}" - - mv Rompaq/68*.BIN ec.bin - if [ ! -f ec.bin ]; then - unar -D ROM.CAB Rom.bin - mv Rom.bin ec.bin - fi - - "${kbc1126_ec_dump}" ec.bin - ) - - for i in 1 2; do - if [ -f "${appdir}/${dl_path##*/}/ec.bin.fw${i}" ]; then - continue - fi - printf "Not found: %s/%s/ec.bin.fw%s\n" \ - ${appdir} ${dl_path##*/} ${i} - printf "Could not extract EC firmware for: %s\n" \ - ${board} - return 1 - done - - cp "${appdir}/${dl_path##*/}"/ec.bin.fw* "${_ec_destination%/*}/" -} - -download_e6400vga() -{ - printf "Downloading Nvidia VGA ROM for Dell Latitude E6400\n" - - fetch_update e6400vga || return 1 - extract_e6400vga || return 1 -} - -extract_e6400vga() -{ - printf "Extracting Nvidia VGA ROM for ${board}\n" - - _vga_destination=${CONFIG_VGA_BIOS_FILE#../../} - - if [ -f "${_vga_destination}" ]; then - printf 'vga rom already downloaded\n' - return 0 - fi - if [ ! -d "${_vga_destination%/*}" ]; then - mkdir -p ${_vga_destination%/*} - fi - if [ -d "${appdir}" ]; then - rm -r ${appdir} - fi - - mkdir -p "${appdir}" - mv "${dl_path}" "${appdir}" - - if [ "${e6400_vga_offset}" = "" ]; then - printf "E6400 VGA offset not defined\n" - return 1 - elif [ "${e6400_vga_romname}" = "" ]; then - printf "E6400 VGA ROM name not defined\n" - return 1 - fi - - ( - cd "${appdir}" - tail -c +${e6400_vga_offset} "${dl_path##*/}" \ - | gunzip > bios.bin - if [ ! -f "bios.bin" ]; then - fail 'Could not extract bios.bin from Dell E6400 update' - fi - "${e6400_unpack}" bios.bin || printf "TODO: fix dell extract util\n" - if [ ! -f "${e6400_vga_romname}" ]; then - fail 'Could not extract VGA ROM from Dell E6400 BIOS update' - fi - ) - - cp "${appdir}"/"${e6400_vga_romname}" "${_vga_destination}" - - printf "E6400 Nvidia ROM saved to: %s\n" "${_vga_destination}" -} - -fetch_update() -{ - printf "Fetching vendor update for board: %s\n" ${board} - - fw_type="${1}" - dl="" - dl_bkup="" - dlsum="" - if [ "${fw_type}" = "me" ]; then - dl=${dl_url} - dl_bkup=${dl_url_bkup} - dlsum=${dl_hash} - elif [ "${fw_type}" = "ec" ]; then - dl=${ec_url} - dl_bkup=${ec_url_bkup} - dlsum=${ec_hash} - elif [ "${fw_type}" = "e6400vga" ]; then - dl=${e6400_vga_dl_url} - dl_bkup=${e6400_vga_dl_url_bkup} - dlsum=${e6400_vga_dl_hash} - else - printf "Unsupported download type: %s\n" ${fw_type} - return 1 - fi - - if [ -z "${dl_url+x}" ] && [ "${fw_type}" != "e6400vga" ]; then - printf "No vendor update specified for board: %s\n" ${board} - return 1 - fi - - vendor_checksum ${dlsum} || \ - wget ${dl} -O ${dl_path} || wget ${dl_bkup} -O ${dl_path} - - vendor_checksum ${dlsum} || fail \ - "Cannot guarantee intergity of vendor update for: ${board}" -} - -vendor_checksum() -{ - if [ ! -f "${dl_path}" ]; then - printf "Vendor update not found on disk for: %s\n" ${board} - return 1 - elif [ "$(sha1sum ${dl_path} | awk '{print $1}')" != "${1}" ]; then - printf "Bad checksum on vendor update for: %s\n" ${board} - return 1 - fi -} - -fail() -{ - printf "\nERROR: $@\n" - exit 1 -} - -main $@ diff --git a/resources/scripts/blobs/extract b/resources/scripts/blobs/extract deleted file mode 100755 index 8e9c74ed..00000000 --- a/resources/scripts/blobs/extract +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env bash -# script to automate extracting blobs from an existing vendor bios - -# SPDX-FileCopyrightText: 2022 Caleb La Grange -# SPDX-FileCopyrightText: 2023 Leah Rowe -# SPDX-License-Identifier: GPL-3.0-only - -sname="" -board="" -vendor_rom="" - -cbdir="coreboot/default" -cbcfgsdir="resources/coreboot" -ifdtool="${cbdir}/util/ifdtool/ifdtool" -mecleaner="me_cleaner/me_cleaner.py" -me7updateparser="resources/blobs/me7_update_parser.py" - -boarddir="" - -CONFIG_HAVE_MRC="" -CONFIG_ME_BIN_PATH="" -CONFIG_GBE_BIN_PATH="" -CONFIG_IFD_BIN_PATH="" - -_me_destination="" -_gbe_destination="" -_ifd_destination="" - -main() -{ - sname=${0} - if [ $# -lt 2 ]; then - fail "Missing arguments (less than two)." - fi - - board="${1}" - vendor_rom="${2}" - - boarddir="${cbcfgsdir}/${board}" - - check_board - build_dependencies - extract_blobs -} - -check_board() -{ - if [ ! -f "${vendor_rom}" ] ; then - fail "file does not exist: ${vendor_rom}" - elif [ ! -d "${boarddir}" ]; then - fail "build/roms ${board}: target not defined" - elif [ ! -f "${boarddir}/board.cfg" ]; then - fail "build/roms ${board}: missing board.cfg" - fi -} - -build_dependencies() -{ - if [ ! -d me_cleaner ]; then - printf "downloading me_cleaner\n" - ./download me_cleaner || fail 'could not download me_cleaner' - else - printf "me_cleaner already downloaded. Skipping.\n" - printf "run ./download me_cleaner to manually overwrite\n" - fi - - if [ ! -d ${cbdir} ]; then - printf "downloading coreboot\n" - ./download coreboot default \ - || fail "could not download coreboot" - else - printf "coreboot already downloaded. Skipping.\n" - printf "run ./download coreboot to manually overwrite\n" - fi - - if ! [ -f ${ifdtool} ]; then - printf "building ifdtool from coreboot\n" - make -C "${ifdtool%/ifdtool}" \ - || fail "could not build ifdtool" - fi -} - -extract_blobs() -{ - printf "extracting blobs for %s from %s\n" ${board} ${vendor_rom} - - set -- "${boarddir}/config/"* - . ${1} 2>/dev/null - . "${boarddir}/board.cfg" - - if [ "$CONFIG_HAVE_MRC" = "y" ]; then - printf 'haswell board detected, downloading mrc\n' - ./download mrc || fail "could not download mrc" - fi - - _me_destination=${CONFIG_ME_BIN_PATH#../../} - _gbe_destination=${CONFIG_GBE_BIN_PATH#../../} - _ifd_destination=${CONFIG_IFD_BIN_PATH#../../} - - extract_blob_intel_me - extract_blob_intel_gbe_nvm - - # Cleans up other files extracted with ifdtool - rm -f flashregion*.bin 2> /dev/null - - if [ -f ${_ifd_destination} ]; then - printf "gbe, ifd, and me extracted to %s\n" \ - ${_me_destination%/*} - else - printf "WARNING: Intel firmware descriptor could not " - printf "be extracted with modified me\n" - fi -} - -extract_blob_intel_me() -{ - printf "extracting clean ime and modified ifd\n" - - ${mecleaner} -D ${_ifd_destination} \ - -M ${_me_destination} ${vendor_rom} -t -r -S \ - || ${me7updateparser} \ - -O ${_me_destination} ${vendor_rom} \ - || fail \ - "me_cleaner failed to extract blobs from rom" -} - -extract_blob_intel_gbe_nvm() -{ - printf "extracting gigabit ethernet firmware" - ./${ifdtool} -x ${vendor_rom} - mv flashregion*gbe.bin ${_gbe_destination} \ - || fail 'could not extract gbe' -} - -fail() -{ - print_help - - printf "\n%s: ERROR: %s\n" ${sname} $@ - exit 1 -} - -print_help() -{ - printf "Usage: ./blobutil extract {boardname} {path/to/vendor_rom}\n" - printf "Example: ./blobutil extract x230 12mb_flash.bin\n" - printf "\nYou need to specify exactly 2 arguments\n" -} - -main $@ diff --git a/resources/scripts/blobs/inject b/resources/scripts/blobs/inject deleted file mode 100755 index 51f67255..00000000 --- a/resources/scripts/blobs/inject +++ /dev/null @@ -1,398 +0,0 @@ -#!/usr/bin/env bash - -# SPDX-FileCopyrightText: 2022 Caleb La Grange -# SPDX-FileCopyrightText: 2023 Leah Rowe -# SPDX-License-Identifier: GPL-3.0-only - -sname="" -archive="" -_filetype="" -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() -{ - sname="${0}" - - if [ $# -lt 1 ]; then - fail "No options specified." - elif [ "${1}" = "listboards" ]; then - listboards - exit 0 - fi - - archive="${1}" - - while getopts r:b:m: option - do - case "${option}" - in - r)rom=${OPTARG};; - b)board=${OPTARG};; - m) - modifygbe=true - new_mac=${OPTARG} - ;; - esac - 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. -# 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=$(cut -d '_' -f2-3 <<<${filename}) - ;; - seabios_withgrub_*) - board=$(cut -d '_' -f3-4 <<<${filename}) - ;; - *.tar.xz) - _stripped_prefix=${filename#*_} - board="${_stripped_prefix%.tar.xz}" - ;; - *) - return 1 - esac - - if [ -d "${boarddir}/" ]; then - printf '%s\n' "${board}" - return 0 - else - return 1 - fi -} - -build_dependencies() -{ - if [ ! -d ${cbdir} ]; then - printf "downloading coreboot\n" - ./download coreboot default - fi - - if [ ! -f "${ifdtool}" ]; then - printf "building ifdtool from coreboot\n" - ./build module cbutils default \ - || fail 'could not build ifdtool' - fi - - if [ ! -f "${cbfstool}" ]; then - printf "building cbfstool from coreboot\n" - ./build module cbutils default \ - || fail 'could not build cbfstool' - fi - - ./blobutil download ${board} || \ - fail "Could not download blobs for ${board}" -} - -inject_blobs() -{ - if [ "${release}" = "true" ]; then - echo 'patching release file' - patch_release_roms - else - patch_rom ${rom} - fi -} - -patch_release_roms() -{ - _tmpdir=$(mktemp -d "/tmp/${board}_tmpXXXX") - tar xf "${releasearchive}" -C "${_tmpdir}" || \ - fail 'could not extract release archive' - - for x in ${_tmpdir}/bin/*/*.rom ; do - echo "patching rom $x" - patch_rom ${x} || fail "could not patch ${x}" - done - - ( - cd ${_tmpdir}/bin/* - sha1sum --status -c blobhashes || \ - fail 'ROMs did not match expected hashes' - ) - - if [ "${modifygbe}" = "true" ]; then - for x in ${_tmpdir}/bin/*/*.rom ; do - modify_gbe ${x} - done - fi - - if ! [ -d bin/release ]; then - mkdir -p bin/release - fi - - mv ${_tmpdir}/bin/* bin/release/ && \ - printf '%s\n' 'Success! Your ROMs are in bin/release' - - rm -r "${_tmpdir}" -} - -patch_rom() -{ - rom="${1}" - - set -- "${boarddir}/config/"* - . ${1} 2>/dev/null - . "${boarddir}/board.cfg" - - if [ "$CONFIG_HAVE_MRC" = "y" ]; then - inject_blob_intel_mrc "${rom}" - 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 -} - -inject_blob_intel_mrc() -{ - rom="${1}" - - printf 'adding mrc\n' - - # mrc.bin must be inserted at a specific offset. the only - # libreboot platform that needs it, at present, is haswell - - # in cbfstool, -b values above 0x80000000 are interpreted as - # top-aligned x86 memory locations. this is converted into an - # absolute offset within the flash, and inserted accordingly - # at that offset into the ROM image file - - # coreboot's own build system hardcodes the mrc.bin offset - # because there is only one correct location in memory, but - # it would be useful for lbmk if it could be easily scanned - # from Kconfig, with the option to change it where in practise - # it is not changed - - # the hardcoded offset below is based upon reading of the coreboot - # source code, and it is *always* correct for haswell platform. - # TODO: this logic should be tweaked to handle more platforms - - ${cbfstool} ${rom} add -f mrc/haswell/mrc.bin -n mrc.bin -t mrc \ - -b 0xfffa0000 || exit 1 -} - -inject_blob_intel_me() -{ - printf 'adding intel management engine\n' - - rom="${1}" - - if [ -z ${CONFIG_ME_BIN_PATH} ]; then - fail "CONFIG_ME_BIN_PATH not set" - fi - - _me_location=${CONFIG_ME_BIN_PATH#../../} - - if [ ! -f "${_me_location}" ]; then - fail "CONFIG_ME_BIN_PATH points to missing file" - fi - - ${ifdtool} -i me:${_me_location} ${rom} -O ${rom} || exit 1 -} - -inject_blob_hp_kbc1126_ec() -{ - 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 - - ${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 -} - -inject_blob_dell_e6400_vgarom_nvidia() -{ - rom="${1}" - - _vga_location="${CONFIG_VGA_BIOS_FILE#../../}" - _vga_dir="${_vga_location%/*}" - _vga_filename="${_vga_location##*/}" - - printf "adding pci option rom\n" - - if [ "${_vga_dir}" != "${pciromsdir}" ]; 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 - - ${cbfstool} ${rom} add -f "${_vga_location}" \ - -n "pci${CONFIG_VGA_BIOS_ID}.rom" \ - -t optionrom || exit 1 -} - -modify_gbe() -{ - printf "changing mac address in gbe to ${new_mac}\n" - - rom=${1} - - if [ -z ${CONFIG_GBE_BIN_PATH} ]; then - fail "CONFIG_GBE_BIN_PATH not set" - fi - - _gbe_location=${CONFIG_GBE_BIN_PATH#../../} - - if [ ! -f "${_gbe_location}" ]; then - fail "CONFIG_GBE_BIN_PATH points to missing file" - fi - - 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 "\n%s: ERROR: ${@}\n" ${sname} - 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 $@ diff --git a/resources/scripts/update/blobs/download b/resources/scripts/update/blobs/download new file mode 100755 index 00000000..57bdfe62 --- /dev/null +++ b/resources/scripts/update/blobs/download @@ -0,0 +1,455 @@ +#!/usr/bin/env bash + +# SPDX-FileCopyrightText: 2022 Caleb La Grange +# SPDX-FileCopyrightText: 2023 Leah Rowe +# SPDX-License-Identifier: GPL-3.0-only + +ec_url="" +ec_url_bkup="" +ec_hash="" +dl_hash="" +dl_url="" +dl_url_bkup="" +e6400_vga_dl_hash="" +e6400_vga_dl_url="" +e6400_vga_dl_url_bkup="" +e6400_vga_offset="" +e6400_vga_romname="" + +cbdir="coreboot/default" +cbcfgsdir="resources/coreboot" +boarddir="" +blobdir="blobs" +dl_path="${blobdir}/vendorupdate" +appdir="${blobdir}/app" +_7ztest="a" +mecleaner="$(pwd)/me_cleaner/me_cleaner.py" +e6400_unpack="$(pwd)/bios_extract/dell_inspiron_1100_unpacker.py" +me7updateparser="$(pwd)/resources/blobs/me7_update_parser.py" +kbc1126_ec_dump="$(pwd)/${cbdir}/util/kbc1126/kbc1126_ec_dump" +board="" +_b="" # board shorthand without e.g. _4mb (avoid duplication per flash size) + +CONFIG_HAVE_MRC="" +CONFIG_HAVE_IFD_BIN="" +CONFIG_HAVE_ME_BIN="" +CONFIG_HAVE_GBE_BIN="" +CONFIG_KBC1126_FIRMWARE="" +CONFIG_BOARD_DELL_E6400="" +CONFIG_VGA_BIOS_FILE="" + +main() +{ + board="${1}" + boarddir="${cbcfgsdir}/${board}" + + if [ ! -d "${boarddir}" ]; then + fail "Target not defined" + elif [ ! -f "${boarddir}/board.cfg" ]; then + fail "Target missing board.cfg" + fi + + detect_firmware || exit 0 + scan_sources_config + + build_dependencies + download_blobs +} + +detect_firmware() +{ + set -- "${boarddir}/config/"* + . ${1} 2>/dev/null + . "${boarddir}/board.cfg" + + if [ "${CONFIG_HAVE_MRC}" = "y" ]; then + needs+=" MRC" + fi + if [ "${CONFIG_HAVE_IFD_BIN}" = "y" ]; then + needs+=" IFD" + fi + if [ "${CONFIG_HAVE_ME_BIN}" = "y" ]; then + needs+=" ME" + fi + if [ "${CONFIG_HAVE_GBE_BIN}" = "y" ]; then + needs+=" GBE" + fi + if [ "${CONFIG_KBC1126_FIRMWARE}" = "y" ]; then + needs+=" EC" + fi + if [ "${CONFIG_BOARD_DELL_E6400}" = "y" ] \ + && [ "${CONFIG_VGA_BIOS_FILE}" != "" ]; then + needs+=" E6400VGA" + fi + if [ -z ${needs+x} ]; then + printf 'No binary blobs needed for this board\n' + return 1 + fi + printf "Firmware needed for board %s: %s\n" ${board} ${needs} +} + +scan_sources_config() +{ + # Shorthand (avoid duplicating configs per flash size) + _b=${board%%_*mb} + + awkstr=" /\{.*${_b}.*}{/ {flag=1;next} /\}/{flag=0} flag { print }" + + while read -r line ; do + case ${line} in + EC_url*) + set ${line} + ec_url=${2} + ;; + EC_url_bkup*) + set ${line} + ec_url_bkup=${2} + ;; + EC_hash*) + set ${line} + ec_hash=${2} + ;; + DL_hash*) + set ${line} + dl_hash=${2} + ;; + DL_url*) + set ${line} + dl_url=${2} + ;; + DL_url_bkup*) + set ${line} + dl_url_bkup=${2} + ;; + E6400_VGA_DL_hash*) + set ${line} + e6400_vga_dl_hash=${2} + ;; + E6400_VGA_DL_url*) + set ${line} + e6400_vga_dl_url=${2} + ;; + E6400_VGA_DL_url_bkup*) + set ${line} + e6400_vga_dl_url_bkup=${2} + ;; + E6400_VGA_offset*) + set ${line} + e6400_vga_offset=${2} + ;; + E6400_VGA_romname*) + set ${line} + e6400_vga_romname=${2} + ;; + esac + done <<< $(eval "awk '${awkstr}' resources/blobs/sources") +} + +build_dependencies() +{ + if [ ! -d me_cleaner ]; then + printf "downloading me_cleaner\n" + ./download me_cleaner || fail "could not download me_cleaner" + fi + if [ ! -d ${cbdir} ]; then + printf "downloading coreboot\n" + ./download coreboot default \ + || fail "could not download coreboot" + fi + if [ ! -d bios_extract ]; then + printf "downloading bios_extract\n" + ./download bios_extract \ + || fail "could not download bios_extract" + fi + if [ ! -f ${cbdir}/util/kbc1126/kbc1126_ec_dump ]; then + printf "Building kbc1126_ec_dump from coreboot\n" + make -BC ${cbdir}/util/kbc1126 \ + || fail "could not build kbc1126_ec_dump" + fi + if [ ! -f "${cbdir}/util/ifdtool/ifdtool" ]; then + printf "building ifdtool from coreboot\n" + make -C ${cbdir}/util/ifdtool \ + || fail 'could not build ifdtool' + fi +} + +download_blobs() +{ + for need in ${needs}; do + case ${need} in + *ME*) + download_blob_intel_me || _failed+=" me" + ;; + *EC*) + download_ec || _failed+=" ec" + ;; + *E6400VGA*) + download_e6400vga || _failed+=" e6400vga" + ;; + *MRC*) + ./download mrc || _failed+=" mrc" + ;; + esac + done + + if [ ! -z ${_failed+x} ]; then + fail "failed to obtain ${_failed}\nTry manual extraction?" + fi +} + +download_blob_intel_me() +{ + printf "Downloading neutered ME for board: %s\n" ${board} + + fetch_update me || return 1 + extract_blob_intel_me || return 1 +} + +extract_blob_intel_me() +{ + printf "Extracting neutered ME for ${board}\n" + + _me_destination=${CONFIG_ME_BIN_PATH#../../} + + if [ ! -d "${_me_destination%/*}" ]; then + mkdir -p ${_me_destination%/*} + fi + if [ -d "${appdir}" ]; then + rm -r ${appdir} + fi + if [ -f "${_me_destination}" ]; then + printf 'me already downloaded\n' + return 0 + fi + + printf "Extracting and stripping Intel ME firmware\n" + + innoextract ${dl_path} -d ${blobdir} \ + || 7z x ${dl_path} -o${appdir} \ + || fail 'Could not extract vendor update' + + bruteforce_extract_blob_intel_me "$(pwd)/${_me_destination}" \ + "$(pwd)/${appdir}" \ + || fail "Could not extract Intel ME firmware" + + printf "Truncated and cleaned me output to ${_me_destination}\n" +} + +# cursed, carcinogenic code. TODO rewrite it better +bruteforce_extract_blob_intel_me() +{ + _me_destination="${1}" + cdir="${2}" # must be an absolute path, not relative + + if [ -f "${_me_destination}" ]; then + return 0 + fi + + sdir="$(mktemp -d)" + mkdir -p "${sdir}" || return 1 + + ( + printf "Entering %s\n" "${cdir}" + cd "${cdir}" || exit 1 + for i in *; do + if [ -f "${_me_destination}" ]; then + # me.bin found, so avoid needless further traversal + break + elif [ -L "${i}" ]; then + # symlinks are a security risk, in this context + continue + elif [ -f "${i}" ]; then + "${mecleaner}" -r -t -O "${sdir}/vendorfile" \ + -M "${_me_destination}" "${i}" \ + && break # (we found me.bin) + "${mecleaner}" -r -t -O "${_me_destination}" "${i}" \ + && break # (we found me.bin) + "${me7updateparser}" -O ${_me_destination} "${i}" \ + && break # (we found me.bin) + _7ztest="${_7ztest}a" + 7z x "${i}" -o${_7ztest} || continue + bruteforce_extract_blob_intel_me "${_me_destination}" \ + "${cdir}/${_7ztest}" + cdir="${1}" + cd "${cdir}" + elif [ -d "$i" ]; then + bruteforce_extract_blob_intel_me "${_me_destination}" \ + "${cdir}/${i}" + cdir="${1}" + cd "${cdir}" + else + printf "SKIPPING: %s\n" "${i}" + fi + done + ) + + rm -Rf "${sdir}" + + if [ ! -f "${_me_destination}" ]; then + printf "me.bin not found in vendor update for: %s\n" ${board} + return 1 + fi +} + +download_ec() +{ + printf "Downloading KBC1126 EC firmware for HP laptop\n" + + fetch_update ec || return 1 + extract_ec || return 1 +} + +extract_ec() +{ + printf "Extracting KBC1126 EC firmware for board: %s\n" ${board} + + _ec_destination=${CONFIG_KBC1126_FW1#../../} + + if [ ! -d "${_ec_destination%/*}" ]; then + mkdir -p "${_ec_destination%/*}" + fi + if [ -d "${appdir}" ]; then + rm -Rf "${appdir}" + fi + if [ -f "${_ec_destination}" ]; then + printf "ec already downloaded\n" + return 0 + fi + + unar "${dl_path}" -o "${appdir}" + + ( + cd "${appdir}/${dl_path##*/}" + + mv Rompaq/68*.BIN ec.bin + if [ ! -f ec.bin ]; then + unar -D ROM.CAB Rom.bin + mv Rom.bin ec.bin + fi + + "${kbc1126_ec_dump}" ec.bin + ) + + for i in 1 2; do + if [ -f "${appdir}/${dl_path##*/}/ec.bin.fw${i}" ]; then + continue + fi + printf "Not found: %s/%s/ec.bin.fw%s\n" \ + ${appdir} ${dl_path##*/} ${i} + printf "Could not extract EC firmware for: %s\n" \ + ${board} + return 1 + done + + cp "${appdir}/${dl_path##*/}"/ec.bin.fw* "${_ec_destination%/*}/" +} + +download_e6400vga() +{ + printf "Downloading Nvidia VGA ROM for Dell Latitude E6400\n" + + fetch_update e6400vga || return 1 + extract_e6400vga || return 1 +} + +extract_e6400vga() +{ + printf "Extracting Nvidia VGA ROM for ${board}\n" + + _vga_destination=${CONFIG_VGA_BIOS_FILE#../../} + + if [ -f "${_vga_destination}" ]; then + printf 'vga rom already downloaded\n' + return 0 + fi + if [ ! -d "${_vga_destination%/*}" ]; then + mkdir -p ${_vga_destination%/*} + fi + if [ -d "${appdir}" ]; then + rm -r ${appdir} + fi + + mkdir -p "${appdir}" + mv "${dl_path}" "${appdir}" + + if [ "${e6400_vga_offset}" = "" ]; then + printf "E6400 VGA offset not defined\n" + return 1 + elif [ "${e6400_vga_romname}" = "" ]; then + printf "E6400 VGA ROM name not defined\n" + return 1 + fi + + ( + cd "${appdir}" + tail -c +${e6400_vga_offset} "${dl_path##*/}" \ + | gunzip > bios.bin + if [ ! -f "bios.bin" ]; then + fail 'Could not extract bios.bin from Dell E6400 update' + fi + "${e6400_unpack}" bios.bin || printf "TODO: fix dell extract util\n" + if [ ! -f "${e6400_vga_romname}" ]; then + fail 'Could not extract VGA ROM from Dell E6400 BIOS update' + fi + ) + + cp "${appdir}"/"${e6400_vga_romname}" "${_vga_destination}" + + printf "E6400 Nvidia ROM saved to: %s\n" "${_vga_destination}" +} + +fetch_update() +{ + printf "Fetching vendor update for board: %s\n" ${board} + + fw_type="${1}" + dl="" + dl_bkup="" + dlsum="" + if [ "${fw_type}" = "me" ]; then + dl=${dl_url} + dl_bkup=${dl_url_bkup} + dlsum=${dl_hash} + elif [ "${fw_type}" = "ec" ]; then + dl=${ec_url} + dl_bkup=${ec_url_bkup} + dlsum=${ec_hash} + elif [ "${fw_type}" = "e6400vga" ]; then + dl=${e6400_vga_dl_url} + dl_bkup=${e6400_vga_dl_url_bkup} + dlsum=${e6400_vga_dl_hash} + else + printf "Unsupported download type: %s\n" ${fw_type} + return 1 + fi + + if [ -z "${dl_url+x}" ] && [ "${fw_type}" != "e6400vga" ]; then + printf "No vendor update specified for board: %s\n" ${board} + return 1 + fi + + vendor_checksum ${dlsum} || \ + wget ${dl} -O ${dl_path} || wget ${dl_bkup} -O ${dl_path} + + vendor_checksum ${dlsum} || fail \ + "Cannot guarantee intergity of vendor update for: ${board}" +} + +vendor_checksum() +{ + if [ ! -f "${dl_path}" ]; then + printf "Vendor update not found on disk for: %s\n" ${board} + return 1 + elif [ "$(sha1sum ${dl_path} | awk '{print $1}')" != "${1}" ]; then + printf "Bad checksum on vendor update for: %s\n" ${board} + return 1 + fi +} + +fail() +{ + printf "\nERROR: $@\n" + exit 1 +} + +main $@ diff --git a/resources/scripts/update/blobs/extract b/resources/scripts/update/blobs/extract new file mode 100755 index 00000000..8e9c74ed --- /dev/null +++ b/resources/scripts/update/blobs/extract @@ -0,0 +1,150 @@ +#!/usr/bin/env bash +# script to automate extracting blobs from an existing vendor bios + +# SPDX-FileCopyrightText: 2022 Caleb La Grange +# SPDX-FileCopyrightText: 2023 Leah Rowe +# SPDX-License-Identifier: GPL-3.0-only + +sname="" +board="" +vendor_rom="" + +cbdir="coreboot/default" +cbcfgsdir="resources/coreboot" +ifdtool="${cbdir}/util/ifdtool/ifdtool" +mecleaner="me_cleaner/me_cleaner.py" +me7updateparser="resources/blobs/me7_update_parser.py" + +boarddir="" + +CONFIG_HAVE_MRC="" +CONFIG_ME_BIN_PATH="" +CONFIG_GBE_BIN_PATH="" +CONFIG_IFD_BIN_PATH="" + +_me_destination="" +_gbe_destination="" +_ifd_destination="" + +main() +{ + sname=${0} + if [ $# -lt 2 ]; then + fail "Missing arguments (less than two)." + fi + + board="${1}" + vendor_rom="${2}" + + boarddir="${cbcfgsdir}/${board}" + + check_board + build_dependencies + extract_blobs +} + +check_board() +{ + if [ ! -f "${vendor_rom}" ] ; then + fail "file does not exist: ${vendor_rom}" + elif [ ! -d "${boarddir}" ]; then + fail "build/roms ${board}: target not defined" + elif [ ! -f "${boarddir}/board.cfg" ]; then + fail "build/roms ${board}: missing board.cfg" + fi +} + +build_dependencies() +{ + if [ ! -d me_cleaner ]; then + printf "downloading me_cleaner\n" + ./download me_cleaner || fail 'could not download me_cleaner' + else + printf "me_cleaner already downloaded. Skipping.\n" + printf "run ./download me_cleaner to manually overwrite\n" + fi + + if [ ! -d ${cbdir} ]; then + printf "downloading coreboot\n" + ./download coreboot default \ + || fail "could not download coreboot" + else + printf "coreboot already downloaded. Skipping.\n" + printf "run ./download coreboot to manually overwrite\n" + fi + + if ! [ -f ${ifdtool} ]; then + printf "building ifdtool from coreboot\n" + make -C "${ifdtool%/ifdtool}" \ + || fail "could not build ifdtool" + fi +} + +extract_blobs() +{ + printf "extracting blobs for %s from %s\n" ${board} ${vendor_rom} + + set -- "${boarddir}/config/"* + . ${1} 2>/dev/null + . "${boarddir}/board.cfg" + + if [ "$CONFIG_HAVE_MRC" = "y" ]; then + printf 'haswell board detected, downloading mrc\n' + ./download mrc || fail "could not download mrc" + fi + + _me_destination=${CONFIG_ME_BIN_PATH#../../} + _gbe_destination=${CONFIG_GBE_BIN_PATH#../../} + _ifd_destination=${CONFIG_IFD_BIN_PATH#../../} + + extract_blob_intel_me + extract_blob_intel_gbe_nvm + + # Cleans up other files extracted with ifdtool + rm -f flashregion*.bin 2> /dev/null + + if [ -f ${_ifd_destination} ]; then + printf "gbe, ifd, and me extracted to %s\n" \ + ${_me_destination%/*} + else + printf "WARNING: Intel firmware descriptor could not " + printf "be extracted with modified me\n" + fi +} + +extract_blob_intel_me() +{ + printf "extracting clean ime and modified ifd\n" + + ${mecleaner} -D ${_ifd_destination} \ + -M ${_me_destination} ${vendor_rom} -t -r -S \ + || ${me7updateparser} \ + -O ${_me_destination} ${vendor_rom} \ + || fail \ + "me_cleaner failed to extract blobs from rom" +} + +extract_blob_intel_gbe_nvm() +{ + printf "extracting gigabit ethernet firmware" + ./${ifdtool} -x ${vendor_rom} + mv flashregion*gbe.bin ${_gbe_destination} \ + || fail 'could not extract gbe' +} + +fail() +{ + print_help + + printf "\n%s: ERROR: %s\n" ${sname} $@ + exit 1 +} + +print_help() +{ + printf "Usage: ./blobutil extract {boardname} {path/to/vendor_rom}\n" + printf "Example: ./blobutil extract x230 12mb_flash.bin\n" + printf "\nYou need to specify exactly 2 arguments\n" +} + +main $@ diff --git a/resources/scripts/update/blobs/inject b/resources/scripts/update/blobs/inject new file mode 100755 index 00000000..51f67255 --- /dev/null +++ b/resources/scripts/update/blobs/inject @@ -0,0 +1,398 @@ +#!/usr/bin/env bash + +# SPDX-FileCopyrightText: 2022 Caleb La Grange +# SPDX-FileCopyrightText: 2023 Leah Rowe +# SPDX-License-Identifier: GPL-3.0-only + +sname="" +archive="" +_filetype="" +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() +{ + sname="${0}" + + if [ $# -lt 1 ]; then + fail "No options specified." + elif [ "${1}" = "listboards" ]; then + listboards + exit 0 + fi + + archive="${1}" + + while getopts r:b:m: option + do + case "${option}" + in + r)rom=${OPTARG};; + b)board=${OPTARG};; + m) + modifygbe=true + new_mac=${OPTARG} + ;; + esac + 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. +# 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=$(cut -d '_' -f2-3 <<<${filename}) + ;; + seabios_withgrub_*) + board=$(cut -d '_' -f3-4 <<<${filename}) + ;; + *.tar.xz) + _stripped_prefix=${filename#*_} + board="${_stripped_prefix%.tar.xz}" + ;; + *) + return 1 + esac + + if [ -d "${boarddir}/" ]; then + printf '%s\n' "${board}" + return 0 + else + return 1 + fi +} + +build_dependencies() +{ + if [ ! -d ${cbdir} ]; then + printf "downloading coreboot\n" + ./download coreboot default + fi + + if [ ! -f "${ifdtool}" ]; then + printf "building ifdtool from coreboot\n" + ./build module cbutils default \ + || fail 'could not build ifdtool' + fi + + if [ ! -f "${cbfstool}" ]; then + printf "building cbfstool from coreboot\n" + ./build module cbutils default \ + || fail 'could not build cbfstool' + fi + + ./blobutil download ${board} || \ + fail "Could not download blobs for ${board}" +} + +inject_blobs() +{ + if [ "${release}" = "true" ]; then + echo 'patching release file' + patch_release_roms + else + patch_rom ${rom} + fi +} + +patch_release_roms() +{ + _tmpdir=$(mktemp -d "/tmp/${board}_tmpXXXX") + tar xf "${releasearchive}" -C "${_tmpdir}" || \ + fail 'could not extract release archive' + + for x in ${_tmpdir}/bin/*/*.rom ; do + echo "patching rom $x" + patch_rom ${x} || fail "could not patch ${x}" + done + + ( + cd ${_tmpdir}/bin/* + sha1sum --status -c blobhashes || \ + fail 'ROMs did not match expected hashes' + ) + + if [ "${modifygbe}" = "true" ]; then + for x in ${_tmpdir}/bin/*/*.rom ; do + modify_gbe ${x} + done + fi + + if ! [ -d bin/release ]; then + mkdir -p bin/release + fi + + mv ${_tmpdir}/bin/* bin/release/ && \ + printf '%s\n' 'Success! Your ROMs are in bin/release' + + rm -r "${_tmpdir}" +} + +patch_rom() +{ + rom="${1}" + + set -- "${boarddir}/config/"* + . ${1} 2>/dev/null + . "${boarddir}/board.cfg" + + if [ "$CONFIG_HAVE_MRC" = "y" ]; then + inject_blob_intel_mrc "${rom}" + 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 +} + +inject_blob_intel_mrc() +{ + rom="${1}" + + printf 'adding mrc\n' + + # mrc.bin must be inserted at a specific offset. the only + # libreboot platform that needs it, at present, is haswell + + # in cbfstool, -b values above 0x80000000 are interpreted as + # top-aligned x86 memory locations. this is converted into an + # absolute offset within the flash, and inserted accordingly + # at that offset into the ROM image file + + # coreboot's own build system hardcodes the mrc.bin offset + # because there is only one correct location in memory, but + # it would be useful for lbmk if it could be easily scanned + # from Kconfig, with the option to change it where in practise + # it is not changed + + # the hardcoded offset below is based upon reading of the coreboot + # source code, and it is *always* correct for haswell platform. + # TODO: this logic should be tweaked to handle more platforms + + ${cbfstool} ${rom} add -f mrc/haswell/mrc.bin -n mrc.bin -t mrc \ + -b 0xfffa0000 || exit 1 +} + +inject_blob_intel_me() +{ + printf 'adding intel management engine\n' + + rom="${1}" + + if [ -z ${CONFIG_ME_BIN_PATH} ]; then + fail "CONFIG_ME_BIN_PATH not set" + fi + + _me_location=${CONFIG_ME_BIN_PATH#../../} + + if [ ! -f "${_me_location}" ]; then + fail "CONFIG_ME_BIN_PATH points to missing file" + fi + + ${ifdtool} -i me:${_me_location} ${rom} -O ${rom} || exit 1 +} + +inject_blob_hp_kbc1126_ec() +{ + 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 + + ${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 +} + +inject_blob_dell_e6400_vgarom_nvidia() +{ + rom="${1}" + + _vga_location="${CONFIG_VGA_BIOS_FILE#../../}" + _vga_dir="${_vga_location%/*}" + _vga_filename="${_vga_location##*/}" + + printf "adding pci option rom\n" + + if [ "${_vga_dir}" != "${pciromsdir}" ]; 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 + + ${cbfstool} ${rom} add -f "${_vga_location}" \ + -n "pci${CONFIG_VGA_BIOS_ID}.rom" \ + -t optionrom || exit 1 +} + +modify_gbe() +{ + printf "changing mac address in gbe to ${new_mac}\n" + + rom=${1} + + if [ -z ${CONFIG_GBE_BIN_PATH} ]; then + fail "CONFIG_GBE_BIN_PATH not set" + fi + + _gbe_location=${CONFIG_GBE_BIN_PATH#../../} + + if [ ! -f "${_gbe_location}" ]; then + fail "CONFIG_GBE_BIN_PATH points to missing file" + fi + + 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 "\n%s: ERROR: ${@}\n" ${sname} + 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 $@ -- cgit v1.2.1