udpstream: reboot is 1-in-2 on the real unit, not a working hand-back

Attempt 1 (16:58:45) came back: port 771 reopened at 88 s, the unit pinged,
and a VRAM screenshot showed the Terminal Manager.  Attempt 2 (17:04:15,
after a power cycle) never came back -- no ping, no rdebug at 130 s, monitor
asleep, operator reports it stuck.

The previous commit recorded attempt 1 as "it works, no power cycle needed".
That was a single sample and attempt 2 falsified it.  Section 72.3 now records
both runs as a table, the 1-of-2 rate, and the two corrections made on the way
(first "hung", then "works").

Untested hypothesis: the reset path does not reset the LANCE, and the payload
hands over with bus-master DMA enabled; an in-flight transfer or pending
interrupt may leave the board-window handshake at 0xC00000B0/0xC0000100
waiting forever.  The single-variable test would be CSR0_STOP before the jump.

vtcmd.py reboot requires --force again and states the measured rate.
This commit is contained in:
arti committed 2026-10-30 17:06:49 +02:00
1 parent 55236fbf54
commit f1dc5e7f6e
2 files changed
+48 -29

No files matched your search

+37 -26
View File
@@ -4693,38 +4693,49 @@ anyway, which is the condition we reproduce.
MAME evidence: after the reply, the PC leaves the payload (`0x018Cxxxx`) for ROM
(`0x3FB43E40` at the next sample) and the payload stops answering.
### 72.3 It works on the real machine — and a correction
### 72.3 On the real machine it succeeded once and hung the second time — it is NOT reliable
`reboot` was issued on the unit at **16:58:45** while the payload owned the LANCE.
The reply came back (`control -> bit 0x3f200040`, status 0), the payload stopped
answering, and the screen went black.
Two attempts, both issued while the payload owned the LANCE, both acknowledged
(`control -> bit 0x3f200040`, status 0), both followed by a screen that lost
sync (the monitor went to sleep) rather than showing the power-on circle.
**That is POST, not a hang.** Port 771 reopened **88 s** later, the unit answered
ping, and a VRAM screenshot (`dwt/screenshot.py --real`) shows the machine fully
back:
| | attempt 1 | attempt 2 |
|---|---|---|
| time | 16:58:45 | 17:04:15 |
| payload state | `RXF=11` | `RXF=15` (fresh power cycle before it) |
| port 771 back | **yes, at 88 s** | **no**, still down at 130 s |
| ping | yes | no |
| display | Terminal Manager (VRAM screenshot) | monitor asleep, operator: "stuck" |
```
Terminal Manager V2.2 Copyright (C) 1991 Digital Equipment Corporation
Messages: Debug connection from IP host 100.103.255.254
Ethernet Address 08-00-2B-16-4B-5A IP 100.103.100.103
LAT Host Name LAT_08002B164B5A Memory Remaining: 4M
```
Attempt 1 looked like a working hand-back: 88 s later rdebug reopened, the unit
answered ping, and the VRAM screenshot showed the Terminal Manager with
`08-00-2B-16-4B-5A`, `100.103.100.103`, `LAT_08002B164B5A` and the clean-boot
`Ethernet Port Error - 24` banner (section 65).
with the documented `Ethernet Port Error - 24` clean-boot banner (section 65).
So a taken-over unit **can hand itself back without a power cycle**, which was
the point of the command.
**Attempt 2 never came back.** So the reset-vector jump is a **1-in-2** operation
on this machine, and a power cycle is still required when it fails.
**Correction, recorded on purpose.** An earlier reading of this same run called
it "black and hung, needs a power cycle", because the observation was taken
inside the ~90 s POST window. That conclusion was wrong, and it is the exact
mistake this project's own rule 3 warns about — one sample, taken early, reported
as a property. The screen being black is normal: the reset path reprograms the
video window (`0xC00000B0`, `0xC0000100` in the trace above) and does not
re-enable the display until POST is done.
**Hypothesis (untested).** The reset path does not reset the LANCE, and the
payload hands over with the chip started and bus-master DMA enabled. If a
transfer is in flight — or an interrupt is pending — when control jumps, the
firmware's early board-window handshake (`0xC00000B0` / `0xC0000100` in the trace
above) can wait forever, which would look exactly like this: dead display, no
network, no progress. On the successful run the chip happened to be idle.
`vtcmd.py reboot` therefore prints the expected ~90 s and warns not to power
cycle during it. `jump` and `reboot` both transmit their reply and wait for the
descriptor to complete before transferring control, so the host always gets its
The single-variable experiment that would test it: `CSR0_STOP` (and mask
interrupts) immediately before the jump, so the reset path starts with a quiet
LANCE. That has **not** been run.
**Two corrections are recorded here on purpose.** First, an earlier reading of
attempt 1 called it "black and hung, needs a power cycle", because the
observation was taken inside the ~90 s window. Then, after attempt 1 returned,
the opposite claim — "it works, no power cycle needed" — was made from the same
single sample. Attempt 2 falsified that. Both mistakes are the same mistake rule 3
of this project warns about: a conclusion drawn from one observation.
`vtcmd.py reboot` therefore requires `--force` and states that it worked 1 of 2
times. `jump` and `reboot` still transmit their reply and wait for the descriptor
to complete before transferring control, so the host always gets its
acknowledgement first.
### 72.4 There is no vendor reboot to jump to (checked in Ghidra)
+11 -3
View File
@@ -151,6 +151,8 @@ def main():
help="busy-wait instead of time.sleep while pacing; "
"sleep granularity is ~250us and bunches frames "
"into microbursts that the switch drops")
ap.add_argument("--force", action="store_true",
help="reboot: required, it succeeded 1 of 2 times and can hang")
ap.add_argument("--terse", action="store_true",
help="one CSV line per run, for sweeps and for the report")
ap.add_argument("--timeout", type=float, default=2.0)
@@ -190,10 +192,16 @@ def main():
return 0
if a.cmd in ("jump", "reboot"):
if a.cmd == "reboot" and not a.force:
print("refusing reboot without --force.")
print(" It is NOT reliable: 1 success out of 2 attempts on the real")
print(" VT1200. Attempt 1 came back in 88 s; attempt 2 never came")
print(" back (no ping, no rdebug, monitor asleep) and needed a power")
print(" cycle. The screen always loses sync, so the monitor sleeps")
print(" for the whole window. See NETWORK_REPORT.md 72.3.")
return 2
if a.cmd == "reboot":
print("rebooting: the screen goes black while POST runs; the OS is")
print(" back in about 90 s (measured 88 s) and rdebug :771 returns")
print(" on its own. Do not power cycle it during that window.")
print("rebooting: it may take ~90 s and it may never come back.")
cmd = 4 if a.cmd == "jump" else 5
status, data = request(sock, a.iface, cmd, a.addr, 0, a.timeout)
if status is None: