335 lines
7.4 KiB
Bash
Executable File
335 lines
7.4 KiB
Bash
Executable File
#!/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 "$@" |