• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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