Custom Kernel
Do not follow instructions here until this notice is removed.  | 
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 lts 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.
You should disable modules to increase security. By default, Alpine will install modules but not disable most of them. Disabling modules will reduce an DMA attack but not eliminate it completely. If you have a newer processor with VT-d, you can mitigate as long as you:
Leave CONFIG_INTEL_IOMMU_DEFAULT_ON=y or pass intel_iommu=on as a kernel parameter and disable kernel logging so the attacker doesn't gain DMAR address information through dmesg.[1]  Also remove references to the kernel version to calculate the IOMMU addresses.[2]
You may also want to harden your kernel by adding at least some of the config changes recommended by kernel-hardening-checker [3]
To increase the security of the boot process, if you have a TPM, you could set CONFIG_INTEL_TXT=y (Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)) (which is not enabled in the hardened kernel by default), then you would need the SINIT module (provided only by Intel)[4], a possibly compiled TrustedGrub2[5], trousers[6], tboot[7].  These packages are not in aports and it is unknown if these tools work on musl.  It's not recommended for Edge.  Also, there would be trigger packages to generate hashes for the kernel and the mkinitfs updates.
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.
After setting up accounts and repos, change your shell's current working directory to aports that you just cloned.
$ cd aports
Working with aports
We will try using an existing lts kernel just tweaking the lts.ARCH.config 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.22.0 | 3.22-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.22 do:
$ git checkout -b 3.22-stable origin/3.22-stable
If you are on Edge do:
$ git checkout master
Creating your config
You can use linux-lts but what you should do is create a local branch by doing:
For Alpine 3.22 (linux-lts - 6.12):
$ git checkout -b my-custom-kernel origin/3.22-stable
For Alpine Edge:
$ git checkout -b my-custom-kernel
Doing it this way, you do less work in maintaining. All you need to do is keep master or 3.22-stable in sync[8][9] 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-lts folder where you should see a APKBUILD and some config- files.
You may want to change APKBUILD to change the name of your kernel and package (custom flavor or revision) and comment out or remove lines with config files that are not for your cpu architectures or virt* configs that are for virtualized environments.(They provide optimized kernel configurations for running Alpine as a guest in virtual machines.) Setting custom name/flavor will prevent overriding your default linux-lts kernel modules and commenting out unused configs will speed up the process of applying kernel patches by applying it for your architecture only. (Obviously ARCH in the following example is whatever architecture (x86, x86_64, ...) you use.)
_flavor=lts-custom
pkgname=linux-$_flavor
pkgrel=0
pkgdesc="Linux ${_flavor} kernel (optimized)"
When you are done with your edits to the APKBUILD file copy your config from lts.ARCH.config to .config.  You can then move .config back overriding the lts.ARCH.config generated by make localmodconfig or make menuconfig (discussed below in the Configuring kernel section).  After generating your config, you need to run abuild checksum.
Then add your changes, eg git add APKBUILD lts.ARCH.config. 
And commit git commit APKBUILD lts.ARCH.config -m "Enabled these options ...." for your customization 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 create a config for your currently running system and modules first.
To create a kernel config based on your currently running PC, use:
make localmodconfig
This command reads your current kernel's configuration from /proc/config.gz (if available) or /boot/config-* and creates a .config file that includes only the modules currently loaded on your system. This results in a minimal configuration tailored to your hardware.
Alternatively, you can use:
make localyesconfig
This is similar to localmodconfig, but instead of building features as modules (m), it builds them directly into the kernel (y), which can result in a larger kernel image but eliminates the need for separate module files.
Note: Before running either command, make sure you have all the hardware you want to support actively in use (USB devices plugged in, network cards active, etc.) so their modules are loaded and included in the configuration.
The alternative is to use the kernel configuration menu in the build-NAME folder, but before you 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 lts.ARCH.config 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 and tuning
| 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)
 | 
1000 Hz | No Forced Preemption (Server) | 64 | 
| ppc64le | Server processors | POWER8 (-mcpu=power8), AltiVec (-Wa,-maltivec to assembler or -maltivec -mabi=altivec), VSX
 | 
1000 HZ | No Forced Preemption (Server) | 64 | 
| ppc | 
 512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx 
  | 
AltiVec (-Wa,-maltivec to assembler or -maltivec -mabi=altivec) on >=74xx
 | 
1000 HZ | No Forced Preemption (Server) | 32 | 
| x86_64 | Generic-x86-64 | (-mtune=generic ; SIMD assembly modules enabled based on simple compile test and/or presence of CPU flag) | 1000 HZ | Voluntary Kernel Preemption (Desktop) | 64 | 
| x86 | 586/K5/5x86/6x86/6x86MX | (-mtune=generic ; SIMD assembly modules enabled based on simple compile test and/or presence of CPU flag) | 1000 HZ | Voluntary Kernel Preemption (Desktop) | 32 | 
| armv7 | 
  | 
Either -march=armv7-a or -march=armv5t -Wa,-march=armv7-a based on a compile test. -mfpu=vfp
 | 
1000 Hz | Voluntary Kernel Preemption (Desktop) | 32 | 
| aarch64 | 
  | 
1000 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. If you run a dedicated render farm node or a dedicated bitcoin miner use No Forced Preemption (Server) and decrease 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 (part of aes-ni), 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 doas apk add kexec-tools and enable kexec in the kernel:
Processor type and features [*] kexec system call
Hibernation to prevent data loss
Power management and ACPI options [*] Hibernation (aka 'suspend to disk')
Hibernation should be used if you have a laptop. You don't want the laptop to suddenly shut off resulting in data loss, you want it to save your work based on a percentage of battery life (this requires special script). When hibernation resumes, should lock and ask for credentials. Depending on your needs, the hibernated image can be encrypted/decrypted which again requires additional customization to scripts.
Hibernation with an unsanitized swap file is generally insecure because data and unlocked memory pages are swapped out in plaintext. To increase the security either disable swap or use an encrypted swap. The swap file/partition is typically used as the hibernation resume image.
Building
Before building, make sure you have ccache installed.  This should reduce compile time on multiple builds.
You may also want to read up on compile flags - perhaps you want your build to be optimized for speed (or size which is the default).
Review /etc/abuild.conf and set:
PACKAGER_PRIVKEY="/home/MY_USER_HERE/.abuild/my-email@mydomain.com-ID.rsa"
USE_CCACHE=1
If you have your config ready, first try building with abuild -rK which install most of the dependencies and keep buildtime temp dirs and files (srcdir/pkgdir/deps).
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.
Unless you removed or commented out virt.*.config configs
there should be two sets one for -lts 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 lts.ARCH.config in the srcdir.
Installing
To install it you do a doas apk add linux-NAME where NAME is your custom kernel name.
Testing
Before you test, you should install the lts kernel too, using apk add linux-lts.  You may be missing a module and can't boot, so you use the other kernel as the fallback boot kernel.
Normally during the installation using with apk there are tools that will update initramfs and a boot loader automatically for you. For easier debugging you may want to change boot loader config and remove quiet from linux command line in /etc/default/grub or /etc/update-extlinux.conf.
Or perhaps you want to change other kernel options in /etc/mkinitfs/mkinitfs.conf - please remember to generate initramfs and update your bootloader manually, eg:
- mkinitfs
 
- grub-mkconfig -o /boot/grub/grub.cfg
 
To test, first you should make a bootable Alpine USB image.  Then, when you have your rescue USB done, you 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.
If you are curious about correctness testing, some kernel modules or components do preform self tests at the beginning of the boot process. The tools may have test suites that you run with the make command.
