Skip to main content

Build the BSP from Source

Build the Modalix Linux kernel, U-Boot and device trees yourself, then install the results on a board. Everything here uses public repositories — no NDA and no sales enquiry.

note

Build from the source commit that matches the release running on your board. Release Compatibility maps each platform release to its kernel and U-Boot commit. See Board Support Package for what a BSP contains and where each repository lives.

Before You Start​

  • An Ubuntu 22.04 host for the build.

  • Docker Engine installed.

  • qemu-user-static installed:

    sima-user@sima-user-machine:~$ sudo apt install qemu-user-static

To install what you build, you also need a board already running an eLxr image with root access, reachable over the network from the container, and booted from eMMC (enumerated as mmcblk0).

Set Up the Build Container​

The SDK container carries the toolchain, headers and libraries for the target. Save the Dockerfile below as Dockerfile.modalix, then build the image from the directory that contains it. The Dockerfile sets up the SDK for release 2.1.0.

Dockerfile.modalix
Dockerfile.modalix
# Generated Dockerfile for modalix Build:release[2.1.0]

FROM debian:bookworm

# List of additional packages that are to be deployed in SDK sysroot
ARG SDK_PKG_LIST
ENV SDK_PKG_LIST="\
libgrpc-dev,\
protobuf-compiler-grpc,\
python3-pybind11,\
${SDK_PKG_LIST}"

RUN dpkg --add-architecture arm64
RUN dpkg --add-architecture arc
RUN dpkg --add-architecture armhf
RUN apt-get clean && \
apt-get update --allow-releaseinfo-change && \
apt-get install -y wget pip
RUN wget -qO - https://mirror.elxr.dev/elxr/public.gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/elxr.gpg
RUN wget -qO - https://packages.fluentbit.io/fluentbit.key | gpg --dearmor > /etc/apt/trusted.gpg.d/fluentbit.gpg
RUN wget --no-check-certificate -O - https://repo.sima.ai/elxr/deb/simaai.gpg | gpg --dearmor > /etc/apt/trusted.gpg.d/simaai.gpg
RUN chmod 644 /etc/apt/trusted.gpg.d/elxr.gpg
RUN chmod 644 /etc/apt/trusted.gpg.d/fluentbit.gpg

RUN echo "deb [signed-by=/etc/apt/trusted.gpg.d/elxr.gpg] https://mirror.elxr.dev/elxr aria main" > /etc/apt/sources.list.d/elxr.list
RUN echo "deb [signed-by=/etc/apt/trusted.gpg.d/fluentbit.gpg] https://packages.fluentbit.io/debian/bookworm bookworm main" >> /etc/apt/sources.list.d/elxr.list
RUN echo "deb [trusted=yes] https://repo.sima.ai/elxr/deb/release bookworm non-free #simaai repo" >> /etc/apt/sources.list.d/elxr.list

RUN apt-get update --allow-releaseinfo-change && \
apt-get install -y --no-install-recommends \
python3-apt-ostree \
vim \
make \
cmake \
gcc-aarch64-linux-gnu \
g++-aarch64-linux-gnu \
device-tree-compiler \
bison \
flex \
quilt \
zlib1g-dev \
bzip2 \
bc \
rsync \
kmod \
cpio \
git \
curl \
libssl-dev \
libgnutls28-dev \
openssh-client \
simaai-sdk-tools

RUN echo "Package: *" > /etc/apt/preferences.d/stable.pref
RUN echo "Pin: origin \"repo.sima.ai/elxr\"" >> /etc/apt/preferences.d/stable.pref
RUN echo "Pin-Priority: 999" >> /etc/apt/preferences.d/stable.pref

RUN export RUSTUP_HOME=/opt/toolchain/rust && export CARGO_HOME=/opt/toolchain/rust && \
mkdir -p ${RUSTUP_HOME} && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rustup.sh && \
chmod 755 /tmp/rustup.sh && /tmp/rustup.sh -y && \
echo "export RUSTUP_HOME=${RUSTUP_HOME}" >> ${CARGO_HOME}/env && \
echo "export CARGO_HOME=${CARGO_HOME}" >> ${CARGO_HOME}/env && \
. ${CARGO_HOME}/env && rm /tmp/rustup.sh

RUN if uname -a | grep -q '#[0-9]*-Ubuntu'; then \
apt-get update --allow-releaseinfo-change; \
--privileged mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc || true; \
fi

RUN if [ "x86_64" = "x86_64" ]; then apt update --allow-releaseinfo-change && apt install \
arch-test -y; fi

RUN python3 /opt/bin/simaai_setup_sdk.py modalix 2.1.0 \
\
"${SDK_PKG_LIST}"

RUN echo "source /opt/bin/simaai-init-build-env modalix" >> /root/.bashrc
sima-user@sima-user-machine:~$ docker build -t modalix-sdk --file Dockerfile.modalix .

To preload extra packages into the sysroot, pass a comma-separated list:

sima-user@sima-user-machine:~$ docker build --build-arg SDK_PKG_LIST=libzix-dev,vxi-dev -t modalix-sdk --file Dockerfile.modalix .

Launch it from a directory you can write to:

sima-user@sima-user-machine:~$ docker run -it --privileged -v $(pwd):/data -w /data -v /dev:/dev --pid=host modalix-sdk

The sysroot is at /opt/toolchain/aarch64/<platform>. The build environment is set automatically at launch; to set it by hand, run source /opt/bin/simaai-init-build-env modalix.

Build the Kernel​

Inside the container:

root@sdk:/data$ git clone https://github.com/SiMa-ai/simaai-linux.git && cd simaai-linux
root@sdk:/data/simaai-linux$ git checkout <kernel-commit>
root@sdk:/data/simaai-linux$ make ARCH=arm64 simaai_modalix_defconfig
root@sdk:/data/simaai-linux$ make all -j8 ARCH=arm64 LOCALVERSION="-modalix" DTC_FLAGS=-@

Replace <kernel-commit> with the kernel commit for your release from Release Compatibility. Building master gives you the latest release, which may not match the image on your board.

This produces:

ArtifactPath
Kernel imagearch/arm64/boot/Image
Device treesarch/arm64/boot/dts/simaai/*.dtb

Build a Device Tree Overlay (Optional)​

Write the overlay source (.dtso), then compile it to a blob (.dtbo):

root@sdk:/data$ dtc -@ -I dts -O dtb -o imx415.dtbo imx415.dtso

An overlay that uses #include, as some camera overlays in the kernel tree do, has to go through the C preprocessor first. Run this in the kernel tree:

root@sdk:/data/simaai-linux$ aarch64-linux-gnu-cpp -nostdinc -I include -I arch/arm64/boot/dts/simaai/overlays -undef -x assembler-with-cpp my-overlay.dtso | dtc -@ -I dts -O dtb -o my-overlay.dtbo -

Build U-Boot​

root@sdk:/data$ git clone https://github.com/SiMa-ai/sima-ai-uboot.git && cd sima-ai-uboot
root@sdk:/data/sima-ai-uboot$ git checkout <u-boot-commit>
root@sdk:/data/sima-ai-uboot$ make ARCH=arm64 simaai_modalix_debug_defconfig
root@sdk:/data/sima-ai-uboot$ make all u-boot-initial-env V=1

Replace <u-boot-commit> with the U-Boot commit for your release from Release Compatibility. The image is u-boot.bin.

Install the Artifacts​

How the eMMC Is Laid Out​

PartitionContents
mmcblk0p1U-Boot, primary
mmcblk0p2U-Boot, backup
mmcblk0p3Boot partition — holds two directories, boot-0 and boot-1, one primary and one backup
mmcblk0p4Root filesystem
warning

Write partitions with dd, not cp, and copy to the board as root. To find the board's address, run hostname -I or ip route get 1.1.1.1 on the board.

U-Boot​

Copy the image over, find the partition currently in use, and write it:

root@sdk:/data$ scp sima-ai-uboot/u-boot.bin root@<board-ip>:/tmp/
root@modalix:~# parted /dev/mmcblk0 print | grep legacy_boot | cut -f2 -d" "
1
root@modalix:~# dd if=/tmp/u-boot.bin of=/dev/mmcblk0p1 status=progress # use the partition number printed above
root@modalix:~# sync

Kernel, Device Trees and Overlays​

Find the active boot directory first — it is either boot-0 or boot-1:

root@modalix:~# strings /boot/uboot.env | grep boot_path= | cut -f2 -d"="
/boot-0/

Copy the artifacts into that directory:

root@sdk:/data$ scp simaai-linux/arch/arm64/boot/Image root@<board-ip>:/boot/boot-0/
root@sdk:/data$ scp simaai-linux/arch/arm64/boot/dts/simaai/modalix*.dtb root@<board-ip>:/boot/boot-0/
root@sdk:/data$ scp imx415.dtbo root@<board-ip>:/boot/boot-0/

Kernel Modules​

Modules go into the running kernel's module tree. uname -r on the board gives the version string:

root@sdk:/data$ scp simaai-linux/drivers/net/phy/marvell10g.ko root@<board-ip>:/lib/modules/6.18.3-modalix/kernel/drivers/net/phy/

Finish Up​

root@modalix:~# depmod -a 6.18.3-modalix
root@modalix:~# sync
root@modalix:~# reboot

If you added a new overlay, register it in U-Boot's dtbos variable. Interrupt autoboot, then:

sima$ env set dtbos $dtbos imx415.dtbo
sima$ saveenv
sima$ boot

Deploy Your Build​

There are two ways to get a custom build onto a board, and they suit different stages of work.

Iterate on a running board. While developing, copy the kernel image, device trees, overlays and modules onto a board that already boots, as in Install the Artifacts, then reboot. This is the fastest loop, but it changes one board by hand and leaves no reproducible image behind.

Flash a complete image. To put the same build on many boards, including in production, boot each board from the network or an SD card and write a complete image to its eMMC. See Flash an Image to eMMC, and Factory Build and Test for the full production flow.

The update format changes in 3.0

Platform releases 2.x and 3.0 use different update mechanisms: 3.0 moves to swupdate. To build a complete image from source, see Build a Complete Image with Yocto. Assembling a complete eLxr image is not yet documented. To package an update for a Yocto image, see Build and Apply an Update Package.

Firmware Update installs the stock SiMa.ai image. Use it to return a board to a known release, not to deploy your own build: it overwrites what you installed.

References​

ReferenceWhere
Release to source commit mappingRelease Compatibility
Build containerDockerfile.modalix
Kernel sourcesimaai-linux
Kernel defconfigsimaai_modalix_defconfig
U-Boot sourcesima-ai-uboot
Device trees and overlaysdts/simaai

Next Steps​