#!/usr/bin/env sh # SPDX-FileCopyrightText: 2022 Caleb La Grange # SPDX-FileCopyrightText: 2022 Ferass El Hafidi # SPDX-FileCopyrightText: 2023 Leah Rowe # SPDX-License-Identifier: GPL-3.0-only ec_url="" ec_url_bkup="" ec_hash="" e6400_vga_dl_hash="" e6400_vga_dl_url="" e6400_vga_dl_url_bkup="" e6400_vga_offset="" e6400_vga_romname="" 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)/coreboot/default/util/kbc1126/kbc1126_ec_dump" board="${1}" # A shorthand for each board, to avoid duplicating configs per flash size board_short=${board%%_*mb} set -- "resources/coreboot/${board}/config/*" . ${1} 2>/dev/null . "resources/coreboot/${board}/board.cfg" if [ "${CONFIG_HAVE_MRC}" = "y" ]; then printf 'haswell board detected, downloading mrc\n' needs="${needs} MRC" fi if [ "${CONFIG_HAVE_IFD_BIN}" = "y" ]; then printf 'board needs intel firmware descriptor\n' needs="${needs} IFD" fi if [ "${CONFIG_HAVE_ME_BIN}" = "y" ]; then printf 'board needs intel management engine\n' needs="${needs} ME" fi if [ "${CONFIG_HAVE_GBE_BIN}" = "y" ]; then printf 'board needs gigabit ethernet firmware\n' needs="${needs} GBE" fi if [ "${CONFIG_KBC1126_FIRMWARE}" = "y" ]; then printf "HP board with KBC1126 EC detected, downloading ec\n" needs="${needs} EC" fi if [ "${CONFIG_BOARD_DELL_E6400}" = "y" ] \ && [ "${CONFIG_VGA_BIOS_FILE}" != "" ]; then printf "Dell E6400 with Nvidia GPU detected, downloading VGA ROM\n" needs="${needs} E6400VGA" fi # Quickly exit without wasting more time if there are no blobs needed (GM45) if [ -z ${needs+x} ]; then printf 'No binary blobs needed for this board\n' exit 0 fi 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 << EOF $(eval "awk ' /\{.*${board_short}.*}{/ {flag=1;next} /\}/{flag=0} flag { print }' resources/blobs/sources") EOF Main() { Build_deps Download_needed } Fail(){ printf "\nERROR: $@\n" exit 1 } Build_deps(){ if [ ! -d me_cleaner ]; then printf "downloading me_cleaner\n" ./download me_cleaner || Fail 'could not download me_cleaner' fi if [ ! -d coreboot/default ]; 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 coreboot/default/util/kbc1126/kbc1126_ec_dump ]; then printf "Building kbc1126_ec_dump from coreboot\n" make -BC coreboot/default/util/kbc1126 || Fail \ "could not build kbc1126_ec_dump" fi if [ ! -f "coreboot/default/util/ifdtool/ifdtool" ]; then printf "building ifdtool from coreboot\n" make -C coreboot/default/util/ifdtool || Fail 'could not build ifdtool' fi } Download_needed(){ for need in ${needs}; do case ${need} in *ME*) Download_me || _failed="${_failed} me" ;; *MRC*) ./download mrc || _failed="${_failed} mrc" ;; *EC*) Download_ec || _failed="${_failed} ec" ;; *E6400VGA*) Download_e6400vga || _failed="${_failed} e6400vga" ;; esac done if [ ! -z ${_failed+x} ]; then Fail "failed to obtain ${_failed}\nYou may try manually extracting blobs with './blobutil extract'" fi } Download_me() { printf "Downloading neutered ME for board: %s\n" ${board} Fetch_update me || return 1 Extract_me || return 1 return 0 } Extract_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 management engine\n' innoextract ${dl_path} -d ${blobdir} \ || 7z x ${dl_path} -o${appdir} \ || Fail 'could not extract me executable with innoextract' Bruteforce_extract_me "$(pwd)/${_me_destination}" "$(pwd)/${appdir}" \ || return 1 printf "Truncated and cleaned me output to ${_me_destination}\n" return 0 } # cursed, carcinogenic code. TODO rewrite it better Bruteforce_extract_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 _7ztest="${_7ztest}a" 7z x "${i}" -o${_7ztest} || continue Bruteforce_extract_me "${_me_destination}" "${cdir}/${_7ztest}" cdir="${1}" cd "${cdir}" elif [ -d "$i" ]; then Bruteforce_extract_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 board: %s\n" ${board} return 1 else return 0 fi } Download_ec() { printf "Downloading KBC1126 EC firmware for HP laptop\n" Fetch_update ec || return 1 Extract_ec || return 1 return 0 } 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 printf "Not found: %s/%s/ec.bin.fw%s\n" \ ${appdir} ${dl_path##*/} ${i} printf "Could not extract EC firmware for board: %s\n" \ ${board} return 1 fi 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 return 0 } 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 fi if [ "${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}" return 0 } 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: ${board}" return 0 } Vendor_checksum() { sha1=$1 if [ ! -f "${dl_path}" ]; then printf "Vendor update not found on disk for board: %s\n" ${board} return 1 fi if [ "$(sha1sum ${dl_path} | awk '{print $1}')" != "${sha1}" ]; then printf "Bad checksum on vendor update for board: %s\n" ${board} # rm ${dl_path} return 1 fi return 0 } Main