HACK: Add script to build an image without portage

This script allows building a mandolin, trembyle, etc rom without
portage. This script must be run inside the chroot and from the
coreboot-zork directory.

Usage:
    ./build-fast trembyle mandolin-hardcore

    *** Built /tmp/coreboot/trembyle/image-trembyle.serial.bin ***
    *** Built /tmp/coreboot/mandolin-hardcore/image-mandolin-hardcore.serial.bin ***

The script utilizes a cache located in /tmp/coreboot so repeat builds
don't have to start from scratch.

    ./build-fast trembyle
    real    0m4.420s
    user    0m3.235s
    sys     0m2.785s

BUG=none
BRANCH=none
TEST=Built a mandolin rom and trembyle rom. Verified trembyle rom boots
to OS.

Signed-off-by: Raul E Rangel <rrangel@chromium.org>
Change-Id: I7dff8620705070b594a0ab67f37ab1900192357b
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/coreboot/+/2083901
Reviewed-by: Martin Roth <martinroth@google.com>
diff --git a/build-board.sh b/build-board.sh
new file mode 100755
index 0000000..ee5d623
--- /dev/null
+++ b/build-board.sh
@@ -0,0 +1,232 @@
+#!/bin/bash
+
+set -eu
+
+# These are used by the coreboot build system
+export VBOOT_SOURCE=$HOME/trunk/src/platform/vboot_reference/
+
+declare FIRMWARE_ROOT=/build/zork/firmware
+declare KEYDIR=/usr/share/vboot/devkeys
+
+
+if [[ "$#" -eq 0 ]]; then
+	echo "Usage: $0 <board|config file>..."
+	echo "e.g., $0 trembyle mandolin-hardcore"
+	exit 1
+fi
+
+declare -a CONFIGS
+declare -a CONFIG_PATHS=(
+	"$HOME/trunk/src/overlays/overlay-zork/sys-boot/coreboot-zork/files/configs"
+	"$HOME/trunk/src/overlays/overlay-zork/sys-boot/coreboot/files/configs"
+	"./configs"
+)
+
+for arg in "$@"; do
+	if [[ -e "$arg" ]]; then
+		CONFIGS+=("$arg")
+		continue
+	fi
+	found=0
+	for config_path in "${CONFIG_PATHS[@]}"; do
+		if [[ -e "$config_path/config.$arg" ]]; then
+			CONFIGS+=("$config_path/config.$arg")
+			found=1
+			break
+		fi
+	done
+	if [[ "$found" -eq 0 ]]; then
+		echo "Failed to find config for '$arg'"
+		exit 1
+	fi
+done
+
+declare -a CLEANUP
+
+function finish {
+	local dir
+	for dir in "${CLEANUP[@]}"; do
+		if [[ -e "$dir" ]]; then
+			rm -r "$dir"
+		fi
+	done
+}
+
+trap finish EXIT
+
+#
+# Replace local paths with paths to $FIRMWARE_ROOT/coreboot-private
+#
+# $1: full config
+#
+function replace-paths() {
+	local full_config="$1"
+	local private="$FIRMWARE_ROOT/coreboot-private"
+	local full_path
+	local -a replace
+	while read -r key val; do
+		full_path="$private/$val"
+		if [[ -e $full_path ]]; then
+			replace+=(-e "s|^${key}=.*|${key}=\"${full_path}\"|")
+		fi
+	done <<<"$(sed -En -e 's/^([A-Z0-9_]+)="(3rdparty\/blobs\/.*)"$/\1 \2/p' "$full_config")"
+	sed -iE "${replace[@]}" "$full_config"
+}
+
+# $1: cache_dir
+# $2: work_dir
+# $3: config_path
+function build-coreboot-rom() {
+	local cache_dir="$1" work_dir="$2" config_path="$3"
+
+	cp "$config_path" "$work_dir/.config"
+	{
+		echo CONFIG_CONSOLE_SERIAL=y
+		echo CONFIG_FATAL_ASSERTS=y
+	} >> "$work_dir/.config"
+	make \
+		obj="$work_dir" \
+		DOTCONFIG="$work_dir/.config" \
+		HOSTCC="x86_64-pc-linux-gnu-clang"\
+		HOSTPKGCONFIG="x86_64-pc-linux-gnu-pkg-config" \
+		VBOOT_SOURCE="$HOME/trunk/src/platform/vboot_reference" \
+		olddefconfig
+
+	replace-paths "$work_dir/.config"
+
+	if [[ ! -e "$cache_dir/.config" ]] || ! cmp "$work_dir/.config" "$cache_dir/.config"; then
+		echo "Cache busted: $cache_dir"
+		# Bust the cache anytime the .config is updated
+		rm -rf "$cache_dir"
+		mkdir -p "$cache_dir"
+
+		cp "$work_dir/.config" "$cache_dir/.config"
+	else
+		echo "Reusing cache at $cache_dir"
+	fi
+
+	make -j \
+		obj="$cache_dir" \
+		DOTCONFIG="$cache_dir/.config" \
+		HOSTCC="x86_64-pc-linux-gnu-clang"\
+		HOSTPKGCONFIG="x86_64-pc-linux-gnu-pkg-config" \
+		VBOOT_SOURCE="$HOME/trunk/src/platform/vboot_reference"
+
+	# Kconfig generates a dummy file that doesn't get removed.
+	rm -f ..config.tmp.*
+
+	echo "Successfully built $cache_dir"
+}
+
+# Use make compress assets in parallel
+# $1: src
+# $2: dst
+# $3: image.bin
+function compress-assets() {
+	local src="$1" dest="$2"
+
+	make -j -f - src="$src" dest="$dest" << 'EOF'
+.DELETE_ON_ERROR:
+inputs:=$(wildcard $(src)/*)
+outputs:=$(inputs:$(src)/%=$(dest)/%)
+
+.PHONY: all
+
+all: $(outputs)
+
+$(dest):
+	mkdir -p "$@"
+
+$(dest)/%: $(src)/% | $(dest)
+	cbfs-compression-tool compress "$<" "$@" LZMA
+EOF
+}
+
+# $1: work_dir
+# $2: image.bin
+# $3: slot
+function sign-region() {
+	local work_dir="$1" image="$2" slot="$3"
+	local main="FW_MAIN_${slot}" vblock="VBLOCK_${slot}"
+	local -i size
+
+	size="$(cbfstool "${image}" truncate -r "$main")"
+	cbfstool "${image}" read -r "$main" -f "$work_dir/$main"
+	truncate -s "$size" "$work_dir/$main"
+	cbfstool "${image}" write --force -u -i 255 \
+		-r "$main" -f "$work_dir/$main"
+
+	futility vbutil_firmware \
+		--keyblock "${KEYDIR}/firmware.keyblock" \
+		--signprivate "${KEYDIR}/firmware_data_key.vbprivk" \
+		--kernelkey "${KEYDIR}/kernel_subkey.vbpubk" \
+		--fv "$work_dir/$main" \
+		--vblock "$work_dir/$vblock"
+
+	cbfstool "${image}" write -u -i 255 -r "${vblock}" \
+		-f "$work_dir/$vblock"
+}
+
+# $1: cache_dir
+# $2: work_dir
+# $3: image.bin
+function add-depthcharge() {
+	local cache_dir="$1" work_dir="$2" image="$3"
+	local payload="$FIRMWARE_ROOT/zork/depthcharge/depthcharge.elf"
+
+	compress-assets "$FIRMWARE_ROOT/cbfs-ro-compress" \
+		"$cache_dir/compressed-assets-ro"
+
+	local file
+	for file in "$cache_dir/compressed-assets-ro"/*; do
+		cbfstool "${image}" add -r COREBOOT -f "${file}" \
+			-n "$(basename "${file}")" -t raw -c precompression
+	done
+
+	cbfstool "${image}" expand -r FW_MAIN_A,FW_MAIN_B
+
+	cbfstool "${image}" add-payload -r COREBOOT,FW_MAIN_A,FW_MAIN_B \
+			-f "${payload}" -n fallback/payload -c lzma
+
+	sign-region "$work_dir" "$image" "A"
+	sign-region "$work_dir" "$image" "B"
+}
+
+# $1: config_path
+function build-boot-image() {
+	local config_path="$1"
+	local work_dir build_name cache_dir image_name
+	work_dir="$(mktemp -d)" && CLEANUP+=("$work_dir")
+	build_name="${config_path##*.}"
+	cache_dir="/tmp/coreboot/$build_name"
+	image_name="image-$build_name.serial.bin"
+
+	echo "Building $config_path"
+
+	build-coreboot-rom "$cache_dir"	"$work_dir" "$config_path"
+
+	if grep -q CONFIG_VBOOT=y "$cache_dir/.config"; then
+		cp "$cache_dir/coreboot.rom" "$work_dir/$image_name"
+		add-depthcharge "$cache_dir" "$work_dir" "$work_dir/$image_name"
+		cp "$work_dir/$image_name" "$cache_dir/$image_name"
+	else
+		cp "$cache_dir/coreboot.rom" "$cache_dir/$image_name"
+	fi
+	FINAL_IMAGES+=("$cache_dir/$image_name")
+}
+
+# Ugh, still in the src tree
+rm -f .xcompile
+util/xcompile/xcompile /opt/coreboot-sdk/bin/ > .xcompile
+
+declare -a FINAL_IMAGES
+
+for config in "${CONFIGS[@]}"; do
+	build-boot-image "$config"
+done
+
+echo
+
+for image in "${FINAL_IMAGES[@]}"; do
+	echo "*** Built $image ***"
+done