1345 lines
37 KiB
Bash
Executable File
1345 lines
37 KiB
Bash
Executable File
#! /bin/bash
|
|
#
|
|
# Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
|
|
################################################################################
|
|
# Heterogeneous Firmware Compilation and Unified Image Provisioning Framework
|
|
#
|
|
# This script orchestrates a multi-stage automated build pipeline specifically
|
|
# engineered for embedded ecosystems with heterogeneous processor architectures,
|
|
# notably integrating ARM application cores and specialized Xtensa DSP engines.
|
|
# The framework enforces a systematic firmware lifecycle methodology,
|
|
# encompassing dynamic parameter resolution, cross-compilation toolchain
|
|
# configuration, and cryptographic image signing (via MCUboot or U-Boot
|
|
# standards). It resolves hardware-specific configuration matrices to guarantee
|
|
# binary integrity across diverse SoC variants.
|
|
# The pipeline culminates in the synthesis of a monolithic, deplorable system
|
|
# image (supporting both OTA and local upgrade formats), consolidating
|
|
# distributed binary artifacts while preserving diagnostic symbols and
|
|
# maintaining rigorous workspace sanitization.
|
|
################################################################################
|
|
|
|
set -euo pipefail
|
|
trap 'clean_up' EXIT SIGINT SIGTERM
|
|
|
|
# Global variable values initialization
|
|
|
|
# Inheritance of Environment Variables from the pkg_env.sh Shell.
|
|
CHOICE_PACKAGE=${CHOICE_PACKAGE:-0}
|
|
PACKAGE_COMBINATION=${PACKAGE_COMBINATION:-""}
|
|
KERNEL=${KERNEL:-""}
|
|
|
|
FW_LISTS=()
|
|
BOOTLOADER_TYPE=${BOOTLOADER_TYPE:-"uboot"}
|
|
WAITING_PID=${WAITING_PID:-""}
|
|
|
|
PKG_PRODUCT=${PKG_PRODUCT:-""}
|
|
PKG_IMG_DIR=${PKG_IMG_DIR:-""}
|
|
PKG_VERBOSE=${PKG_VERBOSE:-""}
|
|
PKG_GEN_OTA=${PKG_GEN_OTA:-""}
|
|
PKG_BUILD_LOG=${PKG_BUILD_LOG:-""}
|
|
PKG_DBG_EN=${PKG_DBG_EN:-""}
|
|
PKG_IMG_CFG_FILE=${PKG_IMG_CFG_FILE:-""}
|
|
PKG_CONSUME=${PKG_CONSUME:-0.00}
|
|
|
|
declare -i RTOS_XIP_RAM_ADDR=0
|
|
declare -i RTOS_XIP_ROM_ADDR=$((0))
|
|
RTOS_XIP_RAM_ROM_FILL_SIZE=$((8192))
|
|
RTOS_OUTPUT_DIR=${RTOS_OUTPUT_DIR:-""}
|
|
RTOS_ROOT_DIR=${RTOS_ROOT_DIR:-""}
|
|
RTOS_BUILD_DIR=${RTOS_BUILD_DIR:-""}
|
|
RTOS_DBG_FILE_PREFIX=${RTOS_DBG_FILE_PREFIX:-""}
|
|
RTOS_IMG_DIR=${RTOS_IMG_DIR:-""}
|
|
RTOS_BIN_FILE=${RTOS_BIN_FILE:-""}
|
|
RTOS_BUILD_CORE=${RTOS_BUILD_CORE:-""}
|
|
RTOS_FW_TOOL=${RTOS_FW_TOOL:-""}
|
|
RTOS_BUILD_NINJA=${RTOS_BUILD_NINJA:-""}
|
|
RTOS_WCN_FW_SRC_DIR=${RTOS_WCN_FW_SRC_DIR:-""}
|
|
RTOS_BRANCH_TYPES=("hifi_dsp" "speaker")
|
|
RTOS_USER_RODARA_DIR=${RTOS_BRANCH_TYPES:-""}
|
|
RTOS_LOAD_ADDR=${RTOS_LOAD_ADDR:-""}
|
|
RTOS_MKLFS_BLOCK_SZ="4096"
|
|
RTOS_MKLFS_PAGE_SZ="256"
|
|
RTOS_MKLFS_READ_SZ="256"
|
|
RTOS_MKLFS_SRC_PATH=${RTOS_MKLFS_SRC_PATH:-""}
|
|
RTOS_MKLFS_DST_PATH=${RTOS_MKLFS_DST_PATH:-""}
|
|
|
|
|
|
# partition name : partition start address
|
|
# Constructed using the gen_partition_map routine.
|
|
declare -A PART_ADDR=() # key(partition name): val(partition start address)
|
|
declare -A PART_SIZE=() # key(partition name): val(partition size)
|
|
declare -A SZ_MAP=(
|
|
[SZ_1K]=$((1024))
|
|
[SZ_2K]=$((2*1024))
|
|
[SZ_4K]=$((4*1024))
|
|
[SZ_8K]=$((8*1024))
|
|
[SZ_16K]=$((16*1024))
|
|
[SZ_64K]=$((64*1024))
|
|
[SZ_128K]=$((128*1024))
|
|
[SZ_256K]=$((256*1024))
|
|
[SZ_512K]=$((256*1024))
|
|
[SZ_1M]=$((1024*1024))
|
|
)
|
|
|
|
log_info() { echo -e "[INFO]: \033[32m$*\033[0m"; }
|
|
log_note() { echo -e "\033[7m>>> $*\033[0m"; }
|
|
log_warn() { echo -e "[WARN]: \033[33m$*\033[0m"; }
|
|
log_err() { echo -e "[ERROR]: \033[31m$*\033[0m"; }
|
|
log_msg() { echo -en ">>> $*"; }
|
|
log_dbg() { [[ "$PKG_DBG_EN" == "y" ]] && echo -e "[DBG]: \033[34m$*\033[0m"; }
|
|
|
|
function log_ok() {
|
|
kill -9 "$WAITING_PID" 2>/dev/null || true
|
|
wait "$WAITING_PID" 2>/dev/null || true
|
|
|
|
printf "\b\b"
|
|
echo -e "\e[32m OK(${PKG_CONSUME}S)\e[0m";
|
|
}
|
|
|
|
function log_fail() {
|
|
kill -9 "$WAITING_PID" 2>/dev/null || true
|
|
wait "$WAITING_PID" 2>/dev/null || true
|
|
|
|
printf "\b\b"
|
|
echo -e "\e[31m Failed\e[0m"
|
|
|
|
if [[ -f "$PKG_BUILD_LOG" ]]; then
|
|
cat $PKG_BUILD_LOG
|
|
fi
|
|
}
|
|
|
|
up_pid() { WAITING_PID=$!; }
|
|
|
|
function waiting() {
|
|
local spin_str='|/-\'
|
|
local tmp_str=''
|
|
# tput civis
|
|
|
|
while true; do
|
|
tmp_str=${spin_str#?}
|
|
printf " %c" "$spin_str"
|
|
spin_str=$tmp_str${spin_str%"$tmp_str"}
|
|
sleep 0.1
|
|
printf "\b\b"
|
|
done
|
|
}
|
|
|
|
function waiting_start() {
|
|
start=$(date +%s%N)
|
|
log_msg "$@"
|
|
waiting &
|
|
up_pid
|
|
}
|
|
|
|
function waiting_end() {
|
|
end=$(date +%s%N)
|
|
if [[ "$1" == 0 ]]; then
|
|
PKG_CONSUME=$(bc -l <<< "scale=2; ($end - $start)/1000000000")
|
|
log_ok
|
|
else
|
|
log_fail
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Write an 8-bit value to a binary file.
|
|
#
|
|
# Arguments:
|
|
# $1 - Target binary file.
|
|
# $2 - Byte offset in the file.
|
|
# $3 - 8-bit value to write.
|
|
function write_od_to_bin_1()
|
|
{
|
|
target_file=$1
|
|
offset=$2
|
|
od_value=$3
|
|
size_hex=$(printf '%02x' $od_value)
|
|
size_little_hex=$(echo -n "$size_hex" | grep -o '..' | tac | tr -d '\n')
|
|
echo -n $size_little_hex | xxd -r -p | dd of=$target_file bs=1 \
|
|
seek=$offset conv=notrunc
|
|
}
|
|
|
|
#
|
|
# Write a 32-bit value to a binary file in little-endian format.
|
|
#
|
|
# Arguments:
|
|
# $1 - Target binary file.
|
|
# $2 - Byte offset in the file.
|
|
# $3 - 32-bit value to write.
|
|
function write_od_to_bin_4()
|
|
{
|
|
local target_file=$1
|
|
local offset=$2
|
|
local od_value=$3
|
|
local size_hex=$(printf '%08x' $od_value)
|
|
local size_little_hex=$(echo -n "$size_hex" | grep -o '..' | tac | tr -d '\n')
|
|
|
|
echo -n $size_little_hex | xxd -r -p | dd of=$target_file \
|
|
bs=1 seek=$offset conv=notrunc
|
|
}
|
|
|
|
#
|
|
# Clean up resources and terminate the current build flow.
|
|
#
|
|
function clean_up() {
|
|
if [[ -n "${WAITING_PID:-}" ]] && kill -0 "$WAITING_PID" 2>/dev/null; then
|
|
kill -9 "$WAITING_PID" 2>/dev/null || true
|
|
fi
|
|
|
|
set +euo pipefail
|
|
return 1
|
|
}
|
|
|
|
#
|
|
# Align a value up to the specified boundary.
|
|
#
|
|
# Arguments:
|
|
# $1 - Value to align.
|
|
# $2 - Alignment size.
|
|
align_up() {
|
|
local -i value=$(( $1 ))
|
|
local -i align=$(( $2 ))
|
|
|
|
echo $(((value + align - 1) & ~(align - 1)))
|
|
}
|
|
|
|
#
|
|
# Parse the selected package target and initialize packaging paths.
|
|
#
|
|
# This function extracts architecture, SoC, board, and product
|
|
# information from PACKAGE_COMBINATION according to CHOICE_PACKAGE,
|
|
# then prepares the output directory and build log.
|
|
function parse_pkg_target() {
|
|
|
|
local arch_prefix=""
|
|
local product_suffix=""
|
|
|
|
#Get the packed sequence selected by the user
|
|
j=0
|
|
while IFS= read -r LINE; do
|
|
if [[ "$j" -eq "$CHOICE_PACKAGE" ]]; then
|
|
read -ra PACKAGE_ARRY <<< "$LINE"
|
|
fi
|
|
((j++))
|
|
done < "$PACKAGE_COMBINATION"
|
|
|
|
#parameter check
|
|
if [ -z "$PACKAGE_ARRY" ]; then
|
|
log_err " Please execute source scripts/pkg_env.sh"
|
|
return 1
|
|
fi
|
|
|
|
#parameter check
|
|
j=0
|
|
unset pkg_arch pkg_soc pkg_board pkg_product
|
|
|
|
pkg_size=${#PACKAGE_ARRY[@]}
|
|
for ((loop = 0; loop < ${pkg_size}; loop += 4)); do
|
|
[[ $((loop + 3)) -lt $pkg_size ]] || {
|
|
log_err "ERROR: malformed PACKAGE_ARRY ($((loop + 3)) > $pkg_size)"
|
|
return 1
|
|
}
|
|
pkg_arch[j]=${PACKAGE_ARRY[loop]}
|
|
pkg_soc[j]=${PACKAGE_ARRY[loop + 1]}
|
|
pkg_board[j]=${PACKAGE_ARRY[loop + 2]}
|
|
pkg_product[j]=${PACKAGE_ARRY[loop + 3]}
|
|
|
|
arch_prefix="$arch_prefix""${pkg_arch[j]}""-"
|
|
product_suffix="$product_suffix""-""${pkg_product[j]}"
|
|
|
|
((j+=1))
|
|
done
|
|
|
|
# set the board configuration path
|
|
PKG_ORIGIN_CFG_DIR="$RTOS_ROOT_DIR/image_packer/${pkg_soc[0]}"
|
|
|
|
# mirror storage path
|
|
package_dir=$RTOS_ROOT_DIR/output/packages
|
|
platform="${arch_prefix}""${pkg_soc[0]}"-"${pkg_board[0]}"
|
|
PKG_IMG_DIR=$package_dir/$platform
|
|
PKG_BUILD_LOG="$PKG_IMG_DIR/pkb_build.log"
|
|
|
|
# create mirror file directory
|
|
rm -fr $PKG_IMG_DIR
|
|
mkdir -p $PKG_IMG_DIR
|
|
: > "$PKG_BUILD_LOG"
|
|
}
|
|
|
|
#
|
|
# Signs and packages the RTOS kernel and Bluetooth firmware using the MCUboot
|
|
# imgtool utility for secure boot deployment.
|
|
#
|
|
# Arguments:
|
|
# - $1 target SoC architecture name.
|
|
# - $2 target board name.
|
|
# - $3 target product variant name.
|
|
function package_kernel_for_mcuboot() {
|
|
local m_lib_dir=${RTOS_BUILD_DIR}/lib/mcuboot
|
|
local m_sig_dir=${m_lib_dir}/scripts
|
|
local m_sig_tool=${m_sig_dir}/imgtool.py
|
|
local m_out_dir=${RTOS_BUILD_DIR}/output/$1-$2-mcuboot
|
|
local m_cfg=$m_out_dir/$KERNEL/.config
|
|
local img_in_file=$RTOS_OUTPUT_DIR/$KERNEL/$KERNEL.bin
|
|
local img_out_file=$RTOS_OUTPUT_DIR/images/$KERNEL-signed.bin
|
|
local m_slot_sz=""
|
|
local bt_in_file=""
|
|
local bt_out_file=""
|
|
local prf_conf=""
|
|
local bt_slot_sz=""
|
|
|
|
m_slot_sz="$(grep -E \
|
|
"^CONFIG_LIB_MCUBOOT_KERNEL_SIZE=" "$m_cfg" | cut -d '=' -f2)"
|
|
|
|
python3 $m_sig_tool sign --key $m_lib_dir/root-rsa-2048.pem \
|
|
--header-size 0x1000 --align 4 --slot-size ${m_slot_sz} \
|
|
--pad --version 1.0.0 --pad-header --load-addr 0x10000 \
|
|
${img_in_file} \
|
|
${img_out_file}
|
|
|
|
cp ${img_out_file} ${RTOS_IMG_DIR}/rtos-mcuImage
|
|
|
|
prf_conf=${RTOS_BUILD_DIR}/output/$1-$2-$3/$KERNEL/.config
|
|
bt_in_file=\
|
|
${RTOS_BUILD_DIR}/boards/${pkg_arch[0]}/${pkg_board[0]}/bt_fw.bin
|
|
bt_out_file=$PKG_IMG_DIR/bt-signed.bin
|
|
bt_slot_sz="$(
|
|
grep -E "^CONFIG_LIB_MCUBOOT_BT_SIZE=" "$m_cfg" |
|
|
cut -d '=' -f2)"
|
|
|
|
python3 $m_sig_tool sign --key $m_lib_dir/root-rsa-2048.pem \
|
|
--header-size 0x1000 --align 4 --slot-size ${bt_slot_sz} \
|
|
--version 1.0.0 \
|
|
--pad-header \
|
|
${bt_in_file} \
|
|
${bt_out_file}
|
|
cp "$bt_out_file" "${RTOS_IMG_DIR}/bt-signed.bin"
|
|
}
|
|
|
|
#
|
|
# Wraps a raw RTOS binary into a U-Boot legacy image format wrapper
|
|
# as a standalone executable using the 'mkimage' tool.
|
|
#
|
|
# Arguments:
|
|
# - $1 target CPU architecture (e.g., "arm", "arm64").
|
|
# - $2 hex memory address for both load and execution entry.
|
|
# - $3 path to the input raw binary payload file.
|
|
# - $4 destination path for the generated U-Boot legacy image file.
|
|
function mkimg_rtos_for_uboot() {
|
|
local arch=$1
|
|
local load_addr=$2
|
|
local input=$3
|
|
local output=$4
|
|
|
|
# -A Operating system type
|
|
# -O Image type: standalone executable image
|
|
# -C Compression type: no compression
|
|
# -a Load address in memory
|
|
# -e Entry point address
|
|
# -n Image name
|
|
# -d Input binary file
|
|
# Output image file
|
|
mkimage -A ${arch} \
|
|
-O u-boot \
|
|
-T standalone \
|
|
-C none \
|
|
-a ${load_addr} \
|
|
-e ${load_addr} \
|
|
-n rtos \
|
|
-d ${input} \
|
|
${output}
|
|
}
|
|
|
|
#
|
|
# Generate and source the RTOS .config file.
|
|
#
|
|
# Arguments:
|
|
# - $1 target SoC architecture name.
|
|
# - $2 target board name.
|
|
# - $3 target product variant name.
|
|
# - $4 additional build variation context.
|
|
function gen_dot_config() {
|
|
# Every variable from .config should be unset first in here to provent
|
|
# effects the different products or environment.
|
|
unset CONFIG_AML_FW_FS
|
|
unset CONFIG_AML_FW_BUILTIN
|
|
unset CONFIG_USER_RODATA_FS_IMG
|
|
unset CONFIG_LFS_USE_BLOCK
|
|
|
|
set +euo pipefail
|
|
source scripts/env.sh $1 $2 $3 $4
|
|
set -euo pipefail
|
|
|
|
make distclean && make config
|
|
|
|
source $RTOS_OUTPUT_DIR/$KERNEL/.config
|
|
log_dbg "Completion of generating .config file!"
|
|
}
|
|
|
|
#
|
|
# Evaluate a size expression and return a hex value.
|
|
#
|
|
# Arguments:
|
|
# - $1 the size expression to be evaluated (spaces are auto-stripped).
|
|
function eval_size_expr() {
|
|
local expr="$1"
|
|
expr="${expr// /}"
|
|
local total=0
|
|
|
|
# Evaluate multi-block expressions containing a coefficient and symbol.
|
|
if [[ "$expr" =~ ^([0-9]+)\*([A-Z0-9_]+)$ ]]; then
|
|
local num="${BASH_REMATCH[1]}"
|
|
local sym="${BASH_REMATCH[2]}"
|
|
total=$(( num * SZ_MAP[$sym] ))
|
|
# Evaluate standalone symbolic strings mapped inside the global size map.
|
|
elif [[ "$expr" =~ ^([A-Z0-9_]+)$ ]]; then
|
|
total=$(( SZ_MAP[$expr] ))
|
|
# Evaluate direct hexadecimal literal tokens.
|
|
elif [[ "$expr" =~ ^0x[0-9a-fA-F]+$ ]]; then
|
|
total=$(( expr ))
|
|
# Evaluate direct base-10 decimal integer tokens.
|
|
elif [[ "$expr" =~ ^[0-9]+$ ]]; then
|
|
total=$(( expr ))
|
|
else
|
|
log_err "unsupported size expr: $expr" >&2
|
|
return 1
|
|
fi
|
|
|
|
printf "0x%x\n" "$total"
|
|
}
|
|
|
|
#
|
|
# Generate partition address and size map from partition_tbl.c.
|
|
#
|
|
# Builds PART_ADDR and PART_SIZE by evaluating partition definitions
|
|
# after C preprocessing.
|
|
function gen_partition_map() {
|
|
local compiler=""
|
|
local cmake_cache="${RTOS_OUTPUT_DIR}/${KERNEL}/CMakeCache.txt"
|
|
local autoconf="${RTOS_OUTPUT_DIR}/${KERNEL}/autoconf.h"
|
|
local part_tbl="${RTOS_BUILD_DIR}/boards/${ARCH}/${BOARD}/partition_tbl.c"
|
|
local part_name=""
|
|
local size_expr=""
|
|
local size_hex=""
|
|
local part_start=$((0x100000))
|
|
|
|
# Extract the explicit cross-compiler binary filepath from the CMake cache.
|
|
compiler=$(
|
|
awk -F= '/^CMAKE_C_COMPILER:FILEPATH/ {print $2; exit}' \
|
|
"$cmake_cache" 2>/dev/null
|
|
)
|
|
|
|
if [[ -z "$compiler" ]]; then
|
|
#Compatible with different cmake version
|
|
compiler=$(
|
|
awk -F= '/^CMAKE_C_COMPILER:STRING/ {print $2; exit}' \
|
|
"$cmake_cache" 2>/dev/null
|
|
)
|
|
fi
|
|
|
|
if [[ -z "$compiler" ]]; then
|
|
log_err "error: compiler not found"
|
|
return 1
|
|
fi
|
|
|
|
# Preprocess the C layout file to resolve structural definitions and
|
|
# evaluate line-by-line.
|
|
while IFS= read -r line; do
|
|
# Skip preprocessor directives.
|
|
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
|
|
|
# Match the name of partition item.
|
|
if [[ "$line" =~ \.name[[:space:]]*=[[:space:]]*\"([^\"]+)\" ]]; then
|
|
part_name="${BASH_REMATCH[1]}"
|
|
continue
|
|
fi
|
|
|
|
# Match the size of partition item.
|
|
if [[ "$line" =~ \.size[[:space:]]*=[[:space:]]*(.+) ]]; then
|
|
size_expr="${BASH_REMATCH[1]}"
|
|
# Trim off common C-syntax trailing delimiters
|
|
size_expr="${size_expr%%;*}"
|
|
size_expr="${size_expr%%}*"
|
|
size_expr="${size_expr%%,*}"
|
|
size_expr="${size_expr//[[:space:]]/}"
|
|
|
|
# Bypass dynamically evaluated full-disk markers
|
|
if [[ "$size_expr" == "MTDPART_SIZ_FULL" ]]; then
|
|
continue
|
|
fi
|
|
|
|
if ! size_hex=$(eval_size_expr "$size_expr"); then
|
|
return 1
|
|
fi
|
|
|
|
PART_ADDR["$part_name"]=$(printf "0x%x" "$part_start")
|
|
PART_SIZE["$part_name"]=$(printf "0x%x" "$size_hex")
|
|
|
|
((part_start += $((size_hex))))
|
|
part_name=""
|
|
fi
|
|
done < <("$compiler" -E -include "$autoconf" "$part_tbl" 2>/dev/null)
|
|
}
|
|
|
|
#
|
|
# Embed DSP and WCN firmware into a filesystem image.
|
|
#
|
|
# This function collects DSP boot images and wireless firmware,
|
|
# stages them into a temporary filesystem directory, and generates
|
|
# a LittleFS image using gen_fs_img().
|
|
#
|
|
# Arguments:
|
|
# $1 - Filesystem directory name.
|
|
# $2 - Output filesystem image name.
|
|
# $3 - Filesystem image size.
|
|
function embed_firmware_as_fs() {
|
|
local fs_dir_name="$1"
|
|
local fs_img_name="$2"
|
|
local fs_img_sz="$3"
|
|
|
|
# Collect DSP firmware.
|
|
while IFS= read -r -d '' f; do
|
|
FW_LISTS+=("$f")
|
|
done < <(find "${PKG_IMG_DIR}" \
|
|
-type f -name "dspboot*.bin" -print0)
|
|
|
|
# Collect WCN firmwares.
|
|
while IFS= read -r -d '' f; do
|
|
FW_LISTS+=("$f")
|
|
done < <(find "${RTOS_WCN_FW_SRC_DIR}" -type f \
|
|
\( -name "*.bin" -o -name "aml_wifi_rf.txt" \) -print0)
|
|
|
|
# Prepare firmware for generate filesystem image or builtin image.
|
|
for fw in "${FW_LISTS[@]}"; do
|
|
install -m 644 "$fw" "$PKG_IMG_DIR/system_fs/" || return 1
|
|
done
|
|
|
|
gen_fs_img "$fs_dir_name" "$fs_img_name" "$fs_img_sz" || return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# Embed DSP firmware into RTOS rodata as a generated header file.
|
|
#
|
|
# This function checks for DSP boot images in PKG_IMG_DIR and, if found,
|
|
# uses RTOS_FW_TOOL to generate a C header file for firmware embedding.
|
|
function embed_firmware_as_rodata() {
|
|
[[ -f ${RTOS_FW_TOOL} ]] || return 1
|
|
|
|
# Integration of DSP firmware into the rtos rodata
|
|
if find "$PKG_IMG_DIR" -maxdepth 1 -type f | \
|
|
grep -Eq '/dspboot.*\.bin$'; then
|
|
python3 ${RTOS_FW_TOOL} \
|
|
-I ${PKG_IMG_DIR} \
|
|
-o ${RTOS_OUTPUT_DIR}/${KERNEL}/dsp_firmware.h
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Select firmware embedding method based on build configuration.
|
|
#
|
|
# Depending on configuration, system firmware is either embedded as
|
|
# a LittleFS image or compiled into RTOS rodata.
|
|
function embed_firmware() {
|
|
if [[ "${CONFIG_AML_FW_FS:-n}" == "y" ]]; then
|
|
embed_firmware_as_fs "system_fs" "system.lfs" "2097152" || return 1
|
|
elif [[ "${CONFIG_AML_FW_BUILTIN:-n}" == "y" ]]; then
|
|
embed_firmware_as_rodata
|
|
fi
|
|
|
|
log_dbg "Implementation and Integration of the System Firmware"
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# Recalculate XIP memory layout (RAM/ROM address and size).
|
|
#
|
|
# This function rebuilds the RTOS image to obtain final binary sizes,
|
|
# then computes aligned XIP RAM/ROM addresses and flash region length.
|
|
# The results are exported for CMake to consume in downstream builds.
|
|
function auto_get_xip_addr_len() {
|
|
# Rebuild the workspace from scratch to generate XIP-compliant binaries.
|
|
[[ -f "${RTOS_BUILD_NINJA}" ]] && rm -f ${RTOS_BUILD_NINJA}
|
|
|
|
if [[ "${CONFIG_BACKTRACE:-n}" == "y" ]]; then
|
|
make backtrace
|
|
else
|
|
make
|
|
fi
|
|
|
|
[[ "$?" == 0 ]] || return 1
|
|
|
|
# Extract file sizes of the generated RAM runtime binary and ROM code
|
|
# segment
|
|
local -i xip_ram_sz=$(stat -c %s \
|
|
"${RTOS_OUTPUT_DIR}/${KERNEL}/${KERNEL}.bin")
|
|
local -i xip_rom_sz=$(stat -c %s \
|
|
"${RTOS_OUTPUT_DIR}/${KERNEL}/freertos_b.bin")
|
|
|
|
if [[ "${PKG_PRODUCT}" != "recovery" ]]; then
|
|
RTOS_XIP_RAM_ADDR=${PART_ADDR["kernel"]}
|
|
else
|
|
RTOS_XIP_RAM_ADDR=${PART_ADDR["recovery"]}
|
|
fi
|
|
|
|
log_dbg "Before align: xip ram/rom: $xip_ram_sz/$xip_rom_sz"
|
|
|
|
RTOS_XIP_ROM_ADDR=$((
|
|
RTOS_XIP_RAM_ADDR + xip_ram_sz + RTOS_XIP_RAM_ROM_FILL_SIZE))
|
|
RTOS_XIP_ROM_ADDR=$(align_up ${RTOS_XIP_ROM_ADDR} 4096)
|
|
|
|
if [[ "${CONFIG_USER_RODATA_FS_IMG:-n}" == "y" ]]; then
|
|
xip_rom_sz=$(align_up ${xip_rom_sz} 0x10000)
|
|
xip_rom_sz=$((xip_rom_sz + CONFIG_USER_RODATA_SIZE))
|
|
fi
|
|
xip_rom_sz=$(align_up ${xip_rom_sz} 0x10000)
|
|
|
|
log_dbg "After align: xip rom addr/size $RTOS_XIP_ROM_ADDR/$xip_rom_sz"
|
|
|
|
# These two variables are exported exclusively when the XIP_MODE is enabled.
|
|
# They are subsequently captured by the CMake process to participate in
|
|
# downstream compilation.
|
|
FLASH_XIP_START_ADDR=$((RTOS_XIP_ROM_ADDR | $FLASH_XIP_START_ADDR))
|
|
FLASH_XIP_LENGTH=$xip_rom_sz
|
|
printf "\033[1mFLASH_XIP_START_ADDR: 0x%X\033[0m\n" "$FLASH_XIP_START_ADDR"
|
|
printf "\033[1mFLASH_XIP_LENGTH: 0x%X\033[0m\n" "$FLASH_XIP_LENGTH"
|
|
}
|
|
|
|
# Generate a LittleFS image from a specified directory.
|
|
#
|
|
# This function first checks whether the `mklfs` tool exists. If not, it
|
|
# builds the tool from source and installs it to the destination path.
|
|
# Then it invokes `mklfs` to package the specified directory into a
|
|
# LittleFS image with the configured block size, read size, page size,
|
|
# and image size.
|
|
#
|
|
# Arguments:
|
|
# $1 - Source directory name under PKG_IMG_DIR to be packed.
|
|
# $2 - Output filesystem image name.
|
|
# $3 - Filesystem image size in bytes.
|
|
function gen_fs_img() {
|
|
local fs_dir_name=$1
|
|
local fs_img_name=$2
|
|
local fs_img_sz=$3
|
|
local fs_img_dir="${PKG_IMG_DIR}/$fs_dir_name"
|
|
|
|
if [[ ! -e "$RTOS_MKLFS_DST_PATH" ]]; then
|
|
log_dbg "cp $RTOS_MKLFS_SRC_PATH to $RTOS_MKLFS_DST_PATH"
|
|
install -m 777 "${RTOS_MKLFS_SRC_PATH}" "$RTOS_MKLFS_DST_PATH"
|
|
fi
|
|
|
|
pushd $PKG_IMG_DIR >/dev/null 2>&1
|
|
trap 'trap - RETURN; popd >/dev/null 2>&1' RETURN
|
|
|
|
if [[ "${CONFIG_LFS_USE_BLOCK:-n}" == "y" ]]; then
|
|
RTOS_MKLFS_BLOCK_SZ="65536"
|
|
fi
|
|
|
|
./mklfs -c "$fs_dir_name" \
|
|
-b $RTOS_MKLFS_BLOCK_SZ \
|
|
-r $RTOS_MKLFS_READ_SZ \
|
|
-p $RTOS_MKLFS_PAGE_SZ \
|
|
-s "$fs_img_sz" \
|
|
-i "$fs_img_name" || return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# Generate user_rodata LittleFS image and append it to the RTOS kernel image.
|
|
#
|
|
# This function creates a temporary directory under PKG_IMG_DIR, copies
|
|
# all files from CONFIG_USER_RODATA_PATH into it, and generates a
|
|
# LittleFS image by calling gen_fs_img().
|
|
#
|
|
# After the filesystem image is generated, the function pads the kernel
|
|
# image with 0xFF so that its size reaches the end of the kernel
|
|
# partition, then appends the filesystem image to the kernel image.
|
|
#
|
|
# Memory layout:
|
|
# +---------------------------------------------------+
|
|
# | rtos-xip (RTOS_XIP_ROM_ADDR) |
|
|
# +---------------------------------------------------+
|
|
# | Padding area filled with 0xFF |
|
|
# +---------------------------------------------------+
|
|
# | user_rodata LittleFS image |
|
|
# +---------------------------------------------------+
|
|
#
|
|
# Arguments:
|
|
# $1 - Temporary directory name used to generate the filesystem image.
|
|
# $2 - Output LittleFS image name.
|
|
# $3 - Kernel image file path to which the filesystem image is appended.
|
|
function gen_user_rodata_fs_img() {
|
|
local fs_dir_name=$1
|
|
local fs_img_name=$2
|
|
local kernel_file=$3
|
|
|
|
local -i kernel_file_sz=0
|
|
local -i fill_sz=0
|
|
local -i fs_img_sz=0
|
|
|
|
local fs_img_path="$PKG_IMG_DIR/$fs_img_name"
|
|
local fs_dir_path="$PKG_IMG_DIR/$fs_dir_name"
|
|
|
|
[[ -e "$fs_dir_path" ]] && rm -rf "$fs_dir_path"
|
|
mkdir $fs_dir_path
|
|
|
|
if [[ -n "${CONFIG_USER_RODATA_PATH:-""}" ]]; then
|
|
find $CONFIG_USER_RODATA_PATH/ -type f -exec cp {} $fs_dir_path/ \; \
|
|
|| return 1
|
|
fi
|
|
|
|
gen_fs_img "$fs_dir_name" "$fs_img_name" \
|
|
$(printf "%d" "$CONFIG_USER_RODATA_SIZE") || return 1
|
|
|
|
return 0
|
|
|
|
#
|
|
# This code snippet is designed to integrate the user_rodata.lfs into the
|
|
# rtos-xip. However, a more elegant approach involes allocating the
|
|
# user_rodata.lfs into the user partition within U-Boot and mapping it to
|
|
# the user_rodata partition within RTOS. This decoupling facilitates fexibly
|
|
# customization of the user_rodata partition size to meet diverse customer
|
|
# requirements.
|
|
if [[ -f "$kernel_file" ]]; then
|
|
kernel_file_sz=$(stat -c %s "$kernel_file")
|
|
else
|
|
log_err "Error: File $kernel_file does not exist!"
|
|
return 1
|
|
fi
|
|
|
|
if [[ -f "$fs_img_path" ]]; then
|
|
fs_img_sz=$(stat -c %s "$fs_img_path")
|
|
else
|
|
log_err "Error: File $fs_img_path does not exist!"
|
|
return 1
|
|
fi
|
|
|
|
log_dbg "kernel partition size: ${PART_SIZE['kernel']}"
|
|
local kernel_part_sz=$(echo $((PART_SIZE["kernel"])))
|
|
local -i kernel_offset=$((RTOS_XIP_ROM_ADDR - RTOS_XIP_RAM_ADDR))
|
|
|
|
# fill_sz + kernel_file_sz = PART_SIZE['kernel']}
|
|
fill_sz=$((
|
|
kernel_part_sz -
|
|
RTOS_XIP_ROM_ADDR + RTOS_XIP_RAM_ADDR -
|
|
kernel_file_sz))
|
|
|
|
if [[ "$fill_sz" -gt 0 ]]; then
|
|
dd if=/dev/zero bs="$fill_sz" count=1 2>/dev/null | \
|
|
tr '\000' '\377' >> "$kernel_file"
|
|
elif [[ "$fill_sz" -lt 0 ]]; then
|
|
log_err "The size is overflow!"
|
|
fi
|
|
|
|
log_dbg "kernel_file_sz + fill_sz: $kernel_file_sz + $fill_sz"
|
|
|
|
cat "$fs_img_path" >> "$kernel_file" || return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# Prepare an RTOS image for encryption.
|
|
#
|
|
# This function creates a U-Boot compatible RTOS image, prepends a
|
|
# 4032-byte reserved header area, and fills RTOS metadata into the
|
|
# image header.
|
|
#
|
|
# When XIP mode is enabled, additional XIP information, including the
|
|
# partition name, XIP offset, and XIP size, is written into the header.
|
|
#
|
|
# Header layout:
|
|
# Offset Size Description
|
|
# ------ ---- -----------------------------
|
|
# 1 1 XIP enable flag
|
|
# 3 4 RTOS image type/version
|
|
# 7 4 RTOS image size
|
|
# 16 16 Partition name ("boot" or "recovery")
|
|
# 32 4 XIP offset
|
|
# 36 4 XIP image size
|
|
#
|
|
# Arguments:
|
|
# $1 - Source RTOS image file.
|
|
# $2 - Output image file prepared for encryption.
|
|
function pack_rtos_for_encrypt() {
|
|
local src_file=$1
|
|
local dst_file=$2
|
|
|
|
local part_name=""
|
|
local -i src_file_sz=0
|
|
local -i xip_offset=$((RTOS_XIP_ROM_ADDR - RTOS_XIP_RAM_ADDR))
|
|
local -i xip_size=$(stat -c %s ${RTOS_IMG_DIR}/rtos-xip)
|
|
|
|
mkimg_rtos_for_uboot ${ARCH} ${RTOS_LOAD_ADDR} ${RTOS_BIN_FILE} \
|
|
${RTOS_IMG_DIR}/rtos-uImage
|
|
|
|
#preappend 4032B at the beginning and generate image header again
|
|
dd if=/dev/zero bs=4032 count=1 2>/dev/null | \
|
|
cat - "$src_file" > "$dst_file"
|
|
|
|
# Fill the rtos information to header.
|
|
write_od_to_bin_4 "$dst_file" 3 80
|
|
src_file_sz=$(stat -c %s "$src_file")
|
|
src_file_sz=$((src_file_sz + 4032 - 16))
|
|
write_od_to_bin_4 "$dst_file" 7 $src_file_sz
|
|
|
|
if [ "${CONFIG_XIP_MODE:-n}" = "y" ]; then
|
|
if [[ "${PKG_PRODUCT}" == "recovery" ]]; then
|
|
part_name="recovery"
|
|
else
|
|
part_name="boot"
|
|
fi
|
|
|
|
write_od_to_bin_1 "$dst_file" 1 0x1
|
|
|
|
echo -n $part_name | head -c 15 | \
|
|
dd of="$dst_file" bs=1 seek=16 conv=notrunc
|
|
|
|
write_od_to_bin_4 "$dst_file" 32 $xip_offset
|
|
write_od_to_bin_4 "$dst_file" 36 $xip_size
|
|
fi
|
|
|
|
log_dbg "xip_size + xip_offset = $xip_size + $xip_offset"
|
|
}
|
|
|
|
#
|
|
# Compile and package the RTOS image for ARM platforms.
|
|
#
|
|
# This function performs the complete RTOS build workflow, including:
|
|
# Supported features:
|
|
# - XIP (Execute In Place) mode
|
|
# - user_rodata LittleFS image
|
|
# - U-Boot image packaging
|
|
# - MCUboot image packaging
|
|
#
|
|
# Arguments:
|
|
# $1 - Architecture name.
|
|
# $2 - Board name.
|
|
# $3 - Product name.
|
|
# $4 - Package type (e.g. normal, recovery).
|
|
function _compile_rtos_for_arm() {
|
|
# target file path
|
|
RTOS_OUTPUT_DIR=${RTOS_BUILD_DIR}/output/$1-$3-$4
|
|
RTOS_IMG_DIR=${RTOS_OUTPUT_DIR}/images
|
|
RTOS_BIN_FILE=${RTOS_IMG_DIR}/${KERNEL}-signed.bin
|
|
RTOS_DBG_FILE_PREFIX=${RTOS_OUTPUT_DIR}/${KERNEL}/${KERNEL}
|
|
RTOS_BUILD_NINJA="${RTOS_OUTPUT_DIR}/${KERNEL}/build.ninja"
|
|
RTOS_FW_TOOL=${RTOS_BUILD_DIR}/scripts/gen_firmware.py
|
|
RTOS_MKLFS_SRC_PATH="${RTOS_OUTPUT_DIR}/${KERNEL}/mklfs"
|
|
RTOS_MKLFS_DST_PATH="${PKG_IMG_DIR}/mklfs"
|
|
RTOS_WCN_FW_SRC_DIR="${RTOS_BUILD_DIR}/wcn/firmware"
|
|
PKG_PRODUCT=$4
|
|
|
|
pushd $RTOS_BUILD_DIR >/dev/null 2>&1 || return 1
|
|
trap 'trap - RETURN; popd >/dev/null 2>&1' RETURN
|
|
|
|
gen_dot_config $1 $2 $3 $4
|
|
|
|
# Package auxiliary firmware components unless compiling for recovery mode.
|
|
if [[ "${PKG_PRODUCT}" != "recovery" ]]; then
|
|
embed_firmware
|
|
|
|
if [[ "$?" != 0 ]]; then
|
|
log_err "❌ Generate firmware failed!"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
gen_partition_map || return 1
|
|
|
|
# Handle pre-compilation alignment and layout parameters if XIP is enabled.
|
|
if [ "${CONFIG_XIP_MODE:-n}" = "y" ]; then
|
|
export FLASH_XIP_START_ADDR=0xE0000000
|
|
export FLASH_XIP_LENGTH=0x500000
|
|
auto_get_xip_addr_len || return 1
|
|
fi
|
|
|
|
# start compile flow
|
|
[[ -f "${RTOS_BUILD_NINJA}" ]] && rm -f ${RTOS_BUILD_NINJA}
|
|
|
|
if [[ "${CONFIG_BACKTRACE:-n}" == "y" ]]; then
|
|
make backtrace
|
|
else
|
|
make
|
|
fi
|
|
|
|
if [ $? -ne 0 ]; then
|
|
log_err "❌ build rtos image faile error:$?"
|
|
clean_up
|
|
return 1
|
|
fi
|
|
|
|
# If in XIP MODE, the file is xip_ram file
|
|
local kernel_bin=${RTOS_BIN_FILE}
|
|
install -m 644 ${RTOS_OUTPUT_DIR}/${KERNEL}/${KERNEL}.bin ${RTOS_BIN_FILE}
|
|
|
|
# The file is xip_rom file
|
|
if [ "${CONFIG_XIP_MODE:-n}" = "y" ]; then
|
|
install -m 644 ${RTOS_OUTPUT_DIR}/${KERNEL}/freertos_b.bin \
|
|
${RTOS_IMG_DIR}/rtos-xip
|
|
kernel_bin=${RTOS_IMG_DIR}/rtos-xip
|
|
fi
|
|
|
|
if [[ "${CONFIG_USER_RODATA_FS_IMG:-n}" == "y" ]]; then
|
|
gen_user_rodata_fs_img "user_rodata_fs" "user_rodata.lfs" $kernel_bin \
|
|
|| return 1
|
|
fi
|
|
|
|
# rtos load address
|
|
compiler=$RTOS_BUILD_DIR/output/toolchains/$COMPILER-$TOOLCHAIN_KEYWORD
|
|
NM=$compiler/bin/$TOOLCHAIN_KEYWORD-nm
|
|
RTOS_LOAD_ADDR=$(
|
|
$NM -g --defined-only $RTOS_OUTPUT_DIR/$KERNEL/$KERNEL.elf |
|
|
grep image_start |
|
|
awk '{print $1}' |
|
|
sed 's/^0*//'
|
|
)
|
|
|
|
if [[ ! -n "$RTOS_LOAD_ADDR" ]]; then
|
|
log_err "load addr not found"
|
|
return 1
|
|
fi
|
|
|
|
# Package RTOS kernel for uboot.
|
|
if [[ "$BOOTLOADER_TYPE" == "uboot" ]]; then
|
|
pack_rtos_for_encrypt \
|
|
"${RTOS_IMG_DIR}/rtos-uImage" "${RTOS_IMG_DIR}/rtos-uImage.tmp"
|
|
|
|
mkimg_rtos_for_uboot ${ARCH} ${RTOS_LOAD_ADDR} \
|
|
"${RTOS_IMG_DIR}/rtos-uImage.tmp" "${RTOS_IMG_DIR}/rtos-uImage"
|
|
|
|
# Append the XIP ROM to the end of XIP RAM(rtos-uImage).
|
|
if [ "${CONFIG_XIP_MODE:-n}" = "y" ]; then
|
|
local rtos_uimg_size=$(stat -c %s ${RTOS_IMG_DIR}/rtos-uImage)
|
|
local fill_size=$((
|
|
RTOS_XIP_ROM_ADDR - RTOS_XIP_RAM_ADDR - rtos_uimg_size))
|
|
|
|
# Fill up to RTOS_XIP_ROM_ADDR - RTOS_XIP_RAM_ADDR
|
|
dd if=/dev/zero bs=${fill_size} count=1 >> \
|
|
"${RTOS_IMG_DIR}/rtos-uImage"
|
|
cat ${RTOS_IMG_DIR}/rtos-xip >> ${RTOS_IMG_DIR}/rtos-uImage
|
|
fi
|
|
|
|
# Copy rtos img to specify directory
|
|
if [[ "${PKG_PRODUCT}" == "recovery" ]]; then
|
|
install -m 644 ${RTOS_IMG_DIR}/rtos-uImage \
|
|
$PKG_IMG_DIR/rtos.${PKG_PRODUCT}
|
|
else
|
|
install -m 644 ${RTOS_IMG_DIR}/rtos-uImage \
|
|
$PKG_IMG_DIR/rtos-uImage
|
|
fi
|
|
# Package the RTOS kernel for mcuboot.
|
|
elif [ "$BOOTLOADER_TYPE" == "mcuboot" ]; then
|
|
package_kernel_for_mcuboot $1 $3 $4
|
|
test -f ${RTOS_IMG_DIR}/rtos-mcuImage &&\
|
|
cp ${RTOS_IMG_DIR}/rtos-mcuImage $PKG_IMG_DIR/rtos-mcuImage
|
|
else
|
|
log_err "Invalid bootloader type: $BOOTLOADER_TYPE"
|
|
return 1
|
|
fi
|
|
|
|
test -f ${RTOS_DBG_FILE_PREFIX}.lst && \
|
|
cp ${RTOS_DBG_FILE_PREFIX}.lst $PKG_IMG_DIR/$1-$3.lst
|
|
test -f ${RTOS_DBG_FILE_PREFIX}.map && \
|
|
cp ${RTOS_DBG_FILE_PREFIX}.map $PKG_IMG_DIR/$1-$3.map
|
|
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# Compile and package the RTOS image for Xtensa platforms.
|
|
#
|
|
# This function performs the complete RTOS build workflow for Xtensa
|
|
# targets, including environment initialization, firmware compilation,
|
|
# DSP boot variant detection, and exporting final images and debug
|
|
# artifacts.
|
|
#
|
|
# Arguments:
|
|
# $1 - Architecture name.
|
|
# $2 - Board name.
|
|
# $3 - Product name.
|
|
# $4 - Package type.
|
|
function _compile_rtos_for_xtensa() {
|
|
# target file path
|
|
RTOS_OUTPUT_DIR=${RTOS_BUILD_DIR}/output/$1-$3-$4
|
|
|
|
RTOS_IMG_DIR=${RTOS_OUTPUT_DIR}/images
|
|
RTOS_BIN_FILE=${RTOS_IMG_DIR}/${KERNEL}-signed.bin
|
|
RTOS_DBG_FILE_PREFIX=${RTOS_OUTPUT_DIR}/${KERNEL}/${KERNEL}
|
|
|
|
# start compile flow
|
|
pushd "$RTOS_BUILD_DIR" >/dev/null 2>&1
|
|
|
|
set +euo pipefail
|
|
source scripts/env.sh $1 $2 $3 $4
|
|
set -euo pipefail
|
|
|
|
make distclean
|
|
|
|
if [[ "${CONFIG_BACKTRACE:-n}" == "y" ]]; then
|
|
make backtrace
|
|
else
|
|
make
|
|
fi
|
|
|
|
[[ "$?" == 0 ]] || return 1
|
|
|
|
# Extract the DSP boot variant suffix (a/b) for HiFi4/HiFi5 from the third
|
|
# argument. The pattern matches strings like "hifi4a", "hifi4b", "hifi5a",
|
|
# or "hifi5b", and captures only the trailing letter to determine the DSP
|
|
# boot type.
|
|
local dspboot_type=$(echo "$3" |
|
|
grep -oP 'hifi[4-5]\K[a-bA-B]' |
|
|
tr '[:lower:]' '[:upper:]')
|
|
|
|
test -f ${RTOS_BIN_FILE} && \
|
|
cp ${RTOS_BIN_FILE} $PKG_IMG_DIR/dspboot${dspboot_type}.bin
|
|
test -f ${RTOS_DBG_FILE_PREFIX}.lst && \
|
|
cp ${RTOS_DBG_FILE_PREFIX}.lst $PKG_IMG_DIR/$1-$3.lst
|
|
test -f ${RTOS_DBG_FILE_PREFIX}.map && \
|
|
cp ${RTOS_DBG_FILE_PREFIX}.map $PKG_IMG_DIR/$1-$3.map
|
|
|
|
popd >/dev/null 2>&1
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# Compile RTOS for ARM targets with optional log redirection and
|
|
# progress indication.
|
|
#
|
|
# Arguments:
|
|
# $1 - Architecture name.
|
|
# $2 - Board name.
|
|
# $3 - Product name.
|
|
# $4 - Package type.
|
|
function compile_rtos_for_arm() {
|
|
if [[ "$PKG_VERBOSE" == "y" ]]; then
|
|
_compile_rtos_for_arm ${1} ${2} ${3} ${4} || return 1
|
|
else
|
|
waiting_start "Building ${1} ${2} ${3} ${4} ..."
|
|
_compile_rtos_for_arm ${1} ${2} ${3} ${4} >> "$PKG_BUILD_LOG" 2>&1
|
|
waiting_end $? || return 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Compile RTOS for Xtensa targets with optional log redirection and
|
|
# progress indication.
|
|
#
|
|
# This is a wrapper around _compile_rtos_for_xtensa() that controls
|
|
# console output and build log handling based on PKG_VERBOSE.
|
|
#
|
|
# Arguments:
|
|
# $1 - Architecture name.
|
|
# $2 - Board name.
|
|
# $3 - Product name.
|
|
# $4 - Package type.
|
|
function compile_rtos_for_xtensa() {
|
|
if [[ "$PKG_VERBOSE" == "y" ]]; then
|
|
_compile_rtos_for_xtensa ${1} ${2} ${3} ${4} || return 1
|
|
else
|
|
waiting_start "Building ${1} ${2} ${3} ${4} ..."
|
|
_compile_rtos_for_xtensa ${1} ${2} ${3} ${4} >> "$PKG_BUILD_LOG" 2>&1
|
|
waiting_end $? || return 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Build RTOS images for all configured targets.
|
|
#
|
|
# Iterate over all configured targets and invoke the corresponding
|
|
# build function according to the architecture and RTOS_BUILD_CORE.
|
|
function build_rtos() {
|
|
for ((loop = 0; loop < ${#pkg_board[@]}; loop += 1)); do
|
|
if [[ ${pkg_arch[loop]} == *"arm"* ]] \
|
|
&& [[ "$RTOS_BUILD_CORE" == "arm" ]]; then
|
|
compile_rtos_for_arm ${pkg_arch[loop]} ${pkg_soc[loop]} \
|
|
${pkg_board[loop]} ${pkg_product[loop]} || return 1
|
|
|
|
elif [[ ${pkg_arch[loop]} == "xtensa" ]] \
|
|
&& [[ "$RTOS_BUILD_CORE" == "xtensa" ]]; then
|
|
compile_rtos_for_xtensa ${pkg_arch[loop]} ${pkg_soc[loop]} \
|
|
${pkg_board[loop]} ${pkg_product[loop]} || return 1
|
|
fi
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# Generate package images with optional log redirection and progress
|
|
# indication.
|
|
#
|
|
# This is a wrapper around _gen_pkg_img() that controls console output
|
|
# and build log handling based on PKG_VERBOSE.
|
|
function gen_pkg_img() {
|
|
if [[ "$PKG_VERBOSE" == "y" ]]; then
|
|
_gen_pkg_img || return 1
|
|
else
|
|
waiting_start "Packing image file ..."
|
|
_gen_pkg_img >> "$PKG_BUILD_LOG" 2>&1
|
|
waiting_end $? || return 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Generate the upgrade package configuration file from the template.
|
|
#
|
|
# Entries under #[CUSTOM_OPTION] are included only if the referenced
|
|
# image exists in PKG_IMG_DIR, while entries under #[CUSTOM_COMMON]
|
|
# are always preserved.
|
|
function gen_pkg_cfg() {
|
|
local pkg_original_cfg=$PKG_ORIGIN_CFG_DIR/aml_upgrade_package.conf
|
|
PKG_IMG_CFG_FILE="$PKG_IMG_DIR/aml_upgrade_package.conf"
|
|
|
|
custom_state=""
|
|
while IFS= read -r line; do
|
|
if [[ "$line" == "[LIST_NORMAL]" || "$line" == "[LIST_VERIFY]" ]]; then
|
|
echo "$line" >> $PKG_IMG_CFG_FILE
|
|
continue
|
|
fi
|
|
|
|
if [[ "$line" == "#[CUSTOM_OPTION]" ]]; then
|
|
custom_state="OPTION"
|
|
continue
|
|
elif [[ "$line" == "#[CUSTOM_COMMON]" ]]; then
|
|
custom_state="COMMON"
|
|
continue
|
|
fi
|
|
|
|
if [[ "$custom_state" == "OPTION" ]]; then
|
|
local Q='"'
|
|
file=${line#*file=$Q}
|
|
file=${file%%$Q*}
|
|
if [[ -e "$PKG_IMG_DIR/$file" ]]; then
|
|
echo "$line" >> $PKG_IMG_CFG_FILE
|
|
continue
|
|
fi
|
|
elif [[ "$custom_state" == "COMMON" ]]; then
|
|
echo "$line" >> $PKG_IMG_CFG_FILE
|
|
continue
|
|
fi
|
|
|
|
done < $pkg_original_cfg
|
|
}
|
|
|
|
function build_bootloader() {
|
|
if [[ "$PKG_VERBOSE" == "y" ]]; then
|
|
_build_bootloader || return 1
|
|
else
|
|
waiting_start "Building boorloader($BOOTLOADER_TYPE) ..."
|
|
_build_bootloader >> "$PKG_BUILD_LOG" 2>&1
|
|
waiting_end $? || return 1
|
|
fi
|
|
}
|
|
|
|
# Compile the bootloader
|
|
function _build_bootloader() {
|
|
log_info "Building $BOOTLOADER_TYPE ..."
|
|
|
|
if [ "$BOOTLOADER_TYPE" == "mcuboot" ]; then
|
|
|
|
source $RTOS_BUILD_DIR/scripts/package_mcuboot.sh
|
|
compile_mcuboot \
|
|
${pkg_arch[0]} \
|
|
${pkg_soc[0]} \
|
|
${pkg_board[0]} \
|
|
mcuboot \
|
|
$PKG_IMG_DIR
|
|
log_info "Compilation of MCUBoot is successful"
|
|
else
|
|
#Select the compile parameters of the bootstrap
|
|
case ${pkg_board[0]} in
|
|
'ad401_a113l')
|
|
uboot_type="a1_ad401_nand_rtos"
|
|
;;
|
|
'ad403_a113l')
|
|
uboot_type="a1_ad40as_nor_rtos"
|
|
;;
|
|
'ad40as_a113l')
|
|
uboot_type="a1_ad40as_nor_rtos"
|
|
;;
|
|
'ad401_a113l_hifi4a_psram')
|
|
uboot_type="a1_ad401_nor_rtos"
|
|
;;
|
|
'ad403_a113l_hifi4a')
|
|
uboot_type="a1_ad403_nand_rtos"
|
|
;;
|
|
*) ;;
|
|
esac
|
|
if [ -z "$uboot_type" ]; then
|
|
log_warn "Waring: Select board(${pkg_board[0]}) not support uboot"
|
|
return 1
|
|
else
|
|
pushd $RTOS_ROOT_DIR/boot/u-boot
|
|
trap 'trap - RETURN; popd >/dev/null 2>&1' RETURN
|
|
|
|
./mk $uboot_type
|
|
test -f build/u-boot.bin && \
|
|
cp -av build/u-boot.bin* $PKG_IMG_DIR
|
|
return 0
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function gen_ota_img () {
|
|
if [[ "$PKG_VERBOSE" == "y" ]]; then
|
|
_gen_ota_img $PKG_IMG_DIR/aml_upgrade_package.img \
|
|
>> "$PKG_BUILD_LOG" 2>&1 || return 1
|
|
else
|
|
waiting_start "Packing OTA image ..."
|
|
_gen_ota_img $PKG_IMG_DIR/aml_upgrade_package.img \
|
|
>> "$PKG_BUILD_LOG" 2>&1
|
|
waiting_end $? || return 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Generate an OTA package image from the specified upgrade package.
|
|
#
|
|
# This function unpacks the upgrade image, extracts supported
|
|
# partitions, and repackages them into an OTA image.
|
|
#
|
|
# Arguments:
|
|
# $1 - Upgrade package image.
|
|
function _gen_ota_img() {
|
|
local image_package=$1
|
|
|
|
if [[ ! -e "$image_package" ]]; then
|
|
log_err "❌ $image_package does not exist!"
|
|
return 1
|
|
fi
|
|
|
|
local ota_tool=$RTOS_BUILD_DIR/scripts/ota_img_packer.py
|
|
local unpackage_dir=$PKG_IMG_DIR/unpackage
|
|
mkdir -p $unpackage_dir
|
|
$RTOS_ROOT_DIR/image_packer/aml_image_v2_packer \
|
|
-d $image_package $unpackage_dir >/dev/null
|
|
|
|
local ota_cmd_opt=""
|
|
local ota_partition=""
|
|
for f in $unpackage_dir/*; do
|
|
[ -f "$f" ] || continue
|
|
[[ "$f" =~ \.PARTITION$ ]] || continue
|
|
ota_partition=${f%.*}
|
|
ota_partition=${ota_partition##*/}
|
|
if [[ "$ota_partition" == "boot" ]]; then
|
|
ota_partition="kernel"
|
|
else
|
|
continue
|
|
fi
|
|
|
|
ota_cmd_opt+=" -f $f -p $ota_partition"
|
|
done
|
|
|
|
ota_cmd_opt+=" -t ${PKG_IMG_DIR} -o ota_package_img -d -l"
|
|
python3 $RTOS_BUILD_DIR/scripts/ota_img_packer.py $ota_cmd_opt
|
|
}
|
|
|
|
function output_info() {
|
|
log_info "Package Conf: "
|
|
echo -e "\t$PKG_IMG_CFG_FILE"
|
|
|
|
log_info "Package Image: "
|
|
echo -e "\t$PKG_IMG_DIR/aml_upgrade_package.img"
|
|
|
|
if [[ "$PKG_GEN_OTA" == "y" ]]; then
|
|
log_info "OTA Image: "
|
|
echo -e "\t$PKG_IMG_DIR/ota_package_img"
|
|
fi
|
|
|
|
[[ "$PKG_VERBOSE" != "y" ]] && log_info "Build Log: " && \
|
|
echo -e "\t$PKG_IMG_DIR/pkg_build.log"
|
|
}
|
|
|
|
#
|
|
# Generate the AML upgrade package image.
|
|
#
|
|
# This function copies the required configuration files, invokes
|
|
# aml_image_v2_packer to generate aml_upgrade_package.img, and
|
|
# removes temporary files after packaging.
|
|
function _gen_pkg_img() {
|
|
install $PKG_ORIGIN_CFG_DIR/platform.conf $PKG_IMG_DIR/
|
|
install $PKG_ORIGIN_CFG_DIR/usb_flow.aml $PKG_IMG_DIR/
|
|
install $PKG_ORIGIN_CFG_DIR/aml_sdc_burn.ini $PKG_IMG_DIR/
|
|
|
|
$RTOS_ROOT_DIR/image_packer/aml_image_v2_packer \
|
|
-r $PKG_IMG_CFG_FILE \
|
|
$PKG_IMG_DIR \
|
|
$PKG_IMG_DIR/aml_upgrade_package.img
|
|
if [[ "$?" == 0 ]]; then
|
|
log_info "Aml Package Successful!"
|
|
else
|
|
log_err "Aml Package Failed!"
|
|
fi
|
|
|
|
cd $PKG_IMG_DIR >/dev/null 2>&1 && \
|
|
rm $(ls | grep -v ".lst" | grep -v ".map" | grep -v ".img" |
|
|
grep -v ".log" | grep -v ".conf") >/dev/null 2>&1
|
|
cd - >/dev/null 2>&1
|
|
}
|
|
|
|
function parse_param() {
|
|
while getopts "b:vud" opt; do
|
|
case "$opt" in
|
|
b)
|
|
BOOTLOADER_TYPE="$OPTARG"
|
|
;;
|
|
v)
|
|
PKG_VERBOSE="y"
|
|
;;
|
|
u)
|
|
PKG_GEN_OTA="y"
|
|
;;
|
|
d)
|
|
PKG_DBG_EN="y"
|
|
;;
|
|
?)
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
function main() {
|
|
parse_param $@
|
|
|
|
parse_pkg_target || return 1
|
|
|
|
for branch in ${RTOS_BRANCH_TYPES[@]}; do
|
|
arch_dir=$RTOS_ROOT_DIR/rtos/$branch/arch
|
|
export RTOS_BUILD_DIR=$RTOS_ROOT_DIR/rtos/$branch
|
|
|
|
if [[ -d "$arch_dir/arm" || -d "$arch_dir/arm64" ]]; then
|
|
RTOS_BUILD_CORE="arm"
|
|
elif [ -d $arch_dir/xtensa ]; then
|
|
RTOS_BUILD_CORE="xtensa"
|
|
fi
|
|
|
|
build_rtos
|
|
if [[ $? -ne 0 ]]; then
|
|
log_err "Building RTOS failed!"
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
build_bootloader || return 1
|
|
gen_pkg_cfg || return 1
|
|
gen_pkg_img || return 1
|
|
|
|
if [[ "$PKG_GEN_OTA" == "y" ]]; then
|
|
gen_ota_img || return 1
|
|
fi
|
|
|
|
output_info
|
|
}
|
|
|
|
main "$@"
|
|
|
|
set +euo pipefail
|