diff options
Diffstat (limited to 'resources/scripts/update/blobs/download')
| -rwxr-xr-x | resources/scripts/update/blobs/download | 455 | 
1 files changed, 455 insertions, 0 deletions
| 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 <thonkpeasant@protonmail.com> +# SPDX-FileCopyrightText: 2023 Leah Rowe <info@minifree.org> +# 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 $@ | 
