Add a script to help build a functional U-Boot binary for the ZynqMP Kria KV260. Also add some documentation.
Signed-off-by: Jerome Forissier <jerome.foriss...@linaro.org> --- doc/board/xilinx/index.rst | 1 + doc/board/xilinx/zynqmp-kv260.rst | 27 +++++++++ tools/zynqmp_kv260_build.sh | 43 ++++++++++++++ tools/zynqmp_pmufw_elf_convert.py | 96 +++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 doc/board/xilinx/zynqmp-kv260.rst create mode 100755 tools/zynqmp_kv260_build.sh create mode 100755 tools/zynqmp_pmufw_elf_convert.py diff --git a/doc/board/xilinx/index.rst b/doc/board/xilinx/index.rst index 2e31fe3f3a4..3f3a85b709c 100644 --- a/doc/board/xilinx/index.rst +++ b/doc/board/xilinx/index.rst @@ -9,4 +9,5 @@ Xilinx xilinx zynq zynqmp + zynqmp-kv260 zynqmp-r5 diff --git a/doc/board/xilinx/zynqmp-kv260.rst b/doc/board/xilinx/zynqmp-kv260.rst new file mode 100644 index 00000000000..219bbd602e9 --- /dev/null +++ b/doc/board/xilinx/zynqmp-kv260.rst @@ -0,0 +1,27 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. (C) Copyright 2025 Linaro Ltd. + +ZYNQMP KV260 +============ + +Building +-------- + +To build for the KV260: + + $ ./tools/zynqmp_kv260_build.sh + +The first invocation will fetch and build some required binaries (bl31.bin, +pm_cfg_obj.o, pmufw.bin). Subsequently `make` can be invoked directly as +follows: + + $ export BL31=bl31.bin + # export CROSS_COMPILE=aarch64-linux-gnu- + $ make -j$(nproc) BINMAN_ALLOW_MISSING=1 + +Flashing +-------- + +Press the FWUEN button on the carrier board, the press and release the RESET +button, then release FWUEN. Connect to the embedded HTTP server and upload +`qspi.bin`. Press and release RESET again. diff --git a/tools/zynqmp_kv260_build.sh b/tools/zynqmp_kv260_build.sh new file mode 100755 index 00000000000..3cf7147e3a6 --- /dev/null +++ b/tools/zynqmp_kv260_build.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2025 Linaro Ltd. + +set -ex + +if [ "$1" == "-c" ]; then + rm -f bl31.bin pmufw.elf pmufw.bin pm_cfg_obj.c pm_cfg_obj.o + exit 0 +fi +[ -e bl31.bin ] || { + ATF_SRC=$(mktemp -d /tmp/arm-trusted-firmware.XXXXXXXXXX) + git clone https://github.com/ARM-software/arm-trusted-firmware ${ATF_SRC} + make -C ${ATF_SRC} -j$(nproc) bl31 CROSS_COMPILE=aarch64-linux-gnu- \ + LOG_LEVEL=40 ZYNQMP_CONSOLE=cadence1 CONSOLE_RUNTIME=cadence1 \ + RESET_TO_BL31=1 PLAT=zynqmp ZYNQMP_ATF_MEM_BASE=0x10000 \ + ZYNQMP_ATF_MEM_SIZE=0x2ffff ENABLE_LTO=1 + cp ${ATF_SRC}/build/zynqmp/release/bl31.bin . + rm -rf ${ATF_SRC} +} +[ -e pmufw.bin ] || { + wget https://github.com/Xilinx/soc-prebuilt-firmware/raw/refs/heads/xlnx_rel_v2023.1/kv260-kria/pmufw.elf + ./tools/zynqmp_pmufw_elf_convert.py pmufw.elf pmufw.bin +} +[ -e pm_cfg_obj.o ] || { + wget https://github.com/Xilinx/embeddedsw/raw/refs/heads/xlnx_rel_v2023.1/lib/sw_apps/zynqmp_fsbl/misc/pm_cfg_obj.c + ./tools/zynqmp_pm_cfg_obj_convert.py pm_cfg_obj.c pm_cfg_obj.o +} +[ -e .config ] || { + make xilinx_zynqmp_kria_defconfig + cat << EOF >> .config +CONFIG_PMUFW_INIT_FILE="pmufw.bin" +CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE="pm_cfg_obj.o" +CONFIG_BL31_LOAD_ADDR=0x10000 +CONFIG_BL32_LOAD_ADDR=0 +EOF +} +export BL31=bl31.bin +export BL32= +export TEE= +export CROSS_COMPILE=aarch64-linux-gnu- +make -j$(nproc) BINMAN_ALLOW_MISSING=1 diff --git a/tools/zynqmp_pmufw_elf_convert.py b/tools/zynqmp_pmufw_elf_convert.py new file mode 100755 index 00000000000..b4eb2695831 --- /dev/null +++ b/tools/zynqmp_pmufw_elf_convert.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2025 Linaro Ltd. +# +# Written by Gemini (Google AI) then reviewed and edited to remove some comments + +import sys +from elftools.elf.elffile import ELFFile +from elftools.elf.segments import Segment +from elftools.common.exceptions import ELFError + +def elf_to_bin_with_elftools(elf_path, bin_path): + """ + Converts a Microblaze ELF file to a raw binary (.bin) + by extracting LOAD segments using the elftools library. + + Args: + elf_path (str): Path to the input .elf file. + bin_path (str): Path for the output .bin file. + """ + try: + with open(elf_path, 'rb') as f: + elffile = ELFFile(f) + + if elffile.header['e_machine'] not in ('EM_MICROBLAZE', 'EM_MICROBLAZE_OLD'): + print(f"Error: ELF machine type is {elffile.header['e_machine']}, " + f"not typical Microblaze.") + return + + print(f"ELF Header Info:") + print(f" Entry Point: 0x{elffile.header['e_entry']:08X}") + print(f" Endianness: {elffile.little_endian and 'Little-endian' or 'Big-endian'}") + + load_segments = [] + for segment in elffile.iter_segments(): + if segment.header['p_type'] == 'PT_LOAD': + load_segments.append(segment) + print(f" Found LOAD segment:") + print(f" Offset: 0x{segment.header['p_offset']:08X}, VAddr: 0x{segment.header['p_vaddr']:08X}") + print(f" File Size: {segment.header['p_filesz']} bytes, Memory Size: {segment.header['p_memsz']} bytes") + + if not load_segments: + print("Error: No LOADable segments found in the ELF file. Cannot create binary.") + return + + load_segments.sort(key=lambda seg: seg.header['p_vaddr']) + + min_vaddr = load_segments[0].header['p_vaddr'] + max_vaddr = 0 + for segment in load_segments: + end_vaddr = segment.header['p_vaddr'] + segment.header['p_memsz'] + if end_vaddr > max_vaddr: + max_vaddr = end_vaddr + + total_bin_size = max_vaddr - min_vaddr + print(f"Calculated binary memory range: 0x{min_vaddr:08X} to 0x{max_vaddr:08X} (Size: {total_bin_size} bytes)") + + output_buffer = bytearray(total_bin_size) + + for segment in load_segments: + buffer_start = segment.header['p_vaddr'] - min_vaddr + buffer_end = buffer_start + segment.header['p_memsz'] # Using memsz for bounds check + + if buffer_end > total_bin_size: + print(f"Warning: Segment at 0x{segment.header['p_vaddr']:08X} " + f"extends beyond calculated total binary size. Truncating.") + buffer_end = total_bin_size + + segment_data = segment.data() + + output_buffer[buffer_start : buffer_start + len(segment_data)] = segment_data + + # The remaining part of the segment in memory (if p_memsz > p_filesz) + # is already zeroed due to output_buffer initialization. + + with open(bin_path, 'wb') as out_f: + out_f.write(output_buffer) + + print(f"Successfully created '{bin_path}' (size: {len(output_buffer)} bytes) from '{elf_path}'.") + + except FileNotFoundError: + print(f"Error: ELF file not found at '{elf_path}'") + except ELFError as e: + print(f"Error parsing ELF file with elftools: {e}. The file might be malformed or not a valid ELF.") + except Exception as e: + print(f"An unexpected error occurred: {e}") + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: python elf_to_bin.py <input_elf_file> <output_bin_file>") + sys.exit(1) + + input_elf = sys.argv[1] + output_bin = sys.argv[2] + + elf_to_bin_with_elftools(input_elf, output_bin) -- 2.43.0 base-commit: fcdb871cb79e21d53fa8ef241dd0f06336c27d47 branch: kv260-spl-build