#!/bin/bash set -euo pipefail # ARM-native QEMU test with framebuffer using Alpine Linux (virtualization, not emulation) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" WORK_DIR="${PROJECT_DIR}/qemu-fb-test" CLOUD_INIT_DIR="${WORK_DIR}/cloud-init" # QEMU settings QEMU_MEM="2G" QEMU_CPUS="4" DISK_SIZE="4G" VNC_PORT="5902" # Alpine Linux ARM64 (native virtualization on Apple Silicon) ALPINE_VERSION="3.19" ALPINE_ISO="alpine-virt-${ALPINE_VERSION}.0-aarch64.iso" ALPINE_URL="https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VERSION}/releases/aarch64/${ALPINE_ISO}" # Colors GREEN='\033[0;32m' RED='\033[0;31m' NC='\033[0m' log() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $*" } error() { echo -e "${RED}[ERROR]${NC} $*" >&2 exit 1 } # Check dependencies check_dependencies() { log "Checking dependencies..." if ! command -v qemu-system-aarch64 &> /dev/null; then error "qemu-system-aarch64 not found" fi log "Dependencies OK" } # Setup directories setup_directories() { log "Setting up directories..." mkdir -p "$WORK_DIR" mkdir -p "$CLOUD_INIT_DIR" } # Download Alpine Linux download_alpine() { cd "$WORK_DIR" if [ -f "$ALPINE_ISO" ]; then log "Alpine Linux ISO already exists" return fi log "Downloading Alpine Linux..." wget -O "$ALPINE_ISO" "$ALPINE_URL" || error "Failed to download Alpine" } # Create disk image create_disk() { cd "$WORK_DIR" if [ -f "hdmistat-test.qcow2" ]; then log "Disk image already exists" return fi log "Creating disk image..." qemu-img create -f qcow2 hdmistat-test.qcow2 $DISK_SIZE } # Create startup script that will be run inside the VM create_vm_setup_script() { cat > "${WORK_DIR}/setup-hdmistat.sh" << 'EOF' #!/bin/sh set -e echo "Setting up hdmistat test environment..." # Install required packages apk update apk add --no-cache \ go \ git \ make \ gcc \ musl-dev \ linux-headers \ bash \ sudo \ openrc \ fbset \ util-linux # Enable framebuffer console rc-update add consolefont boot rc-update add keymaps boot # Create test user adduser -D -s /bin/bash testuser echo "testuser:hdmistat" | chpasswd addgroup testuser wheel echo "%wheel ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/wheel # Mount shared folder if available if [ -e /dev/vdb ]; then mkdir -p /mnt/hdmistat mount /dev/vdb /mnt/hdmistat fi # Build hdmistat if [ -d "/mnt/hdmistat" ]; then echo "Building hdmistat from mounted source..." cd /mnt/hdmistat make build cp hdmistat /usr/local/bin/ else echo "Installing hdmistat from git..." export GOPROXY=https://proxy.golang.org go install git.eeqj.de/sneak/hdmistat/cmd/hdmistat@latest cp ~/go/bin/hdmistat /usr/local/bin/ fi # Create init script for hdmistat cat > /etc/init.d/hdmistat << 'INIT_EOF' #!/sbin/openrc-run name="hdmistat" description="HDMI Statistics Display Daemon" command="/usr/local/bin/hdmistat" command_args="daemon" command_background=true pidfile="/run/${RC_SVCNAME}.pid" start_stop_daemon_args="--stdout /var/log/hdmistat.log --stderr /var/log/hdmistat.log" depend() { need localmount after bootmisc } INIT_EOF chmod +x /etc/init.d/hdmistat # Create config directory mkdir -p /etc/hdmistat cat > /etc/hdmistat/config.yaml << 'CONFIG_EOF' framebuffer_device: /dev/fb0 rotation_interval: 10s update_interval: 1s log_level: info width: 1024 height: 768 screens: - overview - top_cpu - top_memory CONFIG_EOF # Enable services rc-update add hdmistat default echo "Setup complete! You can now:" echo "1. Switch to framebuffer console with Alt+F1" echo "2. Check hdmistat status: rc-service hdmistat status" echo "3. View logs: tail -f /var/log/hdmistat.log" EOF chmod +x "${WORK_DIR}/setup-hdmistat.sh" } # Create run script create_run_script() { cat > "${WORK_DIR}/run-qemu.sh" << EOF #!/bin/bash cd "$WORK_DIR" echo "Starting QEMU with framebuffer support..." echo "" echo "After boot:" echo "1. Login as root (no password)" echo "2. Run: /mnt/setup-hdmistat.sh" echo "3. Switch to framebuffer with Alt+F1 to see hdmistat" echo "4. VNC available on port $VNC_PORT" echo "" echo "Press Ctrl+A, X to quit" echo "" # Create a FAT filesystem image with our setup script if [ ! -f "scripts.img" ]; then dd if=/dev/zero of=scripts.img bs=1M count=10 mkfs.vfat scripts.img mcopy -i scripts.img setup-hdmistat.sh :: fi # Find QEMU firmware files EFI_CODE="" for path in /nix/store/*/share/qemu/edk2-aarch64-code.fd /run/current-system/sw/share/qemu/edk2-aarch64-code.fd; do if [ -f "$path" ]; then EFI_CODE="$path" break fi done if [ -z "$EFI_CODE" ]; then echo "Warning: EFI firmware not found, trying without it" BIOS_ARGS="" else BIOS_ARGS="-bios $EFI_CODE" fi qemu-system-aarch64 \\ -M virt \\ -accel hvf \\ -cpu host \\ -smp $QEMU_CPUS \\ -m $QEMU_MEM \\ -drive file=hdmistat-test.qcow2,format=qcow2,if=virtio \\ -drive file=scripts.img,format=raw,if=virtio \\ -drive file="${PROJECT_DIR}",if=virtio,format=raw,readonly=on \\ -cdrom $ALPINE_ISO \\ -boot d \\ -netdev user,id=net0,hostfwd=tcp::2223-:22 \\ -device virtio-net-pci,netdev=net0 \\ -device virtio-gpu-pci \\ -display default,show-cursor=on \\ -vnc :2 \\ -serial mon:stdio \\ $BIOS_ARGS \\ \${@} EOF chmod +x "${WORK_DIR}/run-qemu.sh" } # Create helper scripts create_helpers() { # VNC viewer cat > "${WORK_DIR}/view-vnc.sh" << EOF #!/bin/bash echo "Opening VNC viewer on localhost:$VNC_PORT" vncviewer localhost:$VNC_PORT || open vnc://localhost:$VNC_PORT EOF chmod +x "${WORK_DIR}/view-vnc.sh" # Instructions cat > "${WORK_DIR}/README.md" << EOF # QEMU Framebuffer Test Environment This is a lightweight QEMU setup for testing hdmistat with framebuffer support. ## Quick Start 1. Start QEMU: \`\`\`bash ./run-qemu.sh \`\`\` 2. In the Alpine Linux boot menu, select the default option 3. Login as root (no password required) 4. Mount the scripts volume: \`\`\`bash mkdir -p /mnt mount /dev/vdb /mnt \`\`\` 5. Run the setup script: \`\`\`bash /mnt/setup-hdmistat.sh \`\`\` 6. Start hdmistat: \`\`\`bash rc-service hdmistat start \`\`\` 7. View the framebuffer output: - Press Alt+F1 to switch to the framebuffer console - Or use VNC: ./view-vnc.sh ## Tips - The framebuffer is available at /dev/fb0 - Default resolution is 1024x768 - hdmistat source is mounted at /dev/vdc (mount to /mnt/hdmistat) - Logs are at /var/log/hdmistat.log ## Troubleshooting If framebuffer doesn't work: 1. Check if /dev/fb0 exists 2. Try: modprobe fbdev 3. Check dmesg for framebuffer messages EOF } # Print instructions print_instructions() { echo "" echo "======================================" echo "QEMU Framebuffer Test Setup Complete!" echo "======================================" echo "" echo "To start testing:" echo " cd $WORK_DIR" echo " ./run-qemu.sh" echo "" echo "See README.md for detailed instructions" echo "" } # Main main() { log "Setting up QEMU framebuffer test environment..." check_dependencies setup_directories download_alpine create_disk create_vm_setup_script create_run_script create_helpers print_instructions log "Setup complete!" } main "$@"