#!/bin/bash

#  helper script: create ROM images for a given system, with GRUB payload
#
#	Copyright (C) 2020 Leah Rowe <info@minifree.org>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# This script assumes that the working directory is the root
# of git or release archive


# TODO: add make -jWHATEVER to "make" command for coreboot
# TODO: check if coreboot supports multi-core building in its build system
[ "x${DEBUG+set}" = 'xset' ] && set -v
set -u -e
if [ -z ${NPROC+x} ]; then
    cores="$(nproc)"
else
    case ${NPROC} in
        ''|*[!0-9]*)
            printf "value '%s' for NPROC is invalid. non-numeric. Exiting.\n" "${NPROC}"
            exit 1
            ;;
    esac
    cores="${NPROC}"
fi

if (( $# != 1 )); then
	printf "Usage: ./build roms withgrub boardname\n"
	printf "Example: ./build roms withgrub x230\n"
	printf "You need to specify exactly 1 argument\n"
	exit 1
fi

board="${1}"
romdir_grub="bin/grub_${board}"
cbdir="coreboot/${board}"
cbfstool="${cbdir}/util/cbfstool/cbfstool"
corebootrom="${cbdir}/build/coreboot.rom"
optionromdir="resources/coreboot/${board}/optionroms"
seavgabiosrom="payload/seabios/seavgabios.bin"

if [ ! -f "${seavgabiosrom}" ]; then
    printf "seavgabios is not built. Please run ./build payload seabios\n"
    exit 1
fi

if [ ! -d "resources/coreboot/${board}" ]; then
    printf "Target %s does not exist in the retroboot build system.\n" "${board}"
    exit 1
fi

if [ ! -d "resources/coreboot/${board}/config/grub" ]; then
    printf "GRUB payload not supported on target: %s - skipping\n" "${board}"
    exit 0
fi

[ -d "bin/grub_${board}/" ] || mkdir -p "bin/grub_${board}/"
rm -f "bin/grub_${board}"/* coreboot.tmp.grub.rom

if [ -d "${optionromdir}" ]; then
    cp "${optionromdir}"/pci*.rom "${cbdir}/"
fi

for displaymode in vesafb txtmode; do
    for initmode in libgfxinit vgarom; do

        cbcfgpath="resources/coreboot/${board}/config/grub/${initmode}_${displaymode}"
        seabioself="payload/seabios/seabios_${initmode}.elf"

        if [ ! -f "${seabioself}" ]; then
            printf "seabios is not built. please run ./build payload seabios\n"
            exit 1
        fi

        # TODO: make these error out with specific message advising if
        # a single thing is missing. e.g. error says: "Please compile cbfstool"
        if [ ! -f "${cbcfgpath}" ] || [ ! -f "${cbfstool}" ]; then
            continue
        fi
        if [ ! -d "${cbdir}" ]; then
            continue
        fi

        (
            cd "${cbdir}"
            make distclean
        )
        cp "${cbcfgpath}" "${cbdir}"/.config
        
        (
            cd "${cbdir}"
            make
        )

        # copy the bootblock, for purpose of internal flashing from lenovobios.
        # when doing that, upper bootblock isn't flashed so you set bucts to
        # use the alt (lower) bootblock. These dd commands make that safe
        if [ "${board}" = "t60_ati_x1400" ]; then
			dd if="${corebootrom}" of=top64k.bin bs=1 skip=$[$(stat -c %s "${corebootrom}") - 0x10000] count=64k
			dd if=top64k.bin of="${corebootrom}" bs=1 seek=$[$(stat -c %s "${corebootrom}") - 0x20000] count=64k conv=notrunc
			rm -f top64k.bin
        fi

        if [ "${displaymode}" = "txtmode" ]; then
            # by putting it under img/, SeaBIOS can also use it
            # and GRUB ROMs are configured to use that location aswell
            # This is useful if the user wishes to add SeaBIOS in their ROM
            # that has the GRUB payload. This is entirely possible in coreboot
            "${cbfstool}" "${corebootrom}" add-payload -f memtest86plus/memtest.bin -n img/memtest.bin -c lzma
        fi

        "${cbfstool}" "${corebootrom}" add-payload -f "${seabioself}" -n seabios.elf -c lzma

        if [ "${initmode}" = "libgfxinit" ]; then
            "${cbfstool}" "${corebootrom}" add -f "${seavgabiosrom}" -n vgaroms/seavgabios.bin -t raw
        fi

        for keymapfile in resources/grub/keymap/original/*; do
            if [ ! -f "${keymapfile}" ]; then
                continue
            fi
            keymap="${keymapfile##*/}"

            grubelf="payload/grub/grub_${keymap}.elf"
            grubcfg="payload/grub/grub_${keymap}_${displaymode}.cfg"
            grubtestcfg="payload/grub/grub_${keymap}_${displaymode}_test.cfg"

            # TODO: do these individually and error out with specific message
            # if something is missing. e.g. error says: "Please compile GRUB"
            if [ ! -f "${grubelf}" ] || [ ! -f "${grubcfg}" ] \
                || [ ! -f "${grubtestcfg}" ]; then
                continue
            fi

            cp "${corebootrom}" coreboot.tmp.grub.rom
            "${cbfstool}" coreboot.tmp.grub.rom add-payload -f "${grubelf}" -n fallback/payload -c lzma
            "${cbfstool}" coreboot.tmp.grub.rom add -f "${grubcfg}" -n grub.cfg -t raw
            "${cbfstool}" coreboot.tmp.grub.rom add -f "${grubtestcfg}" -n grubtest.cfg -t raw

            if [ "${displaymode}" = "vesafb" ]; then
                "${cbfstool}" coreboot.tmp.grub.rom add -f resources/grub/font/dejavusansmono.pf2 -n dejavusansmono.pf2 -t raw
            fi

            newrompath="${romdir_grub}/grub_${board}_${initmode}_${displaymode}_${keymap}.rom"
            if [ "${board}" = "x230" ] || [ "${board}" = "x230t" ]; then
                printf "\nExtracting 4MiB BIOS region for %s\n" "${newrompath}"
                dd if=coreboot.tmp.grub.rom of=${newrompath} bs=1 skip=$[$(stat -c %s coreboot.tmp.grub.rom) - 0x400000] count=4194304
            elif [ "${board}" = "x220" ]; then
                printf "\nExtracting 2MiB BIOS region for %s\n" "${newrompath}"
                dd if=coreboot.tmp.grub.rom of=${newrompath} bs=1 skip=$[$(stat -c %s coreboot.tmp.grub.rom) - 0x200000] count=2097152
            else
                mv coreboot.tmp.grub.rom ${newrompath}
            fi
        done

    done
done

rm -f "${cbdir}"/pci*.rom coreboot.tmp.grub.rom

printf "\nDone! Your ROMs are in bin/grub_%s/\n\n" "${board}"

