Raspberry Pi Custom Installation/Kernel

From JMK Wiki

To be able to boot from LVM a custom kernel is required with an initial ram disk

On raspbian a few things need to be installed and set up

root@localhost ~ # apt install bc git ncurses-dev
root@localhost ~ # modprobe configs

Download the kernel source

root@localhost ~ # cd /usr/src
root@localhost ~ # wget -O rpi-4.9.y.zip https://codeload.github.com/raspberrypi/linux/zip/rpi-4.9.y
root@localhost ~ # unzip rpi-4.9.y.zip

Prepare and configure the kernel

root@localhost /usr/src # cd /usr/src/linux-rpi-4.9.y
root@localhost /usr/src # make -j5 -l5 mrproper

For building upon the current running kernel copy the configuration from the procfs

root@localhost /usr/src/linux-rpi-4.9.y # zcat /proc/config.gz > .config

For the default rpi config use arch/arm/configs/bcmrpi_defconfig

root@localhost /usr/src/linux-rpi-4.9.y # cp arch/arm/configs/bcmrpi_defconfig .config

For the default rpi 3 config use arch/arm64/configs/bcmrpi64_defconfig

root@localhost /usr/src/linux-rpi-4.9.y # cp arch/arm64/configs/bcmrpi3_defconfig .config

Configure the kernel

root@localhost /usr/src/linux-rpi-4.9.y # make -j5 -l5 menuconfig

Set LVM to compile into kernel and enabled initrd to be able to add custom initrd file

General setup  --->
   [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
       [*] Support initial ramdisks compressed using gzip (NEW)
Device Drivers  --->
   Multiple devices driver support (RAID and LVM)  --->
       <*> Device mapper support 
           <*> Crypt target support
           <*> Snapshot target
           <*> Mirror target
       <*> Multipath target
           <*> I/O Path Selector based on the number of in-flight I/Os
           <*> I/O Path Selector based on the service time

Compile the kernel and install modules

root@localhost /usr/src/linux-rpi-4.9.y # make -j5 -l5 && make -j5 -l5 modules_install

Copy the kernel based on your previous choice

root@localhost /usr/src/linux-rpi-4.9.y # cp -v arch/arm/boot/zImage /boot/linux-4.9.y-raspbian

Or

root@localhost /usr/src/linux-rpi-4.9.y # cp -v arch/arm/boot/zImage /boot/linux-4.9.y-rpi

Or

root@localhost /usr/src/linux-rpi-4.9.y # cp -v arch/arm64/boot/zImage /boot/linux-4.9.y-rpi64

Create an initramfs directory

root@localhost /usr/src/linux-rpi-4.9.y # mkdir -p /usr/src/initramfs
root@localhost /usr/src/linux-rpi-4.9.y # cd /usr/src/initramfs

Install a static builds of busybox and e2fsck-static

root@localhost /usr/src/initramfs # apt install busybox-static e2fsck-static

Collect the files needed for the initial ram disk

root@localhost /usr/src/initramfs # touch initramfs_list
# directory structure
dir /bin														755 0 0
dir /dev														755 0 0
dir /etc														755 0 0
dir /lib														755 0 0
dir /lib64														755 0 0
dir /mnt														755 0 0
dir /mnt/root														755 0 0
dir /proc														755 0 0
dir /root														700 0 0
dir /sbin														755 0 0
dir /sys														755 0 0
dir /usr														755 0 0
dir /var														755 0 0

# busybox
file	/bin/busybox						/bin/busybox						755 0 0

# fsck
file	/sbin/e2fsck						/sbin/e2fsck.static					755 0 0
file	/sbin/fsck						/sbin/fsck						755 0 0
file	/sbin/fsck.cramfs					/sbin/fsck.cramfs					755 0 0
file	/sbin/fsck.fat						/sbin/fsck.fat						755 0 0
file	/sbin/fsck.minix					/sbin/fsck.minix					755 0 0
slink	/sbin/dosfsck						/sbin/fsck.fat						755 0 0
slink	/sbin/fsck.ext2						/sbin/e2fsck						755 0 0
slink	/sbin/fsck.ext3						/sbin/e2fsck						755 0 0
slink	/sbin/fsck.ext4						/sbin/e2fsck						755 0 0
slink	/sbin/fsck.msdos					/sbin/fsck.fat						755 0 0
slink	/sbin/fsck.vfat						/sbin/fsck.fat						755 0 0

# lvm
file	/sbin/lvm						/sbin/lvm						755 0 0
slink	/sbin/lvchange						/sbin/lvm						755 0 0
slink	/sbin/lvconvert						/sbin/lvm						755 0 0
slink	/sbin/lvcreate						/sbin/lvm						755 0 0
slink	/sbin/lvdisplay						/sbin/lvm						755 0 0
slink	/sbin/lvextend						/sbin/lvm						755 0 0
slink	/sbin/lvmchange						/sbin/lvm						755 0 0
slink	/sbin/lvmconfig						/sbin/lvm						755 0 0
slink	/sbin/lvmdiskscan					/sbin/lvm						755 0 0
slink	/sbin/lvmsadc						/sbin/lvm						755 0 0
slink	/sbin/lvmsar						/sbin/lvm						755 0 0
slink	/sbin/lvreduce						/sbin/lvm						755 0 0
slink	/sbin/lvremove						/sbin/lvm						755 0 0
slink	/sbin/lvrename						/sbin/lvm						755 0 0
slink	/sbin/lvresize						/sbin/lvm						755 0 0
slink	/sbin/lvs						/sbin/lvm						755 0 0
slink	/sbin/lvscan						/sbin/lvm						755 0 0
slink	/sbin/pvchange						/sbin/lvm						755 0 0
slink	/sbin/pvck						/sbin/lvm						755 0 0
slink	/sbin/pvcreate						/sbin/lvm						755 0 0
slink	/sbin/pvdisplay						/sbin/lvm						755 0 0
slink	/sbin/pvmove						/sbin/lvm						755 0 0
slink	/sbin/pvremove						/sbin/lvm						755 0 0
slink	/sbin/pvresize						/sbin/lvm						755 0 0
slink	/sbin/pvs						/sbin/lvm						755 0 0
slink	/sbin/pvscan						/sbin/lvm						755 0 0
slink	/sbin/vgcfgbackup					/sbin/lvm						755 0 0
slink	/sbin/vgcfgrestore					/sbin/lvm						755 0 0
slink	/sbin/vgchange						/sbin/lvm						755 0 0
slink	/sbin/vgck						/sbin/lvm						755 0 0
slink	/sbin/vgconvert						/sbin/lvm						755 0 0
slink	/sbin/vgcreate						/sbin/lvm						755 0 0
slink	/sbin/vgdisplay						/sbin/lvm						755 0 0
slink	/sbin/vgexport						/sbin/lvm						755 0 0
slink	/sbin/vgextend						/sbin/lvm						755 0 0
slink	/sbin/vgimport						/sbin/lvm						755 0 0
slink	/sbin/vgmerge						/sbin/lvm						755 0 0
slink	/sbin/vgmknodes						/sbin/lvm						755 0 0
slink	/sbin/vgreduce						/sbin/lvm						755 0 0
slink	/sbin/vgremove						/sbin/lvm						755 0 0
slink	/sbin/vgrename						/sbin/lvm						755 0 0
slink	/sbin/vgs						/sbin/lvm						755 0 0
slink	/sbin/vgscan						/sbin/lvm						755 0 0
slink	/sbin/vgsplit						/sbin/lvm						755 0 0

# libraries required by fsck, e2fsck
file	/lib/arm-linux-gnueabihf/libc.so.6			/lib/arm-linux-gnueabihf/libc.so.6			755 0 0
file	/lib/arm-linux-gnueabihf/libz.so.1			/lib/arm-linux-gnueabihf/libz.so.1			755 0 0
file	/lib/arm-linux-gnueabihf/libudev.so.1			/lib/arm-linux-gnueabihf/libudev.so.1			755 0 0
file	/lib/arm-linux-gnueabihf/libdl.so.2			/lib/arm-linux-gnueabihf/libdl.so.2			755 0 0
file	/lib/arm-linux-gnueabihf/libblkid.so.1			/lib/arm-linux-gnueabihf/libblkid.so.1			755 0 0
file	/lib/arm-linux-gnueabihf/libdevmapper-event.so.1.02.1	/lib/arm-linux-gnueabihf/libdevmapper-event.so.1.02.1	755 0 0
file	/lib/arm-linux-gnueabihf/libdevmapper.so.1.02.1		/lib/arm-linux-gnueabihf/libdevmapper.so.1.02.1		755 0 0
file	/lib/arm-linux-gnueabihf/libreadline.so.5		/lib/arm-linux-gnueabihf/libreadline.so.5		755 0 0
file	/lib/arm-linux-gnueabihf/librt.so.1			/lib/arm-linux-gnueabihf/librt.so.1			755 0 0
file	/lib/arm-linux-gnueabihf/libc.so.6			/lib/arm-linux-gnueabihf/libc.so.6			755 0 0
file	/lib/arm-linux-gnueabihf/libgcc_s.so.1			/lib/arm-linux-gnueabihf/libgcc_s.so.1			755 0 0
file	/lib/arm-linux-gnueabihf/libm.so.6			/lib/arm-linux-gnueabihf/libm.so.6			755 0 0
file	/lib/arm-linux-gnueabihf/libpcre.so.3			/lib/arm-linux-gnueabihf/libpcre.so.3			755 0 0
file	/lib/arm-linux-gnueabihf/libpthread.so.0		/lib/arm-linux-gnueabihf/libpthread.so.0		755 0 0
file	/lib/arm-linux-gnueabihf/libselinux.so.1		/lib/arm-linux-gnueabihf/libselinux.so.1		755 0 0
file	/lib/arm-linux-gnueabihf/libtinfo.so.5			/lib/arm-linux-gnueabihf/libtinfo.so.5			755 0 0
file	/lib/arm-linux-gnueabihf/libuuid.so.1			/lib/arm-linux-gnueabihf/libuuid.so.1			755 0 0
file	/lib/ld-linux-armhf.so.3				/lib/ld-linux-armhf.so.3				755 0 0
file	/usr/lib/arm-linux-gnueabihf/libarmmem.so		/usr/lib/arm-linux-gnueabihf/libarmmem.so		755 0 0

# our init script
file	/init							/usr/src/initramfs/init					755 0 0


Create the init script

root@localhost /usr/src/initramfs # touch init
#!/bin/busybox sh

rescue_shell() {
	echo "$@"
	echo "Something went wrong. Dropping you to a shell."
	/bin/busybox --install -s
	exec /bin/sh
}

activate_vgs() {
	/sbin/pvscan --uuid --verbose || rescue_shell "Error while scanning physical volumes"
	/sbin/vgscan --mknodes --verbose || rescue_shell "Error while scanning volume groups"

	for vg in $(/sbin/vgscan | grep "Found volume group" | cut -d\" -f2) ; do
		echo "Activating volume group: $vg"
		/sbin/vgchange -ay $vg --sysinit || rescue_shell "Error while activating $vg"
		/sbin/vgmknodes --ignorelockingfailure $vg || rescue_shell "Error while making nodes for $vg"
	done
}

find_rootfs() {
	for cmd in $(cat /proc/cmdline) ; do
		case $cmd in
			root=*)
				type=$(echo $cmd | cut -d= -f2)
				echo "Mounting rootfs"
				if [ $type == "LABEL" ] || [ $type == "UUID" ] ; then
					uuid=$(echo $cmd | cut -d= -f3)
					mount -o ro $(findfs "$type"="$uuid") /mnt/root
					return
				else
					mount -o ro $(echo $cmd | cut -d= -f2) /mnt/root
					return
				fi
			;;
		esac
	done

	rescue_shell "No root partition found"
}

check_filesystem() {
	# most of code coming from /etc/init.d/fsck

	local fsck_opts= check_extra= RC_UNAME=$(uname -s)

	# FIXME : get_bootparam forcefsck
	if [ -e /forcefsck ]; then
		fsck_opts="$fsck_opts -f"
		check_extra="(check forced)"
	fi

	echo "Checking local filesystem $check_extra : $1"

	if [ "$RC_UNAME" = Linux ]; then
		fsck_opts="$fsck_opts -C0 -T"
	fi

	trap : INT QUIT

	# using our own fsck, not the builtin one from busybox
	/sbin/fsck -p $fsck_opts $1

	case $? in
		0)		return 0;;
		1)		echo "Filesystem repaired"; return 0;;
		2|3)	if [ "$RC_UNAME" = Linux ]; then
						echo "Filesystem repaired, but reboot needed"
						reboot -f
				else
						rescue_shell "Filesystem still have errors; manual fsck required"
				fi;;
		4)		if [ "$RC_UNAME" = Linux ]; then
						rescue_shell "Fileystem errors left uncorrected, aborting"
				else
						echo "Filesystem repaired, but reboot needed"
						reboot
				fi;;
		8)		echo "Operational error"; return 0;;
		12)		echo "fsck interrupted";;
		*)		echo "Filesystem couldn't be fixed";;
	esac
	rescue_shell
}

# temporarily mount proc and sys
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev

# disable kernel messages from popping onto the screen
echo 0 > /proc/sys/kernel/printk

# clear the screen
clear

# scan for vgs and activate each and every one of them
activate_vgs || rescue_shell "Error while activating volume groups"

# mounting rootfs on /mnt/root
find_rootfs || rescue_shell "Error while finding root filesystem"

# space separated list of mountpoints that ...
mountpoints=""

# ... we want to find in /etc/fstab ...
ln -s /mnt/root/etc/fstab /etc/fstab

# ... to check filesystems and mount our devices.
for m in $mountpoints ; do
	check_filesystem $m

	echo "Mounting $m"
	# mount the device and ...
	mount $m || rescue_shell "Error while mounting $m"

	# ... move the tree to its final location
	mount --move $m "/mnt/root"$m || rescue_shell "Error while moving $m"
done

echo "All done. Switching to real root."

# clean up. The init process will remount proc sys and dev later
umount /proc
umount /sys
umount /dev

# switch to the real root and execute init
exec switch_root /mnt/root /sbin/init

Get back to the kernel directory

root@localhost /usr/src/initramfs # cd /usr/src/linux-rpi-4.9.y

Set the generator script to be executable

root@localhost /usr/src/linux-rpi-4.9.y # chmod +x usr/gen_init_cpio scripts/gen_initramfs_list.sh

Generate the initial ram disk and copy it with a name based on your previous choice

root@localhost /usr/src/linux-rpi-4.9.y # scripts/gen_initramfs_list.sh -o /boot/initrd-4.9.y-raspbian /usr/src/initramfs/initramfs_list

Or

root@localhost /usr/src/linux-rpi-4.9.y # scripts/gen_initramfs_list.sh -o /boot/initrd-4.9.y-rpi /usr/src/initramfs/initramfs_list

Or

root@localhost /usr/src/linux-rpi-4.9.y # scripts/gen_initramfs_list.sh -o /boot/initrd-4.9.y-rpi64 /usr/src/initramfs/initramfs_list

Use the newly created kernel and initial ram fs

root@localhost /usr/src/linux-rpi-4.9.y # nano/boot/config.txt
kernel=linux-4.9.y-raspbian
initramfs initrd-4.9.y-raspbian

Or

kernel=linux-4.9.y-rpi
initramfs initrd-4.9.y-rpi

Or

kernel=linux-4.9.y-rpi64
initramfs initrd-4.9.y-rpi64

In some cases the archive gets messed up, in that case decompress it re-compress it

root@localhost /usr/src/linux-rpi-4.9.y # mkdir -p /tmp/initrd
root@localhost /usr/src/linux-rpi-4.9.y # cd /tmp/initrd
root@localhost /tmp/initrd # mv /boot/initrd-4.9.y-raspbian initrd-4.9.y-raspbian.cpio.gz
root@localhost /tmp/initrd # gunzip initrd-4.9.y-raspbian
root@localhost /tmp/initrd # cpio -idv < initrd-4.9.y-raspbian
root@localhost /tmp/initrd # rm initrd-4.9.y-raspbian
root@localhost /tmp/initrd # find . | cpio -ov > initrd-4.9.y-raspbian.cpio
root@localhost /tmp/initrd # gzip initrd-4.9.y-raspbian.cpio
root@localhost /tmp/initrd # mv initrd-4.9.y-raspbian.cpio.gz /boot/initrd-4.9.y-raspbian