diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/get.sh | 353 | ||||
-rw-r--r-- | include/git.sh | 106 | ||||
-rw-r--r-- | include/init.sh | 509 | ||||
-rw-r--r-- | include/inject.sh | 205 | ||||
-rw-r--r-- | include/lib.sh | 300 | ||||
-rw-r--r-- | include/mrc.sh | 71 | ||||
-rw-r--r-- | include/release.sh | 131 | ||||
-rw-r--r-- | include/rom.sh | 512 | ||||
-rw-r--r-- | include/tree.sh | 740 | ||||
-rw-r--r-- | include/vendor.sh | 718 |
10 files changed, 2703 insertions, 942 deletions
diff --git a/include/get.sh b/include/get.sh new file mode 100644 index 00000000..4731c694 --- /dev/null +++ b/include/get.sh @@ -0,0 +1,353 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +# Copyright (c) 2020-2021,2023-2025 Leah Rowe <leah@libreboot.org> +# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> + +depend="" +loc="" +url="" +bkup_url="" +subgit="" +subgit_bkup="" +subcurl="" +subcurl_bkup="" +subhash="" + +tmpgit="$xbtmp/gitclone" +tmpgitcache="$xbtmp/tmpgit" + +fetch_targets() +{ + if [ ! -d "src/$project/$tree" ]; then + git_prep "$url" "$bkup_url" \ + "$xbmkpwd/$configdir/$tree/patches" \ + "src/$project/$tree" "submod" + fi +} + +fetch_project() +{ + xgcctree="" + + . "config/git/$project/pkg.cfg" || \ + err "Can't read config 'config/git/$project/pkg.cfg'" \ + "fetch_project" "@" + + if [ -z "$url" ] || [ -z "$bkup_url" ]; then + err "url/bkup_url not both set 'config/git/$project/pkg.cfg'" \ + "fetch_project" "$@" + fi + + if [ -n "$xgcctree" ]; then + x_ ./mk -f coreboot "$xgcctree" + fi + if [ -n "$depend" ]; then + for d in $depend ; do + x_ ./mk -f $d + done + fi + + clone_project +} + +clone_project() +{ + loc="$XBMK_CACHE/clone/$project" + if singletree "$project"; then + loc="src/$project" + fi + + if e "$loc" d missing; then + remkdir "${tmpgit%/*}" + git_prep "$url" "$bkup_url" \ + "$xbmkpwd/config/$project/patches" "$loc" + fi +} + +git_prep() +{ + printf "Creating code directory, src/%s/%s\n" "$project" "$tree" + + _patchdir="$3" + _loc="$4" # $1 and $2 are gitrepo and gitrepo_backup + + if [ -z "$rev" ]; then + err "$project/$tree: rev not set" "git_prep" "$@" + fi + + xbget git "$1" "$2" "$tmpgit" "$rev" "$_patchdir" + if singletree "$project" || [ $# -gt 4 ]; then + dx_ fetch_submodule "$mdir/module.list" + fi + + if [ "$_loc" != "${_loc%/*}" ]; then + x_ xbmkdir "${_loc%/*}" + fi + x_ mv "$tmpgit" "$_loc" +} + +fetch_submodule() +{ + mcfgdir="$mdir/${1##*/}" + + subhash="" + subgit="" + subgit_bkup="" + subcurl="" + subcurl_bkup="" + st="" + + if e "$mcfgdir/module.cfg" f missing; then + return 0 + fi + . "$mcfgdir/module.cfg" || \ + err "Can't read '$mcfgdir/module.cfg'" "fetch_submodules" "$@" + + if [ -n "$subgit" ] || [ -n "$subgit_bkup" ]; then + st="$st git" + fi + if [ -n "$subcurl" ] || [ -n "$subcurl_bkup" ]; then + st="$st curl" + fi + + st="${st# }" + if [ "$st" = "git curl" ]; then + err "$mdir: git+curl defined" "fetch_submodule" "$@" + fi + + if [ -z "$st" ]; then + return 0 + fi + + if [ "$st" = "curl" ]; then + if [ -z "$subcurl" ] || [ -z "$subcurl_bkup" ]; then + err "subcurl/subcurl_bkup not both set" \ + "fetch_submodule" "$@" + fi + elif [ -z "$subgit" ] || [ -z "$subgit_bkup" ]; then + err "subgit/subgit_bkup not both set" "fetch_submodule" "$@" + elif [ -z "$subhash" ]; then + err "subhash not set" "fetch_submodule" "$@" + fi + + if [ "$st" = "git" ]; then + x_ rm -Rf "$tmpgit/$1" + xbget "$st" "$subgit" "$subgit_bkup" "$tmpgit/$1" \ + "$subhash" "$mdir/${1##*/}/patches" + else + xbget "$st" "$subcurl" "$subcurl_bkup" "$tmpgit/$1" \ + "$subhash" "$mdir/${1##*/}/patches" + fi +} + +# TODO: in the following functions, argument numbers are used +# which is hard to understand. the code should be modified +# so that variable names are used instead, for easy reading + +xbget() +{ + if [ "$1" != "curl" ] && [ "$1" != "copy" ] && [ "$1" != "git" ]; then + err "Bad dlop (arg 1)" "xbget" "$@" + fi + + for url in "$2" "$3" + do + if [ -z "$url" ]; then + err "empty URL given in" "xbget" "$@" + elif ! try_fetch "$url" "$@"; then + continue + fi + + case "$1" in + git) + if [ ! -d "$4" ]; then + continue + fi + ;; + *) + if [ ! -f "$4" ]; then + continue + fi + ;; + esac + return 0 # successful download/copy + done + + err "failed to download file/repository" "xbget" "$@"; : +} + +try_fetch() +{ + if [ "$2" = "git" ]; then + if ! try_fetch_git "$@"; then + return 1 + fi + else + if ! try_fetch_file "$@"; then + return 1 + fi + fi +} + +try_fetch_git() +{ + # always the main repo as basis for naming, + # in case the backup has another name + + cached="clone/${3##*/}" + cached="${cached%.git}" + cached="$XBMK_CACHE/$cached" + + x_ xbmkdir "${5%/*}" "${cached%/*}" + + if ! try_$2 "$cached" "$@"; then + return 1 + elif [ ! -d "$cached" ]; then + return 1 + fi + + if [ ! -d "$5" ]; then + tmpclone "$cached" "$5" "$6" "$7" || \ + err "Can't clone final repo" "try_fetch" "$@"; : + fi + + if [ ! -d "$5" ]; then + return 1 + fi +} + +try_fetch_file() +{ + cached="file/$6" + cached="$XBMK_CACHE/$cached" + + x_ xbmkdir "${5%/*}" "${cached%/*}" + + if bad_checksum "$6" "$cached" 2>/dev/null; then + x_ rm -f "$cached" + fi + + if [ ! -f "$cached" ]; then + if ! try_$2 "$cached" "$@"; then + return 1 + fi + fi + + if [ -f "$5" ]; then + if bad_checksum "$6" "$5" 2>/dev/null; then + x_ cp "$cached" "$5" + fi + fi + + if [ ! -f "$cached" ]; then + return 1 + elif bad_checksum "$6" "$cached"; then + x_ rm -f "$cached" + + return 1 + fi + + if [ "$cached" != "$5" ]; then + x_ cp "$cached" "$5" + fi + + if bad_checksum "$6" "$5"; then + x_ rm -f "$5" + + return 1 + elif [ ! -f "$5" ]; then + return 1 + fi +} + +try_curl() +{ + _ua="Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0" + + ( x_ curl --location --retry 3 -A "$_ua" "$2" -o "$1" ) \ + || ( x_ wget --tries 3 -U "$_ua" "$2" -O "$1" ) \ + || return 1; : +} + +try_copy() +{ + ( x_ cp "$2" "$1" ) || return 1; : +} + +try_git() +{ + gitdest="`findpath "$1" || err "Can't get findpath for '$1'"`" || \ + err "failed findpath for '$1'" try_get "$@" + + x_ rm -Rf "$tmpgitcache" + + if [ ! -d "$gitdest" ]; then + ( x_ git clone "$2" "$tmpgitcache" ) || return 1 + + x_ xbmkdir "${gitdest%/*}" + x_ mv "$tmpgitcache" "$gitdest" + fi + + if git -C "$gitdest" show "$7" 1>/dev/null 2>/dev/null && \ + [ "$forcepull" != "y" ]; then + # don't try to pull the latest changes if the given target + # revision already exists locally. this saves a lot of time + # during release builds, and reduces the chance that we will + # interact with grub.git or gnulib.git overall during runtime + + return 0 + fi + + ( x_ git -C "$gitdest" remote remove main ) || : + ( x_ git -C "$gitdest" remote remove backup ) || : + + x_ git -C "$gitdest" remote add main "$4" + x_ git -C "$gitdest" remote add backup "$5" + + ( x_ git -C "$gitdest" pull --all ) || :; : +} + +bad_checksum() +{ + if e "$2" f missing; then + return 0 + fi + + build_sbase + csum="$(x_ "$sha512sum" "$2" | awk '{print $1}')" || \ + err "!sha512 '$2' $1" bad_checksum "$@" + + if [ "$csum" = "$1" ]; then + return 1 + else + x_ rm -f "$2" + printf "BAD SHA512 %s, '%s'; need %s\n" "$csum" "$2" "$1" 1>&2 + fi +} + +tmpclone() +{ + ( x_ git clone "$1" "$2" ) || return 1 + ( x_ git -C "$2" reset --hard "$3" ) || return 1 + + if [ ! -d "$4" ]; then + return 0 + fi + + tmpclone_patchlist="`mktemp || err "Can't create tmp patch list"`" || \ + err "Can't create tmp patch list" "tmpclone" "$@" + + x_ find "$4" -type f | sort > "$tmpclone_patchlist" || \ + err "Can't write patch names to '$tmpclone_patchlist'" \ + "tmpclone" "$@" + + while read -r tmpclone_patch; do + + ( x_ git -C "$2" am "$tmpclone_patch" ) || \ + err "Can't apply '$tmpclone_patch'" "tmpclone" "$@"; : + + done < "$tmpclone_patchlist" || \ + err "Can't read '$tmpclone_patchlist'" "tmpclone" "$@" + + x_ rm -f "$tmpclone_patchlist" +} diff --git a/include/git.sh b/include/git.sh deleted file mode 100644 index bbc5140e..00000000 --- a/include/git.sh +++ /dev/null @@ -1,106 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-or-later -# Copyright (c) 2020-2021,2023-2025 Leah Rowe <leah@libreboot.org> -# Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> - -eval "`setvars "" loc url bkup_url subfile subhash subrepo subrepo_bkup \ - depend subfile_bkup repofail`" - -tmpgit="$xbmklocal/gitclone" - -fetch_targets() -{ - e "src/$project/$tree" d && return 0 - - printf "Creating %s tree %s\n" "$project" "$tree" - git_prep "$loc" "$loc" "$xbmkpwd/$configdir/$tree/patches" \ - "src/$project/$tree" with_submodules - nuke "$project/$tree" "$project/$tree" -} - -fetch_project() -{ - eval "`setvars "" xtree`" - eval "`setcfg "config/git/$project/pkg.cfg"`" - - chkvars url - - [ -n "$xtree" ] && x_ ./mk -f coreboot "$xtree" - [ -z "$depend" ] || for d in $depend ; do - printf "'%s' needs '%s'; grabbing '%s'\n" "$project" "$d" "$d" - x_ ./mk -f $d - done - clone_project - - for x in config/git/*; do - [ -d "$x" ] && nuke "${x##*/}" "src/${x##*/}" 2>/dev/null; : - done; : -} - -clone_project() -{ - loc="$XBMK_CACHE/repo/$project" && singletree "$project" && \ - loc="src/$project" - printf "Downloading project '%s' to '%s'\n" "$project" "$loc" - - e "$loc" d missing && remkdir "${tmpgit%/*}" && git_prep \ - "$url" "$bkup_url" "$xbmkpwd/config/$project/patches" "$loc"; : -} - -git_prep() -{ - _patchdir="$3" - _loc="$4" # $1 and $2 are gitrepo and gitrepo_backup - - chkvars rev - tmpclone "$1" "$2" "$tmpgit" "$rev" "$_patchdir" - if singletree "$project" || [ $# -gt 4 ]; then - dx_ fetch_submodule "$mdir/module.list" - fi - - [ "$_loc" != "$XBMK_CACHE/repo/$project" ] && \ - [ "$XBMK_RELEASE" = "y" ] && rmgit "$tmpgit" - - [ "$_loc" = "${_loc%/*}" ] || x_ mkdir -p "${_loc%/*}" - x_ mv "$tmpgit" "$_loc" -} - -fetch_submodule() -{ - mcfgdir="$mdir/${1##*/}"; eval \ - "`setvars "" subhash subrepo subrepo_bkup subfile subfile_bkup st`" - [ ! -f "$mcfgdir/module.cfg" ] || . "$mcfgdir/module.cfg" || \ - err "! . $mcfgdir/module.cfg" - - for xt in repo file; do - _seval="if [ -n \"\$sub$xt\" ] || [ -n \"\$sub${xt}_bkup\" ]" - eval "$_seval; then st=\"\$st \$xt\"; fi" - done - st="${st# }" && [ "$st" = "repo file" ] && err "$mdir: repo+file" - - [ -z "$st" ] && return 0 # subrepo/subfile not defined - chkvars "sub${st}" "sub${st}_bkup" "subhash" - - [ "$st" = "file" ] && xbmkget "$subfile" "$subfile_bkup" \ - "$tmpgit/$1" "$subhash" && return 0 - x_ rm -Rf "$tmpgit/$1" - tmpclone "$subrepo" "$subrepo_bkup" "$tmpgit/$1" "$subhash" \ - "$mdir/${1##*/}/patches" -} - -tmpclone() -{ - [ -d "$3" ] && return 0 - printf "Creating git clone '%s' from '%s', '%s'\n" "$3" "$1" "$2" - git clone "$1" "$3" || x_ rm -Rf "$3" - [ -d "$3" ] || x_ git clone "$2" "$3" - x_ git -C "$3" reset --hard "$4" - fx_ "eval x_ git -C \"$3\" am" find "$5" -type f -} - -nuke() -{ - e "config/${1%/}/nuke.list" f missing || while read -r nukefile; do - rmf="src/${2%/}/$nukefile" && [ -L "$rmf" ] && continue - e "$rmf" e missing || x_ rm -Rf "$rmf" - done < "config/${1%/}/nuke.list"; : -} diff --git a/include/init.sh b/include/init.sh index 2dd9e88f..96247908 100644 --- a/include/init.sh +++ b/include/init.sh @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-3.0-only + # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2020-2025 Leah Rowe <leah@libreboot.org> @@ -10,60 +11,351 @@ export LC_ALL=C projectname="libreboot" projectsite="https://libreboot.org/" -[ -z "${PATH+x}" ] && \ - export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" -xbmkpath="$PATH" - -eval "`setvars "" _nogit board reinstall versiondate aur_notice configdir \ - datadir version xbmkpwd relname xbmkpwd xbmktmp python pyver xbmklocal \ - xbmklock cvxbmk cvchk`" +if [ -z "${PATH+x}" ]; then + export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" +fi + +board="" +reinstall="" +version="" +versiondate="" +aur_notice="" +configdir="" +xbmkpath="" +datadir="" +xbmkpwd="" +relname="" +xbmkpwd="" +xbtmp="" +python="" +pyver="" +xbmklock="" +checkvarsxbmk="" +checkvarschk="" +is_child="" +basetmp="" + +sha512sum="util/sbase/sha512sum" xbmk_init() { - xbmkpwd="`pwd`" || err "Cannot generate PWD" - xbmklocal="$xbmkpwd/tmp" + xbmkpwd="`pwd || err "Cannot generate PWD"`" || err "!" xbmk_init "$@" xbmklock="$xbmkpwd/lock" + basetmp="$xbmkpwd/xbmkwd" + sha512sum="$xbmkpwd/util/sbase/sha512sum" - export PWD="$xbmkpwd" + if [ $# -gt 0 ] && [ "$1" = "dependencies" ]; then + x_ xbmkpkg "$@" - [ $# -gt 0 ] && [ "$1" = "dependencies" ] && x_ xbmkpkg "$@" && exit 0 + exit 0 + fi + + id -u 1>/dev/null 2>/dev/null || \ + err "suid check failed" "xbmk_init" "$@" - id -u 1>/dev/null 2>/dev/null || err "suid check failed (id -u)" - [ "$(id -u)" != "0" ] || err "this command as root is not permitted" + if [ "$(id -u)" = "0" ]; then + err "this command as root is not permitted" "xbmk_init" "$@" + fi - for init_cmd in set_pyver set_version set_env git_init create_tmpdir \ - lock create_pathdirs child_exec; do - xbmk_$init_cmd "$@" || break + export PWD="$xbmkpwd" + x_ xbmkdir "$basetmp" + + if [ ! -e "cache" ]; then + x_ xbmkdir "cache" + fi + + for init_cmd in get_version set_env set_threads git_init child_exec; do + if ! xbmk_$init_cmd "$@"; then + break + fi done } xbmkpkg() { - [ $# -lt 2 ] && err "fewer than two arguments" - [ $# -gt 2 ] && reinstall="$3" + xchk xbmkpkg "$@" - eval "`setcfg "config/dependencies/$2"`" + if [ $# -gt 2 ]; then + reinstall="$3" + fi + + . "config/dependencies/$2" || \ + err "Can't read 'config/dependencies/$2'" "xbmkpkg" "$@" + + if [ -z "$pkg_add" ] || [ -z "$pkglist" ]; then + err "pkg_add/pkglist not both set" "xbmkpkg" "$@" + fi - chkvars pkg_add pkglist x_ $pkg_add $pkglist - [ -n "$aur_notice" ] && \ - printf "You need AUR packages: %s\n" "$aur_notice" 1>&2; : + if [ -n "$aur_notice" ]; then + printf "You need AUR packages: %s\n" "$aur_notice" 1>&2 + fi +} + +xbmk_get_version() +{ + if [ -f ".version" ]; then + read -r version < ".version" || \ + err "can't read version file" "xbmk_get_version" "$@" + fi + if [ -f ".versiondate" ]; then + read -r versiondate < ".versiondate" || \ + err "can't read versiondate" xbmk_get_version "$@" + fi + + if [ -f ".version" ] && [ -z "$version" ]; then + err "version not set" "xbmk_get_version" "$@" + fi + if [ -f ".versiondate" ] && [ -z "$versiondate" ]; then + err "versiondate not set" "xbmk_get_version" "$@" + fi + + if [ ! -e ".git" ] && [ ! -f ".version" ]; then + version="unknown" + fi + if [ ! -e ".git" ] && [ ! -f ".versiondate" ]; then + versiondate="1716415872" + fi + + xbmk_sanitize_version + + if [ -n "$version" ]; then + relname="$projectname-$version" + fi +} + +# a parent instance will cause this function to return 0. +# a child instance will return 1, skipping further initialisation +# after this function is called. +xbmk_set_env() +{ + is_child="n" + + xbmkpath="$PATH" + + # unify all temporary files/directories in a single TMPDIR + if [ -n "${TMPDIR+x}" ] && [ "${TMPDIR%_*}" != "$basetmp/xbmk" ]; then + unset TMPDIR + fi + if [ -n "${TMPDIR+x}" ]; then + export TMPDIR="$TMPDIR" + xbtmp="$TMPDIR" + fi + if [ -n "${TMPDIR+x}" ]; then + is_child="y" + fi + + if [ "$is_child" = "y" ] + then + # child instance of xbmk, so we stop init after this point + # and execute the given user command upon return: + + xbmk_child_set_env + + return 1 + else + # parent instance of xbmk, so we continue initialising. + # a parent instance of xbmk never processes its own + # command directly; instead, it calls a child instance + # of xbmk, and exits with the corresponding return status. + + xbmk_parent_set_env + + return 0 + fi +} + +xbmk_child_set_env() +{ + xbmk_child_set_tmp + + if [ -z "${XBMK_CACHE+x}" ]; then + err "XBMK_CACHE unset on child" "xbmk_set_env" "$@" + fi + if [ -z "${XBMK_THREADS+x}" ]; then + xbmk_set_threads; : + fi +} + +xbmk_child_set_tmp() +{ + badtmp="" + xbtmpchk="" + locktmp="" + + xbtmpchk="`findpath "$TMPDIR" || err "!findpath $TMPDIR"`" || \ + err "!findpath '$TMPDIR'" "xbmk_child_set_tmp" "$@" + + read -r locktmp < "$xbmklock" || \ + err "can't read '$xbmklock'" "xbmk_child_set_tmp" "$@" + + if [ "$locktmp" != "$xbtmpchk" ]; then + badtmp="TMPDIR '$xbtmpchk' changed; was '$locktmp'" + + printf "bad TMPDIR init, '%s': %s\n" "$TMPDIR" "$badtmp" 1>&2 + err "'$xbmklock' present with bad tmpdir. is a build running?" + fi + + xbtmp="$xbtmpchk" + export TMPDIR="$xbtmpchk" +} + +xbmk_parent_set_env() +{ + xbmk_parent_check_tmp + + printf "%s\n" "$xbtmp" > "$xbmklock" || \ + err "cannot create '$xbmklock'" xbmk_set_env "$@"; : + + # not really critical for security, but it's a barrier + # against the user to make them think twice before deleting it + # in case an actual instance of xbmk is already running: + + x_ chmod -w "$xbmklock" + + xbmk_parent_set_export + xbmk_set_version + + remkdir "$xbtmp" "$xbtmp/gnupath" "$xbtmp/xbmkpath" + + xbmk_set_pyver +} + +xbmk_parent_check_tmp() +{ + export TMPDIR="$basetmp" + + xbmklist="`mktemp || err "can't make tmplist"`" || \ + err "can't make tmplist" xbmk_parent_check_tmp "$@" + + x_ rm -f "$xbmklist" + x_ touch "$xbmklist" + + for xtmpdir in "$basetmp"/xbmk_*; do + if [ -e "$xtmpdir" ]; then + printf "%s\n" "$xtmpdir" >> "$xbmklist" || \ + err "can't write '$xtmpdir' to '$xbmklist'" \ + "xbmk_parent_check_tmp" "$@"; : + fi + done + + # set up a unified temporary directory, for common deletion later: + export TMPDIR="`x_ mktemp -d -t xbmk_XXXXXXXX`" || \ + err "can't export TMPDIR" "xbmk_parent_check_tmp" "$@" + xbtmp="$TMPDIR" + + while read -r xtmpdir; do + if [ "$xtmpdir" = "$xbtmp" ]; then + err "pre-existing '$xbtmp'" "xbmk_parent_check_tmp" "$@" + fi + done < "$xbmklist" || \ + err "Can't read xbmklist: '$xbmklist'" "xbmk_parent_check_tmp" "$@" + + x_ rm -f "$xbmklist" +} + +xbmk_parent_set_export() +{ + export XBMK_CACHE="$xbmkpwd/cache" + + if [ -e "$XBMK_CACHE" ] && [ ! -d "$XBMK_CACHE" ]; then + err "cachedir '$XBMK_CACHE' is a file" \ + "xbmk_parent_set_export" "$@" + fi + + export PATH="$xbtmp/xbmkpath:$xbtmp/gnupath:$PATH" + xbmkpath="$PATH" + + # if "y": a coreboot target won't be built if target.cfg says release=n + # (this is used to exclude certain build targets from releases) + + if [ -z "${XBMK_RELEASE+x}" ]; then + export XBMK_RELEASE="n" + fi + if [ "$XBMK_RELEASE" = "Y" ]; then + export XBMK_RELEASE="y" + fi + if [ "$XBMK_RELEASE" != "y" ]; then + export XBMK_RELEASE="n" + fi +} + +xbmk_set_threads() +{ + if [ -z "${XBMK_THREADS+x}" ]; then + export XBMK_THREADS=1 + fi + if ! expr "X$XBMK_THREADS" : "X-\{0,1\}[0123456789][0123456789]*$" \ + 1>/dev/null 2>/dev/null; then + export XBMK_THREADS=1 + fi +} + +xbmk_set_version() +{ + version_="$version" + if [ -e ".git" ]; then + version="$(git describe --tags HEAD 2>&1)" || \ + version="git-$(git rev-parse HEAD 2>&1)" || \ + version="$version_" + fi + + versiondate_="$versiondate" + if [ -e ".git" ]; then + versiondate="$(git show --no-patch --no-notes \ + --pretty='%ct' HEAD)" || versiondate="$versiondate_" + fi + + if [ -z "$version" ] || [ -z "$versiondate" ]; then + err "version and/or versiondate unset" "xbmk_set_version" "$@" + fi + + update_xbmkver "." + + relname="$projectname-$version" + export LOCALVERSION="-$projectname-${version%%-*}" } xbmk_set_pyver() { pyv="import sys; print(sys.version_info[:])" python="python3" - pybin python3 1>/dev/null || python="python" - pyver="2" && [ "$python" = "python3" ] && pyver="3" - pybin "$python" 1>/dev/null || pyver="" - [ -z "$pyver" ] || "`pybin "$python"`" -c "$pyv" 1>/dev/null \ - 2>/dev/null || err "Cannot detect host Python version." - [ -n "$pyver" ] && \ - pyver="$("$(pybin "$python")" -c "$pyv" | awk '{print $1}')" && \ - pyver="${pyver#(}" && pyver="${pyver%,}" - [ "${pyver%%.*}" = "3" ] || err "Bad python version (must by 3.x)"; : + pyver="2" + + if ! pybin python3 1>/dev/null; then + python="python" + fi + if [ "$python" = "python3" ]; then + pyver="3" + fi + if ! pybin "$python" 1>/dev/null; then + pyver="" + fi + if [ -n "$pyver" ]; then + "`x_ pybin "$python"`" -c "$pyv" 1>/dev/null \ + 2>/dev/null || \ + err "Can't detect Python version." "xbmk_set_pyver" "$@" + fi + if [ -n "$pyver" ]; then + pyver="$("$(pybin "$python")" -c "$pyv" | awk '{print $1}')" + pyver="${pyver#(}" + pyver="${pyver%,}" + fi + if [ "${pyver%%.*}" != "3" ]; then + err "Bad python version (must by 3.x)" "xbmk_set_pyver" "$@" + fi + + # set up python in PATH (environmental variable): + + ( + x_ cd "$xbtmp/xbmkpath" + + x_ ln -s "`x_ pybin "$python"`" python || \ + err "can't make symlink" "xbmk_set_pyver" "$@" + + ) || \ + err "Can't link Python in $xbtmp/xbmkpath" "xbmk_set_pyver" "$@"; : } # Use direct path, to prevent a hang if Python is using a virtual environment, @@ -74,90 +366,74 @@ pybin() py="import sys; quit(1) if sys.prefix == sys.base_prefix else quit(0)" venv=1 - command -v "$1" 1>/dev/null 2>/dev/null || venv=0 - [ $venv -lt 1 ] || "$1" -c "$py" 1>/dev/null 2>/dev/null || venv=0 + if ! command -v "$1" 1>/dev/null 2>/dev/null; then + venv=0 + fi + if [ $venv -gt 0 ]; then + if ! "$1" -c "$py" 1>/dev/null 2>/dev/null; then + venv=0 + fi + fi # ideally, don't rely on PATH or hardcoded paths if python venv. - # use the *real*, direct executable linked to by the venv symlink + # use the *real*, direct executable linked to by the venv symlink: + if [ $venv -gt 0 ] && [ -L "`command -v "$1" 2>/dev/null`" ]; then pypath="$(findpath \ "$(command -v "$1" 2>/dev/null)" 2>/dev/null || :)" - [ -e "$pypath" ] && [ ! -d "$pypath" ] && \ - [ -x "$pypath" ] && printf "%s\n" "$pypath" && return 0; : - fi - # if python venv: fall back to common PATH directories for checking - [ $venv -gt 0 ] && for pypath in "/usr/local/bin" "/usr/bin"; do - [ -e "$pypath/$1" ] && [ ! -d "$pypath/$1" ] && \ - [ -x "$pypath/$1" ] && printf "%s/%s\n" "$pypath" "$1" && \ - return 0 - done && return 1 + if [ -e "$pypath" ] && [ ! -d "$pypath" ] && \ + [ -x "$pypath" ]; then - # Defer to normal command -v if not a venv - command -v "$1" 2>/dev/null || return 1 -} + printf "%s\n" "$pypath" -xbmk_set_version() -{ - [ ! -f ".version" ] || read -r version < ".version" || :; : - [ ! -f ".versiondate" ] || read -r versiondate < ".versiondate" || :; : - - [ -e ".git" ] || [ -f ".version" ] || printf "unknown\n" > ".version" \ - || err "Cannot generate unknown .version file" - [ -e ".git" ] || [ -f ".versiondate" ] || printf "1716415872\n" > \ - ".versiondate" || err "Can't generate unknown versiondate file"; : - - version_="$version" - [ ! -e ".git" ] || version="$(git describe --tags HEAD 2>&1)" || \ - version="git-$(git rev-parse HEAD 2>&1)" || version="$version_" - versiondate_="$versiondate" - [ ! -e ".git" ] || versiondate="$(git show --no-patch --no-notes \ - --pretty='%ct' HEAD)" || versiondate="$versiondate_" + return 0 + fi + fi - chkvars version versiondate - printf "%s\n" "$version" > ".version" || err "can't save version" - printf "%s\n" "$versiondate" > ".versiondate" || err "can't save date" + # if python venv: fall back to common PATH directories for checking: - relname="$projectname-$version" -} + [ $venv -gt 0 ] && for pypath in "/usr/local/bin" "/usr/bin"; do + if [ -e "$pypath/$1" ] && [ ! -d "$pypath/$1" ] && \ + [ -x "$pypath/$1" ]; then -xbmk_set_env() -{ - export LOCALVERSION="-$projectname-${version%%-*}" + printf "%s/%s\n" "$pypath" "$1" - # XBMK_CACHE is a directory, for caching downloads and git repon - [ -z "${XBMK_CACHE+x}" ] && export XBMK_CACHE="$xbmkpwd/cache" - [ -z "$XBMK_CACHE" ] && export XBMK_CACHE="$xbmkpwd/cache" - [ -L "$XBMK_CACHE" ] && [ "$XBMK_CACHE" = "$xbmkpwd/cache" ] && \ - err "cachedir '$xbmkpwd/cache' is a symlink" - [ -L "$XBMK_CACHE" ] && export XBMK_CACHE="$xbmkpwd/cache" - xbmkcache="`findpath "$XBMK_CACHE"`" || \ - err "Can't resolve cachedir: '$XBMK_CACHE'" - export XBMK_CACHE="$xbmkcache" - [ ! -e "$XBMK_CACHE" ] || \ - [ -d "$XBMK_CACHE" ] || err "cachedir '$XBMK_CACHE' is a file"; : - - # if "y": a coreboot target won't be built if target.cfg says release="n" - # (this is used to exclude certain build targets from releases) - [ -z "${XBMK_RELEASE+x}" ] && export XBMK_RELEASE="n" - [ "$XBMK_RELEASE" = "Y" ] && export XBMK_RELEASE="y" - [ "$XBMK_RELEASE" = "y" ] || export XBMK_RELEASE="n" + return 0 + fi + done && return 1 - [ -z "${XBMK_THREADS+x}" ] && export XBMK_THREADS=1 - expr "X$XBMK_THREADS" : "X-\{0,1\}[0123456789][0123456789]*$" \ - 1>/dev/null 2>/dev/null || export XBMK_THREADS=1; : + # Defer to normal command -v if not a venv + if ! command -v "$1" 2>/dev/null; then + return 1 + fi } xbmk_git_init() { for gitarg in "--global user.name" "--global user.email"; do - gitcmd="git config $gitarg"; $gitcmd 1>/dev/null 2>/dev/null \ - || err "Run this first: $gitcmd \"your ${gitcmd##*.}\"" + gitcmd="git config $gitarg" + if ! $gitcmd 1>/dev/null 2>/dev/null; then + err "Run this first: $gitcmd \"your ${gitcmd##*.}\"" \ + "xbmk_git_init" "$@" + fi done - [ -L ".git" ] && return 1 - [ -e ".git" ] && return 0 - eval "`setvars "$(date -Rud @$versiondate)" cdate _nogit`" + if [ -L ".git" ]; then + err "'$xbmkpwd/.git' is a symlink" "xbmk_git_init" "$@" + fi + if [ -e ".git" ]; then + return 0 + fi + + # GNU-specific extensions of date are used. + # TODO: that is a bug. fix it! + + x_ date --version | grep "GNU coreutils" 1>/dev/null 2>/dev/null || \ + err "Non-GNU date implementation" "xbmk_git_init" "$@" + + cdate="`x_ date -Rud @$versiondate || err "can't get date"`" || \ + err "can't get date" "xbmk_git_init" "$@" x_ git init 1>/dev/null 2>/dev/null x_ git add -A . 1>/dev/null 2>/dev/null @@ -167,50 +443,15 @@ xbmk_git_init() 2>/dev/null; : } -xbmk_create_tmpdir() -{ - x_ mkdir -p "$xbmklocal" - - # unify all temporary files/directories in a single TMPDIR - [ -z "${TMPDIR+x}" ] || [ "${TMPDIR%_*}" = "/tmp/xbmk" ] || \ - unset TMPDIR - [ -n "${TMPDIR+x}" ] && export TMPDIR="$TMPDIR" && xbmktmp="$TMPDIR" - [ -z "${TMPDIR+x}" ] || return 1 # child instance, so return - - # parent instance of xbmk, so don't return. set up TMPDIR - export TMPDIR="/tmp" - export TMPDIR="$(mktemp -d -t xbmk_XXXXXXXX)" - xbmktmp="$TMPDIR" - - # /tmp might be a tmpfs, so for large files we use ./tmp, - # not to be confused with xbmktmp (xbmktmp points to /tmp) - remkdir "$xbmktmp" "$xbmklocal" -} - -xbmk_lock() -{ - [ -f "$xbmklock" ] && err "'$xbmklock' exists. Is a build running?" - touch "$xbmklock" || err "cannot create '$xbmklock'"; : -} - -xbmk_create_pathdirs() -{ - remkdir "$XBMK_CACHE/gnupath" "$XBMK_CACHE/xbmkpath" - export PATH="$XBMK_CACHE/xbmkpath:$XBMK_CACHE/gnupath:$PATH" - ( - # set up python v3.x in PATH, in case it's not set up correctly. - # see code above that detected the correct python3 command. - x_ cd "$XBMK_CACHE/xbmkpath" - x_ ln -s "`pybin "$python"`" python - ) || err "Can't set up python symlink in $XBMK_CACHE/xbmkpath"; : -} - xbmk_child_exec() { xbmk_rval=0 + ( x_ ./mk "$@" ) || xbmk_rval=1 - ( x_ rm -Rf "$xbmklocal" "$xbmktmp" ) || xbmk_rval=1 + + ( x_ rm -Rf "$xbtmp" ) || xbmk_rval=1 ( x_ rm -f "$xbmklock" ) || xbmk_rval=1 + exit $xbmk_rval } diff --git a/include/inject.sh b/include/inject.sh index 890ac275..90528ac0 100644 --- a/include/inject.sh +++ b/include/inject.sh @@ -1,28 +1,45 @@ # SPDX-License-Identifier: GPL-3.0-only + # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2023-2025 Leah Rowe <leah@libreboot.org> cbcfgsdir="config/coreboot" -hashfiles="vendorhashes blobhashes" # blobhashes for backwards compatibility tmpromdel="$XBMK_CACHE/DO_NOT_FLASH" nvm="util/nvmutil/nvm" -ifdtool="elf/ifdtool/default/ifdtool" - -cv="CONFIG_GBE_BIN_PATH" -[ -n "$cvxbmk" ] && cv="$cv $cvxbmk" -[ -n "$cvchk" ] && cv="$cv $cvchk" - -eval "`setvars "" archive boarddir IFD_platform ifdprefix tree new_mac \ - tmpromdir board $cv`" +ifdtool="elf/coreboot/default/ifdtool" + +checkvars="CONFIG_GBE_BIN_PATH" +if [ -n "$checkvarsxbmk" ]; then + checkvars="$checkvars $checkvarsxbmk" +fi +if [ -n "$checkvarschk" ]; then + checkvars="$checkvars $checkvarschk" +fi + +archive="" +boarddir="" +IFD_platform="" +ifdprefix="" +tree="" +new_mac="" +tmpromdir="" +board="" +xchanged="" + +eval "`setvars "" $checkvars`" inject() { remkdir "$tmpromdel" - set +u +e - [ $# -lt 1 ] && err "No options specified" - eval "`setvars "" nukemode new_mac xchanged`" + if [ $# -lt 1 ]; then + err "No options specified" "inject" "$@" + fi + + nuke="" + new_mac="" + xchanged="" archive="$1"; new_mac="xx:xx:xx:xx:xx:xx" @@ -30,61 +47,104 @@ inject() [ $# -gt 1 ] && case "$2" in nuke) new_mac="" - nukemode="nuke" ;; + nuke="nuke" + ;; setmac) - [ $# -gt 2 ] && new_mac="$3" && \ - [ -z "$new_mac" ] && err "Empty MAC address specified" ;; + if [ $# -gt 2 ]; then + new_mac="$3" && \ + if [ -z "$new_mac" ]; then + err "Empty MAC address specified" "inject" "$@" + fi + fi + ;; *) - err "Unrecognised inject mode: '$2'" + err "Unrecognised inject mode: '$2'" "inject" "$@" ;; esac - [ "$new_mac" = "keep" ] && new_mac="" - - check_release - check_target && patch_release - [ "$xchanged" = "y" ] && remktar + if [ "$new_mac" = "keep" ]; then + new_mac="" + fi - xnot=" NOT" && [ "$xchanged" = "y" ] && xnot="" - printf "\n'%s' was%s modified\n" "$archive" "$xnot" 1>&2 + check_release + if check_target; then + if ! patch_release; then + return 0 + fi + fi + if [ "$xchanged" = "y" ]; then + remktar + fi + + if [ "$xchanged" = "y" ]; then + printf "\n'%s' was modified\n" "$archive" 1>&2 + else + printf "\n'%s' was NOT modified\n" "$archive" 1>&2 + fi x_ rm -Rf "$tmpromdel" } check_release() { - [ -L "$archive" ] && err "'$archive' is a symlink" - e "$archive" f missing && err "'$archive' missing" + if [ -L "$archive" ]; then + err "'$archive' is a symlink" "check_release" "$@" + fi + if e "$archive" f missing; then + err "'$archive' missing" "check_release" "$@" + fi + + archivename="`basename "$archive" || err "Can't get '$archive' name"`" \ + || err "can't get '$archive' name" "check_release" "$@" - archivename="`basename "$archive"`" || err "Can't get '$archive' name" - [ -z "$archivename" ] && err "Can't determine archive name" + if [ -z "$archivename" ]; then + err "Can't determine archive name" "check_release" "$@" + fi case "$archivename" in *_src.tar.xz) - err "'$archive' is a src archive, silly!" ;; + err "'$archive' is a src archive!" "check_release" "$@" + ;; grub_*|seagrub_*|custom_*|seauboot_*|seabios_withgrub_*) - err "'$archive' is a ROM image (it must be a tarball)" ;; + err "'$archive' is a ROM image" "check_release" "$@" + ;; *.tar.xz) _stripped_prefix="${archivename#*_}" - board="${_stripped_prefix%.tar.xz}" ;; + board="${_stripped_prefix%.tar.xz}" + ;; *) - err "'$archive': could not detect board type" + err "'$archive': cannot detect board" "check_release" "$@" + ;; esac; : } check_target() { - [ "$board" = "${board#serprog_}" ] || return 1 + if [ "$board" != "${board#serprog_}" ]; then + return 1 + fi + boarddir="$cbcfgsdir/$board" - eval "`setcfg "$boarddir/target.cfg"`" - chkvars tree && x_ ./mk -d coreboot "$tree" + . "$boarddir/target.cfg" || \ + err "Can't read '$boarddir/target.cfg'" "check_target" "$@" + + if [ -z "$tree" ]; then + err "tree unset in '$boarddir/target.cfg'" "check_target" "$@" + fi + + x_ ./mk -d coreboot "$tree" - ifdtool="elf/ifdtool/$tree/ifdtool" - [ -n "$IFD_platform" ] && ifdprefix="-p $IFD_platform"; : + ifdtool="elf/coreboot/$tree/ifdtool" + + if [ -n "$IFD_platform" ]; then + ifdprefix="-p $IFD_platform" + fi } patch_release() { - [ "$nukemode" = "nuke" ] || x_ ./mk download "$board" + if [ "$nuke" != "nuke" ]; then + x_ ./mk download "$board" + fi has_hashes="n" tmpromdir="$tmpromdel/bin/$board" @@ -92,58 +152,83 @@ patch_release() remkdir "${tmpromdir%"/bin/$board"}" x_ tar -xf "$archive" -C "${tmpromdir%"/bin/$board"}" - for _hashes in $hashfiles; do - e "$tmpromdir/$_hashes" f && \ - has_hashes="y" && hashfile="$_hashes" && break; : - done + for _hashes in "vendorhashes" "blobhashes"; do + if e "$tmpromdir/$_hashes" f; then + has_hashes="y" + hashfile="$_hashes" - readkconfig || exit 0 + break + fi + done - [ -n "$new_mac" ] && [ -n "$CONFIG_GBE_BIN_PATH" ] && modify_mac; : + if ! readkconfig; then + return 1 + elif [ -n "$new_mac" ] && [ -n "$CONFIG_GBE_BIN_PATH" ]; then + modify_mac + fi } readkconfig() { - x_ rm -f "$xbmktmp/cbcfg" + x_ rm -f "$xbtmp/cbcfg" + fx_ scankconfig x_ find "$boarddir/config" -type f - eval "`setcfg "$xbmktmp/cbcfg" 1`" - setvfile "$@" || return 1; : + + if e "$xbtmp/cbcfg" f missing; then + return 1 + fi + + . "$xbtmp/cbcfg" || \ + err "Can't read '$xbtmp/cbcfg'" "readkconfig" "$@" + + if ! setvfile "$@"; then + return 1 + fi } scankconfig() { - for cbc in $cv; do - grep "$cbc" "$1" 1>>"$xbmktmp/cbcfg" 2>/dev/null || : + for cbc in $checkvars; do + grep "$cbc" "$1" 2>/dev/null 1>>"$xbtmp/cbcfg" || : done } modify_mac() { - x_ cp "${CONFIG_GBE_BIN_PATH##*../}" "$xbmklocal/gbe" - [ -n "$new_mac" ] && [ "$new_mac" != "restore" ] && \ - x_ make -C util/nvmutil clean && x_ make -C util/nvmutil && \ - x_ "$nvm" "$xbmklocal/gbe" setmac "$new_mac" + x_ cp "${CONFIG_GBE_BIN_PATH##*../}" "$xbtmp/gbe" + + if [ -n "$new_mac" ] && [ "$new_mac" != "restore" ]; then + x_ make -C util/nvmutil clean + x_ make -C util/nvmutil + + x_ "$nvm" "$xbtmp/gbe" setmac "$new_mac" + fi fx_ newmac x_ find "$tmpromdir" -maxdepth 1 -type f -name "*.rom" printf "\nThe following GbE NVM data will be written:\n" - x_ "$nvm" "$xbmklocal/gbe" dump | grep -v "bytes read from file" || : + x_ "$nvm" "$xbtmp/gbe" dump | grep -v "bytes read from file" || : } newmac() { - e "$1" f && xchanged="y" && x_ \ - "$ifdtool" $ifdprefix -i GbE:"$xbmklocal/gbe" "$1" -O "$1"; : + if e "$1" f; then + xchanged="y" + x_ "$ifdtool" $ifdprefix -i GbE:"$xbtmp/gbe" "$1" -O "$1" + fi } remktar() { ( - x_ cd "${tmpromdir%"/bin/$board"}" - printf "Re-building tar archive (please wait)\n" - mkrom_tarball "bin/$board" 1>/dev/null - ) || err "Cannot re-generate '$archive'" + x_ cd "${tmpromdir%"/bin/$board"}" + + printf "Re-building tar archive (please wait)\n" + mkrom_tarball "bin/$board" 1>/dev/null + + ) || err "Cannot re-generate '$archive'" "remktar" "$@" mv "${tmpromdir%"/bin/$board"}/bin/${relname}_${board}.tar.xz" \ - "$archive" || err "'$archive' -> Can't overwrite"; : + "$archive" || \ + err "'$archive' -> Can't overwrite" "remktar" "$@"; : } diff --git a/include/lib.sh b/include/lib.sh index c69825e8..feb411e0 100644 --- a/include/lib.sh +++ b/include/lib.sh @@ -1,185 +1,267 @@ # SPDX-License-Identifier: GPL-3.0-only + # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2020-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2025 Alper Nebi Yasak <alpernebiyasak@gmail.com> -cbfstool="elf/cbfstool/default/cbfstool" -rmodtool="elf/cbfstool/default/rmodtool" - -remkdir() -{ - x_ rm -Rf "$@" - x_ mkdir -p "$@" -} +cbfstool="elf/coreboot/default/cbfstool" +rmodtool="elf/coreboot/default/rmodtool" mkrom_tarball() { - printf "%s\n" "$version" > "$1/.version" || err "$1 !version" - printf "%s\n" "$versiondate" > "$1/.versiondate" || err "$1 !vdate" - + update_xbmkver "$1" mktarball "$1" "${1%/*}/${relname}_${1##*/}.tar.xz" + x_ rm -Rf "$1" } -mktarball() +update_xbmkver() { - printf "Creating tar archive '%s' from directory '%s'\n" "$2" "$1" - [ "${2%/*}" = "$2" ] || x_ mkdir -p "${2%/*}" - x_ tar -c "$1" | xz -T$XBMK_THREADS -9e > "$2" || err "mktarball2, $1" -} + xbmk_sanitize_version -mksha512sum() -{ - ( - [ "${1%/*}" != "$1" ] && x_ cd "${1%/*}" - sha512sum ./"${1##*/}" >> "$2" || err "!sha512sum \"$1\" > \"$2\"" - ) || err "failed to create tarball checksum" -} + printf "%s\n" "$version" > "$1/.version" || \ + err "can't write '$1'" "update_xbmkver" "$@"; : -rmgit() -{ - x_ find "$1" -name ".git" -exec rm -Rf {} + - x_ find "$1" -name ".gitmodules" -exec rm -Rf {} + + printf "%s\n" "$versiondate" > "$1/.versiondate" || \ + err "can't write '$versiondate'" "update_xbmkver" "$@"; : } -# can grab from the internet, or copy locally. -# if copying locally, it can only copy a file. -xbmkget() +xbmk_sanitize_version() { - _ua="Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0" + if [ -z "$version" ]; then + return 0 + fi - _dlop="curl" && [ $# -gt 4 ] && _dlop="$5" - x_ mkdir -p "${3%/*}" "$XBMK_CACHE/file" - for url in "$1" "$2"; do - [ -n "$url" ] && try_file "$url" "$_dlop" "$@" && return 0 - done && err "$1 $2 $3 $4: not downloaded"; : -} + version="`printf "%s\n" "$version" | sed -e 's/\t//g'`" + version="`printf "%s\n" "$version" | sed -e 's/\ //g'`" + version="`printf "%s\n" "$version" | sed -e 's/\.\.//g'`" + version="`printf "%s\n" "$version" | sed -e 's/\.\///g'`" + version="`printf "%s\n" "$version" | sed -e 's/\//-/g'`" -try_file() -{ - cached="$XBMK_CACHE/file/$6" - dl_fail="n" # 1 url, 2 url backup, 3 destination, 4 checksum - bad_checksum "$6" "$cached" 2>/dev/null && dl_fail="y" - [ "$dl_fail" = "n" ] && e "$5" f && return 0 + version="${version#-}" - x_ rm -f "$cached" - if [ "$2" = "curl" ]; then - curl --location --retry 3 -A "$_ua" "$1" -o "$cached" || \ - wget --tries 3 -U "$_ua" "$1" -O "$cached" || return 1 - elif [ "$2" = "copy" ]; then - [ -L "$1" ] && printf "dl %s %s %s %s: '%s' is a symlink\n" \ - "$3" "$4" "$5" "$6" "$1" 1>&2 && return 1 - [ ! -f "$1" ] && printf "dl %s %s %s %s: '%s' not a file\n" \ - "$3" "$4" "$5" "$6" "$1" 1>&2 && return 1 - cp "$1" "$cached" || return 1 - else - err "$3 $4 $5 $6: Unsupported dlop type: '$2'" + if [ -z "$version" ]; then + err "'version' empty after sanitization" \ + "xbmk_sanitize_version" "$@" fi - bad_checksum "$6" "$cached" && return 1 - [ "$cached" = "$5" ] || x_ cp "$cached" "$5"; : } -bad_checksum() +mktarball() { - [ "$(sha512sum "$2" | awk '{print $1}')" != "$1" ] || return 1 - printf "Bad checksum for file: %s\n" "$2" 1>&2; rm -f "$2" || :; : + printf "Creating tar archive '%s' from directory '%s'\n" "$2" "$1" + + if [ "${2%/*}" != "$2" ]; then + x_ xbmkdir "${2%/*}" + fi + + x_ tar -c "$1" | xz -T$XBMK_THREADS -9e > "$2" || \ + err "can't make tarball '$1'" "mktarball" "$@" } e() { - es_t="e" && [ $# -gt 1 ] && es_t="$2" + es_t="e" + + if [ $# -gt 1 ]; then + es_t="$2" + fi + es2="already exists" estr="[ -$es_t \"\$1\" ] || return 1" - [ $# -gt 2 ] && estr="[ -$es_t \"\$1\" ] && return 1" && es2="missing" + + if [ $# -gt 2 ]; then + estr="[ -$es_t \"\$1\" ] && return 1" + es2="missing" + fi eval "$estr" - printf "%s %s\n" "$1" "$es2" 1>&2 -} -mk() -{ - mk_flag="$1" || err "No argument given" - shift 1 && for mk_arg in "$@"; do - x_ ./mk $mk_flag $mk_arg - done; : + printf "%s %s\n" "$1" "$es2" 1>&2 } setvars() { _setvars="" + if [ $# -lt 2 ]; then - printf "err \"setvars: too few args\\n\"" + return 0 - fi - val="$1" - shift 1 - for var in "$@"; do - _setvars="$var=\"$val\"; $_setvars" - done - printf "%s\n" "${_setvars% }" -} + else + val="$1" -setcfg() -{ - [ $# -gt 1 ] && printf "e \"%s\" f missing && return %s;\n" "$1" "$2" - [ $# -gt 1 ] || \ - printf "e \"%s\" f not && err \"Missing config\";\n" "$1" - printf ". \"%s\" || err \"Could not read config\";\n" "$1" -} + shift 1 -chkvars() -{ - for var in "$@"; do - eval "[ -n \"\${$var+x}\" ] || err \"$var unset\"" - eval "[ -n \"\$$var\" ] || err \"$var unset\"" - done; : + while [ $# -gt 0 ]; do + printf "%s=\"%s\"\n" "$1" "$val" + + shift 1 + done + fi } # return 0 if project is single-tree, otherwise 1 # e.g. coreboot is multi-tree, so 1 singletree() { - ( fx_ "exit 1" find "config/$1/"*/ -type f -name "target.cfg" ) || \ - return 1 + ( fx_ "eval exit 1 && err" find "config/$1/"*/ -type f \ + -name "target.cfg" ) || return 1; : } findpath() { - [ $# -gt 0 ] || err "findpath: No arguments provided" - while [ $# -gt 0 ]; do + if [ $# -lt 1 ]; then + err "findpath: No arguments provided" "findpath" "$@" + fi + + while [ $# -gt 0 ] + do found="`readlink -f "$1" 2>/dev/null`" || return 1; : - [ -n "$found" ] || found="`realpath "$1" 2>/dev/null`" || \ - return 1; : + + if [ -z "$found" ]; then + found="`realpath "$1" 2>/dev/null`" || \ + return 1 + fi + printf "%s\n" "$found" + + shift 1 + done +} + +pad_one_byte() +{ + paddedfile="`mktemp || err "mktemp pad_one_byte"`" || \ + err "can't make tmp file" "pad_one_byte" "$@" + + x_ cat "$1" config/data/coreboot/0 > "$paddedfile" || \ + err "could not pad file '$paddedfile'" "pad_one_byte" "$1"; : + + x_ mv "$paddedfile" "$1" +} + +unpad_one_byte() +{ + xromsize="$(expr $(stat -c '%s' "$1") - 1)" || \ + err "can't increment file size" "unpad_one_byte" "$@" + + if [ $xromsize -lt 524288 ]; then + err "too small, $xromsize: $1" "unpad_one_byte" "$@" + fi + + unpaddedfile="`mktemp || err "mktemp unpad_one_byte"`" || \ + err "can't make tmp file" "unpad_one_byte" "$@" + + x_ dd if="$1" of="$unpaddedfile" bs=$xromsize count=1 + x_ mv "$unpaddedfile" "$1" +} + +build_sbase() +{ + if [ ! -f "$sha512sum" ]; then + x_ make -C "$xbmkpwd/util/sbase" + fi +} + +remkdir() +{ + x_ rm -Rf "$@" + x_ xbmkdir "$@" +} + +xbmkdir() +{ + while [ $# -gt 0 ] + do + if [ ! -d "$1" ]; then + x_ mkdir -p "$1" + fi + shift 1 done } fx_() { - fd="`mktemp`" && x_ rm -f "$fd" && x_ touch "$fd" - xx="$1" && shift 1 - "$@" 2>/dev/null | sort 1>"$fd" 2>/dev/null || err "FATAL: !sort fx_" - dx_ "$xx" "$fd" || break - x_ rm -f "$fd" + xchk fx_ "$@" + xcmd="$1" + + xfile="`mktemp || err "can't create tmpfile"`" || \ + err "can't make tmpfile" "fx_" "$@" + + x_ rm -f "$xfile" + x_ touch "$xfile" + + shift 1 + + "$@" 2>/dev/null | sort 1>"$xfile" 2>/dev/null || \ + err "can't sort to '$xfile'" "fx_" "$xcmd" "$@" + + dx_ "$xcmd" "$xfile" || : + x_ rm -f "$xfile" } dx_() { - [ -f "$2" ] && while read -r fx; do - $1 "$fx" || return 1 - done < "$2"; : + xchk dx_ "$@" + + if [ ! -f "$2" ]; then + return 0 + fi + + while read -r fx; do + $1 "$fx" || return 1; : + done < "$2" || err "cannot read '$2'" "dx_" "$@"; : } x_() { - [ $# -lt 1 ] || [ -n "$1" ] || err "Empty first arg: x_ $(echo "$@")" - [ $# -lt 1 ] || "$@" || err "Unhandled error for: $(echo "$@")"; : + if [ $# -lt 1 ]; then + return 0 + elif [ -z "$1" ]; then + err "Empty first arg" "x_" "$@" + else + "$@" || err "Unhandled error" "x_" "$@" + fi +} + +xchk() +{ + if [ $# -lt 3 ]; then + err "$1 needs at least two arguments" "xchk" "$@" + elif [ -z "$2" ] || [ -z "$3" ]; then + err "arguments must not be empty" "xchk" "$@" + fi } err() { - [ $# -lt 1 ] || printf "ERROR %s: %s\n" "$0" "$1" 1>&2 || : + if [ $# -eq 1 ]; then + printf "ERROR %s: %s\n" "$0" "$1" 1>&2 || : + elif [ $# -gt 1 ]; then + printf "ERROR %s: %s: in command with args: " "$0" "$1" 1>&2 + shift 1 + xprintf "$@" 1>&2 + else + printf "ERROR, but no arguments provided to err\n" 1>&2 + fi + exit 1 } + +xprintf() +{ + xprintfargs=0 + while [ $# -gt 0 ]; do + printf "\"%s\"" "$1" + if [ $# -gt 1 ]; then + printf " " + fi + + xprintfargs=1 + shift 1 + done + if [ $xprintfargs -gt 0 ]; then + printf "\n" + fi +} diff --git a/include/mrc.sh b/include/mrc.sh index 3b3089fc..f1e31fa7 100644 --- a/include/mrc.sh +++ b/include/mrc.sh @@ -1,68 +1,77 @@ # SPDX-License-Identifier: GPL-2.0-only # Logic based on util/chromeos/crosfirmware.sh in coreboot cfc26ce278. -# Modifications in this version are Copyright 2021, 2023 and 2024 Leah Rowe. +# Modifications in this version are Copyright 2021,2023-2025 Leah Rowe. # Original copyright detailed in repo: https://review.coreboot.org/coreboot/ -eval "`setvars "" MRC_url MRC_url_bkup MRC_hash MRC_board SHELLBALL`" - -extract_mrc() -{ - extract_shellball - - x_ "$cbfstool" "$appdir/"bios.bin extract -n mrc.bin \ - -f "$_dest" -r RO_SECTION - - [ -n "$CONFIG_REFCODE_BLOB_FILE" ] && extract_refcode extra; : -} +MRC_url="" +MRC_url_bkup="" +MRC_hash="" +MRC_board="" +SHELLBALL="" extract_refcode() { - _refdest="${CONFIG_REFCODE_BLOB_FILE##*../}" - e "$_refdest" f && return 0 - - [ $# -lt 1 ] && extract_shellball + extract_mrc # cbfstool after coreboot 4.13 changed the stage file attribute scheme, # and refcode is extracted from an image using the old scheme. we use - # cbfstool from coreboot 4.11_branch, the tree used by ASUS KGPE-D16 - chkvars cbfstoolref - x_ mkdir -p "${_refdest%/*}" + # cbfstool from coreboot 4.11_branch, the tree used by ASUS KGPE-D16: + + if [ -z "$cbfstoolref" ]; then + err "cbfstoolref not set" "extract_refcode" "$@" + fi + + x_ xbmkdir "${_pre_dest%/*}" x_ "$cbfstoolref" "$appdir/bios.bin" extract \ -m x86 -n fallback/refcode -f "$appdir/ref" -r RO_SECTION # enable the Intel GbE device, if told by offset MRC_refcode_gbe - [ -z "$MRC_refcode_gbe" ] || x_ dd if="config/ifd/hp820g2/1.bin" \ - of="$appdir/ref" bs=1 seek=$MRC_refcode_gbe count=1 conv=notrunc; : + if [ -n "$MRC_refcode_gbe" ]; then + x_ dd if="config/ifd/hp820g2/1.bin" of="$appdir/ref" bs=1 \ + seek=$MRC_refcode_gbe count=1 conv=notrunc; : + fi - x_ mv "$appdir/ref" "$_refdest" + x_ mv "$appdir/ref" "$_pre_dest" } -extract_shellball() +extract_mrc() { - chkvars "MRC_board" "CONFIG_MRC_FILE" + if [ -z "$MRC_board" ]; then + err "MRC_board unset" "extract_mrc" "$@" + elif [ -z "$CONFIG_MRC_FILE" ]; then + err "CONFIG_MRC_FILE unset" "extract_mrc" "$@" + fi + SHELLBALL="chromeos-firmwareupdate-$MRC_board" ( - x_ cd "$appdir" - extract_partition "${MRC_url##*/}" - extract_archive "$SHELLBALL" . - ) || err "mrc download/extract failure"; : + x_ cd "$appdir" + extract_partition "${MRC_url##*/}" + extract_archive "$SHELLBALL" . + + ) || err "mrc download/extract failure" "extract_mrc" "$@" + + x_ "$cbfstool" "$appdir/"bios.bin extract -n mrc.bin \ + -f "${_pre_dest%/*}/mrc.bin" -r RO_SECTION } extract_partition() { printf "Extracting ROOT-A partition\n" + ROOTP=$( printf "unit\nB\nprint\nquit\n" | \ parted "${1%.zip}" 2>/dev/null | grep "ROOT-A" ) START=$(( $( echo $ROOTP | cut -f2 -d\ | tr -d "B" ) )) + SIZE=$(( $( echo $ROOTP | cut -f4 -d\ | tr -d "B" ) )) - x_ dd if="${1%.zip}" of="root-a.ext2" bs=1024 skip=$(( $START / 1024 )) \ - count=$(( $SIZE / 1024 )) + x_ dd if="${1%.zip}" of="root-a.ext2" bs=1024 \ + skip=$(( $START / 1024 )) count=$(( $SIZE / 1024 )) printf "cd /usr/sbin\ndump chromeos-firmwareupdate %s\nquit" \ - "$SHELLBALL" | debugfs "root-a.ext2" || err "!extract shellball" + "$SHELLBALL" | debugfs "root-a.ext2" || \ + err "!extract shellball" "extract_partition" "$@" } diff --git a/include/release.sh b/include/release.sh index 4741b44a..339ab3f5 100644 --- a/include/release.sh +++ b/include/release.sh @@ -1,65 +1,130 @@ # SPDX-License-Identifier: GPL-3.0-or-later + # Copyright (c) 2023-2025 Leah Rowe <leah@libreboot.org> -eval "`setvars "" vdir src_dirname relsrcdir relmode`" +reldir="" +reldest="" +vdir="" +rsrc="" +relmode="" release() { export XBMK_RELEASE="y" - vdir="release" - while getopts d:m: option; do - [ -z "$OPTARG" ] && err "empty argument not allowed" + reldir="release" + + while getopts m: option + do + if [ -z "$OPTARG" ]; then + err "empty argument not allowed" "release" "$@" + fi + case "$option" in - d) vdir="$OPTARG" ;; - m) relmode="$OPTARG" ;; - *) err "invalid option '-$option'" ;; + m) + relmode="$OPTARG" + ;; + *) + err "invalid option '-$option'" "release" "$@" + ;; esac done + reldest="$reldir/$version" + if [ -e "$reldest" ]; then + err "already exists: \"$reldest\"" "release" "$@" + fi + + vdir="`mktemp -d || err "can't make vdir"`" || \ + err "can't make tmp vdir" "release" "$@" vdir="$vdir/$version" - src_dirname="${relname}_src" - relsrcdir="$vdir/$src_dirname" - [ -e "$vdir" ] && err "already exists: \"$vdir\"" - x_ mkdir -p "$vdir" - x_ git clone . "$relsrcdir" - x_ touch "$relsrcdir/lock" + rsrc="$vdir/${relname}_src" - build_release + remkdir "$vdir" + x_ git clone . "$rsrc" + update_xbmkver "$rsrc" - printf "\n\nDONE! Check release files under %s\n" "$vdir" + prep_release src + prep_release tarball + if [ "$relmode" != "src" ]; then + prep_release bin + fi + x_ rm -Rf "$rsrc" + + x_ xbmkdir "$reldir" + x_ mv "$vdir" "$reldir" + x_ rm -Rf "${vdir%"/$version"}" + + printf "\n\nDONE! Check release files under %s\n" "$reldest" } -build_release() +prep_release() { ( - x_ cd "$relsrcdir" + if [ "$1" != "tarball" ]; then + x_ cd "$rsrc" + if [ ! -e "cache" ]; then + x_ ln -s "$XBMK_CACHE" "cache" + fi + fi + + prep_release_$1 + + ) || err "can't prep release $1" "prep_release" "$@" +} + +prep_release_src() +{ + x_ cp -R "util/sbase" "util/sbase2" x_ ./mk -f - rmgit . - x_ mv src/docs docs - ) || err "can't create release files" + fx_ "x_ rm -Rf" x_ find . -name ".git" + fx_ "x_ rm -Rf" x_ find . -name ".gitmodules" + + ( fx_ nuke x_ find config -type f -name "nuke.list" ) || \ + err "can't prune project files" "prep_release_src" "$@"; : +} + +nuke() +{ + r="$rsrc/src/${1#config/}" + + if [ -d "${r%/*}" ]; then + x_ cd "${r%/*}" + + dx_ "x_ rm -Rf" "$rsrc/$1" + fi +} + +prep_release_tarball() +{ git log --graph --pretty=format:'%Cred%h%Creset %s %Creset' \ - --abbrev-commit > "$relsrcdir/CHANGELOG" || err "!log $relsrcdir" - x_ rm -f "$relsrcdir/lock" + --abbrev-commit > "$rsrc/CHANGELOG" || \ + err "can't create '$rsrc/CHANGELOG'" "prep_release_tarball" "$@" - ( - x_ cd "${relsrcdir%/*}" - x_ mktarball "${relsrcdir##*/}" "${relsrcdir##*/}.tar.xz" - ) || err "can't create src tarball" - [ "$relmode" = "src" ] && return 0 + x_ rm -f "$rsrc/lock" "$rsrc/cache" + x_ rm -Rf "$rsrc/xbmkwd" "$rsrc/util/sbase" + x_ mv "$rsrc/util/sbase2" "$rsrc/util/sbase" - x_ touch "$relsrcdir/lock" ( - x_ cd "$relsrcdir" + x_ cd "${rsrc%/*}" + x_ mktarball "${rsrc##*/}" "${rsrc##*/}.tar.xz" + + ) || err "can't create src tarball" "prep_release_tarball" "$@"; : +} + +prep_release_bin() +{ x_ ./mk -d coreboot - mk -b coreboot pico-serprog stm32-vserprog pcsx-redux + + x_ ./mk -b coreboot + x_ ./mk -b pico-serprog + x_ ./mk -b stm32-vserprog + x_ ./mk -b pcsx-redux fx_ mkrom_tarball x_ find bin -maxdepth 1 -type d -name "serprog_*" - x_ mv bin ../roms - ) || err "can't build rom images" - x_ rm -Rf "$relsrcdir" + x_ mv bin ../roms } diff --git a/include/rom.sh b/include/rom.sh index fdd0787f..6f0e3529 100644 --- a/include/rom.sh +++ b/include/rom.sh @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-3.0-or-later + # Copyright (c) 2014-2016,2020-2021,2023-2025 Leah Rowe <leah@libreboot.org> # Copyright (c) 2021-2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> @@ -9,31 +10,50 @@ grubdata="config/data/grub" buildser() { - [ "$1" = "pico" ] && x_ cmake -DPICO_BOARD="$2" \ - -DPICO_SDK_PATH="$picosdk" -B "$sersrc/build" "$sersrc" && \ - x_ cmake --build "$sersrc/build" - [ "$1" = "stm32" ] && x_ make -C "$sersrc" libopencm3-just-make \ - BOARD=$2 && x_ make -C "$sersrc" BOARD=$2 - x_ mkdir -p "bin/serprog_$1" + if [ "$1" = "pico" ]; then + x_ cmake -DPICO_BOARD="$2" \ + -DPICO_SDK_PATH="$picosdk" -B "$sersrc/build" "$sersrc" + x_ cmake --build "$sersrc/build" + elif [ "$1" = "stm32" ]; then + x_ make -C "$sersrc" libopencm3-just-make BOARD=$2 + x_ make -C "$sersrc" BOARD=$2 + fi + + x_ xbmkdir "bin/serprog_$1" x_ mv "$serx" "bin/serprog_$1/serprog_$2.${serx##*.}" } copyps1bios() { + $if_dry_build \ + return 0 + remkdir "bin/playstation" x_ cp src/pcsx-redux/src/mips/openbios/openbios.bin bin/playstation - printf "MIT License\n\nCopyright (c) 2019-2024 PCSX-Redux authors\n\n" \ - > bin/playstation/COPYING.txt || err "!pcsx-redux copyright" - cat config/snippet/mit >>bin/playstation/COPYING.txt || err "!pcsx MIT" + printf "MIT License\n\nCopyright (c) 2019-2025 PCSX-Redux authors\n\n" \ + > bin/playstation/COPYING.txt || \ + err "can't write PCSX Redux copyright info" "copyps1bios" "$@" + + x_ cat config/snippet/mit >>bin/playstation/COPYING.txt || \ + err "can't copy MIT license snippet" "copyps1bios" "$@" } mkpayload_grub() { - eval "`setvars "" grub_modules grub_install_modules`" - $dry eval "`setcfg "$grubdata/module/$tree"`" - $dry x_ rm -f "$srcdir/grub.elf"; $dry \ - x_ "$srcdir/grub-mkstandalone" --grub-mkimage="$srcdir/grub-mkimage" \ + grub_modules="" + grub_install_modules="" + + $if_dry_build \ + return 0 + + . "$grubdata/module/$tree" || \ + err "Can't read '$grubdata/module/$tree'" "mkpayload_grub" "$@" + + x_ rm -f "$srcdir/grub.elf" + + x_ "$srcdir/grub-mkstandalone" \ + --grub-mkimage="$srcdir/grub-mkimage" \ -O i386-coreboot -o "$srcdir/grub.elf" -d "${srcdir}/grub-core/" \ --fonts= --themes= --locales= --modules="$grub_modules" \ --install-modules="$grub_install_modules" \ @@ -41,160 +61,337 @@ mkpayload_grub() "/boot/grub/grub.cfg=$grubdata/memdisk.cfg"; : } -mkvendorfiles() +corebootpremake() { - [ -z "$mode" ] && $dry cook_coreboot_config - check_coreboot_utils "$tree" + if [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ]; then + return 0 + fi + + $if_not_dry_build \ + cook_coreboot_config + + fx_ check_coreboot_util printf "cbfstool\nifdtool\n" + printf "%s\n" "${version%%-*}" > "$srcdir/.coreboot-version" || \ - err "!mk $srcdir .coreboot-version" - [ -z "$mode" ] && [ "$target" != "$tree" ] && \ - x_ ./mk download "$target"; : + err "!mk $srcdir .coreboot-version" "corebootpremake" "$@" + + if [ -z "$mode" ] && [ "$target" != "$tree" ]; then + x_ ./mk download "$target" + fi } cook_coreboot_config() { - [ -f "$srcdir/.config" ] || return 0 - printf "CONFIG_CCACHE=y\n" >> "$srcdir/.config" || \ - err "$srcdir/.config: Could not enable ccache" - make -C "$srcdir" oldconfig || err "Could not cook $srcdir/.config"; : + if [ -z "$mode" ] && [ -f "$srcdir/.config" ]; then + printf "CONFIG_CCACHE=y\n" >> "$srcdir/.config" || \ + err "can't cook '$srcdir'" "cook_coreboot_config" "$@" + fi +} + +check_coreboot_util() +{ + if [ "$badhash" = "y" ]; then + x_ rm -f "elf/coreboot/$tree/$1" + fi + if e "elf/coreboot/$tree/$1" f; then + return 0 + fi + + utilelfdir="elf/coreboot/$tree" + utilsrcdir="src/coreboot/$tree/util/$1" + + utilmode="" + if [ -n "$mode" ]; then + utilmode="clean" + fi + + x_ make -C "$utilsrcdir" $utilmode -j$XBMK_THREADS $makeargs + + if [ -n "$mode" ]; then + # TODO: is this rm command needed? + + x_ rm -Rf "$utilelfdir" + + return 0 + elif [ -n "$mode" ] || [ -f "$utilelfdir/$1" ]; then + return 0 + fi + + x_ xbmkdir "$utilelfdir" + x_ cp "$utilsrcdir/$1" "$utilelfdir" + + if [ "$1" = "cbfstool" ]; then + x_ cp "$utilsrcdir/rmodtool" "$utilelfdir" + fi } -check_coreboot_utils() +coreboot_pad_one_byte() { - for util in cbfstool ifdtool; do - [ "$badhash" = "y" ] && x_ rm -f "elf/$util/$1/$util" - e "elf/$util/$1/$util" f && continue - - utilelfdir="elf/$util/$1" - utilsrcdir="src/coreboot/$1/util/$util" - - utilmode="" && [ -n "$mode" ] && utilmode="clean" - x_ make -C "$utilsrcdir" $utilmode -j$XBMK_THREADS $makeargs - if [ -z "$mode" ] && [ ! -f "$utilelfdir/$util" ]; then - x_ mkdir -p "$utilelfdir" - x_ cp "$utilsrcdir/$util" "$utilelfdir" - [ "$util" = "cbfstool" ] || continue - x_ cp "$utilsrcdir/rmodtool" "$utilelfdir" - elif [ -n "$mode" ]; then - x_ rm -Rf "$utilelfdir" - fi; : - done; : + if [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ]; then + return 0 + fi + + $if_not_dry_build \ + pad_one_byte "$srcdir/build/coreboot.rom" } mkcorebootbin() { - [ "$target" = "$tree" ] && return 0 + if [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ]; then + return 0 + fi + + $if_not_dry_build \ + check_coreboot_util cbfstool + + $if_not_dry_build \ + check_coreboot_util ifdtool + + for y in "$target_dir/config"/*; do + defconfig="$y" + mkcorebootbin_real + done + + mkcoreboottar +} + +mkcorebootbin_real() +{ + if [ "$target" = "$tree" ]; then + return 0 + fi - tmprom="$xbmktmp/coreboot.rom" - $dry x_ cp "$srcdir/build/coreboot.rom" "$tmprom" + tmprom="$xbtmp/coreboot.rom" initmode="${defconfig##*/}" displaymode="${initmode##*_}" - [ "$displaymode" = "$initmode" ] && displaymode="" # "normal" config + if [ "$displaymode" = "$initmode" ]; then + # blank it for "normal" or "fspgop" configs: + + displaymode="" + fi initmode="${initmode%%_*}" - cbfstool="elf/cbfstool/$tree/cbfstool" + cbfstool="elf/coreboot/$tree/cbfstool" - [ "$payload_uboot_i386" = "y" ] && \ - [ "$payload_uboot_amd64" = "y" ] && \ - err "'$target' enables 32- and 64-bit x86 U-Boot" + # cbfstool option backends, if they exist + cbfscfg="config/coreboot/$target/cbfs.cfg" - if [ "$payload_uboot_i386" = "y" ] || \ - [ "$payload_uboot_amd64" = "y" ]; then - printf "'%s' has x86 U-Boot; assuming SeaBIOS=y\n" \ - "$target" 1>&2 + elfrom="elf/coreboot/$tree/$target/$initmode" + if [ -n "$displaymode" ]; then + elfrom="${elfrom}_$displaymode" + fi + elfrom="$elfrom/coreboot.rom" + + $if_not_dry_build \ + x_ cp "$elfrom" "$tmprom" + + $if_not_dry_build \ + unpad_one_byte "$tmprom" + + if [ -n "$payload_uboot" ] && [ "$payload_uboot" != "amd64" ] && \ + [ "$payload_uboot" != "i386" ] && [ "$payload_uboot" != "arm64" ] + then + err "'$target' defines bad u-boot type '$payload_uboot'" \ + "mkcorebootbin_real" "$@" + fi + + if [ -n "$payload_uboot" ] && [ "$payload_uboot" != "arm64" ]; then + payload_seabios="y" + fi + + if [ -z "$uboot_config" ]; then + uboot_config="default" + fi + if [ "$payload_grub" = "y" ]; then payload_seabios="y" fi + if [ "$payload_seabios" = "y" ] && [ "$payload_uboot" = "arm64" ]; then + $if_not_dry_build \ + err "$target: U-Boot arm / SeaBIOS/GRUB both enabled" \ + "mkcorebootbin_real" "$@" + fi - [ -n "$uboot_config" ] || uboot_config="default" - [ "$payload_uboot" = "y" ] || payload_seabios="y" - [ "$payload_grub" = "y" ] && payload_seabios="y" - [ "$payload_seabios" = "y" ] && [ "$payload_uboot" = "y" ] && \ - $dry err "$target: U-Boot(arm64) and SeaBIOS/GRUB both enabled." + if [ -z "$grub_scan_disk" ]; then + grub_scan_disk="nvme ahci ata" + fi + if [ -z "$grubtree" ]; then + grubtree="default" + fi + grubelf="elf/grub/$grubtree/$grubtree/payload/grub.elf" - [ -z "$grub_scan_disk" ] && grub_scan_disk="nvme ahci ata" + if [ "$payload_memtest" != "y" ]; then + payload_memtest="n" + fi + if [ "$(uname -m)" != "x86_64" ]; then + payload_memtest="n" + fi - [ -n "$grubtree" ] || grubtree="default" - grubelf="elf/grub/$grubtree/payload/grub.elf" + if [ "$payload_grubsea" = "y" ] && [ "$initmode" = "normal" ]; then + payload_grubsea="n" + fi + if [ "$payload_grub" != "y" ]; then + payload_grubsea="n" + fi - [ "$payload_memtest" = "y" ] || payload_memtest="n" - [ "$(uname -m)" = "x86_64" ] || payload_memtest="n" + $if_dry_build \ + return 0 - [ "$payload_grubsea" = "y" ] && [ "$initmode" = "normal" ] && \ - payload_grubsea="n" - [ "$payload_grub" = "y" ] || payload_grubsea="n" + if [ -f "$cbfscfg" ]; then + dx_ add_cbfs_option "$cbfscfg" + fi - if $dry grep "CONFIG_PAYLOAD_NONE=y" "$defconfig"; then - [ "$payload_seabios" = "y" ] && pname="seabios" && \ - $dry add_seabios - [ "$payload_uboot" = "y" ] && pname="uboot" && $dry add_uboot + if grep "CONFIG_PAYLOAD_NONE=y" "$defconfig"; then + if [ "$payload_seabios" = "y" ]; then + pname="seabios" + add_seabios + fi + if [ "$payload_uboot" = "arm64" ]; then + pname="uboot" + add_uboot + fi else pname="custom" - $dry cprom + cprom fi; : } +# options for cbfs backend (as opposed to nvram/smmstore): + +add_cbfs_option() +{ + # TODO: input sanitization (currently mitigated by careful config) + + op_name="`printf "%s\n" "$1" | awk '{print $1}'`" + op_arg="`printf "%s\n" "$1" | awk '{print $2}'`" + + if [ -z "$op_name" ] || [ -z "$op_arg" ]; then + return 0 + fi + + ( x_ "$cbfstool" "$tmprom" remove -n "option/$op_name" 1>/dev/null \ + 2>/dev/null ) || : + + x_ "$cbfstool" "$tmprom" add-int -i "$op_arg" -n "option/$op_name" +} + +# in our design, SeaBIOS is also responsible for starting either +# a GRUB or U-Boot payload. this is because SeaBIOS is generally +# a more reliable codebase, so it's less likely to cause a brick +# during testing and development, or user configuration. if one +# of the u-boot or grub payloads fails, the user still has a +# functional SeaBIOS setup to fall back on. watch: + add_seabios() { - if [ "$payload_uboot_i386" = "y" ] || \ - [ "$payload_uboot_amd64" = "y" ]; then - $dry add_uboot + if [ -n "$payload_uboot" ] && [ "$payload_uboot" != "arm64" ]; then + # we must add u-boot first, because it's added as a flat + # binary at a specific offset for secondary program loader + + $if_not_dry_build \ + add_uboot fi - _seabioself="elf/seabios/default/$initmode/bios.bin.elf" - _seaname="fallback/payload" && [ "$payload_grubsea" = "y" ] && \ - _seaname="seabios.elf" + _seabioself="elf/seabios/default/default/$initmode/bios.bin.elf" + [ "$initmode" = "fspgop" ] && \ + _seabioself="elf/seabios/default/default/libgfxinit/bios.bin.elf" + + _seaname="fallback/payload" + if [ "$payload_grubsea" = "y" ]; then + _seaname="seabios.elf" + fi cbfs "$tmprom" "$_seabioself" "$_seaname" + x_ "$cbfstool" "$tmprom" add-int -i 3000 -n etc/ps2-keyboard-spinup - _z="2" && [ "$initmode" = "vgarom" ] && _z="0" - x_ "$cbfstool" "$tmprom" add-int -i $_z -n etc/pci-optionrom-exec + opexec="2" + if [ "$initmode" = "vgarom" ]; then + opexec="0" + fi + x_ "$cbfstool" "$tmprom" add-int -i $opexec -n etc/pci-optionrom-exec + x_ "$cbfstool" "$tmprom" add-int -i 0 -n etc/optionroms-checksum - [ "$initmode" = "libgfxinit" ] && \ - cbfs "$tmprom" "$seavgabiosrom" vgaroms/seavgabios.bin raw + if [ "$initmode" = "libgfxinit" ] || [ "$initmode" = "fspgop" ]; then + cbfs "$tmprom" "$seavgabiosrom" vgaroms/seavgabios.bin raw + fi - [ "$payload_memtest" = "y" ] && cbfs "$tmprom" \ - "elf/memtest86plus/memtest.bin" img/memtest + if [ "$payload_memtest" = "y" ]; then + # because why not have memtest? - [ "$payload_grub" = "y" ] && add_grub + cbfs "$tmprom" "elf/memtest86plus/memtest.bin" img/memtest + fi - [ "$payload_grubsea" != "y" ] && cprom - [ "$payload_uboot_amd64" = "y" ] && [ "$displaymode" != "txtmode" ] && \ - [ "$initmode" != "normal" ] && [ "$payload_grubsea" != "y" ] && \ - pname="seauboot" && cprom "seauboot" - [ "$payload_grub" = "y" ] && pname="seagrub" && mkseagrub; : + if [ "$payload_grub" = "y" ]; then + add_grub + fi + + if [ "$payload_grubsea" != "y" ]; then + # ROM image where SeaBIOS doesn't load grub/u-boot first. + # U-Boot/GRUB available in ESC menu if enabled for the board + + cprom + fi + + # now make "SeaUBoot" and "SeaGRUB" images, where SeaBIOS auto-loads + # SeaBIOS or U-Boot first; users can bypass this by pressing ESC + # in the SeaBIOS menu, to boot devices using SeaBIOS itself instead + + if [ "$payload_uboot" = "amd64" ] && \ + [ "$displaymode" != "txtmode" ] && \ + [ "$initmode" != "normal" ] && [ "$payload_grubsea" != "y" ]; then + pname="seauboot" + cprom "seauboot" + fi + + if [ "$payload_grub" = "y" ]; then + pname="seagrub" + mkseagrub + fi } add_grub() { - _grubname="img/grub2" && [ "$payload_grubsea" = "y" ] && \ - _grubname="fallback/payload" + # path in CBFS for the GRUB payload + _grubname="img/grub2" + if [ "$payload_grubsea" = "y" ]; then + _grubname="fallback/payload" + fi + cbfs "$tmprom" "$grubelf" "$_grubname" + printf "set grub_scan_disk=\"%s\"\n" "$grub_scan_disk" \ - > "$xbmktmp/tmpcfg" || err "$target: !insert scandisk" - cbfs "$tmprom" "$xbmktmp/tmpcfg" scan.cfg raw - [ "$initmode" != "normal" ] && [ "$displaymode" != "txtmode" ] && \ - cbfs "$tmprom" "$grubdata/background/background1280x800.png" \ - "background.png" raw; : + > "$xbtmp/tmpcfg" || \ + err "$target: !insert scandisk" "add_grub" "$@" + + cbfs "$tmprom" "$xbtmp/tmpcfg" scan.cfg raw + + if [ "$initmode" != "normal" ] && [ "$displaymode" != "txtmode" ]; then + cbfs "$tmprom" "$grubdata/background/background1280x800.png" \ + "background.png" raw + fi } mkseagrub() { - [ "$payload_grubsea" = "y" ] && pname="grub" - [ "$payload_grubsea" = "y" ] || \ - cbfs "$tmprom" "$grubdata/bootorder" bootorder raw + if [ "$payload_grubsea" = "y" ]; then + pname="grub" + else + cbfs "$tmprom" "$grubdata/bootorder" bootorder raw + fi + fx_ cprom x_ find "$grubdata/keymap" -type f -name "*.gkb" } add_uboot() { if [ "$displaymode" = "txtmode" ]; then - printf "cb/%s: Cannot use U-Boot in text mode\n" \ - "$target" 1>&2 + printf "cb/%s: Can't use U-Boot in text mode\n" "$target" 1>&2 + return 0 elif [ "$initmode" = "normal" ]; then - printf "cb/%s: Cannot use U-Boot in normal initmode\n" \ + printf "cb/%s: Can't use U-Boot in normal initmode\n" \ "$target" 1>&2 + return 0 fi @@ -204,73 +401,114 @@ add_uboot() # aarch64 targets: ubcbfsargs="" ubpath="fallback/payload" + ubtree="default" ubtarget="$target" + # override for x86/x86_64 targets: - if [ "$payload_uboot_i386" = "y" ] || \ - [ "$payload_uboot_amd64" = "y" ]; then + if [ -n "$payload_uboot" ] && [ "$payload_uboot" != "arm64" ]; then ubcbfsargs="-l 0x1110000 -e 0x1110000" # 64-bit and 32-bit - # on 64-bit, 0x1120000 is the SPL, and stub before that + # on 64-bit, 0x1120000 is the SPL, with a stub that + # loads it, located at 0x1110000 + ubpath="img/u-boot" # 64-bit + ubtree="x86_64" ubtarget="amd64coreboot" - [ "$payload_uboot_i386" = "y" ] && ubpath="u-boot" # 32-bit - [ "$payload_uboot_i386" = "y" ] && ubtarget="i386coreboot"; : + + if [ "$payload_uboot" = "i386" ] + then + ubpath="u-boot" # 32-bit + ubtree="x86" + ubtarget="i386coreboot"; : + fi fi - ubdir="elf/u-boot/$ubtarget/$uboot_config" + ubdir="elf/u-boot/$ubtree/$ubtarget/$uboot_config" # aarch64 targets: - ubootelf="$ubdir/u-boot.elf" && [ ! -f "$ubootelf" ] && \ - ubootelf="$ubdir/u-boot" + ubootelf="$ubdir/u-boot.elf" + if [ ! -f "$ubootelf" ]; then + ubootelf="$ubdir/u-boot" + fi + # override for x86/x86_64 targets: - [ "$payload_uboot_i386" = "y" ] && ubootelf="$ubdir/u-boot-dtb.bin" - [ "$payload_uboot_amd64" = "y" ] && \ - ubootelf="$ubdir/u-boot-x86-with-spl.bin" # EFI-compatible + if [ "$payload_uboot" = "i386" ]; then + ubootelf="$ubdir/u-boot-dtb.bin" + elif [ "$payload_uboot" = "amd64" ]; then + ubootelf="$ubdir/u-boot-x86-with-spl.bin" # EFI-compatible + fi cbfs "$tmprom" "$ubootelf" "$ubpath" $ubcbfsargs - [ "$payload_seabios" = "y" ] || cprom; : + if [ "$payload_seabios" != "y" ]; then + cprom + fi } +# prepare the final image in bin/ for user installation: + cprom() { cpcmd="cp" - tmpnew=""; newrom="bin/$target/${pname}_${target}_$initmode.rom" - [ -n "$displaymode" ] && newrom="${newrom%.rom}_$displaymode.rom" - [ $# -gt 0 ] && [ "${1%.gkb}" != "$1" ] && tmpnew="${1##*/}" && \ - newrom="${newrom%.rom}_${tmpnew%.gkb}.rom" + tmpnew="" + newrom="bin/$target/${pname}_${target}_$initmode.rom" + + if [ -n "$displaymode" ]; then + newrom="${newrom%.rom}_$displaymode.rom" + fi + if [ $# -gt 0 ] && [ "${1%.gkb}" != "$1" ]; then + tmpnew="${1##*/}" + newrom="${newrom%.rom}_${tmpnew%.gkb}.rom" + fi irom="$tmprom" - [ $# -lt 1 ] || irom="`mktemp`" || err "!mk irom, $(echo "$@")" - [ $# -gt 0 ] && x_ cp "$tmprom" "$irom" && cpcmd="mv" - [ $# -gt 0 ] && [ "${1%.gkb}" != "$1" ] && \ - cbfs "$irom" "$grubdata/keymap/$tmpnew" keymap.gkb raw - [ $# -gt 0 ] && [ "$1" = "seauboot" ] && \ - cbfs "$irom" "$grubdata/bootorder_uboot" bootorder raw; : + if [ $# -gt 0 ]; then + irom="$(mktemp || err "!mk irom, $(echo "$@")")" || \ + err "can't copy rom" "cprom" "$@" + + x_ cp "$tmprom" "$irom" && cpcmd="mv" + + if [ "${1%.gkb}" != "$1" ]; then + cbfs "$irom" "$grubdata/keymap/$tmpnew" keymap.gkb raw + elif [ "$1" = "seauboot" ]; then + cbfs "$irom" "$grubdata/bootorder_uboot" bootorder raw + fi + fi printf "Creating new %s image: '%s'\n" "$projectname" "$newrom" - x_ mkdir -p "bin/$target" + + x_ xbmkdir "bin/$target" x_ $cpcmd "$irom" "$newrom" } cbfs() { - ccmd="add-payload" && [ $# -gt 3 ] && [ $# -lt 5 ] && ccmd="add" - lzma="-c lzma" && [ $# -gt 3 ] && [ $# -lt 5 ] && lzma="-t $4" - - [ $# -gt 4 ] && [ "$5" = "0x1110000" ] && \ - ccmd="add-flat-binary" && \ - lzma="-c lzma -l 0x1110000 -e 0x1110000" + ccmd="add-payload" + lzma="-c lzma" + + if [ $# -gt 3 ] && [ $# -lt 5 ]; then + ccmd="add" + lzma="-t $4" + elif [ $# -gt 4 ] && [ "$5" = "0x1110000" ]; then + ccmd="add-flat-binary" && \ + lzma="-c lzma -l 0x1110000 -e 0x1110000" + fi x_ "$cbfstool" "$1" $ccmd -f "$2" -n "$3" $lzma } +# for release files: + mkcoreboottar() { - [ "$target" = "$tree" ] && return 0 - [ "$XBMK_RELEASE" = "y" ] || return 0 - [ "$release" != "n" ] || return 0 + $if_dry_build \ + return 0 + + if [ "$target" = "$tree" ] || [ "$XBMK_RELEASE" != "y" ] || \ + [ "$release" = "n" ]; then + return 0 + fi - $dry mkrom_tarball "bin/$target" - $dry x_ ./mk inject "bin/${relname}_${target}.tar.xz" nuke; : + mkrom_tarball "bin/$target" + x_ ./mk inject "bin/${relname}_${target}.tar.xz" nuke } diff --git a/include/tree.sh b/include/tree.sh index d4585b92..2020c450 100644 --- a/include/tree.sh +++ b/include/tree.sh @@ -1,103 +1,207 @@ # SPDX-License-Identifier: GPL-3.0-or-later + # Copyright (c) 2022-2023 Alper Nebi Yasak <alpernebiyasak@gmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2023-2025 Leah Rowe <leah@libreboot.org> -eval "`setvars "" xarch srcdir premake gnatdir xlang mode makeargs elfdir cmd \ - project target target_dir targets xtree _f release bootstrapargs mkhelper \ - autoconfargs listfile autogenargs btype rev build_depend gccdir cmakedir \ - defconfig postmake mkhelpercfg dry dest_dir mdir cleanargs gccver gccfull \ - gnatver gnatfull do_make badhash tree`" +# flag e.g. ./mk -b <-- mkflag would be "b" +flag="" + +xarch="" +srcdir="" +premake="" +gnatdir="" +xlang="" +mode="" +makeargs="" +elfdir="" +cmd="" +project="" +target="" +target_dir="" +targets="" +xgcctree="" +release="" +bootstrapargs="" +mkhelper="" +autoconfargs="" +listfile="" +autogenargs="" +buildtype="" +rev="" +build_depend="" +gccdir="" +cmakedir="" +defconfig="" +postmake="" +mkhelpercfg="" +if_dry_build=":" +if_not_dry_build="" +dest_dir="" +mdir="" +cleanargs="" +gccver="" +gccfull="" +gnatver="" +gnatfull="" +do_make="" +badhash="" +badtghash="" +tree="" +forcepull="" trees() { - flags="f:b:m:u:c:x:s:l:n:d:" + flags="f:F:b:m:u:c:x:s:l:n:d:" + + while getopts $flags option + do + if [ -n "$flag" ]; then + err "only one flag is permitted" "trees" "$@" + fi - while getopts $flags option; do - [ -n "$_f" ] && err "only one flag is permitted" - _f="$1" + flag="$1" - case "$_f" in - -d) dry=":" ;; + # the "mode" variable is affixed to a make command, example: + # ./mk -m coreboot does: make menuconfig -C src/coreboot/tree + + case "$flag" in + -d) + # -d is similar to -b, except that + # a large number of operations will be + # skipped. these are "if_not_dry_build build" scenarios + # where only a subset of build tasks are done, + # and $if_not_dry_build is prefixed to skipped commands + + if_not_dry_build=":" + if_dry_build="" + ;; -b) : ;; -u) mode="oldconfig" ;; -m) mode="menuconfig" ;; -c) mode="distclean" ;; -x) mode="crossgcc-clean" ;; - -f) - do_make="n" - dry=":" ;; + -f) # download source code for a project + do_make="n" # lets us know not to build anything + if_not_dry_build=":" + if_dry_build="" + ;; + -F) # same as -F, but don't skip git fetch/pull on cache + do_make="n" # lets us know not to build anything + if_not_dry_build=":" + if_dry_build="" + forcepull="y" + ;; -s) mode="savedefconfig" ;; -l) mode="olddefconfig" ;; -n) mode="nconfig" ;; - *) err "invalid option '-$option'" ;; + *) err "invalid option '-$option'" "trees" "$@" ;; esac if [ -z "${OPTARG+x}" ]; then shift 1 + break fi project="${OPTARG#src/}" + project="${project#config/git/}" + shift 2 done - [ -z "$_f" ] && err "missing flag ($flags)" - if [ -z "$project" ]; then - mk $_f $(ls -1 config/git) + + if [ -z "$flag" ]; then + err "missing flag ($flags)" "trees" "$@" + elif [ -z "$project" ]; then + fx_ "x_ ./mk $flag" x_ ls -1 config/git + return 1 - fi - [ -f "config/git/$project/pkg.cfg" ] || \ - err "config/git/$project/pkg.cfg missing" + elif [ ! -f "config/git/$project/pkg.cfg" ]; then + err "config/git/$project/pkg.cfg missing" "trees" "$@" + fi - for d in "elf" "config/data" "config" "src"; do - eval "${d#*/}dir=\"$d/$project\"" - done + elfdir="elf/$project" + datadir="config/data/$project" + configdir="config/$project" + srcdir="src/$project" dest_dir="$elfdir" listfile="$datadir/build.list" - [ -f "$listfile" ] || listfile="" # optional on all projects + if [ ! -f "$listfile" ]; then + listfile="" # build.list is optional on all projects + fi mkhelpercfg="$datadir/mkhelper.cfg" if e "$mkhelpercfg" f missing; then - mkhelpercfg="$xbmktmp/mkhelper.cfg" + mkhelpercfg="$xbtmp/mkhelper.cfg" x_ touch "$mkhelpercfg" fi targets="$*" cmd="build_targets $targets" - singletree "$project" && cmd="build_project" + if singletree "$project"; then + cmd="build_project" + fi remkdir "${tmpgit%/*}" } build_project() { - configure_project "$configdir" || return 0 - [ ! -f "$listfile" ] || $dry elfcheck || return 0 + if ! configure_project "$configdir"; then + return 0 + elif [ -f "$listfile" ]; then + if ! $if_not_dry_build elfcheck; then + return 0 + fi + fi + + if [ "$mode" = "distclean" ]; then + mode="clean" + fi - [ "$mode" = "distclean" ] && mode="clean" - run_make_command || return 0 + if ! run_make_command; then + return 0 + fi - [ -n "$mode" ] || $dry copy_elf; : + if [ -z "$mode" ]; then + $if_not_dry_build \ + copy_elf; : + fi } build_targets() { - [ -d "$configdir" ] || err "directory, $configdir, does not exist" - [ $# -gt 0 ] || targets="$(ls -1 "$configdir")" || err "!o $configdir" + if [ ! -d "$configdir" ]; then + err "directory '$configdir' doesn't exist" "build_targets" "$@" + elif [ $# -lt 1 ]; then + targets="$(ls -1 "$configdir")" || \ + err "'$configdir': can't list targets" "build_targets" "$@" + fi - for x in $targets; do + for x in $targets + do unset CROSS_COMPILE export PATH="$xbmkpath" - [ "$x" = "list" ] && x_ ls -1 "config/$project" && \ - listfile="" && break + + if [ "$x" = "list" ]; then + x_ ls -1 "config/$project" + + listfile="" + + break + fi + + printf "'make %s', '%s', '%s'\n" "$mode" "$project" "$x" target="$x" - printf "'make %s', '%s', '%s'\n" "$mode" "$project" "$target" + x_ handle_defconfig - [ -n "$mode" ] || x_ $postmake + if [ -z "$mode" ]; then + x_ $postmake + fi done; : } @@ -105,156 +209,410 @@ handle_defconfig() { target_dir="$configdir/$target" - [ -f "CHANGELOG" ] || fetch_project "$project" - configure_project "$target_dir" || return 0 + if [ ! -f "CHANGELOG" ]; then + fetch_project "$project" + fi + if ! configure_project "$target_dir"; then + return 0 + fi + + if [ -z "$tree" ]; then + err "$configdir: 'tree' not set" "handle_defconfig" "$@" + fi - chkvars tree srcdir="src/$project/$tree" - [ "$mode" = "${mode%clean}" ] && [ ! -d "$srcdir" ] && return 0 + if [ "$mode" = "${mode%clean}" ] && [ ! -d "$srcdir" ]; then + return 0 + fi - [ -z "$mode" ] && for _xarch in $xarch; do - $dry check_cross_compiler "$_xarch" - done; : + for y in "$target_dir/config"/* + do + if [ "$flag" != "-d" ] && [ ! -f "$y" ]; then + continue + elif [ "$flag" != "-d" ]; then + defconfig="$y" + fi - for y in "$target_dir/config"/*; do - [ "$_f" = "-d" ] || [ -f "$y" ] || continue - [ "$_f" = "-d" ] || defconfig="$y" + if [ -z "$mode" ]; then + check_defconfig || continue; : + fi + + if [ -z "$mode" ]; then + for _xarch in $xarch; do + $if_dry_build \ + break + if [ -n "$_xarch" ]; then + check_cross_compiler "$_xarch" + fi + done; : + fi - [ -n "$mode" ] || check_defconfig || continue handle_makefile - [ -n "$mode" ] || $dry copy_elf + + if [ -z "$mode" ]; then + $if_not_dry_build \ + copy_elf + fi done; : } configure_project() { - eval "`setvars "" cleanargs build_depend autoconfargs xtree postmake \ - makeargs btype mkhelper bootstrapargs premake release xlang xarch \ - badhash`" + cleanargs="" + build_depend="" + autoconfargs="" + xgcctree="" + postmake="" + makeargs="" + buildtype="" + mkhelper="" + bootstrapargs="" + premake="" + release="" + xlang="" + xarch="" + badhash="" + badtghash="" + _tcfg="$1/target.cfg" - [ -f "$_tcfg" ] || btype="auto" - e "$datadir/mkhelper.cfg" f && eval "`setcfg "$datadir/mkhelper.cfg"`" - while e "$_tcfg" f || [ "$cmd" != "build_project" ]; do - eval "`setvars "" rev tree`" - eval "`setcfg "$_tcfg"`" + if [ ! -f "$_tcfg" ]; then + buildtype="auto" + fi + + # globally initialise all variables for a source tree / target: + + if e "$datadir/mkhelper.cfg" f; then + . "$datadir/mkhelper.cfg" || \ + err "Can't read '$datadir/mkhelper.cfg'" \ + "configure_project" "$@" + fi + + # override target/tree specific variables from per-target config: + + while e "$_tcfg" f || [ "$cmd" != "build_project" ] + do + # TODO: implement infinite loop detection here, caused + # by project targets pointing to other targets/trees + # when then ultimate point back repeatedly; this is + # currently avoided simply by careful configuration. + # temporary files per tree/target name could be created + # per iteration, and then checked the next time + printf "Loading %s config: %s\n" "$project" "$_tcfg" - [ "$_f" = "-d" ] && build_depend="" # dry run - [ "$cmd" = "build_project" ] && break - [ "$do_make" != "n" ] && break + rev="" + tree="" + + . "$_tcfg" || \ + err "Can't read '$_tcfg'" "configure_project" "$@" + + if [ "$flag" = "-d" ]; then + build_depend="" # dry run + fi + if [ "$cmd" = "build_project" ]; then + # single-tree, so it can't be a target pointing + # to a main source tree + + break + fi + if [ "$do_make" != "n" ]; then + # if we're *downloading* a project, then + # we don't need to to change the target.cfg + + break + fi + if [ "${_tcfg%/*/target.cfg}" = "${_tcfg%"/$tree/target.cfg"}" ] + then + # we have found the main source tree that + # a given target uses; no need to continue + + break + else + _tcfg="${_tcfg%/*/target.cfg}/$tree/target.cfg" + fi - [ "${_tcfg%/*/target.cfg}" = "${_tcfg%"/$tree/target.cfg"}" ] \ - && break - _tcfg="${_tcfg%/*/target.cfg}/$tree/target.cfg" done - [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ] && return 1 - [ -z "$btype" ] || [ "${mode%config}" = "$mode" ] || return 1 - [ -z "$mode" ] && $dry build_dependencies + + if [ "$XBMK_RELEASE" = "y" ] && [ "$release" = "n" ]; then + return 1 + fi + if [ -n "$buildtype" ] && [ "${mode%config}" != "$mode" ]; then + return 1 + fi + + if [ -z "$mode" ]; then + $if_not_dry_build \ + build_dependencies + fi mdir="$xbmkpwd/config/submodule/$project" - [ -n "$tree" ] && mdir="$mdir/$tree" - [ -f "CHANGELOG" ] || check_project_hashes + if [ -n "$tree" ]; then + mdir="$mdir/$tree" + fi + if [ ! -f "CHANGELOG" ]; then + delete_old_project_files + fi if [ "$do_make" = "n" ]; then - [ -f "CHANGELOG" ] || fetch_${cmd#build_} + if [ ! -f "CHANGELOG" ]; then + fetch_${cmd#build_} + fi + return 1 fi + x_ ./mk -f "$project" "$target" } +# projects can specify which other projects +# to build first, as declared dependencies: + build_dependencies() { - for bd in $build_depend; do - bd_p="${bd%%/*}" - bd_t="${bd##*/}" - [ -z "$bd_p" ] && $dry err "$project/$tree: !bd '$bd'" - [ "${bd##*/}" = "$bd" ] && bd_t="" - [ -z "$bd_p" ] || $dry x_ ./mk -b $bd_p $bd_t; : + for bd in $build_depend + do + bd_project="${bd%%/*}" + bd_tree="${bd##*/}" + + if [ -z "$bd_project" ]; then + $if_not_dry_build \ + err "$project/$tree: !bd '$bd'" \ + "build_dependencies" "$@" + fi + if [ "${bd##*/}" = "$bd" ]; then + bd_tree="" + fi + if [ -n "$bd_project" ]; then + $if_not_dry_build \ + x_ ./mk -b $bd_project $bd_tree; : + fi done; : } -check_project_hashes() +# delete_old_project_files along with project_up_to_date, +# concatenates the sha512sum hashes of all files related to +# a project, tree or target, then gets the sha512sum of that +# concatenation. this is checked against any existing +# calculation previously cached; if the result differs, or +# nothing was previously stored, we know to delete resources +# such as builds, project sources and so on, for auto-rebuild: + +delete_old_project_files() { - old_pjhash="" && x_ mkdir -p "$XBMK_CACHE/hash" - [ ! -f "$XBMK_CACHE/hash/$project$tree" ] || \ - read -r old_pjhash < "$XBMK_CACHE/hash/$project$tree" + # delete an entire source tree along with its builds: + if ! project_up_to_date hash "$tree" badhash "$datadir" \ + "$configdir/$tree" "$mdir"; then + x_ rm -Rf "src/$project/$tree" "elf/$project/$tree" + fi + + x_ cp "$xbtmp/new.hash" "$XBMK_CACHE/hash/$project$tree" + + if singletree "$project" || [ -z "$target" ] || [ "$target" = "$tree" ] + then + return 0 + fi + + # delete only the builds of a given target, but not src. + # this is useful when only the target config changes, for + # example x200_8mb coreboot configs change, but not coreboot: + + if ! project_up_to_date tghash "$target" badtghash "$configdir/$target" + then + x_ rm -Rf "elf/$project/$tree/$target" + fi + + x_ cp "$xbtmp/new.hash" "$XBMK_CACHE/tghash/$project$target" +} + +project_up_to_date() +{ + old_hash="" + hash="" + + hashdir="$1" + hashname="$2" + badhashvar="$3" + + shift 3 + + x_ xbmkdir "$XBMK_CACHE/$hashdir" + + if [ -f "$XBMK_CACHE/$hashdir/$project$hashname" ]; then + read -r old_hash < "$XBMK_CACHE/$hashdir/$project$hashname" \ + || err \ + "$hashdir: err '$XBMK_CACHE/$hashdir/$project$hashname'" \ + "project_up_to_date" "$hashdir" "$hashname" "$badhashvar" \ + "$@" + fi + + build_sbase + fx_ "x_ util/sbase/sha512sum" find "$@" -type f -not -path \ + "*/.git*/*" | awk '{print $1}' > "$xbtmp/tmp.hash" || \ + err "!h $project $hashdir" \ + "project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@" - fx_ "x_ sha512sum" find "$datadir" "$configdir/$tree" "$mdir" \ - -type f -not -path "*/.git*/*" | awk '{print $1}' > \ - "$xbmktmp/project.hash" || err "!h $project $tree" + hash="$(x_ "$sha512sum" "$xbtmp/tmp.hash" | awk '{print $1}' || \ + err)" || err "$hashname: Can't read sha512 of '$xbtmp/tmp.hash'" \ + "project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@" - pjhash="$(sha512sum "$xbmktmp/project.hash" | awk '{print $1}')" || : - [ "$pjhash" != "$old_pjhash" ] && badhash="y" - [ -f "$XBMK_CACHE/hash/$project$tree" ] || badhash="y" + if [ "$hash" != "$old_hash" ] || \ + [ ! -f "$XBMK_CACHE/$hashdir/$project$hashname" ]; then + eval "$badhashvar=\"y\"" + fi - printf "%s\n" "$pjhash" > "$XBMK_CACHE/hash/$project$tree" || \ - err "!mk $XBMK_CACHE/hash/$project$tree" + printf "%s\n" "$hash" > "$xbtmp/new.hash" || \ + err "!mkhash $xbtmp/new.hash ($hashdir $hashname $badhashvar)" \ + "project_up_to_date" "$hashdir" "$hashname" "$badhashvar" "$@" - [ "$badhash" != "y" ] || x_ rm -Rf "src/$project/$tree" \ - "elf/$project/$tree" "elf/$project/$target"; : + eval "[ \"\$$badhashvar\" = \"y\" ] && return 1"; : } check_cross_compiler() { cbdir="src/coreboot/$tree" - [ "$project" != "coreboot" ] && cbdir="src/coreboot/default" - [ -n "$xtree" ] && cbdir="src/coreboot/$xtree" + + if [ "$project" != "coreboot" ]; then + cbdir="src/coreboot/default" + fi + if [ -n "$xgcctree" ]; then + cbdir="src/coreboot/$xgcctree" + fi + + xfix="${1%-*}" + + if [ "$xfix" = "x86_64" ]; then + xfix="x64" + fi + + xgccfile="elf/coreboot/$tree/xgcc_${xfix}_was_compiled" + xgccargs="crossgcc-$xfix UPDATED_SUBMODULES=1 CPUS=$XBMK_THREADS" x_ ./mk -f coreboot "${cbdir#src/coreboot/}" + x_ xbmkdir "elf/coreboot/$tree" # TODO: is this needed? export PATH="$xbmkpwd/$cbdir/util/crossgcc/xgcc/bin:$PATH" export CROSS_COMPILE="${xarch% *}-" - [ -n "$xlang" ] && export BUILD_LANGUAGES="$xlang" - # match gnat-X to gcc - check_gnu_path gcc gnat || x_ check_gnu_path gnat gcc + if [ -n "$xlang" ]; then + export BUILD_LANGUAGES="$xlang" + fi - xfix="${1%-*}" && [ "$xfix" = "x86_64" ] && xfix="x64" - xgccargs="crossgcc-$xfix UPDATED_SUBMODULES=1 CPUS=$XBMK_THREADS" + if [ -f "$xgccfile" ]; then + # skip the build, because a build already exists: + + return 0 + fi + + check_gnu_path gcc gnat || x_ check_gnu_path gnat gcc make -C "$cbdir" $xgccargs || x_ make -C "$cbdir" $xgccargs - # we only want to mess with hostcc to build xgcc - remkdir "$XBMK_CACHE/gnupath" + # this tells subsequent runs that the build was already done: + x_ touch "$xgccfile" + + # reset hostcc in PATH: + remkdir "$xbtmp/gnupath" } # fix mismatching gcc/gnat versions on debian trixie/sid. as of december 2024, # trixie/sid had gnat-13 as gnat and gcc-14 as gcc, but has gnat-14 in apt. in # some cases, gcc 13+14 and gnat-13 are present; or gnat-14 and gcc-14, but # gnat in PATH never resolves to gnat-14, because gnat-14 was "experimental" + check_gnu_path() { - command -v "$1" 1>/dev/null || err "Host '$1' unavailable" + if ! command -v "$1" 1>/dev/null; then + err "Host '$1' unavailable" "check_gnu_path" "$@" + fi + + gccver="" + gccfull="" + gnatver="" + gnatfull="" + gccdir="" + gnatdir="" + + if host_gcc_gnat_match "$@"; then + return 0 + fi - eval "`setvars "" gccver gccfull gnatver gnatfull gccdir gnatdir`" - x_ gnu_setver "$1" "$1" || err "Command '$1' unavailable." + if ! match_gcc_gnat_versions "$@"; then + return 1 + fi +} + +# check if gcc/gnat versions already match: + +host_gcc_gnat_match() +{ + if ! gnu_setver "$1" "$1"; then + err "Command '$1' unavailable." "check_gnu_path" "$@" + fi gnu_setver "$2" "$2" || : eval "[ -z \"\$$1ver\" ] && err \"Cannot detect host '$1' version\"" - [ "$gnatfull" = "$gccfull" ] && return 0 + if [ "$gnatfull" != "$gccfull" ]; then + # non-matching gcc/gnat versions + + return 1 + fi +} + +# find all gcc/gnat versions, matching them up in PATH: + +match_gcc_gnat_versions() +{ eval "$1dir=\"$(dirname "$(command -v "$1")")\"" - eval "_gnudir=\"\$$1dir\"; _gnuver=\"\$$1ver\"" - for _bin in "$_gnudir/$2-"*; do - [ "${_bin#"$_gnudir/$2-"}" = "$_gnuver" ] && [ -x "$_bin" ] \ - && _gnuver="${_bin#"$_gnudir/$2-"}" && break; : + eval "_gnudir=\"\$$1dir\"" + eval "_gnuver=\"\$$1ver\"" + + for _bin in "$_gnudir/$2-"* + do + if [ "${_bin#"$_gnudir/$2-"}" = "$_gnuver" ] && [ -x "$_bin" ] + then + _gnuver="${_bin#"$_gnudir/$2-"}" + break + fi done - gnu_setver "$2" "$_gnudir/$2-$_gnuver" || return 1 - [ "$gnatfull" = "$gccfull" ] || return 1 - ( - remkdir "$XBMK_CACHE/gnupath" && x_ cd "$XBMK_CACHE/gnupath" - for _gnubin in "$_gnudir/$2"*"-$_gnuver"; do - _gnuutil="${_gnubin##*/}" && [ -e "$_gnubin" ] && \ - x_ ln -s "$_gnubin" "${_gnuutil%"-$_gnuver"}" + if ! gnu_setver "$2" "$_gnudir/$2-$_gnuver"; then + return 1 + elif [ "$gnatfull" != "$gccfull" ]; then + return 1 + fi + + ( link_gcc_gnat_versions "$@" "$_gnudir" "$_gnuver" ) || \ + err "Can't link '$2-$_gnuver' '$_gnudir'" "check_gnu_path" "$@"; : +} + +# create symlinks in PATH, so that the GCC/GNAT versions match: + +link_gcc_gnat_versions() +{ + _gnudir="$3" + _gnuver="$4" + + remkdir "$xbtmp/gnupath" + + x_ cd "$xbtmp/gnupath" + + for _gnubin in "$_gnudir/$2"*"-$_gnuver" + do + _gnuutil="${_gnubin##*/}" + if [ -e "$_gnubin" ]; then + x_ ln -s "$_gnubin" "${_gnuutil%"-$_gnuver"}" + fi done - ) || err "Cannot create $2-$_gnuver link in $_gnudir"; : } +# get the gcc/gnat version +# fail: return 1 if util not found gnu_setver() { eval "$2 --version 1>/dev/null 2>/dev/null || return 1" + eval "$1ver=\"`"$2" --version 2>/dev/null | head -n1`\"" eval "$1ver=\"\${$1ver##* }\"" eval "$1full=\"\$$1ver\"" @@ -263,79 +621,155 @@ gnu_setver() check_defconfig() { - [ -f "$defconfig" ] || $dry err "$project/$target: missing defconfig" - dest_dir="$elfdir/$target/${defconfig#"$target_dir/config/"}" + if [ ! -f "$defconfig" ]; then + $if_not_dry_build \ + err "$project/$target: no config" "check_defconfig" "$@" + fi + + dest_dir="$elfdir/$tree/$target/${defconfig#"$target_dir/config/"}" - $dry elfcheck || return 1; : # skip build if a previous one exists + # skip build if a previous one exists: + + $if_dry_build \ + return 0 + if ! elfcheck; then + return 1 + fi } elfcheck() { # TODO: *STILL* very hacky check. do it properly (based on build.list) - ( fx_ "exit 1" find "$dest_dir" -type f ) || return 1; : + + ( fx_ "eval exit 1 && err" find "$dest_dir" -type f ) || return 1; : } handle_makefile() { - $dry check_makefile "$srcdir" && x_ make -C "$srcdir" $cleanargs clean + if $if_not_dry_build check_makefile "$srcdir"; then + $if_not_dry_build \ + x_ make -C "$srcdir" $cleanargs clean + fi + + if [ -f "$defconfig" ]; then + x_ cp "$defconfig" "$srcdir/.config" + fi - [ -f "$defconfig" ] && x_ cp "$defconfig" "$srcdir/.config" - [ -n "$mode" ] || [ -n "$btype" ] || $dry make -C \ - "$srcdir" silentoldconfig || make -C "$srcdir" oldconfig || : + run_make_command || \ + err "no makefile!" "handle_makefile" "$@" - run_make_command || err "handle_makefile $srcdir: no makefile!" + _copy=".config" - _copy=".config" && [ "$mode" = "savedefconfig" ] && _copy="defconfig" - [ "${mode%config}" = "$mode" ] || \ - $dry x_ cp "$srcdir/$_copy" "$defconfig" + if [ "$mode" = "savedefconfig" ]; then + _copy="defconfig" + fi - [ -e "$srcdir/.git" ] && [ "$project" = "u-boot" ] && \ - [ "$mode" = "distclean" ] && \ - $dry x_ git -C "$srcdir" $cleanargs clean -fdx; : + if [ "${mode%config}" != "$mode" ]; then + $if_not_dry_build \ + x_ cp "$srcdir/$_copy" "$defconfig"; : + fi + + if [ -e "$srcdir/.git" ] && [ "$project" = "u-boot" ] && \ + [ "$mode" = "distclean" ]; then + $if_not_dry_build \ + x_ git -C "$srcdir" $cleanargs clean -fdx; : + fi } run_make_command() { - [ -n "$mode" ] || x_ $premake + if [ -z "$mode" ]; then + x_ $premake + fi + + if $if_not_dry_build check_cmake "$srcdir"; then + if [ -z "$mode" ]; then + $if_not_dry_build \ + check_autoconf "$srcdir" + fi + fi + if ! $if_not_dry_build check_makefile "$srcdir"; then + return 1 + fi - $dry check_cmake "$srcdir" && [ -z "$mode" ] && \ - $dry check_autoconf "$srcdir" - $dry check_makefile "$srcdir" || return 1 + $if_not_dry_build \ + x_ make -C "$srcdir" $mode -j$XBMK_THREADS $makeargs - $dry x_ make -C "$srcdir" $mode -j$XBMK_THREADS $makeargs - [ -n "$mode" ] || x_ $mkhelper + if [ -z "$mode" ]; then + x_ $mkhelper + fi + + if ! check_makefile "$srcdir"; then + return 0 + fi - [ "$mode" != "clean" ] || \ - $dry make -C "$srcdir" $cleanargs distclean || :; : + if [ "$mode" = "clean" ]; then + $if_dry_build \ + return 0 + if ! make -C "$srcdir" $cleanargs distclean; then + x_ make -C "$srcdir" $cleanargs clean + fi + fi } check_cmake() { - [ -z "$cmakedir" ] || $dry check_makefile "$1" || cmake -B "$1" \ - "$1/$cmakedir" || $dry x_ check_makefile "$1" - [ -z "$cmakedir" ] || $dry x_ check_makefile "$1"; : + $if_dry_build \ + return 0 + if [ ! -n "$cmakedir" ]; then + return 0 + elif ! check_makefile "$1"; then + if ! cmake -B "$1" "$1/$cmakedir"; then + x_ check_makefile "$1" + fi + fi + x_ check_makefile "$1"; : } check_autoconf() { ( - x_ cd "$1" - [ -f "bootstrap" ] && x_ ./bootstrap $bootstrapargs - [ -f "autogen.sh" ] && x_ ./autogen.sh $autogenargs - [ -f "configure" ] && x_ ./configure $autoconfargs; : - ) || err "can't bootstrap project: $1"; : + x_ cd "$1" + + if [ -f "bootstrap" ]; then + x_ ./bootstrap $bootstrapargs + fi + if [ -f "autogen.sh" ]; then + x_ ./autogen.sh $autogenargs + fi + if [ -f "configure" ]; then + x_ ./configure $autoconfargs; : + fi + + ) || err "can't bootstrap project: $1" "check_autoconf" "$@"; : } check_makefile() { - [ -f "$1/Makefile" ] || [ -f "$1/makefile" ] || \ - [ -f "$1/GNUmakefile" ] || return 1; : + if [ ! -f "$1/Makefile" ] && [ ! -f "$1/makefile" ] && \ + [ ! -f "$1/GNUmakefile" ]; then + + return 1 + fi } copy_elf() { - [ -f "$listfile" ] && x_ mkdir -p "$dest_dir" && while read -r f; do - [ -f "$srcdir/$f" ] && x_ cp "$srcdir/$f" "$dest_dir" - done < "$listfile" - x_ make clean -C "$srcdir" $cleanargs + if [ -f "$listfile" ]; then + x_ xbmkdir "$dest_dir" + fi + + if [ -f "$listfile" ]; then + while read -r f + do + if [ -f "$srcdir/$f" ]; then + x_ cp "$srcdir/$f" "$dest_dir" + fi + + done < "$listfile" || err \ + "cannot read '$listfile'" "copy_elf" "$@"; : + fi + + ( x_ make clean -C "$srcdir" $cleanargs ) || \ + err "can't make-clean '$srcdir'" "copy_elf" "$@"; : } diff --git a/include/vendor.sh b/include/vendor.sh index 89e352a7..761f9250 100644 --- a/include/vendor.sh +++ b/include/vendor.sh @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-3.0-only + # Copyright (c) 2022 Caleb La Grange <thonkpeasant@protonmail.com> # Copyright (c) 2022 Ferass El Hafidi <vitali64pmemail@protonmail.com> # Copyright (c) 2023-2025 Leah Rowe <leah@libreboot.org> @@ -16,60 +17,142 @@ e6400_unpack="$xbmkpwd/src/bios_extract/dell_inspiron_1100_unpacker.py" me7updateparser="$xbmkpwd/util/me7_update_parser/me7_update_parser.py" pfs_extract="$xbmkpwd/src/biosutilities/Dell_PFS_Extract.py" uefiextract="$xbmkpwd/elf/uefitool/uefiextract" +bsdtar="$xbmkpwd/elf/libarchive/bsdtar" +bsdunzip="$xbmkpwd/elf/libarchive/bsdunzip" vendir="vendorfiles" appdir="$vendir/app" vfix="DO_NOT_FLASH_YET._FIRST,_INJECT_FILES_VIA_INSTRUCTIONS_ON_LIBREBOOT.ORG_" -# lbmk-specific extension to the "cv" variable (not suitable for cbmk) -cvchk="CONFIG_INCLUDE_SMSC_SCH5545_EC_FW CONFIG_HAVE_MRC CONFIG_HAVE_ME_BIN \ - CONFIG_KBC1126_FIRMWARE CONFIG_LENOVO_TBFW_BIN CONFIG_VGA_BIOS_FILE \ - CONFIG_FSP_M_FILE CONFIG_FSP_S_FILE" - -# lbmk-specific extensions to the "cv" variable (not suitable for cbmk) -cvxbmk="CONFIG_ME_BIN_PATH CONFIG_SMSC_SCH5545_EC_FW_FILE CONFIG_KBC1126_FW1 \ - CONFIG_KBC1126_FW2 CONFIG_KBC1126_FW1_OFFSET CONFIG_KBC1126_FW2_OFFSET \ - CONFIG_VGA_BIOS_ID CONFIG_BOARD_DELL_E6400 CONFIG_FSP_S_CBFS \ - CONFIG_HAVE_REFCODE_BLOB CONFIG_REFCODE_BLOB_FILE CONFIG_FSP_FD_PATH \ - CONFIG_IFD_BIN_PATH CONFIG_MRC_FILE CONFIG_FSP_M_CBFS \ - CONFIG_FSP_USE_REPO CONFIG_FSP_FULL_FD" - -# lbmk-specific extensions; mostly used for downloading vendor files -eval "`setvars "" has_hashes EC_hash DL_hash DL_url_bkup MRC_refcode_gbe vcfg \ - E6400_VGA_DL_hash E6400_VGA_DL_url E6400_VGA_DL_url_bkup E6400_VGA_offset \ - E6400_VGA_romname SCH5545EC_DL_url_bkup SCH5545EC_DL_hash _dest mecleaner \ - kbc1126_ec_dump MRC_refcode_cbtree _dl SCH5545EC_DL_url EC_url rom DL_url \ - nukemode cbfstoolref FSPFD_hash _7ztest ME11bootguard ME11delta xromsize \ - ME11version ME11sku ME11pch _me _metmp mfs TBFW_url_bkup TBFW_url vfile \ - TBFW_hash TBFW_size hashfile xchanged EC_url_bkup cbdir`" +# lbmk-specific extension to the "checkvars" variable (not suitable for cbmk) +checkvarschk="CONFIG_INCLUDE_SMSC_SCH5545_EC_FW CONFIG_HAVE_MRC \ + CONFIG_HAVE_ME_BIN CONFIG_LENOVO_TBFW_BIN CONFIG_VGA_BIOS_FILE \ + CONFIG_FSP_M_FILE CONFIG_FSP_S_FILE CONFIG_KBC1126_FW1 CONFIG_KBC1126_FW2" + +# lbmk-specific extensions to the "checkvars" variable (not suitable for cbmk) +checkvarsxbmk="CONFIG_ME_BIN_PATH CONFIG_SMSC_SCH5545_EC_FW_FILE \ + CONFIG_FSP_FULL_FD CONFIG_KBC1126_FW1_OFFSET CONFIG_KBC1126_FW2_OFFSET \ + CONFIG_FSP_USE_REPO CONFIG_VGA_BIOS_ID CONFIG_BOARD_DELL_E6400 \ + CONFIG_FSP_S_CBFS CONFIG_HAVE_REFCODE_BLOB CONFIG_REFCODE_BLOB_FILE \ + CONFIG_FSP_FD_PATH CONFIG_IFD_BIN_PATH CONFIG_MRC_FILE CONFIG_FSP_M_CBFS" + +# lbmk-specific extensions; general variables +_dest="" +has_hashes="" +vcfg="" +mecleaner="" +kbc1126_ec_dump="" +_dl="" +rom="" +nuke="" +_7ztest="" +cbfstoolref="" +_me="" +_metmp="" +mfs="" +cbdir="" +hashfile="" +_dl_bin="" +_pre_dest="" +xromsize="" + +# lbmk-specific extensions; declared in pkg.cfg files in config/vendor/ +EC_hash="" +DL_hash="" +DL_url_bkup="" +MRC_refcode_gbe="" +E6400_VGA_DL_hash="" +E6400_VGA_DL_url="" +E6400_VGA_DL_url_bkup="" +E6400_VGA_offset="" +E6400_VGA_romname="" +SCH5545EC_DL_url_bkup="" +SCH5545EC_DL_hash="" +MRC_refcode_cbtree="" +SCH5545EC_DL_url="" +EC_url="" +DL_url="" +FSPFD_hash="" +ME11bootguard="" +ME11delta="" +ME11version="" +ME11sku="" +ME11pch="" +TBFW_url_bkup="" +TBFW_url="" +TBFW_hash="" +TBFW_size="" +EC_url_bkup="" +FSPM_bin_hash="" +FSPS_bin_hash="" +EC_FW1_hash="" +EC_FW2_hash="" +ME_bin_hash="" +MRC_bin_hash="" +REF_bin_hash="" +SCH5545EC_bin_hash="" +TBFW_bin_hash="" +E6400_VGA_bin_hash="" +XBMKmecleaner="" +MEclean="" download() { - [ $# -gt 0 ] || err "No argument given" + if [ $# -lt 1 ]; then + err "No argument given" "download" "$@" + fi + export PATH="$PATH:/sbin" - board="$1" && check_target && readkconfig download + board="$1" + + if check_target; then + readkconfig download + fi } getfiles() { - [ -z "$CONFIG_HAVE_ME_BIN" ] || fetch intel_me "$DL_url" \ - "$DL_url_bkup" "$DL_hash" "$CONFIG_ME_BIN_PATH" - [ -z "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" ] || fetch sch5545ec \ - "$SCH5545EC_DL_url" "$SCH5545EC_DL_url_bkup" "$SCH5545EC_DL_hash" \ - "$CONFIG_SMSC_SCH5545_EC_FW_FILE" - [ -z "$CONFIG_KBC1126_FIRMWARE" ] || fetch kbc1126ec "$EC_url" \ - "$EC_url_bkup" "$EC_hash" "$CONFIG_KBC1126_FW1" - [ -z "$CONFIG_VGA_BIOS_FILE" ] || fetch e6400vga "$E6400_VGA_DL_url" \ - "$E6400_VGA_DL_url_bkup" "$E6400_VGA_DL_hash" "$CONFIG_VGA_BIOS_FILE" - [ -z "$CONFIG_HAVE_MRC" ] || fetch "mrc" "$MRC_url" "$MRC_url_bkup" \ - "$MRC_hash" "$CONFIG_MRC_FILE" - [ -n "$CONFIG_REFCODE_BLOB_FILE" ] && fetch "refcode" "$MRC_url" \ - "$MRC_url_bkup" "$MRC_hash" "$CONFIG_REFCODE_BLOB_FILE" - [ -z "$CONFIG_LENOVO_TBFW_BIN" ] || fetch "tbfw" "$TBFW_url" \ - "$TBFW_url_bkup" "$TBFW_hash" "$CONFIG_LENOVO_TBFW_BIN" - [ -z "$CONFIG_FSP_M_FILE" ] || fetch "fsp" "$CONFIG_FSP_FD_PATH" \ - "$CONFIG_FSP_FD_PATH" "$FSPFD_hash" "$CONFIG_FSP_M_FILE" copy - [ -z "$CONFIG_FSP_S_FILE" ] || fetch "fsp" "$CONFIG_FSP_FD_PATH" \ - "$CONFIG_FSP_FD_PATH" "$FSPFD_hash" "$CONFIG_FSP_S_FILE" copy; : + if [ -n "$CONFIG_HAVE_ME_BIN" ];then + fetch intel_me "$DL_url" "$DL_url_bkup" "$DL_hash" \ + "$CONFIG_ME_BIN_PATH" curl "$ME_bin_hash" + fi + if [ -n "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" ]; then + fetch sch5545ec "$SCH5545EC_DL_url" "$SCH5545EC_DL_url_bkup" \ + "$SCH5545EC_DL_hash" "$CONFIG_SMSC_SCH5545_EC_FW_FILE" \ + "curl" "$SCH5545EC_bin_hash" + fi + if [ -n "$CONFIG_KBC1126_FW1" ]; then + fetch kbc1126ec "$EC_url" "$EC_url_bkup" "$EC_hash" \ + "$CONFIG_KBC1126_FW1" curl "$EC_FW1_hash" + fi + if [ -n "$CONFIG_KBC1126_FW2" ]; then + fetch kbc1126ec "$EC_url" "$EC_url_bkup" "$EC_hash" \ + "$CONFIG_KBC1126_FW2" curl "$EC_FW2_hash" + fi + if [ -n "$CONFIG_VGA_BIOS_FILE" ]; then + fetch e6400vga "$E6400_VGA_DL_url" "$E6400_VGA_DL_url_bkup" \ + "$E6400_VGA_DL_hash" "$CONFIG_VGA_BIOS_FILE" "curl" \ + "$E6400_VGA_bin_hash" + fi + if [ -n "$CONFIG_HAVE_MRC" ]; then + fetch "mrc" "$MRC_url" "$MRC_url_bkup" "$MRC_hash" \ + "$CONFIG_MRC_FILE" "curl" "$MRC_bin_hash" + fi + if [ -n "$CONFIG_REFCODE_BLOB_FILE" ]; then + fetch "refcode" "$MRC_url" "$MRC_url_bkup" "$MRC_hash" \ + "$CONFIG_REFCODE_BLOB_FILE" "curl" "$REF_bin_hash" + fi + if [ -n "$CONFIG_LENOVO_TBFW_BIN" ]; then + fetch "tbfw" "$TBFW_url" "$TBFW_url_bkup" "$TBFW_hash" \ + "$CONFIG_LENOVO_TBFW_BIN" "curl" "$TBFW_bin_hash" + fi + if [ -n "$CONFIG_FSP_M_FILE" ]; then + fetch "fsp" "$CONFIG_FSP_FD_PATH" "$CONFIG_FSP_FD_PATH" \ + "$FSPFD_hash" "$CONFIG_FSP_M_FILE" "copy" "$FSPM_bin_hash" + fi + if [ -n "$CONFIG_FSP_S_FILE" ]; then + fetch "fsp" "$CONFIG_FSP_FD_PATH" "$CONFIG_FSP_FD_PATH" \ + "$FSPFD_hash" "$CONFIG_FSP_S_FILE" "copy" "$FSPS_bin_hash" + fi } fetch() @@ -79,184 +162,402 @@ fetch() dl_bkup="$3" dlsum="$4" _dest="${5##*../}" + _pre_dest="$XBMK_CACHE/tmpdl/check" + dlop="$6" + binsum="$7" + + if [ -z "$binsum" ]; then + err "binsum is empty (no checksum)" "fetch" "$@" + fi + + _dl="$XBMK_CACHE/file/$dlsum" # internet file to extract from e.g. .exe + _dl_bin="$XBMK_CACHE/file/$binsum" # extracted file e.g. me.bin + + if [ "$5" = "/dev/null" ]; then + return 0 + fi + + # an extracted vendor file will be placed in pre_dest first, for + # verifying its checksum. if it matches, it is later moved to _dest + remkdir "${_pre_dest%/*}" "$appdir" - [ "$5" = "/dev/null" ] && return 0 - _dl="$XBMK_CACHE/file/$dlsum" # HACK: if grabbing fsp from coreboot, fix the path for lbmk - [ "$dl_type" = "fsp" ] && for _cdl in dl dl_bkup; do - eval "$_cdl=\"\${$_cdl##*../}\"; _cdp=\"\$$_cdl\"" - [ -f "$_cdp" ] || _cdp="$cbdir/$_cdp" - [ -f "$_cdp" ] && eval "$_cdl=\"$_cdp\"" - done; : + if [ "$dl_type" = "fsp" ] + then + dl="${dl##*../}" + _cdp="$dl" + + if [ ! -f "$_cdp" ]; then + _cdp="$cbdir/$_cdp" + fi + if [ -f "$_cdp" ]; then + dl="$_cdp" + fi + + dl_bkup="${dl_bkup##*../}" + _cdp="$dl_bkup" + + if [ ! -f "$_cdp" ]; then + _cdp="$cbdir/$_cdp" + fi + if [ -f "$_cdp" ]; then + dl_bkup="$_cdp"; : + fi + fi - dlop="curl" && [ $# -gt 5 ] && dlop="$6" - xbmkget "$dl" "$dl_bkup" "$_dl" "$dlsum" "$dlop" + # download the file (from the internet) to extract from: + xbget "$dlop" "$dl" "$dl_bkup" "$_dl" "$dlsum" x_ rm -Rf "${_dl}_extracted" - e "$_dest" f && return 0 - x_ mkdir -p "${_dest%/*}" - remkdir "$appdir" - [ "$dl_type" = "fsp" ] || extract_archive "$_dl" "$appdir" || \ - [ "$dl_type" = "e6400vga" ] || err "$_dest $dl_type: !extract" + # skip extraction if a cached extracted file exists: + + ( xbget copy "$_dl_bin" "$_dl_bin" "$_dest" "$binsum" 2>/dev/null ) || : + if [ -f "$_dest" ]; then + return 0 + fi + + x_ xbmkdir "${_dest%/*}" + + if [ "$dl_type" != "fsp" ]; then + extract_archive "$_dl" "$appdir" || \ + [ "$dl_type" = "e6400vga" ] || \ + err "$_dest $dl_type: !extract" "fetch" "$@" + fi x_ extract_$dl_type "$_dl" "$appdir" set -u -e - e "$_dest" f missing && err "!extract_$dl_type"; : + + # some functions don't output directly to the given file, _pre_dest. + # instead, they put multiple files there, but we need the one matching + # the given hashsum. So, search for a matching file via bruteforce: + ( fx_ "mkdst $binsum" x_ find "${_pre_dest%/*}" -type f ) || : + + if ! bad_checksum "$binsum" "$_dest"; then + if [ -f "$_dest" ]; then + return 0 + fi + fi + + if [ -z "$binsum" ]; then + printf "'%s': checksum undefined\n" "$_dest" 1>&2 + fi + + if [ -L "$_dest" ]; then + printf "WARNING: '%s' is a link!\n" "$_dest" 1>&2 + else + x_ rm -f "$_dest" + fi + + err "Can't safely extract '$_dest', for board '$board'" "fetch" "$@" +} + +mkdst() +{ + if bad_checksum "$1" "$2" 2>/dev/null; then + x_ rm -f "$2" + else + x_ mv "$2" "$_dl_bin" + x_ cp "$_dl_bin" "$_dest" + + exit 1 + fi } extract_intel_me() { - e "$mecleaner" f not && err "$cbdir: me_cleaner missing" + if e "$mecleaner" f missing; then + err "$cbdir: me_cleaner missing" "extract_intel_me" "$@" + fi + + mfs="" + _7ztest="$xbtmp/metmp/a" + _metmp="$xbtmp/me.bin" - _7ztest="$xbmklocal/metmp/a" - _me="$xbmkpwd/$_dest" - _metmp="$xbmklocal/me.bin" - x_ rm -f "$_metmp" "$xbmklocal/a" + x_ rm -f "$_metmp" "$xbtmp/a" + x_ rm -Rf "$_7ztest" - mfs="" && [ "$ME11bootguard" = "y" ] && mfs="--whitelist MFS" && \ - chkvars ME11delta ME11version ME11sku ME11pch - [ "$ME11bootguard" = "y" ] && x_ ./mk -f deguard + if [ "$ME11bootguard" = "y" ]; then + mfs="--whitelist MFS" + + if [ -z "$ME11delta" ] || [ -z "$ME11version" ] || \ + [ -z "$ME11sku" ] || [ -z "$ME11pch" ]; then + err "$board: ME11delta/ME11version/ME11sku/ME11pch" \ + "extract_intel_me" "$@" + fi + + x_ ./mk -f deguard + fi set +u +e - x_ rm -Rf "$xbmkpwd/metmp" - ( fx_ find_me x_ find "$xbmkpwd/$appdir" -type f ) || : - [ "$ME11bootguard" != "y" ] && x_ mv "$_metmp" "$_me" && return 0 - ( - x_ cd src/deguard/ - x_ ./finalimage.py --delta "data/delta/$ME11delta" --version \ - "$ME11version" --pch "$ME11pch" --sku "$ME11sku" \ - --fake-fpfs data/fpfs/zero --input "$_metmp" --output "$_me" - ) || err "Error running deguard for $_me"; : + ( fx_ find_me x_ find "$xbmkpwd/$appdir" -type f ) || :; : + + set -u -e + + if [ "$ME11bootguard" != "y" ]; then + x_ mv "$_metmp" "$_pre_dest" + else + ( apply_deguard_hack ) || \ + err "deguard error on '$_dest'" "extract_intel_me" "$@"; : + fi } +# bruteforce Intel ME extraction. +# must be called inside a subshell. find_me() { - [ -f "$_metmp" ] && exit 1 - [ -L "$1" ] && return 0 + if [ -f "$_metmp" ]; then + # we found me.bin, so we stop searching + + exit 1 + elif [ -L "$1" ]; then + return 0 + fi + + _7ztest="${_7ztest}a" + _r="-r" # re-locate modules + _trunc="-t" # -t: truncate the ME size + _keep="" # -k: keep fptr modules even if they can be removed + _pass="" # -p: skip fptr check + + if [ -n "$mfs" ] || [ "$MEclean" = "n" ]; then + _r="" + fi - _7ztest="${_7ztest}a" && _r="-r" && [ -n "$mfs" ] && _r="" + if [ "$MEclean" = "n" ]; then + _keep="-k" + _trunc="" + _pass="-p" + fi + + if "$mecleaner" $mfs $_r $_keep $_pass $_trunc -O "$xbtmp/a" \ + -M "$_metmp" "$1" || [ -f "$_metmp" ]; then + # me.bin extracted from a full image with ifd, then shrunk + : + elif "$mecleaner" $mfs $_r $_pass $_keep $_trunc -O "$_metmp" "$1" || \ + [ -f "$_metmp" ]; then + # me.bin image already present, and we shrunk it + : + elif "$me7updateparser" $_keep -O "$_metmp" "$1"; then + # thinkpad sandybridge me.bin image e.g. x220/t420 + : + elif extract_archive "$1" "$_7ztest"; then + # scan newly extracted archive within extracted archive + : + else + # could not extract anything, so we'll try the next file + return 0 + fi + + if [ -f "$_metmp" ]; then + # we found me.bin, so we stop searching - "$mecleaner" $mfs $_r -t -O "$xbmklocal/a" -M "$_metmp" "$1" || \ - "$mecleaner" $mfs $_r -t -O "$_metmp" "$1" || "$me7updateparser" \ - -O "$_metmp" "$1" || extract_archive "$1" "$_7ztest" || return 0 + exit 1 + else + # if the subshell does exit 1, we found me.bin, so exit 1 + ( fx_ find_me x_ find "$_7ztest" -type f ) || exit 1; : + fi +} + +apply_deguard_hack() +{ + x_ cd src/deguard - [ -f "$_metmp" ] && exit 1 - ( fx_ find_me x_ find "$_7ztest" -type f ) || exit 1; : + x_ ./finalimage.py --delta "data/delta/$ME11delta" \ + --version "$ME11version" --pch "$ME11pch" --sku "$ME11sku" \ + --fake-fpfs data/fpfs/zero --input "$_metmp" --output "$_pre_dest" } extract_archive() { - innoextract "$1" -d "$2" || python "$pfs_extract" "$1" -e || 7z x \ - "$1" -o"$2" || unar "$1" -o "$2" || unzip "$1" -d "$2" || return 1 + if innoextract "$1" -d "$2"; then + : + elif python "$pfs_extract" "$1" -e; then + : + elif 7z x "$1" -o"$2"; then + : + elif "$bsdtar" -C "$2" -xf "$1"; then + : + elif "$bsdunzip" "$1" -d "$2"; then + : + else + return 1 + fi - [ ! -d "${_dl}_extracted" ] || x_ cp -R "${_dl}_extracted" "$2"; : + if [ -d "${_dl}_extracted" ]; then + x_ cp -R "${_dl}_extracted" "$2" + fi } extract_kbc1126ec() { - ( + ( extract_kbc1126ec_dump ) || \ + err "$board: can't extract kbc1126 fw" "extract_kbc1126ec" "$@" + + # throw error if either file is missing + x_ e "$appdir/ec.bin.fw1" f + x_ e "$appdir/ec.bin.fw2" f + + x_ cp "$appdir/"ec.bin.fw* "${_pre_dest%/*}/" +} + +extract_kbc1126ec_dump() +{ x_ cd "$appdir/" - mv Rompaq/68*.BIN ec.bin || unar -D ROM.CAB Rom.bin || unar -D \ - Rom.CAB Rom.bin || unar -D 68*.CAB Rom.bin || err "!kbc1126 unar" - [ -f "ec.bin" ] || x_ mv Rom.bin ec.bin - x_ e ec.bin f && x_ "$kbc1126_ec_dump" ec.bin - ) || err "$board: can't extract kbc1126 ec firmware" - - x_ e "$appdir/ec.bin.fw1" f && x_ e "$appdir/ec.bin.fw2" f - x_ cp "$appdir/"ec.bin.fw* "${_dest%/*}/" + + if mv Rompaq/68*.BIN ec.bin; then + : + elif unar -D ROM.CAB Rom.bin; then + : + elif unar -D Rom.CAB Rom.bin; then + : + elif unar -D 68*.CAB Rom.bin; then + : + else + err "!kbc1126 unar" "extract_kbc1126ec" "$@" + fi + + if [ ! -f "ec.bin" ]; then + x_ mv Rom.bin ec.bin + fi + + if x_ e ec.bin f; then + x_ "$kbc1126_ec_dump" ec.bin + fi } extract_e6400vga() { set +u +e - chkvars E6400_VGA_offset E6400_VGA_romname + + if [ -z "$E6400_VGA_offset" ] || [ -z "$E6400_VGA_romname" ]; then + err "$board: E6400_VGA_romname/E6400_VGA_offset unset" \ + "extract_e6400vga" "$@" + fi + tail -c +$E6400_VGA_offset "$_dl" | gunzip > "$appdir/bios.bin" || : + ( x_ cd "$appdir" x_ e "bios.bin" f "$e6400_unpack" bios.bin || printf "TODO: fix dell extract util\n" - ) || err "can't extract e6400 vga rom" - x_ cp "$appdir/$E6400_VGA_romname" "$_dest" + ) || err "can't extract e6400 vga rom" "extract_e6400vga" "$@" + + x_ cp "$appdir/$E6400_VGA_romname" "$_pre_dest" } extract_sch5545ec() { # full system ROM (UEFI), to extract with UEFIExtract: _bios="${_dl}_extracted/Firmware/1 $dlsum -- 1 System BIOS vA.28.bin" + # this is the SCH5545 firmware, inside of the extracted UEFI ROM: _sch5545ec_fw="$_bios.dump/4 7A9354D9-0468-444A-81CE-0BF617D890DF" _sch5545ec_fw="$_sch5545ec_fw/54 D386BEB8-4B54-4E69-94F5-06091F67E0D3" _sch5545ec_fw="$_sch5545ec_fw/0 Raw section/body.bin" # <-- this! x_ "$uefiextract" "$_bios" - x_ cp "$_sch5545ec_fw" "$_dest" + x_ cp "$_sch5545ec_fw" "$_pre_dest" } # Lenovo ThunderBolt firmware updates: # https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-t-series-laptops/thinkpad-t480-type-20l5-20l6/20l5/solutions/ht508988 extract_tbfw() { - chkvars TBFW_size; fx_ copytb x_ find "$appdir" -type f -name "TBT.bin" + if [ -z "$TBFW_size" ]; then + err "$board: TBFW_size unset" "extract_tbfw" "$@" + fi + + fx_ copytb x_ find "$appdir" -type f -name "TBT.bin" } copytb() { - [ -f "$1" ] && [ ! -L "$1" ] && x_ dd if=/dev/null of="$1" bs=1 \ - seek=$TBFW_size && x_ mv "$1" "$_dest" && return 1; : + if [ -f "$1" ] && [ ! -L "$1" ]; then + x_ dd if=/dev/null of="$1" bs=1 seek=$TBFW_size + x_ mv "$1" "$_pre_dest" + + return 1 + fi } extract_fsp() { x_ python "$cbdir/3rdparty/fsp/Tools/SplitFspBin.py" split -f "$1" \ - -o "${_dest%/*}" -n "Fsp.fd" + -o "${_pre_dest%/*}" -n "Fsp.fd" } setvfile() { - [ -n "$vcfg" ] && check_vcfg && for c in $cvchk; do - eval "[ \"\${$c}\" = \"/dev/null\" ] && continue" - eval "[ -z \"\${$c}\" ] && continue" - getvfile "$@" && return 0 + [ -n "$vcfg" ] && for c in $checkvarschk + do + do_getvfile="n" + vcmd="[ \"\${$c}\" != \"/dev/null\" ] && [ -n \"\${$c}\" ]" + + eval "$vcmd && do_getvfile=\"y\"" + + if [ "$do_getvfile" = "y" ]; then + if getvfile "$@"; then + return 0 + fi + fi done && return 1; : } -check_vcfg() -{ - vfile="config/vendor/$vcfg/pkg.cfg" - [ -L "$vfile" ] && err "'$archive', '$board': $vfile is a symlink"; : - [ -f "$vfile" ] || err "'$archive', '$board': $vfile missing"; : -} - getvfile() { - # valid vcfg. proceed to download files - eval "`setcfg "$vfile"`" + if e "config/vendor/$vcfg/pkg.cfg" f missing; then + return 1 + fi + + . "config/vendor/$vcfg/pkg.cfg" || \ + err "Can't read 'config/vendor/$vcfg/pkg.cfg'" "getvfile" "$@" bootstrap - [ $# -gt 0 ] && getfiles - [ $# -gt 0 ] && return 0 # download + if [ $# -gt 0 ]; then + # download vendor files + + getfiles + else + # inject vendor files + + fx_ prep x_ find "$tmpromdir" -maxdepth 1 -type f -name "*.rom" + ( check_vendor_hashes ) || \ + err "$archive: Can't verify hashes" "getvfile" "$@"; : + fi - fx_ prep x_ find "$tmpromdir" -maxdepth 1 -type f -name "*.rom" - ( check_vendor_hashes ) || err "$archive: Can't verify hashes"; : } bootstrap() { cbdir="src/coreboot/$tree" - mecleaner="$xbmkpwd/$cbdir/util/me_cleaner/me_cleaner.py" kbc1126_ec_dump="$xbmkpwd/$cbdir/util/kbc1126/kbc1126_ec_dump" - cbfstool="elf/cbfstool/$tree/cbfstool" - rmodtool="elf/cbfstool/$tree/rmodtool" + cbfstool="elf/coreboot/$tree/cbfstool" + rmodtool="elf/coreboot/$tree/rmodtool" + + mecleaner="$xbmkpwd/$cbdir/util/me_cleaner/me_cleaner.py" + if [ "$XBMKmecleaner" = "y" ]; then + mecleaner="$xbmkpwd/src/me_cleaner/me_cleaner.py" + fi x_ ./mk -f coreboot "${cbdir##*/}" - mk -b uefitool biosutilities bios_extract - [ -d "${kbc1126_ec_dump%/*}" ] && x_ make -C "$cbdir/util/kbc1126" - [ -n "$MRC_refcode_cbtree" ] && \ - cbfstoolref="elf/cbfstool/$MRC_refcode_cbtree/cbfstool" && \ - x_ ./mk -d coreboot "$MRC_refcode_cbtree"; : + x_ ./mk -f me_cleaner + + x_ ./mk -b bios_extract + x_ ./mk -b biosutilities + x_ ./mk -b uefitool + x_ ./mk -b libarchive # for bsdtar and bsdunzip + + if [ -d "${kbc1126_ec_dump%/*}" ]; then + x_ make -C "$cbdir/util/kbc1126" + fi + + if [ -n "$MRC_refcode_cbtree" ]; then + cbfstoolref="elf/coreboot/$MRC_refcode_cbtree/cbfstool" + x_ ./mk -d coreboot "$MRC_refcode_cbtree"; : + fi } prep() @@ -264,110 +565,169 @@ prep() _xrom="$1" _xromname="${1##*/}" _xromnew="${_xrom%/*}/${_xromname#"$vfix"}" - [ "$nukemode" = "nuke" ] && _xromnew="${_xrom%/*}/$vfix${_xrom##*/}" - e "$_xrom" f missing && return 0 - [ -z "${_xromname#"$vfix"}" ] && err "$_xromname / $vfix: name match" + if [ "$nuke" = "nuke" ]; then + _xromnew="${_xrom%/*}/$vfix${_xrom##*/}" + fi + + if e "$_xrom" f missing; then + return 0 + fi + + if [ -z "${_xromname#"$vfix"}" ]; then + err "$_xromname / $vfix: name match" "prep" "$@" + fi # Remove the prefix and 1-byte pad - if [ "$nukemode" != "nuke" ] && \ - [ "${_xromname#"$vfix"}" != "$_xromname" ]; then - xromsize="$(expr $(stat -c '%s' "$_xrom") - 1)" || err "!int" - [ $xromsize -lt 524288 ] && err "too small, $xromsize: $_xrom" + if [ "${_xromname#"$vfix"}" != "$_xromname" ] \ + && [ "$nuke" != "nuke" ]; then - x_ dd if="$_xrom" of="$_xromnew" bs=$xromsize count=1 - x_ rm -f "$_xrom" + unpad_one_byte "$_xrom" + x_ mv "$_xrom" "$_xromnew" _xrom="$_xromnew" fi - [ "$nukemode" = "nuke" ] && mksha512sum "$_xrom" "vendorhashes" + if [ "$nuke" = "nuke" ]; then + ( mksha512 "$_xrom" "vendorhashes" ) || err; : + fi + + if ! add_vfiles "$_xrom"; then + # no need to insert files. we will later + # still process MAC addresses as required - add_vfiles "$_xrom" || return 1 # if break return, can still change MAC - [ "$nukemode" != "nuke" ] && return 0 + return 1 + fi - # Rename the file, prefixing a warning saying not to flash - cat "$_xrom" config/data/coreboot/0 > "$_xromnew" || err "!pad $_xrom" - x_ rm -f "$_xrom" + if [ "$nuke" = "nuke" ]; then + pad_one_byte "$_xrom" + x_ mv "$_xrom" "$_xromnew" + fi +} + +mksha512() +{ + build_sbase + + if [ "${1%/*}" != "$1" ]; then + x_ cd "${1%/*}" + fi + + x_ "$sha512sum" ./"${1##*/}" >> "$2" || \ + err "!sha512sum \"$1\" > \"$2\"" "mksha512" "$@" } add_vfiles() { rom="$1" - if [ "$has_hashes" != "y" ] && [ "$nukemode" != "nuke" ]; then + if [ "$has_hashes" != "y" ] && [ "$nuke" != "nuke" ]; then printf "'%s' has no hash file. Skipping.\n" "$archive" 1>&2 + return 1 - elif [ "$has_hashes" = "y" ] && [ "$nukemode" = "nuke" ]; then + elif [ "$has_hashes" = "y" ] && [ "$nuke" = "nuke" ]; then printf "'%s' has a hash file. Skipping nuke.\n" "$archive" 1>&2 + return 1 fi - [ -n "$CONFIG_HAVE_REFCODE_BLOB" ] && vfile "fallback/refcode" \ - "$CONFIG_REFCODE_BLOB_FILE" "stage" - [ "$CONFIG_HAVE_MRC" = "y" ] && vfile "mrc.bin" "$CONFIG_MRC_FILE" \ - "mrc" "0xfffa0000" - [ "$CONFIG_HAVE_ME_BIN" = "y" ] && vfile IFD "$CONFIG_ME_BIN_PATH" me - [ "$CONFIG_KBC1126_FIRMWARE" = "y" ] && vfile ecfw1.bin \ - "$CONFIG_KBC1126_FW1" raw "$CONFIG_KBC1126_FW1_OFFSET" && vfile \ - ecfw2.bin "$CONFIG_KBC1126_FW2" raw "$CONFIG_KBC1126_FW2_OFFSET" - [ -n "$CONFIG_VGA_BIOS_FILE" ] && [ -n "$CONFIG_VGA_BIOS_ID" ] && \ - vfile "pci$CONFIG_VGA_BIOS_ID.rom" "$CONFIG_VGA_BIOS_FILE" optionrom - [ "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" = "y" ] && \ - [ -n "$CONFIG_SMSC_SCH5545_EC_FW_FILE" ] && \ + if [ -n "$CONFIG_HAVE_REFCODE_BLOB" ]; then + vfile "fallback/refcode" "$CONFIG_REFCODE_BLOB_FILE" "stage" + fi + if [ "$CONFIG_HAVE_MRC" = "y" ]; then + vfile "mrc.bin" "$CONFIG_MRC_FILE" "mrc" "0xfffa0000" + fi + if [ "$CONFIG_HAVE_ME_BIN" = "y" ]; then + vfile IFD "$CONFIG_ME_BIN_PATH" me + fi + if [ -n "$CONFIG_KBC1126_FW1" ]; then + vfile ecfw1.bin "$CONFIG_KBC1126_FW1" raw \ + "$CONFIG_KBC1126_FW1_OFFSET" + fi + if [ -n "$CONFIG_KBC1126_FW2" ]; then + vfile ecfw2.bin "$CONFIG_KBC1126_FW2" raw \ + "$CONFIG_KBC1126_FW2_OFFSET" + fi + if [ -n "$CONFIG_VGA_BIOS_FILE" ] && [ -n "$CONFIG_VGA_BIOS_ID" ]; then + vfile "pci$CONFIG_VGA_BIOS_ID.rom" "$CONFIG_VGA_BIOS_FILE" \ + optionrom + fi + if [ "$CONFIG_INCLUDE_SMSC_SCH5545_EC_FW" = "y" ] && \ + [ -n "$CONFIG_SMSC_SCH5545_EC_FW_FILE" ]; then vfile sch5545_ecfw.bin "$CONFIG_SMSC_SCH5545_EC_FW_FILE" raw - [ -z "$CONFIG_FSP_USE_REPO" ] && [ -z "$CONFIG_FSP_FULL_FD" ] && \ - [ -n "$CONFIG_FSP_M_FILE" ] && \ + fi + if [ -z "$CONFIG_FSP_USE_REPO" ] && [ -z "$CONFIG_FSP_FULL_FD" ] && \ + [ -n "$CONFIG_FSP_M_FILE" ]; then vfile "$CONFIG_FSP_M_CBFS" "$CONFIG_FSP_M_FILE" fsp --xip - [ -z "$CONFIG_FSP_USE_REPO" ] && [ -z "$CONFIG_FSP_FULL_FD" ] && \ - [ -n "$CONFIG_FSP_S_FILE" ] && \ + fi + if [ -z "$CONFIG_FSP_USE_REPO" ] && [ -z "$CONFIG_FSP_FULL_FD" ] && \ + [ -n "$CONFIG_FSP_S_FILE" ]; then vfile "$CONFIG_FSP_S_CBFS" "$CONFIG_FSP_S_FILE" fsp + fi - printf "ROM image successfully patched: %s\n" "$rom" xchanged="y" + + printf "ROM image successfully patched: %s\n" "$rom" } vfile() { - [ "$2" = "/dev/null" ] && return 0 + if [ "$2" = "/dev/null" ]; then + return 0 + fi cbfsname="$1" _dest="${2##*../}" - _t="$3" + blobtype="$3" _offset="" - if [ "$_t" = "fsp" ] && [ $# -gt 3 ]; then + if [ "$blobtype" = "fsp" ] && [ $# -gt 3 ]; then _offset="$4" elif [ $# -gt 3 ] && _offset="-b $4" && [ -z "$4" ]; then - err "vfile $*, $rom: offset given but empty (undefined)" + err "$rom: offset given but empty (undefined)" "vfile" "$@" fi - [ "$nukemode" = "nuke" ] || x_ e "$_dest" f + if [ "$nuke" != "nuke" ]; then + x_ e "$_dest" f + fi if [ "$cbfsname" = "IFD" ]; then - [ "$nukemode" = "nuke" ] || x_ "$ifdtool" $ifdprefix -i \ - $_t:$_dest "$rom" -O "$rom" - [ "$nukemode" != "nuke" ] || x_ "$ifdtool" $ifdprefix --nuke \ - $_t "$rom" -O "$rom" - elif [ "$nukemode" = "nuke" ]; then + if [ "$nuke" = "nuke" ]; then + x_ "$ifdtool" $ifdprefix --nuke $blobtype "$rom" \ + -O "$rom" + else + x_ "$ifdtool" $ifdprefix -i $blobtype:$_dest "$rom" \ + -O "$rom" + fi + elif [ "$nuke" = "nuke" ]; then x_ "$cbfstool" "$rom" remove -n "$cbfsname" - elif [ "$_t" = "stage" ]; then # the only stage we handle is refcode - x_ rm -f "$xbmklocal/refcode" - x_ "$rmodtool" -i "$_dest" -o "$xbmklocal/refcode" - x_ "$cbfstool" "$rom" add-stage -f "$xbmklocal/refcode" \ + elif [ "$blobtype" = "stage" ]; then + # the only stage we handle is refcode + + x_ rm -f "$xbtmp/refcode" + x_ "$rmodtool" -i "$_dest" -o "$xbtmp/refcode" + x_ "$cbfstool" "$rom" add-stage -f "$xbtmp/refcode" \ -n "$cbfsname" -t stage else x_ "$cbfstool" "$rom" add -f "$_dest" -n "$cbfsname" \ - -t $_t $_offset + -t $blobtype $_offset fi - xchanged="y"; : + + xchanged="y" } +# must be called from a subshell check_vendor_hashes() { + build_sbase + x_ cd "$tmpromdir" - [ "$has_hashes" = "n" ] || [ "$nukemode" = "nuke" ] || sha512sum \ - --status -c "$hashfile" || x_ sha1sum --status -c "$hashfile" + + if [ "$has_hashes" != "n" ] && [ "$nuke" != "nuke" ]; then + ( x_ "$sha512sum" -c "$hashfile" ) || \ + x_ sha1sum -c "$hashfile" + fi + x_ rm -f "$hashfile" } |