Files
TeslaRel410/emulator/render-bridge/podrun.sh
T
CydandClaude Fable 5 f2687a3146 BT410 5.3.72: the fault caught in the act; the inside view gets its cockpit
VPX_PF_WATCH (fork, cpu/paging.cpp): on a guest page fault at the watched
linear address, dump guest registers, the last 64 serial RX deliveries with
guest cs:eip at each, the code bytes at the faulting EIP and the stack top.
serialnamedpipe's doReceive feeds the ring.  Armed in podrun.sh and
launch_pod.ps1.

The first catch decoded the residual fault completely: CS:EIP 00FF:000066D4
in the DPMI host, EBX = F000CA60 -- an IVT entry read as a dword, segment
F000 offset CA60, a BIOS default interrupt handler -- and the faulting access
is [EBX+0x3004], whose 0x80000000 segment-base wrap gives exactly cr2
7000FA64.  The host probes a word 0x3004 bytes past a real-mode vector value
treated as a flat pointer: harmless for its own low-memory handlers, a fault
for BIOS F000:xxxx defaults.  The serial ring shows a steady 1-byte/1-3ms
vRIO stream with nothing special at the fault -- the stream determines which
vectors get walked, not the crash itself.  The 0x3004 appears nowhere in
DPMI32VM.OVL or 32RTM.EXE as an immediate, so the probe now also dumps code
bytes at EIP; faulthunt.sh loops runs until the next catch.

Shipped baseline streak: 4/4 clean -- consistent with exposure, not yet
discriminating.

The inside view now loads the COCKPIT skeleton: the fleet-wide X-variant
naming convention (MAD->MAX etc., all 64 skeletons present) selects the same
25-joint chain with a single object -- max_cop.bgf, the MAX_COP canopy shell
with the PUNCH-texel windows from the capture forensics.  The donor names the
same mechanism from the decomp side (inside = SkeletonType_A with '_cop'
selection).  Fallback to the body skeleton when no X file exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 18:09:22 -05:00

109 lines
3.8 KiB
Bash

#!/bin/bash
#
# podrun -- stage the current build and start one pod run, keeping the log.
#
# podrun.sh [conf-basename] [tag]
#
# podrun.sh # pod_render_rec.conf, our build
# podrun.sh pod_render_shp # the shipped exe, for A/B
# podrun.sh pod_render_rec noskl
#
# WHY THIS EXISTS
#
# Two traps have each already cost a round of wrong conclusions on this rig:
#
# 1. STALE BINARY. The confs run BTL4REC.EXE out of ALPHA_1/REL410/BT,
# while the build writes build410/btl4opt.exe. Forgetting to copy means
# silently measuring the previous binary. This script always stages and
# always prints the timestamp it staged, so the evidence is in the log.
#
# 2. OVERWRITTEN LOG. serial3 truncates podlog.txt on every launch, so the
# only preserved crash dump on this rig was an accident. Runs are four
# minutes and the defect is intermittent, so a lost log is a lost run.
# Every run is archived to logs/<tag>-<n>.txt when the NEXT one starts.
#
# The rule this rig taught: an intermittent fault needs TWO AGREEING RUNS
# before you believe anything. One run is a story, not evidence.
#
set -e
BR=/c/VWE/TeslaRel410/emulator/render-bridge
IMG=/c/VWE/TeslaRel410/ALPHA_1/REL410/BT
SRC=/c/VWE/TeslaRel410/restoration/build410/btl4opt.exe
CONF=${1:-pod_render_rec}
TAG=${2:-$CONF}
mkdir -p "$BR/logs"
# archive whatever the last run left behind before serial3 truncates it
if [ -s "$BR/podlog.txt" ]; then
N=$(ls "$BR/logs" 2>/dev/null | wc -l)
PREV="$BR/logs/$(printf '%03d' "$N")-prev.txt"
cp "$BR/podlog.txt" "$PREV"
if grep -q "page you don't own" "$PREV"; then
mv "$PREV" "${PREV%-prev.txt}-CRASH.txt"
echo "archived previous run (CRASHED) -> $(basename "${PREV%-prev.txt}-CRASH.txt")"
else
echo "archived previous run -> $(basename "$PREV")"
fi
[ -s "$BR/dosboxlog.txt" ] && cp "$BR/dosboxlog.txt" "$BR/logs/$(printf '%03d' "$N")-dosbox.txt"
fi
if tasklist //FI "IMAGENAME eq dosbox-x.exe" 2>/dev/null | grep -qi dosbox-x; then
echo "killing running dosbox-x"
taskkill //F //IM dosbox-x.exe > /dev/null 2>&1 || true
sleep 2
fi
case "$CONF" in
*shp*)
echo "shipped side -- no staging"
;;
*)
[ -f "$SRC" ] || { echo "no build at $SRC -- run build410.sh link"; exit 1; }
cp -f "$SRC" "$IMG/BTL4REC.EXE"
echo "staged BTL4REC.EXE <- btl4opt.exe $(ls -la "$SRC" | awk '{print $5" bytes "$6" "$7" "$8}')"
;;
esac
#
# HOST-SIDE BOARD ENV. These belong to the VPX device inside DOSBox, not to
# the guest, so they must be exported here. Launching without them does not
# merely disable rendering -- the iserver handshake fails outright with
# "Protocol error : length 65535 too big" and the run dies during boot.
#
WORK="$LOCALAPPDATA/Temp/vwe-pod"
mkdir -p "$WORK"
export VPXLOG="$WORK/vpxresp.txt"
export VPX_RESPOND=1
export VPX_RENDER=1
export VPX_EXPLODE=1
export VPX_DUMPDIR="$WORK"
export VPX_NOMAIN=1
export VPX_CLEAR=0,0,0
export RIO_TAP="$WORK/riotap.txt"
#
# Board stream capture. Without these the run renders but leaves nothing
# to look at afterwards, which on a four-minute rig means re-running just
# to see a frame. FIFOSOCK also lets the render bridge attach live.
#
export VPX_FIFODUMP="$WORK/live.fifodump"
export VPX_FIFOSOCK=8621
#
# Arm the page-fault watch on the residual load-window fault (cpu/paging.cpp
# VPX_PFWatch). When cr2 hits this address the emulator dumps guest state +
# the last 64 serial RX deliveries to its stderr (dosboxlog.txt).
#
export VPX_PF_WATCH=7000FA64
rm -f "$BR/podlog.txt"
cd /c/VWE/TeslaRel410/emulator/src/src
#
# Keep the emulator's own stdout/stderr. The game's stdout comes back over
# COM3, but the DPMI host's exception report and any device-side complaint go
# to the emulator, and those were being thrown away.
#
./dosbox-x.exe -conf "$BR/$CONF.conf" > "$BR/dosboxlog.txt" 2>&1 &
echo "launched $CONF (tag=$TAG) -- pid $!"
echo "watch: tail -f $BR/podlog.txt"