On Thu, Jan 19, 2012 at 10:29 AM, Bruce Dubbs <[email protected]> wrote:
> I've been thinking about the discussion we had earlier and think a
> couple of pages added to BLFS would be a good start (yes, I know this is
> lfs-dev).  The outline of the pages is below and I'm looking for feedback.

<snip>

>
>   Using dracut to create an initramfs (add dracut to the book)
>

I've been experimenting with initramfs recently (I used to use initrd
for my cdrom bootable lfs firewall).

It's relatively straightforward. I understand dracut may automate some
of the LVM\MD\RAID stuff (not looked at it yet), but for purely
educational purposes, isn't a hand-crafted version better?
Anyway, here are my notes for building initramfs during the last
stages of LFS. involves one additional package (busybox), a
requirement for a kernel parameter to be set (initramfs support) and
an additional line in grub.cfg

What we get as an end result is a simple, expandable initramfs
environment, that will drop to a rescue shell if the real root device
can't be loaded. This allows some diagnostics to be done regarding
device nodes, modules, use of lspci\lsusb, etc, which might be useful
given the number of issues recently with people configuring grub
correctly for the root= parameter.

Feel free to comment - if it's preferred, I can implement as a hint
instead. Note that module support is not yet tested and needs further
work, but was lifted verbatim from the existing gentoo initramfs wiki
page, so should be functional.

===========================
Using an INITRAMFS with LFS
===========================

@@@@@@@@@
FIXME: wordy and awkward
@@@@@@@@@

Modern Linux systems feature the ability to start what is known as
"early userspace". This is used in most cases to perform extra actions
that require features that
are either not generic enough to be in the Linux kernel, or are
complex enough to require user interaction.

This early userspace consists of a temporary root filesystem, with
just enough scripts and programs to perform the early actions needed.
This temporary root
filesystem, called an INITRAMFS, is loaded from a compressed cpio
archive into memory, is discarded when complete, and replaced by the
real root filesystem.

The INITRAMFS can be used to load binary firmware images to a RAID
controller, mounting of LVM or MD devices, decrypting an encrypted
root filesystem, or simply
providing a diagnostic (or rescue) shell environment if the real root
filesystem cannot be mounted.

LFS provides an INITRAMFS system that includes a rescue shell, and
which can be extended to provide other service such as LVM\MD or
encryption services as required.

=====================================
Creating the INITRAMFS directory tree
=====================================

We first need to create a place that the initramfs image can be built
from, and then populate the area with the necessary minimal scripts
and binaries.

  mkdir -pv /usr/src/initramfs

We don't need all the FHS required directories for an INITRAMFS, so we
just create the minimum required set

  mkdir -pv /usr/src/initramfs/{bin,dev,etc,lib,mnt/root,proc,root,sbin,sys}

We create a few minimal device nodes in case the device detection has problems.

  cp -av /dev/{console,null,tty} /usr/src/initramfs/dev

================
Building BusyBox
================

Next we use BusyBox, a single binary that can be referenced by many
different names to perform most of the functions needed by an
INITRAMFS (FIXME: ).

@@@@@@@@@
FIXME: Need a better description than this
FIXME: Mention the other option? Copy static\dynamic binaries from LFS
system and necessary dynamic libs? Helps teach use of LDD, etc? Much
larger INITRAMFS image, although we are talking 10's of megabytes
here...
@@@@@@@@@

  tar xvf busybox
  cd busybox
  make menuconfig
  Select at least the following
    BusyBox Settings --->
      General Configuration --->
        [*] Support --install [-s] to install applet links at runtime
        [*] Don't use /usr
      Build Options --->
        [*] Build BusyBox as a static binary (no shared libs)
    Archival Utilities --->
      [*] cpio
      [*]   Support for archive creation
    Coreutils --->
      [*] cat
      [*] cp
      [*] env
      [*] ls
      [*[ mkdir
      [*] mv
    Editors --->
      [*] vi
    Init Utilities --->
      [*] poweroff, halt and reboot
    Linux Module Utilities --->
      [*] insmod
      [*] lsmod
      [*] modprobe
    Linux System Utilities --->
      [*] dmesg]
      [*] lspci
      [*] lsusb
      [*] mdev
      [*] more
      [*] mount
      [*] switch_root
      [*] umount
    Miscellaneous Utilities --->
      [*] less
      [*] setsid
    Networking Utilities --->
      [*] ifconfig
      [*] route
      [*] telnetd
      [*] udhcpc client (udhcpc)
    Shells --->
      [*] ash
      [*] cttyhack
      [*] POSIX math support
  make
  cp busybox /usr/src/initramfs/bin
  cp examples/udhcp/simple.script /usr/src/initramfs/bin

==================================
Creating the temporary init script
==================================

Once the INITRAMFS is loaded, the kernel will immediately execute the
init program in the / directory of the temporary root. We create a
script called init in this location, using the commands below.

cat > /usr/src/initramfs/init < EOF
#!/bin/busybox sh

#==============
# Functions
#==============

# Create a rescue shell. If NETWORK is set to YES, then
# start the busybox telnetd daemon to allow remote login
rescue_shell() {

  if [ "$REMOTE_SHELL" = "YES" ]; then
    # telnetd requires devpts
    mkdir -p /dev/pts
    mount -t devpts none /dev/pts
    # Start the telnet server
    telnetd
  fi

  echo "Something went wrong. Dropping you to a shell."
  # cttyhack allows you to use job control in our
  # simple busybox shell environment
  exec setsid cttyhack sh

}

# Load any modules we have installed in initramfs
load_modules() {

  # This needs to be a list of modules installed
  # Better to just load all modules in dir?
  MODULES="mbcache.ko jbd2.ko ext4.ko"
  MOD_PATH="/lib/modules"
  for MODULE in ${MODULES} ; do
    insmod -f ${MOD_PATH}/${MODULE}
  done

}

echo "Starting INITRAMFS init script..."

#==============
# Constants
# Remove the comment line to enable these features
#==============
echo "  Setting Constants..."
NETWORK=YES
REMOTE_SHELL=YES
IP_DHCP=YES

#==============
# Variables
#==============
echo "  Setting Variables..."
IPADDR=192.168.1.1
IPGWAY=192.168.1.254

#==============
# Main script start
#==============

# Create the busybox symlinks for all the functions compiled in
echo "  Creating symlinks..."
/bin/busybox --install -s

# Mount the filesystems.
echo "  Mounting Filesystems..."
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t tmpfs devfs /dev

# Populate devices
echo "  Populating /dev..."
echo /bin/mdev > /proc/sys/kernel/hotplug
mdev -s

# Load any required modules.
echo "  Loading modules..."
load_modules || rescue_shell

# get default ROOT= and INIT= devices from kernel command line
echo "  Extracting root= and init= command lines..."
for cmd in $(cat /proc/cmdline) ; do
  case $cmd in
    root=*) ROOTDEV=${cmd#root=} ;;
    init=*) INITPRG=${cmd#init=} ;;
  esac
done
if [ "$ROOTDEV" = "" ]; then
  echo "ERROR: No root device found on kernel command line" && rescue_shell
fi
# set initprg to default to /sbin/init if none provided on command line
${INITPRG:="/sbin/init"}
echo "  Will mount $ROOTDEV and execute $INITPRG..."

# Enable networking if required
if [ "$NETWORK" = "YES" ]; then

  echo "  Enabling Networking..."
  if [ "$IP_DHCP" = "YES" ]; then
    echo "    Waiting for DHCP response..."
    ifconfig eth0 up
    udhcpc -t 5 -q -s /bin/simple.script
  else
    echo "    Setting IP address and gateway..."
    ifconfig eth0 $IPADDR
    route add default gw $IPGWAY
  fi

fi

#########################################
#
# Here you can include any commands you need to
# load firmware, mount LVM or MD root devices etc.
#
# set ROOTDEV to the root device node, if not
# already set on the kernel command line
#
#########################################

# Mount the real root filesystem.
echo "  Mounting real root ($ROOTDEV) on /mnt/root..."
mount -o ro $ROOTDEV /mnt/root || rescue_shell

# Clean up filesystems
echo "  Unmounting filesystems..."
umount /proc
umount /sys
umount /dev/pts

# Boot the real thing init process
echo "  Switching to real root and executing init process..."
exec switch_root /mnt/root $INITPRG
EOF
chmod +x /usr/src/initramfs/init

==========================
Explanation of init script
==========================

1. Set up some simple shell functions

  rescue_shell

    Provides a command line ash shell, and can also provide a telnet
daemon if configured to allow remote access if the system does not
have a local monitor or keyboard

  load_modules

    Function to load any kernel modules that are needed in this early
userspace environment. Examples are the modules for LVM\MD, the
filesystem module for the real root fs, etc.

2. Mount the filesystems required to get the minimal device nodes
detected, such as /sys, /proc and /dev

3. Populate /dev using busybox cutdown version of udev (mdev)

4. Load any moduless, using the function declared earlier

5. Extract the real init= and root= entries from the kernel command line

6. If configured, setup the netwiork interface to allow remote access
if required. Note that you will either have to setup networking as
compiled in, or provide the appropriate modules to be loaded by the
function declared earlier.

7. At this point you can extend this init script by adding any command
you would run for mounting LVM or MD devices, decrypting, or uploading
firmware, etc.

8. Mount the real root filesystem as read-only at a temporary
location. If this fails (device error, failure to load modules, etc)
then we start a rescue shell.

9. Cleanup after ourselves, removing the filesystem mounts we created

10. Run the switch_root command to overwrite our temporary root
filesystem with the real root, and execute the real init process.

==================
Kernel Compilation (existing section)
==================

Enable the following kernel options

  General setup  --->
    [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
      () Initramfs source file(s)

======================
Copying Kernel Modules
======================

For each kernel module that needs to be in the INITRAMFS, do the following

  modinfo /lib/modules/$(uname
-r)/kernel/<subsection>/<module>/<module>.ko | grep depends

  e.g. If you root filesystem is EXT4, and you have compiled it as a module, do
  modinfo /lib/modules/$(uname -r)/kernel/fs/ext4/ext4.ko | grep depends

The output should be similar to the following, which shows we need
those two modules as well.
        depends:        mbcache,jbd2

Create the /usr/src/initramfs/lib/modules directory:
  mkdir -p /usr/src/initramfs/lib/modules

Use find to search and copy the module and it's dependencies
  find /lib/modules/$(uname -r)/ -iname "mbcache.ko" -exec cp {}
/usr/src/initramfs/lib/modules/ \;
  find /lib/modules/$(uname -r)/ -iname "jbd2.ko" -exec cp {}
/usr/src/initramfs/lib/modules/ \;
  find /lib/modules/$(uname -r)/ -iname "ext4.ko" -exec cp {}
/usr/src/initramfs/lib/modules/ \;

Repeat above for any other modules required.

================================
Build the initramfs cpio archive
================================

cd /usr/src/initramfs
find . -print0 | bin/busybox cpio -ov -H newc | bzip2 -9 >
/boot/initramfs.cpio.bz2

add following to /boot/grub.cfg after linux line
  initrd        /boot/initramfs.cpio.bz2

Should make a recommendation to leave initramfs source in place for
future updates\changes, or instructions on how to extract from cpio
archive. Note that changes to INITRAMFS need only to replace cpio file
in
/boot, kernel recompile not needed.

@@@@@@@@@
FIXME: should note there is an option to build cpio into kernel? may
complicate issue? extraction is painful using kernel image, and
require kernel recompile for any changes
@@@@@@@@@

-- 
-- -
Steve Crosby
-- 
http://linuxfromscratch.org/mailman/listinfo/lfs-dev
FAQ: http://www.linuxfromscratch.org/faq/
Unsubscribe: See the above information page

Reply via email to