Commit Graph
140 Commits
Author SHA1 Message Date
SDD f3d26ad687 dwt: trace the bottom diagnostics message box to @0xCB640 and the RAM message table 2026-10-18 17:49:13 +03:00
SDD 225394e1ae dwt: xtext draws text in a real X window on the VT1200; TFTP retarget fetches the COFF 2026-10-18 17:28:08 +03:00
SDD 3c16824f5b dwt: record that the owner moved windows on the real unit (extra windows are not a bug) 2026-10-18 17:28:01 +03:00
SDD edc26855fd dwt: full ROM dump over rdebug is byte-identical to vt1200_v22.bin (md5 match) 2026-10-18 17:25:18 +03:00
SDD 09f8607466 dwt/tcpip: LAN TFTP client (100.103.255.254) and a verified self-contained fetch + load on the real unit 2026-10-18 17:12:00 +03:00
SDD efef682b63 dwt/evidence: real-unit Diagnostics dialog and the session-manager hang after the first ROM-test run 2026-10-18 17:07:11 +03:00
SDD e2c18ee70b dwt: NVRAM dump over rdebug (settings block) and LANCE address ROM read; both match the model 2026-10-18 17:06:12 +03:00
SDD 0db6dd2e65 dwt: real-unit menu-driven Ethernet Address ROM test passes (All Diagnostics Passed); 24 is the separate port/termination test 2026-10-18 17:02:55 +03:00
SDD 6195556524 dwt: mailbox_watch.py -- poll 0x27C190/0x16F0 across a boot; results are consumed before rdebug is reachable 2026-10-18 16:57:45 +03:00
SDD 2df00d32e5 dwt: real-unit MOP console works; SHOW reports Monitor Type VR319; TEST refused with DWT IN USE while a window is open 2026-10-18 16:40:19 +03:00
SDD 1c1f804a13 dwt: real X11 app via rdebug -- hostload --real; xhello window on the terminal (status 0, stage 6) 2026-10-18 16:32:58 +03:00
SDD 736e2c84a4 dwt: 50%-pattern real-unit capture at the correct 1280x1024/256-stride geometry 2026-10-18 16:30:30 +03:00
SDD 479d822aca dwt/screenshot: real geometry is 1280x1024 with a 256-byte stride (160B image + 96B mask); --real captures the full screen 2026-10-18 16:26:37 +03:00
SDD 6adc04ba02 dwt/screenshot: --real reads the 1024x2048 interleaved framebuffer and keeps the even rows 1:1; corrects the earlier doubling 2026-10-18 16:22:24 +03:00
SDD 71588e5405 dwt/screenshot: --field even for the real unit's line-interleaved framebuffer; the capture now matches the glass 2026-10-18 16:18:27 +03:00
SDD d6d6a7d44a dwt: real-unit note -- root background is white, TM stipple is a display-mode/fetch effect, not a setting 2026-10-18 16:12:44 +03:00
SDD f696a2e8f6 dwt/screenshot: --stretch for the real unit's 1024->1280 display; record geometry and the background stipple 2026-10-18 16:11:24 +03:00
SDD 4a0e1235c7 dwt: first real-unit contact -- TCP 771 and the computed challenge work; ROM peek matches v2.2; screenshot over peek 2026-10-18 15:55:48 +03:00
SDD 8588340527 dwt/loader: end-to-end host loader over rdebug
hostload.py drives one rdebug connection: jump(malloc) for the COFF buffer,
poke the COFF, poke the loader at 0x01880000, write the descriptor, call the
loader, and verify status 0 plus app evidence (marker cells or xhello stage 6
and a VRAM screenshot). --tftp uses the existing tftpc.bin fetch instead of a
host poke. Adds evidence for two/three fresh boots and appends the integrate
section to dwt/notes/LOADER.md, including the bit-offset result-block layout
and the create_process clobber of the descriptor.
2026-10-18 15:34:25 +03:00
SDD bebc0ccbc1 reference: map the ROM's third-party code -- MIT X11 R4, BSD 4.3 TCP/IP + BIND + telnet, TI RTS, and the font licences 2026-10-18 15:25:43 +03:00
SDD 01923ecb69 dwt/tcpip: map the socket API and fetch a file over TFTP into RAM
The firmware's tftp_open hangs in its resolver from the rdebug process, so
the payload speaks RFC 783 over the firmware socket API: socket(2,2,0),
sendto(RRQ), recvfrom(DATA)/ACK into a malloc'd buffer, close. Verified
live: 600 B fetched from 192.168.99.1 into the malloc buffer, server RRQ
logged, and rdebug peek matches probe.bin byte-for-byte.

Notes: dwt/notes/TCPIP.md (function table, ABI, limits) and the
loader/transport hand-off in dwt/notes/LOADER_CROSS.md.
2026-10-18 15:24:34 +03:00
SDD 139d89a10c dwt/loader: COFF loader places GSPLNK images and runs them via create_process 2026-10-18 15:19:44 +03:00
SDD dcca6bee4d dwt: map the firmware heap -- payload scratch sits inside the largest free block; document malloc/free and add heapmap.py 2026-10-18 14:47:14 +03:00
SDD a94e99579f dwt/gui: injected X window works via create_process
The xserver local service is reachable from a payload, but a connect made
inside the rdebug process is accepted at the service layer and then never
dequeued: the server's accept callback runs (3F34EC50), but no 12-byte X11
setup read follows and Xlib waits in select.

create_process(entry,name,stack,1,arg) from a new process fixes it. xlaunch
creates the child; the server reads the setup (READ12 ret 0x0C), writes the
reply (8 + 0x90), and xhello creates/maps/syncs a 400x200 window. The payload
also had to keep Display* in a11 (callee-saved) instead of reloading it from a
RAM cell, and re-run SETF after each Xlib call.

Final breakpoint-free frame: dwt/gui/evidence/xhello_window_frame2838.png.
ROM untouched (b46a3e442ccb86134d2356bd70d22fd2).
2026-10-18 14:28:58 +03:00
SDD a5769d3d2e dwt: GUI/X architecture note; Xlib callable but XOpenDisplay hangs
Static: the VT1200 GUI is an X11 dix server in ROM plus Xlib clients
(SERVER, SESSIONMGR/Terminal Manager, WM, VTE).  Internal clients use the
local service "xserver" via the display string "0::0"; TCP 6000 is a
separate authorised listener.  Function table and the 4-call hello-window
sequence are in dwt/notes/GUI_APPS.md.

Dynamic: a poke+jump payload proved the firmware ABI (strlen=4) and then
called XOpenDisplay; it never returns (stage 2, display 0, X-server client
watermark unchanged) and the rdebug service dies.  Verdict: hard for a
self-contained window; shared-RAM UI mutation (opcode 8) is the working
route.
2026-10-18 14:08:42 +03:00
SDD c0f142300b dwt/screenshot.py: network screenshot over rdebug peek (VRAM -> PNG), verified against the live OS 2026-10-18 13:49:19 +03:00
SDD 2cc3ab1c79 dwt/exploit.py: default to the computed dwt_prf answer -- echo is the known-failing mode and made a bare --peek look like a closed socket 2026-10-18 11:28:00 +03:00
SDD 0e4075958b dwt: rdebug opcode 8 puts attacker text in the TM Messages box 2026-10-18 11:03:01 +03:00
SDD 619aff0a93 dwt: visual injection -- confirm the persistent box on the live OS, and record that the blink is not established (toggle period is ~1536 frames, not 30) 2026-10-18 03:24:38 +03:00
SDD 05f1895bf5 dwt: visual injection experiments via the returning rdebug jump 2026-10-18 03:22:59 +03:00
SDD 1e5c095b72 dwt: reverse the dwt_prf challenge; remote poke/jump now works
The firmware transforms the reply (16-round Feistel per 8-byte record) and
compares it with the host-order copy of the challenge, so the answer is
swap4(inverse_transform(swap4(challenge))).  The font stages are memcpy in
this path because dwt_prf initialises only mode 1.

challenge.py implements the transform and its inverse using the firmware's
fixed key/SP table; solve.py answers the challenge over TCP using the
unmodified exploit client.  320 forward vectors, the firmware's own inverse
and three live sessions validate it.  A live run with no breakpoints poked
the 82-byte hello-world payload and ran it: MAGIC DEAD/BEEF/0400, VRAM
1024/1024.  Notes and evidence under dwt/notes and dwt/evidence.
2026-10-18 02:36:23 +03:00
SDD 041c82cb73 dwt: runtime oracle and ground-truth vectors for the dwt_prf challenge transform 2026-10-18 02:30:49 +03:00
SDD 5645bb00b3 dwt: exploit client and gate analysis; remote execution blocked at the challenge 2026-10-18 02:20:16 +03:00
SDD 2c7b2e8c2e dwt: gate B is real; challenge args must follow the answer 2026-10-18 02:19:54 +03:00
SDD bd58af3569 dwt: gate A is a 2-bit field and is open; correct the static reading 2026-10-18 02:07:18 +03:00
SDD a18881f45d dwt: MOP console carrier client, protocol notes, and emulator evidence 2026-10-18 02:02:17 +03:00
SDD 0a1042e81f dwt: correct the Done\n reply length (payload includes its NUL, len field = payload+1) 2026-10-18 01:55:56 +03:00
SDD 68a1aeabdc dwt: static analysis of rdebug / DWT console -- poke+jump exist, gated by a config word and a 16-byte handshake 2026-10-18 01:55:41 +03:00
SDD be32e8a138 harness: regenerate duart2_default_tm_frame3000.png -- the cited evidence image predated the LANCE and contradicted the README (no MAC on screen) 2026-10-18 01:21:41 +03:00
SDD 1608a68cdb hello-world: the TMS34010 SDK assembles code that runs on the emulated VT1200
An 82-byte payload written in GSPA assembly, linked at bit 01800000h and
loaded into main RAM by harness/mame/hello.lua, executes on the CPU: it
writes DEAD/BEEF and a 1024-iteration counter into RAM and fills a 256x64
block in video RAM, which appears in the frame dump at x 256..511,
y 136..199.  Entry is a debugger breakpoint on the level-0 menu idle loop,
not a delivery mechanism.  Includes the build script, a COFF .text
extractor (gsprom's hex addresses wrap at 64 KB), the run log, RAM excerpt,
frame crops including a no-load control, and HELLO_WORLD_REPORT.md.
2026-10-18 01:20:38 +03:00
SDD 0c3d24b93b tools/tms34010-sdk: the two dis34 bugs are fixed (af7d3565a5) -- record it, with the 2623/6235-line scale of the correction 2026-10-18 00:55:12 +03:00
SDD af7d3565a5 dis34: print long relative JR as jr and surface B-file SP as b15
The 16-bit-displacement jump (low byte 0x00, two words) is JRcc, not the
three-word JAcc (low byte 0x80).  Printing it as ja made linear
disassembly report the wrong control flow and made every such branch grow
by a word when reassembled.

Register 15 is the stack pointer in either file: 0x0F is A15 and 0x1F is
B15.  The disassembler printed both as sp, hiding B-file stack-pointer
code.  Print b15 when the R bit selects the B file.

Validated with the 1987 TI GSPA/GSPLNK/GSPROM round trip: the 32 KB region
at bit 3F208000 still reassembles byte-for-byte (md5
43adb6669571041985f3e26fd9ff7cb9), as do the 4 KB and 16 KB spans and the
0x8000/3F240000 region.  The converter no longer needs its ja->jr or
sp->b15 rewrites (5 fixups -> 3); a whole-ROM diff contains only those two
output categories.  The ROM is unchanged
(b46a3e442ccb86134d2356bd70d22fd2).
2026-10-18 00:54:34 +03:00
SDD 8bc8d90ea6 tools/tms34010-sdk: record the results -- GSPA (not as34), byte-exact round trip at bit 0x3F208000, 1990 tools are OS/2, dosemu 5x faster, plus the traps 2026-10-18 00:40:25 +03:00
SDD 7d299451da reference: TMS34010 SDK investigation; prove GSPA round trip
The 1987 DOS toolchain (GSPA/GSPLNK/GSPROM) runs under DOSBox and
reassembles 32 KB of the v2.2 ROM byte-for-byte after five documented
fixups to smart34010 output.  The 1990 r5.01 tools are OS/2 NE and do
not run in DOS.  Adds the converter, round-trip script, and the
DOSBox/dosemu benchmark.
2026-10-18 00:39:32 +03:00
SDD 960b256b00 tools/tms34010-sdk: add DOSBOX.md -- how to run the SDK's DOS tools headless and at speed, with measurements 2026-10-18 00:12:18 +03:00
SDD 1ec84abf03 tools: TMS34010 SDK (curated) -- the 1987 ASM/LNK package and the 1990 Code Generation Tools, so the project has an assembler/linker/compiler it was missing; scanned docs excluded 2026-10-17 23:59:24 +03:00
SDD c21cab05f8 harness: net-setup.sh -- recreate the tap+bridge the harness needs (they do not survive a reboot) 2026-10-17 14:15:17 +03:00
arti 307df67f9d harness/mame: the TFTP PCF loader skips BITMAPS, so the n*4 overflow is not on that path
The TFTP font path loads through 3F96B850 and parses with the metadata
reader 3F97EF00, which handles only PROPERTIES/ACCELERATORS/METRICS/
ENCODINGS and silently skips BITMAPS. A font with num_chars=0x40000001
therefore passes the loader (LOADER-A-SUCCESS) without the field ever
being read, and pcfReadBitmaps (3F984970, multiply 3F985050) is never
entered. pcfReadBitmaps has exactly one caller, 3F98BB70, in the X11
font-request reader 3F98AC20, not the TFTP fetch path.

The 'refused after 1024 bytes' of evil-real.pcf is the METRICS table:
its big-endian compressed count 0x00DF is read little-endian as 57088,
so fosAlloc(57088*16) fails at ~906 bytes; BITMAPS (offset 2024) is
never reached.  Baseline.pcf fails the same way; baseline_le.pcf puts
that one 2-byte field in the order the loader reads it, parses cleanly,
and still ignores the crafted BITMAPS count.

No ROM patch, no check disabled, no serve.py edit.  Baselines unchanged:
no env samples=198, stub samples=53.
2026-10-17 14:14:07 +03:00
arti 3a51b95317 harness/fontwork: reproduction scripts for the TFTP Disk-full investigation
Isolated-netns test setup (a private tap-mess-0-0 so a second MAME can run
without holding the owner's tap), the one-file/one-index TFTP servers, the
trace/probe run wrappers, and the two server logs quoted in
FONT_STORAGE_REPORT.md.
2026-10-16 22:03:49 +03:00
arti 7efb4880f0 harness: the TFTP font 'Disk full' is the terminal's own tftp_close, not a storage or map bug
A tcpdump on the tap plus a live execution trace settle the 'Disk full or
allocation exceeded' abort: the TERMINAL sends TFTP error 3, from
tftp_close (0x3F5EC860), which reports an incomplete read (the last DATA
block read was a full 512-byte block) using its fixed text for code 3. It
is not a capacity or disk condition.

The font buffers (path/index read buffer bit 0x9316D0, fos parser stream
buffer 0x227FD0, parsed-font cache 0x227F50) are all in main RAM
(0x00000000-0x01FFFFFF), mapped and writable; the writes land in RAM dumps.
No second map overlap exists, so the NVR fix did not cause this. vt1200.cpp
is unchanged and every baseline is intact.

New: fonttrace.lua, fontprobe.lua, two evidence pcaps, FONT_STORAGE_REPORT.md.
2026-10-16 22:03:16 +03:00