Slackware initrd mini HOWTO by Patrick Volkerding, volkerdi@slackware.com Fri Apr 10 18:45:55 CDT 2009 Adapted for Slackware ARM port by Stuart Winter, mozes@slackware.com Sat Jun 20 11:20:14 BST 2009 Removed legacy ARMv5 for Slackware ARM port by Stuart Winter, mozes@slackware.com Mon Sep 26 21:27:38 BST 2016 Updated for Slackware ARM / AArch64 by Stuart Winter, mozes@slackware.com Fri Apr 23 21:43:34 BST 2021 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Contents: 1. What is an initrd? 2. Why to I need an initrd? 3. initrd, Kernel packages and /boot in Slackware ARM 4. Exposition of the Slackware ARM / AArch64 initrd 5. How do I change the initrd? 6. mkinitrd_command_generator.sh in Slackware ARM / AArch64 1. What is an initrd? ====================================================================== Initrd stands for "initial ramdisk". An initial ramdisk is a very small Linux filesystem that is loaded into RAM and mounted as the kernel boots, and before the main root filesystem is mounted. 2. Why do I need an initrd? ====================================================================== The usual reason to use an initrd is because you need to load kernel modules before mounting the root partition. Usually these modules are required to support the filesystem used by the root partition (ext3, reiserfs, xfs), or perhaps the controller that the hard drive is attached to (SCSI, RAID, etc). Essentially, there are so many different options available in modern Linux kernels that it isn't practical to try to ship many different kernels to try to cover everyone's needs. It's a lot more flexible to ship a generic kernel and a set of kernel modules for it. 3. initrd, Kernel packages and /boot in Slackware ARM ====================================================================== In Slackware ARM and AArch64 15.0 and later releases, there is a single "armv7" (32bit "ARM") and "armv8" (64bit ARM, "AArch64") Kernel that directly supports the officially (and some community) supported devices for those architectures, For each platform that Slackware ARM / AArch64 supports, the following are provided: - 1 Kernel package in slackware/a/ e.g. kernel_armv7-5.10.32-arm-1.txz - 1 Kernel module package in slackware/a/ e.g. kernel-modules-armv7-5.10.32_armv7-arm-1.txz - 1 initrd in kernels//initrd- e.g. kernels/armv7/initrd-armv7 The Kernel, Kernel module packages and initrd contain the name of the platform or architecture. In the example above, the 'armv7' name refers to the ARMv7 architecture which covers most supported devices. For Slackware AArch64, the examples above would use the "armv8" architecture name. The Kernels found in the slackwarearm-/kernels//zImage- e.g. slackwarearm-15.0/kernels/armv7/zImage-armv7 are copies of those found in the Slackware Kernel package in the a/series: kernel_--arm-.txz package In most other platforms, including the x86, the Kernel lives on a Linux filesystem inside /boot. Slackware ARM also provides a Kernel in this location. For the officially supported devices, /boot is generally either an ext4 formatted partition (since modern versions of the U-Boot loader can read ext4) or is a directory within the root file system. On some devices and using QEMU you'd need to have the Kernel and initial RAM disk accessible outside of Linux. Please refer to the documentation for such systems. Typically users will want to rebuild their initrd to include support for some specific hardware peripheral that they have added locally. ARM and AArch64 hardware are SoC's (System On Chip) which essentially means that the hardware vendor has 'baked in' a variety of hardware into a single chip (even before the SoC design was the standard on ARM platforms, the ARM platforms were sufficiently niche that the variety of available compatible peripherals could easily be catalogued). This means that the Operating System vendor (in this case the author of this dicument) knows in advance what modules are required for a particular device (at least enough to support the storage upon which the OS resides). In Slackware ARM / AArch64, the initrd is generic/universal and contains the major sub systems required for all ARM/AArch64 hardware models. It contains a module loader that and a set of helper loaders to load the modules for the specific hardware model (the "host") it's running on at boot time. In general, the user should not need to update the initial RAM disk unless there's a particular storage device for which the drivers are not presently loaded. 4. Exposition of the Slackware ARM / AArch64 initrd ====================================================================== 4.1 Kernel Helpers -------------- The following examples are from Slackware AArch64. The structure is identical on Slackware ARM, apart from the architecture name is 'armv7'. Let's unpack the initrd and explore. Enter the /boot directory in which the initial RAM disks live: root@bladswede:/# cd /boot Create a directory in which to unpack the initrd: root@bladswede:/boot# mkdir unpack root@bladswede:/boot# cd unpack/ Unpack the initrd: root@bladswede:/boot/unpack# zcat ../initrd-armv8 | cpio -di 613535 blocks root@bladswede:/boot/unpack# ls bin/ etc/ initrd-name lib/ load_kernel_modules* luksdev mnt/ resumedev rootdev run/ sys/ wait-for-root dev/ init* keymap lib64/ load_kernel_modules.scr/ lukskey proc/ root/ rootfs sbin/ usr/ root@bladswede:/boot/unpack# ls -la load_* -rwxr-xr-x 1 root root 9365 Apr 23 22:09 load_kernel_modules* The 'load_kernel_modules' file is a 'bash' shell script that handles: * Opening a 'Pre-Boot shell' at two key stages of the boot process: prior to loading the Kernel modules, and post loading of Kernel modules. * Executing 'local' additional scripts (see section 5) * Populating a set of core modules required for any ARM/AArch64 hardware model * Calling out to 'helper' scripts that identify the hardware model and further populate or amend the base set of modules * Loading the Kernel modules The module loader callout helpers are located within a sub directory within the root of the initrd: root@bladswede:/boot/unpack# tree load_kernel_modules.scr/ load_kernel_modules.scr/ └── platform Each ARM platform has its own architecture directory name. In this case it's 'aarch64' (on 32bit ARM platforms, it's 'arm'). └── aarch64 Each platform has a 'baseline_' helper script. This is to set modules required for all hardware models of that architecture, but not for the others (in this case for the 32 bit 'arm' platform). Kernel modules applicable to all architectures are set within the '/load_kernel_modules' loader script. ├── baseline_aarch64 Module loader helper scripts are named after the SoC name rather than the marketing name (e.g. rk3399 rather than 'Rock Pro64' or 'Pinebook Pro'). This is because - as the example above highlights - a single SoC can support multiple hardware models that perhaps have a different hardware form factor or presentation. For example, the Pinebook Pro is essentially a Rock Pro64 in a laptop form factor. ├── bcm2711 ├── bcm2837 └── rk3399 Users should _not_ change these files. These will be overwritten when the Kernel packages are upgraded. If you would like to improve these loaders, or would like to contribute new ones to help onboard Slackware to new ARM / AArch64 platforms, please see http://arm.slackware.com/slackwarearm-devel/ for more information. 4.2 OS InitRD Configuration Files ----------------------------- In addition to the Kernel helper scripts detailed in the previous sections, the following files may also be present within /boot/local and control the operation of the OS InitRD once they have been incorporated into the local copy of the OS InitRD. See section 5 below ('5. How do I change the OS InitRD?') for details on how to do that. ********************************************************************** * IMPORTANT NOTE: * ********************************************************************** By default, the Slackware ARM / AArch64 Kernel package ships these files as empty, as the principal configurations are stored within the Boot Loader configuration (/boot/extlinux/extlinux.conf on Slackware AArch64). These options are passed to the Kernel via its command line interface (/proc/cmdline). Users are at liberty to set the configuration via either method, but must be aware that options supplied via the Kernel command line interface take precedence over the file-based configuration options. ********************************************************************** By default there are no sample files supplied, as the configuration is simple and is described below: if you wish to configure these specific settings, create the relevant files within /boot/local and move to section 5. /boot/local/rootdev Contains the name of the root device, such as: /dev/sda2 [ Default: Set within the Boot Loader configuration ] /boot/local/rootfs Contains the root filesystem type, such as: xfs [ Default: Set within the Boot Loader configuration ] /boot/local/wait-for-root Contains a number - the init script will wait this amount of seconds before creating device nodes. [ Default: Set within the Boot Loader configuration ] /boot/local/resumedev Contains the name of the device to resume from hibernation. /boot/local/luksdev Contains colon separated list of luks encrypted devices to be unlocked. /boot/local/lukstrim Contains colon separated list of luks encrypted devices to pass to the LUKS command line option '--allow-discards' when unlocking /boot/local/lukskey Contains the path to a LUKS key-file for automatic unlock. Format: LABEL=:/path/to/file UUID=:/path/to/file /boot/local/keymap Contains the name for a custom keyboard map /boot/local/initrd-name Contains the name of the initrd file. 5. How do I change the OS InitRD? ====================================================================== 5.1 Using the Operating System Initial RAM Disk Manager --------------------------------------------------- If you have made any changes to either the Kernel helper scripts or any of the OS InitRD configuration files, you will need to rebuild the OS InitRD. First, let's explore /boot/local as shipped: root@bladswede:/boot/local# ls -1 README.txt load_kernel_modules.post.sample load_kernel_modules.pre-modload.sample load_kernel_modules.pre.sample In this example, we'd like to set the keymap to UK and add a Kernel module to support a particular USB storage device. Set the UK keymap: root@bladswede:/boot/local# echo uk > keymap Now comes the Kernel helper shell scripts: Script Stage ------------------------------------------------------------------ /load_kernel_modules.pre Load user-supplied script prior to setting and loading any Kernel modules. This is a chance to run 'demod' if you're testing an OS InitRD without running depmod on the contents prior to booting. Typically this will not be used. /load_kernel_modules.pre-modload Load a user-supplied script subsequent to all module variable definitions being finalised, and prior to loading those Kernel modules. This enables you to make minor adjustments to the module lists that have been set by the provided platform support scripts. If one of the modules within the base list is causing problems on your platform, here are the options laid out as examples. You could include this type of code within this pre hook script: USB="${USB/ehci_orion/differentmodule}" # Substitute module 'ehci_orion' with 'differentmodule' USB="${USB/ehci_orion/}" # Remove the 'ehci_orion' module from the list USB="${USB} some_other_module" # Add a module to the list /load_kernel_modules.post Load a user-supplied script subsequent to loading the Kernel modules, but prior to restoring execution control to /init. * Note: You must ensure that modules that you add are present within the OS InitRD's cache of Kernel modules (lib/modules/*). * Developer note: If you are debugging, you may wish to open a shell to examine the environment before booting the Slackware OS proper. This was used extensively during the development of Slackware AArch64. You may supply 'slackpbs' as a Kernel command line token from the boot loader, which will cause /load_kernel_modules to open a shell at the two key stages (as described above). In general, most users will want to only create a 'post' script to load an additional module. For this example, we'll load the Kernel module 'ums-datafab' that supports the device we need to access within the OS InitRD: root@bladswede:/boot/local# echo 'modprobe -v ums-datafab' > load_kernel_modules.post The local customisations are complete. We now need to rebuild the OS InitRD: Repack with the Operating System Initial RAM Disk Manager ('os-initrd-mgr'): root@bladswede:/boot/local# os-initrd-mgr Searching for local customisations ... Found: /boot/local/keymap Found: /boot/local/load_kernel_modules.post Unpacking /boot/initrd-armv8 ... Adding customisations ... Repacking /boot/initrd-armv8 ... Successfully added local customisations to the OS InitRD. root@bladswede:/boot/local# The OS InitRD is now rebuilt. You should now reboot to test it. Note: When upgrading the Kernel packages, the local settings will be re-incorporated automatically during the package upgrade process, as long as they remain within /boot/local. 5.2 The manual route --------------------------------------------------- If you'd like to work with the OS InitRD manually: root@bladswede:/# cd /boot Create a directory in which to unpack the OS InitRD: root@bladswede:/boot# mkdir unpack root@bladswede:/boot# cd unpack/ Unpack the OS InitRD: root@bladswede:/boot/unpack# zcat ../initrd-armv8 | cpio -di Make changes: See Section 5.1 for examples of the types of changes you can make. However, using the manual route you can change _anything_ where as 'os-initrd-mgr' manages a particular collection of local customisations. Re-pack the OS InitRD: For AArch64: root@bladswede:/boot/unpack# find . | cpio -o -H newc | gzip -9fv > /boot/initrd-armv8 For ARM: root@bladswede:/boot/unpack# find . | cpio -o -H newc | gzip -9fv > /boot/initrd-armv7 Note: Do NOT change the compression type. This author has tried with LZMA compression, but whilst the LZMA decompression support is enabled in the Kernel, the Kernel won't boot. gzip is tried and tested. Clean up: As the OS InitRD will be replaced when the Kernel packages are upgraded, there is no requirement or reason to keep the temporary extraction directory: just remember to store your changes in /boot/local. root@bladswede:/boot/unpack# cd ../ root@bladswede:/boot# rm -rf unpack You may now reboot and your Kernel module will be loaded prior to init mounting the storage and pivoting into the OS proper. 6. mkinitrd_command_generator.sh in Slackware ARM / AArch64 ====================================================================== In Slackware ARM / AArch64 the mkinitrd_command_generator.sh script is not used, and will not create a working OS InitRD. Please use the generic/universal OS InitRD's supplied with Slackware ARM / AArch64 and use the guidance in section 6 to make local additions/changes. >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Have fun! -- Stuart Winter mozes@slackware April 2021