User:Knuxify/Draft:Getting started

This page serves as an introduction to the basics of mainlining.

What is mainlining?

Mainlining is the act of adding support for a device, or porting its drivers from an older, non-upstream tree, to the mainline Linux kernel.

The name comes from the term "mainline Linux kernel", which is used to refer to the upstream Linux kernel repository maintained by Linus Torvalds[1], and which itself comes from the term "mainline branch" used to refer to the main development trunk of a project[2].

Why is mainlining necessary?

Users of the Linux kernel on x86-64 PCs may be accustomed to the fact that most components work out of the box on these devices. This can be partly attributed to the fact that both AMD and Intel - the largest players in the x86-64 market - contribute support for their CPUs and chipsets directly to the mainline Linux kernel.

With most embedded SoCs, however, the typical lifecycle of Linux support looks like this:

  • The SoC vendor forks the Linux kernel and applies patches for device support on top of this fork
  • The SoC fork is sent to device manufacturers, who apply their own patches on top of it to add support for their devices

The code from these forks usually never makes it back upstream; it's maintained internally by the SoC vendor's team. Yet worse, device vendors often neglect rebasing their forks on the vendor's updated kernels. As kernel APIs change over time, updating these kernels to the latest version becomes more difficult.

Since upstreaming is not a priority, and the main goal of a vendor is to provide a viable product to developers as fast as possible, the drivers in an SoC fork don't necessarily conform to the standards and practices of the mainline Linux kernel.

This is where mainlining comes in. Mainlining comprises of:

  • Analyzing the drivers from original source code, or experimenting with the hardware itself to determine how it works (reverse engineering), to then write new, upstream-ready drivers for it;
  • Submitting those drivers upstream, responding to review comments, maintaining them in the mainline Linux kernel tree.

Prerequisites

  • A computer running Linux, which will handle building the kernel.
    • If you're on Windows, you can use WSL (though flashing the kernel to your device might be a bit challenging, TODO).
    • (Note about recommended specs goes here; faster hardware is better, but only necessary bits are rebuilt on subsequent builds; also mention ccache?)
  • Some familiarity with the Linux shell and C programming language syntax is recommended.

Getting to know your device and SoC

  TODO: These are both topics worthy of their own page. Some things to mention here:
  • Finding out whether the SoC is supported to mainline and, if so, how well.
  • Finding out what components your device has (it's nice to keep a table!)

Preparing the build environment

In order to mainline a device, we need to be able to cross-compile the Linux kernel for it.

Downloading the Linux kernel source code

Depending on your SoC's support status:

  • There may be an up-to-date maintained close-to mainline fork of the Linux kernel for your device's SoC; if there is one, start from it.
  • If there is no dedicated fork for your device's SoC, or the fork is out of date, start with either:
    • The latest stable tag directly from Torvalds' tree (see [1] or github.com/torvalds/linux).
    • For very new SoCs with ongoing work, you may want to use the linux-next tree instead.

If you're on GitHub, you can fork the torvalds/linux repository and start from there.

Once you have your kernel cloned, switch to the latest tag, then create a new feature branch from it:

$ git checkout v6.14  # replace 6.14 with latest kernel version
$ git checkout -b codename-mainline  # git checkout -b creates a new branch based on current HEAD and checks out into it
  TODO: Link to some nice guide on git here (and probably elsewhere in the page)

Cross-compiler setup

  TODO: Explain cross-compiler setup; where to get toolchains (AUR for Arch users? Linaro?), postmarketOS envkernel.sh

Selecting/creating a defconfig

The kernel config dictates which drivers and platform-specific support bits (including DTBs) get built. There are a handful of pre-made configs, called defconfigs, in arch/{arm,arm64,...}/configs - use make name_defconfig to build them.

  TODO: Common ARM(64) config? Which options to select/unselect? pmbootstrap kconfig check might be useful here

Adding a device tree for your device

Devices using ARM chipsets use devicetrees to describe the hardware. See Devicetree/Writing a Linux device tree for a guide.

Building the kernel

  TODO: make -j$(nproc)

Packaging the kernel into a boot image

  TODO: See how I do it in mainline-tools, mention pmbootstrap build --envkernel?

Then, flash the resulting kernel to the device.

Getting the kernel to boot

  TODO: UART, DTBO trickery

See also

  TODO: pmOS wiki has links to talks and resources

References