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.
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-staticinstalled: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
# 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:
| Artifact | Path |
|---|---|
| Kernel image | arch/arm64/boot/Image |
| Device trees | arch/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
| Partition | Contents |
|---|---|
mmcblk0p1 | U-Boot, primary |
mmcblk0p2 | U-Boot, backup |
mmcblk0p3 | Boot partition — holds two directories, boot-0 and boot-1, one primary and one backup |
mmcblk0p4 | Root filesystem |
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.
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
| Reference | Where |
|---|---|
| Release to source commit mapping | Release Compatibility |
| Build container | Dockerfile.modalix |
| Kernel source | simaai-linux |
| Kernel defconfig | simaai_modalix_defconfig |
| U-Boot source | sima-ai-uboot |
| Device trees and overlays | dts/simaai |
Next Steps
- Release Compatibility — which source commit matches each platform release.
- Carrier Board Bring-up — adapting the device tree for your own carrier board.
- Convert to eLxr — moving a Yocto DevKit to eLxr.