1#!/bin/bash 2# verify_build.sh - Verify a80x0_nbx TF-A build 3# 4# Usage: ./verify_build.sh [build_dir] 5# build_dir: Path to build output (default: build/a80x0_nbx/debug) 6# Also accepts BUILD_BASE; a80x0_nbx/{debug,release} is probed. 7# 8# SPDX-License-Identifier: BSD-3-Clause 9# Copyright (C) 2025-2026 Free Mobile / Freebox 10 11set -e 12 13BUILD_DIR="${1:-build/a80x0_nbx/debug}" 14 15# When called with BUILD_BASE (e.g. by CI), artifacts are in the 16# a80x0_nbx/{debug,release} subdirectory. Probe for it so that both 17# verify_build.sh build/a80x0_nbx/debug (local, default) 18# verify_build.sh $BUILD_BASE (CI: post_tf_build hook) 19# work transparently. 20if [ ! -f "${BUILD_DIR}/ble.bin" ]; then 21 for _subdir in "${BUILD_DIR}"/a80x0_nbx/debug \ 22 "${BUILD_DIR}"/a80x0_nbx/release; do 23 if [ -d "${_subdir}" ]; then 24 BUILD_DIR="${_subdir}" 25 break 26 fi 27 done 28 unset _subdir 29fi 30 31BLE_ELF="${BUILD_DIR}/ble/ble.elf" 32BL31_ELF="${BUILD_DIR}/bl31/bl31.elf" 33CROSS_PREFIX="${CROSS_COMPILE:-aarch64-linux-gnu-}" 34 35# Colors for output 36RED='\033[0;31m' 37GREEN='\033[0;32m' 38YELLOW='\033[1;33m' 39NC='\033[0m' # No Color 40 41pass() { printf '%b[OK]%b\n' "${GREEN}" "${NC}"; } 42fail() { printf '%b[FAILED]%b\n' "${RED}" "${NC}"; } 43warn() { printf '%b[WARN]%b\n' "${YELLOW}" "${NC}"; } 44missing() { printf '%b[MISSING]%b\n' "${RED}" "${NC}"; } 45 46echo "==============================================" 47echo " a80x0_nbx TF-A Build Verification" 48echo "==============================================" 49echo "" 50echo "Build directory: ${BUILD_DIR}" 51echo "Cross prefix: ${CROSS_PREFIX}" 52echo "" 53 54ERRORS=0 55 56# 1. Check build artifacts exist 57echo "1. Checking build artifacts..." 58echo " ----------------------------------------" 59ARTIFACTS="ble.bin bl1.bin bl2.bin bl31.bin fip.bin flash-image.bin" 60for f in ${ARTIFACTS}; do 61 if [ -f "${BUILD_DIR}/${f}" ]; then 62 SIZE=$(stat -c%s "${BUILD_DIR}/${f}") 63 printf " %-20s %8d bytes " "${f}" "${SIZE}" 64 pass 65 else 66 printf " %-20s %8s " "${f}" "-" 67 missing 68 ERRORS=$((ERRORS + 1)) 69 fi 70done 71echo "" 72 73# 2. Check ramoopsies linker wrapping 74echo "2. Checking ramoopsies --wrap mechanism..." 75echo " ----------------------------------------" 76if [ -f "${BLE_ELF}" ]; then 77 # Check symbols exist 78 printf " %-35s " "__wrap_mv_ddr_mem_scrubbing" 79 if "${CROSS_PREFIX}nm" "${BLE_ELF}" 2>/dev/null | grep -q "__wrap_mv_ddr_mem_scrubbing"; then 80 pass 81 else 82 fail 83 ERRORS=$((ERRORS + 1)) 84 fi 85 86 printf " %-35s " "mv_ddr_mem_scrubbing (original)" 87 if "${CROSS_PREFIX}nm" "${BLE_ELF}" 2>/dev/null | grep -q "T mv_ddr_mem_scrubbing$"; then 88 pass 89 else 90 fail 91 ERRORS=$((ERRORS + 1)) 92 fi 93 94 printf " %-35s " "ramoopsies_backup buffer" 95 if "${CROSS_PREFIX}nm" "${BLE_ELF}" 2>/dev/null | grep -q "ramoopsies_backup"; then 96 pass 97 else 98 fail 99 ERRORS=$((ERRORS + 1)) 100 fi 101 102 # Verify wrapper calls real function 103 printf " %-35s " "Wrapper calls original function" 104 CALL_CHAIN=$("${CROSS_PREFIX}objdump" -d "${BLE_ELF}" 2>/dev/null | \ 105 grep -A50 "<__wrap_mv_ddr_mem_scrubbing>:" | \ 106 grep "bl.*<mv_ddr_mem_scrubbing>" || true) 107 if [ -n "${CALL_CHAIN}" ]; then 108 pass 109 else 110 fail 111 ERRORS=$((ERRORS + 1)) 112 fi 113 114 # Check SError vector handling 115 printf " %-35s " "SError exception vectors" 116 if "${CROSS_PREFIX}nm" "${BLE_ELF}" 2>/dev/null | grep -q "vectors"; then 117 pass 118 else 119 warn 120 fi 121else 122 echo " BLE ELF not found: ${BLE_ELF}" 123 ERRORS=$((ERRORS + 1)) 124fi 125echo "" 126 127# 3. Check DDR driver integration 128echo "3. Checking DDR driver integration..." 129echo " ----------------------------------------" 130if [ -f "${BLE_ELF}" ]; then 131 DDR_SYMS="ddr3_init mv_ddr_topology_map_get mv_ddr_spd_supported_cls_calc mv_ddr_is_ecc_ena" 132 for sym in ${DDR_SYMS}; do 133 printf " %-35s " "${sym}" 134 if "${CROSS_PREFIX}nm" "${BLE_ELF}" 2>/dev/null | grep -q "T ${sym}"; then 135 pass 136 else 137 fail 138 ERRORS=$((ERRORS + 1)) 139 fi 140 done 141fi 142echo "" 143 144# 4. Check BL31 runtime services 145echo "4. Checking BL31 runtime services..." 146echo " ----------------------------------------" 147if [ -f "${BL31_ELF}" ]; then 148 BL31_SYMS="mvebu_get_dram_size plat_marvell_get_pm_cfg a8k_pwr_domain_off a8k_system_reset" 149 for sym in ${BL31_SYMS}; do 150 printf " %-35s " "${sym}" 151 if "${CROSS_PREFIX}nm" "${BL31_ELF}" 2>/dev/null | grep -q " ${sym}"; then 152 pass 153 else 154 echo -n "(inlined?) " 155 warn 156 fi 157 done 158else 159 echo " BL31 ELF not found: ${BL31_ELF}" 160 ERRORS=$((ERRORS + 1)) 161fi 162echo "" 163 164# 5. Check OP-TEE integration (optional) 165echo "5. Checking OP-TEE integration..." 166echo " ----------------------------------------" 167FIP_BIN="${BUILD_DIR}/fip.bin" 168FIPTOOL="tools/fiptool/fiptool" 169 170# Check if opteed is compiled into BL31 171OPTEE_ENABLED=false 172if [ -f "${BL31_ELF}" ]; then 173 if "${CROSS_PREFIX}nm" "${BL31_ELF}" 2>/dev/null | grep -q "opteed_setup"; then 174 OPTEE_ENABLED=true 175 fi 176fi 177 178if [ "${OPTEE_ENABLED}" = true ]; then 179 printf " %-35s " "OP-TEE dispatcher (opteed)" 180 pass 181 182 # Check opteed symbols in BL31 183 OPTEE_SYMS="opteed_setup opteed_init optee_vector_table bl32_image_ep_info" 184 for sym in ${OPTEE_SYMS}; do 185 printf " %-35s " "${sym}" 186 if "${CROSS_PREFIX}nm" "${BL31_ELF}" 2>/dev/null | grep -q "${sym}"; then 187 pass 188 else 189 fail 190 ERRORS=$((ERRORS + 1)) 191 fi 192 done 193 194 # Check BL32 (header), BL32_EXTRA1 (pager), BL32_EXTRA2 (pageable) in FIP 195 if [ -f "${FIP_BIN}" ] && [ -x "${FIPTOOL}" ]; then 196 # Check BL32 (v2 header) 197 printf " %-35s " "BL32 (header) in FIP" 198 BL32_INFO=$(${FIPTOOL} info "${FIP_BIN}" 2>/dev/null | \ 199 grep -E "Secure Payload BL32 \(Trusted OS\):" | \ 200 head -1 || true) 201 if [ -n "${BL32_INFO}" ]; then 202 BL32_SIZE=$(echo "${BL32_INFO}" | sed -n 's/.*size=\(0x[0-9a-fA-F]*\).*/\1/p') 203 echo -n "(${BL32_SIZE}) " 204 pass 205 else 206 fail 207 echo " ERROR: BL32 header not found in FIP!" 208 ERRORS=$((ERRORS + 1)) 209 fi 210 211 # Check BL32_EXTRA1 (pager) 212 printf " %-35s " "BL32_EXTRA1 (pager) in FIP" 213 EXTRA1_INFO=$(${FIPTOOL} info "${FIP_BIN}" 2>/dev/null \ 214 | grep -E "Trusted OS Extra1" || true) 215 if [ -n "${EXTRA1_INFO}" ]; then 216 EXTRA1_SIZE=$(echo "${EXTRA1_INFO}" | sed -n 's/.*size=\(0x[0-9a-fA-F]*\).*/\1/p') 217 echo -n "(${EXTRA1_SIZE}) " 218 pass 219 else 220 fail 221 echo " ERROR: BL32_EXTRA1 (pager) not found in FIP - OP-TEE will fail!" 222 ERRORS=$((ERRORS + 1)) 223 fi 224 225 # Check BL32_EXTRA2 (pageable) - may be empty/missing for non-paged builds 226 printf " %-35s " "BL32_EXTRA2 (pageable) in FIP" 227 EXTRA2_INFO=$(${FIPTOOL} info "${FIP_BIN}" 2>/dev/null \ 228 | grep -E "Trusted OS Extra2" || true) 229 if [ -n "${EXTRA2_INFO}" ]; then 230 EXTRA2_SIZE=$(echo "${EXTRA2_INFO}" | sed -n 's/.*size=\(0x[0-9a-fA-F]*\).*/\1/p') 231 echo -n "(${EXTRA2_SIZE}) " 232 pass 233 else 234 echo -n "(not present - OK for non-paged) " 235 pass 236 fi 237 238 # Extract and verify OP-TEE header magic and version 239 printf " %-35s " "OP-TEE header magic" 240 TMPBL32=$(mktemp) 241 if ${FIPTOOL} unpack --tos-fw "${TMPBL32}" --force "${FIP_BIN}" 2>/dev/null; then 242 MAGIC=$(hexdump -n 4 -e '4/1 "%c"' "${TMPBL32}" 2>/dev/null) || MAGIC="" 243 if [ "${MAGIC}" = "OPTE" ]; then 244 echo -n "(\"OPTE\") " 245 pass 246 247 # Check header version (byte 4, should be 2 for v2 format) 248 printf " %-35s " "OP-TEE header version" 249 VERSION=$(hexdump -s 4 -n 1 -e '1/1 "%d"' "${TMPBL32}" 2>/dev/null) || VERSION="0" 250 if [ "${VERSION}" = "2" ]; then 251 echo -n "(v${VERSION}) " 252 pass 253 else 254 echo -n "(v${VERSION}) " 255 fail 256 echo " ERROR: Expected version 2, got ${VERSION}!" 257 echo " Use tee-header_v2.bin as BL32, not tee.bin" 258 ERRORS=$((ERRORS + 1)) 259 fi 260 261 # Check load address (v2 header: load_addr at offset 16) 262 printf " %-35s " "OP-TEE load address" 263 LOAD_ADDR=$(hexdump -s 16 -n 4 \ 264 -e '1/4 "0x%08x"' "${TMPBL32}" \ 265 2>/dev/null) || LOAD_ADDR="" 266 if [ "${LOAD_ADDR}" = "0x04400000" ]; then 267 echo -n "(${LOAD_ADDR}) " 268 pass 269 else 270 echo -n "(${LOAD_ADDR}) " 271 warn 272 echo " WARNING: Expected 0x04400000" 273 fi 274 else 275 echo -n "(\"${MAGIC}\") " 276 fail 277 echo " ERROR: Invalid OP-TEE header - expected \"OPTE\" magic!" 278 ERRORS=$((ERRORS + 1)) 279 fi 280 else 281 echo -n "(extract failed) " 282 warn 283 fi 284 rm -f "${TMPBL32}" 285 else 286 printf " %-35s " "BL32 in FIP" 287 echo -n "(fiptool not available) " 288 warn 289 fi 290else 291 printf " %-35s " "OP-TEE dispatcher (opteed)" 292 echo -n "(not enabled) " 293 warn 294 echo " INFO: Build without OP-TEE support - this is OK if not using --optee-*" 295fi 296echo "" 297 298# 6. Check platform configuration 299echo "6. Checking platform configuration..." 300echo " ----------------------------------------" 301if [ -f "${BLE_ELF}" ]; then 302 PLAT_SYMS="" 303 PLAT_SYMS="${PLAT_SYMS} marvell_get_io_win_memory_map" 304 PLAT_SYMS="${PLAT_SYMS} marvell_get_ccu_memory_map" 305 PLAT_SYMS="${PLAT_SYMS} plat_marvell_dram_update_topology" 306 for sym in ${PLAT_SYMS}; do 307 printf " %-35s " "${sym}" 308 if "${CROSS_PREFIX}nm" "${BLE_ELF}" 2>/dev/null | grep -q " ${sym}"; then 309 pass 310 else 311 echo -n "(inlined?) " 312 warn 313 fi 314 done 315fi 316echo "" 317 318# 7. Check I2C/SPD support 319echo "7. Checking I2C/SPD support..." 320echo " ----------------------------------------" 321if [ -f "${BLE_ELF}" ]; then 322 I2C_SYMS="i2c_init i2c_read" 323 for sym in ${I2C_SYMS}; do 324 printf " %-35s " "${sym}" 325 if "${CROSS_PREFIX}nm" "${BLE_ELF}" 2>/dev/null | grep -q "T ${sym}"; then 326 pass 327 else 328 warn 329 fi 330 done 331fi 332echo "" 333 334# 8. Flash image sanity check 335echo "8. Checking flash image format..." 336echo " ----------------------------------------" 337FLASH_IMAGE="${BUILD_DIR}/flash-image.bin" 338if [ -f "${FLASH_IMAGE}" ]; then 339 # Check magic number (Marvell boot image starts with specific header) 340 MAGIC=$(hexdump -n 4 -e '1/4 "%08x"' "${FLASH_IMAGE}" 2>/dev/null) || \ 341 MAGIC=$(od -A n -t x4 -N 4 "${FLASH_IMAGE}" 2>/dev/null | tr -d ' \n') || \ 342 MAGIC="" 343 printf " %-35s " "Flash image header" 344 if [ -n "${MAGIC}" ]; then 345 echo -n "(0x${MAGIC}) " 346 pass 347 else 348 echo -n "(no hex tool) " 349 warn 350 fi 351 352 # Check file size is reasonable 353 SIZE=$(stat -c%s "${FLASH_IMAGE}") 354 printf " %-35s " "Flash image size" 355 if [ "${SIZE}" -gt 100000 ] && [ "${SIZE}" -lt 2000000 ]; then 356 echo -n "(${SIZE} bytes) " 357 pass 358 else 359 echo -n "(${SIZE} bytes) " 360 warn 361 fi 362else 363 echo " Flash image not found: ${FLASH_IMAGE}" 364 ERRORS=$((ERRORS + 1)) 365fi 366echo "" 367 368# Summary 369echo "==============================================" 370if [ ${ERRORS} -eq 0 ]; then 371 printf ' Result: %bALL CHECKS PASSED%b\n' "${GREEN}" "${NC}" 372else 373 printf ' Result: %b%d CHECK(S) FAILED%b\n' "${RED}" "${ERRORS}" "${NC}" 374fi 375echo "==============================================" 376echo "" 377 378exit ${ERRORS} 379