; xtext.asm -- open a window on the live DWT X server and draw text in it. ; ; Run as a first-class process created by the COFF loader (create_process), NOT ; in the rdebug dispatcher's context: a connect made from the rdebug process is ; accepted at the service layer but the server never reads the X11 setup, so ; XOpenDisplay returns an unusable Display. A fresh process works. ; ; This is xhello.asm plus the text path: ; XLoadFont(d,"fixed") 3FD4AE80 ; XCreateGC(d,win,mask,&values) 3F997000 ; XSetForeground(d,gc,1) 3FD99A60 ; XMapWindow(d,win) 3FD645B0 ; XSync(d,0) / XDrawString(...) loop 3FD9F6B0 / 3FDA0000 ; ; The GC is created with a zero value-mask, so the server fills it from the ; screen's default GC (which carries the server's default font, "fixed"). The ; draw is repeated with an XSync between iterations so that it lands after the ; WM has framed/reparented/mapped the window; a single early draw can be lost ; when the window is reparented. ; ; Calling convention (the one the firmware itself uses; see the WM at ; 07F57044 and the TM at 07E5D2B4): ; ; MOVE A14,-*SP,1 ; reserve the slot the callee restores A14 from ; MOVI argN,A0 / MOVE A0,*A14+,1 ; last argument first, upward via A14 ; ... ; MOVI arg0,A0 / MOVE A0,*A14+,1 ; first argument last ; CALLA target ; ; The callee's `rets 2` pops the return address and the reserved slot, so SP is ; restored by the call itself; A14 is restored from that slot. Do NOT keep the ; entry SP/A14 in RAM and restore them after each call: the app's own stack and ; Xlib data structures use the same free heap, and a clobbered saved-SP cell ; turns the next call into a wild push. That exact pattern crashed the first ; version of this payload at XCreateGC. ; ; Xlib clobbers the CPU's SETF field state, so the ABI's 32-bit field 1 is ; re-established after every call. The Display pointer and the window/GC ids ; are kept in callee-saved registers (a11/a10/a12). ; ; Markers live in 224 bytes of zero padding at the end of .text (01842000h), ; NOT in the free heap: the first version's cells at 01895000h were overwritten ; by the OS heap (the string "Exiting\n" landed on them). ; ; 01842000 stage (1 start, 2 display, 3 window, 4 font, 5 GC, 6 setfg, ; 7 map, 8 synced/drawn, 9 flushed, 0FFh failed) ; 01842020 display pointer ; 01842040 font id returned by XLoadFont ; 01842060 window id ; 01842080 GC id returned by XCreateGC ; 018420A0 XSetForeground return ; 018420C0 XMapWindow return ; 018420E0 last XSync return ; 01842100 first XDrawString return ; 01842120 second XDrawString return ; 01842140 final XSync return ; 01841760 strlen("0::0") -- must be 4 ; ; Scratch: 01894000 argument area .text _start: setf 16, 0, 0 setf 32, 0, 1 mmtm sp, a0,a1,a2,a3,a4,a5,a6,a7 movi 1, a0, L move a0, @01842000h, 1 ; stage = 1 ; ---- convention check: strlen("0::0") == 4 -------------------- move a14, -*sp, 1 movi 01894000h, a14, L movi 3FACE948h, a0, L ; ROM "0::0" move a0, *a14+, 1 ; arg0 calla 3FB458D0h ; strlen setf 16, 0, 0 setf 32, 0, 1 move a8, @01842160h, 1 ; MARK strlen movi 4, a0, L cmp a0, a8 jrne failed movi 2, a0, L move a0, @01842000h, 1 ; stage = 2 ; ---- display = XOpenDisplay("0::0") --------------------------- move a14, -*sp, 1 movi 01894000h, a14, L movi 3FACE948h, a0, L move a0, *a14+, 1 ; arg0 = name calla 3F9C2570h ; XOpenDisplay setf 16, 0, 0 setf 32, 0, 1 move a8, a11 ; Display * (callee-saved) move a11, @01842020h, 1 ; MARK display move a11, a11 jreq failed ; ---- root = *(*(display+0x480)+0x40) -------------------------- move *a11(0480h), a10, 1 move *a10(040h), a10, 1 movi 3, a0, L move a0, @01842000h, 1 ; stage = 3 ; ---- window = XCreateSimpleWindow(d,root,100,100,400,200,2,1,0) -- move a14, -*sp, 1 movi 01894000h, a14, L movi 0, a0, L move a0, *a14+, 1 ; background = 0 (black) movi 1, a0, L move a0, *a14+, 1 ; border = 1 (white) movi 2, a0, L move a0, *a14+, 1 ; border width movi 200, a0, L move a0, *a14+, 1 ; height movi 400, a0, L move a0, *a14+, 1 ; width movi 100, a0, L move a0, *a14+, 1 ; y move a0, *a14+, 1 ; x move a10, *a14+, 1 ; parent = root move a11, *a14+, 1 ; display calla 3FD41B90h ; XCreateSimpleWindow setf 16, 0, 0 setf 32, 0, 1 move a8, a10 ; window id move a10, @01842060h, 1 ; MARK window move a10, a10 jreq failed movi 4, a0, L move a0, @01842000h, 1 ; stage = 4 ; ---- font = XLoadFont(display, "fixed") ----------------------- move a14, -*sp, 1 movi 01894000h, a14, L movi FONTNAME, a0, L move a0, *a14+, 1 ; arg1 = name move a11, *a14+, 1 ; arg0 = display calla 3FD4AE80h ; XLoadFont setf 16, 0, 0 setf 32, 0, 1 move a8, a9 ; Font (callee-saved) move a9, @01842040h, 1 ; MARK font move a9, a9 jreq failed movi 5, a0, L move a0, @01842000h, 1 ; stage = 5 ; ---- gc = XCreateGC(d, window, 0, NULL) ---------------------- ; mask 0 -> server default GC values (no value-list to misparse). move a14, -*sp, 1 movi 01894000h, a14, L movi 0, a0, L move a0, *a14+, 1 ; arg3 = values move a0, *a14+, 1 ; arg2 = mask 0 move a10, *a14+, 1 ; arg1 = drawable move a11, *a14+, 1 ; arg0 = display calla 3F997000h ; XCreateGC setf 16, 0, 0 setf 32, 0, 1 move a8, a12 ; GC (callee-saved) move a12, @01842080h, 1 ; MARK gc move a12, a12 jreq failed ; ---- XSetForeground(display, gc, 1) -------------------------- move a14, -*sp, 1 movi 01894000h, a14, L movi 1, a0, L move a0, *a14+, 1 ; arg2 = pixel 1 (white) move a12, *a14+, 1 ; arg1 = gc move a11, *a14+, 1 ; arg0 = display calla 3FD99A60h ; XSetForeground setf 16, 0, 0 setf 32, 0, 1 move a8, @018420A0h, 1 ; MARK setfg movi 6, a0, L move a0, @01842000h, 1 ; stage = 6 ; ---- XMapWindow(display, window) ----------------------------- move a14, -*sp, 1 movi 01894000h, a14, L move a10, *a14+, 1 ; window move a11, *a14+, 1 ; display calla 3FD645B0h ; XMapWindow setf 16, 0, 0 setf 32, 0, 1 move a8, @018420C0h, 1 ; MARK map movi 7, a0, L move a0, @01842000h, 1 ; stage = 7 ; ---- sync + draw, repeated: the WM needs time to frame/map ----- movi 4, a9, L draw_loop: move a14, -*sp, 1 movi 01894000h, a14, L movi 0, a0, L move a0, *a14+, 1 ; discard = 0 move a11, *a14+, 1 ; display calla 3FD9F6B0h ; XSync (flush + round trip) setf 16, 0, 0 setf 32, 0, 1 move a8, @018420E0h, 1 ; MARK last sync ; ---- XDrawString(display, window, gc, 20, 80, msg1, 12) ------ move a14, -*sp, 1 movi 01894000h, a14, L movi 12, a0, L move a0, *a14+, 1 ; arg6 = length movi MSG1, a0, L move a0, *a14+, 1 ; arg5 = string movi 80, a0, L move a0, *a14+, 1 ; arg4 = y movi 20, a0, L move a0, *a14+, 1 ; arg3 = x move a12, *a14+, 1 ; arg2 = gc move a10, *a14+, 1 ; arg1 = window move a11, *a14+, 1 ; arg0 = display calla 3FDA0000h ; XDrawString setf 16, 0, 0 setf 32, 0, 1 move a8, @01842100h, 1 ; MARK draw1 ; ---- XDrawString(display, window, gc, 20, 120, msg2, 10) ---- move a14, -*sp, 1 movi 01894000h, a14, L movi 10, a0, L move a0, *a14+, 1 ; arg6 = length movi MSG2, a0, L move a0, *a14+, 1 ; arg5 = string movi 120, a0, L move a0, *a14+, 1 ; arg4 = y movi 20, a0, L move a0, *a14+, 1 ; arg3 = x move a12, *a14+, 1 ; arg2 = gc move a10, *a14+, 1 ; arg1 = window move a11, *a14+, 1 ; arg0 = display calla 3FDA0000h ; XDrawString setf 16, 0, 0 setf 32, 0, 1 move a8, @01842120h, 1 ; MARK draw2 ; DSJS has a short range; trampoline to the long backward jump. dsjs a9, draw_next jruc draw_done draw_next: jruc draw_loop draw_done: movi 8, a0, L move a0, @01842000h, 1 ; stage = 8 ; ---- final XSync flushes the last PolyText8 ----------------- move a14, -*sp, 1 movi 01894000h, a14, L movi 0, a0, L move a0, *a14+, 1 ; discard = 0 move a11, *a14+, 1 ; display calla 3FD9F6B0h ; XSync setf 16, 0, 0 setf 32, 0, 1 move a8, @01842140h, 1 ; MARK final sync movi 9, a0, L move a0, @01842000h, 1 ; stage = 9 (text drawn and flushed) jruc done failed: movi 0FFh, a0, L move a0, @01842000h, 1 done: mmfm sp, a0,a1,a2,a3,a4,a5,a6,a7 movi 0, a8, L rets MSG1: .byte "HELLO VT1200", 0 MSG2: .byte "text works", 0 FONTNAME: .byte "-DEC-Terminal-Medium-R-Normal--14-140-75-75-C-8-ISO8859-1", 0 ; 224 bytes of padding: marker cells 01842000h..0184217Fh live here. .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .end