
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/<platform name or architecture grouping>/initrd-<platformname>
    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-<version>/kernels/<platform>/zImage-<platform>

  e.g. slackwarearm-15.0/kernels/armv7/zImage-armv7

are copies of those found in the Slackware Kernel package in the a/series:
  kernel_<platform>-<version>-arm-<build>.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_<arch>' 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=<partition_label>:/path/to/file
                    UUID=<partition_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
