1. Introduction
Agilex™ FPGAs are equipped with multiple CPU cores, and depending on the application, there are cases where you may want to run some of the cores under an OS other than Linux or in a Bare-metal environment without an OS.
In this article, we will show you how to create an SD card image that can run Linux and Bare-metal applications in parallel using the Agilex™ 5 FPGA E-Series Premium Development Kit.
[Figure 1] Image with Linux and Bare-metal
This article is based on the procedure in the HPS GHRD Linux Boot Examples below, with some customizations.
Reference: HPS GHRD Linux Boot Examples - Altera FPGA Developer Site
Point:
This article focuses on Agilex™ 5 FPGA, but the same procedure can be used for Agilex™ 7 FPGA.
It also describes the settings specific to the Agilex™ 7 FPGA, so we hope that those who use this device will find them useful.
2. Preliminary preparations
Please prepare the following host PC environment to execute the contents of this article.
- Linux OS * This article uses Ubuntu 22.04 LTS.
- 64 GB RAM or more
- Quartus® Prime Pro Edition Version 25.1
2-1. Quartus® environment variable settings
Since this article will use the Quartus® Prime tools, please execute the following command to set the Quartus path to the environment variable.
Note: You will need to modify the following commands to match your Quartus® Prime installation directory.
export QUARTUS_ROOTDIR=~/altera_pro/25.1/quartus/
export PATH=$QUARTUS_ROOTDIR/bin:$QUARTUS_ROOTDIR/linux64:$QUARTUS_ROOTDIR/../qsys/bin:$PATH2-2. Creating Bare-metal Application
Please refer to the following site to pre-create "hello_world.bin" for Bare-metal application.
Reference: E-Series Premium Development Kit GHRD - Baremetal Hello World Example -
If you create only "hello_world.bin", you do not need to follow step 4 (Build ATF) and step 10 (Build FIP file, containing ATF bl31 and the hello application) of the reference site. Note:
The operating environment in this article assumes the entry point for Bare-metal applications is at 0x90200000.
Therefore, the baremetal-drivers/build/aarch64/core0.ld file must be changed as follows.
[Figure 2] Modification of core0.ld file
2-3. Preparation of hardware design file
Please prepare the hardware design "legacy_baseline.sof" file in advance by referring to the following site.
Reference: HPS GHRD Linux Boot Examples - Altera FPGA Developer Site
ATF, U-Boot, LinuxKernel, and Rootfs will be done in "Creating SD Card Image", so you only need to create a .sof file at the time of preparation. (Build Arm Trusted Firmware and subsequent steps are not required.)
2-4. Preparation of Yocto environment
In this article, the Root File System will be created using the Yocto project environment. Therefore, prepare an environment where Yocto build can be executed in advance.
2-4-1. Package installation
Install the packages required for Yocto build by executing the following commands.
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install openssh-server mc libgmp3-dev libmpc-dev gawk wget git diffstat unzip texinfo gcc \
build-essential chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping \
python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint xterm python3-subunit mesa-common-dev zstd \
liblz4-tool git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison xinetd \
tftpd tftp nfs-kernel-server libncurses5 libc6-i386 libstdc++6:i386 libgcc++1:i386 lib32z1 \
device-tree-compiler curl mtd-utils u-boot-tools net-tools swig -y2-4-2. Changing the linker of sh command
The Yocto project scripts are written under the assumption that sh commands are executed with "bash". However, on Ubuntu, "dash" is the default setting, so change the link source of sh commands from "dash" to "bash" by executing the following command.
sudo ln -sf /bin/bash /bin/sh
3. Creating SD card image
3-1. Environment setup
Set up the environment for creating each executable file.
3-1-1. Creating a working directory
Create a working directory (agilex5_boot.enablement) for environment creation by executing the following command.
mkdir agilex5_boot.enablement
cd agilex5_boot.enablement
export TOP_FOLDER=`pwd`3-1-2. Tool chain setup
Execute the following command to download the GNU toolchain from the ARM Developer site and set the toolchain path and other environment variables.
cd $TOP_FOLDER
wget https://developer.arm.com/-/media/Files/downloads/gnu/11.2-2022.02/binrel/\
gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
tar xf gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
rm -f gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu.tar.xz
export PATH=`pwd`/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATH
export ARCH=arm64
export CROSS_COMPILE=aarch64-none-linux-gnu-
3-2. Storing prerequisite files
Store "hello_world.bin" and "legacy_baseline.sof" prepared in step "3-2. pre-preparation" in $TOP_FOLDER.
3-3. Building the Arm Trusted Firmware
Execute the following command to download and build Arm Trusted Firmware (ATF).
cd $TOP_FOLDER
git clone -b QPDS25.1_REL_GSRD_PR https://github.com/altera-fpga/arm-trusted-firmware
cd arm-trusted-firmware
make -j 48 PLAT=agilex5 bl31When the above command is successfully executed, the following file will be generated.
- $TOP_FOLDER/arm-trusted-firmware/build/agilex5/release/bl31.bin
3-4. Building the U-Boot
3-4-1. Download U-Boot source code
Execute the following command to download the U-Boot source code from Altera github and move to the downloaded directory.
cd $TOP_FOLDER
git clone -b QPDS25.1_REL_GSRD_PR https://github.com/altera-fpga/u-boot-socfpga
cd u-boot-socfpga3-4-2. Configuration change
Change the Configuration in the downloaded U-Boot source code.
(1) Change CONFIG_BOOTCOMMAND
Add the following setting to CONFIG_BOOTCOMMAND and change Bare-metal application to run on CPU3 (Cortex-A76#1).
-
-
fatload mmc 0:1 0x90200000 hello_world.bin
-> Read hello_world.bin from the FAT partition of the SD card and load it into DDR at 0x90200000 -
dcache flush
-> Cache flush the hello_world.bin program loaded at 0x90200000 so that it can be referenced by other CPUs -
smc 0xC4000003 0x300 0x90200000 0
-> Execute SMC to start CPU3 from the entry point at 0x90200000. The format of the SMC command is as follows:- 1st argument: 0xC4000003 ... Command ID for CPU ON
- 2nd argument: 0x300 ............. CPU No. * It is necessary to set the value of the Aff1-0 field (Bit#11-0) of the MPIDR_EL1 register format.
- 3rd argument: 0x90200000 ... Entry point
- 4th argument: 0 ..................... Not used
-
fatload mmc 0:1 0x90200000 hello_world.bin
Point:
In the case of Agilex™ 7 FPGA, the Aff0 field (Bit#3-0) corresponds to CPU No., so the value of the 2nd argument should be set to "0x0003".
-
-
setenv bootargs maxcpus=3
-> Add maxcpus=3 to the bootargs environment variable to make CPU3 unused by SMP on Linux
-
setenv bootargs maxcpus=3
(2) Add CONFIG_CMD_SMC
Add the following SMC command Configuration.
-
- CONFIG_CMD_SMC=y
The command to change the configuration with the above changes is as follows.
The settings other than the above changes follow the settings in HPS GHRD Linux Boot Examples - Altera FPGA Developer Site.
# enable dwarf4 debug info, for compatibility with arm ds
sed -i 's/PLATFORM_CPPFLAGS += -D__ARM__/PLATFORM_CPPFLAGS += -D__ARM__ -gdwarf-4/g' arch/arm/config.mk
# only boot from SD, do not try QSPI and NAND
sed -i 's/u-boot,spl-boot-order.*/u-boot\,spl-boot-order = \&mmc;/g' arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi
# disable NAND in the device tree
sed -i '/&nand {/!b;n;c\tstatus = "disabled";' arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi
# link to atf
ln -s . /arm-trusted-firmware/build/agilex5/release/bl31.bin
# create configuration custom file.
cat << EOF > config-fragment
# use Image instead of kernel.itb
CONFIG_BOOTFILE="Image".
# disable NAND/UBI related settings from defconfig.
CONFIG_NAND_BOOT=n
CONFIG_SPL_NAND_SUPPORT=n
CONFIG_CMD_NAND_TRIMFFS=n
CONFIG_CMD_NAND_LOCK_UNLOCK=n
CONFIG_NAND_DENALI_DT=n
CONFIG_SYS_NAND_U_BOOT_LOCATIONS=n
CONFIG_SPL_NAND_FRAMEWORK=n
CONFIG_CMD_NAND=n
CONFIG_MTD_RAW_NAND=n
CONFIG_CMD_UBI=n
CONFIG_CMD_UBIFS=n
CONFIG_MTD_UBI=n
CONFIG_ENV_IS_IN_UBI=n
CONFIG_UBI_SILENCE_MSG=n
CONFIG_UBIFS_SILENCE_MSG=n
# disable distroboot and use specific boot command.
CONFIG_DISTRO_DEFAULTS=n
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT_HUSH_PS2="> "
CONFIG_USE_BOOTCOMMAND=y
CONFIG_BOOTCOMMAND="load mmc 0:1 ${loadaddr} ghrd.core.rbf; fpga load 0 ${loadaddr} ${filesize};bridge enable; mmc rescan; fatload mmc 0:1 0x 90200000 hello_world.bin; dcache flush; smc 0xC4000003 0x300 0x90200000 0; fatload mmc 0:1 82000000 Image;fatload mmc 0:1 86000000 socfpga_agilex5_ socdk.dtb;setenv bootargs console=ttyS0,115200 root=${mmcroot} rw rootwait maxcpus=3;booti 0x82000000 - 0x86000000"
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_DOS_PARTITION=y
CONFIG_SPL_DOS_PARTITION=y
CONFIG_CMD_PART=y
CONFIG_SPL_CRC32=y
CONFIG_LZO=y
CONFIG_CMD_DHCP=y
# enable more QSPI flash manufacturers
CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_SPI_FLASH_GIGADEVICE=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SPI_FLASH_ISSI=y
# enable SMC
CONFIG_CMD_SMC=y
EOF3-4-3. Execution of U-Boot build
Execute the following commands to run U-Boot according to the modified configuration settings.
make clean && make mrproper
make socfpga_agilex5_defconfig
. /scripts/kconfig/merge_config.sh -O . -m .config config-fragment
make -j 64When the above command is successfully executed, the following file is generated.
-
- $TOP_FOLDER/u-boot-socfpga/u-boot.itb
- $TOP_FOLDER/u-boot-socfpga/spl/u-boot-spl-dtb.hex
3-5. Building the Linux Kernel
Execute the following commands to download and build Linux Kernel.
cd $TOP_FOLDER
git clone -b QPDS25.1_REL_GSRD_PR https://github.com/altera-fpga/linux-socfpga
cd linux-socfpga
cat << EOF > config-fragment-agilex5
# Enable Ethernet connectivity so we can get an IP address
CONFIG_MARVELL_PHY=y
EOF
make defconfig
. /scripts/kconfig/merge_config.sh -O . / . /.config . /config-fragment-agilex5
make oldconfig
make -j 64 Image && make intel/socfpga_agilex5_socdk.dtbWhen the above command is successfully executed, the following file is generated.
-
- $TOP_FOLDER/linux-socfpga/arch/arm64/boot/dts/intel/socfpga_agilex5_socdk.dtb
- $TOP_FOLDER/linux-socfpga/arch/arm64/boot/Image
3-6. Creation of Root File System
Execute the following command to download layers and recipes from Yocto project, edit local.conf, and execute bitbake.
cd $TOP_FOLDER
mkdir yocto && cd yocto
git clone -b styhead https://git.yoctoproject.org/poky
git clone -b styhead https://git.yoctoproject.org/meta-intel-fpga
git clone -b styhead https://github.com/openembedded/meta-openembedded
source poky/oe-init-build-env . /build
echo 'MACHINE = "agilex5_dk_a5e065bb32aes1"' >> conf/local.conf
echo 'BBLAYERS += " ${TOPDIR}/../meta-intel-fpga "' >> conf/bblayers.conf
echo 'BBLAYERS += " ${TOPDIR}/../meta-openembedded/meta-oe "' >> conf/bblayers.conf
echo 'CORE_IMAGE_EXTRA_INSTALL += "openssh gdbserver"'' >> conf/local.conf
bitbake core-image-minimalWhen the above command is successfully executed, the following file will be generated.
-
- $TOP_FOLDER/yocto/build/tmp/deploy/images/agilex5_dk_a5e065bb32aes1/core-image-minimal-agilex5_dk_a5e065bb32aes1.rootfs.tar.gz
3-7. Creating FPGA configuration file
In case of HPS Boot First mode, FPGA Core configuration must be performed at the timing after U-Boot (SSBL) startup.
Therefore, the FPGA Core configuration data (core.rbf file) must also be stored in the SD card.
Execute the following commands to create "ghrd.core.rbf" from "legacy_baseline.sof" prepared in step "2. advance preparation" and "u-boot-spl-dtb.hex" created in step "3-4. Build the U-Boot".
cd $TOP_FOLDER
quartus_pfg -c $TOP_FOLDER/legacy_baseline.sof ghrd.jic \
-o device=MT25QU128 \}
-o flash_loader=A5ED065BB32AE6SR0 \
-o hps_path=$TOP_FOLDER/u-boot-socfpga/spl/u-boot-spl-dtb.hex \ \
-o mode=ASX4 \
-o hps=1When the above command is successfully executed, the following file is generated.
-
- $TOP_FOLDER/ghrd.core.rbf
- $TOP_FOLDER/ghrd.hps.jic
Point:
"ghrd.hps.jic" generated at the same time as "ghrd.core.rbf" is a file that is not included in the SD card, but is a file that is written to the QSPI Flash on the SDM side for operation check.
3-8. Generating SD card image
Execute the following command to generate the SD card image.
The following command downloads a tool for SD card image generation (make_sdimage_p3.py), collects files to be written to the SD card, and then executes the tool.
cd $TOP_FOLDER
mkdir sd_card && cd sd_card
wget https://releases.rocketboards.org/release/2020.11/gsrd/tools/make_sdimage_p3.py
sed -i 's/\"\-F 32\",//g' make_sdimage_p3.py
chmod +x make_sdimage_p3.py
mkdir fatfs && cd fatfs
cp $TOP_FOLDER/ghrd.core.rbf .
cp $TOP_FOLDER/hello_world.bin .
cp $TOP_FOLDER/u-boot-socfpga/u-boot.itb .
cp $TOP_FOLDER/linux-socfpga/arch/arm64/boot/Image .
cp $TOP_FOLDER/linux-socfpga/arch/arm64/boot/dts/intel/socfpga_agilex5_socdk.dtb .
cd ..
mkdir rootfs && cd rootfs
tar xf $TOP_FOLDER/yocto/build/tmp/deploy/images/agilex5_dk_a5e065bb32aes1/core-image-minimal-agilex5_dk_a5e065bb32aes1.rootfs.tar.gz
cd ..
sudo python3 make_sdimage_p3.py -f \f
-P fatfs/*,num=1,format=fat32,size=64M \
-P rootfs/*,num=2,format=ext3,size=64M \
-s 140M \ -n sdcard.img
-n sdcard.imgWhen the above command is successfully executed, the following file will be generated.
- $TOP_FOLDER/sd_card/sdcard.img
4. Execution result and confirmation
Insert the SD card that contains the image created in "3. Creating SD card image" into the Agilex™ 5 FPGA E-Series Premium Development Kit, and use the Quartus® Prime Programmer tool to write the "ghrd.hps.jic" file, which was created in "3-7. Creating FPGA configuration file" to the QSPI Flash on the SDM side.
After that, power off -> on and the following U-Boot log will be output on the terminal.
U-Boot 2025.01-gcd3a9044d661-dirty (Aug 06 2025 - 09:11:31 +0900)socfpga_agilex5
CPU: Intel FPGA SoCFPGA Platform (ARMv8 64bit Cortex-A55/A76)
Model: SoCFPGA Agilex5 SoCDK
DRAM: 2 GiB (effective 8 GiB)
Core: 51 devices, 25 uclasses, devicetree: separate
WDT: Not starting watchdog@10d00200
WDT: Not starting watchdog@10d00300
WDT: Not starting watchdog@10d00400
WDT: Not starting watchdog@10d00500
WDT: Not starting watchdog@10d00600
MMC: mmc0@10808000: 0
Loading Environment from FAT... Unable to read "uboot.env" from mmc0:1...
In: serial0@10c02000
Out: serial0@10c02000
Err: serial0@10c02000
Starting HPS SMMU test for SDM.
sdm_tbu_stream_ctrl_reg_1_sdm : 0x3
smmuSetBaseAddr()
smmu1_S_IDR1.secure : 0x0
smmuInitStreamTable()
main(): Installing Event Queue
main(): Installing Command Queue
Issue commands to invalidate TLBs
main(): Enabling SMMU (Non-secure only)
smmuEnableCommandProcessing
smmuEnableEventQueue
smmuEnableTranslation()
main(): Intializing a context descriptor
~
Hit any key to stop autoboot: 5 4 3 2 1 0
1904640 bytes read in 93 ms (19.5 MiB/s)
. FPGA reconfiguration OK!
2107848 bytes read in 101 ms (19.9 MiB/s)
Res: 0x0 0x300 0x90200000 0x0
Hello, World!
46778880 bytes read in 2018 ms (22.1 MiB/s)
25456 bytes read in 14 ms (1.7 MiB/s)
## Flattened Device Tree blob at 86000000
Booting using the fdt blob at 0x86000000
Working FDT set to 86000000
Loading Device Tree to 00000000feb05000, end 00000000feb0e36f ... OK
Working FDT set to feb05000
Starting kernel ...
The above log shows that the SMC command to start CPU3 is executed and the Bare-metal application is started, as shown in the log section below.
---------------------------------------
Res: 0x0 0x300 0x90200000 0x0
Hello, World!
---------------------------------------
In addition, when the debugger (ARM® DS) is started after the Linux startup is completed and the program counter of each CPU is checked, it can be confirmed that only Cortex-A76 #1 is operating in the Bare-metal program area (0x90200000~) as shown in the figure below.
[Figure 3] Program Counter on ARM® DS Debugger
5. Conclusion
In this article, we have shown how to build an environment to run Linux and Bare-metal applications simultaneously on an Agilex™ FPGA.
It should be noted that a flexible multi-OS configuration that assigns different OSs to multiple CPU cores can be achieved with a few modifications to the U-Boot configuration.
This approach makes it possible to optimize the entire system by assigning Bare-metal for tasks that require real-time processing and Linux for general-purpose processing.
We hope you will consider using the high flexibility of Agilex™ FPGA to design an efficient system that meets your application needs.