Skip to main content
The standalone workflow lets you compile, test, and deploy kernel changes without building the full Yocto image. All required cross-compilation and image-packaging tools are bundled in the kmake-image Docker container.

Limitations and caveats

The standalone workflow builds and packages the kernel and modules only. It does not produce a root file system. To build or modify out-of-tree kernel modules that depend on the full Yocto BSP, use the Yocto-based workflow instead.
  • Toolchain: the kmake-image Docker image provides an aarch64 cross-toolchain, systemd ukify, and image-packaging scripts. No host toolchain installation is needed.
  • DTB packaging: when building standalone, you must package the DTB manually using a static ITS configuration from the qcom-dtb-metadata repository. The Yocto build handles this automatically via meta-qcom.
  • Source revision: to match the exact source used in a release build, check the SRCREV field in meta-qcom/recipes-kernel/linux/linux-qcom_6.18.bb.

Access kernel sources

Clone the kernel repository directly:
git clone --branch qcom-6.18.y \
    https://github.com/qualcomm-linux/kernel.git kernel
Table: Kernel branches
BranchUse case
qcom-6.18.yLTS production builds; recommended for SoC bring-up and integration
qcom-nextUpstream contribution and validation against the latest kernel

Set up the Docker toolchain

Clone and build the kmake-image container:
git clone https://github.com/qualcomm-linux/kmake-image.git
cd kmake-image
docker build --build-arg USER_ID=$(id -u) \
             --build-arg GROUP_ID=$(id -g) \
             --build-arg USER_NAME=$(whoami) \
             -t kmake-image .
cd ..
Set up shell aliases for convenience. Add these to your shell profile to persist across sessions:
alias kmake-image-run='docker run -it --rm \
  --user $(id -u):$(id -g) \
  --workdir="$PWD" \
  -v "$(dirname $PWD)":"$(dirname $PWD)" \
  kmake-image'
alias kmake='kmake-image-run make'

Gather build artifacts

Create an artifacts/ directory to hold the ramdisk, boot binaries, and DTB metadata required to assemble the final images:
mkdir artifacts
Get the initramfs ramdisk
wget -O artifacts/ramdisk.gz \
    http://storage.kernelci.org/images/rootfs/buildroot/buildroot-baseline/20230703.0/arm64/rootfs.cpio.gz
Get systemd-boot binaries
wget -O artifacts/systemd-boot-efi.deb \
    http://ports.ubuntu.com/pool/universe/s/systemd/systemd-boot-efi_255.4-1ubuntu8_arm64.deb
dpkg-deb -xv artifacts/systemd-boot-efi.deb artifacts/systemd
Get DTB metadata When building standalone, DTBs must be packaged manually using a static ITS configuration. Clone the qcom-dtb-metadata repository to get the required qcom-metadata.dts and qcom-next-fitimage.its files:
git clone https://github.com/qualcomm-linux/qcom-dtb-metadata.git \
    artifacts/qcom-dtb-metadata

Build the kernel and modules

Configure and build the kernel using the standard Qualcomm® configuration fragments, then install modules into a staging directory:
cd kernel
mkdir -p ../kobj

env -u KCONFIG_CONFIG ./scripts/kconfig/merge_config.sh -m -O ../kobj \
    arch/arm64/configs/defconfig \
    arch/arm64/configs/prune.config \
    arch/arm64/configs/qcom.config

kmake O=../kobj olddefconfig
kmake O=../kobj -j$(nproc)
kmake O=../kobj -j$(nproc) dir-pkg INSTALL_MOD_STRIP=1
Package the built kernel modules (DLKMs) into the ramdisk:
(cd ../kobj/tar-install ; \
 find lib/modules | cpio -o -H newc -R +0:+0 | gzip -9 >> ../../artifacts/ramdisk.gz)

Package the boot images

Generate efi.bin (ESP partition) The efi.bin image contains systemd-boot, the kernel (packaged as a UKI type-2 image), and the initramfs:
cd ..
# Default command line matches the Yocto UKI_CMDLINE from esp-qcom-image.bb.
# Override CMDLINE if your rootfs partition label or console differs.
CMDLINE="root=PARTLABEL=rootfs rw rootwait console=ttyMSM0,115200"
kmake-image-run generate_boot_bins.sh efi \
    --ramdisk artifacts/ramdisk.gz \
    --systemd-boot artifacts/systemd/usr/lib/systemd/boot/efi/systemd-bootaa64.efi \
    --stub artifacts/systemd/usr/lib/systemd/boot/efi/linuxaa64.efi.stub \
    --linux kobj/arch/arm64/boot/Image \
    --cmdline "${CMDLINE}" \
    --output images
Generate dtb.bin (DTB partition) Build a FIT-based dtb.bin for all targets that support device tree:
kmake-image-run make_fitimage.sh \
    --metadata artifacts/qcom-dtb-metadata/qcom-metadata.dts \
    --its artifacts/qcom-dtb-metadata/qcom-next-fitimage.its \
    --kobj kobj \
    --output images
Both efi.bin and dtb.bin are placed in the images/ directory and are ready to flash.

Kernel Image Build Script

Above build and package steps are wrapped under a build.sh script which is part of docker, to automate building and packaging a bootable kernel image into efi.bin, dtb.bin, and boot.img. To use this alternative build.sh script run following:
kmake-image-run build.sh --dtb qcs6490-rb3gen2.dtb \
        --out kobj \
        --systemd artifacts/systemd/usr/lib/systemd/boot/efi \
        --ramdisk artifacts/ramdisk.gz \
        --images images \
        --cmdline "${CMDLINE}"
  • The —dtb argument is mandatory. It specifies the Device Tree Blob to be packed into the kernel image. Above command shows using qcs6490-rb3gen2.dtb as an example.
  • Initialize CMDLINE to set your kernel cmdline parameter else a default generic is used.

Flash and boot

Put the device into fastboot mode, then flash both images:
fastboot flash efi images/efi.bin
fastboot flash dtb_a images/dtb.bin
fastboot reboot
After the device reboots, verify the running kernel version as described in Install & boot the kernel.