Skip to content

Change a kernel driver

Build uImage alone (about two minutes), then flash it alone: the board is back in about fifteen seconds.

The kernel loop as four boxes: edit the driver and add dev_warn(); build uImage, about two minutes; flash --kernel-only, back in about fifteen seconds; read dmesg on the board. A dashed arrow leads back to the start: and again. The kernel loop as four boxes: edit the driver and add dev_warn(); build uImage, about two minutes; flash --kernel-only, back in about fifteen seconds; read dmesg on the board. A dashed arrow leads back to the start: and again.

# run from: firmware-modern/src/linux
CROSS=arm-linux-gnueabi-      # or arm-linux-gnueabihf-
make ARCH=arm CROSS_COMPILE=$CROSS fishball_defconfig
make ARCH=arm CROSS_COMPILE=$CROSS uImage LOADADDR=0x8000 -j$(nproc)
cp arch/arm/boot/uImage ../../output/
# run from: the repo root
./devkit flash --kernel-only
# run from: firmware/
make -C src/linux -j"$(nproc)" ARCH=arm \
  CROSS_COMPILE=arm-linux-gnueabi- uImage UIMAGE_LOADADDR=0x8000
cp src/linux/arch/arm/boot/uImage output/uImage
# run from: the repo root
./devkit flash --target factory --kernel-only

You should see: your dev_warn() lines in dmesg on the board. There is no ftrace and no kprobes on either kernel; dev_warn() plus dump_stack() is the tool.

A change survives only as a patch

Both src/ directories are regenerated by their setup.sh. Save the change as a numbered patch in firmware-modern/patches/ (or firmware/patches/), with a CI assertion. How: making it stick.

Debugging tips, the transmitter-safety attributes and kernel options: changing the kernel.

Comparing two builds byte for byte

The uImage is not reproducible by default: the kernel and mkimage stamp the build time. Pin these before building (firmware-modern/):

# run from: firmware-modern/src/linux
export KBUILD_BUILD_TIMESTAMP="Thu Jan  1 00:00:00 UTC 2026"
export KBUILD_BUILD_USER=devkit KBUILD_BUILD_HOST=devkit KBUILD_BUILD_VERSION=1
export SOURCE_DATE_EPOCH=1767225600