Linux

Kernel Source, Versions & Patching

"Just update the kernel" hides a surprising amount of real work in embedded Linux — which source tree, which version scheme, and how a fix that landed in mainline actually reaches a product's kernel that's years and hundreds of vendor patches away from it.

Quick reference
What it is
Where kernel source comes from, how its version numbers and maintenance branches work, and how fixes move between them via patches.
Mental model
Mainline is the trunk; stable and longterm (LTS) are bugfix-only branches off specific releases; a vendor BSP is a long-running fork that occasionally sends changes back upstream.
Key numbers
Mainline releases roughly every 9–10 weeks; a longterm (LTS) branch is maintained for 2–6 years of security/bugfix backports.
Reach for it when
Backporting a security fix onto a product kernel, evaluating a vendor BSP, or figuring out whether a bug is already fixed upstream.

Where kernel source actually comes from

Mainline is Linus Torvalds' own tree at git.kernel.org — the trunk everything else eventually traces back to. Almost no embedded product ships mainline directly, though: silicon vendors (Broadcom, NXP, TI, Xilinx, and others) maintain their own long-running forks — vendor BSPs (board support packages) — carrying the driver and platform code their chips need, much of which hasn't been merged into mainline (and in some cases never will be). A real embedded project is almost always working from one of these vendor forks, not from torvalds/linux directly.

A mainline release branches into a short-lived stable line, a multi-year longterm (LTS) line, and separately, a long-running vendor BSP fork Mainline, stable, LTS, and vendor forks v6.5 v6.6 v6.7 Stable bugfixes only, until v6.7 Longterm (LTS) maintained 2–6 years Vendor BSP fork hundreds of out-of-tree patches Production embedded systems almost always run a longterm release, often with vendor patches layered on top — mainline itself is rarely what actually ships.
A vendor's patches occasionally get upstreamed back into mainline over time — but plenty never do, which is exactly why the fork keeps existing release after release.

Versioning: mainline, stable, and longterm

A kernel version like 6.6.30 breaks down as major.minor.patch: 6.6 is a mainline release (major/minor numbers today are largely just sequential, not meaningful on their own), and .30 is the stable patch level — the 30th round of bugfixes backported onto 6.6 since its release.

Mainline
Linus's tree. New features land here first, in a ~9–10 week cycle: a 2-week merge window, then 6–8 weekly release candidates (rc1…rcN) stabilizing before the final release.
Stable
Bugfix-only backports onto the most recent mainline release, maintained only until the next mainline release supersedes it.
Longterm (LTS)
Select releases (a few per year) chosen for extended maintenance — typically 2 years, sometimes up to 6 — receiving security and critical bugfixes long after their mainline peers have gone unmaintained. This is what almost every real embedded product is actually built on.
linux-next
An integration tree combining what's queued for the next merge window — used by kernel developers to catch conflicts early, not something a product ships.

Getting the source

# mainline, directly from kernel.org
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git checkout v6.6

# a vendor BSP fork instead — e.g. Raspberry Pi's kernel, carrying
# hundreds of out-of-tree patches for the Broadcom SoC it targets
git clone https://github.com/raspberrypi/linux.git

Which one is right depends entirely on the board: mainline only supports hardware that's actually been upstreamed, so a board whose vendor hasn't finished that work simply won't boot on a plain mainline checkout — the vendor fork exists precisely to fill that gap.

How patches are actually applied

A patch is a text diff describing exactly which lines changed in which files — the standard way a fix moves from one tree to another without needing a full merge. Two common forms show up constantly in embedded work: a plain diff (applied with patch) and a git-formatted patch that preserves the original commit's author and message (applied with git am).

# plain diff, old-school
patch -p1 < fix-i2c-timeout.patch

# a git-formatted patch — keeps the original commit's author/message
git am 0001-i2c-fix-timeout-on-slow-bus.patch

# backporting one specific upstream fix by commit hash, directly
git cherry-pick a1b2c3d4e5f6
An upstream fix is extracted as a patch file, then applied onto a vendor or LTS tree that never received it directly Upstream fix one commit in mainline/stable Patch file git format-patch -1 <sha> Vendor / LTS tree git am / git cherry-pick
This is the actual daily mechanics behind a CVE-driven fix from dependency analysis turning into a change in a product's kernel tree.

Configuration and cross-compiling

A kernel build is driven by a .config file selecting which subsystems, drivers, and features to compile — generated from a board-specific baseline and then adjusted.

# cross-compiling for ARM64 from an x86_64 build host
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

make defconfig          # start from a board's known-good baseline .config
make menuconfig         # interactively enable/disable subsystems
make -j$(nproc) Image modules dtbs

ARCH and CROSS_COMPILE are how the same kernel source tree builds for a completely different target architecture than the machine doing the compiling — the toolchain prefix in CROSS_COMPILE selects the actual cross-compiler binaries (aarch64-linux-gnu-gcc, etc.) used for every compilation step.

Real-world applications

Gotchas

Field notes