INT 21h is what DOS programs call when they need the operating system: files, directories, memory, launching children, device checks, and compatibility probes. This page is the end-user map of what LainDOS can answer today.
How to read this
If a DOS game starts, opens its data files, launches overlays, saves, and exits back to the shell, it is mostly living on this page. BIOS calls still handle hardware like keyboard, video, disk sectors, timers, and sound devices; INT 21h is the DOS contract layered above that hardware.
Target
games + utilities
Version
DOS 3.30 identity
Calls
68 AH branches
All recognized calls
This is every AH value the current INT 21h dispatcher recognizes. Supported means the behavior is backed by real state or disk data in LainDOS. Partial, narrow, compat, and stub mean the call exists for the compatibility surface games and tests currently need, but it should not be read as full MS-DOS coverage.
Console, keyboard, and drive selection
00h
Terminate program
supported
Same termination path as INT 20h; AL becomes the stored return code.
01h
Read char with echo
supported
Blocks for a key and echoes normal characters to the console.
02h
Write character
supported
Writes DL to the LainDOS console.
06h
Direct console I/O
supported
DL=FFh polls/reads with ZF status; other DL values print one character.
07h
Direct char input
supported
Reads a key without echo.
08h
Char input without echo
supported
Reads a key without echo.
09h
Print $ string
supported
Prints DS:DX until $, the classic DOS string output call.
0Ah
Buffered line input
supported
Fills the DOS line buffer, including backspace handling and the final CR.
0Bh
STDIN status
supported
Returns FFh when console input is waiting, 00h otherwise.
0Ch
Flush input then read
supported
Clears pending input and dispatches the requested console read function.
0Eh
Select default drive
supported
Updates the current mounted drive letter and returns the drive count.
Drive, DTA, country, version, and probes
19h
Get current drive
supported
Returns AL=0 for A:, 1 for B:, etc.
1Ah
Set DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results.
supported
Stores DS:DX as the Disk Transfer AreaDTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results. for find calls.
1Bh
Default drive data
supported
Returns FAT layout data for the current drive.
1Ch
Drive data
supported
Returns FAT layout data for a requested drive.
25h
Set interrupt vector
supported
Writes an IVTIVTThe table at physical address zero containing 256 far pointers for CPU, BIOS, and DOS interrupts. entry from DS:DX.
29h
Parse filename into FCB
narrow
Covers parser semantics used by compatibility probes; handle APIs are preferred.
2Ah
Get date
supported
Returns the stored DOS date and weekday.
2Bh
Set date
supported
Accepts valid 1980-2099 dates and recomputes weekday.
2Ch
Get time
supported
Uses BIOSBIOSFirmware services available before DOS exists; it loads the boot sector and provides interrupts such as INT 13h disk I/O. ticks until a DOS time has been set.
2Dh
Set time
supported
Stores a DOS-visible time after range validation.
2Eh
Set verify flag
compat
Stores the flag; disk writes are still explicit in LainDOS.
2Fh
Get DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results.
supported
Returns ES:BX for the current DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results..
30h
Get DOS version
supported
Reports DOS 3.30 style identity.
31h
Terminate and stay resident
partial
Keeps the PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer.MCBMCBA 16-byte DOS memory header that describes the allocated or free block immediately after it. resident, frees non-resident child-owned MCBs, and reports TSR return type.
33h
Ctrl-Break state
partial
Supports get/set break flag, boot drive query, and true-version query.
35h
Get interrupt vector
supported
Reads an IVTIVTThe table at physical address zero containing 256 far pointers for CPU, BIOS, and DOS interrupts. entry into ES:BX.
36h
Get disk free space
supported
Counts free clusters from the real FAT.
38h
Country information
partial
Returns a small default country table and accepts country 1.
50h
Set PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer.
compat
Updates the current PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer. segment for runtimes that temporarily switch DOS process context.
51h
Get PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer.
supported
Alias for AH=62h; returns the current PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer. segment in BX.
52h
List of lists
compat
Returns a minimal internal DOS data pointer.
54h
Get verify flag
compat
Returns the stored verify flag.
5Dh
DOS internal
stub
Supports AX=5D06h with a minimal swappable-data-area pointer; other subfunctions fail.
60h
Truename
compat
Canonicalizes 8.3 paths with drive, current directory, dot, and dot-dot handling.
63h
Get DBCS table
compat
Returns an empty DBCS lead-byte table for single-byte code page setups.
66h
Global code page
compat
Reports and accepts the default 437 code page used by Norton Commander-style startup probes.
71h
Windows LFN family
compat
Always fails with AX=7100h so callers can detect unsupported long filename services and fall back.
Directories, files, and save-game writes
39h
Make directory
supported
Creates a FAT directory with initialized dot entries.
Handles root, .., subdirectories, and drive-qualified paths.
3Ch
Create/truncate file
supported
Creates a new handle or truncates an existing writable closed file.
3Dh
Open file
supported
Opens files and DOS device names using the requested access mode.
3Eh
Close file
supported
Closes handles and flushes table metadata where needed.
3Fh
Read file/device
supported
Reads through a sector cache and advances file position.
40h
Write file/device
supported
Extends files, allocates clusters, updates size, and invalidates read cache.
41h
Delete file
supported
Rejects directories, read-only files, and open files before freeing clusters.
42h
Seek
supported
Supports DOS seek origins and 32-bit positions.
43h
Get/set attributes
supported
Mutable bits can be changed; directory/volume identity is protected.
56h
Rename
supported
Same-directory rename with read-only/open-handle guards.
57h
Get/set file time
supported
Reads or writes directory timestamp fields for an open handle.
5Ah
Create temporary file
supported
Generates LDxxxx.TMP style names under the requested path.
5Bh
Create new file
supported
Fails if the target already exists.
68h
Commit file
supported
Flushes handle directory entry and FAT for file handles.
Handles, devices, processes, and memory
44h
IOCTL
partial
Supports device info probes, input/output status, removable/local drive, and local handle checks.
45h
Duplicate handle
supported
Creates aliases for table handles or implicit console std handles.
46h
Force duplicate handle
supported
Replaces the destination handle with an alias/source device mapping.
48h
Allocate memory
supported
Allocates paragraphs from the MCBMCBA 16-byte DOS memory header that describes the allocated or free block immediately after it. arena.
49h
Free memory
supported
Releases an MCBMCBA 16-byte DOS memory header that describes the allocated or free block immediately after it.-owned block.
4Ah
Resize memory
supported
Shrinks or grows blocks when adjacent free space permits.
4Bh
EXEC
partial
Supports AL=00h load-and-run, AL=03h overlay load, child-owned environment copies with executable path tails, and inherited child PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer. JFT entries.
4Ch
Terminate with return code
supported
Stores AL and returns control to the parent or shell.
4Dh
Get return code
supported
Returns and clears the last child return code and termination type.
58h
Allocation strategy
supported
Supports get/set for first, best, and last fit.
62h
Get PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer.
supported
Returns the current PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer. segment in BX.
67h
Set handle count
stub
Refreshes fixed PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer. JFT metadata; LainDOS still uses MAX_HANDLES=20.
Directory search
11h
FCB FindFirst
narrow
Searches the current directory from a normal or extended FCB, honoring the extended attribute mask, and writes AL status plus a drive byte/raw directory entry into the DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results..
Returns the current directory path without the drive prefix.
4Eh
FindFirst
supported
Stores search state in the DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results. and returns the first matching entry.
4Fh
FindNext
supported
Continues the DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results.-backed directory search.
Subfunction boundaries
A recognized AH value does not always mean every AL subfunction exists. These are the narrow edges users are most likely to notice when a program probes DOS behavior.
AH=33h
Ctrl-Break
AL=00h gets the stored break flag, AL=01h sets it, AL=05h returns the boot drive, and AL=06h returns the true DOS version. Other subfunctions fail with function-number error.
AH=38h
Country
AL=00h/01h read the small default table; AL=FFh accepts country BX=1. Full international formatting tables are intentionally deferred.
AH=63h
DBCS
AL=00h returns DS:SI pointing at an empty lead-byte table; other subfunctions fail with function-number error.
AH=66h
Code page
AL=01h returns active/system code page 437; AL=02h accepts setting active code page BX=437. Other subfunctions fail with function-number error.
AH=5Dh
DOS internal
AX=5D06h returns DS:SI for a minimal swappable-data-area header with current DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results., PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer., return code/type, and drive fields; other subfunctions fail.
AH=71h
LFN unsupported
All Windows long-filename subfunctions fail with CF set and AX=7100h, matching the fallback signal expected by DJGPP-era callers.
AH=44h
IOCTL
AL=00h reads device information, AL=01h is accepted as the same compatibility answer, AL=06h/07h report input/output status, and AL=08h/09h/0Ah report local drive or handle state.
AH=4Bh
EXEC
AL=00h loads and runs a child program; AL=03h loads an overlay. Load-but-do-not-execute and other EXEC variants are not implemented yet.
AH=58h
Allocator
AL=00h gets the strategy and AL=01h sets strategy BL=0/1/2 for first/best/last fit. Other values fail with function-number error.
Console and shell basics
covered
AH=01h,02h,06h,07h,08h,09h,0Ah,0Bh,0Ch,0Eh
Ready for text-mode installers, utilities, and the LainDOS shell.
These calls are the classic DOS way to print strings, read keys, poll the keyboard, and select the current drive. LainDOS routes them through the same console layer that writes to VGAVGAThe PC video standard LainDOS and the demos use for text and graphics output. text memory and COM1COM1The first PC serial port. LainDOS uses it as the primary machine-readable debug log., so user-visible text also appears in the serial logserial logCaptured COM1 text output, used by tests to detect PASS, FAIL, exceptions, and unhandled DOS calls. when useful.
For end users this means simple command-line tools, batch files, and setup programs have the basic terminal behavior they expect. It is not a full ANSI terminal, but it covers the plain DOS console style used by the current test ladder.
›src/kernel/int21.incNASM · 16-bit
108
109
110
111
114
115
120
121
cmp ah, 0x09
je .print_string
cmp ah, 0x01
je .read_char_echo
cmp ah, 0x06
je .direct_console_io
cmp ah, 0x0A
je .read_line_buffered
Registers & state after
AHfunctionconsole service number
DLchar/driveAH=02h prints DL; AH=0Eh selects drive DL
CFclearsuccessful console calls return without carry
The core file API is in place for real game data and save writes.
This is the compatibility surface most games hit first: make and remove directories, change directory, create/open/close/read/write/seek files, delete, rename, get or set attributes, get or set file timestamps, create temporary files, create-new, and commit writes.
LainDOS deliberately handles real FAT writeback here: truncating an existing writable file frees its old cluster chain, writes update file size and directory metadata, rename refuses read-only/open files, and commit flushes both the directory entry and FAT.
›src/kernel/int21.incNASM · 16-bit
140
141
142
143
146
147
148
149
222
223
cmp ah, 0x3C
je .create_file
cmp ah, 0x3D
je .open_file
cmp ah, 0x3F
je .read_file
cmp ah, 0x40
je .write_file
cmp ah, 0x56
je .rename_file
Registers & state after
DS:DXpath/bufferpathnames for open/create/delete; buffer for read/write
BXhandlefile handle for close/read/write/seek/time/commit
AXresulthandle, byte count, or DOS error code if CF is set
Shell-launched COM/EXE programs, overlays, TSR exits, and PSP probes are supported.
When SHELL.COM starts another program, it uses EXEC. LainDOS loads the child image, builds a PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer., supplies the command tail and child-owned environment, inherits the parent's fixed PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer. handle table, applies EXE relocations, and restores the parent after the child exits.
The default environment includes COMSPEC, PATH, PROMPT, and a conventional SB16SB16Sound Blaster 16 audio hardware. QEMU exposes the DSP path with -device sb16; some games also need the separate -device adlib OPL path. BLASTER string so games launched under QEMUQEMUThe default fast emulator for automated LainDOS builds, tests, monitor probes, and game smoke runs.'s -device sb16 can detect the emulator-provided sound card.
For users this is why typing midemo at A:\> works instead of needing a direct-boot image. The same path also supports overlay loads, TSR-style keep-process exits used by runtime helpers such as DPMIDPMIDOS Protected Mode Interface, the service layer many protected-mode DOS programs expect from an extender or host. hosts, and set/get PSPPSPThe DOS data block placed before each program, holding terminate vectors, the job file table, command tail, and environment pointer. probes used by older runtimes.
›src/kernel/int21.incNASM · 16-bit
214
215
216
217
1908
1909
1938
1942
1945
cmp ah, 0x50
je .set_psp
cmp ah, 0x51
je .get_psp
.exec:
cmp al, 0
call load_exec_program
call exec_com_dyn
call setup_exe_dyn
Registers & state after
AH4BhEXEC
AL00h/03hload-and-run program or load overlay
ES:BXparamsEXEC parameter block supplied by the parent
Directory searches work across the current directory and drive-qualified paths.
DOS programs do not get directory listings as one big array. They set a Disk Transfer AreaDTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results., call FindFirst with a wildcard and attribute mask, then call FindNext until DOS reports no more matches.
LainDOS stores search state in the DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results. and understands root paths, subdirectories, drive-qualified relative paths, wildcard attributes, timestamps, and current-directory queries.
Older DOS programs may also use FCB FindFirst/FindNext. LainDOS covers the current-directory 8.3 search path needed by Civilization startup, including extended-FCB attribute masks, returning AL status and a drive byte plus raw directory entry at the DTADTAThe DOS buffer where FindFirst/FindNext and some FCB calls return directory search results..
›src/kernel/int21.incNASM · 16-bit
128
129
130
131
176
177
210
211
212
213
551
595
4356
4396
cmp ah, 0x11
je .fcb_find_first
cmp ah, 0x12
je .fcb_find_next
cmp ah, 0x1A
je .set_dta
cmp ah, 0x4E
je .find_first
cmp ah, 0x4F
je .find_next
.fcb_find_first:
call .fcb_store_dta
call store_find_dta
call store_find_dta
Registers & state after
DS:DXFCB/DTA/pathFCB for AH=11h/12h; DTA pointer for AH=1Ah; search path for AH=4Eh
Conventional-memory allocation is backed by a real MCB chain.
DOS games ask for memory in 16-byte paragraphs. LainDOS tracks those allocations with Memory Control Blocks, supports allocate/free/resize, and exposes allocation strategy so programs that probe DOS behavior see plausible first-fit, best-fit, and last-fit behavior.
This matters for older games and utilities that inspect the largest executable program size, allocate temporary buffers, or expect parent and child processes to release their memory cleanly.
Common DOS device checks and standard handles are implemented.
Programs often ask DOS whether a handle is a character device, whether input is ready, whether output can proceed, or whether a drive is removable/local. Those checks go through IOCTL rather than normal file reads.
LainDOS answers the IOCTL functions used by the current suite and maps DOS device names so tools can open CON, write to NUL, duplicate handles, or detect console readiness without creating fake files on disk.
Compatibility probes return stable DOS-like answers or explicit unsupported-LFN status.
Many programs do not immediately open files. They first ask DOS what version it is, what drive is current, how much disk space is free, what the date/time is, or where an interrupt vector points.
LainDOS answers these probes with DOS 3.30-style behavior where that helps old games, returns real disk-free counts from the FAT, keeps enough vector/date/verify state for installers and utilities to continue, and includes narrow FCB compatibility used by older probes and launchers.
Newer DOS-extender runtimes also hit internal and Windows-era compatibility probes. LainDOS now canonicalizes truename paths, returns a minimal DOS swappable-data-area pointer for AX=5D06h, and reports unsupported long-filename APIs with AX=7100h so DJGPP-style callers can fall back to 8.3 searches.
›src/kernel/int21.incNASM · 16-bit
198
199
204
205
206
207
234
235
246
247
775
776
cmp ah, 0x30
je .get_version
cmp ah, 0x35
je .get_vector
cmp ah, 0x36
je .get_disk_free
cmp ah, 0x5D
je .dos_internal
cmp ah, 0x71
je .lfn_unsupported
.get_version:
mov ax, 0x1E03
Registers & state after
AX1E03hAL=03h, AH=1Eh reports DOS version 3.30
DLdrive0=current, 1=A:, 2=B:, etc. for drive queries
LainDOS is not trying to be a replacement for every DOS installation. It grows from target programs and regression tests, so unsupported APIs are treated as new compatibility work rather than hidden magic.
todoNetworking, redirectors, SHARE/locking, printing, CONFIG.SYS device drivers, and full country-table behavior are outside the current game target set.
todoFCB compatibility is intentionally narrow: filename parsing plus current-directory FCB FindFirst/FindNext are covered, but modern handle APIs are the primary supported file path.
todoWhen an unsupported INT 21hINT 21hThe main DOS API interrupt. Programs select services such as open, read, EXEC, and exit with AH. function appears, LainDOS logs it over COM1COM1The first PC serial port. LainDOS uses it as the primary machine-readable debug log. and returns carry set with a DOS-style error where practical.