checkpointing, heavy dev
This commit is contained in:
248
scripts/docker-fb-test.sh
Executable file
248
scripts/docker-fb-test.sh
Executable file
@@ -0,0 +1,248 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Docker-based framebuffer testing for hdmistat
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() {
|
||||
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $*"
|
||||
}
|
||||
|
||||
# Create Dockerfile
|
||||
create_dockerfile() {
|
||||
log "Creating Dockerfile for framebuffer testing..."
|
||||
|
||||
cat > "${PROJECT_DIR}/Dockerfile.fbtest" << 'EOF'
|
||||
FROM ubuntu:22.04
|
||||
|
||||
# Avoid interactive prompts
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
# Build tools
|
||||
build-essential \
|
||||
git \
|
||||
wget \
|
||||
golang-go \
|
||||
# Framebuffer tools
|
||||
fbset \
|
||||
fbi \
|
||||
# Virtual framebuffer
|
||||
xvfb \
|
||||
x11vnc \
|
||||
# System tools
|
||||
systemd \
|
||||
systemd-sysv \
|
||||
sudo \
|
||||
htop \
|
||||
procps \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Go 1.24.4 (ARM64 compatible)
|
||||
RUN ARCH=$(dpkg --print-architecture) && \
|
||||
GO_ARCH=$([ "$ARCH" = "arm64" ] && echo "arm64" || echo "amd64") && \
|
||||
wget -q -O /tmp/go.tar.gz https://go.dev/dl/go1.24.4.linux-${GO_ARCH}.tar.gz && \
|
||||
rm -rf /usr/local/go && \
|
||||
tar -C /usr/local -xzf /tmp/go.tar.gz && \
|
||||
rm /tmp/go.tar.gz
|
||||
|
||||
ENV PATH="/usr/local/go/bin:${PATH}"
|
||||
ENV GOPATH="/root/go"
|
||||
ENV PATH="${GOPATH}/bin:${PATH}"
|
||||
|
||||
# Create virtual framebuffer on startup
|
||||
RUN echo '#!/bin/bash\n\
|
||||
Xvfb :99 -screen 0 1920x1080x24 &\n\
|
||||
export DISPLAY=:99\n\
|
||||
sleep 2\n\
|
||||
x11vnc -display :99 -forever -nopw -quiet -shared -bg\n\
|
||||
' > /usr/local/bin/start-vnc.sh && chmod +x /usr/local/bin/start-vnc.sh
|
||||
|
||||
# Copy hdmistat source
|
||||
COPY . /hdmistat
|
||||
WORKDIR /hdmistat
|
||||
|
||||
# Build hdmistat
|
||||
RUN make build && \
|
||||
cp hdmistat /usr/local/bin/
|
||||
|
||||
# Create test script
|
||||
RUN echo '#!/bin/bash\n\
|
||||
echo "Starting virtual framebuffer..."\n\
|
||||
/usr/local/bin/start-vnc.sh\n\
|
||||
echo "VNC server started on port 5900"\n\
|
||||
echo ""\n\
|
||||
echo "Creating virtual framebuffer device..."\n\
|
||||
# Note: In Docker, we cannot access real /dev/fb0\n\
|
||||
# For testing, hdmistat can be modified to render to a file/image\n\
|
||||
echo ""\n\
|
||||
echo "Starting hdmistat in test mode..."\n\
|
||||
hdmistat info\n\
|
||||
echo ""\n\
|
||||
echo "To test hdmistat daemon:"\n\
|
||||
echo " hdmistat daemon --framebuffer /tmp/fb0"\n\
|
||||
echo ""\n\
|
||||
echo "Note: Real framebuffer access requires --privileged mode"\n\
|
||||
exec /bin/bash\n\
|
||||
' > /test-hdmistat.sh && chmod +x /test-hdmistat.sh
|
||||
|
||||
# Expose VNC port
|
||||
EXPOSE 5900
|
||||
|
||||
CMD ["/test-hdmistat.sh"]
|
||||
EOF
|
||||
}
|
||||
|
||||
# Create docker-compose file
|
||||
create_compose() {
|
||||
log "Creating docker-compose configuration..."
|
||||
|
||||
cat > "${PROJECT_DIR}/docker-compose.fbtest.yml" << 'EOF'
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
hdmistat-test:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.fbtest
|
||||
image: hdmistat-fbtest:latest
|
||||
container_name: hdmistat-fbtest
|
||||
# Uncomment for real framebuffer access (Linux only)
|
||||
# privileged: true
|
||||
# devices:
|
||||
# - /dev/fb0:/dev/fb0
|
||||
ports:
|
||||
- "5900:5900" # VNC port
|
||||
volumes:
|
||||
- .:/hdmistat:rw
|
||||
- /tmp/.X11-unix:/tmp/.X11-unix:rw
|
||||
environment:
|
||||
- DISPLAY=:99
|
||||
stdin_open: true
|
||||
tty: true
|
||||
# Uncomment for systemd support
|
||||
# command: /sbin/init
|
||||
# tmpfs:
|
||||
# - /run
|
||||
# - /run/lock
|
||||
# - /tmp
|
||||
# volumes:
|
||||
# - /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
EOF
|
||||
}
|
||||
|
||||
# Create run script
|
||||
create_run_script() {
|
||||
log "Creating run script..."
|
||||
|
||||
cat > "${PROJECT_DIR}/run-docker-fbtest.sh" << 'EOF'
|
||||
#!/bin/bash
|
||||
|
||||
echo "Building and starting hdmistat framebuffer test container..."
|
||||
echo ""
|
||||
|
||||
# Build the container
|
||||
docker-compose -f docker-compose.fbtest.yml build
|
||||
|
||||
# Run the container
|
||||
echo "Starting container..."
|
||||
echo "VNC will be available on localhost:5900"
|
||||
echo ""
|
||||
|
||||
docker-compose -f docker-compose.fbtest.yml run --rm hdmistat-test
|
||||
|
||||
# Cleanup
|
||||
echo ""
|
||||
echo "Cleaning up..."
|
||||
docker-compose -f docker-compose.fbtest.yml down
|
||||
EOF
|
||||
chmod +x "${PROJECT_DIR}/run-docker-fbtest.sh"
|
||||
}
|
||||
|
||||
# Create VNC helper
|
||||
create_vnc_helper() {
|
||||
cat > "${PROJECT_DIR}/view-docker-vnc.sh" << 'EOF'
|
||||
#!/bin/bash
|
||||
echo "Connecting to VNC server in Docker container..."
|
||||
echo "Make sure the container is running first!"
|
||||
echo ""
|
||||
|
||||
# Try different VNC viewers
|
||||
if command -v vncviewer &> /dev/null; then
|
||||
vncviewer localhost:5900
|
||||
elif command -v open &> /dev/null; then
|
||||
open vnc://localhost:5900
|
||||
else
|
||||
echo "No VNC viewer found"
|
||||
echo "Connect manually to: localhost:5900"
|
||||
fi
|
||||
EOF
|
||||
chmod +x "${PROJECT_DIR}/view-docker-vnc.sh"
|
||||
}
|
||||
|
||||
# Print instructions
|
||||
print_instructions() {
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo "Docker Framebuffer Test Setup Complete!"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "Three test environments have been created:"
|
||||
echo ""
|
||||
echo "1. QEMU Raspberry Pi (Full emulation):"
|
||||
echo " ./scripts/qemu-rpi-test.sh"
|
||||
echo ""
|
||||
echo "2. QEMU with Alpine (Lightweight):"
|
||||
echo " ./scripts/qemu-fb-test.sh"
|
||||
echo ""
|
||||
echo "3. Docker with virtual framebuffer:"
|
||||
echo " ./run-docker-fbtest.sh"
|
||||
echo ""
|
||||
echo "For Docker testing:"
|
||||
echo " - Easiest to set up"
|
||||
echo " - Uses virtual framebuffer (Xvfb)"
|
||||
echo " - View via VNC on port 5900"
|
||||
echo ""
|
||||
echo "For QEMU testing:"
|
||||
echo " - More realistic framebuffer"
|
||||
echo " - Full system emulation"
|
||||
echo " - Better for final testing"
|
||||
echo ""
|
||||
warn "Note: Real framebuffer (/dev/fb0) testing requires:"
|
||||
warn " - Linux host system"
|
||||
warn " - Running with appropriate permissions"
|
||||
warn " - Or using QEMU/real hardware"
|
||||
}
|
||||
|
||||
# Main
|
||||
main() {
|
||||
log "Setting up Docker framebuffer test environment..."
|
||||
|
||||
create_dockerfile
|
||||
create_compose
|
||||
create_run_script
|
||||
create_vnc_helper
|
||||
print_instructions
|
||||
|
||||
log "Setup complete!"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
258
scripts/qemu-alpine-arm64.sh
Executable file
258
scripts/qemu-alpine-arm64.sh
Executable file
@@ -0,0 +1,258 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Simple ARM64 Alpine Linux QEMU setup for hdmistat testing
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
WORK_DIR="${PROJECT_DIR}/qemu-alpine-test"
|
||||
|
||||
# QEMU settings
|
||||
QEMU_MEM="2G"
|
||||
QEMU_CPUS="4"
|
||||
DISK_SIZE="4G"
|
||||
VNC_PORT="5902"
|
||||
|
||||
# Alpine Linux ARM64
|
||||
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..."
|
||||
|
||||
local deps=("qemu-system-aarch64" "wget")
|
||||
for dep in "${deps[@]}"; do
|
||||
if ! command -v "$dep" &> /dev/null; then
|
||||
error "$dep not found"
|
||||
fi
|
||||
done
|
||||
|
||||
log "Dependencies OK"
|
||||
}
|
||||
|
||||
# Setup directories
|
||||
setup_directories() {
|
||||
log "Setting up directories..."
|
||||
mkdir -p "$WORK_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 ARM64..."
|
||||
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 setup script
|
||||
create_setup_script() {
|
||||
cat > "${WORK_DIR}/setup-hdmistat.sh" << 'EOF'
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "==================================="
|
||||
echo "hdmistat Alpine Linux Setup Script"
|
||||
echo "==================================="
|
||||
|
||||
# Update packages
|
||||
echo "Updating packages..."
|
||||
apk update
|
||||
|
||||
# Install required packages
|
||||
echo "Installing build dependencies..."
|
||||
apk add --no-cache \
|
||||
go \
|
||||
git \
|
||||
make \
|
||||
gcc \
|
||||
musl-dev \
|
||||
linux-headers \
|
||||
bash \
|
||||
sudo \
|
||||
fbset \
|
||||
util-linux
|
||||
|
||||
# Install newer Go if needed
|
||||
GO_VERSION="1.24.4"
|
||||
if ! go version | grep -q "$GO_VERSION"; then
|
||||
echo "Installing Go $GO_VERSION..."
|
||||
wget -q -O /tmp/go.tar.gz "https://go.dev/dl/go${GO_VERSION}.linux-aarch64.tar.gz"
|
||||
rm -rf /usr/local/go
|
||||
tar -C /usr/local -xzf /tmp/go.tar.gz
|
||||
rm /tmp/go.tar.gz
|
||||
export PATH="/usr/local/go/bin:$PATH"
|
||||
fi
|
||||
|
||||
# Build hdmistat from mounted source
|
||||
if [ -d "/mnt/hdmistat" ]; then
|
||||
echo "Building hdmistat from source..."
|
||||
cd /mnt/hdmistat
|
||||
make build
|
||||
cp hdmistat /usr/local/bin/
|
||||
echo "hdmistat installed successfully!"
|
||||
else
|
||||
echo "Warning: hdmistat source not mounted at /mnt/hdmistat"
|
||||
echo "Mount with: mount -t 9p -o trans=virtio,version=9p2000.L hdmistat /mnt/hdmistat"
|
||||
fi
|
||||
|
||||
# Create test config
|
||||
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
|
||||
|
||||
echo ""
|
||||
echo "Setup complete!"
|
||||
echo ""
|
||||
echo "To test hdmistat:"
|
||||
echo "1. hdmistat info - Show system information"
|
||||
echo "2. hdmistat daemon - Run the framebuffer daemon"
|
||||
echo "3. hdmistat status - Check daemon status"
|
||||
echo ""
|
||||
echo "Note: Framebuffer access requires appropriate permissions"
|
||||
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 ARM64 Alpine Linux..."
|
||||
echo ""
|
||||
echo "Instructions:"
|
||||
echo "1. Boot Alpine Linux and login as root (no password)"
|
||||
echo "2. Mount the hdmistat source: mkdir -p /mnt/hdmistat && mount -t 9p -o trans=virtio,version=9p2000.L hdmistat /mnt/hdmistat"
|
||||
echo "3. Run the setup script: sh /mnt/hdmistat/scripts/qemu-alpine-test/setup-hdmistat.sh"
|
||||
echo ""
|
||||
echo "VNC available on port $VNC_PORT"
|
||||
echo "Press Ctrl+A, X to quit"
|
||||
echo ""
|
||||
|
||||
# Find EFI firmware
|
||||
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
|
||||
|
||||
BIOS_ARGS=""
|
||||
if [ -n "\$EFI_CODE" ]; then
|
||||
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 \\
|
||||
-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 \\
|
||||
-virtfs local,path="${PROJECT_DIR}",mount_tag=hdmistat,security_model=none,id=hdmistat \\
|
||||
\$BIOS_ARGS \\
|
||||
\${@}
|
||||
EOF
|
||||
chmod +x "${WORK_DIR}/run-qemu.sh"
|
||||
}
|
||||
|
||||
# Create VNC helper
|
||||
create_vnc_helper() {
|
||||
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 || echo "Connect to VNC at localhost:$VNC_PORT"
|
||||
EOF
|
||||
chmod +x "${WORK_DIR}/view-vnc.sh"
|
||||
}
|
||||
|
||||
# Print instructions
|
||||
print_instructions() {
|
||||
echo ""
|
||||
echo "======================================="
|
||||
echo "QEMU ARM64 Alpine Setup Complete!"
|
||||
echo "======================================="
|
||||
echo ""
|
||||
echo "To start testing:"
|
||||
echo " cd $WORK_DIR"
|
||||
echo " ./run-qemu.sh"
|
||||
echo ""
|
||||
echo "This creates a lightweight Alpine Linux ARM64 VM with:"
|
||||
echo " - Native ARM64 virtualization (hvf)"
|
||||
echo " - Framebuffer support"
|
||||
echo " - hdmistat source mounted via 9p"
|
||||
echo " - No cloud-init required"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main
|
||||
main() {
|
||||
log "Setting up QEMU ARM64 Alpine environment..."
|
||||
|
||||
check_dependencies
|
||||
setup_directories
|
||||
download_alpine
|
||||
create_disk
|
||||
create_setup_script
|
||||
create_run_script
|
||||
create_vnc_helper
|
||||
print_instructions
|
||||
|
||||
log "Setup complete!"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
335
scripts/qemu-fb-test.sh
Executable file
335
scripts/qemu-fb-test.sh
Executable file
@@ -0,0 +1,335 @@
|
||||
#!/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 "$@"
|
||||
338
scripts/qemu-rpi-test.sh
Executable file
338
scripts/qemu-rpi-test.sh
Executable file
@@ -0,0 +1,338 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Script to run Raspberry Pi OS in QEMU with hdmistat installation
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
WORK_DIR="${PROJECT_DIR}/qemu-test"
|
||||
CLOUD_INIT_DIR="${WORK_DIR}/cloud-init"
|
||||
|
||||
# QEMU and image settings
|
||||
QEMU_ARCH="aarch64"
|
||||
RPI_IMAGE_URL="https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2024-03-15/2024-03-15-raspios-bookworm-arm64-lite.img.xz"
|
||||
RPI_IMAGE_NAME="raspios-lite-arm64.img"
|
||||
QEMU_MEM="2G"
|
||||
QEMU_CPUS="4"
|
||||
VNC_PORT="5901"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log() {
|
||||
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $*"
|
||||
}
|
||||
|
||||
# Check dependencies
|
||||
check_dependencies() {
|
||||
log "Checking dependencies..."
|
||||
|
||||
local deps=("qemu-system-aarch64" "cloud-localds" "xz" "wget")
|
||||
local missing=()
|
||||
|
||||
for dep in "${deps[@]}"; do
|
||||
if ! command -v "$dep" &> /dev/null; then
|
||||
missing+=("$dep")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing[@]} -ne 0 ]; then
|
||||
error "Missing dependencies: ${missing[*]}"
|
||||
fi
|
||||
|
||||
log "All dependencies found"
|
||||
}
|
||||
|
||||
# Create work directory
|
||||
setup_directories() {
|
||||
log "Setting up directories..."
|
||||
mkdir -p "$WORK_DIR"
|
||||
mkdir -p "$CLOUD_INIT_DIR"
|
||||
}
|
||||
|
||||
# Download Raspberry Pi OS image
|
||||
download_image() {
|
||||
if [ -f "${WORK_DIR}/${RPI_IMAGE_NAME}" ]; then
|
||||
log "Raspberry Pi OS image already exists"
|
||||
return
|
||||
fi
|
||||
|
||||
log "Downloading Raspberry Pi OS image..."
|
||||
cd "$WORK_DIR"
|
||||
|
||||
if [ ! -f "${RPI_IMAGE_NAME}.xz" ]; then
|
||||
wget -O "${RPI_IMAGE_NAME}.xz" "$RPI_IMAGE_URL" || error "Failed to download image"
|
||||
fi
|
||||
|
||||
log "Extracting image..."
|
||||
xz -d -k "${RPI_IMAGE_NAME}.xz" || error "Failed to extract image"
|
||||
|
||||
# Resize image to have more space
|
||||
log "Resizing image to 8GB..."
|
||||
qemu-img resize "${RPI_IMAGE_NAME}" 8G
|
||||
}
|
||||
|
||||
# Create cloud-init configuration
|
||||
create_cloud_init() {
|
||||
log "Creating cloud-init configuration..."
|
||||
|
||||
# Create meta-data
|
||||
cat > "${CLOUD_INIT_DIR}/meta-data" << 'EOF'
|
||||
instance-id: hdmistat-test-01
|
||||
local-hostname: hdmistat-test
|
||||
EOF
|
||||
|
||||
# Create user-data with hdmistat installation
|
||||
cat > "${CLOUD_INIT_DIR}/user-data" << 'EOF'
|
||||
#cloud-config
|
||||
hostname: hdmistat-test
|
||||
manage_etc_hosts: true
|
||||
|
||||
users:
|
||||
- name: pi
|
||||
groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
shell: /bin/bash
|
||||
lock_passwd: false
|
||||
passwd: $6$rounds=4096$8VNRmFT9yR$7TVlOepTJjMW0CzBkpMrdWA7aH4rZ94pZng8XjqaY8d8qqBmFvO/hYL5L2gqJ5nKLhDR8Jz9Z9nqfHBl5kVZHe1
|
||||
ssh_authorized_keys:
|
||||
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf0q4PyG0doiBQYV7OlOxbRjle026hJPBWbZe test@hdmistat
|
||||
|
||||
packages:
|
||||
- git
|
||||
- golang
|
||||
- build-essential
|
||||
- systemd
|
||||
- htop
|
||||
- tmux
|
||||
|
||||
# Enable SSH
|
||||
ssh_pwauth: true
|
||||
|
||||
# Update system
|
||||
package_update: true
|
||||
package_upgrade: true
|
||||
|
||||
# Install Go 1.24.4
|
||||
write_files:
|
||||
- path: /tmp/install-go.sh
|
||||
permissions: '0755'
|
||||
content: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
GO_VERSION="1.24.4"
|
||||
wget -q -O /tmp/go.tar.gz "https://go.dev/dl/go${GO_VERSION}.linux-arm64.tar.gz"
|
||||
sudo rm -rf /usr/local/go
|
||||
sudo tar -C /usr/local -xzf /tmp/go.tar.gz
|
||||
echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee -a /etc/profile
|
||||
echo 'export GOPATH=$HOME/go' | sudo tee -a /etc/profile
|
||||
echo 'export PATH=$PATH:$GOPATH/bin' | sudo tee -a /etc/profile
|
||||
|
||||
- path: /tmp/build-hdmistat.sh
|
||||
permissions: '0755'
|
||||
content: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
export GOPATH=/home/pi/go
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
|
||||
# Clone and build hdmistat from local source
|
||||
mkdir -p /home/pi/hdmistat-src
|
||||
cd /home/pi/hdmistat-src
|
||||
|
||||
# Note: In real usage, you'd clone from git repo
|
||||
# For testing, we'll mount the source directory
|
||||
|
||||
# Build hdmistat
|
||||
if [ -d "/mnt/hdmistat" ]; then
|
||||
cd /mnt/hdmistat
|
||||
make build
|
||||
sudo cp hdmistat /usr/local/bin/
|
||||
else
|
||||
# Fallback: try to install from git
|
||||
go install git.eeqj.de/sneak/hdmistat/cmd/hdmistat@latest
|
||||
sudo cp $GOPATH/bin/hdmistat /usr/local/bin/
|
||||
fi
|
||||
|
||||
# Install as systemd service
|
||||
sudo /usr/local/bin/hdmistat install
|
||||
|
||||
# Enable framebuffer console
|
||||
sudo sed -i 's/console=serial0,115200 //' /boot/cmdline.txt
|
||||
echo "hdmi_force_hotplug=1" | sudo tee -a /boot/config.txt
|
||||
echo "hdmi_group=2" | sudo tee -a /boot/config.txt
|
||||
echo "hdmi_mode=82" | sudo tee -a /boot/config.txt
|
||||
echo "framebuffer_width=1920" | sudo tee -a /boot/config.txt
|
||||
echo "framebuffer_height=1080" | sudo tee -a /boot/config.txt
|
||||
|
||||
# Run installation scripts
|
||||
runcmd:
|
||||
- /tmp/install-go.sh
|
||||
- sleep 5
|
||||
- /tmp/build-hdmistat.sh
|
||||
- sudo systemctl daemon-reload
|
||||
- sudo systemctl enable hdmistat
|
||||
- sudo systemctl start hdmistat
|
||||
|
||||
# Final message
|
||||
final_message: "hdmistat installation complete! System ready for testing."
|
||||
EOF
|
||||
|
||||
# Create cloud-init ISO
|
||||
log "Creating cloud-init ISO..."
|
||||
cd "$WORK_DIR"
|
||||
cloud-localds cloud-init.iso "${CLOUD_INIT_DIR}/user-data" "${CLOUD_INIT_DIR}/meta-data"
|
||||
}
|
||||
|
||||
# Create QEMU run script
|
||||
create_run_script() {
|
||||
log "Creating QEMU run script..."
|
||||
|
||||
cat > "${WORK_DIR}/run-qemu.sh" << EOF
|
||||
#!/bin/bash
|
||||
# Run QEMU with Raspberry Pi emulation
|
||||
|
||||
cd "$WORK_DIR"
|
||||
|
||||
echo "Starting QEMU Raspberry Pi emulation..."
|
||||
echo "VNC server will be available on port $VNC_PORT"
|
||||
echo "SSH: ssh pi@localhost -p 2222 (password: raspberry)"
|
||||
echo "Framebuffer: The emulated display supports framebuffer at /dev/fb0"
|
||||
echo ""
|
||||
echo "Press Ctrl+A, X to quit QEMU"
|
||||
|
||||
qemu-system-aarch64 \\
|
||||
-M raspi3b \\
|
||||
-cpu cortex-a72 \\
|
||||
-smp $QEMU_CPUS \\
|
||||
-m $QEMU_MEM \\
|
||||
-kernel kernel8.img \\
|
||||
-dtb bcm2710-rpi-3-b-plus.dtb \\
|
||||
-append "rw earlyprintk loglevel=8 console=ttyAMA0,115200 dwc_otg.lpm_enable=0 root=/dev/mmcblk0p2 rootdelay=1" \\
|
||||
-drive file=${RPI_IMAGE_NAME},format=raw,if=sd \\
|
||||
-drive file=cloud-init.iso,format=raw,if=none,id=cloud-init \\
|
||||
-device usb-storage,drive=cloud-init \\
|
||||
-netdev user,id=net0,hostfwd=tcp::2222-:22 \\
|
||||
-device usb-net,netdev=net0 \\
|
||||
-vnc :1 \\
|
||||
-serial stdio \\
|
||||
-display none \\
|
||||
-virtfs local,path="${PROJECT_DIR}",mount_tag=hdmistat,security_model=passthrough,id=hdmistat \\
|
||||
\${@}
|
||||
EOF
|
||||
|
||||
chmod +x "${WORK_DIR}/run-qemu.sh"
|
||||
}
|
||||
|
||||
# Download kernel and DTB files
|
||||
download_kernel() {
|
||||
log "Downloading kernel and DTB files..."
|
||||
|
||||
cd "$WORK_DIR"
|
||||
|
||||
# These are required for booting Raspberry Pi OS in QEMU
|
||||
if [ ! -f "kernel8.img" ]; then
|
||||
wget -q https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel8.img || \
|
||||
error "Failed to download kernel"
|
||||
fi
|
||||
|
||||
if [ ! -f "bcm2710-rpi-3-b-plus.dtb" ]; then
|
||||
wget -q https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/bcm2710-rpi-3-b-plus.dtb || \
|
||||
error "Failed to download DTB"
|
||||
fi
|
||||
}
|
||||
|
||||
# Create helper scripts
|
||||
create_helpers() {
|
||||
log "Creating helper scripts..."
|
||||
|
||||
# VNC viewer script
|
||||
cat > "${WORK_DIR}/view-vnc.sh" << EOF
|
||||
#!/bin/bash
|
||||
echo "Opening VNC viewer on localhost:$VNC_PORT"
|
||||
vncviewer localhost:$VNC_PORT || echo "VNC viewer not found. Connect manually to localhost:$VNC_PORT"
|
||||
EOF
|
||||
chmod +x "${WORK_DIR}/view-vnc.sh"
|
||||
|
||||
# SSH script
|
||||
cat > "${WORK_DIR}/ssh-pi.sh" << EOF
|
||||
#!/bin/bash
|
||||
echo "Connecting to Raspberry Pi via SSH..."
|
||||
echo "Default password is: raspberry"
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null pi@localhost -p 2222
|
||||
EOF
|
||||
chmod +x "${WORK_DIR}/ssh-pi.sh"
|
||||
|
||||
# Mount script for 9p filesystem
|
||||
cat > "${WORK_DIR}/mount-hdmistat.sh" << EOF
|
||||
#!/bin/bash
|
||||
# Run this inside the VM to mount the hdmistat source
|
||||
echo "Run this inside the Raspberry Pi VM:"
|
||||
echo "sudo mkdir -p /mnt/hdmistat"
|
||||
echo "sudo mount -t 9p -o trans=virtio hdmistat /mnt/hdmistat -oversion=9p2000.L"
|
||||
EOF
|
||||
chmod +x "${WORK_DIR}/mount-hdmistat.sh"
|
||||
}
|
||||
|
||||
# Print usage instructions
|
||||
print_instructions() {
|
||||
log "Setup complete!"
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "QEMU Raspberry Pi Test Environment Ready"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
echo "To start the emulated Raspberry Pi:"
|
||||
echo " cd $WORK_DIR"
|
||||
echo " ./run-qemu.sh"
|
||||
echo ""
|
||||
echo "To view the display (framebuffer):"
|
||||
echo " ./view-vnc.sh"
|
||||
echo ""
|
||||
echo "To SSH into the system:"
|
||||
echo " ./ssh-pi.sh"
|
||||
echo ""
|
||||
echo "To mount hdmistat source inside VM:"
|
||||
echo " 1. SSH into the VM"
|
||||
echo " 2. Run: sudo mount -t 9p -o trans=virtio hdmistat /mnt/hdmistat -oversion=9p2000.L"
|
||||
echo ""
|
||||
echo "Default credentials:"
|
||||
echo " Username: pi"
|
||||
echo " Password: raspberry"
|
||||
echo ""
|
||||
echo "The framebuffer device will be available at /dev/fb0"
|
||||
echo "hdmistat will be installed automatically via cloud-init on first boot"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
log "Starting QEMU Raspberry Pi setup for hdmistat testing..."
|
||||
|
||||
check_dependencies
|
||||
setup_directories
|
||||
download_image
|
||||
download_kernel
|
||||
create_cloud_init
|
||||
create_run_script
|
||||
create_helpers
|
||||
print_instructions
|
||||
|
||||
log "Setup completed successfully!"
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
315
scripts/qemu-ubuntu-arm64.sh
Executable file
315
scripts/qemu-ubuntu-arm64.sh
Executable file
@@ -0,0 +1,315 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# ARM64 Ubuntu QEMU setup with cloud-init for hdmistat testing
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
WORK_DIR="${PROJECT_DIR}/qemu-ubuntu-test"
|
||||
CLOUD_INIT_DIR="${WORK_DIR}/cloud-init"
|
||||
|
||||
# QEMU settings
|
||||
QEMU_MEM="2G"
|
||||
QEMU_CPUS="4"
|
||||
DISK_SIZE="8G"
|
||||
VNC_PORT="5902"
|
||||
|
||||
# Ubuntu Cloud Image ARM64
|
||||
UBUNTU_VERSION="22.04"
|
||||
UBUNTU_IMAGE="ubuntu-${UBUNTU_VERSION}-server-cloudimg-arm64.img"
|
||||
UBUNTU_URL="https://cloud-images.ubuntu.com/releases/${UBUNTU_VERSION}/release/${UBUNTU_IMAGE}"
|
||||
|
||||
# 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..."
|
||||
|
||||
local deps=("qemu-system-aarch64" "qemu-img" "wget" "genisoimage")
|
||||
for dep in "${deps[@]}"; do
|
||||
if ! command -v "$dep" &> /dev/null; then
|
||||
error "$dep not found"
|
||||
fi
|
||||
done
|
||||
|
||||
log "Dependencies OK"
|
||||
}
|
||||
|
||||
# Setup directories
|
||||
setup_directories() {
|
||||
log "Setting up directories..."
|
||||
mkdir -p "$WORK_DIR"
|
||||
mkdir -p "$CLOUD_INIT_DIR"
|
||||
}
|
||||
|
||||
# Download Ubuntu cloud image
|
||||
download_ubuntu() {
|
||||
cd "$WORK_DIR"
|
||||
|
||||
if [ -f "$UBUNTU_IMAGE" ]; then
|
||||
log "Ubuntu cloud image already exists"
|
||||
return
|
||||
fi
|
||||
|
||||
log "Downloading Ubuntu ${UBUNTU_VERSION} ARM64 cloud image..."
|
||||
wget -O "$UBUNTU_IMAGE" "$UBUNTU_URL" || error "Failed to download Ubuntu image"
|
||||
}
|
||||
|
||||
# Create working disk from cloud image
|
||||
create_disk() {
|
||||
cd "$WORK_DIR"
|
||||
|
||||
if [ -f "hdmistat-test.qcow2" ]; then
|
||||
log "Working disk already exists"
|
||||
return
|
||||
fi
|
||||
|
||||
log "Creating working disk from cloud image..."
|
||||
qemu-img create -f qcow2 -F qcow2 -b "$UBUNTU_IMAGE" hdmistat-test.qcow2 $DISK_SIZE
|
||||
}
|
||||
|
||||
# Create cloud-init configuration
|
||||
create_cloud_init() {
|
||||
log "Creating cloud-init configuration..."
|
||||
|
||||
# Create meta-data
|
||||
cat > "${CLOUD_INIT_DIR}/meta-data" << 'EOF'
|
||||
instance-id: hdmistat-test-01
|
||||
local-hostname: hdmistat-test
|
||||
EOF
|
||||
|
||||
# Create user-data with hdmistat installation
|
||||
cat > "${CLOUD_INIT_DIR}/user-data" << 'EOF'
|
||||
#cloud-config
|
||||
hostname: hdmistat-test
|
||||
manage_etc_hosts: true
|
||||
|
||||
users:
|
||||
- name: ubuntu
|
||||
groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
shell: /bin/bash
|
||||
lock_passwd: false
|
||||
passwd: $6$rounds=4096$8VNRmFT9yR$7TVlOepTJjMW0CzBkpMrdWA7aH4rZ94pZng8XjqaY8d8qqBmFvO/hYL5L2gqJ5nKLhDR8Jz9Z9nqfHBl5kVZHe1
|
||||
|
||||
packages:
|
||||
- git
|
||||
- build-essential
|
||||
- wget
|
||||
- fbset
|
||||
|
||||
# Enable SSH (already enabled in cloud images)
|
||||
ssh_pwauth: true
|
||||
|
||||
# Update system
|
||||
package_update: true
|
||||
package_upgrade: false
|
||||
|
||||
write_files:
|
||||
- path: /tmp/install-go.sh
|
||||
permissions: '0755'
|
||||
content: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
GO_VERSION="1.24.4"
|
||||
wget -q -O /tmp/go.tar.gz "https://go.dev/dl/go${GO_VERSION}.linux-arm64.tar.gz"
|
||||
sudo rm -rf /usr/local/go
|
||||
sudo tar -C /usr/local -xzf /tmp/go.tar.gz
|
||||
echo 'export PATH=$PATH:/usr/local/go/bin' | sudo tee -a /etc/profile
|
||||
echo 'export GOPATH=$HOME/go' | sudo tee -a /etc/profile
|
||||
echo 'export PATH=$PATH:$GOPATH/bin' | sudo tee -a /etc/profile
|
||||
|
||||
- path: /tmp/setup-hdmistat.sh
|
||||
permissions: '0755'
|
||||
content: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
export GOPATH=$HOME/go
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
|
||||
# Mount hdmistat source
|
||||
sudo mkdir -p /mnt/hdmistat
|
||||
sudo mount -t 9p -o trans=virtio,version=9p2000.L hdmistat /mnt/hdmistat || echo "Failed to mount hdmistat source"
|
||||
|
||||
# Build hdmistat
|
||||
if [ -d "/mnt/hdmistat" ]; then
|
||||
echo "Building hdmistat from mounted source..."
|
||||
cd /mnt/hdmistat
|
||||
make build
|
||||
sudo cp hdmistat /usr/local/bin/
|
||||
fi
|
||||
|
||||
# Create config
|
||||
sudo mkdir -p /etc/hdmistat
|
||||
sudo tee /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 framebuffer
|
||||
echo "fbcon=map:10" | sudo tee -a /etc/default/grub
|
||||
sudo update-grub || true
|
||||
|
||||
runcmd:
|
||||
- /tmp/install-go.sh
|
||||
- su - ubuntu -c /tmp/setup-hdmistat.sh
|
||||
- echo "hdmistat setup complete! Use 'hdmistat daemon' to start"
|
||||
|
||||
final_message: "hdmistat test environment ready!"
|
||||
EOF
|
||||
|
||||
# Create cloud-init ISO
|
||||
log "Creating cloud-init ISO..."
|
||||
cd "$WORK_DIR"
|
||||
genisoimage -output cloud-init.iso -volid cidata -joliet -rock "${CLOUD_INIT_DIR}/user-data" "${CLOUD_INIT_DIR}/meta-data"
|
||||
}
|
||||
|
||||
# Create run script
|
||||
create_run_script() {
|
||||
cat > "${WORK_DIR}/run-qemu.sh" << EOF
|
||||
#!/bin/bash
|
||||
cd "$WORK_DIR"
|
||||
|
||||
echo "Starting QEMU ARM64 Ubuntu with cloud-init..."
|
||||
echo ""
|
||||
echo "Login: ubuntu / ubuntu"
|
||||
echo "SSH available on port 2223: ssh ubuntu@localhost -p 2223"
|
||||
echo "VNC available on port $VNC_PORT"
|
||||
echo ""
|
||||
echo "hdmistat will be installed automatically via cloud-init"
|
||||
echo "Check cloud-init status with: cloud-init status"
|
||||
echo ""
|
||||
echo "Press Ctrl+A, X to quit"
|
||||
echo ""
|
||||
|
||||
# Find EFI firmware and vars
|
||||
EFI_CODE=""
|
||||
EFI_VARS=""
|
||||
for dir in /nix/store/*/share/qemu /run/current-system/sw/share/qemu; do
|
||||
if [ -f "\$dir/edk2-aarch64-code.fd" ]; then
|
||||
EFI_CODE="\$dir/edk2-aarch64-code.fd"
|
||||
if [ -f "\$dir/edk2-arm-vars.fd" ]; then
|
||||
EFI_VARS="\$dir/edk2-arm-vars.fd"
|
||||
fi
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Create a copy of EFI vars if found
|
||||
if [ -n "\$EFI_VARS" ] && [ ! -f "efivars.fd" ]; then
|
||||
cp "\$EFI_VARS" efivars.fd
|
||||
fi
|
||||
|
||||
BIOS_ARGS=""
|
||||
if [ -n "\$EFI_CODE" ]; then
|
||||
BIOS_ARGS="-bios \$EFI_CODE"
|
||||
if [ -f "efivars.fd" ]; then
|
||||
BIOS_ARGS="\$BIOS_ARGS -drive if=pflash,format=raw,file=efivars.fd"
|
||||
fi
|
||||
fi
|
||||
|
||||
qemu-system-aarch64 \\
|
||||
-M virt \\
|
||||
-accel hvf \\
|
||||
-cpu host \\
|
||||
-smp $QEMU_CPUS \\
|
||||
-m $QEMU_MEM \\
|
||||
-nographic \\
|
||||
-drive file=hdmistat-test.qcow2,format=qcow2,if=virtio \\
|
||||
-drive file=cloud-init.iso,format=raw,if=virtio \\
|
||||
-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 \\
|
||||
-virtfs local,path="${PROJECT_DIR}",mount_tag=hdmistat,security_model=none,id=hdmistat \\
|
||||
\$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 || echo "Connect to VNC at localhost:$VNC_PORT"
|
||||
EOF
|
||||
chmod +x "${WORK_DIR}/view-vnc.sh"
|
||||
|
||||
# SSH helper
|
||||
cat > "${WORK_DIR}/ssh-ubuntu.sh" << EOF
|
||||
#!/bin/bash
|
||||
echo "Connecting to Ubuntu VM..."
|
||||
echo "Password: ubuntu"
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@localhost -p 2223
|
||||
EOF
|
||||
chmod +x "${WORK_DIR}/ssh-ubuntu.sh"
|
||||
}
|
||||
|
||||
# Print instructions
|
||||
print_instructions() {
|
||||
echo ""
|
||||
echo "======================================="
|
||||
echo "QEMU ARM64 Ubuntu Setup Complete!"
|
||||
echo "======================================="
|
||||
echo ""
|
||||
echo "To start testing:"
|
||||
echo " cd $WORK_DIR"
|
||||
echo " ./run-qemu.sh"
|
||||
echo ""
|
||||
echo "Features:"
|
||||
echo " - Ubuntu ${UBUNTU_VERSION} ARM64 with cloud-init"
|
||||
echo " - Native ARM64 virtualization (hvf)"
|
||||
echo " - Automatic hdmistat installation"
|
||||
echo " - Framebuffer support"
|
||||
echo " - SSH access on port 2223"
|
||||
echo " - VNC access on port $VNC_PORT"
|
||||
echo ""
|
||||
echo "The cloud-init config is in: $CLOUD_INIT_DIR/"
|
||||
echo "You can modify it and regenerate the ISO with:"
|
||||
echo " genisoimage -output cloud-init.iso -volid cidata -joliet -rock user-data meta-data"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main
|
||||
main() {
|
||||
log "Setting up QEMU ARM64 Ubuntu environment with cloud-init..."
|
||||
|
||||
check_dependencies
|
||||
setup_directories
|
||||
download_ubuntu
|
||||
create_disk
|
||||
create_cloud_init
|
||||
create_run_script
|
||||
create_helpers
|
||||
print_instructions
|
||||
|
||||
log "Setup complete!"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Verwijs in nieuw issue
Block a user