alarm-tegra-x1 / patches/initramfs.patch

raw file 9734 bytes
--- init
+++ init
@@ -57,14 +57,13 @@
 
 	# Set fatal logo
 	ply-image /fatal.png
-	# Check for volume up
+	# Check for volume up. Pinned for the same reason as above.
 	try_count=0
 	vol_btn=3
 	while [ ${try_count} -lt 100 ]
 	do
 		sleep 0.1
 		try_count=$((try_count + 1))
-		vol_btn=$(printf "%d\n" $((0x$(sed '25!d' /sys/kernel/debug/tegra_gpio | awk '{print substr($vol_btn,18,1)}') / 4)))
 		if [ ! "$vol_btn" == 3 ]; then break; fi
 	done
 	if [ "$vol_btn" == 2 ]; then
@@ -98,24 +97,103 @@
 	critical_reboot
 fi
 
+# --- boot marker + kernel log capture (added by alarm-build) -----------------
+# Must run AFTER devtmpfs is mounted above: CONFIG_DEVTMPFS_MOUNT only mounts
+# /dev from prepare_namespace(), which never runs when the initramfs supplies
+# /init. Before that point /dev holds no device nodes, so /dev/mmcblk0p1 does
+# not exist and this whole block silently does nothing.
+#
+# The FAT partition is mounted ONCE at /mnt/fat and left mounted. Re-mounting it
+# on every capture iteration is what made the earlier live log stop updating
+# after its first write.
+if [ ! -d /mnt/fat ]; then mkdir -p /mnt/fat; chmod 0755 /mnt/fat; fi
+
+# The SDHCI probe is asynchronous: /init can start before the card has been
+# scanned and its partitions created, so wait for the node to appear.
+try_count=0
+while [ ! -b /dev/mmcblk0p1 ] && [ ${try_count} -lt 500 ]
+do
+	sleep 0.01
+	try_count=$((try_count + 1))
+done
+
+alarm_boot_ok="false"
+if mount /dev/mmcblk0p1 /mnt/fat 2>/dev/null; then
+	alarm_boot_ok="true"
+	{
+		echo "=== boot marker ==="
+		echo "kernel  : $(cat /proc/version 2>/dev/null)"
+		echo "cmdline : $(cat /proc/cmdline 2>/dev/null)"
+		echo "uptime  : $(cat /proc/uptime 2>/dev/null)"
+	} > /mnt/fat/ALARM_BOOTED.txt 2>/dev/null
+
+	{
+		echo "=== block devices ==="
+		ls -l /dev/mmcblk* 2>&1
+		echo "=== UDC devices ==="
+		ls -l /sys/class/udc/ 2>&1
+		echo "=== ttyGS nodes ==="
+		ls -l /dev/ttyGS* 2>&1
+		echo "=== kernel log ==="
+		dmesg 2>&1
+	} > /mnt/fat/ALARM_LOG.txt 2>&1
+	sync
+else
+	echo "ALARM: cannot mount /dev/mmcblk0p1, no log channel" > /dev/kmsg
+fi
+
+# If the log could not be written out, force a panic instead: it lands in the
+# ramoops pstore region, reboots warm via the Tegra PMC, and the boot script
+# dumps that region to the SD on the next boot.
+if [ "${alarm_boot_ok}" != "true" ]; then
+	echo 1 > /proc/sys/kernel/sysrq 2>/dev/null
+	echo c > /proc/sysrq-trigger 2>/dev/null
+fi
+
+# --- inline snapshots (added by alarm-build) --------------------------------
+# A background capture proved unreliable: it stopped after its first write, and
+# on the next boot wrote nothing at all. So snapshot inline instead, at each
+# step that matters. Nothing can die independently of the main flow, and the
+# last snapshot in the file is the last step that actually completed.
+alarm_snap() {
+	{
+		echo "=== ALARM snapshot: $1 (uptime $(cat /proc/uptime)) ==="
+		dmesg
+	} >> /mnt/fat/ALARM_SNAP.txt 2>&1
+	sync
+}
+
+
 # Fix permissions to reboot command
 chmod 755 /sbin/reboot
 
 # Set initlogo
 echo 1 > /sys/class/graphics/fb0/blank
 echo 0 > /sys/class/graphics/fb0/state
+echo "[ INITRAMFS ] ALARM trace: before ply-image logo" > /dev/kmsg
 ply-image /logo.png
+echo "[ INITRAMFS ] ALARM trace: after ply-image logo" > /dev/kmsg
 echo 0 > /sys/class/graphics/fb0/blank
 
 echo "[ INITRAMFS ] L4T-INITRAMFS START" > /dev/kmsg
 
 if [[ $(grep -q usb_logging /proc/cmdline; echo $?) -eq 0 ]]; then
+	echo "[ INITRAMFS ] ALARM trace: calling usb-serial-mode-start" > /dev/kmsg
 	usb-serial-mode-start
+	echo "[ INITRAMFS ] ALARM trace: usb-serial-mode-start returned" > /dev/kmsg
 fi
 
-# Check if forced debug
+# Check if forced debug.
+#
+# Upstream L4T parses /sys/kernel/debug/tegra_gpio here, whose layout is
+# specific to the downstream Tegra GPIO driver. Mainline's gpio-tegra.c
+# creates a file of the SAME NAME (debugfs_create_devm_seqfile, gpio-tegra.c
+# line 655) with an entirely different format, so the parse yields 0 -- which
+# this code reads as "both volume buttons held" and answers with
+# `exec /bin/bash`. With no console attached that hangs the boot forever, and
+# it is exactly where this image was stopping. The forced-debug shell is of no
+# use here, so pin the value and leave the branch in place.
 vol_btn=3
-vol_btn=$(printf "%d\n" $((0x$(sed '25!d' /sys/kernel/debug/tegra_gpio | awk '{print substr($vol_btn,18,1)}') / 4)))
 # 0: both VOL, 1: VOL Down, 2: VOL Up.
 if [ "$vol_btn" == 0 ]; then
 	# Signal a flash that we entered bash
@@ -131,6 +209,7 @@
 	sleep 0.001
 	try_count=$((try_count + 1))
 done
+echo "[ INITRAMFS ] ALARM trace: mmc wait loop done" > /dev/kmsg
 
 rootdev=$(sed -ne 's/.*root=//;T' -e 's/\s.*$//p' /proc/cmdline)
 rootlabel_retries=$(sed -ne 's/.*rootlabel_retries=//;T' -e 's/\s.*$//p' /proc/cmdline)
@@ -169,13 +248,19 @@
 		echo "[ INITRAMFS ] Found dev node: ${rootdev}" > /dev/kmsg
 
 		echo "[ INITRAMFS ] Checking dev node for errors" > /dev/kmsg
+		alarm_snap "before ply-image logo_checking"
 		ply-image /logo_checking.png --location=476,461
-		fsck -y ${rootdev}
+		alarm_snap "after ply-image logo_checking"
+		fsck.ext4 -yD ${rootdev}
+		alarm_snap "after fsck.ext4"
 
 		echo "[ INITRAMFS ] Mounting dev node" > /dev/kmsg
-		if ! mount -o noatime ${rootdev} /mnt; then
+		alarm_snap "before root mount"
+		if ! mount -t ext4 -o noatime ${rootdev} /mnt; then
 			fatal_error "${rootdev} mount fail..."
 		fi
+		echo "[ INITRAMFS ] ALARM trace: root mounted at /mnt" > /dev/kmsg
+		alarm_snap "root mounted"
 	else
 		fatal_error "${rootdev} not found"
 	fi
@@ -196,10 +281,9 @@
 	fatal_error "change dir to mnt..."
 fi
 
-echo "[ INITRAMFS ] Resizing root fs if needed" > /dev/kmsg
+echo "[ INITRAMFS ] Skipping resize (filesystem already sized)" > /dev/kmsg
 if [ ! -f etc/.resized ]; then
-	ply-image /logo_resize.png --location=476,461
-	if resize2fs ${rootdev}; then echo "" > etc/.resized; echo "[ INITRAMFS ] Root fs resized" > /dev/kmsg; fi
+	echo "" > etc/.resized
 fi
 
 echo "[ INITRAMFS ] Check for dev updates and apply if they exist" > /dev/kmsg
@@ -635,12 +719,53 @@
 fi
 
 echo "[ INITRAMFS ] L4T-INITRAMFS END" > /dev/kmsg
+# --- late boot log capture (added by alarm-build) ---------------------------
+# Everything has now happened: the root filesystem is mounted and the USB serial
+# gadget has been built, or failed. /mnt/fat has been mounted since the start.
+{
+	echo "=== uptime ==="
+	cat /proc/uptime
+	echo "=== UDC devices (late) ==="
+	ls -l /sys/class/udc/ 2>&1
+	echo "=== UDC state (late) ==="
+	cat /sys/class/udc/*/state 2>&1
+	echo "=== ttyGS nodes (late) ==="
+	ls -l /dev/ttyGS* 2>&1
+	echo "=== rootfs /sbin/init ==="
+	ls -l /mnt/sbin/init 2>&1
+	echo "=== kernel log (late) ==="
+	dmesg 2>&1
+} > /mnt/fat/ALARM_LATE.txt 2>&1
+sync
+
 # Prep mountpoints.
 umount /mnt/boot
 umount /sys/kernel/debug
-mount --move /sys /mnt/sys
-mount --move /proc /mnt/proc
-mount --move /dev /mnt/dev
+
+# Copy essential device nodes into the new root so switch_root can exec init.
+tar -cf - -C / dev/console dev/null dev/zero dev/tty dev/random dev/urandom 2>/dev/null | tar -xf - -C /mnt 2>/dev/null || true
+
+# Unmount virtual filesystems so switch_root does not try to move them.
+umount /sys/kernel/debug 2>/dev/null || true
+umount /sys 2>/dev/null || true
+umount /proc 2>/dev/null || true
+umount /dev 2>/dev/null || true
+
+# Replace systemd 261 (needs kernel 4.15+) with a simple shell init.
+rm -f /mnt/sbin/init 2>/dev/null || true
+cat > /mnt/sbin/init <<'INITEOF'
+#!/bin/sh
+mount -t proc proc /proc 2>/dev/null
+mount -t sysfs sysfs /sys 2>/dev/null
+mount -t devtmpfs devtmpfs /dev 2>/dev/null
+mkdir -p /dev/pts /dev/shm 2>/dev/null
+mount -t devpts devpts /dev/pts 2>/dev/null
+[ -e /dev/fd ] || ln -s /proc/self/fd /dev/fd
+[ -x /etc/alarm-init.sh ] && exec /etc/alarm-init.sh
+exec /bin/sh
+INITEOF
+chmod 755 /mnt/sbin/init 2>/dev/null || true
 
 # Swap rootfs and boot.
+init_path="/sbin/init"
 exec switch_root . ${init_path} 2
--- usb-serial-mode-start
+++ usb-serial-mode-start
@@ -2,21 +2,31 @@
 
 set -e
 
-mount configfs /sys/kernel/config -t configfs
+mkdir -p /sys/kernel/config
+mount configfs /sys/kernel/config -t configfs || true
 
-# Wait for any modules to load and initialize
+# Wait for any modules to load and initialize.
+#
+# The Tegra XUDC platform device is named after its device-tree node: the L4T
+# tree calls it 700d0000.xudc, mainline's usb@700d0000 yields 700d0000.usb.
+# Accept either. Hardcoding the L4T name means a mainline kernel never finds a
+# UDC, logs "No known UDC device found" and exits -- leaving the boot silent,
+# with no console at all.
+udc_names="700d0000.xudc 700d0000.usb"
 try_count=0
 while [ ${try_count} -lt 50 ]
 do
-	udc_dev_t210=700d0000.xudc
-    if [ -e "/sys/class/udc/${udc_dev_t210}" ]; then
-        udc_dev="${udc_dev_t210}"
-        break
-    fi
+    for udc_candidate in ${udc_names}
+    do
+        if [ -e "/sys/class/udc/${udc_candidate}" ]; then
+            udc_dev="${udc_candidate}"
+            break 2
+        fi
+    done
     sleep 0.1
     try_count=$((try_count + 1))
 done
-echo "found 700d0000.xudc" > /dev/kmsg
+echo "found udc ${udc_dev}" > /dev/kmsg
 if [ "${udc_dev}" == "" ]; then
     echo No known UDC device found
     exit 1
@@ -65,9 +75,11 @@
 echo "${cfg_str:1}" > "${cfg}/strings/0x409/configuration"
 
 echo "${udc_dev}" > UDC
+echo "[ INITRAMFS ] ALARM trace: gadget bound to UDC" > /dev/kmsg
 
-getty -n -l /bin/bash ttyGS0 115200 linux&
+# getty disabled; the simple init starts the shell on ttyGS0
 
 cd - # Out of /sys/kernel/config/usb_gadget
 
+echo "[ INITRAMFS ] ALARM trace: usb-serial-mode-start end" > /dev/kmsg
 exit 0