blob: 59908c5b08c3438e4a6dd87042e4dbf25fb67b34 [file] [log] [blame]
#!/usr/bin/env bash
#
# This file is part of the coreboot project.
#
# Copyright (C) 2007-2010 coresystems GmbH
# Copyright (C) 2012 Google Inc
# Copyright (C) 2016 Raptor Engineering, LLC
#
# 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; version 2 of the License.
#
# 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.
#
# Usage: [--debug] [path to xgcc/bin directory]
# Enable debug output
if [ "$1" = "--debug" ]; then
shift
set -x
fi
TMPFILE=""
XGCCPATH=$1
# payloads under payloads/external crossgcc path
if [ -d "$(pwd)/../../../../util/crossgcc/xgcc/bin/" ]
then
XGCCPATH=${XGCCPATH:-"$(pwd)/../../../../util/crossgcc/xgcc/bin/"}
fi
# libpayload crossgcc path
if [ -d "$(pwd)/../../util/crossgcc/xgcc/bin/" ]
then
XGCCPATH=${XGCCPATH:-"$(pwd)/../../util/crossgcc/xgcc/bin/"}
fi
# coreboot crossgcc path
if [ -d "$(pwd)/util/crossgcc/xgcc/bin/" ]
then
XGCCPATH=${XGCCPATH:-"$(pwd)/util/crossgcc/xgcc/bin/"}
fi
die() {
echo "ERROR: $*" >&2
exit 1
}
clean_up() {
if [ -n "$TMPFILE" ]; then
rm -f "$TMPFILE" "$TMPFILE.c" "$TMPFILE.o"
fi
}
trap clean_up EXIT
program_exists() {
type "$1" >/dev/null 2>&1
}
if [ "$("${XGCCPATH}/iasl" 2>/dev/null | grep -c ACPI)" -gt 0 ]; then
IASL=${XGCCPATH}iasl
elif [ "$(iasl 2>/dev/null | grep -c ACPI)" -gt 0 ]; then
IASL=iasl
fi
if program_exists gcc; then
HOSTCC=gcc
elif program_exists cc; then
HOSTCC=cc
else
die "no host compiler found"
fi
# try to find the core count using various methods
CORES="$(getconf _NPROCESSORS_ONLN 2>/dev/null)"
if [ -z "$CORES" ]; then
NPROC=$(command -v nproc)
if [ -n "$NPROC" ]; then
CORES="$($NPROC)"
fi
fi
if [ -z "$CORES" ]; then
SYSCTL=$(command -v sysctl)
if [ -n "$SYSCTL" ]; then
CORES="$(${SYSCTL} -n hw.ncpu 2>/dev/null)"
fi
fi
if [ -z "$CORES" ] && [ -f /proc/cpuinfo ]; then
CORES="$(grep 'processor' /proc/cpuinfo 2>/dev/null | wc -l)"
fi
cat <<EOF
# platform agnostic and host tools
XGCCPATH:=${XGCCPATH}
IASL:=${IASL}
HOSTCC?=${HOSTCC}
CPUS?=${CORES}
EOF
testcc() {
local cc="$1"
local cflags="$2"
local tmp_c="$TMPFILE.c"
local tmp_o="$TMPFILE.o"
rm -f "$tmp_c" "$tmp_o"
echo "void _start(void) {}" >"$tmp_c"
"$cc" -nostdlib -Werror $cflags -c "$tmp_c" -o "$tmp_o" >/dev/null 2>&1
}
testld() {
local gcc="$1"
local cflags="$2"
local ld="$3"
local ldflags="$4"
local tmp_o="$TMPFILE.o"
local tmp_elf="$TMPFILE.elf"
rm -f "$tmp_elf"
testcc "$gcc" "$cflags" &&
$ld -nostdlib -static $ldflags -o "$tmp_elf" "$tmp_o" >/dev/null 2>&1
}
testas() {
local gccprefix="$1"
local twidth="$2"
local arch="$3"
local use_dash_twidth="$4"
local endian="$5"
local obj_file="$TMPFILE.o"
local full_arch="elf$twidth-$arch"
rm -f "$obj_file"
[ -n "$use_dash_twidth" ] && use_dash_twidth="--$twidth"
[ -n "$endian" ] && endian="-$endian"
"${gccprefix}as" $use_dash_twidth $endian -o "$obj_file" "$TMPFILE" \
2>/dev/null || return 1
# Check output content type.
local obj_type="$(LANG=C LC_ALL='' "${gccprefix}"objdump -p "$obj_file" 2>/dev/null)"
local obj_arch="$(expr "$obj_type" : '.*format \(.[a-z0-9-]*\)')"
[ "$obj_arch" = "$full_arch" ] || return 1
unset ASFLAGS LDFLAGS
unset CFLAGS_GCC CFLAGS_CLANG
if [ -n "$use_dash_twidth" ]; then
ASFLAGS="--$twidth"
CFLAGS_GCC="-m$twidth"
CFLAGS_CLANG="-m$twidth"
LDFLAGS="-b $full_arch"
fi
# Special parameters only available in dash_twidth mode.
[ -n "$use_dash_twidth" ] && case "$full_arch" in
"elf32-i386" )
LDFLAGS="$LDFLAGS -melf_i386"
CFLAGS_GCC="$CFLAGS_GCC -Wl,-b,elf32-i386 -Wl,-melf_i386"
CFLAGS_CLANG="$CFLAGS_CLANG -Wl,-b,elf32-i386 -Wl,-melf_i386"
;;
esac
return 0
}
detect_special_flags() {
local architecture="$1"
# Check for an operational -m32/-m64
testcc "$GCC" "$CFLAGS_GCC -m$TWIDTH " &&
CFLAGS_GCC="$CFLAGS_GCC -m$TWIDTH "
# Use bfd linker instead of gold if available:
testcc "$GCC" "$CFLAGS_GCC -fuse-ld=bfd" &&
CFLAGS_GCC="$CFLAGS_GCC -fuse-ld=bfd" && LINKER_SUFFIX='.bfd'
testcc "$GCC" "$CFLAGS_GCC -fno-stack-protector" &&
CFLAGS_GCC="$CFLAGS_GCC -fno-stack-protector"
testcc "$GCC" "$CFLAGS_GCC -Wl,--build-id=none" &&
CFLAGS_GCC="$CFLAGS_GCC -Wl,--build-id=none"
case "$architecture" in
x86)
;;
x64)
;;
arm64)
testld "$GCC" "$CFLAGS_GCC" "${GCCPREFIX}ld${LINKER_SUFFIX}" \
"$LDFLAGS --fix-cortex-a53-843419" && \
LDFLAGS_ARM64_A53_ERRATUM_843419+=" --fix-cortex-a53-843419"
;;
esac
}
detect_compiler_runtime() {
test -z "$GCC" || \
CC_RT_GCC="$(${GCC} ${CFLAGS_GCC} -print-libgcc-file-name)"
if [ ${CLANG_RUNTIME} = "libgcc" ]; then
CC_RT_CLANG=${CC_RT_GCC}
else
test -z "$CLANG" || \
CC_RT_CLANG="$(${CLANG} ${CFLAGS_CLANG} -print-libgcc-file-name 2>/dev/null)"
fi
}
report_arch_toolchain() {
cat <<EOF
# elf${TWIDTH}-${TBFDARCH} toolchain (${GCC})
ARCH_SUPPORTED+=${TARCH}
SUBARCH_SUPPORTED+=${TSUPP-${TARCH}}
# GCC
GCC_CC_${TARCH}:=${GCC}
GCC_CFLAGS_${TARCH}:=${CFLAGS_GCC}
# Generally available for GCC's cc1:
GCC_CFLAGS_${TARCH}+=-fno-delete-null-pointer-checks -Wlogical-op -Wno-address-of-packed-member
GCC_ADAFLAGS_${TARCH}:=${CFLAGS_GCC}
GCC_COMPILER_RT_${TARCH}:=${CC_RT_GCC}
GCC_COMPILER_RT_FLAGS_${TARCH}:=${CC_RT_EXTRA_GCC}
# Clang
CLANG_CC_${TARCH}:=${CLANG}
CLANG_CFLAGS_${TARCH}:=${CFLAGS_CLANG}
CLANG_CFLAGS_${TARCH}+=-Qunused-arguments -m${TWIDTH}
# tone down clang compiler warnings
CLANG_CFLAGS_${TARCH}+=-Wno-unused-variable -Wno-unused-function -Wno-tautological-compare
CLANG_CFLAGS_${TARCH}+=-Wno-shift-overflow -Wno-address-of-packed-member -Wno-initializer-overrides
CLANG_COMPILER_RT_${TARCH}:=${CC_RT_CLANG}
CLANG_COMPILER_RT_FLAGS_${TARCH}:=${CC_RT_EXTRA_CLANG}
# GCC/Clang Common
ifeq (\$(CONFIG_COMPILER_GCC)\$(CONFIG_LP_COMPILER_GCC),y)
CC_${TARCH}:=\$(GCC_CC_${TARCH})
CFLAGS_${TARCH}:=\$(GCC_CFLAGS_${TARCH})
COMPILER_RT_${TARCH}:=\$(GCC_COMPILER_RT_${TARCH})
COMPILER_RT_FLAGS_${TARCH}:=\$(GCC_COMPILER_RT_FLAGS_${TARCH})
else
CC_${TARCH}:=\$(CLANG_CC_${TARCH})
CFLAGS_${TARCH}:=\$(CLANG_CFLAGS_${TARCH})
COMPILER_RT_${TARCH}:=\$(CLANG_COMPILER_RT_${TARCH})
COMPILER_RT_FLAGS_${TARCH}:=\$(CLANG_COMPILER_RT_FLAGS_${TARCH})
endif
EOF
# Generally the x86 should build for i686 -- no sse/mmx
# instructions since SMM modules are compiled using these
# flags. Note that this doesn't prevent a project using
# xcompile to explicitly specify -mmsse, etc flags.
# The Quark processor doesn't support the instructions
# introduced with the Pentium 6 architecture, so allow it
# to use i586 instead.
if [ "${TARCH}" = "x86_64" ]; then
cat <<EOF
CFLAGS_${TARCH} += -march=nocona -malign-data=abi
EOF
fi
if [ "${TARCH}" = "x86_32" ]; then
cat <<EOF
ifneq (\$(CONFIG_USE_MARCH_586)\$(CONFIG_LP_USE_MARCH_586),)
CFLAGS_${TARCH} += -march=i586
else
CFLAGS_${TARCH} += -march=i686
endif
EOF
fi
cat <<EOF
CPP_${TARCH}:=${GCCPREFIX}cpp
AS_${TARCH}:=${GCCPREFIX}as ${ASFLAGS}
LD_${TARCH}:=${GCCPREFIX}ld${LINKER_SUFFIX} ${LDFLAGS}
EOF
if [ "${TARCH}" = "arm64" ] && \
[ -n "${LDFLAGS_ARM64_A53_ERRATUM_843419}" ]; then
cat <<EOF
ifeq (\$(CONFIG_ARM64_A53_ERRATUM_843419),y)
LD_${TARCH}+=${LDFLAGS_ARM64_A53_ERRATUM_843419}
endif
EOF
fi # if [ "${TARCH}" = "arm64" ]...
cat <<EOF
ifeq (\$(CONFIG_COMPILER_GCC)\$(CONFIG_LP_COMPILER_GCC),y)
NM_${TARCH}:=${GCCPREFIX}gcc-nm
AR_${TARCH}:=${GCCPREFIX}gcc-ar
else
NM_${TARCH}:=${GCCPREFIX}nm
AR_${TARCH}:=${GCCPREFIX}ar
endif
OBJCOPY_${TARCH}:=${GCCPREFIX}objcopy
OBJDUMP_${TARCH}:=${GCCPREFIX}objdump
READELF_${TARCH}:=${GCCPREFIX}readelf
STRIP_${TARCH}:=${GCCPREFIX}strip
GNATBIND_${TARCH}:=${GCCPREFIX}gnatbind
CROSS_COMPILE_${TARCH}:=${GCCPREFIX}
EOF
#The two blank lines above are intentional separators
}
# Architecture definitions
SUPPORTED_ARCHITECTURES="arm arm64 riscv x64 x86 ppc64"
# TARCH: local name for the architecture
# (used as CC_${TARCH} in the build system)
# TBFDARCHS: architecture name in binutils (eg elf32-${TBFDARCH})
# TCLIST: first part of the compiler triplet (eg i386 in i386-elf)
# TWIDTH: numerical argument for cpu mode: gcc -m${TWIDTH}
# TSUPP: supported subarchs (for -mcpu=...)
# TABI: typically elf, eabi or linux
arch_config_arm() {
TARCH="arm"
TBFDARCHS="littlearm"
TCLIST="armv7-a armv7a arm"
TWIDTH="32"
TSUPP="arm armv4 armv7 armv7_m armv7_r"
TABI="eabi"
}
arch_config_arm64() {
TARCH="arm64"
TBFDARCHS="littleaarch64"
TCLIST="aarch64"
TWIDTH="64"
TSUPP="arm64 armv8_64"
TABI="elf"
}
arch_config_riscv() {
TARCH="riscv"
TBFDARCHS="littleriscv"
TCLIST="riscv64 riscv"
TWIDTH="64"
TABI="elf"
}
arch_config_x64() {
TARCH="x86_64"
TBFDARCHS="x86-64"
TCLIST="x86_64"
TWIDTH="64"
TABI="elf"
}
arch_config_x86() {
TARCH="x86_32"
TBFDARCHS="i386"
TCLIST="i386 x86_64"
TWIDTH="32"
TABI="elf"
CC_RT_EXTRA_GCC="--wrap __divdi3 --wrap __udivdi3 --wrap __moddi3 --wrap __umoddi3"
}
arch_config_ppc64() {
TARCH="ppc64"
TBFDARCHS="powerpc"
TCLIST="powerpc64"
TWIDTH="64"
TSUPP="ppc64"
TABI="linux-gnu" # there is no generic ABI on ppc64
CC_RT_EXTRA_GCC="-mcpu=power8 -mbig-endian"
}
# Right now, the clang reference toolchain is not building compiler-rt builtins
# for any of the cross compile architectures. Hence we use libgcc for now,
# because that is available and lets us proceed with getting coreboot clang
# ready. Toggle CLANG_RUNTIME if you want to experiment with compiler-rt.
CLANG_RUNTIME="libgcc"
# CLANG_RUNTIME="compiler-rt"
test_architecture() {
local architecture=$1
local endian gccprefix search
GCCPREFIX="invalid"
unset TABI TARCH TBFDARCH TCLIST TENDIAN TSUPP TWIDTH
unset CC_RT_EXTRA_GCC CC_RT_EXTRA_CLANG
unset GCC CLANG
if type "arch_config_$architecture" > /dev/null; then
"arch_config_$architecture"
else
die "no architecture definition for $architecture"
fi
# To override toolchain, define CROSS_COMPILE_$arch or CROSS_COMPILE as
# environment variable.
# Ex: CROSS_COMPILE_arm="armv7a-cros-linux-gnueabi-"
# CROSS_COMPILE_x86="i686-pc-linux-gnu-"
search="$(eval echo "\$CROSS_COMPILE_$architecture" 2>/dev/null)"
search="$search $CROSS_COMPILE"
for toolchain in $TCLIST; do
search="$search $XGCCPATH$toolchain-$TABI-"
search="$search $toolchain-$TABI-"
search="$search $toolchain-linux-gnu-"
search="$search $toolchain-linux-"
search="$search $toolchain-"
search="$search $toolchain-linux-gnueabi-"
done
echo "###########################################################################"
echo "# $architecture"
echo "# TARCH_SEARCH=$search"
# Search toolchain by checking assembler capability.
for TBFDARCH in $TBFDARCHS; do
for gccprefix in $search ""; do
program_exists "${gccprefix}as" || continue
for endian in $TENDIAN ""; do
{ testas "$gccprefix" "$TWIDTH" "$TBFDARCH" \
"" "$endian" ||
testas "$gccprefix" "$TWIDTH" "$TBFDARCH" \
"TRUE" "$endian" ; } && \
testcc "${gccprefix}gcc" "$CFLAGS_GCC" && \
GCCPREFIX="$gccprefix" && \
break 3
done
done
done
if [ "invalid" != "$GCCPREFIX" ]; then
GCC="${GCCPREFIX}gcc"
fi
for clang_arch in $TCLIST invalid; do
for clang_prefix in $search $XGCCPATH ""; do
testcc "${clang_prefix}clang" "-target ${clang_arch}-$TABI -c" && break 2
done
done
if [ "invalid" != "$clang_arch" ]; then
# FIXME: this may break in a clang && !gcc configuration,
# but that's more of a clang limitation. Let's be optimistic
# that this will change in the future.
CLANG="${clang_prefix}clang"
CFLAGS_CLANG="-target ${clang_arch}-${TABI} $CFLAGS_CLANG -ccc-gcc-name ${GCC}"
fi
}
OUT="$(mktemp /tmp/temp.XXXXXX 2>/dev/null || echo /tmp/temp.coreboot.$RANDOM)"
rm -f $OUT
for architecture in $SUPPORTED_ARCHITECTURES; do
(
TMPFILE="$(mktemp /tmp/temp.XXXXXX 2>/dev/null || echo /tmp/temp.coreboot.$RANDOM)"
touch $TMPFILE
test_architecture "$architecture"
detect_special_flags "$architecture"
detect_compiler_runtime "$architecture"
report_arch_toolchain
clean_up
) > $OUT.$architecture &
done
wait
for architecture in $SUPPORTED_ARCHITECTURES; do
cat $OUT.$architecture
rm -f $OUT.$architecture
done
echo XCOMPILE_COMPLETE:=1