Add README.md and expand code comments across all source files
Add comprehensive README covering architecture, API usage, build instructions, tested drivers, binary patching details, and DGROUP layout. Expand file header comments in all library sources and headers to document module responsibilities, data flow, and key constraints. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
431f573422
commit
847db7586b
11 changed files with 445 additions and 22 deletions
12
Makefile
12
Makefile
|
|
@ -1,5 +1,17 @@
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Makefile for windrv demo - Windows 3.x display driver loader for DJGPP/DOS
|
# Makefile for windrv demo - Windows 3.x display driver loader for DJGPP/DOS
|
||||||
|
#
|
||||||
|
# Targets:
|
||||||
|
# all - Build libwindrv.a and demo.exe (default)
|
||||||
|
# lib - Build only libwindrv.a
|
||||||
|
# demo - Build only demo.exe
|
||||||
|
# clean - Remove all build artifacts
|
||||||
|
#
|
||||||
|
# Output:
|
||||||
|
# bin/demo.exe - Demo program
|
||||||
|
# bin/CWSDPMI.EXE - DPMI host (extracted from tools/cwsdpmi.zip)
|
||||||
|
# bin/*.DRV - Driver files (copied from drivers/)
|
||||||
|
# win31drv/libwindrv.a - Static library
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
DJGPP_PREFIX ?= $(HOME)/djgpp/djgpp
|
DJGPP_PREFIX ?= $(HOME)/djgpp/djgpp
|
||||||
|
|
|
||||||
277
README.md
Normal file
277
README.md
Normal file
|
|
@ -0,0 +1,277 @@
|
||||||
|
# win31drv
|
||||||
|
|
||||||
|
A library and demo for loading and using real Windows 3.x display drivers
|
||||||
|
(.DRV files) from 32-bit DOS programs compiled with DJGPP.
|
||||||
|
|
||||||
|
Windows 3.1 shipped with hardware-accelerated display drivers for chipsets
|
||||||
|
like the S3 Trio64 and Tseng ET4000. These drivers are 16-bit NE-format
|
||||||
|
DLLs that implement the Windows DDI (Device Driver Interface). This project
|
||||||
|
loads those drivers into protected mode memory, thunks between 32-bit and
|
||||||
|
16-bit code, stubs the Windows API functions the drivers import, and exposes
|
||||||
|
a clean C API for drawing.
|
||||||
|
|
||||||
|
## Tested Drivers
|
||||||
|
|
||||||
|
| Driver | Chipset | Resolution | DOSBox-X machine type |
|
||||||
|
|---|---|---|---|
|
||||||
|
| S3TRIO.DRV | S3 Trio64 | 800x600 8bpp | `svga_s3trio64` |
|
||||||
|
| VBESVGA.DRV | VESA VBE 2.0 | 800x600 8bpp | `svga_s3trio64` |
|
||||||
|
| VGA.DRV | Standard VGA | 640x480 4-plane | `svga_s3trio64` |
|
||||||
|
| ET4000.DRV | Tseng ET4000 | 640x480 8bpp | `svga_et4000` |
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- **DJGPP cross-compiler**: GCC 12.2.0 targeting `i586-pc-msdosdjgpp`.
|
||||||
|
Expected at `~/djgpp/djgpp/` (override with `DJGPP_PREFIX`).
|
||||||
|
- **CWSDPMI**: Included in `tools/cwsdpmi.zip`, extracted automatically.
|
||||||
|
- **DOSBox-X** (for testing): `flatpak run com.dosbox_x.DOSBox-X`
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```
|
||||||
|
make # Builds libwindrv.a and demo.exe
|
||||||
|
make clean # Removes all build artifacts
|
||||||
|
```
|
||||||
|
|
||||||
|
The build produces:
|
||||||
|
- `win31drv/libwindrv.a` -- the library
|
||||||
|
- `bin/demo.exe` -- the demo program
|
||||||
|
- `bin/CWSDPMI.EXE` -- DPMI host (required to run the demo)
|
||||||
|
|
||||||
|
Driver files from `drivers/` are copied to `bin/` during the build.
|
||||||
|
|
||||||
|
### Running
|
||||||
|
|
||||||
|
Start DOSBox-X with the included configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
flatpak run com.dosbox_x.DOSBox-X -conf dosbox-x.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
Or run manually inside DOSBox-X:
|
||||||
|
|
||||||
|
```
|
||||||
|
C:\BIN> demo.exe S3TRIO.DRV
|
||||||
|
C:\BIN> demo.exe -d VBESVGA.DRV (with debug logging)
|
||||||
|
```
|
||||||
|
|
||||||
|
Output is logged to `OUTPUT.LOG` in the current directory.
|
||||||
|
|
||||||
|
## API Overview
|
||||||
|
|
||||||
|
The public API is declared in `win31drv/windrv.h`.
|
||||||
|
|
||||||
|
### Lifecycle
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "win31drv/windrv.h"
|
||||||
|
|
||||||
|
wdrvInit(); // Initialize library
|
||||||
|
WdrvHandleT drv = wdrvLoadDriver("S3TRIO.DRV");
|
||||||
|
wdrvEnable(drv, 0, 0, 0); // Set video mode (0 = driver defaults)
|
||||||
|
|
||||||
|
// ... draw ...
|
||||||
|
|
||||||
|
wdrvDisable(drv); // Restore text mode
|
||||||
|
wdrvUnloadDriver(drv); // Free driver resources
|
||||||
|
wdrvShutdown(); // Shut down library
|
||||||
|
```
|
||||||
|
|
||||||
|
### Drawing
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Solid rectangle fill (BitBlt with PATCOPY)
|
||||||
|
wdrvFillRect(drv, x, y, w, h, MAKE_RGB(255, 0, 0));
|
||||||
|
|
||||||
|
// Set/get individual pixels
|
||||||
|
wdrvSetPixel(drv, x, y, MAKE_RGB(0, 255, 0));
|
||||||
|
uint32_t color = wdrvGetPixel(drv, x, y);
|
||||||
|
|
||||||
|
// Polyline (Output DDI)
|
||||||
|
Point16T pts[] = {{0, 0}, {100, 100}};
|
||||||
|
wdrvPolyline(drv, pts, 2, MAKE_RGB(0, 0, 255));
|
||||||
|
|
||||||
|
// Screen-to-screen blit
|
||||||
|
WdrvBitBltParamsT bp = { .srcX=0, .srcY=0, .dstX=320, .dstY=240,
|
||||||
|
.width=160, .height=120, .rop3=SRCCOPY };
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
// Direct framebuffer access
|
||||||
|
void *fb = wdrvGetFramebuffer(drv);
|
||||||
|
int32_t pitch = wdrvGetPitch(drv);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
All functions return `WDRV_OK` (0) on success or a negative error code.
|
||||||
|
Use `wdrvGetLastErrorString()` for a human-readable description.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Component Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
demo.c User program
|
||||||
|
|
|
||||||
|
v
|
||||||
|
win31drv/windrv.c Public API, DDI call wrappers, interrupt handlers
|
||||||
|
|
|
||||||
|
+-- win31drv/neload.c NE executable loader (segments, relocations, exports)
|
||||||
|
+-- win31drv/thunk.c 32-bit <-> 16-bit thunking via DPMI
|
||||||
|
+-- win31drv/winstub.c Windows API stubs (KERNEL, GDI, USER, DIBENG)
|
||||||
|
+-- win31drv/log.c Logging to file
|
||||||
|
```
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
1. **NE Loading** (`neload.c`): The driver .DRV file is a 16-bit NE (New
|
||||||
|
Executable) format DLL. The loader reads the MZ+NE headers, allocates
|
||||||
|
16-bit LDT descriptors for each segment via DPMI, loads segment data
|
||||||
|
from the file, and processes relocation records to fix up inter-segment
|
||||||
|
references and imported function addresses.
|
||||||
|
|
||||||
|
2. **Import Resolution** (`winstub.c`): Windows 3.x drivers import
|
||||||
|
functions from KERNEL, GDI, USER, and sometimes DIBENG. The stub layer
|
||||||
|
provides minimal implementations of ~80 functions: memory management
|
||||||
|
(GlobalAlloc/Lock/Free, GlobalDOSAlloc), selector management
|
||||||
|
(AllocSelector, PrestoChangoSelector, SetSelectorBase), system queries
|
||||||
|
(GetVersion, GetWinFlags, GetPrivateProfileString), and more. Each stub
|
||||||
|
is registered as a 16-bit callback via the thunking layer.
|
||||||
|
|
||||||
|
3. **Thunking** (`thunk.c`): The 32-to-16 bit thunking layer bridges
|
||||||
|
DJGPP's 32-bit flat-memory environment with the driver's 16-bit
|
||||||
|
segmented code. A small relay thunk in a 16-bit code segment handles
|
||||||
|
the transition: it receives parameters via a shared data area, sets up
|
||||||
|
a 16-bit stack with DS=SS=DGROUP, far-calls the target function (Pascal
|
||||||
|
calling convention), and captures the DX:AX return value. For callbacks
|
||||||
|
(16-bit driver calling 32-bit stubs), a software interrupt mechanism
|
||||||
|
routes through a registered INT handler that switches to a 32-bit stack
|
||||||
|
and invokes the C callback.
|
||||||
|
|
||||||
|
4. **DDI Wrappers** (`windrv.c`): The main module wraps each DDI function
|
||||||
|
(Enable, Disable, BitBlt, Output, Pixel, RealizeObject, ColorInfo,
|
||||||
|
SetPalette) with proper parameter marshalling. GDI objects (PDEVICE,
|
||||||
|
physical brush, physical pen, draw mode) are embedded within the
|
||||||
|
driver's DGROUP segment so all far pointers share the same selector,
|
||||||
|
matching how Windows 3.1's GDI heap works.
|
||||||
|
|
||||||
|
5. **Interrupt Handlers** (`windrv.c`): Several raw assembly interrupt
|
||||||
|
handlers bridge the gap between the driver's expectations and the DOS
|
||||||
|
environment:
|
||||||
|
- **INT 10h reflector**: Intercepts the driver's video BIOS calls,
|
||||||
|
translates PM selectors to real-mode segments (with transfer buffer
|
||||||
|
bouncing for extended memory), and reflects through DPMI to the
|
||||||
|
real-mode BIOS.
|
||||||
|
- **INT 64h proxy** (DPMI 0x300h): Works around a CWSDPMI bug where
|
||||||
|
INT 31h AX=0300h fails from 16-bit code segments. The driver's
|
||||||
|
DoInt10h is patched to use INT 64h instead.
|
||||||
|
- **INT 2Fh handler**: Responds to the Windows Enhanced Mode
|
||||||
|
installation check (AX=1600h) and VDS/VMM API calls that the
|
||||||
|
driver issues during initialization.
|
||||||
|
- **Exception handlers** (#GP, #PF): Capture fault state with full
|
||||||
|
register dumps before DJGPP's handler (which may crash on faults
|
||||||
|
from 16-bit code).
|
||||||
|
|
||||||
|
### Binary Patching
|
||||||
|
|
||||||
|
The loader applies several patches to the driver's code segments at load
|
||||||
|
time to adapt them for the DOS/DPMI environment:
|
||||||
|
|
||||||
|
- **Prolog/epilog patching**: Converts Win16 `PROLOG_0` sequences
|
||||||
|
(`mov ax, ds; nop; inc bp`) to load the correct DGROUP selector and
|
||||||
|
removes the `inc bp`/`dec bp` frame markers that corrupt frame pointers
|
||||||
|
outside of Windows' stack walker.
|
||||||
|
|
||||||
|
- **DoInt10h INT 31h -> INT 64h**: Redirects the driver's DPMI
|
||||||
|
simulate-real-mode-interrupt call to our proxy handler.
|
||||||
|
|
||||||
|
- **BIOS data area access**: Replaces hardcoded `mov ax, 0040h` with our
|
||||||
|
DPMI selector for the BIOS data area (real-mode segment 0x0040 is
|
||||||
|
invalid in protected mode).
|
||||||
|
|
||||||
|
- **VFLATD bypass**: Forces the DPMI linear framebuffer path instead of
|
||||||
|
the VFLATD VxD path (which requires Windows).
|
||||||
|
|
||||||
|
- **VFLATD stack bug**: Patches a 20-byte stack imbalance in the VFLATD
|
||||||
|
initialization subroutine.
|
||||||
|
|
||||||
|
- **WinFlags repatching**: For VGA-class drivers, changes `WF_ENHANCED`
|
||||||
|
to `WF_STANDARD` after Enable reveals the driver type, preventing a
|
||||||
|
hang in the VDD polling loop.
|
||||||
|
|
||||||
|
### DGROUP Layout
|
||||||
|
|
||||||
|
Windows 3.x drivers expect all GDI objects to reside in DGROUP (the
|
||||||
|
automatic data segment), and SS=DS=DGROUP during function execution. The
|
||||||
|
library extends DGROUP to 64K and allocates objects at fixed offsets:
|
||||||
|
|
||||||
|
```
|
||||||
|
Original driver data: 0x0000 - varies
|
||||||
|
GDI objects:
|
||||||
|
PDEVICE: objBase + 0x0000 (4096 bytes)
|
||||||
|
Physical brush: objBase + 0x1000 (128 bytes)
|
||||||
|
Logical brush: objBase + 0x1080 (16 bytes)
|
||||||
|
Draw mode: objBase + 0x1090 (48 bytes)
|
||||||
|
Physical pen: objBase + 0x10C0 (128 bytes)
|
||||||
|
Logical pen: objBase + 0x1140 (16 bytes)
|
||||||
|
Physical color: objBase + 0x1150 (8 bytes)
|
||||||
|
```
|
||||||
|
|
||||||
|
### S3-Specific Handling
|
||||||
|
|
||||||
|
The S3 Trio64 driver writes an 8x8 dithered brush pattern to a fixed VRAM
|
||||||
|
location during accelerated pattern fills. The library detects S3 hardware
|
||||||
|
by probing CR30 (chip ID register) and shifts the CRTC display start down
|
||||||
|
10 scanlines so this scratch area is off-screen. All drawing Y coordinates
|
||||||
|
are offset to compensate. The GP_STAT register (port 0x9AE8) is polled to
|
||||||
|
wait for the graphics engine to become idle between operations.
|
||||||
|
|
||||||
|
## File Reference
|
||||||
|
|
||||||
|
### Library (`win31drv/`)
|
||||||
|
|
||||||
|
| File | Lines | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `windrv.h` | 189 | Public API: initialization, driver loading, drawing, errors |
|
||||||
|
| `windrv.c` | 3223 | DDI wrappers, GDI object management, interrupt handlers, binary patching |
|
||||||
|
| `neload.h` | 118 | NE loader API |
|
||||||
|
| `neload.c` | 962 | NE format parser: headers, segments, relocations, exports |
|
||||||
|
| `neformat.h` | 215 | NE/MZ header structures, segment/relocation/entry table formats, DDI ordinals |
|
||||||
|
| `thunk.h` | 133 | Thunk layer API |
|
||||||
|
| `thunk.c` | 1021 | 32/16-bit relay, callback dispatch, DOS memory management |
|
||||||
|
| `winstub.h` | 257 | Stub declarations, KERNEL/GDI/USER/DIBENG ordinal constants |
|
||||||
|
| `winstub.c` | 1400 | ~80 Windows API stub implementations |
|
||||||
|
| `winddi.h` | 261 | DDI structures: GDIINFO, PDEVICE, DRAWMODE, brushes, pens |
|
||||||
|
| `wintypes.h` | 153 | Win16 basic types, far pointers, colors, ROP codes |
|
||||||
|
| `log.h` | 37 | Logging API |
|
||||||
|
| `log.c` | 83 | Log file output |
|
||||||
|
|
||||||
|
### Demo and Build
|
||||||
|
|
||||||
|
| File | Description |
|
||||||
|
|---|---|
|
||||||
|
| `demo.c` | Demo program: loads driver, draws rectangles/pixels/lines/blits |
|
||||||
|
| `Makefile` | Top-level build: compiles demo, links with libwindrv.a |
|
||||||
|
| `win31drv/Makefile` | Library build: compiles sources into libwindrv.a |
|
||||||
|
| `dosbox-x.conf` | DOSBox-X configuration for S3 Trio64 testing |
|
||||||
|
| `tools/TEST.BAT` | Quick-test batch file for DOSBox-X |
|
||||||
|
| `drivers/*.DRV` | Windows 3.x display driver binaries |
|
||||||
|
| `tools/cwsdpmi.zip` | CWSDPMI DPMI host (extracted during build) |
|
||||||
|
| `tools/lib/libfl.so.2` | Shared library needed by DJGPP binutils |
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
|
||||||
|
- **Mode mismatch**: The S3 driver configures 800x600 hardware but
|
||||||
|
GDIINFO reports 640x480. Drawing works within the 640x480 region.
|
||||||
|
- **ET4000 is software-only**: DOSBox-X does not emulate the ET4000
|
||||||
|
accelerator engine; all drawing is CPU-rendered by the driver.
|
||||||
|
- **No text output**: ExtTextOut is not yet wired up.
|
||||||
|
- **Single driver instance**: Only one driver can be loaded at a time.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The library code in this repository is original work. The Windows 3.x
|
||||||
|
display driver binaries in `drivers/` are the property of their respective
|
||||||
|
copyright holders and are included for interoperability testing purposes.
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Makefile for win31drv - Windows 3.x display driver library for DJGPP/DOS
|
# Makefile for win31drv - Windows 3.x display driver library for DJGPP/DOS
|
||||||
|
#
|
||||||
|
# Builds libwindrv.a from: log.c neload.c thunk.c winstub.c windrv.c
|
||||||
|
# windrv.c is compiled with -fno-gcse (see WINDRV_CFLAGS below).
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
DJGPP_PREFIX ?= $(HOME)/djgpp/djgpp
|
DJGPP_PREFIX ?= $(HOME)/djgpp/djgpp
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// log.c - Logging to file
|
// log.c - Logging to file
|
||||||
|
//
|
||||||
|
// Simple dual-output logger: messages go to a log file (opened by
|
||||||
|
// logInit) and optionally to stdout (logMsg) or stderr (logErr).
|
||||||
|
// An optional pre-I/O hook is called before every write, used by
|
||||||
|
// windrv.c to ensure the S3 engine is idle before file I/O (DOSBox-X
|
||||||
|
// processes S3 operations during file writes).
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,27 @@
|
||||||
#ifndef NEFORMAT_H
|
#ifndef NEFORMAT_H
|
||||||
#define NEFORMAT_H
|
#define NEFORMAT_H
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// neformat.h - NE (New Executable) binary format structures
|
||||||
|
//
|
||||||
|
// Defines the on-disk structures for the NE executable format used by
|
||||||
|
// Windows 3.x 16-bit DLLs and drivers. An NE file has a DOS MZ stub
|
||||||
|
// header at offset 0, with a pointer at offset 0x3C to the NE header.
|
||||||
|
//
|
||||||
|
// The NE header contains:
|
||||||
|
// - Module metadata (flags, target OS, expected Windows version)
|
||||||
|
// - Offsets to the segment table, entry table, name tables, etc.
|
||||||
|
// - Auto-data segment index (DGROUP) and entry point CS:IP
|
||||||
|
//
|
||||||
|
// Each segment table entry describes one code or data segment with its
|
||||||
|
// file offset, size, flags, and minimum allocation size. Relocation
|
||||||
|
// records follow each segment's data in the file and describe fixups
|
||||||
|
// for inter-segment references, imported functions, and OS fixups.
|
||||||
|
//
|
||||||
|
// Also defines the standard DDI (Device Driver Interface) ordinal
|
||||||
|
// numbers exported by Windows 3.x display drivers.
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,28 @@
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// neload.c - NE (New Executable) format loader
|
// neload.c - NE (New Executable) format loader
|
||||||
//
|
//
|
||||||
// Loads Windows 3.x 16-bit DLLs/drivers into protected mode memory
|
// Loads Windows 3.x 16-bit DLLs/drivers (.DRV files) into protected
|
||||||
// using DPMI to allocate LDT descriptors for 16-bit code/data segments.
|
// mode memory. Each NE segment gets a DPMI LDT descriptor (16-bit
|
||||||
|
// code or data), and the segment data is loaded from the file.
|
||||||
|
//
|
||||||
|
// Loading steps:
|
||||||
|
// 1. Read and validate MZ (DOS stub) + NE headers
|
||||||
|
// 2. Parse the module reference table (imported DLL names)
|
||||||
|
// 3. Parse the resident name table (module name + named exports)
|
||||||
|
// 4. Parse the entry table (ordinal -> segment:offset mappings)
|
||||||
|
// 5. Allocate memory and LDT descriptors for each segment
|
||||||
|
// 6. Load segment data from the file
|
||||||
|
// 7. Process relocations (internal refs, imports by ordinal/name)
|
||||||
|
//
|
||||||
|
// Import resolution is delegated to a caller-supplied callback
|
||||||
|
// (ImportResolverT) which returns a 16:16 far pointer for each
|
||||||
|
// imported function. If the callback returns FARPTR16_NULL, the
|
||||||
|
// loader patches in a stub address and logs a warning.
|
||||||
|
//
|
||||||
|
// Relocations are applied as fixups to the loaded segment data.
|
||||||
|
// Supported fixup types: LOBYTE, SEGMENT, FAR_ADDR (seg:off),
|
||||||
|
// OFFSET, and additive fixups. Chained relocations (linked lists
|
||||||
|
// within the segment) are followed to completion.
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,30 @@
|
||||||
#ifndef WINDDI_H
|
#ifndef WINDDI_H
|
||||||
#define WINDDI_H
|
#define WINDDI_H
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// winddi.h - Windows 3.x Display Driver Interface (DDI) structures
|
||||||
|
//
|
||||||
|
// These packed structures match the binary layout expected by 16-bit
|
||||||
|
// Windows display drivers. They are used to communicate between the
|
||||||
|
// 32-bit host program and the 16-bit driver code via shared memory
|
||||||
|
// in DGROUP.
|
||||||
|
//
|
||||||
|
// Key structures:
|
||||||
|
// GdiInfo16T - Device capabilities, filled by Enable(style=1)
|
||||||
|
// PDevice16T - Physical device descriptor, filled by Enable(style=0)
|
||||||
|
// DrawMode16T - Drawing parameters (ROP2, colors, text spacing)
|
||||||
|
// LogBrush16T - Logical brush input to RealizeObject
|
||||||
|
// LogPen16T - Logical pen input to RealizeObject
|
||||||
|
// DibPDevice16T - DIB engine PDEVICE extension (for software drivers)
|
||||||
|
//
|
||||||
|
// All structures use __attribute__((packed)) to match Win16 layout.
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
#include "wintypes.h"
|
#include "wintypes.h"
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// GDIINFO - Device capabilities structure filled by Enable()
|
// GDIINFO - Device capabilities structure filled by Enable(style=1)
|
||||||
// This is the 16-bit Windows 3.1 DDK GDIINFO structure.
|
// This is the 16-bit Windows 3.1 DDK GDIINFO structure (0x6C bytes).
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,25 @@
|
||||||
// Implements the public windrv.h API by coordinating the NE loader,
|
// Implements the public windrv.h API by coordinating the NE loader,
|
||||||
// thunking layer, and Windows API stubs to load and use Windows 3.x
|
// thunking layer, and Windows API stubs to load and use Windows 3.x
|
||||||
// display drivers from DOS programs compiled with DJGPP.
|
// display drivers from DOS programs compiled with DJGPP.
|
||||||
|
//
|
||||||
|
// This module handles:
|
||||||
|
// - Driver loading: NE module loading, DDI entry point resolution,
|
||||||
|
// binary patching of prologs/epilogs and DPMI workarounds
|
||||||
|
// - Mode setting: two-phase Enable (InquireInfo then EnableDevice),
|
||||||
|
// VRAM mapping, S3 hardware detection and setup
|
||||||
|
// - Drawing: DDI call wrappers for BitBlt, Output, Pixel, ColorInfo,
|
||||||
|
// RealizeObject (brush/pen), and SetPalette
|
||||||
|
// - GDI object management: PDEVICE, physical brush/pen, draw mode,
|
||||||
|
// and physical color buffers are embedded within DGROUP so all far
|
||||||
|
// pointers share the driver's auto-data selector
|
||||||
|
// - Interrupt handlers: INT 10h reflector (PM -> real-mode BIOS),
|
||||||
|
// INT 64h proxy (DPMI 0x300h workaround), INT 2Fh (Enhanced Mode
|
||||||
|
// check), and exception capture (#GP, #PF diagnostics)
|
||||||
|
//
|
||||||
|
// Build note: this file is compiled with -fno-gcse to prevent GCC from
|
||||||
|
// placing stack temporaries at addresses that overlap with memory
|
||||||
|
// corrupted during 16-bit driver calls via thunkCall16. See
|
||||||
|
// WINDRV_CFLAGS in win31drv/Makefile.
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,35 @@
|
||||||
// winstub.c - Windows API function stubs
|
// winstub.c - Windows API function stubs
|
||||||
//
|
//
|
||||||
// Provides minimal implementations of KERNEL, GDI, USER, and DIBENG
|
// Provides minimal implementations of KERNEL, GDI, USER, and DIBENG
|
||||||
// functions that Windows 3.x display drivers import. Each stub is
|
// functions that Windows 3.x display drivers import. Each stub is
|
||||||
// registered as a 16-bit callback via the thunking layer.
|
// registered as a 16-bit callback via thunkRegisterCallback(), giving
|
||||||
|
// it a 16:16 far pointer that the NE loader patches into the driver's
|
||||||
|
// relocation fixups.
|
||||||
//
|
//
|
||||||
// These stubs implement just enough behavior for a display driver to
|
// These stubs implement just enough behavior for a display driver to
|
||||||
// initialize and perform basic drawing operations. Many stubs simply
|
// initialize and perform basic drawing operations:
|
||||||
// return success without doing real work.
|
//
|
||||||
|
// KERNEL (~50 stubs):
|
||||||
|
// - Memory: GlobalAlloc/Lock/Unlock/Free/Realloc/Size,
|
||||||
|
// GlobalDOSAlloc/Free (bump-allocated from a pre-allocated pool),
|
||||||
|
// LocalAlloc/Lock/Free
|
||||||
|
// - Selectors: AllocSelector, FreeSelector, AllocCStoDSAlias,
|
||||||
|
// AllocDSToCSAlias, PrestoChangoSelector, Set/GetSelectorBase,
|
||||||
|
// Set/GetSelectorLimit, SelectorAccessRights
|
||||||
|
// - System: GetVersion (3.10), GetWinFlags (Enhanced + 386),
|
||||||
|
// GetProfileInt, GetPrivateProfileInt/String (returns SYSTEM.INI
|
||||||
|
// values for display driver configuration)
|
||||||
|
// - Module: GetModuleHandle, GetProcAddress, LoadLibrary
|
||||||
|
// - Variable imports: __WINFLAGS, __AHSHIFT, __AHINCR, __A000H,
|
||||||
|
// __B000H, __B800H, __0040H, etc. (resolved as selector values)
|
||||||
|
//
|
||||||
|
// GDI (~8 stubs): GetDeviceCaps, CreateDC, DeleteDC, SelectObject
|
||||||
|
// USER (2 stubs): GetSystemMetrics, MessageBox
|
||||||
|
// DIBENG (9 stubs): DIBBitBlt, DIBOutput, DIBPixel, etc. (return 0
|
||||||
|
// so the driver falls back to its own implementation)
|
||||||
|
// KEYBOARD (1 stub): ScreenSwitchEnable (no-op)
|
||||||
|
//
|
||||||
|
// Stubs that are not implemented return 0 via stubDummy.
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,36 @@
|
||||||
#ifndef WINSTUB_H
|
#ifndef WINSTUB_H
|
||||||
#define WINSTUB_H
|
#define WINSTUB_H
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// winstub.h - Windows API stub layer
|
||||||
|
//
|
||||||
|
// Declares the stub context, initialization/shutdown, and import
|
||||||
|
// resolution functions. Also defines the ordinal numbers for all
|
||||||
|
// stubbed KERNEL, GDI, USER, KEYBOARD, and DIBENG functions.
|
||||||
|
//
|
||||||
|
// The stub context (StubContextT) tracks:
|
||||||
|
// - GlobalAlloc memory blocks and their selectors
|
||||||
|
// - Extra selectors from AllocSelector/AllocCStoDSAlias
|
||||||
|
// - A pre-allocated DOS memory pool for GlobalDOSAlloc
|
||||||
|
// - Well-known memory region selectors (__A000H, __0040H, etc.)
|
||||||
|
// - A lookup table mapping module+ordinal to 16-bit far pointers
|
||||||
|
//
|
||||||
|
// Import resolution flow:
|
||||||
|
// 1. NE loader encounters an imported reference
|
||||||
|
// 2. Calls importResolver -> stubResolveImport
|
||||||
|
// 3. For variable imports (__WINFLAGS, __A000H, etc.): returns the
|
||||||
|
// value directly (selector or constant) in the far pointer
|
||||||
|
// 4. For function imports: looks up the stub table for a matching
|
||||||
|
// module+ordinal entry and returns the 16-bit callback address
|
||||||
|
// 5. Unknown imports: logs a warning and returns FARPTR16_NULL
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "wintypes.h"
|
#include "wintypes.h"
|
||||||
#include "thunk.h"
|
#include "thunk.h"
|
||||||
#include "neload.h"
|
#include "neload.h"
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// Windows API stub layer
|
|
||||||
//
|
|
||||||
// Provides minimal implementations of KERNEL, GDI, and USER functions
|
|
||||||
// that Windows 3.x display drivers import. These stubs are registered as
|
|
||||||
// 16-bit callbacks via the thunking layer so the driver can call them.
|
|
||||||
//
|
|
||||||
// Supported modules:
|
|
||||||
// KERNEL - Memory management (GlobalAlloc/Lock/Free), module queries,
|
|
||||||
// selector management, system info
|
|
||||||
// GDI - Minimal DC management, palette, object stubs
|
|
||||||
// USER - GetSystemMetrics, MessageBox (stub)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Stub context
|
// Stub context
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,19 @@
|
||||||
#ifndef WINTYPES_H
|
#ifndef WINTYPES_H
|
||||||
#define WINTYPES_H
|
#define WINTYPES_H
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// wintypes.h - Windows 16-bit type definitions and constants
|
||||||
|
//
|
||||||
|
// Provides the fundamental types used by the Win16 API and DDI:
|
||||||
|
// basic integer types (WORD, DWORD, BOOL16), 16-bit handle types,
|
||||||
|
// far pointer (segment:offset) helpers, COLORREF, geometry types
|
||||||
|
// (Point16T, Rect16T), GetWinFlags constants, GlobalAlloc flags,
|
||||||
|
// and raster operation codes (ROP2 and ROP3).
|
||||||
|
//
|
||||||
|
// Uses stdint.h types for portability (DJGPP's uint32_t is unsigned
|
||||||
|
// long, not unsigned int).
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue