Lesson
Kernel and Boot Customisation
How to customise the Linux kernel, configuration fragments, and boot-related behaviour in Yocto
Most embedded Linux projects eventually need to adjust the kernel or boot process.
That may mean enabling drivers, applying patches, selecting a kernel provider, adding configuration fragments, or changing how the bootloader and kernel fit together for a specific platform.
This is one of the most hardware-sensitive parts of a Yocto project, so keeping the responsibilities clear matters.
Where Kernel and Boot Customisation Fits
In most projects, kernel and boot changes sit close to the BSP layer because they are usually tied to hardware.
That often includes:
- selecting the correct kernel recipe
- choosing the bootloader configuration
- adding board-specific kernel patches
- enabling drivers or options through kernel config
- selecting device trees
- controlling the image formats used for deployment
These are usually not general product policy decisions. They are answers to a much more specific question: what does this board need in order to boot and run correctly?
Kernel Recipes in Yocto
The Linux kernel is just another BitBake recipe, although it is a very special one.
That means the kernel still fits into the normal Yocto model:
- a recipe fetches source
- patches may be applied
- configuration is prepared
- the source is built
- deployable artifacts are emitted
You will often see kernel recipes or selections tied to:
PREFERRED_PROVIDER_virtual/kernel = "linux-myvendor"
This tells BitBake which recipe should provide the kernel for the active machine or platform.
Common Kernel-Related Variables
Some kernel customisation usually happens through variables rather than rewriting tasks.
Common examples include:
- PREFERRED_PROVIDER_virtual/kernel
-
Selects which recipe provides the kernel.
- KERNEL_DEVICETREE
-
Selects which device tree blob or blobs should be built and deployed.
- SRC_URI
-
Adds patches, config fragments, or other kernel-related files.
- KBUILD_DEFCONFIG
-
Selects a default kernel defconfig in some kernel workflows.
- UBOOT_MACHINE
-
Selects the U-Boot defconfig where U-Boot is used.
Not every project uses every variable, but this is the kind of metadata you will often touch when adapting Yocto to real hardware.
Configure Versus Patch
One of the most useful habits is knowing when a problem should be solved by configuration and when it should be solved by patching.
Use kernel configuration when:
- you need to enable or disable a driver
- you need to switch on a subsystem or option
- the kernel source already supports what you need
Use a patch when:
- you need to change kernel source code
- you need to add support that is not already present
- you need to fix a bug in the kernel tree you are using
This sounds obvious, but in practice it prevents a lot of unnecessary patching.
If the feature already exists in the kernel, a config fragment is usually a better and more maintainable solution than editing source.
Kernel Configuration Fragments
In Yocto, a common way to customise the kernel is with configuration fragments.
A fragment is a small file containing only the kernel options you need to change.
For example:
CONFIG_CAN=y
CONFIG_CAN_RAW=y
CONFIG_SPI_SPIDEV=y
This is usually cleaner than maintaining one huge monolithic defconfig for every board variation.
Fragments are often added through SRC_URI from a kernel append file.
For example:
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " file://myboard.cfg"
This lets you keep your kernel adjustments in your own layer rather than editing the base kernel recipe directly.
Kernel .bbappend Files
In many projects, you do not create a new kernel recipe from scratch.
Instead, an upstream or vendor layer already provides one, and you extend it from
your own BSP layer using a .bbappend.
For example:
meta-my-bsp/
└── recipes-kernel/
└── linux/
├── linux-myvendor_%.bbappend
└── files/
├── myboard.cfg
└── fix-uart.patch
And the append file might contain:
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append = " file://myboard.cfg file://fix-uart.patch"
This is usually the safest pattern because it keeps your changes separate from the vendor or upstream layer.
Device Trees
For many ARM and embedded platforms, device trees are a major part of hardware customisation.
They describe the hardware layout that the kernel should expect, such as:
- buses
- peripherals
- interrupt wiring
- memory layout
- enabled or disabled devices
In Yocto, the selected device tree is often controlled with:
KERNEL_DEVICETREE = "vendor/myboard.dtb"
or sometimes several device trees:
KERNEL_DEVICETREE = "vendor/myboard.dtb vendor/myboard-revB.dtb"
If the wrong device tree is selected, the kernel may build successfully but the board may still boot incorrectly or fail to initialise hardware.
Bootloader Configuration
The kernel is only part of the boot path.
Many embedded systems also need bootloader customisation, often through U-Boot.
That may include:
- selecting the correct bootloader configuration
- enabling storage or network support
- setting boot arguments
- loading the correct kernel and device tree
- handling secure boot or board-specific boot sequences
A common U-Boot setting is:
UBOOT_MACHINE = "myboard_defconfig"
That tells the build which U-Boot configuration should be used for the target.
Boot Arguments and Board Behaviour
Boot behaviour is often shaped by several pieces working together:
- the bootloader environment
- the selected kernel image
- the selected device tree
- kernel command line arguments
- the root filesystem layout
This is why boot problems can be deceptive.
A board that does not reach userspace may not have a kernel bug at all. The issue could be:
- the wrong bootloader configuration
- the wrong device tree
- the wrong root filesystem argument
- a missing storage driver in the kernel config
Kernel and boot customisation work best when you treat the boot chain as one connected system.
Image Formats and Deployment Artifacts
Some boot-related settings also influence which artifacts Yocto should emit.
For example, a platform may need:
- a compressed kernel image
- a raw binary image
- a
wicimage for SD card deployment - a separate boot partition artifact
These decisions are often tied to the board and deployment method rather than the application layer.
That is why machine and BSP metadata often influence image formats, kernel image types, and boot artifacts.
A Practical Example
Suppose a custom board needs:
- one extra kernel driver
- a board-specific device tree
- a small fix to a vendor kernel source file
A reasonable approach would be:
- Keep the vendor kernel recipe as the base.
- Add a
.bbappendin your own BSP layer. - Add a kernel config fragment for the driver option.
- Add a patch for the source fix.
- Select the correct device tree in machine metadata.
That is usually much cleaner than copying the whole kernel recipe into your own layer and maintaining a fork immediately.
Keep Board Truth Separate from Product Policy
This module connects directly to the earlier BSP lesson.
A good boundary is:
- board-specific kernel and boot requirements belong near the BSP
- product-level policy belongs in the distro or image layer
For example:
- selecting the board device tree is usually BSP work
- deciding whether the image should include SSH is not
- choosing a bootloader defconfig is usually BSP work
- deciding whether the product uses
systemdis usually distro work
If those boundaries stay clear, the project remains easier to understand and reuse.
Prefer Small, Traceable Changes
Kernel and boot work can become difficult to maintain if the changes are too large or too hidden.
Good habits include:
- use config fragments for kernel options
- keep patches small and well scoped
- prefer
.bbappendfiles over editing vendor metadata directly - keep device tree selection explicit
- document why a bootloader or kernel choice exists
This makes upgrades much more manageable later.
Debugging Kernel and Boot Problems
When something goes wrong, it helps to separate build success from boot success.
If the build fails:
- inspect the kernel recipe logs
- inspect patch application and config handling
- check that your fragment or patch is actually included in
SRC_URI
If the build succeeds but the board does not boot:
- verify the selected device tree
- verify the bootloader configuration
- verify kernel command line arguments
- verify required drivers are enabled in the kernel configuration
- verify the root filesystem and deployment artifact are correct for the board
This is an important mindset shift: a successful bitbake result does not always
mean the kernel and boot chain are configured correctly for the hardware.
Summary
Kernel and boot customisation in Yocto is mostly about selecting and extending the right low-level metadata.
The main patterns are:
- select the right kernel provider
- use configuration fragments for kernel options
- use patches only when source changes are truly needed
- keep board-specific boot choices in BSP or machine metadata
- extend vendor layers cleanly with
.bbappendfiles
If you keep those changes small, explicit, and hardware-focused, the system is much easier to debug and maintain.
Check your understanding
Quick quiz: kernel and boot
A quick review of low-level platform customisation patterns.