Steffen Nurpmeso wrote in <20230908233854.Xni_j%steffen@sdaoden.eu>: |Michael Kjörling wrote in | : ||On 5 Sep 2023 17:53 +0200, from steffen@sdaoden.eu (Steffen Nurpmeso): ... ||> Of course i am no real Linux expert but only a do-it-yourself guy. || ||If your need is restricted to a highly specific use case and you are ||trying to keep it as small as possible, then it should be possible to ... Actually maybe someone may find it funny, even though it is neither historic nor very sophisticated. Let me post it. In the end it takes some time to get there. I would expect almost all of you will not be interested in the lengthy rest of this mail. Ciao, and a nice Sunday i wish from Germany! All you need are statically linked busybox (and cryptsetup with encryption), and a kernel with EFI_STUB on the EFI partition, so it can be booted directly. The distribution kernels i have (ArchLinux, AlpineLinux) have it enabled; if your EFI is large enough you could simply copy it and all its masses of modules to EFI. Otherwise the kernel needs all the firmware and modules to boot and to access all filesystems where the real stuff is. My own kernel has a lot of things statically built-in, but it can load more via modules (stage2 uses "the same" kernel later, and does). Kernels on stage2 need kexec, i have CONFIG_KEXEC=y CONFIG_KEXEC_FILE=y CONFIG_ARCH_HAS_KEXEC_PURGATORY=y # CONFIG_KEXEC_SIG is not set CONFIG_KEXEC_CORE=y -s1.sh and -s2.sh are docu-commented at the top; they can also be used to create the necessary environment. If i recall correctly cd /boot sh linit-init-s2.sh PATH-TO-BUSYBOX PATH-TO-CRYPTSETUP mount EFI-PARTITION cd EFI-PARTITION sh linit-init-s1.sh PATH-TO-BUSYBOX PATH-TO-CRYPTSETUP This only creates files and directories etc, and beat me if it does any harm otherwise. I use a specific naming scheme, the script reacts in particular on -old and -new to select sensible defaults. #?0|kent:/boot# ll ideapad*.efi -rwxr-xr-x 1 root root 10112672 Aug 26 18:44 ideapad-stage1.efi* -rw-r--r-- 1 root root 10120512 Sep 2 19:52 ideapad-6_1.efi -rw-r--r-- 1 root root 10120512 Sep 9 18:18 ideapad-6_1-old.efi -rw-r--r-- 1 root root 10121376 Sep 9 18:18 ideapad-6_1-new.efi That very kernel (series) is in fact shared in between several computers of a similar series, kent is the one i write this on: #?1|kent:/boot# v kent.sh #!/busybox.static sh #@ kent, step 1., via EFI. PART_ROOT=/dev/nvme0n1p? ROOT_DECRYPT='-t btrfs -o defaults,subvol=/crux/kent/root' PART_ROOT1=/dev/nvme0n1p8 ROOT_DECRYPT1='-t btrfs -o defaults,subvol=/crux/kent/root.old' INIT_S2=/boot/kent-2.sh . /linux-init-s1.sh #?0|kent:/boot# v kent-2.sh #@ kent, stage 2 KERNEL_ID=ideapad ^ restrict kernel selection for kexec: ^ [ "${k##*$KERNEL_ID-*.efi}" != "$k" ] || continue PART_SWAP=/dev/nvme0n1p6 SWAP_INPUT=y ^ you can have additional interactive random for swap encryption ^ (it is a lie i use that in practice) INITRD_PATH=/boot/.kent.initrd KEXEC_ARGS="--append=\"rtw88_pci.disable_aspm=1 rc.hostname=kent\"" FILE_CHECK='kent-direct.sh kent.sh ideapad-stage1.efi' SWITCH_ROOT=media/initrd Stage 2 config file is sourced automatically, so no need to source linux-init-s2.sh yourself (stage 2 uses switch_root). I also have a direct boot, but have not used it for long: #?0|kent:~# v /boot/kent-direct.sh #!/busybox.static sh #@ kent-direct, sole step 1., via EFI. PART_ROOT=/dev/nvme0n1p8 ROOT_DECRYPT='-t btrfs -o defaults,subvol=/crux/kent/root' PART_ROOT1=/dev/nvme0n1p8 ROOT_DECRYPT1='-t btrfs -o defaults,subvol=/crux/kent/root.old' PART_SWAP=/dev/nvme0n1p6 PIVOT_OLDROOT=media/initrd . /linux-init-s1.sh This does not use kexec, but only pivot_root's to the decrypted filesystem, starting sbin/init there. The kernel from EFI continues to run. It is pretty cool how i now can drive several computers easily simply by creating a shell script with some variable assignments. In fact the filesystem is shared in between multiple computers (with only selective partitions being truly unique, but still backed up everywhere), and all those text configs are in /boot. Only the VFAT EFI partition is truly system-specific (ie, in that it only holds the stage1 config file for $HOSTNAME). I like that very much, and hope Linux continues to be so flexible. (Not that one day you need systemd-early to get into Linux to get to systemd-later, or something.) The EFI boot is driven via efibootmgr(8) and has config like #@ /root/hosts/self/efiboot d=/dev/nvme0n1p1 maxno=1 b1=0x01 L1=kent l1=ideapad-stage1 u1='root='${d}' rootfstype=vfat init=/kent.sh' driven by /root/bin/efiboot.sh (shortened): #!/bin/sh : ${HOSTNAME:=$(uname -n)} : ${DBG:=} if [ -f /root/hosts/${HOSTNAME}/efiboot ]; then . /root/hosts/${HOSTNAME}/efiboot else echo >&2 "MISS /root/hosts/${HOSTNAME}/efiboot" exit 1 fi if [ "$1" = create ]; then obo=$(efibootmgr | grep -E ^BootOrder: | sed -E 's/^BootOrder:[[:space:]]*//') if [ -z "$obo" ]; then echo >&2 'Cannot determine previous boot order' exit 1 fi nbo= i=1 while [ $i -le $maxno ]; do eval ${DBG} efibootmgr -c -b \$b$i -L \\\"\$L$i\\\" -d \$d$i -l \\\"\$l$i.efi\\\" -u \\\"\$u$i\\\" #>/dev/null [ -n "$nbo" ] && nbo=$nbo, eval nbo=\$nbo\$b$i i=$((i + 1)) done ${DBG} efibootmgr -o $nbo,$obo #> /dev/null elif [ "$1" = delete ]; then i=1 while [ $i -le $maxno ]; do eval ${DBG} efibootmgr -B -b \$b$i #>/dev/null i=$((i + 1)) done else echo >&2 'Synsopsis: efiboot.sh create|delete' exit 1 fi ${DBG} efibootmgr -v -u This is of course git managed, so i can distribute it easily. (Further even, the entire ideapad series configurations differ in only 193 lines, and most of those are the different SSH keys. The rest are different device names, ie network, display, volume etc, disk partitions, host names.) I am pretty lucky i found a way to manage my systems like this. I have several git branches in root.git, linux.kconfig, bin, iwd.network, and one for each computer. I can then "git merge" selectively together what is necessary. For example my web vserver only needs bin and its own configuration, whereas the laptops also need iwd.network. Etc etc. Like this every computer only knows the selective minimum. The full git repo is on an encrypted volume stored away. And it is not Puppet or Ansible or any of those programs, it is nothing but git and its branches. But now i really left manually driven cryptsetup by far. Ciao! --steffen | |Der Kragenbaer, The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt)