Files
Deshab-OS/CODE/linux/qemu_verify_loop.sh
T

178 lines
6.1 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Headless QEMU verify: Linux guest park + native desktop + KDE scanout.
set -Eeuo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
IMG="${IMG_OVERRIDE:-$ROOT/ISO/deshab-dev.img}"
LOG="${QEMU_SERIAL_LOG:-/home/deshab/qemu_serial_loop1.log}"
MON="${QEMU_MONITOR:-telnet:127.0.0.1:45454,server,nowait}"
TIMEOUT="${QEMU_VERIFY_TIMEOUT:-480}"
SEND_KDE="${QEMU_SEND_KDE:-1}"
SERIAL_TCP="${QEMU_SERIAL_TCP:-127.0.0.1:45455}"
rm -f "$LOG"
: > "$LOG"
export IMG_OVERRIDE="$IMG"
export QEMU_SERIAL_LOG="$LOG"
export QEMU_DISPLAY=none
export QEMU_MONITOR="$MON"
export QEMU_SERIAL_TCP="$SERIAL_TCP"
# Do not attach the AHCI SATA *sidecar*. The boot disk is already AHCI
# (ISO/deshab-dev.img). The old sata_fat32_dsk.img hid ESP deshab.elf.
export SATA_IMG_OVERRIDE="/tmp/deshab-verify-no-sata"
export NVME_IMG_OVERRIDE="/tmp/deshab-verify-no-nvme"
export USB_IMG_OVERRIDE="/tmp/deshab-verify-no-usb"
echo "[verify] starting QEMU, log=$LOG timeout=${TIMEOUT}s serial_tcp=$SERIAL_TCP"
cd "$ROOT/ISO"
# Strip CRLF if the script was edited on Windows.
sed -i 's/\r$//' ./run_qemu_kvm.sh 2>/dev/null || true
bash ./run_qemu_kvm.sh &
QEMU_PID=$!
cleanup() {
set +e
if kill -0 "$QEMU_PID" 2>/dev/null; then
kill "$QEMU_PID" 2>/dev/null || true
sleep 1
kill -9 "$QEMU_PID" 2>/dev/null || true
fi
}
trap cleanup EXIT
log_text() {
# Serial logs often contain CR / NUL; strip so grep anchors work.
tr -d '\r\0' < "$LOG" 2>/dev/null || true
}
log_has() {
log_text | grep -qE "$1"
}
send_serial() {
local msg="$1"
local host="${SERIAL_TCP%%:*}"
local port="${SERIAL_TCP##*:}"
python3 - "$host" "$port" "$msg" <<'PY' || true
import socket, sys
host, port, msg = sys.argv[1], int(sys.argv[2]), sys.argv[3]
s = socket.create_connection((host, port), 3)
s.sendall(msg.encode())
s.close()
PY
}
sent_kde=0
dsk_started=0
plasma_painted=0
deadline=$((SECONDS + TIMEOUT))
guest_ok=0
session_ok=0
kde_ok=0
desktop_ready=0
while kill -0 "$QEMU_PID" 2>/dev/null && [[ $SECONDS -lt $deadline ]]; do
if log_has 'EXEC_READY received from /dev/utsm' && \
log_has 'guest parked \(daemon ready\)'; then
guest_ok=1
fi
if log_has '\[DSK\] session=(kde|native)$' || \
log_has '\[DSK\] session=ask, waiting for 1/2'; then
session_ok=1
fi
if log_has 'desktop ready'; then
desktop_ready=1
fi
if log_has 'session=ask, waiting for 1/2'; then
if [[ "$SEND_KDE" == "1" && "$sent_kde" == "0" ]]; then
sleep 1
echo "[verify] sending serial 2 for KDE (chooser)"
send_serial '2'
sent_kde=1
fi
fi
if [[ "$desktop_ready" == "1" && "$SEND_KDE" == "1" && "$sent_kde" == "0" ]]; then
echo "[verify] sending serial 2 for KDE (native desktop)"
send_serial '2'
sent_kde=1
deadline=$((SECONDS + 180))
fi
# "Plasma failed" is sometimes dropped by kmsg. The loader error
# and the chroot exit status are the ones that actually reach serial.
if log_has '\[deshab-kde\] Plasma failed|invalid ELF header|error while loading shared libraries|exited with status [1-9]|fatal signal'; then
kde_ok=3
elif log_has '\[deshab-kde\] starting Plasma'; then
kde_ok=1
elif [[ "$kde_ok" != "1" ]] && \
log_has 'KDE preflight missing|KDE scanout timeout|KDE failed|could not bind|chroot session exited'; then
kde_ok=3
elif [[ "$kde_ok" == "0" ]] && \
log_has 'serial 2: launch KDE|kde: launching fullscreen Plasma|KDE host loop|KDE spawned|\[deshab-kde\] interpreter alive|\[deshab-kde\] entering KDE'; then
kde_ok=2
fi
# P9: Plasma 只活着还不够,必须真的推帧。Xorg/modesetting 每次提交
# 都发 RESOURCE_FLUSH;utsm.elf 里加了 FLUSH_N 计数日志(每 64 次一行)。
# starting Plasma 之后出现 FLUSH_N 才算 Plasma 画了。
if [[ "$kde_ok" == "1" ]]; then
if log_has '\[VGPU\] FLUSH_N'; then
plasma_painted=1
fi
fi
# drm fbdev SET_SCANOUT at boot is not Plasma. "entering KDE" only
# means the session reached the chroot setup, not that Plasma painted.
if [[ "$kde_ok" == "1" ]] && [[ "$guest_ok" == "1" ]]; then
if [[ "$sent_kde" == "1" ]]; then
sleep 60
else
sleep 8
fi
# starting Plasma is logged before the child returns. Recheck
# after the wait so a 127 during this window is not a false OK.
if log_has '\[deshab-kde\] Plasma failed|invalid ELF header|error while loading shared libraries|exited with status [1-9]|fatal signal'; then
kde_ok=3
elif log_has '\[VGPU\] FLUSH_N'; then
plasma_painted=1
break
else
break
fi
fi
if [[ "$guest_ok" == "1" && "$session_ok" == "1" && "$kde_ok" == "3" ]]; then
sleep 20
break
fi
if [[ "$dsk_started" == "0" ]] && log_has '\[DSK\] FUCK config loaded'; then
dsk_started=1
deadline=$((SECONDS + 240))
echo "[verify] DSK started, extending wait 240s"
fi
sleep 2
echo "[verify] t=${SECONDS}s log=$(wc -c < "$LOG" 2>/dev/null || echo 0) guest=$guest_ok session=$session_ok desktop=$desktop_ready kde=$kde_ok"
done
echo "===== VERIFY SUMMARY ====="
echo "guest_ok=$guest_ok session_ok=$session_ok kde_ok=$kde_ok sent_kde=$sent_kde desktop_ready=$desktop_ready plasma_painted=$plasma_painted"
echo "----- markers -----"
log_text | grep -E 'EXEC_READY|guest parked|session=ask|session=kde|session=native|KDE |Linux guest|FUCK config loaded|switch_root|utsm-linux|desktop ready|serial 2|FAT32 volume LBA|desktop load|user/desktop|VGPU|scanout|FLUSH|deshab-kde|vdc|persist|segfault|fatal signal|Xorg.0.log|Fatal server|overlay' | tail -n 120 || true
if [[ "$guest_ok" != "1" || "$session_ok" != "1" ]]; then
echo VERIFY_FAIL
exit 1
fi
if [[ "$kde_ok" == "1" ]]; then
if [[ "$plasma_painted" == "1" ]]; then
echo VERIFY_KDE_PLASMA_OK
exit 0
else
echo VERIFY_KDE_ALIVE_NO_FRAME
exit 1
fi
fi
if [[ "$kde_ok" == "2" ]]; then
echo VERIFY_KDE_SPAWNED
exit 1
fi
echo VERIFY_PARTIAL_OK
exit 1