Custom Kernel

From Alpine Linux
Revision as of 23:55, 7 March 2018 by Orson Teodoro (talk | contribs) (→‎Configuring kernel: put header for kexec)
This material is work-in-progress ...

Do not follow instructions here until this notice is removed.
(Last edited by Orson Teodoro on 7 Mar 2018.)

This process of building a custom configured kernel assumes you are running on Alpine Linux utilizing abuild & aports.

But why?

You want to build a custom kernel to enable experimental hardware or features or outdated hardware, to reduce bloat further, to tune the kernel to the hardware.

The vanilla kernel for most Alpine ARCHs uses defaults to balance throughput at the expense of some responsiveness, and support for many devices. You can tweak the kernel for desktop use and low latency and responsiveness.

Setting up the Alpine Build System

First, you need to follow the steps in Setup your system and account for building packages. You also need to configure your /etc/apk/repositories so that they search locally for your apks. See Testing the package locally for details.

Working with aports

There are several ways to maintain a kernel. The first option is to create a new kernel package. The other option is to just use the existing vanilla kernel just tweaking the configure-vanilla.ARCH file.

Switching to the proper release version

You need to switch to the proper branch that matches the release so that the kernel compiles against the dependencies properly.

Alpine version Remote branch
Edge master
3.7.0 3.7-stable

The following is required to get access to the APKBUILD released for that version of Alpine and which you will create a commit for.

If you are on 3.7 do:

 git checkout -b 3.7-stable origin/3.7-stable

If you are on Edge do:

 git checkout master

Option A: Creating a new kernel package

Use this option only if you want to want to be a kernel package maintainer or have custom patches.

What you need to do is copy main/linux-vanilla folder to testing/linux-NAME, where NAME could be anything but usually initials or a project name to a special kernel patch or patchset. Just use your last name if you don't know what to put. Rename all files from vanilla to NAME. Rename everything in APKBUILD from vanilla to NAME.

Option B: Vanilla with native settings and minimal edits

Most users will want to use this option.

You can use linux-vanilla but what you should do is create a local branch by doing:

For Alpine Edge:

 git checkout -b my-custom-kernel

For Alpine 3.7:

 git checkout -b my-custom-kernel origin/3.7-stable

Doing it this way, you do less work in maintaining. All you need to do is keep master or 3.7-stable in sync[1][2] and merge any conflicts.

First switch to the branch by doing git checkout my-custom-kernel. Then, you need to navigate to the main/linux-vanilla folder where you should see a APKBUILD and some config- files. When you are done with your edits either by editing directly the APKBUILD and copyting the config-vanilla.ARCH as .config in the linux-4.15 folder. You will then move the .config back overriding the config-vanilla.ARCH generated by make menuconfig (discussed below in the Configuring kernel section). After generating your config, you need to abuild checksum. Then, do git add APKBUILD config-vanilla.ARCH where ARCH is whatever architecture (x86, x86_64, ...) you use. Then, you need to do git commit APKBUILD config-NAME.ARCH -m "Enabled these options ...." for your custom _flavor and the ARCHitecture of your system. You do this so that git can keep your code separate from Alpine's and so your changes float forward between kernel updates.

Adding custom patches

Custom patches should be added to sources=.

After you added the URL, you need to produce a checksum by doing abuild checksum.

The custom patches may not be autopatched, due to being distributed as an archive or different patch level, so you need to define what to do with it in the prepare().

Configuring kernel

Attempt to build the kernel first. To do that, you do abuild -rK to install most of the dependencies. If it complains about a dependency like elfutils-dev use -rKd. Then, when it prompts for values for new found config options just hold enter till it starts compiling the kernel. There should be two sets one for -vanilla and the other for the -virt. Just Ctrl+C out of the compilation process after the second set so you can further customize the config. Then you go into the src/linux-VER and edit the config file. Copy the .config file overriding the config-NAME.ARCH in the srcdir.

The alternative is to use the kernel configuration menu in the build-NAME folder, but before yo do that you need to sudo apk add ncurses-dev

After you are done using the menu in the build-NAME folder by doing make menuconfig, you want to remove ncurses-dev. When you are done, it will be stored in .config which you need to again override the config-NAME.ARCH file. When you are done updating the config-NAME.ARCH, you need to do abuild checksum.

The options in the kernel config are typically defaults. If your device is old, it may be set to n by default.

Vanilla targets

ARCH Processor Type / CPU Selection / System Type Code Generation / Instruction Extensions Timer Frequency Preemption Model Bitness
s390x IBM zEnterprise 114 and 196 IBM zBC12 and zEC12 (-march=zEC12 -mtune=zEC12) 100 Hz No Forced Preemption (Server) 64
ppc64le Server processors POWER8 (-mcpu=power8), AltiVec (-Wa,-maltivec to assembler or -maltivec -mabi=altivec), VSX 100 HZ No Forced Preemption (Server) 64
ppc

512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx

  • Apple PowerMac based machines
AltiVec (-Wa,-maltivec to assembler or -maltivec -mabi=altivec) on >=74xx 250 HZ No Forced Preemption (Server) 32
x86_64 Generic-x86-64 (-mtune=generic ; SIMD assembly modules enabled based on simple test and presence of CPU flag) 300 HZ Voluntary Kernel Preemption (Desktop) 32
x86 586/K5/5x86/6x86/6x86MX (-mtune=generic ; SIMD assembly modules enabled based on simple test and presence of CPU flag) 300 HZ Voluntary Kernel Preemption (Desktop) 32
armhf
  • ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)
  • Freescale i.MX family -- Cortex A (i.MX51, i.MX53, i.MX6 Quad/DualLite, i.MX6 SoloLite, i.MX6 SoloX, i.MX6 UltraLite, i.MX7 Dual)
  • Qualcomm -- (MSM8X60, MSM8960, MSM8974)
  • Allwinner SoCs -- (A10 (sun4i), A10s / A13 (sun5i), A31 (sun6i), A20 (sun7i), sun8i Family, (sun9i))
  • ARM Ldt Versatile Express family --
Either -march=armv7-a or -march=armv5t -Wa,-march=armv7-a based on a compile test. -mfpu=vfp 100 Hz Voluntary Kernel Preemption (Desktop) 32
aarch64
  • Allwinner sunxi 64-bit SoC Family
  • Broadcom BCM2835 family
  • Marvell Berlin SoC Family
  • ARMv8 based Samsung Exynos SoC family
  • ARMv8 based Freescale Layerscape SoC family
  • Hisilicon SoC Family
  • Mediatek MT65xx & MT81xx ARMv8 SoC
  • Marvell EBU SoC Family
  • Qualcomm Platforms
  • Rockchip Platforms
  • AMD Seattle SoC Family
  • Altera's Stratix 10 SoCFPGA Family
  • NVIDIA Tegra SoC Family
  • Spreadtrum SoC platform
  • Cavium Inc. Thunder SoC Family
  • ARMv8 software model (Versatile Express)
  • AppliedMicro X-Gene SOC Family
  • Xilinx ZynqMP Family
300 HZ Voluntary Kernel Preemption (Desktop) 64

If you do desktop multitasking, you may want to switch to Voluntary Kernel Preemption (Desktop) or Preemptible Kernel (Low-Latency Desktop) and up the Timer Frequency.

Optimized modules (most are already compiled as modules):

  • raid6 -- altivec, avx512, ssse3, avx2, mmx, sse, sse2, neon
  • some operations of raid5 -- mmx (32 bit), sse (64 bit), avx

For Kernel API:

  • 32-bit memcpy -- 3dnow
  • 32-bit memory page clearing and copying -- sse (Athlon/K7 only), mmx

From x86/crypto, arm/crypto, powerpc/crypto:

  • CAMELLIA -- avx2, avx, aes-ni
  • CHACHA20 -- avx2, neon
  • CAST5 -- avx
  • CAST6 -- avx
  • TWOFISH -- avx
  • SERPENT -- avx2, avx, sse2
  • SHA1 -- avx2, ssse3, neon, spe
  • SHA2 -- avx2
  • SHA256 -- ssse3, neon, spe
  • SHA512 -- avx2, ssse3, neon
  • POLY1305 -- avx2
  • GHASH -- pclmulqdq, vmx (power8)
  • AES -- aes-ni, neon, vmx (power8), spe
  • CRC32 -- pclmulqdq, sse, neon, vmx (power8)
  • CRCT10DIF -- pclmulqdq, sse, neon, vmx (power8)

Fast reboots with kexec

If you want to reboot the kernel fast avoiding the POST test, you need sudo apk kexec-tools and enable kexec in the kernel:

 Processor type and features
   [x] kexec system call

For the kernel package maintainer

Each config-NAME.ARCH should be updated for all ARCHes so that it doesn't disrupt the building process. To do this for a particular ARCH:

 cd src/linux-4.15
 cp ../../config-NAME.ARCH .config
 yes "" | make ARCH=x86 oldconfig
 (hold enter to accept all default options)
 make ARCH=x86 menuconfig (optional to tweak it for the particular arch)
 cp .config ../../config-NAME.ARCH

The supported archs are in the linux-4.15/arch directory which you replace x86 in the above block or one of the kernel ARCHs below. The mapping is as follows:

Alpine ARCH Kernel ARCH Form Factor Dated
x86 x86 Balanced between desktop PC, laptop and server (i586 is minimum) Older generation
x86_64 x86 Balanced between desktop PC, laptop and server, including newer Apple PC/laptops. Current generation
s390x s390 Mainframe Current generation
ppc64le (64 bit; little endian) powerpc Servers and datacenters mostly ; vanilla is setup as server Active
ppc (32 bit) powerpc Consoles, older Apple PCs, servers ; vanilla is setup as server or unitasker kiosk or appliance Dwindling production
aarch64 arm64 Mostly mobile, single board computers (Raspberry PI), newer smaller laptops and tablets, few datacenter Current Generation
armhf (w/hardware floating point) arm Mobile, single board computers (Raspberry PI) Older Generation

(It doesn't make sense to compile to other architectures. Alpine's precompiled userland is limited to the ARCHes above. If your architecture is not listed, then you need to cross-compile the whole userland yourself. Instructions to do this is provided in the cross compile section.)

Or after abuild has unpacked and patched your kernel, you can use this script which you will place in the same folder as the APKBUILD:

Contents of update-menu

#!/bin/bash # Copyright 2018 Orson Teodoro # License: MIT _flavor="zen" cd src/build-$_flavor update_oldconfig() { ALPINE_ARCH="$1" KERNEL_ARCH="$2" cp ../../config-$_flavor.$ALPINE_ARCH .config yes "" | make ARCH=$KERNEL_ARCH oldconfig cp .config ../../config-$_flavor.$ALPINE_ARCH } update_menuconfig() { ALPINE_ARCH="$1" KERNEL_ARCH="$2" cp ../../config-$_flavor.$ALPINE_ARCH .config make ARCH=$KERNEL_ARCH menuconfig cp .config ../../config-$_flavor.$ALPINE_ARCH } update_all_oldconfig() { update_oldconfig aarch64 arm64 update_oldconfig armhf arm update_oldconfig ppc64le powerpc update_oldconfig ppc powerpc update_oldconfig x86_64 x86 update_oldconfig x86 x86 update_oldconfig s390x s390 } update_all_menuconfig() { update_menuconfig aarch64 arm64 update_menuconfig armhf arm update_menuconfig ppc64le powerpc update_menuconfig ppc powerpc update_menuconfig x86_64 x86 update_menuconfig x86 x86 update_menuconfig s390x s390 } update_all_oldconfig update_all_menuconfig

You can comment out the last update_all_menuconfig if you want to edit by hand the config-$_flavor.ARCH.

Don't forget to abuild checksum when you have processed all ARCHs.

The kernel package name should not have the number in the name. You will either use _gitYYYYMMDD or _p to attach the version number of the patch.

Building

You should then do an abuild -r to attempt to build it.

Installing

To install it you do a sudo apk add linux-NAME where NAME is your custom kernel release name or vanilla if you used option B.

Bootloader

You need to configure your bootloader to use the kernel. Add a new entry but do not replace the old kernel. The old kernel is your way back if the kernel config was a bad one. The naming scheme should be similar but with the tag. You should make sure that the _flavor name is attached for new kernel packages and do not override the existing vanilla kernel and the existing vanilla initramfs.

For Grub, in your /boot/grub/grub.cfg if mounted should contain the new entry something like

 menuentry 'Alpine Linux (ck1)' {
         set root=(hd0,7)
         linux /vmlinuz-ck1 root=/dev/sda17 rw modules=sd-mod,usb-storage,ext4
         initrd /initramfs-ck1
 }

In the above entry hd0,7 (in one based indexing) is associated with the boot partition /dev/sda7. /dev/sda17 should point to your userland partition containing your Alpine system files (/usr/bin, /bin, ...).

To install the bootloader with grub, you do something like grub-install --force /dev/sda7 where /dev/sda7 is your bootable drive found with fdisk -l or grub-install --force /dev/sda to install it at your MBR depending on how you set up grub.

Testing

To test, first you should make a bootable Alpine USB image. Then, when you have your rescue USB done, you sudo reboot the computer.

To test it, you basically do trial and error. Sometimes your config is missing something if you want to have a bare minimum setting.