# Busybox as the init ###### tags: `Busybox`, `QEMU`, `Virtual Machine`, `Linux`, `Raspberry Pi` `Linux from Scratch` ## Linux Kernel Tries to Find init ``` [ 2.146201] Run /sbin/init as init process [ 2.148061] Run /etc/init as init process [ 2.149846] Run /bin/init as init process [ 2.150521] Run /bin/sh as init process [ 2.151871] Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/admin-guide/init.rst for guidance. ``` ## Build Busybox ```shell= $ git clone https://git.busybox.net/busybox $ cd busybox $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- install $ ls -l _install/ total 12 drwxr-xr-x 2 zack zack 4096 Jun 5 12:06 bin lrwxrwxrwx 1 zack zack 11 Jun 5 12:06 linuxrc -> bin/busybox drwxr-xr-x 2 zack zack 4096 Jun 5 12:06 sbin drwxr-xr-x 4 zack zack 4096 Jun 5 12:06 usr ``` PS. When install Busybox into the root partition, have to set `CONFIG_PREFIX="<the root partition mount path>"` ## Prepare the Image and Partitions ```shell= $ dd if=/dev/zero of=~/qemu-images/simple-busybox.img bs=8M count=16 16+0 records in 16+0 records out 134217728 bytes (134 MB, 128 MiB) copied, 0.086382 s, 1.6 GB/s $ fdisk -l ~/qemu-images/simple-busybox.img Disk /home/zack/qemu-images/simple-busybox.img: 128 MiB, 134217728 bytes, 262144 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x7ac31012 Device Boot Start End Sectors Size Id Type /home/zack/qemu-images/simple-busybox.img1 * 2048 206847 204800 100M b W95 FAT32 /home/zack/qemu-images/simple-busybox.img2 206848 262143 55296 27M 83 Linux $ mkfs.vfat -v --offset=2048 ~/qemu-images/simple-busybox.img $((100*1024*1024/1024)) $ mkfs.ext4 -E offset=$((512*206848)) ~/qemu-images/simple-busybox.img ``` ## Prepare Root File System on the Image ```shell= $ sudo mount -o offset=$((512*206848)) ~/qemu-images/simple-busybox.img /mnt/ $ sudo cp -r _install/* /mnt/ $ sudo mkdir -p /mnt/etc $ sudo mkdir -p /mnt/etc/init.d $ sudo mkdir -p /mnt/proc $ sudo mkdir -p /mnt/sys $ sudo mkdir -p /mnt/dev $ sudo mkdir -p /mnt/tmp $ sudo mkdir -p /mnt/root $ sudo mkdir -p /mnt/var $ sudo mkdir -p /mnt/lib $ sudo mkdir -p /mnt/mnt $ sudo mkdir -p /mnt/boot $ ls -l /mnt/ total 15 drwxr-xr-x 2 root root 3072 Apr 5 22:39 bin drwxr-xr-x 2 root root 1024 Apr 5 22:41 boot drwxr-xr-x 2 root root 1024 Apr 5 22:41 dev drwxr-xr-x 3 root root 1024 Apr 5 22:41 etc lrwxrwxrwx 1 root root 11 Apr 5 22:39 linuxrc -> bin/busybox drwxr-xr-x 2 root root 1024 Apr 5 22:41 mnt drwxr-xr-x 2 root root 1024 Apr 5 22:41 proc drwxr-xr-x 2 root root 1024 Apr 5 22:41 root drwxr-xr-x 2 root root 3072 Apr 5 22:39 sbin drwxr-xr-x 2 root root 1024 Apr 5 22:41 sys drwxr-xr-x 2 root root 1024 Apr 5 22:41 tmp drwxr-xr-x 4 root root 1024 Apr 5 22:39 usr drwxr-xr-x 2 root root 1024 Apr 5 22:41 var ``` Note: Must take care the shared C libraries issue. Otherwise, kernel may fail to execute the `init`. **Static link** is a quick solution. ## Install the [/etc/inittab](https://git.busybox.net/busybox/tree/init/init.c?h=1_35_0#n29) ```shell= $ sudo install ~/busybox/examples/inittab /mnt/etc/inittab ``` * Disable the default **askfirst shell** by commenting `::askfirst:-/bin/sh` to avoid duplicated shells on the same console. * The QEMU VM need `ttyAMA0::respawn:/sbin/getty -L 0 ttyAMA0 vt100` for serial console. ## [Creating the /etc/fstab File](https://www.linuxfromscratch.org/lfs/view/9.1/chapter08/fstab.html) ```shell= $ cat /mnt/etc/fstab # Begin /etc/fstab # file system mount-point type options dump fsck # order /dev/vda1 / ext4 rw,relatime 0 0 proc /proc proc nosuid,noexec,nodev 0 0 #sysfs /sys sysfs nosuid,noexec,nodev 0 0 #devpts /dev/pts devpts gid=5,mode=620 0 0 #tmpfs /run tmpfs defaults 0 0 #devtmpfs /dev devtmpfs mode=0755,nosuid 0 0 # End /etc/fstab ``` ```shell= ## Install udhcpc script for obtaining & setting IP to interface ## http://dannysun-unknown.blogspot.com/2018/08/busybox-udhcpc-ipip.html $ sudo install -d /mnt/usr/share/udhcpc $ sudo install examples/udhcp/simple.script /mnt/usr/share/udhcpc/default.script $ echo "nameserver 8.8.8.8" | sudo tee -a /mnt/etc/resolv.conf # Maybe not ## Set host name $ echo "busybox-arm64" | sudo tee -a /mnt/etc/hostname ## Initial script $ cat /mnt/etc/init.d/rcS #!/bin/sh mount -a ip link set eth0 up udhcpc hostname -F /etc/hostname ntpd -n -q -p time.stdtime.gov.tw $ sudo chmod +x /mnt/etc/init.d/rcS ## User list $ echo "root:x:0:0::/root:/bin/sh" | sudo tee -a /mnt/etc/passwd $ echo "root::18541::::::" | sudo tee -a /mnt/etc/shadow ``` ## Build Linux Kernel (virt) ```shell= $ git checkout tags/v5.15.24 $ cp arch/arm/configs/vexpress_defconfig .config $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig # Leave ARMv8 software model (Versatile Express) only $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- ``` ## Launch QEMU VM (virt) ```shell= $ qemu-system-aarch64 -smp 2 -M virt -cpu cortex-a57 -m 1G -kernel ~/linux-stable/arch/arm64/boot/Image --append "console=ttyAMA0 root=/dev/vda2 rw rootfstype=ext4" -hda ~/qemu-images/simple-busybox.img ``` ## Boot on Raspberry Pi 3B * Raspberry Pi 3B's serial console is **ttyS1**. * The mircro SD is **mmcblk0** as the block. So, the boot partition is **mmcblk0p1**. The root partition is **mmcblk0p2**. * Need Raspberry Pi's boot firmware files from Raspberry Pi OS. * Have interactive consoles by listing in `/etc/inittab`: * Have `tty1::respawn:-/bin/sh` for normal console * Have `::respawn:/sbin/getty -L ttyS1 115200 vt100` to replace the original **ttyAMA0** console * Make sure there is `rw` in boot command for read-writable root file system. * May need wait a small time before request with DHCP * Raspberry Pi's wireless devices need the corresponding firmwares. They can be gotten from linux-firmware upstream. ``` [ 2.375289] brcmfmac mmc1:0001:1: Direct firmware load for brcm/brcmfmac43430-sdio.raspberrypi,3-model-b.bin failed with error -2 [ 2.387389] brcmfmac mmc1:0001:1: Direct firmware load for brcm/brcmfmac43430-sdio.bin failed with error -2 [ 2.557444] mmcblk0p2: Can't mount, would change RO state [ 2.571947] Bluetooth: hci0: BCM: firmware Patch file not found, tried: [ 2.578840] Bluetooth: hci0: BCM: 'brcm/BCM43430A1.hcd' [ 2.578860] Bluetooth: hci0: BCM: 'brcm/BCM.hcd' ``` MSDOS Partition does not support that kernel boots with root from `PARTUUID` ```shell= # blkid /dev/vda2: UUID="8d5165f0-d51f-404b-a3a6-7765cf69bbc6" TYPE="ext4" /dev/vda1: UUID="143C-2AED" TYPE="vfat" ``` ## Reference * https://riptutorial.com/embedded-linux * [fdisk](https://man7.org/linux/man-pages/man8/fdisk.8.html) * [mkfs.vfat](https://man7.org/linux/man-pages/man8/mkfs.vfat.8.html) * [mkfs.ext4](https://man7.org/linux/man-pages/man5/ext4.5.html) * [mount](https://man7.org/linux/man-pages/man8/mount.8.html)