# Win31drv Project Memory ## Build Environment - DJGPP cross-compiler: `~/djgpp/djgpp/bin/i586-pc-msdosdjgpp-gcc` (GCC 12.2.0) - DJGPP binutils need `libfl.so.2`: stored in `tools/lib/` (Makefiles set LD_LIBRARY_PATH) - CWSDPMI zip stored in `tools/cwsdpmi.zip` (extracted to bin/ during build) - DOSBox-X: `flatpak run com.dosbox_x.DOSBox-X` (installed as user flatpak) - CWSDPMI.EXE in `bin/` directory for DPMI support under DOSBox-X - Config: `dosbox-x.conf` with S3 Trio64 machine type, 64MB RAM ## Project Structure ``` windriver/ ├── Makefile # Top-level: builds demo, calls win31drv/Makefile ├── demo.c # Demo program ├── dosbox-x.conf # DOSBox-X config (S3 SVGA) ├── obj/ # Demo object files ├── bin/ # Executables + CWSDPMI.EXE └── win31drv/ # Library ├── Makefile # Builds libwindrv.a ├── obj/ # Library objects ├── neload.c/h # NE format loader ├── neformat.h # NE structures ├── thunk.c/h # 32→16 bit thunking ├── windrv.c/h # Main API ├── winstub.c/h # Windows API stubs ├── winddi.h # DDI structures └── wintypes.h # Win16 types ``` ## DJGPP Portability Notes - `uint32_t` is `unsigned long` (not `unsigned int`) in DJGPP — use `PRIu32`/`PRIX32` from `` - Always include `` explicitly for `va_list`/`va_start`/`va_end` - Headers must be self-contained (include their own dependencies) ## Thunking Architecture Notes - **SS == DS == DGROUP**: Win3.x drivers assume SS == DS == DGROUP. VBESVGA's BBLT.ASM does `PrestoChangeoSelector(SS, WorkSelector)` to create a code alias for compiled blit code. thunkCall16 uses dgroupSel as SS (SP=0xFFF0) when available. Without this, the code alias has the wrong base and the CPU executes garbage. - **Register corruption with -O2 inlining**: When demo.c's demoDrawing is inlined into main, DJGPP GCC 12.2.0 mishandles callee-saved registers across thunk calls in long functions. Fix: `__attribute__((noinline))` on demoDrawing. Symptom: handle pointer corrupted to a ColorInfo return value (e.g. 0xFF0001F6) between Demo 2 and Demo 3. ## DOSBox-X Driver Notes - `waitForEngine()`: GP_STAT port 0x9AE8 bit 9 polling — S3 only (gIsS3 guard) - **S3 detection**: Probe CR30 chip ID register. S3 chips: 0x81-0xE1. ET4000: 0x00. Only apply S3-specific setup (cursor disable, dispYOffset, setDisplayStart) when isS3=true AND driver is not VGA-class (1bpp/4planes). - **Pattern scratch artifact**: S3 driver writes 8x8 dithered brush pattern to VRAM at fixed position (~(144,1)-(151,8)) during accelerated pattern fills. Fixed by shifting CRTC display start down 10 scanlines (`dispYOffset`) so the scratch area is off-screen. - **`-fno-gcse` required for windrv.c**: With -O2 GCSE, stack layout causes issues during 16-bit driver calls. Only windrv.c needs this. See `WINDRV_CFLAGS` in win31drv/Makefile. - Output DDI (polylines/rectangles) requires a **physical pen** from RealizeObject, not a raw LogPen16T. The pen must be in DGROUP (same as brush, drawMode, PDEVICE). - `wdrvUnloadDriver` does NOT auto-call Disable — caller must handle text mode restore - `sleep()` hangs under DOSBox-X because BIOS timer ticks don't advance without I/O - Debug output: `-d` flag enables verbose logging in neload, winstub, thunk, and windrv - Known issue: mode mismatch HW=800x600 vs GDIINFO=640x480 ## DGROUP Stack Management - VGA.DRV ships with DGROUP[0x0A]=0xFFFF (stack bottom = top of segment → no stack). Its BitBlt prolog calls a stack check function at 0x18CA that compares available stack against [SS:0x0A]. With 0xFFFF, ALL functions fail immediately (return 0). - Fix: patch [0x0A] to objBase after extending DGROUP. Only done when original = 0xFFFF. - S3TRIO.DRV and VBESVGA.DRV have [0x0A]=0x0000 — no patching needed. - **Do NOT unconditionally overwrite DGROUP offsets 0x00-0x0F** — VBESVGA.DRV stores driver-specific data there (0x030A at offset 0, 0x01 at offset 4). ## BitBlt Source Device Rules - For pattern-only ROPs (PATCOPY=0xF0, BLACKNESS=0x00, WHITENESS=0xFF, etc.), lpSrcDev must be NULL (0:0) per DDI spec. VGA.DRV rejects non-NULL source for pattern-only ROPs. S3TRIO.DRV tolerates it but correct behavior is NULL. - Source dependency check: `ropNeedsSrc = (((rop8 >> 2) ^ rop8) & 0x33) != 0` ## ExtTextOut DDI Notes - **Font format**: VBESVGA.DRV requires .FNT v3 (fsVersion=0x0300) when BigFontFlags is set (386 protected mode with WF_PMODE + WF_CPU386). v2 (0x0200) is rejected at runtime. - **v3 char table**: at file offset 0x94 (fs30CharOffset), 6-byte entries {WORD width, DWORD offset}. The DWORD offset is absolute from the font segment base. Use FntCharEntry30T. - **Bitmap layout**: per-character contiguous (16 bytes per char for 8x16 font, stride=1 between rows). VGA BIOS 8x16 font (INT 10h AH=11h AL=30h BH=06) is already in this format — no transpose needed. - **lpClipRect must NOT be NULL**: VBESVGA's get_clip unconditionally dereferences lpClipRect (STRBLT.ASM:1008 "We assume that we will never get passed a null rectangle"). Pass a RECT covering the full screen (0, 0, 0x7FFF, 0x7FFF). - **lpTextXForm**: declared but never read by VBESVGA — pass NULL. - **lp_font offset**: passed as fontSel:0x42 (points to fsType within the .FNT block). - **Return value**: DX bit 15 = error. AX=0 is NOT necessarily failure. ## INT 10h ES Translation - Different INT 10h function families use different ES:offset registers: VBE 4Fxx → ES:DI, AH=10h (palette) → ES:DX, AH=11h (fonts) → ES:BP, AH=1Bh → ES:DI - Only specific AL subfunctions use ES as a buffer pointer; most don't - Copy sizes must be exact (17 bytes for palette, CX*3 for DAC blocks, etc.) - Copy direction matters: "Set" = copy-in only, "Read/Get" = copy-out only ## WINFLAGS Handling - **WF_80x87 NOT used**: We don't save/restore FPU state across thunk boundaries - **VGA-class drivers need WF_STANDARD**: VGA.DRV's physical_enable hangs in Enhanced mode (polls VDD that doesn't exist). Auto-detected after Enable(style=1) returns 1bpp/4planes GDIINFO → repatch __WINFLAGS in all segments (0x0025→0x0015). - SVGA drivers (S3TRIO, VBESVGA) use WF_ENHANCED normally ## ET4000 Driver Notes - ET4000.DRV from Win 3.x distribution is SZDD-compressed; decompress with `msexpand` (rename to .DR_ first, output is .DR without the V — rename to .DRV) - DOSBox-X machine type: `svga_et4000` for ET4000 hardware emulation - ET4000 is 640x480 8bpp, software-rendered (no accelerator engine in DOSBox-X) - CR30=0x00 on ET4000 → isS3=false → no S3 engine wait, no display start shift ## Current Demo Status - S3TRIO.DRV, VBESVGA.DRV, VGA.DRV, ET4000.DRV all work: Load → Enable → Draw → Disable → Unload - Demo 1: Fill rectangles (BitBlt) — works - Demo 2: Pixel patterns (Pixel) — works - Demo 3: Lines/starburst (Output/Polyline) — works - Demo 4: Screen-to-screen blit (BitBlt SRCCOPY) — works - Demo 5: ExtTextOut text rendering — works (VBESVGA.DRV) - VGA.DRV: 640x480 4-plane 16-color mode; limited color palette but functional - ET4000.DRV: 640x480 8bpp on svga_et4000; software-only, no hw acceleration - Drivers stored in `drivers/` directory, copied to `bin/` during build