Address rpardini review round 2: major cleanup
- Use SERIALCON instead of systemd override for serial console - Remove fdtfile from bootenv (use BOOT_FDT_FILE instead) - Remove ATF_COMPILER (arm64 default) - Inline OPTEE variables into fetch_sources_tools hook - Remove empty family_tweaks() and family_tweaks_bsp() - Use only debug mode for ATF build - Build fiptool in atf_custom_postprocess - Move header creation inline into uboot_custom_postprocess - Use <<- heredoc for Python script
This commit is contained in:
parent
e5752ad9ee
commit
60650cf015
@ -11,20 +11,7 @@ BOOT_FDT_FILE="nuvoton/ma35d1-iot-512m.dtb"
|
||||
BOOT_SCENARIO="blobless"
|
||||
IMAGE_PARTITION_TABLE="msdos"
|
||||
DEFAULT_CONSOLE="serial"
|
||||
SERIALCON="ttyS0:115200"
|
||||
|
||||
# Hardware features
|
||||
HAS_VIDEO_OUTPUT="yes"
|
||||
|
||||
function post_family_tweaks__numaker_iot_ma35d16f90() {
|
||||
display_alert "$BOARD" "Applying NuMaker IoT MA35D16F90 tweaks" "info"
|
||||
|
||||
# Serial console 115200 baud
|
||||
mkdir -p "$SDCARD/etc/systemd/system/serial-getty@ttyS0.service.d/"
|
||||
cat <<- EOF > "$SDCARD/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf"
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=-/sbin/agetty -o '-p -- \\u' 115200 ttyS0 linux
|
||||
EOF
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -1,3 +1,2 @@
|
||||
bootlogo=false
|
||||
console=serial
|
||||
fdtfile=nuvoton/ma35d1-iot-512m.dtb
|
||||
|
||||
@ -11,10 +11,6 @@
|
||||
# Boot flow: Mask ROM (IBR) -> BL2 (TF-A) -> BL31 -> BL32 (OP-TEE) -> BL33 (U-Boot) -> Linux
|
||||
ARCH="arm64"
|
||||
|
||||
# Keep kernel version clean (5.10.140 instead of 5.10.140-vendor-nuvoton-ma35d1)
|
||||
# Nuvoton expects exact version for compatibility
|
||||
declare -g LOCALVERSION=""
|
||||
|
||||
# Disable BTF - 5.10.y kernel has issues with newer pahole/toolchain
|
||||
declare -g KERNEL_BTF="no"
|
||||
|
||||
@ -28,45 +24,20 @@ BOOTPATCHDIR="u-boot-nuvoton-ma35d1"
|
||||
BOOTSOURCE='https://github.com/OpenNuvoton/MA35D1_u-boot-v2020.07.git'
|
||||
BOOTBRANCH='branch:master'
|
||||
BOOTDIR='u-boot-nuvoton-ma35d1'
|
||||
# MA35D1 uses TF-A (BL2/BL31) + OP-TEE, not U-Boot SPL
|
||||
# All boot files: header.bin, bl2.bin, bl31.bin, bl2-ma35d1.dtb, tee-header_v2.bin, tee-pager_v2.bin, fip.bin, u-boot.bin
|
||||
UBOOT_TARGET_MAP=";;u-boot.bin header.bin fip.bin bl2.bin bl31.bin bl2-ma35d1.dtb tee-header_v2.bin tee-pager_v2.bin"
|
||||
|
||||
# TF-A source from Nuvoton
|
||||
declare -g ATF_USE_GCC="> 8.0"
|
||||
declare -g ATF_COMPILER="aarch64-linux-gnu-"
|
||||
declare -g ATFSOURCE="https://github.com/OpenNuvoton/MA35D1_arm-trusted-firmware-v2.3.git"
|
||||
declare -g ATFDIR="arm-trusted-firmware-ma35d1"
|
||||
declare -g ATFBRANCH="branch:master"
|
||||
declare -g ATFPATCHDIR="atf-nuvoton-ma35d1"
|
||||
# Fix RWX segment warning with binutils 2.39+ (skip -Wl, prefix for LD flags)
|
||||
declare -g ATF_SKIP_LDFLAGS_WL="yes"
|
||||
|
||||
# OP-TEE source from Nuvoton
|
||||
declare -g OPTEE_SOURCE="https://github.com/OpenNuvoton/MA35D1_optee_os-v3.9.0.git"
|
||||
declare -g OPTEE_DIR="optee-os-ma35d1"
|
||||
declare -g OPTEE_BRANCH="branch:master"
|
||||
declare -g OPTEE_COMPILER="aarch64-linux-gnu-"
|
||||
|
||||
# Host dependencies for OP-TEE build (pycryptodome for signing, pyelftools for ELF parsing)
|
||||
function add_host_dependencies__ma35d1_optee_deps() {
|
||||
display_alert "Adding MA35D1 OP-TEE host dependencies" "python3-pycryptodome python3-pyelftools" "info"
|
||||
declare -g EXTRA_BUILD_DEPS="${EXTRA_BUILD_DEPS} python3-pycryptodome python3-pyelftools"
|
||||
}
|
||||
|
||||
# Fetch OP-TEE source using Armbian's fetch_from_repo mechanism
|
||||
function fetch_sources_tools__ma35d1_fetch_optee() {
|
||||
display_alert "Fetching OP-TEE source" "for MA35D1" "info"
|
||||
fetch_from_repo "${OPTEE_SOURCE}" "${OPTEE_DIR}" "${OPTEE_BRANCH}"
|
||||
}
|
||||
|
||||
# DDR configuration DTB - 512MB for IoT board
|
||||
# Available options: ma35d1-cpu800-wb-512m, ma35d1-cpu1g-wb-512m, etc.
|
||||
declare -g MA35D1_DDR_DTB="${MA35D1_DDR_DTB:-ma35d1-cpu800-wb-512m}"
|
||||
MA35D1_DDR_DTB="${MA35D1_DDR_DTB:-ma35d1-cpu800-wb-512m}"
|
||||
|
||||
# TF-A build: BL2 + BL31 + DTB (FIP is created later in uboot_custom_postprocess)
|
||||
# DEBUG=1 matches platform.mk default, output goes to build/ma35d1/debug/
|
||||
# dtbs target is needed to build DDR configuration DTB
|
||||
declare -g ATF_TARGET_MAP="PLAT=ma35d1 DEBUG=1 DTB_FILE_NAME=${MA35D1_DDR_DTB}.dtb bl2 bl31 dtbs;;build/ma35d1/debug/bl2.bin build/ma35d1/debug/bl31.bin build/ma35d1/debug/fdts/${MA35D1_DDR_DTB}.dtb:bl2-ma35d1.dtb"
|
||||
|
||||
LINUXFAMILY="nuvoton-ma35d1"
|
||||
@ -76,13 +47,7 @@ IMAGE_PARTITION_TABLE="msdos"
|
||||
BOOTSCRIPT="boot-nuvoton-ma35d1.cmd:boot.cmd"
|
||||
BOOTENV_FILE="nuvoton-ma35d1.txt"
|
||||
|
||||
# Clean kernel version - disabled for now, causes packaging issues
|
||||
# Clean kernel version - required for Nuvoton precompiled modules (dcultrafb.ko, ma35d1-vc8000.ko etc.)
|
||||
# These modules have vermagic "5.10.140" and won't load with suffix
|
||||
# enable_extension "nuvoton-clean-kernel-version"
|
||||
|
||||
case "${BRANCH}" in
|
||||
|
||||
vendor)
|
||||
declare -g KERNEL_MAJOR_MINOR="5.10"
|
||||
KERNELSOURCE='https://github.com/OpenNuvoton/MA35D1_linux-5.10.y.git'
|
||||
@ -90,7 +55,6 @@ case "${BRANCH}" in
|
||||
KERNELPATCHDIR="nuvoton-ma35d1-${BRANCH}"
|
||||
LINUXCONFIG="linux-nuvoton-ma35d1-${BRANCH}"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
KERNEL_TARGET="vendor"
|
||||
@ -98,93 +62,59 @@ CPUMIN=180000
|
||||
CPUMAX=800000
|
||||
GOVERNOR="ondemand"
|
||||
|
||||
family_tweaks() {
|
||||
:
|
||||
# Host dependencies for OP-TEE build
|
||||
function add_host_dependencies__ma35d1_optee_deps() {
|
||||
display_alert "Adding MA35D1 OP-TEE host dependencies" "python3-pycryptodome python3-pyelftools" "info"
|
||||
declare -g EXTRA_BUILD_DEPS="${EXTRA_BUILD_DEPS} python3-pycryptodome python3-pyelftools"
|
||||
}
|
||||
|
||||
family_tweaks_bsp() {
|
||||
:
|
||||
# Fetch OP-TEE source using Armbian's fetch_from_repo mechanism
|
||||
function fetch_sources_tools__ma35d1_fetch_optee() {
|
||||
local optee_source="https://github.com/OpenNuvoton/MA35D1_optee_os-v3.9.0.git"
|
||||
local optee_dir="optee-os-ma35d1"
|
||||
local optee_branch="branch:master"
|
||||
|
||||
display_alert "Fetching OP-TEE source" "for MA35D1" "info"
|
||||
fetch_from_repo "${optee_source}" "${optee_dir}" "${optee_branch}"
|
||||
}
|
||||
|
||||
# Custom ATF build for MA35D1 - we need BL2 with DTB embedded
|
||||
# NOTE: atf_custom_postprocess runs BEFORE atftempdir is created!
|
||||
# We are in the ATF source directory at this point (pwd = $SRC/cache/sources/$ATFSOURCEDIR)
|
||||
# ATF post-processing: verify build outputs and build fiptool
|
||||
atf_custom_postprocess() {
|
||||
display_alert "Post-processing ATF" "MA35D1" "info"
|
||||
|
||||
# We're in the ATF source directory, build output is in ./build/
|
||||
local atf_src_dir="$(pwd)"
|
||||
local atf_build_dir=""
|
||||
local atf_build_dir="${atf_src_dir}/build/ma35d1/debug"
|
||||
|
||||
# Debug: show current directory
|
||||
display_alert "ATF source dir" "${atf_src_dir}" "info"
|
||||
|
||||
# Try release directory first (DEBUG=0), then debug (DEBUG=1)
|
||||
if [[ -d "${atf_src_dir}/build/ma35d1/release" ]]; then
|
||||
atf_build_dir="${atf_src_dir}/build/ma35d1/release"
|
||||
display_alert "Using release build" "${atf_build_dir}" "info"
|
||||
elif [[ -d "${atf_src_dir}/build/ma35d1/debug" ]]; then
|
||||
atf_build_dir="${atf_src_dir}/build/ma35d1/debug"
|
||||
display_alert "Using debug build" "${atf_build_dir}" "info"
|
||||
else
|
||||
display_alert "Build directory not found, listing contents" "debug" "warn"
|
||||
ls -la "${atf_src_dir}/build/" 2>/dev/null || echo "No build directory"
|
||||
ls -la "${atf_src_dir}/build/ma35d1/" 2>/dev/null || echo "No ma35d1 directory"
|
||||
exit_with_error "ATF build directory not found in ${atf_src_dir}/build/ma35d1/"
|
||||
if [[ ! -d "${atf_build_dir}" ]]; then
|
||||
exit_with_error "ATF build directory not found: ${atf_build_dir}"
|
||||
fi
|
||||
|
||||
# List what was built
|
||||
display_alert "ATF build contents" "$(ls ${atf_build_dir}/*.bin 2>/dev/null | xargs -n1 basename 2>/dev/null || echo 'none')" "info"
|
||||
# Verify required files
|
||||
[[ -f "${atf_build_dir}/bl2.bin" ]] || exit_with_error "bl2.bin not found in ${atf_build_dir}"
|
||||
[[ -f "${atf_build_dir}/bl31.bin" ]] || exit_with_error "bl31.bin not found in ${atf_build_dir}"
|
||||
[[ -f "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" ]] || exit_with_error "DTB ${MA35D1_DDR_DTB}.dtb not found"
|
||||
|
||||
# Verify bl2.bin and bl31.bin exist
|
||||
if [[ ! -f "${atf_build_dir}/bl2.bin" ]]; then
|
||||
exit_with_error "bl2.bin not found in ${atf_build_dir}"
|
||||
fi
|
||||
# Build fiptool for use in uboot_custom_postprocess
|
||||
display_alert "Building fiptool" "MA35D1" "info"
|
||||
run_host_command_logged make -C "${atf_src_dir}/tools/fiptool" HOSTCC=gcc
|
||||
[[ -x "${atf_src_dir}/tools/fiptool/fiptool" ]] || exit_with_error "fiptool build failed"
|
||||
|
||||
if [[ ! -f "${atf_build_dir}/bl31.bin" ]]; then
|
||||
exit_with_error "bl31.bin not found in ${atf_build_dir}"
|
||||
fi
|
||||
|
||||
# Look for DTB
|
||||
local dtb_file=""
|
||||
if [[ -f "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" ]]; then
|
||||
dtb_file="${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb"
|
||||
display_alert "DTB found" "${dtb_file}" "info"
|
||||
else
|
||||
display_alert "DTB not found in fdts/" "listing available DTBs" "warn"
|
||||
ls -la "${atf_build_dir}/fdts/"*.dtb 2>/dev/null || echo "No DTB files found"
|
||||
fi
|
||||
|
||||
# Export the build directory path for use by the target_files copy
|
||||
# The DTB will be copied via ATF_TARGET_MAP, we just verify it exists here
|
||||
display_alert "ATF post-processing complete" "bl2.bin + bl31.bin ready" "info"
|
||||
display_alert "ATF post-processing complete" "bl2.bin + bl31.bin + fiptool ready" "info"
|
||||
}
|
||||
|
||||
# Compile OP-TEE for MA35D1
|
||||
# Called from uboot_custom_postprocess to build OP-TEE before FIP creation
|
||||
compile_optee_ma35d1() {
|
||||
local optee_src_dir="${SRC}/cache/sources/${OPTEE_DIR}"
|
||||
local optee_src_dir="${SRC}/cache/sources/optee-os-ma35d1"
|
||||
local optee_out_dir="${optee_src_dir}/out/arm-plat-nuvoton/core"
|
||||
|
||||
display_alert "Compiling OP-TEE" "MA35D1" "info"
|
||||
|
||||
# OP-TEE source is fetched via fetch_sources_tools__ma35d1_fetch_optee()
|
||||
# Build dependencies are declared via add_host_dependencies__ma35d1_optee_deps()
|
||||
if [[ ! -d "${optee_src_dir}" ]]; then
|
||||
exit_with_error "OP-TEE source not found at ${optee_src_dir} - fetch_sources_tools hook may have failed"
|
||||
fi
|
||||
[[ -d "${optee_src_dir}" ]] || exit_with_error "OP-TEE source not found at ${optee_src_dir}"
|
||||
|
||||
# Determine cross compiler - use system compiler directly
|
||||
local cross_compile="aarch64-linux-gnu-"
|
||||
|
||||
# Clean previous build to avoid stale artifacts
|
||||
run_host_command_logged make -C "${optee_src_dir}" clean PLATFORM=nuvoton-MA35D1 2>/dev/null || true
|
||||
|
||||
# Build OP-TEE
|
||||
# Note: Using system cross-compiler
|
||||
# LDFLAGS: --no-warn-rwx-segments suppresses RWX segment warning in binutils 2.39+
|
||||
# NOWERROR=1: Treats warnings as warnings, not errors
|
||||
# V=1: Verbose output to see actual linker command and errors
|
||||
display_alert "Building OP-TEE" "PLATFORM=nuvoton-MA35D1" "info"
|
||||
run_host_command_logged make -C "${optee_src_dir}" \
|
||||
CROSS_COMPILE_core="${cross_compile}" \
|
||||
@ -194,74 +124,44 @@ compile_optee_ma35d1() {
|
||||
CFG_TEE_CORE_LOG_LEVEL=1 \
|
||||
LDFLAGS="--no-warn-rwx-segments" \
|
||||
NOWERROR=1 \
|
||||
V=1 \
|
||||
-j$(nproc)
|
||||
|
||||
# Verify output files
|
||||
if [[ ! -f "${optee_out_dir}/tee-header_v2.bin" ]]; then
|
||||
exit_with_error "OP-TEE build failed: tee-header_v2.bin not found"
|
||||
fi
|
||||
if [[ ! -f "${optee_out_dir}/tee-pager_v2.bin" ]]; then
|
||||
exit_with_error "OP-TEE build failed: tee-pager_v2.bin not found"
|
||||
fi
|
||||
[[ -f "${optee_out_dir}/tee-header_v2.bin" ]] || exit_with_error "OP-TEE build failed: tee-header_v2.bin not found"
|
||||
[[ -f "${optee_out_dir}/tee-pager_v2.bin" ]] || exit_with_error "OP-TEE build failed: tee-pager_v2.bin not found"
|
||||
|
||||
display_alert "OP-TEE built successfully" "$(ls -la ${optee_out_dir}/tee-*.bin 2>/dev/null | wc -l) files" "info"
|
||||
display_alert "OP-TEE built successfully" "MA35D1" "info"
|
||||
}
|
||||
|
||||
# Post-process U-Boot: create FIP and Nuvoton boot header
|
||||
uboot_custom_postprocess() {
|
||||
display_alert "Creating MA35D1 boot images" "BL2 + OP-TEE + FIP + Header" "info"
|
||||
|
||||
# Debug: list available files from ATF
|
||||
display_alert "U-Boot build directory" "$(pwd)" "info"
|
||||
display_alert "Available .bin files" "$(ls -la *.bin 2>/dev/null | head -5)" "debug"
|
||||
|
||||
# ATF source directory (for fiptool and DTB)
|
||||
local atf_dir="${SRC}/cache/sources/${ATFDIR}/${ATFBRANCH##*:}"
|
||||
local atf_build_dir="${atf_dir}/build/ma35d1/debug"
|
||||
local fiptool="${atf_dir}/tools/fiptool/fiptool"
|
||||
|
||||
# Find ATF build directory (debug or release)
|
||||
local atf_build_dir=""
|
||||
if [[ -d "${atf_dir}/build/ma35d1/debug" ]]; then
|
||||
atf_build_dir="${atf_dir}/build/ma35d1/debug"
|
||||
elif [[ -d "${atf_dir}/build/ma35d1/release" ]]; then
|
||||
atf_build_dir="${atf_dir}/build/ma35d1/release"
|
||||
fi
|
||||
# Verify fiptool exists (built in atf_custom_postprocess)
|
||||
[[ -x "${fiptool}" ]] || exit_with_error "fiptool not found at ${fiptool}"
|
||||
|
||||
# Copy DTB from ATF build if not already present
|
||||
if [[ -n "${atf_build_dir}" ]] && [[ -f "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" ]]; then
|
||||
display_alert "Copying DTB from ATF" "${MA35D1_DDR_DTB}.dtb" "info"
|
||||
if [[ ! -f "bl2-ma35d1.dtb" ]] && [[ -f "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" ]]; then
|
||||
cp "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" "bl2-ma35d1.dtb"
|
||||
else
|
||||
display_alert "DTB not found in ATF build" "boot may fail without DDR config" "warn"
|
||||
fi
|
||||
|
||||
# Build fiptool if not exists
|
||||
if [[ ! -x "${fiptool}" ]]; then
|
||||
display_alert "Building fiptool" "MA35D1" "info"
|
||||
run_host_command_logged make -C "${atf_dir}/tools/fiptool" HOSTCC=gcc
|
||||
fi
|
||||
|
||||
# Check required files - show what's available if not found
|
||||
if [[ ! -f "bl2.bin" ]]; then
|
||||
display_alert "Files in directory" "$(ls -la)" "warn"
|
||||
exit_with_error "bl2.bin not found in u-boot build directory"
|
||||
fi
|
||||
|
||||
if [[ ! -f "bl31.bin" ]]; then
|
||||
exit_with_error "bl31.bin not found in u-boot build directory"
|
||||
fi
|
||||
# Verify required files
|
||||
[[ -f "bl2.bin" ]] || exit_with_error "bl2.bin not found"
|
||||
[[ -f "bl31.bin" ]] || exit_with_error "bl31.bin not found"
|
||||
[[ -f "bl2-ma35d1.dtb" ]] || exit_with_error "bl2-ma35d1.dtb not found"
|
||||
|
||||
# Build OP-TEE
|
||||
compile_optee_ma35d1
|
||||
|
||||
# Copy OP-TEE binaries
|
||||
local optee_out_dir="${SRC}/cache/sources/${OPTEE_DIR}/out/arm-plat-nuvoton/core"
|
||||
local optee_out_dir="${SRC}/cache/sources/optee-os-ma35d1/out/arm-plat-nuvoton/core"
|
||||
cp "${optee_out_dir}/tee-header_v2.bin" .
|
||||
cp "${optee_out_dir}/tee-pager_v2.bin" .
|
||||
|
||||
# Create fip.bin: bl31 + OP-TEE (tee-header + tee-pager) + u-boot
|
||||
# Boot flow: BL31 -> BL32 (OP-TEE) -> BL33 (U-Boot)
|
||||
# Create FIP
|
||||
display_alert "Creating FIP" "bl31 + optee + u-boot" "info"
|
||||
run_host_command_logged "${fiptool}" create \
|
||||
--soc-fw bl31.bin \
|
||||
@ -271,213 +171,103 @@ uboot_custom_postprocess() {
|
||||
fip.bin
|
||||
|
||||
# Create Nuvoton boot header for SD card boot
|
||||
# Header format: https://github.com/OpenNuvoton/MA35D1_NuWriter
|
||||
create_ma35d1_header
|
||||
display_alert "Creating Nuvoton boot header" "SD card" "info"
|
||||
|
||||
python3 <<- 'HEADER_SCRIPT'
|
||||
import struct
|
||||
import os
|
||||
import binascii
|
||||
|
||||
HEADER_VERSION = 0x20210107
|
||||
BL2_ENTRY = 0x28000000
|
||||
BL2_DTB_LOAD = 0x28023000
|
||||
BL2_LOAD = 0x28000000
|
||||
IMG_TYPE_DATA = 3
|
||||
IMG_TYPE_EXEC = 4
|
||||
|
||||
dtb_offset = 0x20000
|
||||
bl2_offset = 0x30000
|
||||
|
||||
bl2_size = os.path.getsize('bl2.bin')
|
||||
dtb_size = os.path.getsize('bl2-ma35d1.dtb') if os.path.exists('bl2-ma35d1.dtb') else 0
|
||||
|
||||
header = bytearray(512)
|
||||
struct.pack_into('<I', header, 0, 0x4E565420)
|
||||
struct.pack_into('<I', header, 8, 0xC0)
|
||||
struct.pack_into('<I', header, 12, HEADER_VERSION)
|
||||
|
||||
struct.pack_into('<H', header, 16, 2048)
|
||||
struct.pack_into('<H', header, 18, 64)
|
||||
struct.pack_into('<H', header, 20, 64)
|
||||
struct.pack_into('<B', header, 22, 0x6B)
|
||||
struct.pack_into('<B', header, 23, 0x05)
|
||||
struct.pack_into('<B', header, 24, 0x01)
|
||||
struct.pack_into('<B', header, 25, 0x02)
|
||||
struct.pack_into('<B', header, 26, 0)
|
||||
struct.pack_into('<B', header, 27, 1)
|
||||
struct.pack_into('<B', header, 28, 1)
|
||||
for i in range(29, 32):
|
||||
header[i] = 0xFF
|
||||
|
||||
struct.pack_into('<I', header, 32, BL2_ENTRY)
|
||||
struct.pack_into('<I', header, 36, 2)
|
||||
|
||||
desc_offset = 40
|
||||
DESC_SIZE = 80
|
||||
|
||||
struct.pack_into('<I', header, desc_offset + 0, dtb_offset)
|
||||
struct.pack_into('<I', header, desc_offset + 4, BL2_DTB_LOAD)
|
||||
struct.pack_into('<I', header, desc_offset + 8, dtb_size)
|
||||
struct.pack_into('<I', header, desc_offset + 12, IMG_TYPE_DATA)
|
||||
for i in range(desc_offset + 16, desc_offset + DESC_SIZE):
|
||||
header[i] = 0xFF
|
||||
desc_offset += DESC_SIZE
|
||||
|
||||
struct.pack_into('<I', header, desc_offset + 0, bl2_offset)
|
||||
struct.pack_into('<I', header, desc_offset + 4, BL2_LOAD)
|
||||
struct.pack_into('<I', header, desc_offset + 8, bl2_size)
|
||||
struct.pack_into('<I', header, desc_offset + 12, IMG_TYPE_EXEC)
|
||||
for i in range(desc_offset + 16, desc_offset + DESC_SIZE):
|
||||
header[i] = 0xFF
|
||||
|
||||
total_header_size = 200
|
||||
checksum = binascii.crc32(header[8:total_header_size]) & 0xFFFFFFFF
|
||||
struct.pack_into('<I', header, 4, checksum)
|
||||
|
||||
with open('header.bin', 'wb') as f:
|
||||
f.write(header[:total_header_size])
|
||||
|
||||
print(f"Header created: {total_header_size} bytes, CRC=0x{checksum:08x}")
|
||||
HEADER_SCRIPT
|
||||
|
||||
[[ -f "header.bin" ]] || exit_with_error "Failed to create boot header"
|
||||
|
||||
display_alert "MA35D1 boot images created" "header.bin + bl2.bin + fip.bin" "info"
|
||||
}
|
||||
|
||||
# Create Nuvoton boot header for SD card
|
||||
# Based on AN0000 MA35D1 Secure Boot documentation and NuWriter source
|
||||
create_ma35d1_header() {
|
||||
display_alert "Creating Nuvoton boot header" "SD card" "info"
|
||||
|
||||
# Header layout (512 bytes) - from NuWriter:
|
||||
# 0x00-0x03: Boot marker 0x4E565420 ("NVT ")
|
||||
# 0x04-0x07: CRC32 checksum
|
||||
# 0x08-0x0B: Header length
|
||||
# 0x0C-0x0F: Version
|
||||
# 0x10-0x23: SPI info (20 bytes) - zeros for SD boot
|
||||
# 0x24-0x27: Entry point (BL2 entry = 0x28000000)
|
||||
# 0x28-0x2B: Image count
|
||||
# 0x2C+: Image descriptors (each 80 bytes)
|
||||
|
||||
# Image descriptor (80 bytes):
|
||||
# 0x00-0x03: Flash offset
|
||||
# 0x04-0x07: Load address
|
||||
# 0x08-0x0B: Image size
|
||||
# 0x0C-0x0F: Image type (3=data, 4=executable)
|
||||
# 0x10-0x2F: R signature (32 bytes) - zeros for non-secure
|
||||
# 0x30-0x4B: S signature (32 bytes) - zeros for non-secure
|
||||
|
||||
local header_file="header.bin"
|
||||
local bl2_file="bl2.bin"
|
||||
local bl2_dtb_file="bl2-ma35d1.dtb"
|
||||
local fip_file="fip.bin"
|
||||
|
||||
# SD card layout (sector = 512 bytes):
|
||||
# Sector 0: MBR (reserved)
|
||||
# Sector 1: Reserved
|
||||
# Sector 2: Header 0
|
||||
# Sector 3: Header 1 (backup)
|
||||
# Images follow at specified offsets
|
||||
|
||||
# Image offsets (in bytes from start of device)
|
||||
# These must match write_uboot_platform offsets AND Yocto/NuWriter layout
|
||||
# See: meta-ma35d1/recipes-devtools/python/files/pack-sdcard.json
|
||||
local dtb_offset=0x20000 # 128KB (Yocto: 0x20000)
|
||||
local bl2_offset=0x30000 # 192KB (Yocto: 0x30000)
|
||||
local fip_offset=0xC0000 # 768KB (Yocto: 0xC0000)
|
||||
|
||||
# Create header using Python
|
||||
python3 << 'HEADER_SCRIPT'
|
||||
import struct
|
||||
import os
|
||||
import binascii
|
||||
|
||||
# Header constants - matching Yocto/NuWriter format
|
||||
HEADER_VERSION = 0x20210107 # Match Yocto version
|
||||
BL2_ENTRY = 0x28000000
|
||||
BL2_DTB_LOAD = 0x28023000 # Yocto uses 0x28023000, not 0x28030000
|
||||
BL2_LOAD = 0x28000000
|
||||
|
||||
# Image types
|
||||
IMG_TYPE_DATA = 3
|
||||
IMG_TYPE_EXEC = 4
|
||||
|
||||
# Offsets matching Yocto layout
|
||||
dtb_offset = 0x20000 # 128KB
|
||||
bl2_offset = 0x30000 # 192KB
|
||||
# Note: FIP is NOT in header, BL2 knows where to find it
|
||||
|
||||
# Get file sizes
|
||||
bl2_size = os.path.getsize('bl2.bin')
|
||||
dtb_exists = os.path.exists('bl2-ma35d1.dtb')
|
||||
dtb_size = os.path.getsize('bl2-ma35d1.dtb') if dtb_exists else 0
|
||||
|
||||
# Header structure:
|
||||
# - Magic + CRC: 8 bytes (0x00-0x07)
|
||||
# - Length + Version + SPI + Entry + Count: 32 bytes (0x08-0x27)
|
||||
# - 2 descriptors: 160 bytes (0x28-0xC7)
|
||||
# Total: 200 bytes (0xC8), padded to 512 for sector alignment
|
||||
# Header length field (0xC0) = size excluding magic+CRC (192 bytes)
|
||||
header = bytearray(512)
|
||||
|
||||
# === HEADER STRUCTURE (matching NuWriter/Yocto) ===
|
||||
# Offset 0x00-0x03: Magic "NVT " (0x4E565420)
|
||||
# Offset 0x04-0x07: CRC32 checksum
|
||||
# Offset 0x08-0x0B: Header length (0xC0 = 192, excluding magic+CRC)
|
||||
# Offset 0x0C-0x0F: Version
|
||||
# Offset 0x10-0x1F: SPI info (16 bytes)
|
||||
# Offset 0x20-0x23: Entry point
|
||||
# Offset 0x24-0x27: Image count
|
||||
# Offset 0x28+: Image descriptors (80 bytes each)
|
||||
|
||||
# Boot marker (offset 0) - little-endian integer like Yocto!
|
||||
struct.pack_into('<I', header, 0, 0x4E565420)
|
||||
|
||||
# Checksum placeholder (offset 4) - calculated later
|
||||
# Header length (offset 8)
|
||||
struct.pack_into('<I', header, 8, 0xC0)
|
||||
|
||||
# Version (offset 12)
|
||||
struct.pack_into('<I', header, 12, HEADER_VERSION)
|
||||
|
||||
# SPI info (offset 16-31, 16 bytes total)
|
||||
struct.pack_into('<H', header, 16, 2048) # pagesize
|
||||
struct.pack_into('<H', header, 18, 64) # sparearea
|
||||
struct.pack_into('<H', header, 20, 64) # pageperblk
|
||||
struct.pack_into('<B', header, 22, 0x6B) # quadread
|
||||
struct.pack_into('<B', header, 23, 0x05) # readsts
|
||||
struct.pack_into('<B', header, 24, 0x01) # writests
|
||||
struct.pack_into('<B', header, 25, 0x02) # stsvalue
|
||||
struct.pack_into('<B', header, 26, 0) # dummy1
|
||||
struct.pack_into('<B', header, 27, 1) # dummy2
|
||||
struct.pack_into('<B', header, 28, 1) # suspintvl
|
||||
# Fill remaining SPI info bytes with 0xFF (offset 29-31)
|
||||
for i in range(29, 32):
|
||||
header[i] = 0xFF
|
||||
|
||||
# Entry point (offset 0x20 = 32)
|
||||
struct.pack_into('<I', header, 32, BL2_ENTRY)
|
||||
|
||||
# Image count (offset 0x24 = 36)
|
||||
img_count = 2
|
||||
struct.pack_into('<I', header, 36, img_count)
|
||||
|
||||
# Image descriptors start at offset 0x28 = 40
|
||||
desc_offset = 40
|
||||
DESC_SIZE = 80 # Each descriptor: 16 bytes metadata + 64 bytes ECDSA signatures
|
||||
|
||||
# Image 0: BL2 DTB (data type)
|
||||
struct.pack_into('<I', header, desc_offset + 0, dtb_offset) # Flash offset
|
||||
struct.pack_into('<I', header, desc_offset + 4, BL2_DTB_LOAD) # Load address
|
||||
struct.pack_into('<I', header, desc_offset + 8, dtb_size) # Size
|
||||
struct.pack_into('<I', header, desc_offset + 12, IMG_TYPE_DATA) # Type
|
||||
# Fill signature fields with 0xFF (offset 16-79 within descriptor)
|
||||
for i in range(desc_offset + 16, desc_offset + DESC_SIZE):
|
||||
header[i] = 0xFF
|
||||
desc_offset += DESC_SIZE
|
||||
|
||||
# Image 1: BL2 (executable type)
|
||||
struct.pack_into('<I', header, desc_offset + 0, bl2_offset) # Flash offset
|
||||
struct.pack_into('<I', header, desc_offset + 4, BL2_LOAD) # Load address
|
||||
struct.pack_into('<I', header, desc_offset + 8, bl2_size) # Size
|
||||
struct.pack_into('<I', header, desc_offset + 12, IMG_TYPE_EXEC) # Type
|
||||
# Fill signature fields with 0xFF
|
||||
for i in range(desc_offset + 16, desc_offset + DESC_SIZE):
|
||||
header[i] = 0xFF
|
||||
|
||||
# NO FIP in header - BL2 loads it from known location (0xC0000)
|
||||
|
||||
# Calculate actual header size: 40 (fixed) + 2*80 (descriptors) = 200 bytes
|
||||
header_data_size = 0xC0 # 192 bytes (excluding magic+CRC)
|
||||
total_header_size = 8 + header_data_size # 200 bytes = 0xC8
|
||||
|
||||
# CRC32 covers bytes from offset 8 to end of header (bytes 8-199)
|
||||
checksum = binascii.crc32(header[8:total_header_size]) & 0xFFFFFFFF
|
||||
struct.pack_into('<I', header, 4, checksum)
|
||||
|
||||
# Write header (only the actual header bytes, not padding)
|
||||
with open('header.bin', 'wb') as f:
|
||||
f.write(header[:total_header_size])
|
||||
|
||||
print(f"Header created: {total_header_size} bytes, {img_count} images, CRC=0x{checksum:08x}")
|
||||
print(f" DTB: offset=0x{dtb_offset:x}, load=0x{BL2_DTB_LOAD:x}, size={dtb_size}")
|
||||
print(f" BL2: offset=0x{bl2_offset:x}, load=0x{BL2_LOAD:x}, size={bl2_size}")
|
||||
HEADER_SCRIPT
|
||||
|
||||
if [[ ! -f "header.bin" ]]; then
|
||||
exit_with_error "Failed to create Nuvoton boot header"
|
||||
fi
|
||||
}
|
||||
|
||||
# Write bootloader to SD card/image
|
||||
# Layout based on Nuvoton AN0000 documentation
|
||||
# Note: This only works during image creation, not on target board
|
||||
write_uboot_platform() {
|
||||
local src_dir="$1"
|
||||
local target_dev="$2"
|
||||
|
||||
display_alert "Writing MA35D1 bootloader" "${target_dev}" "info"
|
||||
|
||||
# Files to write
|
||||
local header_bin="${src_dir}/header.bin"
|
||||
local bl2_dtb_bin="${src_dir}/bl2-ma35d1.dtb"
|
||||
local bl2_bin="${src_dir}/bl2.bin"
|
||||
local fip_bin="${src_dir}/fip.bin"
|
||||
|
||||
# SD card layout (matching Yocto/NuWriter - pack-sdcard.json):
|
||||
# Sector 2 (0x400): Header 0
|
||||
# Sector 3 (0x600): Header 1 (backup)
|
||||
# 0x20000 (128KB): BL2 DTB
|
||||
# 0x30000 (192KB): BL2
|
||||
# 0xC0000 (768KB): FIP
|
||||
[[ -f "${header_bin}" ]] || { display_alert "Missing" "header.bin" "err"; return 1; }
|
||||
[[ -f "${bl2_bin}" ]] || { display_alert "Missing" "bl2.bin" "err"; return 1; }
|
||||
[[ -f "${fip_bin}" ]] || { display_alert "Missing" "fip.bin" "err"; return 1; }
|
||||
|
||||
# Write Header 0 at sector 2 (offset 1024 = 0x400)
|
||||
dd if="${header_bin}" of="${target_dev}" bs=512 seek=2 conv=notrunc status=none
|
||||
|
||||
# Write Header 1 (backup) at sector 3 (offset 1536 = 0x600)
|
||||
dd if="${header_bin}" of="${target_dev}" bs=512 seek=3 conv=notrunc status=none
|
||||
|
||||
# Write BL2 DTB at 128KB offset (0x20000)
|
||||
if [[ -f "${bl2_dtb_bin}" ]]; then
|
||||
dd if="${bl2_dtb_bin}" of="${target_dev}" bs=1024 seek=128 conv=notrunc status=none
|
||||
fi
|
||||
[[ -f "${bl2_dtb_bin}" ]] && dd if="${bl2_dtb_bin}" of="${target_dev}" bs=1024 seek=128 conv=notrunc status=none
|
||||
|
||||
# Write BL2 at 192KB offset (0x30000)
|
||||
dd if="${bl2_bin}" of="${target_dev}" bs=1024 seek=192 conv=notrunc status=none
|
||||
|
||||
# Write FIP at 768KB offset (0xC0000)
|
||||
dd if="${fip_bin}" of="${target_dev}" bs=1024 seek=768 conv=notrunc status=none
|
||||
|
||||
display_alert "Bootloader written" "header + bl2 + fip" "info"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user