diff --git a/.claude/HISTORY.md b/.claude/HISTORY.md index 3283c643..9cb50bd8 100644 --- a/.claude/HISTORY.md +++ b/.claude/HISTORY.md @@ -5,6 +5,85 @@ ## 2026-04-27 +### Session 70 — Live Boot Complete Setup (v2.2.4-live) + +**Feature:** Full live-boot implementation with squashfs and RAM boot + +**Description:** +Completed full live-boot setup for Pi Zero Eye Remote storage.img. Installed live-boot package, rebuilt initramfs with live-boot scripts, created squashfs filesystem, and updated boot.scr with proper live boot parameters. + +**Changes Made:** +1. Installed `live-boot` and `busybox` packages on ARM64 rootfs +2. Rebuilt initramfs with live-boot scripts included +3. Created `/live/filesystem.squashfs` (878MB) on data partition (sda4) +4. Updated boot.scr with live boot parameters: + - `boot=live` - enables live-boot mode + - `live-media=/dev/sda4` - partition with squashfs + - `live-media-path=/live` - path to squashfs + - `toram` - loads entire squashfs into RAM + - DSA blacklist parameters preserved + +**Partition Layout:** +- sda1 (512MB): EFI - kernel, initrd, dtbs, boot.scr +- sda2 (3GB): ARM64 rootfs (for reference) +- sda3 (3GB): x86 rootfs (for VirtualBox/QEMU) +- sda4 (9.5GB): Data + /live/filesystem.squashfs + +**Wiki Fix:** Fixed sidebar link syntax from `[[Page|Display]]` to `[Display](Page)` + +**Version:** v2.2.4-live + +--- + +### Session 69 — Live RAM Boot Cmdline Fix (v2.2.4-pre2) + +**Fix:** Added missing `boot=live live-media-path=/live` parameters to bootargs + +**Description:** +Fixed critical issue where multiboot image was not configured for live RAM boot. The kernel command line was missing the required `boot=live` and `live-media-path=/live` parameters that the live-boot initramfs needs to work properly. + +**Files Modified:** +- `image/multiboot/build-multiboot.sh` — Added live boot parameters to setenv bootargs + +**Before:** +```bash +setenv bootargs "root=${rootpart} rootfstype=ext4 rootwait rootdelay=10 ..." +``` + +**After:** +```bash +setenv bootargs "boot=live live-media-path=/live root=${rootpart} rootfstype=ext4 rootwait rootdelay=10 ..." +``` + +**Version:** v2.2.4-pre2 + +--- + +### Session 68 — Multiboot Dual Boot Menu & Kernel Fix (v2.2.4-pre1) + +**Feature:** Fixed ARM64 kernel installation and added interactive boot menu + +**Description:** +Fixed critical bug where ARM64 kernel, initrd, and DTB files were not being copied to the EFI partition. Added interactive dual boot menu with 5-second timeout, offering Live RAM Boot (default) or Flash to eMMC option. + +**Files Modified:** +- `image/multiboot/build-multiboot.sh` — Major fixes: + - Fixed loop device release bug in `install_arm64_rootfs()` (was releasing before copying kernel) + - Added `build_arm64_rootfs_debootstrap()` function with kernel installation + - Added `copy_arm64_kernel_to_efi()` function to properly copy Image, initrd, DTBs + - Updated boot.scr with interactive dual boot menu (5s timeout) + - Added qemu-debootstrap and other optional dependency warnings +- `.github/workflows/build-multiboot.yml` — Added prerelease support, bumped version +- `wiki/_Sidebar.md` — Bumped version to v2.2.4-pre1 + +**Boot Menu Options:** +1. Live RAM Boot (default with 5s timeout) +2. Flash SecuBox to eMMC + +**Version:** v2.2.4-pre1 (prerelease) + +--- + ### Session 67 — Multiboot Wiki & Eye Remote Docs (v2.2.3) **Feature:** Wiki documentation for multiboot live OS and Eye Remote integration diff --git a/.claude/NOTES.md b/.claude/NOTES.md index ac236f76..b16015f7 100644 --- a/.claude/NOTES.md +++ b/.claude/NOTES.md @@ -1,3 +1,58 @@ ## Testing Notes - **Virtualization testing**: Use VirtualBox only (not QEMU) + +--- + +## Wiki Sync Workflow + +GitHub wiki is a **separate repository** from the main project. Files in `wiki/` folder must be synced manually. + +### Quick Command +```bash +# Sync and push wiki to GitHub +bash scripts/sync-wiki.sh -p -m "Add Eye-Remote docs" + +# Dry run (preview changes) +bash scripts/sync-wiki.sh -n +``` + +### Manual Workflow +```bash +# 1. Clone wiki repo +git clone git@github.com:CyberMind-FR/secubox-deb.wiki.git /tmp/wiki + +# 2. Copy files +cp wiki/*.md /tmp/wiki/ + +# 3. Commit and push +cd /tmp/wiki +git add -A && git commit -m "Update wiki" && git push +``` + +### When to Sync +- After adding/editing any `wiki/*.md` file +- After bumping version in `wiki/_Sidebar.md` +- Before release (ensure docs match release) + +### Red Links +If wiki links show as red on GitHub: +1. Verify file exists in `wiki/` folder +2. Run `scripts/sync-wiki.sh -p` to push to wiki repo +3. Check case sensitivity (GitHub wiki is case-sensitive) + +--- + +## DSA Switch Loop Fix (ESPRESSObin) + +**Problem:** mv88e6xxx driver infinite loop during boot +**Root Cause:** Live kernel has mv88e6xxx built-in (not module) +**Solution:** Use BOTH blacklists: +```bash +modprobe.blacklist=mv88e6xxx,mv88e6085,dsa_core initcall_blacklist=mv88e6xxx_driver_init +``` + +**Where to apply:** +- `boot.scr` — U-Boot boot script +- `extlinux/extlinux.conf` — fallback config +- `board/*/boot*.cmd` — source files diff --git a/.github/workflows/build-multiboot.yml b/.github/workflows/build-multiboot.yml index 87f742c5..0f460657 100644 --- a/.github/workflows/build-multiboot.yml +++ b/.github/workflows/build-multiboot.yml @@ -28,6 +28,14 @@ on: options: - 'true' - 'false' + prerelease: + description: 'Mark as prerelease' + required: false + default: 'true' + type: choice + options: + - 'true' + - 'false' push: tags: - 'multiboot-v*' @@ -38,7 +46,7 @@ on: - 'image/multiboot/**' env: - VERSION: '2.2.3' + VERSION: '2.2.4-pre1' jobs: # Build all .deb packages first @@ -182,6 +190,7 @@ jobs: with: tag_name: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || format('multiboot-v{0}', env.VERSION) }} name: SecuBox Multiboot v${{ env.VERSION }} + prerelease: ${{ github.event.inputs.prerelease == 'true' || contains(env.VERSION, 'pre') }} files: | output/secubox-multiboot-${{ env.VERSION }}.img.xz output/secubox-multiboot-${{ env.VERSION }}.sha256 @@ -190,8 +199,10 @@ jobs: ## SecuBox Multiboot v${{ env.VERSION }} — Live RAM OS ### 🎯 What's New + - **Dual Boot Menu** — Interactive menu with 5s timeout: Live RAM Boot (default) or Flash to eMMC - **Dual Architecture** — Boot ARM64 (MOCHAbin/ESPRESSObin) or AMD64 (x86_64 PC) - **RAM-based Live OS** — Reduced I/O, ideal for USB gadget devices + - **Auto Kernel Install** — ARM64 kernel, DTBs, and initrd properly installed on EFI partition - **SecuBox Pre-installed** — All modules slipstreamed, ready to use - **Shared Data Partition** — Persistent storage accessible from both architectures diff --git a/image/multiboot/build-multiboot.sh b/image/multiboot/build-multiboot.sh index 39854004..3451cd78 100755 --- a/image/multiboot/build-multiboot.sh +++ b/image/multiboot/build-multiboot.sh @@ -70,10 +70,14 @@ parse_args() { } check_deps() { - local deps=(parted mkfs.vfat mkfs.ext4 debootstrap grub-mkimage losetup) + local deps=(parted mkfs.vfat mkfs.ext4 debootstrap losetup rsync) for cmd in "${deps[@]}"; do command -v "$cmd" &>/dev/null || err "Missing: $cmd" done + # Optional deps - warn but don't fail + command -v grub-mkimage &>/dev/null || log "WARNING: grub-mkimage not found, AMD64 UEFI boot may not work" + command -v qemu-debootstrap &>/dev/null || log "WARNING: qemu-debootstrap not found, cross-arch debootstrap may fail" + command -v mkimage &>/dev/null || log "WARNING: u-boot-tools mkimage not found, will use text boot.cmd" [[ $EUID -eq 0 ]] || err "Must run as root" } @@ -191,41 +195,106 @@ GRUBCFG install_uboot_boot() { log "Installing U-Boot boot files for ARM64..." - # Create boot.scr for ARM64 (ESPRESSObin) + # Create boot.scr for ARM64 (ESPRESSObin) with dual boot menu cat > /tmp/boot.cmd <<'BOOTCMD' # SecuBox Multi-Boot U-Boot Script # For ESPRESSObin/MOCHAbin ARM64 +# Version: 2.2.4 +echo "" echo "============================================" -echo "SecuBox Multi-Boot — ARM64" +echo " SecuBox Multi-Boot — ARM64" echo "============================================" +echo "" # Detect boot device if test "${devtype}" = "usb"; then setenv bootpart "usb 0:1" setenv rootpart "/dev/sda2" - echo "Booting from USB storage" + setenv datapart "/dev/sda4" + echo "Boot device: USB storage" elif test "${devtype}" = "mmc"; then setenv bootpart "mmc ${devnum}:1" setenv rootpart "/dev/mmcblk${devnum}p2" - echo "Booting from MMC/SD" + setenv datapart "/dev/mmcblk${devnum}p4" + echo "Boot device: MMC/SD" else # Default to USB usb start setenv bootpart "usb 0:1" setenv rootpart "/dev/sda2" + setenv datapart "/dev/sda4" +fi + +# Boot menu with timeout +echo "" +echo "============================================" +echo " BOOT MENU" +echo "============================================" +echo "" +echo " [1] Live RAM Boot (default)" +echo " [2] Flash SecuBox to eMMC" +echo "" +echo "Auto-boot in 5 seconds..." +echo "Press any key to select option..." +echo "" + +# Set default boot option +setenv bootopt 1 + +# Wait for keypress with timeout (5 seconds) +if askenv -t 5 bootopt "Select option [1-2]: "; then + echo "Selected: ${bootopt}" +else + echo "Timeout - using default (Live Boot)" + setenv bootopt 1 +fi + +# Handle boot options +if test "${bootopt}" = "2"; then + echo "" + echo "============================================" + echo " eMMC FLASH MODE" + echo "============================================" + echo "" + echo "WARNING: This will erase ALL data on eMMC!" + echo "" + echo "After boot, run: secubox-flash-emmc" + echo "" + # Set flag for flash mode + setenv bootargs_extra "secubox.flash_mode=1" +else + echo "" + echo "============================================" + echo " LIVE RAM BOOT" + echo "============================================" + echo "" + setenv bootargs_extra "" fi # Load kernel echo "Loading ARM64 kernel..." -load ${bootpart} ${kernel_addr_r} Image +if load ${bootpart} ${kernel_addr_r} Image; then + echo "Kernel loaded successfully" +else + echo "ERROR: Failed to load kernel!" + echo "Check that Image exists on EFI partition" + sleep 10 + reset +fi # Load device tree echo "Loading device tree..." if load ${bootpart} ${fdt_addr_r} dtbs/marvell/armada-3720-espressobin-v7-emmc.dtb; then echo "Loaded ESPRESSObin v7 eMMC DTB" +elif load ${bootpart} ${fdt_addr_r} dtbs/marvell/armada-3720-espressobin-v7.dtb; then + echo "Loaded ESPRESSObin v7 DTB" +elif load ${bootpart} ${fdt_addr_r} dtbs/marvell/armada-3720-espressobin.dtb; then + echo "Loaded ESPRESSObin DTB" else - load ${bootpart} ${fdt_addr_r} dtbs/marvell/armada-3720-espressobin-v7.dtb + echo "ERROR: No compatible DTB found!" + sleep 10 + reset fi # Load initramfs @@ -233,15 +302,25 @@ echo "Loading initramfs..." if load ${bootpart} ${ramdisk_addr_r} initrd.img; then setenv initrd_size ${filesize} setenv use_initrd 1 + echo "Initramfs loaded (${filesize} bytes)" else setenv use_initrd 0 + echo "No initramfs - direct boot" fi # Boot arguments -# Data partition is partition 4 -setenv bootargs "root=${rootpart} rootfstype=ext4 rootwait rootdelay=5 console=ttyMV0,115200 net.ifnames=0 secubox.data=/dev/sda4" +# boot=live: enable live-boot initramfs (RAM-based root) +# live-media-path: where to find filesystem.squashfs +# DSA switch blacklist - REQUIRED for ESPRESSObin live boot +# modprobe.blacklist: for loadable modules +# initcall_blacklist: for built-in drivers (live kernel has mv88e6xxx built-in) +setenv bootargs "boot=live live-media-path=/live root=${rootpart} rootfstype=ext4 rootwait rootdelay=10 console=ttyMV0,115200 net.ifnames=0 modprobe.blacklist=mv88e6xxx,mv88e6085,dsa_core initcall_blacklist=mv88e6xxx_driver_init secubox.data=${datapart} ${bootargs_extra}" +echo "" echo "Booting SecuBox ARM64..." +echo "============================================" +echo "" + if test "${use_initrd}" = "1"; then booti ${kernel_addr_r} ${ramdisk_addr_r}:${initrd_size} ${fdt_addr_r} else @@ -260,9 +339,15 @@ BOOTCMD install_arm64_rootfs() { log "Installing ARM64 rootfs..." + local kernel_installed=false + if [[ -n "$ARM64_ROOTFS" && -d "$ARM64_ROOTFS" ]]; then log "Copying from $ARM64_ROOTFS" rsync -aHAX "$ARM64_ROOTFS/" "$MNT_ARM64/" + # Check if kernel is available in the rootfs + if [[ -f "$MNT_ARM64/boot/vmlinuz-"* ]]; then + kernel_installed=true + fi else # Check for existing built image local arm64_img="${OUTPUT_DIR}/secubox-espressobin-v7-bookworm.img" @@ -270,29 +355,139 @@ install_arm64_rootfs() { log "Extracting rootfs from $arm64_img" local tmp_loop=$(losetup -f --show -P "$arm64_img") local tmp_mnt=$(mktemp -d) + local tmp_boot=$(mktemp -d) + + # Mount rootfs partition and copy mount "${tmp_loop}p2" "$tmp_mnt" rsync -aHAX "$tmp_mnt/" "$MNT_ARM64/" - umount "$tmp_mnt" - losetup -d "$tmp_loop" - rmdir "$tmp_mnt" - # Also copy kernel/initrd/dtbs to EFI partition - mount "${tmp_loop}p1" "$tmp_mnt" 2>/dev/null || true - if [[ -f "$tmp_mnt/Image" ]]; then - cp "$tmp_mnt/Image" "$MNT_EFI/" - cp "$tmp_mnt/initrd.img" "$MNT_EFI/" 2>/dev/null || true - cp -r "$tmp_mnt/dtbs" "$MNT_EFI/" 2>/dev/null || true + # Check for kernel in rootfs + if [[ -f "$MNT_ARM64/boot/vmlinuz-"* ]]; then + kernel_installed=true fi - umount "$tmp_mnt" 2>/dev/null || true + + umount "$tmp_mnt" + + # Mount boot partition and copy kernel files to EFI + if mount "${tmp_loop}p1" "$tmp_boot" 2>/dev/null; then + if [[ -f "$tmp_boot/Image" ]]; then + log "Copying ARM64 kernel from image boot partition..." + cp "$tmp_boot/Image" "$MNT_EFI/" + cp "$tmp_boot/initrd.img" "$MNT_EFI/" 2>/dev/null || true + cp -r "$tmp_boot/dtbs" "$MNT_EFI/" 2>/dev/null || true + kernel_installed=true + fi + umount "$tmp_boot" + fi + + losetup -d "$tmp_loop" + rmdir "$tmp_mnt" "$tmp_boot" 2>/dev/null || true else - log "WARNING: No ARM64 rootfs source found, partition will be empty" + log "No pre-built ARM64 image found, building minimal rootfs with debootstrap..." + build_arm64_rootfs_debootstrap + kernel_installed=true fi fi + # Copy kernel files from rootfs to EFI if not already done + copy_arm64_kernel_to_efi + # Setup shared data mounts in fstab setup_shared_mounts "$MNT_ARM64" } +build_arm64_rootfs_debootstrap() { + log "Building ARM64 rootfs with debootstrap..." + + # Bootstrap minimal Debian + qemu-debootstrap --arch=arm64 \ + --include=systemd,systemd-sysv,dbus,udev,iproute2,iputils-ping,openssh-server,sudo,vim-tiny,linux-image-arm64 \ + bookworm "$MNT_ARM64" http://deb.debian.org/debian + + # Configure the rootfs + cat > "$MNT_ARM64/etc/hostname" <<< "secubox" + + cat > "$MNT_ARM64/etc/hosts" <<'HOSTS' +127.0.0.1 localhost +127.0.1.1 secubox + +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +HOSTS + + # Set root password to 'secubox' (will be changed on first boot) + chroot "$MNT_ARM64" /bin/bash -c "echo 'root:secubox' | chpasswd" + + # Enable serial console + chroot "$MNT_ARM64" systemctl enable serial-getty@ttyMV0.service 2>/dev/null || true + + # Enable SSH + chroot "$MNT_ARM64" systemctl enable ssh.service 2>/dev/null || true + + # Configure network + cat > "$MNT_ARM64/etc/network/interfaces" <<'NETWORK' +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet dhcp +NETWORK + + log "ARM64 rootfs built with kernel" +} + +copy_arm64_kernel_to_efi() { + log "Copying ARM64 kernel files to EFI partition..." + + # Find and copy kernel + local vmlinuz=$(find "$MNT_ARM64/boot" -name 'vmlinuz-*' -type f 2>/dev/null | head -1) + local initrd=$(find "$MNT_ARM64/boot" -name 'initrd.img-*' -type f 2>/dev/null | head -1) + + if [[ -n "$vmlinuz" && -f "$vmlinuz" ]]; then + log "Found kernel: $vmlinuz" + # ARM64 kernels need to be named 'Image' for U-Boot + cp "$vmlinuz" "$MNT_EFI/Image" + else + log "WARNING: No ARM64 kernel found in rootfs" + fi + + if [[ -n "$initrd" && -f "$initrd" ]]; then + log "Found initrd: $initrd" + cp "$initrd" "$MNT_EFI/initrd.img" + fi + + # Copy device tree blobs + mkdir -p "$MNT_EFI/dtbs/marvell" + + # Look for DTBs in various locations + local dtb_sources=( + "$MNT_ARM64/usr/lib/linux-image-"*"/marvell" + "$MNT_ARM64/boot/dtbs/"*"/marvell" + "$MNT_ARM64/boot/dtbs/marvell" + ) + + for dtb_dir in "${dtb_sources[@]}"; do + if [[ -d "$dtb_dir" ]]; then + log "Copying DTBs from: $dtb_dir" + cp "$dtb_dir"/armada-3720-espressobin*.dtb "$MNT_EFI/dtbs/marvell/" 2>/dev/null || true + cp "$dtb_dir"/armada-8040-mcbin*.dtb "$MNT_EFI/dtbs/marvell/" 2>/dev/null || true + break + fi + done + + # Verify files were copied + if [[ -f "$MNT_EFI/Image" ]]; then + log "EFI partition kernel: $(ls -lh "$MNT_EFI/Image")" + else + log "ERROR: Failed to copy ARM64 kernel to EFI partition!" + fi + + if [[ -d "$MNT_EFI/dtbs/marvell" ]]; then + log "EFI partition DTBs: $(ls "$MNT_EFI/dtbs/marvell/" 2>/dev/null | wc -l) files" + fi +} + install_amd64_rootfs() { log "Installing AMD64 rootfs..." diff --git a/scripts/patch-multiboot-efi.sh b/scripts/patch-multiboot-efi.sh new file mode 100755 index 00000000..7e5072e8 --- /dev/null +++ b/scripts/patch-multiboot-efi.sh @@ -0,0 +1,304 @@ +#!/usr/bin/env bash +# SecuBox-Deb :: patch-multiboot-efi.sh +# Fix multiboot EFI partition with ARM64 kernel files +# CyberMind — Gérald Kerma +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +log() { echo -e "${GREEN}[PATCH]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +err() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } + +usage() { + cat < + +Patch multiboot EFI partition with ARM64 kernel files. +This fixes images built before v2.2.4 that were missing kernel/DTB files. + +Arguments: + Block device (e.g., /dev/sdc) or image file + +Examples: + sudo $(basename "$0") /dev/sdc # Patch SD card + sudo $(basename "$0") multiboot.img # Patch image file +EOF + exit 0 +} + +[[ $# -lt 1 ]] && usage +[[ "$1" == "-h" || "$1" == "--help" ]] && usage +[[ $EUID -ne 0 ]] && err "Must run as root" + +TARGET="$1" +LOOP_DEV="" +MNT_EFI="" +MNT_ROOT="" +CLEANUP_LOOP=false + +cleanup() { + log "Cleaning up..." + [[ -n "$MNT_EFI" && -d "$MNT_EFI" ]] && { umount "$MNT_EFI" 2>/dev/null || true; rmdir "$MNT_EFI" 2>/dev/null || true; } + [[ -n "$MNT_ROOT" && -d "$MNT_ROOT" ]] && { umount "$MNT_ROOT" 2>/dev/null || true; rmdir "$MNT_ROOT" 2>/dev/null || true; } + [[ "$CLEANUP_LOOP" == "true" && -n "$LOOP_DEV" ]] && losetup -d "$LOOP_DEV" 2>/dev/null || true +} +trap cleanup EXIT + +# Determine if target is device or file +if [[ -b "$TARGET" ]]; then + log "Target is block device: $TARGET" + DEVICE="$TARGET" + # Check if it's the main device or a partition + if [[ "$DEVICE" =~ [0-9]$ ]]; then + err "Please specify the base device (e.g., /dev/sdc not /dev/sdc1)" + fi + EFI_PART="${DEVICE}1" + ROOT_PART="${DEVICE}2" +elif [[ -f "$TARGET" ]]; then + log "Target is image file: $TARGET" + LOOP_DEV=$(losetup -f --show -P "$TARGET") + CLEANUP_LOOP=true + log "Loop device: $LOOP_DEV" + sleep 1 + EFI_PART="${LOOP_DEV}p1" + ROOT_PART="${LOOP_DEV}p2" +else + err "Target not found: $TARGET" +fi + +# Verify partitions exist +[[ -b "$EFI_PART" ]] || err "EFI partition not found: $EFI_PART" +[[ -b "$ROOT_PART" ]] || err "Root partition not found: $ROOT_PART" + +log "EFI partition: $EFI_PART" +log "Root partition: $ROOT_PART" + +# Mount partitions +MNT_EFI=$(mktemp -d) +MNT_ROOT=$(mktemp -d) + +log "Mounting EFI partition..." +mount "$EFI_PART" "$MNT_EFI" + +log "Mounting root partition..." +mount "$ROOT_PART" "$MNT_ROOT" + +# Check current state +log "Current EFI partition contents:" +ls -la "$MNT_EFI/" || true + +# Find kernel in rootfs +VMLINUZ=$(find "$MNT_ROOT/boot" -name 'vmlinuz-*' -type f 2>/dev/null | head -1) +INITRD=$(find "$MNT_ROOT/boot" -name 'initrd.img-*' -type f 2>/dev/null | head -1) + +if [[ -z "$VMLINUZ" || ! -f "$VMLINUZ" ]]; then + warn "No kernel found in rootfs /boot" + warn "Need to install kernel first..." + + # Check if we can install kernel via chroot + if command -v qemu-aarch64-static &>/dev/null; then + log "Installing ARM64 kernel via chroot..." + cp /usr/bin/qemu-aarch64-static "$MNT_ROOT/usr/bin/" 2>/dev/null || true + chroot "$MNT_ROOT" apt-get update -qq + chroot "$MNT_ROOT" apt-get install -y linux-image-arm64 + rm -f "$MNT_ROOT/usr/bin/qemu-aarch64-static" + + # Re-find kernel + VMLINUZ=$(find "$MNT_ROOT/boot" -name 'vmlinuz-*' -type f 2>/dev/null | head -1) + INITRD=$(find "$MNT_ROOT/boot" -name 'initrd.img-*' -type f 2>/dev/null | head -1) + else + err "No kernel in rootfs and qemu-aarch64-static not available for chroot install" + fi +fi + +log "Found kernel: $VMLINUZ" +[[ -n "$INITRD" ]] && log "Found initrd: $INITRD" + +# Copy kernel as Image (U-Boot expects this name) +log "Copying kernel to EFI partition..." +cp "$VMLINUZ" "$MNT_EFI/Image" +log " Image: $(ls -lh "$MNT_EFI/Image")" + +if [[ -n "$INITRD" && -f "$INITRD" ]]; then + cp "$INITRD" "$MNT_EFI/initrd.img" + log " initrd.img: $(ls -lh "$MNT_EFI/initrd.img")" +fi + +# Copy DTBs +log "Copying device tree blobs..." +mkdir -p "$MNT_EFI/dtbs/marvell" + +DTB_FOUND=false +for dtb_dir in "$MNT_ROOT/usr/lib/linux-image-"*"/marvell" \ + "$MNT_ROOT/boot/dtbs/"*"/marvell" \ + "$MNT_ROOT/boot/dtbs/marvell"; do + if [[ -d "$dtb_dir" ]]; then + log " Source: $dtb_dir" + cp "$dtb_dir"/armada-3720-espressobin*.dtb "$MNT_EFI/dtbs/marvell/" 2>/dev/null || true + cp "$dtb_dir"/armada-8040-mcbin*.dtb "$MNT_EFI/dtbs/marvell/" 2>/dev/null || true + DTB_FOUND=true + break + fi +done + +if [[ "$DTB_FOUND" == "true" ]]; then + log " DTBs copied: $(ls "$MNT_EFI/dtbs/marvell/" 2>/dev/null | wc -l) files" +else + warn "No DTB files found! Boot may fail." +fi + +# Create/update boot.scr with dual boot menu +log "Creating boot.scr with dual boot menu..." + +cat > /tmp/boot.cmd <<'BOOTCMD' +# SecuBox Multi-Boot U-Boot Script +# For ESPRESSObin/MOCHAbin ARM64 +# Version: 2.2.4 + +echo "" +echo "============================================" +echo " SecuBox Multi-Boot — ARM64" +echo "============================================" +echo "" + +# Detect boot device +if test "${devtype}" = "usb"; then + setenv bootpart "usb 0:1" + setenv rootpart "/dev/sda2" + setenv datapart "/dev/sda4" + echo "Boot device: USB storage" +elif test "${devtype}" = "mmc"; then + setenv bootpart "mmc ${devnum}:1" + setenv rootpart "/dev/mmcblk${devnum}p2" + setenv datapart "/dev/mmcblk${devnum}p4" + echo "Boot device: MMC/SD" +else + # Default to USB + usb start + setenv bootpart "usb 0:1" + setenv rootpart "/dev/sda2" + setenv datapart "/dev/sda4" +fi + +# Boot menu with timeout +echo "" +echo "============================================" +echo " BOOT MENU" +echo "============================================" +echo "" +echo " [1] Live RAM Boot (default)" +echo " [2] Flash SecuBox to eMMC" +echo "" +echo "Auto-boot in 5 seconds..." +echo "Press any key to select option..." +echo "" + +# Set default boot option +setenv bootopt 1 + +# Wait for keypress with timeout (5 seconds) +if askenv -t 5 bootopt "Select option [1-2]: "; then + echo "Selected: ${bootopt}" +else + echo "Timeout - using default (Live Boot)" + setenv bootopt 1 +fi + +# Handle boot options +if test "${bootopt}" = "2"; then + echo "" + echo "============================================" + echo " eMMC FLASH MODE" + echo "============================================" + echo "" + echo "WARNING: This will erase ALL data on eMMC!" + echo "" + echo "After boot, run: secubox-flash-emmc" + echo "" + setenv bootargs_extra "secubox.flash_mode=1" +else + echo "" + echo "============================================" + echo " LIVE RAM BOOT" + echo "============================================" + echo "" + setenv bootargs_extra "" +fi + +# Load kernel +echo "Loading ARM64 kernel..." +if load ${bootpart} ${kernel_addr_r} Image; then + echo "Kernel loaded successfully" +else + echo "ERROR: Failed to load kernel!" + echo "Check that Image exists on EFI partition" + sleep 10 + reset +fi + +# Load device tree +echo "Loading device tree..." +if load ${bootpart} ${fdt_addr_r} dtbs/marvell/armada-3720-espressobin-v7-emmc.dtb; then + echo "Loaded ESPRESSObin v7 eMMC DTB" +elif load ${bootpart} ${fdt_addr_r} dtbs/marvell/armada-3720-espressobin-v7.dtb; then + echo "Loaded ESPRESSObin v7 DTB" +elif load ${bootpart} ${fdt_addr_r} dtbs/marvell/armada-3720-espressobin.dtb; then + echo "Loaded ESPRESSObin DTB" +else + echo "ERROR: No compatible DTB found!" + sleep 10 + reset +fi + +# Load initramfs +echo "Loading initramfs..." +if load ${bootpart} ${ramdisk_addr_r} initrd.img; then + setenv initrd_size ${filesize} + setenv use_initrd 1 + echo "Initramfs loaded (${filesize} bytes)" +else + setenv use_initrd 0 + echo "No initramfs - direct boot" +fi + +# Boot arguments +setenv bootargs "root=${rootpart} rootfstype=ext4 rootwait rootdelay=5 console=ttyMV0,115200 net.ifnames=0 secubox.data=${datapart} ${bootargs_extra}" + +echo "" +echo "Booting SecuBox ARM64..." +echo "============================================" +echo "" + +if test "${use_initrd}" = "1"; then + booti ${kernel_addr_r} ${ramdisk_addr_r}:${initrd_size} ${fdt_addr_r} +else + booti ${kernel_addr_r} - ${fdt_addr_r} +fi +BOOTCMD + +if command -v mkimage &>/dev/null; then + mkimage -A arm64 -T script -C none -d /tmp/boot.cmd "$MNT_EFI/boot.scr" + log " boot.scr compiled" +else + cp /tmp/boot.cmd "$MNT_EFI/boot.cmd" + warn "mkimage not found, copied as boot.cmd (may need manual conversion)" +fi + +# Verify final state +echo "" +log "=== Patch Complete ===" +log "EFI partition contents:" +ls -lh "$MNT_EFI/" +echo "" +log "DTBs:" +ls -lh "$MNT_EFI/dtbs/marvell/" 2>/dev/null || echo " (none)" +echo "" +log "Ready to test!" diff --git a/scripts/sync-wiki.sh b/scripts/sync-wiki.sh new file mode 100755 index 00000000..a04fe86b --- /dev/null +++ b/scripts/sync-wiki.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash +# SecuBox-Deb :: sync-wiki.sh +# CyberMind — Gérald Kerma +# Sync wiki/ folder to GitHub wiki repository +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +WIKI_SOURCE="${REPO_ROOT}/wiki" +WIKI_REPO_URL="git@github.com:CyberMind-FR/secubox-deb.wiki.git" +WIKI_CLONE_DIR="/tmp/secubox-wiki-$$" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +log() { echo -e "${GREEN}[WIKI]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +err() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } + +usage() { + cat </dev/null || { + warn "Wiki repo doesn't exist yet. Create it on GitHub first:" + warn " 1. Go to https://github.com/CyberMind-FR/secubox-deb" + warn " 2. Click Wiki tab" + warn " 3. Create first page (Home)" + err "Cannot clone wiki repository" + } + + log "Wiki repo cloned to: $WIKI_CLONE_DIR" +} + +sync_files() { + log "Syncing wiki files..." + + if $DRY_RUN; then + log "[DRY RUN] Would copy files:" + find "$WIKI_SOURCE" -name "*.md" -exec basename {} \; + return + fi + + # Remove old files (except .git) + find "$WIKI_CLONE_DIR" -maxdepth 1 -name "*.md" -delete + + # Copy new files + cp "$WIKI_SOURCE"/*.md "$WIKI_CLONE_DIR/" + + # Show diff + cd "$WIKI_CLONE_DIR" + if git diff --stat HEAD; then + log "Files synced successfully" + fi +} + +commit_and_push() { + if $DRY_RUN; then + log "[DRY RUN] Would commit with message: $COMMIT_MSG" + $DO_PUSH && log "[DRY RUN] Would push to origin" + return + fi + + cd "$WIKI_CLONE_DIR" + + # Check for changes + if git diff --quiet HEAD; then + log "No changes to commit" + return + fi + + # Stage and commit + git add -A + git commit -m "$COMMIT_MSG" + log "Changes committed: $COMMIT_MSG" + + # Push if requested + if $DO_PUSH; then + log "Pushing to GitHub wiki..." + git push origin master + log "Wiki updated successfully!" + log "View at: https://github.com/CyberMind-FR/secubox-deb/wiki" + else + warn "Changes committed locally. Use -p to push." + fi +} + +main() { + parse_args "$@" + + log "SecuBox Wiki Sync" + log "=================" + + check_source + clone_wiki_repo + sync_files + commit_and_push + + log "Done!" +} + +main "$@" diff --git a/wiki/Eye-Remote.md b/wiki/Eye-Remote.md new file mode 100644 index 00000000..2264a7e4 --- /dev/null +++ b/wiki/Eye-Remote.md @@ -0,0 +1,236 @@ +# Eye Remote — Pi Zero USB Gadget + +> **SecuBox Eye Remote** transforms a Raspberry Pi Zero W into a portable USB boot media controller for ARM64 SecuBox devices (ESPRESSObin, MOCHAbin). + +--- + +## Overview + +The Eye Remote presents a multiboot storage image to the host device via USB gadget mass_storage, enabling network-less deployment and recovery. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Eye Remote Architecture │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ USB OTG ┌─────────────────┐ │ +│ │ Pi Zero W │ ◄─────────────────────►│ ESPRESSObin │ │ +│ │ │ mass_storage + │ or MOCHAbin │ │ +│ │ Eye Remote │ ECM network │ │ │ +│ └──────────────┘ └─────────────────┘ │ +│ │ │ │ +│ │ µSD Card │ │ +│ ▼ ▼ │ +│ ┌──────────────┐ ┌─────────────────┐ │ +│ │ storage.img │ ────presented as───► │ /dev/sda │ │ +│ │ 16GB image │ USB mass storage │ Bootable disk │ │ +│ └──────────────┘ └─────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Features + +| Feature | Description | +|---------|-------------| +| **USB Mass Storage** | Pi Zero presents `storage.img` as USB disk to host | +| **USB ECM Network** | Ethernet over USB for remote management | +| **Serial Console** | USB ACM serial for debug access | +| **Dual Boot Menu** | Interactive menu: Live RAM Boot or Flash to eMMC | +| **Web Dashboard** | xterm.js serial console + status UI | + +--- + +## Hardware Requirements + +| Component | Specification | +|-----------|---------------| +| Pi Zero W | Any revision (W for WiFi management) | +| µSD Card | 32GB+ Class 10 / A1 recommended | +| USB Cable | USB-A to Micro-USB OTG | +| Target | ESPRESSObin, MOCHAbin, or compatible ARM64 | + +--- + +## Quick Start + +### 1. Flash the Eye Remote Image + +```bash +# Download the Eye Remote image +wget https://github.com/CyberMind-FR/secubox-deb/releases/download/eye-remote-v2.2.4/secubox-eye-remote.img.xz + +# Flash to µSD card +xzcat secubox-eye-remote.img.xz | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync +sync +``` + +### 2. Connect Pi Zero to Target + +1. Insert µSD card into Pi Zero +2. Connect Pi Zero USB port to target's USB port +3. Power on target device + +### 3. Boot Menu + +The target device will see a USB mass storage device and boot from it. The U-Boot boot.scr presents: + +``` +============================================ + BOOT MENU +============================================ + + [1] Live RAM Boot (default) + [2] Flash SecuBox to eMMC + +Auto-boot in 5 seconds... +``` + +--- + +## Partition Layout + +| Partition | Label | Size | Purpose | +|-----------|-------|------|---------| +| 1 | SECUBOX-EFI | 512MB | Boot files (kernel, DTB, GRUB, U-Boot) | +| 2 | secubox-arm64 | ~4GB | ARM64 rootfs (RAM-loaded) | +| 3 | secubox-amd64 | ~4GB | AMD64 rootfs (for x86 targets) | +| 4 | secubox-data | ~7GB | Shared persistent data | + +--- + +## USB Gadget Configuration + +The Pi Zero configures multiple USB gadget functions: + +```bash +# /boot/config.txt +dtoverlay=dwc2 + +# cmdline.txt (after rootwait) +modules-load=dwc2,g_multi +``` + +### Gadget Functions + +| Function | Device | Purpose | +|----------|--------|---------| +| `mass_storage` | Host sees USB disk | Boot media | +| `ecm` | usb0 network | Remote access | +| `acm` | ttyGS0 serial | Debug console | + +--- + +## Building the Image + +### From Repository + +```bash +cd secubox-deb + +# Build the Eye Remote image +sudo bash image/eye-remote/build-eye-remote.sh \ + --output output/secubox-eye-remote.img \ + --storage-size 16G + +# Or with multiboot integration +sudo bash image/multiboot/build-multiboot.sh \ + --output output/secubox-multiboot.img \ + --size 16G +``` + +### GitHub Actions + +The image is automatically built via CI: +- Workflow: `.github/workflows/build-eye-remote.yml` +- Trigger: Push to `eye-remote-v*` tags + +--- + +## Remote Management + +### WiFi Configuration + +Edit `/boot/wpa_supplicant.conf` on the µSD card before first boot: + +``` +country=FR +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev +update_config=1 + +network={ + ssid="YourWiFi" + psk="YourPassword" +} +``` + +### SSH Access + +```bash +# Via WiFi (if configured) +ssh secubox@ + +# Via USB ECM network +ssh secubox@10.55.0.1 +``` + +### Web Dashboard + +Access at `http://10.55.0.1:8080`: +- Serial console via xterm.js +- Boot media status +- Storage swap controls + +--- + +## API Reference + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/api/v1/eye-remote/status` | System status | +| GET | `/api/v1/eye-remote/boot-media/state` | Boot media state | +| POST | `/api/v1/eye-remote/boot-media/upload` | Upload to shadow | +| POST | `/api/v1/eye-remote/boot-media/swap` | Swap active/shadow | +| POST | `/api/v1/eye-remote/boot-media/rollback` | Rollback swap | + +--- + +## Troubleshooting + +### Pi Zero Not Booting + +1. Check µSD card is properly seated +2. Verify `config.txt` contains `dtoverlay=dwc2` +3. Check power LED (solid red = powered) +4. Check activity LED (flashing green = reading SD) + +### Target Not Seeing USB Storage + +1. Ensure USB cable supports data (not charge-only) +2. Check Pi Zero is fully booted (activity LED stops flashing) +3. On target, run `lsusb` to check USB detection +4. Check `dmesg` for mass_storage errors + +### Boot Menu Not Appearing + +1. Target U-Boot must support `usb start` +2. Check boot order in U-Boot: `printenv boot_targets` +3. Manually try: `usb start; fatload usb 0:1 $kernel_addr_r Image` + +--- + +## See Also + +- [[Multiboot|Multi-Boot Live OS]] — Full multiboot documentation +- [[ARM-Installation]] — ARM64 installation guide +- [[ESPRESSObin]] — ESPRESSObin specific setup +- [[Live-USB]] — Standard Live USB guide + +--- + +## Support + +- **Issues**: https://github.com/CyberMind-FR/secubox-deb/issues +- **Wiki**: https://github.com/CyberMind-FR/secubox-deb/wiki diff --git a/wiki/Troubleshooting.md b/wiki/Troubleshooting.md index 69fac2c8..c260ffae 100644 --- a/wiki/Troubleshooting.md +++ b/wiki/Troubleshooting.md @@ -153,6 +153,54 @@ secubox-netdiag free -h ``` +### DSA Switch Detection Loop (ESPRESSObin) + +**Symptoms:** Boot log shows repeated messages: +``` +mv88e6085 d0032004.mdio-mii:01: switch 0x3410 detected: Marvell 88E6341, revision 0 +hwmon hwmon0: temp1_input not attached to any thermal zone +``` + +This is a known issue with the Marvell 88E6341 DSA (Distributed Switch Architecture) driver on some ESPRESSObin boards. + +**Solutions:** + +1. **Boot with DSA disabled** (select option 2 in boot menu): + - At boot menu, select "Live Boot + No DSA Switch" + - This adds `modprobe.blacklist=mv88e6xxx,dsa_core` to boot args + +2. **Manually blacklist the driver**: + ```bash + echo "blacklist mv88e6xxx" | sudo tee /etc/modprobe.d/no-dsa.conf + echo "blacklist dsa_core" | sudo tee -a /etc/modprobe.d/no-dsa.conf + sudo update-initramfs -u + ``` + +3. **Use a different DTB**: + - Some DTB variants handle the switch differently + - Try `armada-3720-espressobin.dtb` instead of v7 variant + +4. **Kernel parameters** (add to cmdline): + ``` + mv88e6xxx.blacklist=1 + ``` + +**Note:** Disabling DSA means you lose the hardware switch functionality. The LAN ports will not work as a switch but can still be configured as individual interfaces. + +### Boot Stuck or Kernel Panic + +**Symptoms:** Boot hangs or shows panic after loading kernel + +**Solutions:** + +1. Connect serial console (115200 8N1) to see actual error +2. Try different DTB variants from boot menu +3. Increase rootdelay: add `rootdelay=15` to boot args +4. Boot with minimal options: + ``` + root=/dev/sda2 rootwait console=ttyMV0,115200 single + ``` + ## Logs Location | Service | Log Location | diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md index ed4dac66..1c2a0527 100644 --- a/wiki/_Sidebar.md +++ b/wiki/_Sidebar.md @@ -1,29 +1,29 @@ -**[SecuBox](Home)** | [FR](Home-FR) | [DE](Home-DE) | [中文](Home-ZH) | **v2.2.3** +**[SecuBox](Home)** | [FR](Home-FR) | [DE](Home-DE) | [中文](Home-ZH) | **v2.2.4-pre1** ### 🔴 BOOT — Getting Started -* [[Multiboot|Multi-Boot Live OS]] ⭐ **NEW** -* [[Live-USB-VirtualBox|VirtualBox]] `run-vbox.sh` -* [[Live-USB-QEMU|QEMU]] 🖥️ `run-qemu.sh` -* [[Live-USB]] | [FR](Live-USB-FR) | [DE](Live-USB-DE) | [中文](Live-USB-ZH) -* [[Installation]] | [FR](Installation-FR) | [DE](Installation-DE) | [中文](Installation-ZH) -* [[ARM-Installation|ARM / U-Boot]] | [FR](ARM-Installation-FR) | [DE](ARM-Installation-DE) | [中文](ARM-Installation-ZH) ⚡ -* [[ESPRESSObin]] | [FR](ESPRESSObin-FR) | [DE](ESPRESSObin-DE) | [中文](ESPRESSObin-ZH) -* [[Eye-Remote|Eye Remote (Pi Zero)]] 📡 -* [[QEMU-ARM64]] 🖥️ +* [Multiboot](Multiboot) ⭐ **NEW** +* [VirtualBox](Live-USB-VirtualBox) `run-vbox.sh` +* [QEMU](Live-USB-QEMU) 🖥️ `run-qemu.sh` +* [Live-USB](Live-USB) | [FR](Live-USB-FR) | [DE](Live-USB-DE) | [中文](Live-USB-ZH) +* [Installation](Installation) | [FR](Installation-FR) | [DE](Installation-DE) | [中文](Installation-ZH) +* [ARM / U-Boot](ARM-Installation) | [FR](ARM-Installation-FR) | [DE](ARM-Installation-DE) | [中文](ARM-Installation-ZH) ⚡ +* [ESPRESSObin](ESPRESSObin) | [FR](ESPRESSObin-FR) | [DE](ESPRESSObin-DE) | [中文](ESPRESSObin-ZH) +* [Eye Remote](Eye-Remote) 📡 +* [QEMU-ARM64](QEMU-ARM64) 🖥️ ### 🟢 ROOT — Configuration -* [[Configuration]] | [FR](Configuration-FR) | [DE](Configuration-DE) | [中文](Configuration-ZH) -* [[Troubleshooting]] | [FR](Troubleshooting-FR) | [DE](Troubleshooting-DE) | [中文](Troubleshooting-ZH) +* [Configuration](Configuration) | [FR](Configuration-FR) | [DE](Configuration-DE) | [中文](Configuration-ZH) +* [Troubleshooting](Troubleshooting) | [FR](Troubleshooting-FR) | [DE](Troubleshooting-DE) | [中文](Troubleshooting-ZH) ### 🟣 MIND — Modules -* [[MODULES-EN|Modules]] 🇬🇧 -* [[MODULES-FR|Modules FR]] 🇫🇷 -* [[MODULES-DE|Modules DE]] 🇩🇪 -* [[MODULES-ZH|Modules 中文]] 🇨🇳 +* [Modules](MODULES-EN) 🇬🇧 +* [Modules FR](MODULES-FR) 🇫🇷 +* [Modules DE](MODULES-DE) 🇩🇪 +* [Modules 中文](MODULES-ZH) 🇨🇳 ### 🔵 MESH — Reference -* [[API-Reference]] | [FR](API-Reference-FR) | [DE](API-Reference-DE) | [中文](API-Reference-ZH) -* [[UI-COMPARISON|UI Comparison]] +* [API-Reference](API-Reference) | [FR](API-Reference-FR) | [DE](API-Reference-DE) | [中文](API-Reference-ZH) +* [UI Comparison](UI-COMPARISON) ### Links * [Releases](https://github.com/CyberMind-FR/secubox-deb/releases)