This document covers building, using, and understanding the DOS version of rustid.
The DOS port of rustid supports two execution environments:
- 32-bit Protected Mode (DOS32A Extender) — Primary target for 386+ CPUs supporting CPUID and DOS extender operation. Uses the DOS32A DOS extender (
tools/dos32a/dos32a.exe) bound into Linear Executable (LE) format viatools/elf2le. - 16-bit Real Mode Fallback — 16-bit real-mode MZ executable for pre-CPUID CPUs (386/486) or environments requiring real-mode CPU reset identification.
Binaries produced:
| Binary | Cargo bin | Mode | Purpose |
|---|---|---|---|
rustid.exe |
dos |
32-bit DOS32A | Main CPU identification (formatted table output) |
rust86.exe |
rust86 |
16-bit Real Mode | Real-mode fallback CPU identification & debug diagnostics (/D) |
Note: You will only need to directly run rustid.exe, as rust86.exe will be executed automatically if running on a pre-CPUID CPU.
- Nightly Rust toolchain — DOS build requires
-Z build-stdand-Zjson-target-spec, both unstable rust-srccomponent — needed forbuild-std:rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnutools/elf2le— bundled ELF-to-LE converter for DOS32A binariestools/make_exe— bundled ELF-to-MZ-EXE converter for 16-bit real-mode binaries- DOSBox-X — required for building
rustid.exe(runs DOS32A patching/binding scripts in DOS environment) and running/testing DOS binaries
just build-dos
# or: make build-dosThis will:
- Build 32-bit protected mode binary, converting via
tools/elf2leand invokingdos32a.exeinside DOSBox-X to generaterustid.exe - Build 16-bit real-mode binary and convert via
tools/make_exeintorust86.exe - Run the binary size test
The resulting executables (rustid.exe, rust86.exe) appear in the project root.
- In DOSBox-X:
just run-dosormake run-dos(launchesrustid.exeusingtools/dosbox-x.conf) - Automated test run:
just test-dosormake test-dos(runs in DOSBox-X with console logging) - On real hardware: Copy
.exefiles to a DOS system and executerustid.exe.
tools/make_exe: Converts ELF binaries produced byrust-lldinto 16-bit DOS MZ executables.tools/elf2le: Converts 32-bit ELF binaries into LE format and binds them with DOS32A (tools/dos32a/dos32a.exe) inside DOSBox-X to generate 32-bit extender binaries (rustid.exe).
A simple bump allocator is used (src/x86/dos/allocator.rs):
- Initialized to memory segment after the binary
- Non-atomic operations for 386 compatibility (no
CMPXCHG) - No deallocation (sufficient for rustid's few allocations)
DosAllocatormarkedunsafe impl Sync— DOS is single-threaded
All output goes through DOS software interrupts:
printc()—INT 21h, AH = 02hwith character inDLexit()—INT 21h, AH = 4Chwith exit code inAL- The
print!/println!macros wrap these, with an optimization for literal string arguments
- Uses the real
CPUIDinstruction directly (src/x86/fns.rs) via inline asm - For pre-CPUID CPUs (386/486): falls back to a CPU reset signature technique in 16-bit real-mode — sets the CMOS shutdown byte to
0x0A(jump to40:67after reset), writes the warm boot vector, triggers reset via port0x92(with keyboard controller fallback), and capturesEDX(which contains the CPU signature on 386/486 after reset) - Cyrix-specific detection uses I/O ports
0x22/0x23to read Configuration Control Registers (src/x86/vendor/cyrix.rs)
CPU frequency is measured using RDTSC + PIT Channel 0 + BIOS timer tick (0040:006C) for about 110ms. For pre-TSC CPUs (386/486), a calibrated instruction loop runs over 8 BIOS ticks (~440ms) with different cycle counts per loop iteration depending on the CPU type. Frequency is derived from the ratio of TSC delta or instruction count to elapsed PIT pulses.
For multi-socket detection (src/x86/mp.rs), the DOS version scans BIOS memory for the Intel MP Specification _MP_ floating pointer structure, using peek_u8/peek_u16 for safe segmented memory access. Falls back to reading the EBDA segment via INT 15h, AX = C100h.
- The real-mode dos binary (
rust86.exe) must stay under ~62KB (64KB segment minus header). A test verifies this. - The new rustid.exe overcomes this limit with the dos32a extender
- Detection relies on performing an actual CPU reset via CMOS/port 0x92. This is:
- Extremely disruptive — the CPU actually resets
- Only works in real mode — will crash in protected/V8086 mode
- Used only as a last resort when CPUID is not available
- Without the reset method, pre-CPUID chips show limited info
- Uses PIT + BIOS timer ticks (~54.9ms each) — less precise than OS-level methods
- Pre-TSC measurement uses a calibrated busy loop over ~440ms
-Z build-stdand-Zjson-target-specare unstable features- May break if the nightly toolchain changes these interfaces
- 386-class (or better) with DOS-compatible BIOS
- Tested on real hardware: 386, 486, Pentium, Pentium II/III/4, AMD K6/Athlon, various embedded SoCs
- Binary size test:
cargo test --test dos_binary_size_test --features dos-build(Verifies real-mode binaries stay under 62KB limit) - DOSBox-X integration test:
just test-dos(Builds and runsrustid.exein DOSBox-X with console logging) - Interactive test:
just run-dos(Launchesrustid.exein DOSBox-X)
--------------- Rustid 1.0.0 (x86-DOS) ---------------
Architecture: i586
Vendor: AuthenticAMD (AMD)
Model: AMD-K6(tm) 3D processor
MicroArch: K6
Codename: Chompers/CXT
Process Node: 250nm
Easter Egg: NexGenerationAMD
Cache: L1d: 32 KB, 2-way
L1i: 32 KB, 2-way
Frequency: 500.00 MHz
Signature: Family 5h, Model 8h, Stepping Ch
(0, 5, 0, 8, 12)
Features: FPU TSC CMPXCHG8B MMX 3DNow!
--------------- Rustid 1.0.0 (x86-DOS) ---------------
Architecture: i686-SSE
Vendor: Vortex86 SoC (DM&P)
Model: Vortex86DX3
MicroArch: Vortex86DX3
Process Node: 40nm
Topology: 2 sockets, 2 cores, 2 threads
Cache: L1d: 2x 16 KB, 4-way
L1i: 2x 16 KB, 4-way
L2: 2x 256 KB, 4-way
Frequency: 1.00 GHz
Signature: Family 6h, Model 1h, Stepping 1h
(0, 6, 0, 1, 1)
Features: FPU TSC CMPXCHG8B CMOV MMX SSE