diff --git a/.gitignore b/.gitignore index ac6f994..a86299f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ packages/ out/ -.swp +*.swp diff --git a/alpine/build-rootfs.sh b/alpine/build-rootfs.sh index da9c1f8..691051a 100755 --- a/alpine/build-rootfs.sh +++ b/alpine/build-rootfs.sh @@ -7,6 +7,14 @@ set -euo pipefail mkdir -p "$ROOTFS/var/cache/apk" mkdir -p "$ROOTFS/opt/monok8s/config" mkdir -p "$ROOTFS/build" +mkdir -p \ + "$ROOTFS/dev" \ + "$ROOTFS/proc" \ + "$ROOTFS/sys" \ + "$ROOTFS/run" \ + "$ROOTFS/data" \ + "$ROOTFS/var" \ + "$ROOTFS/tmp" mount --bind /var/cache/apk "$ROOTFS/var/cache/apk" mount --bind /dev "$ROOTFS/dev" @@ -72,6 +80,8 @@ mount "${TMP_LOOP}p4" /mnt/data # Put the real /var onto the data partition cp -a "$ROOTFS/var" /mnt/data/ +mkdir -p /mnt/data/etc-overlay/work +mkdir -p /mnt/data/etc-overlay/upper # Copy rootfs to root partition, but exclude /var cp -a "$ROOTFS"/. /mnt/img-root/ @@ -79,9 +89,7 @@ rm -rf /mnt/img-root/var mkdir -p /mnt/img-root/var mkdir -p /mnt/img-root/boot -cp /build/Image.gz /mnt/img-root/boot/Image.gz cp /build/board.itb /mnt/img-root/boot/kernel.itb -cp /build/${DEVICE_TREE_TARGET}.dtb /mnt/img-root/boot/${DEVICE_TREE_TARGET}.dtb sync umount /mnt/img-root diff --git a/alpine/install-packages.sh b/alpine/install-packages.sh index 08c8630..c5a834e 100755 --- a/alpine/install-packages.sh +++ b/alpine/install-packages.sh @@ -5,11 +5,11 @@ cd /build echo "##################################################### Installing basic packages" apk add alpine-base \ openrc busybox-openrc bash nftables \ - lm-sensors lm-sensors-fancontrol lm-sensors-fancontrol-openrc + lm-sensors lm-sensors-fancontrol lm-sensors-fancontrol-openrc e2fsprogs # For diagnotics apk add \ - iproute2 iproute2-ss curl bind-tools procps strace tcpdump lsof jq \ + iproute2 iproute2-ss curl bind-tools procps strace tcpdump lsof jq binutils \ openssl nftables conntrack-tools ethtool findmnt kmod coreutils util-linux echo '[ -x /bin/bash ] && exec /bin/bash -l' >> "/root/.profile" diff --git a/alpine/rootfs-extra/etc/fstab b/alpine/rootfs-extra/etc/fstab index f590c2a..055fce5 100644 --- a/alpine/rootfs-extra/etc/fstab +++ b/alpine/rootfs-extra/etc/fstab @@ -1,3 +1,7 @@ -PARTLABEL=config /opt/monok8s/config vfat defaults,noatime 0 0 -PARTLABEL=data /data ext4 defaults,noatime 0 21 -/data/var /var none rbind,noatime 0 0 +PARTLABEL=config /opt/monok8s/config vfat defaults,noatime 0 0 +PARTLABEL=data /data ext4 rw,noatime,nodiratime 0 0 + +/data/var /var none rbind 0 0 + +tmpfs /run tmpfs defaults,nosuid,nodev,mode=0755 0 0 +tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec,mode=1777 0 0 diff --git a/alpine/rootfs-extra/etc/init.d/root.override b/alpine/rootfs-extra/etc/init.d/root.override new file mode 100755 index 0000000..385661e --- /dev/null +++ b/alpine/rootfs-extra/etc/init.d/root.override @@ -0,0 +1,16 @@ +#!/sbin/openrc-run + +description="Keep root filesystem read-only for immutable boot" + +depend() +{ + after clock + need fsck + keyword -docker -podman -jail -lxc -openvz -prefix -systemd-nspawn -vserver -wsl +} + +start() +{ + ebegin "Keeping root filesystem read-only" + eend 0 +} diff --git a/board.its b/board.its index 77bb2d3..9da0a4f 100644 --- a/board.its +++ b/board.its @@ -1,7 +1,7 @@ /dts-v1/; / { - description = "LS1046A-RDB FIT Image"; + description = "LS1046A-RDB-SDK FIT Image"; #address-cells = <1>; images { diff --git a/build.env b/build.env index 9f5bbb5..ca04aed 100644 --- a/build.env +++ b/build.env @@ -18,8 +18,9 @@ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -# Busybox for initramfs +# Tools for initramfs BUSYBOX_VERSION=1_36_1 +E2FSPROGS_VERSION=1.47.4 ## Alpine Linux ALPINE_VER=3.23.3 diff --git a/docker/initramfs.Dockerfile b/docker/initramfs.Dockerfile index db0cdc3..709519b 100644 --- a/docker/initramfs.Dockerfile +++ b/docker/initramfs.Dockerfile @@ -25,6 +25,23 @@ RUN make ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} defconfig \ RUN make CROSS_COMPILE=${CROSS_COMPILE} -j"$(nproc)" RUN make CROSS_COMPILE=${CROSS_COMPILE} CONFIG_PREFIX=/out/initramfs install +ARG E2FSPROGS_VERSION + +WORKDIR /build +COPY packages/e2fsprogs-v${E2FSPROGS_VERSION}.tar.gz ./ +RUN tar -xf e2fsprogs-v${E2FSPROGS_VERSION}.tar.gz && mv "e2fsprogs-${E2FSPROGS_VERSION}" e2fsprogs + +WORKDIR /build/e2fsprogs + +RUN ./configure \ + --host=aarch64-linux-gnu \ + --prefix=/usr +RUN make -j"$(nproc)" +RUN make DESTDIR=/out/initramfs install +RUN mkdir -p /out/initramfs/lib \ + && cp /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 /out/initramfs/lib/ \ + && cp /usr/aarch64-linux-gnu/lib/libc.so.6 /out/initramfs/lib/ + WORKDIR /build ARG BUILD_TAG diff --git a/docs/uboot.md b/docs/uboot.md index 8ec25f5..cdfcf4d 100644 --- a/docs/uboot.md +++ b/docs/uboot.md @@ -3,10 +3,9 @@ Booting release image with bootusb ``` setenv bootusb ' usb start; -setenv bootargs "console=ttyS0,115200 root=/dev/sda2 rw rootwait"; -ext4load usb 0:2 ${kernel_addr_r} /boot/Image.gz; -ext4load usb 0:2 ${fdt_addr_r} /boot/mono-gateway-dk-sdk.dtb; -booti ${kernel_addr_r} - ${fdt_addr_r} +setenv kernel_addr_r 0xa0000000; +ext4load usb 0:2 ${kernel_addr_r} /boot/kernel.itb; +bootm ${kernel_addr_r}; ' run bootusb diff --git a/initramfs/rootfs-extra/init b/initramfs/rootfs-extra/init index cc1495e..c5027de 100755 --- a/initramfs/rootfs-extra/init +++ b/initramfs/rootfs-extra/init @@ -1,24 +1,114 @@ #!/bin/sh +set -eu -mount -t devtmpfs devtmpfs /dev -mount -t proc proc /proc -mount -t sysfs sysfs /sys +log() { + echo "[init] $*" >&2 +} -# Spin the fan -echo 100 > /sys/class/hwmon/hwmon0/pwm1 +panic() { + echo "initramfs panic: $*" >&2 + exec sh +} + +mount_or_panic() { + mount "$@" || panic "mount failed: $*" +} + +mount_retry() { + dev="$1" + target="$2" + fstype="$3" + opts="$4" + + i=0 + while :; do + if mount -o "$opts" -t "$fstype" "$dev" "$target"; then + return 0 + fi + + i=$((i + 1)) + [ "$i" -ge 50 ] && panic "Timed out mounting $dev on $target" + sleep 0.2 + done +} + +wait_for_path() { + path="$1" + i=0 + while [ ! -e "$path" ]; do + i=$((i + 1)) + [ "$i" -ge 50 ] && panic "Timed out waiting for $path" + sleep 0.2 + done +} + +mkdir -p /dev /proc /sys /run +mount_or_panic -t devtmpfs devtmpfs /dev +mount_or_panic -t proc proc /proc +mount_or_panic -t sysfs sysfs /sys +mount_or_panic -t tmpfs tmpfs /run + +echo 1 > /proc/sys/kernel/printk -# Optional but nice mkdir -p /dev/pts -mount -t devpts devpts /dev/pts +mount_or_panic -t devpts devpts /dev/pts -echo "Booting kernel took $(cut -d' ' -f1 /proc/uptime) seconds." -echo "Dropping to shell on ttyS0..." +# Optional early fan kick. Do not fail boot if this path is not ready yet. +if [ -w /sys/class/hwmon/hwmon0/pwm1 ]; then + echo 100 > /sys/class/hwmon/hwmon0/pwm1 || true +fi -. /etc/build-info +log "Booting kernel took $(cut -d' ' -f1 /proc/uptime) seconds." -while true; do - setsid cttyhack /bin/sh - echo "Shell exited. Starting another one..." +. /etc/build-info || panic "failed to source /etc/build-info" + +ROOT_DEV="" +DATA_DEV="" + +for arg in $(cat /proc/cmdline); do + case "$arg" in + root=*) + ROOT_DEV="${arg#root=}" + ;; + data=*) + DATA_DEV="${arg#data=}" + ;; + esac done -exec poweroff -f +[ -n "$ROOT_DEV" ] || { + log "No root= specified in cmdline" + exec sh +} + +[ -n "$DATA_DEV" ] || { + log "No data= specified in cmdline" + exec sh +} + +wait_for_path "$DATA_DEV" + +e2fsck -p "$DATA_DEV" || { + echo "Auto fsck failed, forcing repair" + e2fsck -y "$DATA_DEV" || panic "fsck failed on $DATA_DEV" +} + +mkdir -p /newroot +mount_retry "$ROOT_DEV" /newroot ext4 ro +mount_retry "$DATA_DEV" /newroot/data ext4 rw + +mount_or_panic --bind /newroot/data/var /newroot/var + +mount_or_panic -t overlay overlay \ + -o lowerdir=/newroot/etc,upperdir=/newroot/data/etc-overlay/upper,workdir=/newroot/data/etc-overlay/work \ + /newroot/etc + +mount_or_panic --move /dev /newroot/dev +mount_or_panic --move /proc /newroot/proc +mount_or_panic --move /sys /newroot/sys +mount_or_panic --move /run /newroot/run + +log "Switching root to $ROOT_DEV" +exec switch_root /newroot /sbin/init + +panic "switch_root returned unexpectedly" diff --git a/makefile b/makefile index 2fa068c..1928b19 100644 --- a/makefile +++ b/makefile @@ -6,10 +6,11 @@ TAG ?= dev PACKAGES_DIR := packages OUT_DIR := out -BUSYBOX_TAR := $(PACKAGES_DIR)/busybox-$(BUSYBOX_VERSION).tar.gz -ALPINE_TAR := $(PACKAGES_DIR)/alpine-minirootfs-$(ALPINE_VER)-$(ALPINE_ARCH).tar.gz -NXP_TAR := $(PACKAGES_DIR)/$(NXP_VERSION).tar.gz -CRIO_TAR := $(PACKAGES_DIR)/$(CRIO_VERSION).tar.gz +E2FSPROGS_TAR := $(PACKAGES_DIR)/e2fsprogs-$(E2FSPROGS_VERSION).tar.gz +BUSYBOX_TAR := $(PACKAGES_DIR)/busybox-$(BUSYBOX_VERSION).tar.gz +ALPINE_TAR := $(PACKAGES_DIR)/alpine-minirootfs-$(ALPINE_VER)-$(ALPINE_ARCH).tar.gz +NXP_TAR := $(PACKAGES_DIR)/$(NXP_VERSION).tar.gz +CRIO_TAR := $(PACKAGES_DIR)/$(CRIO_VERSION).tar.gz # Kubernetes components KUBELET_BIN := $(PACKAGES_DIR)/kubernetes/kubelet @@ -62,6 +63,7 @@ KERNEL_DEPS := \ INITRAMFS_DEPS := \ $(KERNEL_IMAGE) \ $(BUSYBOX_TAR) \ + $(E2FSPROGS_TAR) \ docker/initramfs.Dockerfile \ $(INITRAMFS_SRCS) \ $(BUILD_INFO_FILE) \ @@ -111,6 +113,9 @@ $(KUBECTL_BIN): | $(PACKAGES_DIR) $(BUSYBOX_TAR): | $(PACKAGES_DIR) curl -L -o $@ "https://github.com/mirror/busybox/archive/refs/tags/$(BUSYBOX_VERSION).tar.gz" +$(E2FSPROGS_TAR): | $(PACKAGES_DIR) + curl -L -o $@ "https://github.com/tytso/e2fsprogs/archive/refs/tags/v$(E2FSPROGS_VERSION).tar.gz" + $(ALPINE_TAR): | $(PACKAGES_DIR) curl -L -o $@ "https://dl-cdn.alpinelinux.org/alpine/v$(ALPINE_SERIES)/releases/$(ALPINE_ARCH)/alpine-minirootfs-$(ALPINE_VER)-$(ALPINE_ARCH).tar.gz" @@ -158,6 +163,7 @@ $(INITRAMFS): $(INITRAMFS_DEPS) | $(OUT_DIR) --build-arg ARCH=$(ARCH) \ --build-arg CROSS_COMPILE=$(CROSS_COMPILE) \ --build-arg BUSYBOX_VERSION=$(BUSYBOX_VERSION) \ + --build-arg E2FSPROGS_VERSION=$(E2FSPROGS_VERSION) \ --build-arg BUILD_TAG=$(BUILD_TAG) \ --output type=local,dest=./$(OUT_DIR) . test -f $@