This patch adds support to enable a linker workaround to a hardware erratum on some early Cortex-A53 revisions. Since the linker option was added very recently, we use xcompile to test whether the toolchain supports it first. It is also guarded by a Kconfig since only a few ARM64 SoCs will need this and it incurs a performance penalty. BRANCH=none BUG=none TEST=Turned it on or off for Smaug and confirmed that it (dis)appeared in verbose make output accordingly. Change-Id: I01c9642d3cf489134645f0db6f79f1c788ddb00d Signed-off-by: Patrick Georgi <patrick@georgi-clan.de> Original-Commit-Id: 57128785760c4dfa32d6e6d764756443a9323cb7 Original-Change-Id: Ia5dd124f484e38460d75fb864304e7e8b18d16b7 Original-Signed-off-by: Julius Werner <jwerner@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/294745 Original-Reviewed-by: Patrick Georgi <pgeorgi@chromium.org> Reviewed-on: http://review.coreboot.org/11403 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
		
			
				
	
	
		
			362 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			362 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env bash
 | |
| #
 | |
| # This file is part of the coreboot project.
 | |
| #
 | |
| # Copyright (C) 2007-2010 coresystems GmbH
 | |
| # Copyright (C) 2012 Google Inc
 | |
| #
 | |
| # 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.
 | |
| #
 | |
| # You should have received a copy of the GNU General Public License
 | |
| # along with this program; if not, write to the Free Software
 | |
| # Foundation, Inc.
 | |
| #
 | |
| 
 | |
| TMPFILE=""
 | |
| XGCCPATH=$1
 | |
| 
 | |
| # 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
 | |
| }
 | |
| 
 | |
| # Create temporary file(s).
 | |
| TMPFILE="$(mktemp /tmp/temp.XXXX 2>/dev/null || echo /tmp/temp.78gOIUGz)"
 | |
| touch "$TMPFILE"
 | |
| 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
 | |
| else
 | |
| 	die "no iasl found"
 | |
| fi
 | |
| 
 | |
| if program_exists gcc; then
 | |
| 	HOSTCC=gcc
 | |
| elif program_exists cc; then
 | |
| 	HOSTCC=cc
 | |
| else
 | |
| 	die "no host compiler found"
 | |
| fi
 | |
| 
 | |
| cat <<EOF
 | |
| # platform agnostic and host tools
 | |
| IASL:=${IASL}
 | |
| HOSTCC?=${HOSTCC}
 | |
| 
 | |
| EOF
 | |
| 
 | |
| testcc() {
 | |
| 	local tmp_c="$TMPFILE.c"
 | |
| 	local tmp_o="$TMPFILE.o"
 | |
| 	rm -f "$tmp_c" "$tmp_o"
 | |
| 	echo "void _start(void) {}" >"$tmp_c"
 | |
| 	$1 -nostdlib -Werror $2 -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 $1 $2 &&
 | |
| 	$3 -nostdlib -static $4 -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)"
 | |
| 	local obj_arch="$(expr "$obj_type" : '.*format \(.[a-z0-9-]*\)')"
 | |
| 	[ "$obj_arch" = "$full_arch" ] || return 1
 | |
| 
 | |
| 	# Architecture matched.
 | |
| 	GCCPREFIX="$gccprefix"
 | |
| 
 | |
| 	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_GCC -Wl,-b,elf32-i386 -Wl,-melf_i386"
 | |
| 			;;
 | |
| 	esac
 | |
| 
 | |
| 	return 0
 | |
| }
 | |
| 
 | |
| detect_special_flags() {
 | |
| 	local architecture="$1"
 | |
| 	# GCC 4.6 is much more picky about unused variables.
 | |
| 	# Turn off it's warnings for now:
 | |
| 	testcc "$GCC"      "$CFLAGS_GCC -Wno-unused-but-set-variable " &&
 | |
| 		CFLAGS_GCC="$CFLAGS_GCC -Wno-unused-but-set-variable "
 | |
| 
 | |
| 	# 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)
 | |
| 		# Always 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.
 | |
| 		CFLAGS_GCC="$CFLAGS_GCC  -march=i686"
 | |
| 		;;
 | |
| 	x64)
 | |
| 		;;
 | |
| 	arm64)
 | |
| 		testld "$GCC" "$CFLAGS_GCC" "${GCCPREFIX}ld${LINKER_SUFFIX}" \
 | |
| 		  "$LDFLAGS --fix-cortex-a53-843419" && \
 | |
| 		  LDFLAGS_ARM64_A53_ERRATUM_843419+=" --fix-cortex-a53-843419"
 | |
| 		;;
 | |
| 	mipsel)
 | |
| 		testcc "$GCC" "$CFLAGS_GCC -mno-abicalls -fno-pic" && \
 | |
| 		  CFLAGS_GCC+=" -mno-abicalls -fno-pic"
 | |
| 
 | |
|                 # Enforce little endian mode.
 | |
| 		testcc "$GCC" "$CFLAGS_GCC -EL" && \
 | |
| 		  CFLAGS_GCC+=" -EL"
 | |
| 		;;
 | |
| 	esac
 | |
| }
 | |
| 
 | |
| detect_compiler_runtime() {
 | |
| 	test -z "$CLANG" || \
 | |
| 	CC_RT_CLANG="`${CLANG} ${CFLAGS_CLANG} -print-librt-file-name 2>/dev/null`"
 | |
| 	test -z "$GCC" || \
 | |
| 	CC_RT_GCC="`${GCC} ${CFLAGS_GCC} -print-libgcc-file-name`"
 | |
| }
 | |
| 
 | |
| report_arch_toolchain() {
 | |
| 	cat <<EOF
 | |
| # elf${TWIDTH}-${TBFDARCH} toolchain (${GCC})
 | |
| ARCH_SUPPORTED+=${TARCH}
 | |
| SUBARCH_SUPPORTED+=${TSUPP-${TARCH}}
 | |
| ifeq (\$(CONFIG_COMPILER_GCC)\$(CONFIG_LP_COMPILER_GCC),y)
 | |
| CC_${TARCH}:=${GCC}
 | |
| CFLAGS_${TARCH}:=${CFLAGS_GCC}
 | |
| COMPILER_RT_${TARCH}:=${CC_RT_GCC}
 | |
| COMPILER_RT_FLAGS_${TARCH}:=${CC_RT_EXTRA_GCC}
 | |
| else
 | |
| CC_${TARCH}:=${CLANG}
 | |
| CFLAGS_${TARCH}:=${CFLAGS_CLANG}
 | |
| CFLAGS_${TARCH}+=-no-integrated-as -Qunused-arguments -m${TWIDTH}
 | |
| # tone down compiler warnings
 | |
| CFLAGS_${TARCH}+=-Wno-unused-variable -Wno-unused-function -Wno-tautological-compare -Wno-shift-overflow
 | |
| COMPILER_RT_${TARCH}:=${CC_RT_CLANG}
 | |
| COMPILER_RT_FLAGS_${TARCH}:=${CC_RT_EXTRA_CLANG}
 | |
| endif
 | |
| CPP_${TARCH}:=${GCCPREFIX}cpp
 | |
| AS_${TARCH}:=${GCCPREFIX}as ${ASFLAGS}
 | |
| LD_${TARCH}:=${GCCPREFIX}ld${LINKER_SUFFIX} ${LDFLAGS}
 | |
| ifeq (\$(CONFIG_ARM64_A53_ERRATUM_843419)\$(CONFIG_LP_ARM64_A53_ERRATUM_843419),y)
 | |
| LD_${TARCH}+=${LDFLAGS_ARM64_A53_ERRATUM_843419}
 | |
| endif
 | |
| NM_${TARCH}:=${GCCPREFIX}nm
 | |
| OBJCOPY_${TARCH}:=${GCCPREFIX}objcopy
 | |
| OBJDUMP_${TARCH}:=${GCCPREFIX}objdump
 | |
| READELF_${TARCH}:=${GCCPREFIX}readelf
 | |
| STRIP_${TARCH}:=${GCCPREFIX}strip
 | |
| AR_${TARCH}:=${GCCPREFIX}ar
 | |
| CROSS_COMPILE_${TARCH}:=${GCCPREFIX}
 | |
| 
 | |
| EOF
 | |
| }
 | |
| 
 | |
| # Architecture definitions
 | |
| SUPPORTED_ARCHITECTURES="arm arm64 mipsel riscv x64 x86"
 | |
| 
 | |
| arch_config_arm() {
 | |
| 	TARCH="arm"
 | |
| 	TBFDARCHS="littlearm"
 | |
| 	TCLIST="armv7-a armv7a"
 | |
| 	TWIDTH="32"
 | |
| 	TSUPP="arm armv4 armv7 armv7_m"
 | |
| 	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="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_mipsel() {
 | |
| 	TARCH="mips"
 | |
| 	TBFDARCHS="tradlittlemips littlemips"
 | |
| 	TCLIST="mipsel"
 | |
| 	TWIDTH="32"
 | |
| 	TSUPP="mips mipsel"
 | |
| 	TABI="elf"
 | |
| 	TENDIAN="EL"
 | |
| }
 | |
| 
 | |
| 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-"
 | |
| 	done
 | |
| 	echo "# $architecture 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" && break 3
 | |
| 				testas "$gccprefix" "$TWIDTH" "$TBFDARCH" \
 | |
| 					"TRUE" "$endian" && break 3
 | |
| 			done
 | |
| 		done
 | |
| 	done
 | |
| 	if [ "invalid" != "$GCCPREFIX" ]; then
 | |
| 		GCC="${GCCPREFIX}gcc"
 | |
| 	fi
 | |
| 
 | |
| 	for clang_arch in $TCLIST invalid; do
 | |
| 		testcc "clang" "-target ${clang_arch}-$TABI -c" && break
 | |
| 	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 -target ${clang_arch}-${TABI} -ccc-gcc-name ${GCC}"
 | |
| 	fi
 | |
| 
 | |
| 	if [ -z "$GCC" -a -z "$CLANG" ]; then
 | |
| 		echo "Warning: no suitable compiler for $architecture." >&2
 | |
| 		return 1
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| # This loops over all supported architectures.
 | |
| for architecture in $SUPPORTED_ARCHITECTURES; do
 | |
| 	if test_architecture $architecture; then
 | |
| 		detect_special_flags "$architecture"
 | |
| 		detect_compiler_runtime "$architecture"
 | |
| 		report_arch_toolchain
 | |
| 	fi
 | |
| done
 |