We have covered a lot of ground in this stretch of the free embedded systems course: where kernel source comes from, how Kconfig and Kbuild turn a defconfig into a build, how modules differ from built-in drivers, how a board makes itself known through a device tree or a legacy machine ID, and how that all turns into a booting kernel. This lecture pulls those threads together into one map, before we move into the next subject: what the kernel needs once it is running.
modules vs built-in
porting checklist
free linux device drivers course
What You Will Learn
- A single map of every stage from getting kernel source to a booted target
- How to decide between building a driver as a module or built-in for an embedded target
- A reusable pre-flight checklist you can run before any new board bring-up
- What’s still missing after a successful boot, and why that’s the next topic
Prerequisites
- Having followed the earlier lectures in this free linux kernel development course chapter, from getting kernel source through booting a board kernel
The Full Porting Pipeline, End To End
Every board bring-up, however different the SoC, follows the same shape. Source comes from either mainline, a vendor tree, or a third party BSP. That source is configured for the target with Kconfig, built with Kbuild into an image plus any modules and device tree blobs, and then handed to the target by a bootloader that identifies the hardware before jumping into the kernel.
→
Kconfig
→
Kbuild
→
Image + Modules + DTB
→
Bootloader Hand-off
→
Root Filesystem
That final box, root filesystem, is deliberately unfinished here — a kernel that boots but finds no usable root filesystem stops with a kernel panic, and that hand-off is exactly where the next chapter of this course begins.
Modules Versus Built-In, Revisited
This decision comes up on nearly every board, so it’s worth having a firm rule of thumb rather than re-deriving it each time.
| Choose | When | Trade-off |
|---|---|---|
| Built-in | Hardware set is fixed and known at build time (most embedded targets) | Simpler boot, no module-loading dependency on root filesystem being ready |
| Module (.ko) | Driver must be loaded after boot, or the hardware set varies across a product line | Smaller base image, but adds boot-time complexity and licensing boundary considerations |
A Reusable Pre-Flight Checklist
Here is a small original shell script you can drop into any board bring-up repository. It doesn’t touch the kernel tree itself — it just verifies your build environment agrees with itself before you spend ten minutes on a build only to find ARCH was never exported.
#!/bin/sh
# ep_kernel_preflight.sh — sanity-check a cross build environment
set -e
: "${ARCH:?ARCH is not set, e.g. export ARCH=arm}"
: "${CROSS_COMPILE:?CROSS_COMPILE is not set, e.g. export CROSS_COMPILE=arm-linux-gnueabihf-}"
if ! command -v "${CROSS_COMPILE}gcc" >/dev/null 2>&1; then
echo "ERROR: ${CROSS_COMPILE}gcc not found on PATH" >&2
exit 1
fi
echo "ARCH=${ARCH}"
echo "CROSS_COMPILE=${CROSS_COMPILE}"
"${CROSS_COMPILE}gcc" --version | head -n1
echo "Preflight OK — safe to run make defconfig"
Expected output on a correctly configured host:
$ export ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
$ ./ep_kernel_preflight.sh
ARCH=arm
CROSS_COMPILE=arm-linux-gnueabihf-
arm-linux-gnueabihf-gcc (Ubuntu 13.2.0) 13.2.0
Preflight OK — safe to run make defconfig
Common Mistakes Across This Whole Chapter
- Starting from a random vendor tree instead of checking whether mainline already supports the SoC — mainline gets long-term maintenance, vendor trees often don’t.
- Configuring everything as a module on a board where nothing ever changes after manufacturing, adding unnecessary boot-time fragility.
- Not distinguishing a porting failure (nothing on the console) from a root filesystem failure (clean version banner, then a panic) — they need completely different debugging.
Best Practices Recap
- Start from the closest matching mainline board support and diff outward, rather than writing from a blank defconfig.
- Keep board-specific patches rebased and out-of-tree code to an absolute minimum so future kernel upgrades stay tractable.
- Treat the porting pipeline as one reproducible pipeline (source → config → build → boot), not four disconnected manual steps.
Additional Reading
- The kernel’s own in-tree documentation at
Documentation/admin-guide/README.rst - Your SoC vendor’s board integration guide, for anything genuinely hardware-specific that mainline docs can’t cover
Summary And Conclusion
The Linux kernel’s configurability is exactly what lets one codebase span a tiny sensor node and a full server. Porting to a new board is really just: get the right source, configure it, build it, and let a bootloader identify the hardware correctly. Where boards differ is only in how much of that work is already done for you by mainline versus how much you have to do yourself. A booted kernel is a milestone, not the finish line — it still needs a root filesystem to actually run any user-space program, which is exactly where this course picks up next.
FAQ
Should I always start a new port from mainline Linux?
Yes wherever possible — mainline support means long-term maintenance and security fixes; only fall back to a vendor tree when the SoC genuinely isn’t supported upstream yet.
Is there a hard rule for modules versus built-in?
Not a hard rule, but a strong default for embedded targets: if the hardware set is fixed at build time, build in; only modularize what genuinely needs to load later or vary at runtime.
What’s the very next thing the kernel needs after booting?
A root filesystem — without one the kernel has nothing to hand control to and panics, which is the subject of the next chapter.
Why does the checklist script check CROSS_COMPILE instead of just running make?
Because a missing or wrong CROSS_COMPILE fails silently in confusing ways deep into a build; catching it in one second up front saves a much longer debugging session later.
Does this chapter’s approach apply to arm64 boards too?
Yes — the pipeline shape (source, config, build, bootloader hand-off) is architecture-independent; only the specific image format and bootloader commands change.
How do I know if a porting failure is early (kernel) or late (root filesystem)?
If you see a clean kernel version banner and machine/model line before things go wrong, porting succeeded and the problem is downstream in root filesystem setup.
Continue The Free Embedded Systems Course
Next up: what a root filesystem actually needs to contain, and how the kernel finds it.
