1#!/usr/bin/env bash 2# 3# SPDX-License-Identifier: GPL-2.0-only 4 5# Usage: [--debug] [path to xgcc/bin directory] 6 7# Enable debug output 8if [ "$1" = "--debug" ]; then 9 shift 10 set -x 11fi 12 13# GENERIC_COMPILER_PREFIX defaults to empty but can be used to override 14# compiler search behavior 15TMPFILE="" 16XGCCPATH=$1 17 18# payloads under payloads/external crossgcc path 19if [ -d "$(pwd)/../../../../util/crossgcc/xgcc/bin/" ] 20then 21 XGCCPATH=${XGCCPATH:-"$(pwd)/../../../../util/crossgcc/xgcc/bin/"} 22fi 23 24# libpayload crossgcc path 25if [ -d "$(pwd)/../../util/crossgcc/xgcc/bin/" ] 26then 27 XGCCPATH=${XGCCPATH:-"$(pwd)/../../util/crossgcc/xgcc/bin/"} 28fi 29 30# coreboot crossgcc path 31if [ -d "$(pwd)/util/crossgcc/xgcc/bin/" ] 32then 33 XGCCPATH=${XGCCPATH:-"$(pwd)/util/crossgcc/xgcc/bin/"} 34fi 35 36die() { 37 echo "ERROR: $*" >&2 38 exit 1 39} 40 41clean_up() { 42 if [ -n "$TMPFILE" ]; then 43 rm -f "$TMPFILE" "$TMPFILE.c" "$TMPFILE.o" 44 fi 45} 46 47trap clean_up EXIT 48 49 50program_exists() { 51 type "$1" >/dev/null 2>&1 52} 53 54 55if [ "$("${XGCCPATH}/iasl" 2>/dev/null | grep -c ACPI)" -gt 0 ]; then 56 IASL=${XGCCPATH}/iasl 57elif [ "$(iasl 2>/dev/null | grep -c ACPI)" -gt 0 ]; then 58 IASL=iasl 59fi 60 61if program_exists "${XGCCPATH}/nasm" ; then 62 NASM="${XGCCPATH}/nasm" 63elif program_exists nasm; then 64 NASM=nasm 65fi 66 67if program_exists "${XGCCPATH}/gcc"; then 68 HOSTCC="${XGCCPATH}/gcc" 69elif program_exists gcc; then 70 HOSTCC=gcc 71elif program_exists cc; then 72 HOSTCC=cc 73else 74 die "no host compiler found" 75fi 76 77# Look for a C++ compiler (for kconfig's qconf), but don't fail if there is 78# none, just set the compiler to false(1) which will break early enough if 79# used while being less confusing than errors about "g not found" when 80# "$HOSTCXX -g" evaluates to "-g" and make drops the leading dash. 81if program_exists "${XGCCPATH}/g++"; then 82 HOSTCXX="${XGCCPATH}/g++" 83elif program_exists g++; then 84 HOSTCXX=g++ 85elif program_exists c++; then 86 HOSTCXX=c++ 87else 88 HOSTCXX=false 89fi 90 91# try to find the core count using various methods 92CORES="$(getconf _NPROCESSORS_ONLN 2>/dev/null)" 93if [ -z "$CORES" ]; then 94 NPROC=$(command -v nproc) 95 if [ -n "$NPROC" ]; then 96 CORES="$($NPROC)" 97 fi 98fi 99if [ -z "$CORES" ]; then 100 SYSCTL=$(command -v sysctl) 101 if [ -n "$SYSCTL" ]; then 102 CORES="$(${SYSCTL} -n hw.ncpu 2>/dev/null)" 103 fi 104fi 105if [ -z "$CORES" ] && [ -f /proc/cpuinfo ]; then 106 CORES="$(grep 'processor' /proc/cpuinfo 2>/dev/null | wc -l)" 107fi 108 109cat <<EOF 110# platform agnostic and host tools 111XGCCPATH:=${XGCCPATH} 112NASM:=${NASM} 113IASL:=${IASL} 114HOSTCC?=${HOSTCC} 115HOSTCXX?=${HOSTCXX} 116CPUS?=${CORES} 117 118EOF 119 120testcc() { 121 local cc="$1" 122 local cflags="$2" 123 local tmp_c="$TMPFILE.c" 124 local tmp_o="$TMPFILE.o" 125 rm -f "$tmp_c" "$tmp_o" 126 echo "void _start(void) {}" >"$tmp_c" 127 "$cc" -nostdlib -Werror $cflags -c "$tmp_c" -o "$tmp_o" >/dev/null 2>&1 128} 129 130testld() { 131 local gcc="$1" 132 local cflags="$2" 133 local ld="$3" 134 local ldflags="$4" 135 local tmp_o="$TMPFILE.o" 136 local tmp_elf="$TMPFILE.elf" 137 rm -f "$tmp_elf" 138 testcc "$gcc" "$cflags" && 139 $ld -nostdlib -static $ldflags -o "$tmp_elf" "$tmp_o" >/dev/null 2>&1 140} 141 142testas() { 143 local gccprefix="$1" 144 local twidth="$2" 145 local arch="$3" 146 local use_dash_twidth="$4" 147 local endian="$5" 148 local obj_file="$TMPFILE.o" 149 local full_arch="elf$twidth-$arch" 150 151 rm -f "$obj_file" 152 [ -n "$use_dash_twidth" ] && use_dash_twidth="--$twidth" 153 [ -n "$endian" ] && endian="-$endian" 154 "${gccprefix}as" $use_dash_twidth $endian -o "$obj_file" "$TMPFILE" \ 155 2>/dev/null || return 1 156 157 # Check output content type. 158 local obj_type="$(LANG=C LC_ALL='' "${gccprefix}"objdump -p "$obj_file" 2>/dev/null)" 159 local obj_arch="$(expr "$obj_type" : '.*format \(.[a-z0-9-]*\)')" 160 [ "$obj_arch" = "$full_arch" ] || return 1 161 162 unset ASFLAGS LDFLAGS 163 unset FLAGS_GCC CFLAGS_GCC CFLAGS_CLANG 164 165 if [ -n "$use_dash_twidth" ]; then 166 ASFLAGS="--$twidth" 167 FLAGS_GCC="-m$twidth" 168 CFLAGS_CLANG="-m$twidth" 169 LDFLAGS="-b $full_arch" 170 171 fi 172 173 # Special parameters only available in dash_twidth mode. 174 [ -n "$use_dash_twidth" ] && case "$full_arch" in 175 "elf32-i386" ) 176 LDFLAGS="$LDFLAGS -melf_i386" 177 FLAGS_GCC="$FLAGS_GCC -Wl,-b,elf32-i386 -Wl,-melf_i386" 178 CFLAGS_CLANG="$CFLAGS_CLANG -Wl,-b,elf32-i386 -Wl,-melf_i386" 179 ;; 180 esac 181 182 return 0 183} 184 185detect_special_flags() { 186 local architecture="$1" 187 # Check for an operational -m32/-m64 188 testcc "$GCC" "$FLAGS_GCC -m$TWIDTH " && 189 FLAGS_GCC="$FLAGS_GCC -m$TWIDTH " 190 191 # Use bfd linker instead of gold if available: 192 testcc "$GCC" "$FLAGS_GCC -fuse-ld=bfd" && 193 FLAGS_GCC="$FLAGS_GCC -fuse-ld=bfd" && LINKER_SUFFIX='.bfd' 194 195 testcc "$GCC" "$FLAGS_GCC -fno-stack-protector" && 196 FLAGS_GCC="$FLAGS_GCC -fno-stack-protector" 197 testcc "$GCC" "$FLAGS_GCC -Wl,--build-id=none" && 198 FLAGS_GCC="$FLAGS_GCC -Wl,--build-id=none" 199 200 testcc "$GCC" "$CFLAGS_GCC -Wno-address-of-packed-member $FLAGS_GCC" && 201 CFLAGS_GCC="$CFLAGS_GCC -Wno-address-of-packed-member" 202 testcc "$GCC" "$CFLAGS_GCC --param=min-pagesize=1024 $FLAGS_GCC" && 203 CFLAGS_GCC="$CFLAGS_GCC --param=min-pagesize=1024" 204 205 testcc "$GCC" "$CFLAGS_GCC -Wflex-array-member-not-at-end" && 206 CFLAGS_GCC="$CFLAGS_GCC -Wflex-array-member-not-at-end" 207 208 testcc "$GCC" "$CFLAGS_GCC -Wcalloc-transposed-args" && 209 CFLAGS_GCC="$CFLAGS_GCC -Wcalloc-transposed-args" 210 211 case "$architecture" in 212 x86) 213 ;; 214 x64) 215 ;; 216 arm64) 217 testld "$GCC" "$FLAGS_GCC" "${GCCPREFIX}ld${LINKER_SUFFIX}" \ 218 "$LDFLAGS --fix-cortex-a53-843419" && \ 219 LDFLAGS_ARM64_A53_ERRATUM_843419+=" --fix-cortex-a53-843419" 220 ;; 221 riscv) 222 testcc "$GCC" "$FLAGS_GCC -march=rv64iadc_zicsr_zifencei" && 223 ARCH_SUFFIX="_zicsr_zifencei" 224 ;; 225 esac 226} 227 228detect_compiler_runtime() { 229 test -z "$GCC" || \ 230 CC_RT_GCC="$(${GCC} ${CFLAGS_GCC} ${FLAGS_GCC} -print-libgcc-file-name)" 231 if [ ${CLANG_RUNTIME} = "libgcc" ]; then 232 CC_RT_CLANG=${CC_RT_GCC} 233 else 234 test -z "$CLANG" || \ 235 CC_RT_CLANG="$(${CLANG} ${CFLAGS_CLANG} -print-libgcc-file-name 2>/dev/null)" 236 fi 237} 238 239report_arch_toolchain() { 240 cat <<EOF 241# elf${TWIDTH}-${TBFDARCH} toolchain (${GCC}) 242ARCH_SUPPORTED+=${TARCH} 243SUBARCH_SUPPORTED+=${TSUPP-${TARCH}} 244ARCH_SUFFIX_${TARCH}:=${ARCH_SUFFIX} 245 246# GCC 247GCC_CC_${TARCH}:=${GCC} 248GCC_CFLAGS_${TARCH}:=${CFLAGS_GCC} ${FLAGS_GCC} 249# Generally available for GCC's cc1: 250GCC_CFLAGS_${TARCH}+=-fno-delete-null-pointer-checks -Wlogical-op 251GCC_ADAFLAGS_${TARCH}:=${FLAGS_GCC} 252GCC_COMPILER_RT_${TARCH}:=${CC_RT_GCC} 253GCC_COMPILER_RT_FLAGS_${TARCH}:=${CC_RT_EXTRA_GCC} 254EOF 255if [ "${TARCH}" = "x86_64" ]; then 256cat <<EOF 257 GCC_CFLAGS_${TARCH} += -malign-data=abi 258EOF 259fi 260cat <<EOF 261 262# Clang 263CLANG_CC_${TARCH} := ${CLANG} 264CLANG_CFLAGS_${TARCH} := ${CFLAGS_CLANG} 265CLANG_CFLAGS_${TARCH} += -Qunused-arguments 266CLANG_CFLAGS_${TARCH} += -m${TWIDTH} 267# tone down clang compiler warnings 268CLANG_CFLAGS_${TARCH} += -Wno-unused-variable 269CLANG_CFLAGS_${TARCH} += -Wno-unused-function 270CLANG_CFLAGS_${TARCH} += -Wno-tautological-compare 271CLANG_CFLAGS_${TARCH} += -Wno-shift-overflow 272CLANG_CFLAGS_${TARCH} += -Wno-address-of-packed-member 273CLANG_CFLAGS_${TARCH} += -Wno-initializer-overrides 274CLANG_CFLAGS_${TARCH} += -fbracket-depth=2048 275CLANG_CFLAGS_${TARCH} += -mllvm 276CLANG_CFLAGS_${TARCH} += -asm-macro-max-nesting-depth=1000 277CLANG_COMPILER_RT_${TARCH}:=${CC_RT_CLANG} 278CLANG_COMPILER_RT_FLAGS_${TARCH}:=${CC_RT_EXTRA_CLANG} 279# Leak the target arch into the preprocessor flags with clang. 280# This is needed to preprocess linker scripts 281CLANG_CPPFLAGS_${TARCH}:=${CPPFLAGS_CLANG} 282 283# GCC/Clang Common 284ifeq (\$(CONFIG_COMPILER_GCC)\$(CONFIG_LP_COMPILER_GCC),y) 285 CC_${TARCH}:=\$(GCC_CC_${TARCH}) 286 CFLAGS_${TARCH}:=\$(GCC_CFLAGS_${TARCH}) 287 COMPILER_RT_${TARCH}:=\$(GCC_COMPILER_RT_${TARCH}) 288 COMPILER_RT_FLAGS_${TARCH}:=\$(GCC_COMPILER_RT_FLAGS_${TARCH}) 289else 290 CC_${TARCH}:=\$(CLANG_CC_${TARCH}) 291 CFLAGS_${TARCH}:=\$(CLANG_CFLAGS_${TARCH}) 292 CPPFLAGS_${TARCH}:=\$(CLANG_CPPFLAGS_${TARCH}) 293 COMPILER_RT_${TARCH}:=\$(CLANG_COMPILER_RT_${TARCH}) 294 COMPILER_RT_FLAGS_${TARCH}:=\$(CLANG_COMPILER_RT_FLAGS_${TARCH}) 295endif 296EOF 297 298# Generally the x86 should build for i686 -- no sse/mmx 299# instructions since SMM modules are compiled using these 300# flags. Note that this doesn't prevent a project using 301# xcompile to explicitly specify -mmsse, etc flags. 302# The Quark processor doesn't support the instructions 303# introduced with the Pentium 6 architecture, so allow it 304# to use i586 instead. 305if [ "${TARCH}" = "x86_64" ]; then 306cat <<EOF 307 CFLAGS_${TARCH} += -march=nocona 308EOF 309fi 310 311if [ "${TARCH}" = "x86_32" ]; then 312cat <<EOF 313 314CFLAGS_${TARCH} += -march=i686 315EOF 316fi 317 318cat <<EOF 319 320CPP_${TARCH}:=${GCCPREFIX}cpp 321AS_${TARCH}:=${GCCPREFIX}as ${ASFLAGS} 322LD_${TARCH}:=${GCCPREFIX}ld${LINKER_SUFFIX} ${LDFLAGS} 323GCOV_${TARCH}:=${GCCPREFIX}gcov 324EOF 325 326 if [ "${TARCH}" = "arm64" ] && \ 327 [ -n "${LDFLAGS_ARM64_A53_ERRATUM_843419}" ]; then 328 cat <<EOF 329 330ifeq (\$(CONFIG_ARM64_A53_ERRATUM_843419),y) 331 LD_${TARCH}+=${LDFLAGS_ARM64_A53_ERRATUM_843419} 332endif 333 334EOF 335 fi # if [ "${TARCH}" = "arm64" ]... 336 337 cat <<EOF 338ifeq (\$(CONFIG_COMPILER_GCC)\$(CONFIG_LP_COMPILER_GCC),y) 339 NM_${TARCH}:=${GCCPREFIX}gcc-nm 340 AR_${TARCH}:=${GCCPREFIX}gcc-ar 341else 342 NM_${TARCH}:=${GCCPREFIX}nm 343 AR_${TARCH}:=${GCCPREFIX}ar 344endif 345OBJCOPY_${TARCH}:=${GCCPREFIX}objcopy 346OBJDUMP_${TARCH}:=${GCCPREFIX}objdump 347READELF_${TARCH}:=${GCCPREFIX}readelf 348STRIP_${TARCH}:=${GCCPREFIX}strip 349GNATBIND_${TARCH}:=${GCCPREFIX}gnatbind 350CROSS_COMPILE_${TARCH}:=${GCCPREFIX} 351 352 353EOF 354#The two blank lines above are intentional separators 355} 356 357# Architecture definitions 358SUPPORTED_ARCHITECTURES="arm arm64 riscv x64 x86 ppc64" 359 360# TARCH: local name for the architecture 361# (used as CC_${TARCH} in the build system) 362# TBFDARCHS: architecture name in binutils (eg elf32-${TBFDARCH}) 363# TCLIST: first part of the compiler triplet (eg i386 in i386-elf) 364# TWIDTH: numerical argument for cpu mode: gcc -m${TWIDTH} 365# TSUPP: supported subarchs (for -mcpu=...) 366# TABI: typically elf, eabi or linux 367 368arch_config_arm() { 369 TARCH="arm" 370 TBFDARCHS="littlearm" 371 TCLIST="armv7-a armv7a arm" 372 TWIDTH="32" 373 TSUPP="arm armv4 armv7 armv7_m armv7_r" 374 TABI="eabi" 375} 376 377arch_config_arm64() { 378 TARCH="arm64" 379 TBFDARCHS="littleaarch64" 380 TCLIST="aarch64" 381 TWIDTH="64" 382 TSUPP="arm64 armv8_64" 383 TABI="elf" 384} 385 386arch_config_riscv() { 387 TARCH="riscv" 388 TBFDARCHS="littleriscv" 389 TCLIST="riscv64 riscv" 390 TWIDTH="64" 391 TABI="elf" 392} 393 394arch_config_x64() { 395 TARCH="x86_64" 396 TBFDARCHS="x86-64" 397 TCLIST="x86_64" 398 TWIDTH="64" 399 TABI="elf" 400} 401 402arch_config_x86() { 403 TARCH="x86_32" 404 TBFDARCHS="i386" 405 TCLIST="i386 x86_64" 406 TWIDTH="32" 407 TABI="elf" 408 CC_RT_EXTRA_GCC="--wrap __divdi3 --wrap __udivdi3 --wrap __moddi3 --wrap __umoddi3" 409} 410 411arch_config_ppc64() { 412 TARCH="ppc64" 413 TBFDARCHS="powerpc" 414 TCLIST="powerpc64" 415 TWIDTH="64" 416 TSUPP="ppc64" 417 TABI="linux-gnu" # there is no generic ABI on ppc64 418 CC_RT_EXTRA_GCC="-mcpu=power8 -mbig-endian" 419} 420 421# Right now, the clang reference toolchain is not building compiler-rt builtins 422# for any of the cross compile architectures. Hence we use libgcc for now, 423# because that is available and lets us proceed with getting coreboot clang 424# ready. Toggle CLANG_RUNTIME if you want to experiment with compiler-rt. 425 426CLANG_RUNTIME="libgcc" 427# CLANG_RUNTIME="compiler-rt" 428 429test_architecture() { 430 local architecture=$1 431 local endian gccprefix search 432 433 GCCPREFIX="invalid" 434 unset TABI TARCH TBFDARCH TCLIST TENDIAN TSUPP TWIDTH 435 unset CC_RT_EXTRA_GCC CC_RT_EXTRA_CLANG 436 unset GCC CLANG 437 unset ARCH_SUFFIX 438 if type "arch_config_$architecture" > /dev/null; then 439 "arch_config_$architecture" 440 else 441 die "no architecture definition for $architecture" 442 fi 443 444 # To override toolchain, define CROSS_COMPILE_$arch or CROSS_COMPILE as 445 # environment variable. 446 # Ex: CROSS_COMPILE_arm="armv7a-cros-linux-gnueabi-" 447 # CROSS_COMPILE_x86="i686-pc-linux-gnu-" 448 search="$(eval echo "\$CROSS_COMPILE_$architecture" 2>/dev/null)" 449 search="$search $CROSS_COMPILE" 450 for toolchain in $TCLIST; do 451 search="$search $XGCCPATH$toolchain-$TABI-" 452 search="$search $toolchain-$TABI-" 453 search="$search $toolchain-linux-gnu-" 454 search="$search $toolchain-linux-" 455 search="$search $toolchain-" 456 search="$search $toolchain-linux-gnueabi-" 457 done 458 echo "###########################################################################" 459 echo "# $architecture" 460 echo "# TARCH_SEARCH=$search" 461 462 # Search toolchain by checking assembler capability. 463 for TBFDARCH in $TBFDARCHS; do 464 for gccprefix in $search "$GENERIC_COMPILER_PREFIX"; do 465 program_exists "${gccprefix}as" || continue 466 for endian in $TENDIAN ""; do 467 { testas "$gccprefix" "$TWIDTH" "$TBFDARCH" \ 468 "" "$endian" || 469 testas "$gccprefix" "$TWIDTH" "$TBFDARCH" \ 470 "TRUE" "$endian" ; } && \ 471 testcc "${gccprefix}gcc" "$CFLAGS_GCC" "$FLAGS_GCC" && \ 472 GCCPREFIX="$gccprefix" && \ 473 break 3 474 done 475 done 476 done 477 if [ "invalid" != "$GCCPREFIX" ]; then 478 GCC="${GCCPREFIX}gcc" 479 fi 480 481 for clang_arch in $TCLIST invalid; do 482 for clang_prefix in $search $XGCCPATH "$GENERIC_COMPILER_PREFIX"; do 483 testcc "${clang_prefix}clang" "-target ${clang_arch}-none-unknown-${TABI} -c" && break 2 484 done 485 done 486 487 if [ "invalid" != "$clang_arch" ]; then 488 # FIXME: this may break in a clang && !gcc configuration, 489 # but that's more of a clang limitation. Let's be optimistic 490 # that this will change in the future. 491 CLANG="${clang_prefix}clang" 492 CLANG_TARGET="-target ${clang_arch}-none-unknown-${TABI}" 493 CFLAGS_CLANG="$CLANG_TARGET $CFLAGS_CLANG" 494 CPPFLAGS_CLANG="$CLANG_TARGET $CPPFLAGS_CLANG" 495 fi 496} 497 498OUT="$(mktemp /tmp/temp.XXXXXX 2>/dev/null || echo /tmp/temp.coreboot.$RANDOM)" 499rm -f $OUT 500 501for architecture in $SUPPORTED_ARCHITECTURES; do 502 ( 503 TMPFILE="$(mktemp /tmp/temp.XXXXXX 2>/dev/null || echo /tmp/temp.coreboot.$RANDOM)" 504 touch $TMPFILE 505 test_architecture "$architecture" 506 detect_special_flags "$architecture" 507 detect_compiler_runtime "$architecture" 508 report_arch_toolchain 509 clean_up 510 ) > $OUT.$architecture & 511done 512wait 513 514for architecture in $SUPPORTED_ARCHITECTURES; do 515 cat $OUT.$architecture 516 rm -f $OUT.$architecture 517done 518echo XCOMPILE_COMPLETE:=1 519