blob: 4fd7b626ab081e4a0062329444ab55c87261bba8 [file] [log] [blame]
Leonardo Sandoval9dfdd1b2020-08-06 17:08:11 -05001#!/usr/bin/env bash
Fathi Boudra422bf772019-12-02 11:10:16 +02002#
David Vincze82db6932024-02-21 12:05:50 +01003# Copyright (c) 2019-2024 Arm Limited. All rights reserved.
Fathi Boudra422bf772019-12-02 11:10:16 +02004#
5# SPDX-License-Identifier: BSD-3-Clause
6#
7
8# Builds a package with Trusted Firwmare and other payload binaries. The package
9# is meant to be executed by run_package.sh
10
11set -e
12
13ci_root="$(readlink -f "$(dirname "$0")/..")"
14source "$ci_root/utils.sh"
15
16if [ ! -d "$workspace" ]; then
17 die "Directory $workspace doesn't exist"
18fi
19
20# Directory to where the source code e.g. for Trusted Firmware is checked out.
Zelalem219df412020-05-17 19:21:20 -050021export tf_root="${tf_root:-$workspace/trusted_firmware}"
22export tftf_root="${tftf_root:-$workspace/trusted_firmware_tf}"
Zelalem219df412020-05-17 19:21:20 -050023cc_root="${cc_root:-$ccpathspec}"
Olivier Deprez0a9a3482019-12-16 14:10:31 +010024spm_root="${spm_root:-$workspace/spm}"
Zelalem219df412020-05-17 19:21:20 -050025
Fathi Boudra422bf772019-12-02 11:10:16 +020026# Refspecs
27tf_refspec="$TF_REFSPEC"
28tftf_refspec="$TFTF_REFSPEC"
Olivier Deprez0a9a3482019-12-16 14:10:31 +010029spm_refspec="$SPM_REFSPEC"
Fathi Boudra422bf772019-12-02 11:10:16 +020030
31test_config="${TEST_CONFIG:?}"
32test_group="${TEST_GROUP:?}"
33build_configs="${BUILD_CONFIG:?}"
34run_config="${RUN_CONFIG:?}"
Zelalem219df412020-05-17 19:21:20 -050035cc_config="${CC_ENABLE:-}"
Fathi Boudra422bf772019-12-02 11:10:16 +020036
37archive="$artefacts"
38build_log="$artefacts/build.log"
39fiptool="$tf_root/tools/fiptool/fiptool"
40cert_create="$tf_root/tools/cert_create/cert_create"
41
42# Validate $bin_mode
43case "$bin_mode" in
44 "" | debug | release)
45 ;;
46 *)
47 die "Invalid value for bin_mode: $bin_mode"
48 ;;
49esac
50
51# File to save any environem
52hook_env_file="$(mktempfile)"
53
54# Check if a config is valid
55config_valid() {
56 local config="${1?}"
57 if [ -z "$config" ] || [ "$(basename "$config")" = "nil" ]; then
58 return 1
59 fi
60
61 return 0
62}
63
64# Echo from a build wrapper. Print to descriptor 3 that's opened by the build
65# function.
66echo_w() {
67 echo $echo_flags "$@" >&3
68}
69
70# Print a separator to the log file. Intended to be used at the tail end of a pipe
71log_separator() {
72 {
73 echo
74 echo "----------"
75 } >> "$build_log"
76
77 tee -a "$build_log"
78
79 {
80 echo "----------"
81 echo
82 } >> "$build_log"
83}
84
85# Call function $1 if it's defined
86call_func() {
87 if type "${1:?}" &>/dev/null; then
88 echo
89 echo "> ${2:?}:$1()"
90 eval "$1"
91 echo "< $2:$1()"
92 fi
93}
94
Paul Sokolovskybe6510c2024-08-15 21:54:00 +030095# Retry a command a number of times if it fails. Intended for I/O commands
96# in a CI environment which may be flaky.
97function retry() {
98 for i in $(seq 1 3); do
99 if "$@"; then
100 return 0
101 fi
102 sleep $(( i * 5 ))
103 done
104 return 1
105}
106
Fathi Boudra422bf772019-12-02 11:10:16 +0200107# Call hook $1 in all chosen fragments if it's defined. Hooks are invoked from
108# within a subshell, so any variables set within a hook are lost. Should a
109# variable needs to be set from within a hook, the function 'set_hook_var'
110# should be used
111call_hook() {
112 local func="$1"
113 local config_fragment
114
115 [ -z "$func" ] && return 0
116
Paul Sokolovskye9962cd2021-12-17 18:39:40 +0300117 echo "=== Calling hooks: $1 ==="
118
Fathi Boudra422bf772019-12-02 11:10:16 +0200119 : >"$hook_env_file"
120
Nicola Mazzucato7fc5abd2024-02-23 21:32:48 +0000121 if [ "$run_config_candidates" ]; then
122 for config_fragment in $run_config_candidates; do
Fathi Boudra422bf772019-12-02 11:10:16 +0200123 (
124 source "$ci_root/run_config/$config_fragment"
125 call_func "$func" "$config_fragment"
126 )
127 done
128 fi
129
130 # Also source test config file
131 (
132 unset "$func"
133 source "$test_config_file"
134 call_func "$func" "$(basename $test_config_file)"
135 )
136
137 # Have any variables set take effect
138 source "$hook_env_file"
Paul Sokolovskye9962cd2021-12-17 18:39:40 +0300139
140 echo "=== End calling hooks: $1 ==="
Fathi Boudra422bf772019-12-02 11:10:16 +0200141}
142
143# Set a variable from within a hook
144set_hook_var() {
145 echo "export $1=\"${2?}\"" >> "$hook_env_file"
146}
147
148# Append to an array from within a hook
149append_hook_var() {
150 echo "export $1+=\"${2?}\"" >> "$hook_env_file"
151}
152
153# Have the main build script source a file
154source_later() {
155 echo "source ${1?}" >> "$hook_env_file"
156}
157
158# Setup TF build wrapper function by pointing to a script containing a function
159# that will be called with the TF build commands.
160setup_tf_build_wrapper() {
161 source_later "$ci_root/script/${wrapper?}_wrapper.sh"
162 set_hook_var "tf_build_wrapper" "${wrapper}_wrapper"
163 echo "Setup $wrapper build wrapper."
164}
165
166# Collect .bin files for archiving
167collect_build_artefacts() {
168 if [ ! -d "${from:?}" ]; then
169 return
170 fi
171
Yann Gautier7e9d6cf2023-03-08 14:24:38 +0100172 if ! find "$from" \( -name "*.bin" -o -name '*.elf' -o -name '*.dtb' -o -name '*.axf' -o -name '*.stm32' \) -exec cp -t "${to:?}" '{}' +; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200173 echo "You probably are running local CI on local repositories."
174 echo "Did you set 'dont_clean' but forgot to run 'distclean'?"
175 die
176 fi
177}
178
Manish Pandey1e7be852020-11-09 16:04:48 +0000179# Collect SPM/hafnium artefacts with "secure_" appended to the files
180# generated for SPM(secure hafnium).
181collect_spm_artefacts() {
Madhukar Pappireddyc683cf62021-11-01 14:38:32 -0500182 if [ -d "${non_secure_from:?}" ]; then
183 find "$non_secure_from" \( -name "*.bin" -o -name '*.elf' \) -exec cp -t "${to:?}" '{}' +
Manish Pandey1e7be852020-11-09 16:04:48 +0000184 fi
185
Madhukar Pappireddyc683cf62021-11-01 14:38:32 -0500186 if [ -d "${secure_from:?}" ]; then
187 for f in $(find "$secure_from" \( -name "*.bin" -o -name '*.elf' \)); do cp -- "$f" "${to:?}"/secure_$(basename $f); done
188 fi
Manish Pandey1e7be852020-11-09 16:04:48 +0000189}
190
Javier Almansa Sobrino412d3612020-05-22 17:53:12 +0100191# Map the UART ID used for expect with the UART descriptor and port
192# used by the FPGA automation tools.
193map_uart() {
194 local port="${port:?}"
195 local descriptor="${descriptor:?}"
196 local baudrate="${baudrate:?}"
197 local run_root="${archive:?}/run"
198
199 local uart_dir="$run_root/uart${uart:?}"
200 mkdir -p "$uart_dir"
201
202 echo "$port" > "$uart_dir/port"
203 echo "$descriptor" > "$uart_dir/descriptor"
204 echo "$baudrate" > "$uart_dir/baudrate"
205
206 echo "UART${uart} mapped to port ${port} with descriptor ${descriptor} and baudrate ${baudrate}"
207}
208
Fathi Boudra422bf772019-12-02 11:10:16 +0200209# Arrange environment varibles to be set when expect scripts are launched
210set_expect_variable() {
211 local var="${1:?}"
212 local val="${2?}"
213
214 local run_root="${archive:?}/run"
215 local uart_dir="$run_root/uart${uart:?}"
216 mkdir -p "$uart_dir"
217
218 env_file="$uart_dir/env" quote="1" emit_env "$var" "$val"
219 echo "UART$uart: env has $@"
220}
221
222# Place the binary package a pointer to expect script, and its parameters
223track_expect() {
224 local file="${file:?}"
225 local timeout="${timeout-600}"
226 local run_root="${archive:?}/run"
227
228 local uart_dir="$run_root/uart${uart:?}"
229 mkdir -p "$uart_dir"
230
231 echo "$file" > "$uart_dir/expect"
232 echo "$timeout" > "$uart_dir/timeout"
Paul Sokolovskybfa8bab2023-01-25 19:34:51 +0700233 if [ -n "$lava_timeout" ]; then
234 set_run_env "lava_timeout" "$lava_timeout"
235 fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200236
Paul Sokolovskybfa8bab2023-01-25 19:34:51 +0700237 echo "UART$uart to be tracked with $file; timeout ${timeout}s; lava_timeout ${lava_timeout:-N/A}s"
Fathi Boudra422bf772019-12-02 11:10:16 +0200238
Chris Kayfab6edc2022-11-17 19:18:32 +0000239 if [ ! -z "${port}" ]; then
240 echo "${port}" > "$uart_dir/port"
241 fi
242
Fathi Boudra422bf772019-12-02 11:10:16 +0200243 # The run script assumes UART0 to be primary. If we're asked to set any
244 # other UART to be primary, set a run environment variable to signal
245 # that to the run script
246 if upon "$set_primary"; then
247 echo "Primary UART set to UART$uart."
248 set_run_env "primary_uart" "$uart"
249 fi
Madhukar Pappireddy1e953722021-11-08 15:23:02 -0600250
251 # UART used by payload(such as tftf, Linux) may not be the same as the
252 # primary UART. Set a run environment variable to track the payload
253 # UART which is tracked to check if the test has finished sucessfully.
254 if upon "$set_payload_uart"; then
255 echo "Payload uses UART$uart."
256 set_run_env "payload_uart" "$uart"
257 fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200258}
259
260# Extract a FIP in $1 using fiptool
261extract_fip() {
262 local fip="$1"
263
264 if is_url "$1"; then
265 url="$1" fetch_file
266 fip="$(basename "$1")"
267 fi
268
269 "$fiptool" unpack "$fip"
270 echo "Extracted FIP: $fip"
271}
272
273# Report build failure by printing a the tail end of build log. Archive the
274# build log for later inspection
275fail_build() {
276 local log_path
277
278 if upon "$jenkins_run"; then
279 log_path="$BUILD_URL/artifact/artefacts/build.log"
280 else
281 log_path="$build_log"
282 fi
283
284 echo
Leonardo Sandovalae97eda2020-11-12 10:07:03 -0600285 echo "Build failed! Full build log below:"
Fathi Boudra422bf772019-12-02 11:10:16 +0200286 echo "[...]"
287 echo
Leonardo Sandovalae97eda2020-11-12 10:07:03 -0600288 cat "$build_log"
Fathi Boudra422bf772019-12-02 11:10:16 +0200289 echo
290 echo "See $log_path for full output"
291 echo
292 cp -t "$archive" "$build_log"
293 exit 1;
294}
295
296# Build a FIP with supplied arguments
297build_fip() {
298 (
299 echo "Building FIP with arguments: $@"
300 local tf_env="$workspace/tf.env"
301
302 if [ -f "$tf_env" ]; then
303 set -a
304 source "$tf_env"
305 set +a
306 fi
307
308 make -C "$tf_root" $(cat "$tf_config_file") DEBUG="$DEBUG" V=1 "$@" \
309 ${fip_targets:-fip} &>>"$build_log" || fail_build
310 )
311}
312
Sandrine Bailleux189fdb32023-10-20 13:41:22 +0200313# Build any extra rule from TF-A makefile with supplied arguments.
314#
315# This is useful in case you need to build something else than firmware binaries
316# or the FIP.
317build_tf_extra() {
318 (
319 tf_extra_rules=${tf_extra_rules:?}
320 echo "Building extra TF rule(s): $tf_extra_rules"
321 echo " Arguments: $@"
322
323 local tf_env="$workspace/tf.env"
324
325 if [ -f "$tf_env" ]; then
326 set -a
327 source "$tf_env"
328 set +a
329 fi
330
331 make -C "$tf_root" $(cat "$tf_config_file") DEBUG="$DEBUG" V=1 "$@" \
332 ${tf_extra_rules} &>>"$build_log" || fail_build
333 )
334}
335
Fathi Boudra422bf772019-12-02 11:10:16 +0200336fip_update() {
337 # Before the update process, check if the given image is supported by
338 # the fiptool. It's assumed that both fiptool and cert_create move in
Chris Kay197b1022023-08-16 21:31:41 +0100339 # tandem, and therefore, if one has support, the other has it too.
340 if ! ("$fiptool" update 2>&1 || true) | grep -qe "\s\+--${bin_name:?}"; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200341 return 1
342 fi
343
344 if not_upon "$(get_tf_opt TRUSTED_BOARD_BOOT)"; then
345 echo "Updating FIP image: $bin_name"
346 # Update HW config. Without TBBR, it's only a matter of using
347 # the update sub-command of fiptool
348 "$fiptool" update "--$bin_name" "${src:-}" \
349 "$archive/fip.bin"
350 else
351 echo "Updating FIP image (TBBR): $bin_name"
352 # With TBBR, we need to unpack, re-create certificates, and then
353 # recreate the FIP.
354 local fip_dir="$(mktempdir)"
355 local bin common_args stem
356 local rot_key="$(get_tf_opt ROT_KEY)"
357
358 rot_key="${rot_key:?}"
359 if ! is_abs "$rot_key"; then
360 rot_key="$tf_root/$rot_key"
361 fi
362
363 # Arguments only for cert_create
364 local cert_args="-n"
365 cert_args+=" --tfw-nvctr ${nvctr:-31}"
366 cert_args+=" --ntfw-nvctr ${nvctr:-223}"
367 cert_args+=" --key-alg ${KEY_ALG:-rsa}"
368 cert_args+=" --rot-key $rot_key"
369
370 local dyn_config_opts=(
Zelalem1af7a7b2020-08-04 17:34:32 -0500371 "fw-config"
Fathi Boudra422bf772019-12-02 11:10:16 +0200372 "hw-config"
373 "tb-fw-config"
374 "nt-fw-config"
375 "soc-fw-config"
376 "tos-fw-config"
377 )
378
379 # Binaries without key certificates
380 declare -A has_no_key_cert
381 for bin in "tb-fw" "${dyn_config_opts[@]}"; do
382 has_no_key_cert["$bin"]="1"
383 done
384
385 # Binaries without certificates
386 declare -A has_no_cert
387 for bin in "hw-config" "${dyn_config_opts[@]}"; do
388 has_no_cert["$bin"]="1"
389 done
390
391 pushd "$fip_dir"
392
393 # Unpack FIP
394 "$fiptool" unpack "$archive/fip.bin" &>>"$build_log"
395
396 # Remove all existing certificates
397 rm -f *-cert.bin
398
399 # Copy the binary to be updated
400 cp -f "$src" "${bin_name}.bin"
401
402 # FIP unpack dumps binaries with the same name as the option
403 # used to pack it; likewise for certificates. Reverse-engineer
404 # the command line from the binary output.
405 common_args="--trusted-key-cert trusted_key.crt"
406 for bin in *.bin; do
407 stem="${bin%%.bin}"
408 common_args+=" --$stem $bin"
409 if not_upon "${has_no_cert[$stem]}"; then
410 common_args+=" --$stem-cert $stem.crt"
411 fi
412 if not_upon "${has_no_key_cert[$stem]}"; then
413 common_args+=" --$stem-key-cert $stem-key.crt"
414 fi
415 done
416
417 # Create certificates
418 "$cert_create" $cert_args $common_args &>>"$build_log"
419
420 # Recreate and archive FIP
421 "$fiptool" create $common_args "fip.bin" &>>"$build_log"
422 archive_file "fip.bin"
423
424 popd
425 fi
426}
427
428# Update hw-config in FIP, and remove the original DTB afterwards.
429update_fip_hw_config() {
430 # The DTB needs to be loaded by the model (and not updated in the FIP)
Madhukar Pappireddy9062ebf2021-03-02 17:07:06 -0600431 # in configs:
432 # 1. Where BL2 isn't present
433 # 2. Where we boot to Linux directly as BL33
Fathi Boudra422bf772019-12-02 11:10:16 +0200434 case "1" in
435 "$(get_tf_opt RESET_TO_BL31)" | \
Madhukar Pappireddy9062ebf2021-03-02 17:07:06 -0600436 "$(get_tf_opt ARM_LINUX_KERNEL_AS_BL33)" | \
Fathi Boudra422bf772019-12-02 11:10:16 +0200437 "$(get_tf_opt RESET_TO_SP_MIN)" | \
Maksims Svecovs7a0da522023-03-06 16:28:27 +0000438 "$(get_tf_opt RESET_TO_BL2)")
Fathi Boudra422bf772019-12-02 11:10:16 +0200439 return 0;;
440 esac
441
442 if bin_name="hw-config" src="$archive/dtb.bin" fip_update; then
443 # Remove the DTB so that model won't load it
444 rm -f "$archive/dtb.bin"
445 fi
446}
447
Fathi Boudra422bf772019-12-02 11:10:16 +0200448get_tftf_opt() {
449 (
450 name="${1:?}"
451 if config_valid "$tftf_config_file"; then
452 source "$tftf_config_file"
453 echo "${!name}"
454 fi
455 )
456}
457
458get_tf_opt() {
459 (
460 name="${1:?}"
461 if config_valid "$tf_config_file"; then
462 source "$tf_config_file"
463 echo "${!name}"
464 fi
465 )
466}
467
468build_tf() {
469 (
470 env_file="$workspace/tf.env"
471 config_file="${tf_build_config:-$tf_config_file}"
472
473 # Build fiptool and all targets by default
Harrison Mutai32de9d02023-06-12 14:23:37 +0100474 build_targets="${tf_build_targets:-fiptool all}"
Fathi Boudra422bf772019-12-02 11:10:16 +0200475
476 source "$config_file"
477
478 # If it is a TBBR build, extract the MBED TLS library from archive
Manish V Badarkhe8f125012021-12-21 05:47:52 +0000479 if [ "$(get_tf_opt TRUSTED_BOARD_BOOT)" = 1 ] ||
Manish V Badarkhef43e3f52022-06-21 20:37:25 +0100480 [ "$(get_tf_opt MEASURED_BOOT)" = 1 ] ||
481 [ "$(get_tf_opt DRTM_SUPPORT)" = 1 ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +0200482 mbedtls_dir="$workspace/mbedtls"
483 if [ ! -d "$mbedtls_dir" ]; then
484 mbedtls_ar="$workspace/mbedtls.tar.gz"
485
486 url="$mbedtls_archive" saveas="$mbedtls_ar" fetch_file
487 mkdir "$mbedtls_dir"
Leonardo Sandovalec9e16c2020-09-09 14:32:40 -0500488 extract_tarball $mbedtls_ar $mbedtls_dir --strip-components=1
Fathi Boudra422bf772019-12-02 11:10:16 +0200489 fi
490
491 emit_env "MBEDTLS_DIR" "$mbedtls_dir"
492 fi
Jimmy Brisson0d5e12c2023-05-16 14:51:51 -0500493 if [ "$(get_tf_opt PLATFORM_TEST)" = "tfm-testsuite" ] &&
494 not_upon "${TF_M_TESTS_PATH}"; then
495 emit_env "TF_M_TESTS_PATH" "$WORKSPACE/tf-m-tests"
496 fi
497 if [ "$(get_tf_opt PLATFORM_TEST)" = "tfm-testsuite" ] &&
498 not_upon "${TF_M_EXTRAS_PATH}"; then
499 emit_env "TF_M_EXTRAS_PATH" "$WORKSPACE/tf-m-extras"
500 fi
David Vincze82db6932024-02-21 12:05:50 +0100501 if [ "$(get_tf_opt DICE_PROTECTION_ENVIRONMENT)" = 1 ] &&
502 not_upon "${QCBOR_DIR}"; then
503 emit_env "QCBOR_DIR" "$WORKSPACE/qcbor"
504 fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200505 if [ -f "$env_file" ]; then
506 set -a
507 source "$env_file"
508 set +a
509 fi
510
Harrison Mutai013f6332022-02-16 16:06:33 +0000511 if is_arm_jenkins_env || upon "$local_ci"; then
512 path_list=(
513 "$llvm_dir/bin"
514 )
515 extend_path "PATH" "path_list"
516 fi
517
Fathi Boudra422bf772019-12-02 11:10:16 +0200518 cd "$tf_root"
519
520 # Always distclean when running on Jenkins. Skip distclean when running
521 # locally and explicitly requested.
522 if upon "$jenkins_run" || not_upon "$dont_clean"; then
523 make distclean &>>"$build_log" || fail_build
524 fi
525
526 # Log build command line. It is left unfolded on purpose to assist
527 # copying to clipboard.
528 cat <<EOF | log_separator >/dev/null
529
530Build command line:
531 $tf_build_wrapper make $make_j_opts $(cat "$config_file" | tr '\n' ' ') DEBUG=$DEBUG V=1 $build_targets
532
Paul Sokolovsky7f71b072023-10-16 12:59:09 +0300533CC version:
534$(${CC-${CROSS_COMPILE}gcc} -v 2>&1)
Fathi Boudra422bf772019-12-02 11:10:16 +0200535EOF
536
Javier Almansa Sobrinoe8363182020-11-10 16:40:53 +0000537 if not_upon "$local_ci"; then
538 connect_debugger=0
539 fi
540
Fathi Boudra422bf772019-12-02 11:10:16 +0200541 # Build TF. Since build output is being directed to the build log, have
542 # descriptor 3 point to the current terminal for build wrappers to vent.
Harrison Mutai6361dbe2023-02-16 14:12:40 +0000543 $tf_build_wrapper poetry run make $make_j_opts $(cat "$config_file") \
Javier Almansa Sobrinoe8363182020-11-10 16:40:53 +0000544 DEBUG="$DEBUG" V=1 SPIN_ON_BL1_EXIT="$connect_debugger" \
Fathi Boudra422bf772019-12-02 11:10:16 +0200545 $build_targets 3>&1 &>>"$build_log" || fail_build
Harrison Mutai32de9d02023-06-12 14:23:37 +0100546
Harrison Mutai6dafb5f2023-07-18 15:21:48 +0100547 if [ "$build_targets" != "doc" ]; then
Harrison Mutai2c2c9172024-04-12 11:24:27 +0000548 (poetry run memory -sr "$tf_build_root" 2>&1 || true) | tee -a "$build_log"
Harrison Mutai6dafb5f2023-07-18 15:21:48 +0100549 fi
Fathi Boudra422bf772019-12-02 11:10:16 +0200550 )
551}
552
553build_tftf() {
554 (
555 config_file="${tftf_build_config:-$tftf_config_file}"
556
557 # Build tftf target by default
558 build_targets="${tftf_build_targets:-all}"
559
560 source "$config_file"
561
562 cd "$tftf_root"
563
564 # Always distclean when running on Jenkins. Skip distclean when running
565 # locally and explicitly requested.
566 if upon "$jenkins_run" || not_upon "$dont_clean"; then
567 make distclean &>>"$build_log" || fail_build
568 fi
569
570 # TFTF build system cannot reliably deal with -j option, so we avoid
571 # using that.
572
573 # Log build command line
574 cat <<EOF | log_separator >/dev/null
575
576Build command line:
577 make $(cat "$config_file" | tr '\n' ' ') DEBUG=$DEBUG V=1 $build_targets
578
579EOF
580
581 make $(cat "$config_file") DEBUG="$DEBUG" V=1 \
582 $build_targets &>>"$build_log" || fail_build
583 )
584}
585
Zelalem219df412020-05-17 19:21:20 -0500586build_cc() {
587# Building code coverage plugin
588 ARM_DIR=/arm
589 pvlibversion=$(/arm/devsys-tools/abs/detag "SysGen:PVModelLib:$model_version::trunk")
590 PVLIB_HOME=$warehouse/SysGen/PVModelLib/$model_version/${pvlibversion}/external
591 if [ -n "$(find "$ARM_DIR" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
592 echo "Error: Arm warehouse not mounted. Please mount the Arm warehouse to your /arm local folder"
593 exit -1
594 fi # Error if arm warehouse not found
595 cd "$ccpathspec/scripts/tools/code_coverage/fastmodel_baremetal/bmcov"
596
597 make -C model-plugin PVLIB_HOME=$PVLIB_HOME &>>"$build_log"
598}
599
Olivier Deprez0a9a3482019-12-16 14:10:31 +0100600build_spm() {
601 (
602 env_file="$workspace/spm.env"
603 config_file="${spm_build_config:-$spm_config_file}"
604
605 source "$config_file"
606
607 if [ -f "$env_file" ]; then
608 set -a
609 source "$env_file"
610 set +a
611 fi
612
613 cd "$spm_root"
614
615 # Always clean when running on Jenkins. Skip clean when running
616 # locally and explicitly requested.
617 if upon "$jenkins_run" || not_upon "$dont_clean"; then
618 # make clean fails on a fresh repo where the project has not
619 # yet been built. Hence only clean if out/reference directory
620 # already exists.
621 if [ -d "out/reference" ]; then
622 make clean &>>"$build_log" || fail_build
623 fi
624 fi
625
626 # Log build command line. It is left unfolded on purpose to assist
627 # copying to clipboard.
628 cat <<EOF | log_separator >/dev/null
629
630Build command line:
631 make $make_j_opts $(cat "$config_file" | tr '\n' ' ')
632
633EOF
634
635 # Build SPM. Since build output is being directed to the build log, have
636 # descriptor 3 point to the current terminal for build wrappers to vent.
637 make $make_j_opts $(cat "$config_file") 3>&1 &>>"$build_log" \
638 || fail_build
639 )
640}
Zelalem219df412020-05-17 19:21:20 -0500641
Fathi Boudra422bf772019-12-02 11:10:16 +0200642# Set metadata for the whole package so that it can be used by both Jenkins and
643# shell
644set_package_var() {
645 env_file="$artefacts/env" emit_env "$@"
646}
647
648set_tf_build_targets() {
649 echo "Set build target to '${targets:?}'"
650 set_hook_var "tf_build_targets" "$targets"
651}
652
653set_tftf_build_targets() {
654 echo "Set build target to '${targets:?}'"
655 set_hook_var "tftf_build_targets" "$targets"
656}
657
Olivier Deprez0a9a3482019-12-16 14:10:31 +0100658set_spm_build_targets() {
659 echo "Set build target to '${targets:?}'"
660 set_hook_var "spm_build_targets" "$targets"
661}
662
Daniel Boulbyb8d2a462022-03-07 13:55:25 +0000663set_spm_out_dir() {
664 echo "Set SPMC binary build to '${out_dir:?}'"
665 set_hook_var "spm_secure_out_dir" "$out_dir"
666}
Fathi Boudra422bf772019-12-02 11:10:16 +0200667# Look under $archive directory for known files such as blX images, kernel, DTB,
668# initrd etc. For each known file foo, if foo.bin exists, then set variable
669# foo_bin to the path of the file. Make the path relative to the workspace so as
670# to remove any @ characters, which Jenkins inserts for parallel runs. If the
671# file doesn't exist, unset its path.
672set_default_bin_paths() {
673 local image image_name image_path path
674 local archive="${archive:?}"
675 local set_vars
676 local var
677
678 pushd "$archive"
679
680 for file in *.bin; do
681 # Get a shell variable from the file's stem
682 var_name="${file%%.*}_bin"
683 var_name="$(echo "$var_name" | sed -r 's/[^[:alnum:]]/_/g')"
684
685 # Skip setting the variable if it's already
686 if [ "${!var_name}" ]; then
687 echo "Note: not setting $var_name; already set to ${!var_name}"
688 continue
689 else
690 set_vars+="$var_name "
691 fi
692
693 eval "$var_name=$file"
694 done
695
696 echo "Binary paths set for: "
697 {
698 for var in $set_vars; do
699 echo -n "\$$var "
700 done
701 } | fmt -80 | sed 's/^/ /'
702 echo
703
704 popd
705}
706
707gen_model_params() {
708 local model_param_file="$archive/model_params"
Javier Almansa Sobrinoe8363182020-11-10 16:40:53 +0000709 [ "$connect_debugger" ] && [ "$connect_debugger" -eq 1 ] && wait_debugger=1
Fathi Boudra422bf772019-12-02 11:10:16 +0200710
711 set_default_bin_paths
712 echo "Generating model parameter for $model..."
713 source "$ci_root/model/${model:?}.sh"
714 archive_file "$model_param_file"
715}
716
717set_model_path() {
718 set_run_env "model_path" "${1:?}"
719}
720
Zelalem1af7a7b2020-08-04 17:34:32 -0500721set_model_env() {
722 local var="${1:?}"
723 local val="${2?}"
724 local run_root="${archive:?}/run"
725
726 mkdir -p "$run_root"
727 echo "export $var=$val" >> "$run_root/model_env"
728}
Fathi Boudra422bf772019-12-02 11:10:16 +0200729set_run_env() {
730 local var="${1:?}"
731 local val="${2?}"
732 local run_root="${archive:?}/run"
733
734 mkdir -p "$run_root"
735 env_file="$run_root/env" quote="1" emit_env "$var" "$val"
736}
737
738show_head() {
739 # Display HEAD descripton
740 pushd "$1"
741 git show --quiet --no-color | sed 's/^/ > /g'
742 echo
743 popd
744}
745
746# Choose debug binaries to run; by default, release binaries are chosen to run
747use_debug_bins() {
748 local run_root="${archive:?}/run"
749
750 echo "Choosing debug binaries for execution"
751 set_package_var "BIN_MODE" "debug"
752}
753
754assert_can_git_clone() {
755 local name="${1:?}"
756 local dir="${!name}"
757
758 # If it doesn't exist, it can be cloned into
759 if [ ! -e "$dir" ]; then
760 return 0
761 fi
762
763 # If it's a directory, it must be a Git clone already
764 if [ -d "$dir" ] && [ -d "$dir/.git" ]; then
765 # No need to clone again
766 echo "Using existing git clone for $name: $dir"
767 return 1
768 fi
769
770 die "Path $dir exists but is not a git clone"
771}
772
773clone_repo() {
774 if ! is_url "${clone_url?}"; then
775 # For --depth to take effect on local paths, it needs to use the
776 # file:// scheme.
777 clone_url="file://$clone_url"
778 fi
779
780 git clone -q --depth 1 "$clone_url" "${where?}"
781 if [ "$refspec" ]; then
782 pushd "$where"
783 git fetch -q --depth 1 origin "$refspec"
784 git checkout -q FETCH_HEAD
785 popd
786 fi
787}
788
789build_unstable() {
790 echo "--BUILD UNSTABLE--" | tee -a "$build_log"
791}
792
793undo_patch_record() {
794 if [ ! -f "${patch_record:?}" ]; then
795 return
796 fi
797
798 # Undo patches in reverse
799 echo
800 for patch_name in $(tac "$patch_record"); do
801 echo "Undoing $patch_name..."
802 if ! git apply -R "$ci_root/patch/$patch_name"; then
803 if upon "$local_ci"; then
804 echo
805 echo "Your local directory may have been dirtied."
806 echo
807 fi
808 fail_build
809 fi
810 done
811
812 rm -f "$patch_record"
813}
814
815undo_local_patches() {
816 pushd "$tf_root"
817 patch_record="$tf_patch_record" undo_patch_record
818 popd
819
820 if [ -d "$tftf_root" ]; then
821 pushd "$tftf_root"
822 patch_record="$tftf_patch_record" undo_patch_record
823 popd
824 fi
825}
826
827undo_tftf_patches() {
828 pushd "$tftf_root"
829 patch_record="$tftf_patch_record" undo_patch_record
830 popd
831}
832
833undo_tf_patches() {
834 pushd "$tf_root"
835 patch_record="$tf_patch_record" undo_patch_record
836 popd
837}
838
839apply_patch() {
840 # If skip_patches is set, the developer has applied required patches
841 # manually. They probably want to keep them applied for debugging
842 # purposes too. This means we don't have to apply/revert them as part of
843 # build process.
844 if upon "$skip_patches"; then
845 echo "Skipped applying ${1:?}..."
846 return 0
847 else
848 echo "Applying ${1:?}..."
849 fi
850
Sandrine Bailleux4cb8c222023-09-13 13:48:15 +0200851 if git apply --reverse --check < "$ci_root/patch/$1" 2> /dev/null; then
Jimmy Brissonf134e4c2023-03-22 13:20:20 -0500852 echo "Skipping already applied ${1:?}"
853 return 0
854 fi
855
Fathi Boudra422bf772019-12-02 11:10:16 +0200856 if git apply < "$ci_root/patch/$1"; then
857 echo "$1" >> "${patch_record:?}"
858 else
859 if upon "$local_ci"; then
860 undo_local_patches
861 fi
862 fail_build
863 fi
864}
865
866apply_tftf_patch() {
867 pushd "$tftf_root"
868 patch_record="$tftf_patch_record" apply_patch "$1"
869 popd
870}
871
872apply_tf_patch() {
873 pushd "$tf_root"
874 patch_record="$tf_patch_record" apply_patch "$1"
875 popd
876}
877
878# Clear workspace for a local run
879if not_upon "$jenkins_run"; then
880 rm -rf "$workspace"
881
882 # Clear residue from previous runs
883 rm -rf "$archive"
884fi
885
886mkdir -p "$workspace"
887mkdir -p "$archive"
888set_package_var "TEST_CONFIG" "$test_config"
889
890{
891echo
892echo "CONFIGURATION: $test_group/$test_config"
893echo
894} |& log_separator
895
896tf_config="$(echo "$build_configs" | awk -F, '{print $1}')"
897tftf_config="$(echo "$build_configs" | awk -F, '{print $2}')"
Chris Kay19f8b362025-08-04 19:56:35 +0100898spm_config="$(echo "$build_configs" | awk -F, '{print $3}')"
Fathi Boudra422bf772019-12-02 11:10:16 +0200899
900test_config_file="$ci_root/group/$test_group/$test_config"
901
902tf_config_file="$ci_root/tf_config/$tf_config"
903tftf_config_file="$ci_root/tftf_config/$tftf_config"
Olivier Deprez0a9a3482019-12-16 14:10:31 +0100904spm_config_file="$ci_root/spm_config/$spm_config"
Fathi Boudra422bf772019-12-02 11:10:16 +0200905
906# File that keeps track of applied patches
907tf_patch_record="$workspace/tf_patches"
908tftf_patch_record="$workspace/tftf_patches"
909
910pushd "$workspace"
911
912if ! config_valid "$tf_config"; then
913 tf_config=
914else
915 echo "Trusted Firmware config:"
916 echo
917 sort "$tf_config_file" | sed '/^\s*$/d;s/^/\t/'
918 echo
919fi
920
921if ! config_valid "$tftf_config"; then
922 tftf_config=
923else
924 echo "Trusted Firmware TF config:"
925 echo
926 sort "$tftf_config_file" | sed '/^\s*$/d;s/^/\t/'
927 echo
928fi
929
Olivier Deprez0a9a3482019-12-16 14:10:31 +0100930if ! config_valid "$spm_config"; then
931 spm_config=
932else
933 echo "SPM config:"
934 echo
935 sort "$spm_config_file" | sed '/^\s*$/d;s/^/\t/'
Zelalem219df412020-05-17 19:21:20 -0500936 echo
937fi
938
Fathi Boudra422bf772019-12-02 11:10:16 +0200939if ! config_valid "$run_config"; then
940 run_config=
941fi
942
943if [ "$tf_config" ] && assert_can_git_clone "tf_root"; then
944 # If the Trusted Firmware repository has already been checked out, use
945 # that location. Otherwise, clone one ourselves.
946 echo "Cloning Trusted Firmware..."
947 clone_url="${TF_CHECKOUT_LOC:-$tf_src_repo_url}" where="$tf_root" \
948 refspec="$TF_REFSPEC" clone_repo &>>"$build_log"
949 show_head "$tf_root"
950fi
951
952if [ "$tftf_config" ] && assert_can_git_clone "tftf_root"; then
953 # If the Trusted Firmware TF repository has already been checked out,
954 # use that location. Otherwise, clone one ourselves.
955 echo "Cloning Trusted Firmware TF..."
956 clone_url="${TFTF_CHECKOUT_LOC:-$tftf_src_repo_url}" where="$tftf_root" \
957 refspec="$TFTF_REFSPEC" clone_repo &>>"$build_log"
958 show_head "$tftf_root"
959fi
960
Zelalem219df412020-05-17 19:21:20 -0500961if [ -n "$cc_config" ] ; then
962 if [ "$cc_config" -eq 1 ] && assert_can_git_clone "cc_root"; then
963 # Copy code coverage repository
964 echo "Cloning Code Coverage..."
965 git clone -q $cc_src_repo_url cc_plugin --depth 1 -b $cc_src_repo_tag > /dev/null
966 show_head "$cc_root"
967 fi
968fi
969
Daniel Boulby25385ab2023-12-14 14:36:25 +0000970if [ "$spm_config" ] ; then
971 if assert_can_git_clone "spm_root"; then
972 # If the SPM repository has already been checked out, use
973 # that location. Otherwise, clone one ourselves.
974 echo "Cloning SPM..."
975 clone_url="${SPM_CHECKOUT_LOC:-$spm_src_repo_url}" \
976 where="$spm_root" refspec="$SPM_REFSPEC" \
977 clone_repo &>>"$build_log"
978 fi
Olivier Deprez0a9a3482019-12-16 14:10:31 +0100979
980 # Query git submodules
981 pushd "$spm_root"
Daniel Boulby25385ab2023-12-14 14:36:25 +0000982 # Check if submodules need initialising
Paul Sokolovskyad274422024-09-01 10:27:56 +0300983
984 # This handling is needed to reliably fetch submodules
985 # in CI environment.
986 for subm in $(git submodule status | awk '/^-/ {print $2}'); do
987 for i in $(seq 1 7); do
988 git submodule init $subm
989 if git submodule update $subm; then
990 break
991 fi
992 git submodule deinit --force $subm
993 echo "Retrying $subm"
994 sleep $((RANDOM % 10 + 5))
995 done
996 done
997
998 git submodule status
Olivier Deprez0a9a3482019-12-16 14:10:31 +0100999 popd
1000
1001 show_head "$spm_root"
1002fi
1003
Fathi Boudra422bf772019-12-02 11:10:16 +02001004if [ "$run_config" ]; then
1005 # Get candidates for run config
Nicola Mazzucato7fc5abd2024-02-23 21:32:48 +00001006 run_config_candidates="$("$ci_root/script/gen_run_config_candidates.py" \
Fathi Boudra422bf772019-12-02 11:10:16 +02001007 "$run_config")"
Nicola Mazzucato7fc5abd2024-02-23 21:32:48 +00001008 if [ -z "$run_config_candidates" ]; then
Fathi Boudra422bf772019-12-02 11:10:16 +02001009 die "No run config candidates!"
1010 else
1011 echo
1012 echo "Chosen fragments:"
1013 echo
Nicola Mazzucato7fc5abd2024-02-23 21:32:48 +00001014 echo "$run_config_candidates" | sed 's/^\|\n/\t/g'
Fathi Boudra422bf772019-12-02 11:10:16 +02001015 echo
1016 fi
1017fi
1018
1019call_hook "test_setup"
1020echo
1021
1022if upon "$local_ci"; then
1023 # For local runs, since each config is tried in sequence, it's
1024 # advantageous to run jobs in parallel
1025 if [ "$make_j" ]; then
1026 make_j_opts="-j $make_j"
1027 else
1028 n_cores="$(getconf _NPROCESSORS_ONLN)" 2>/dev/null || true
1029 if [ "$n_cores" ]; then
1030 make_j_opts="-j $n_cores"
1031 fi
1032 fi
1033fi
1034
Harrison Mutai07043e92023-07-06 09:41:12 +01001035# Install python build dependencies
1036if is_arm_jenkins_env; then
1037 source "$ci_root/script/install_python_deps.sh"
1038fi
1039
Fathi Boudra422bf772019-12-02 11:10:16 +02001040modes="${bin_mode:-debug release}"
1041for mode in $modes; do
Paul Sokolovskye9962cd2021-12-17 18:39:40 +03001042 echo "===== Building package in mode: $mode ====="
Fathi Boudra422bf772019-12-02 11:10:16 +02001043 # Build with a temporary archive
1044 build_archive="$archive/$mode"
1045 mkdir "$build_archive"
1046
1047 if [ "$mode" = "debug" ]; then
Zelalem219df412020-05-17 19:21:20 -05001048 export bin_mode="debug"
Fathi Boudra422bf772019-12-02 11:10:16 +02001049 DEBUG=1
1050 else
Zelalem219df412020-05-17 19:21:20 -05001051 export bin_mode="release"
Fathi Boudra422bf772019-12-02 11:10:16 +02001052 DEBUG=0
1053 fi
1054
1055 # Perform builds in a subshell so as not to pollute the current and
1056 # subsequent builds' environment
1057
Zelalem219df412020-05-17 19:21:20 -05001058 if config_valid "$cc_config"; then
1059 # Build code coverage plugin
1060 build_cc
1061 fi
1062
Fathi Boudra422bf772019-12-02 11:10:16 +02001063 # TFTF build
1064 if config_valid "$tftf_config"; then
1065 (
1066 echo "##########"
1067
Manish V Badarkhe3bd3fea2020-11-08 15:17:00 +00001068 plat_utils="$(get_tf_opt PLAT_UTILS)"
1069 if [ -z ${plat_utils} ]; then
1070 # Source platform-specific utilities.
1071 plat="$(get_tftf_opt PLAT)"
1072 plat_utils="$ci_root/${plat}_utils.sh"
1073 else
1074 # Source platform-specific utilities by
1075 # using plat_utils name.
1076 plat_utils="$ci_root/${plat_utils}.sh"
1077 fi
1078
Fathi Boudra422bf772019-12-02 11:10:16 +02001079 if [ -f "$plat_utils" ]; then
1080 source "$plat_utils"
1081 fi
1082
1083 archive="$build_archive"
1084 tftf_build_root="$tftf_root/build"
1085
1086 echo "Building Trusted Firmware TF ($mode) ..." |& log_separator
1087
1088 # Call pre-build hook
1089 call_hook pre_tftf_build
1090
1091 build_tftf
1092
1093 from="$tftf_build_root" to="$archive" collect_build_artefacts
1094
1095 # Clear any local changes made by applied patches
1096 undo_tftf_patches
1097
1098 echo "##########"
1099 echo
1100 )
1101 fi
1102
Olivier Deprez0a9a3482019-12-16 14:10:31 +01001103 # SPM build
1104 if config_valid "$spm_config"; then
1105 (
1106 echo "##########"
1107
1108 # Get platform name from spm_config file
1109 plat="$(echo "$spm_config" | awk -F- '{print $1}')"
1110 plat_utils="$ci_root/${plat}_utils.sh"
1111 if [ -f "$plat_utils" ]; then
1112 source "$plat_utils"
1113 fi
1114
Daniel Boulbyb8d2a462022-03-07 13:55:25 +00001115 # Call pre-build hook
1116 call_hook pre_spm_build
1117
Manish Pandey1e7be852020-11-09 16:04:48 +00001118 # SPM build generates two sets of binaries, one for normal and other
1119 # for Secure world. We need both set of binaries for CI.
Olivier Deprez0a9a3482019-12-16 14:10:31 +01001120 archive="$build_archive"
Manish Pandey1e7be852020-11-09 16:04:48 +00001121 spm_build_root="$spm_root/out/reference/$spm_secure_out_dir"
1122 hafnium_build_root="$spm_root/out/reference/$spm_non_secure_out_dir"
Olivier Deprez0a9a3482019-12-16 14:10:31 +01001123
Daniel Boulbyb8d2a462022-03-07 13:55:25 +00001124 echo "spm_build_root is $spm_build_root"
Olivier Deprez0a9a3482019-12-16 14:10:31 +01001125 echo "Building SPM ($mode) ..." |& log_separator
1126
1127 # NOTE: mode has no effect on SPM build (for now), hence debug
1128 # mode is built but subsequent build using release mode just
1129 # goes through with "nothing to do".
1130 build_spm
1131
1132 # Show SPM/Hafnium binary details
Madhukar Pappireddyc683cf62021-11-01 14:38:32 -05001133 cksum $spm_build_root/hafnium.bin
1134
1135 # Some platforms only have secure configuration enabled. Hence,
1136 # non secure hanfnium binary might not be built.
1137 if [ -f $hafnium_build_root/hafnium.bin ]; then
1138 cksum $hafnium_build_root/hafnium.bin
1139 fi
Olivier Deprez0a9a3482019-12-16 14:10:31 +01001140
Manish Pandey1e7be852020-11-09 16:04:48 +00001141 secure_from="$spm_build_root" non_secure_from="$hafnium_build_root" to="$archive" collect_spm_artefacts
Olivier Deprez0a9a3482019-12-16 14:10:31 +01001142
1143 echo "##########"
1144 echo
1145 )
1146 fi
1147
Fathi Boudra422bf772019-12-02 11:10:16 +02001148 # TF build
1149 if config_valid "$tf_config"; then
1150 (
1151 echo "##########"
1152
Manish V Badarkhe3bd3fea2020-11-08 15:17:00 +00001153 plat_utils="$(get_tf_opt PLAT_UTILS)"
Madhukar Pappireddy2f284e12021-08-30 16:06:14 -05001154 export plat_variant="$(get_tf_opt TARGET_PLATFORM)"
1155
Manish V Badarkhe3bd3fea2020-11-08 15:17:00 +00001156 if [ -z ${plat_utils} ]; then
1157 # Source platform-specific utilities.
1158 plat="$(get_tf_opt PLAT)"
1159 plat_utils="$ci_root/${plat}_utils.sh"
1160 else
1161 # Source platform-specific utilities by
1162 # using plat_utils name.
1163 plat_utils="$ci_root/${plat_utils}.sh"
1164 fi
1165
Fathi Boudra422bf772019-12-02 11:10:16 +02001166 if [ -f "$plat_utils" ]; then
1167 source "$plat_utils"
1168 fi
1169
Chris Kaye5a486b2023-08-04 11:50:31 +00001170 fvp_tsram_size="$(get_tf_opt FVP_TRUSTED_SRAM_SIZE)"
1171 fvp_tsram_size="${fvp_tsram_size:-256}"
1172
Harrison Mutaidc703402024-08-02 14:40:16 +00001173 poetry -C "$tf_root" install --without docs
Chris Kayd0837902021-11-17 10:17:52 +00001174
Fathi Boudra422bf772019-12-02 11:10:16 +02001175 archive="$build_archive"
1176 tf_build_root="$tf_root/build"
1177
1178 echo "Building Trusted Firmware ($mode) ..." |& log_separator
1179
1180 # Call pre-build hook
1181 call_hook pre_tf_build
1182
1183 build_tf
1184
1185 # Call post-build hook
1186 call_hook post_tf_build
1187
1188 # Pre-archive hook
1189 call_hook pre_tf_archive
1190
1191 from="$tf_build_root" to="$archive" collect_build_artefacts
1192
1193 # Post-archive hook
1194 call_hook post_tf_archive
1195
1196 call_hook fetch_tf_resource
1197 call_hook post_fetch_tf_resource
1198
Chris Kay4e8aaf12022-09-01 15:21:55 +01001199 # Generate LAVA job files if necessary
1200 call_hook generate_lava_job_template
1201 call_hook generate_lava_job
1202
Fathi Boudra422bf772019-12-02 11:10:16 +02001203 # Clear any local changes made by applied patches
1204 undo_tf_patches
1205
1206 echo "##########"
1207 )
1208 fi
1209
1210 echo
1211 echo
1212done
1213
1214call_hook pre_package
1215
1216call_hook post_package
1217
1218if upon "$jenkins_run" && upon "$artefacts_receiver" && [ -d "artefacts" ]; then
Zelalem219df412020-05-17 19:21:20 -05001219 source "$CI_ROOT/script/send_artefacts.sh" "artefacts"
Fathi Boudra422bf772019-12-02 11:10:16 +02001220fi
1221
1222echo
1223echo "Done"