dosforge 0.9.52
dosforge v0.9.52
Fix: Windows path FreeDOS FAT32 / MS-DOS 7.10 boot for VHDs > 504 MiB
User-reported 86Box symptom: freshly built Windows-side VHDs hung at a
blinking cursor right after POST. Affected:
- FreeDOS FAT16 and FAT32 (any size that pushed footer cylinder count
1024 — typically anything ≥ 512 MiB at 16h/63s).
- MS-DOS 7.10 (OSR2) FAT16 (showed "Missing operating system" — same
underlying bug, different MBR-boot-code failure path).
Root cause: ECHS-doubled start_chs invalid for the BIOS that
actually runs
src/dosforge/disk.py (Windows VHD path, _create_and_prepare_vhd_no_kernel)
contained an ECHS bit-shift loop:
partition_chs_heads = footer.heads
if footer.heads > 0 and footer.cylinders > 1024:
heads = footer.heads
cyls = footer.cylinders
while cyls > 1024 and heads < 256:
heads *= 2
cyls = (cyls + 1) // 2
partition_chs_heads = min(heads, 255)For a 1 GiB VHD with footer (2081, 16, 63), this loop runs twice and
produces partition_chs_heads = 64. _lba_to_chs(2048, heads=64, spt=63) then encodes start CHS as bytes 20 21 00 → (cyl=0,
head=32, sec=33).
The MBR boot loader (440-byte _BUILTIN_MSDOS_MBR_BOOT_CODE) reads
the partition's first sector via INT 13h AH=02 DH=32 (head 32).
86Box's AUTO IDE — and every modern emulator/BIOS preset that
reports the disk's raw geometry rather than auto-translating —
rejects head 32 as out of range for a 16-head disk. The carry flag
gets set, the MBR's JC short-circuit fires, MBR halts at its
blinking-cursor loop.
For MS-DOS 7.10 the same bad CHS triggers the secondary "no
bootable VBR found" path in OSR2's MBR loader → "Missing operating
system".
Why this is a Windows-only regression
The Linux path was given exactly this fix two weeks ago in commit
3951021 (v0.6.3). Quoting that commit's rationale:
parted writes the partition entry with its own BIOS-canonical CHS
values that don't correspond to the VHD footer geometry. On 86Box
AUTO IDE, the mismatch causes the BIOS to pick LRG translation as
a fallback; INT 13h reads then land on the wrong sectors and the
disk fails to boot with 'Missing operating system'.Validated empirically: 4 of 8 boot-success VHDs from the v0.5.2
smoke matrix went from 'Missing operating system' to bootable
after the manual equivalent of this patch.
The Linux fix introduced _rewrite_mbr_partition_entry_for_footer
which uses footer.heads / footer.sectors_per_track directly (no
ECHS doubling) and runs after parted clobbers the partition table.
That commit explicitly noted "The defensive ECHS-translation logic
at the existing core_mbr.write_single_partition_mbr call site was
unreachable on Linux because parted clobbers the partition table
after that call runs" — meaning the Linux author knew the Windows
code path still had ECHS doubling, but didn't fix it because Linux
tests had already moved past the issue.
The Windows path slipped through v0.6.3 → v0.9.51 because:
- Most Windows smoke tests in v0.6 / v0.7 / v0.8 era used VHDs
≤ 504 MiB, where the ECHS loop is a no-op. - FreeDOS FAT32 testing on Windows didn't exercise sizes ≥ 512 MiB
until the v0.9.30+ Grow VHD UI made it easy to grow past that
threshold. - v0.9.37 fixed the related end_chs LBA-marker bug (
FE FF FF
clamped to footer geometry) but only on the end_chs side, not
start_chs.
Why the original ECHS rationale (v0.6.2) was wrong
The June 4, 2026 commit f429eb8 introduced ECHS doubling with the
rationale *"AT BIOSes apply ECHS bit-shift translation for any drive
504 MB"*. That model was correct for pre-1996 AT BIOSes which
auto-translated in hardware. But:
- Post-1996 BIOSes + modern emulators (86Box AUTO IDE, QEMU IDE)
present raw disk geometry to DOS and expect the OS to handle
LBA explicitly via INT 13h AH=42 for transfers. - The MBR boot code we install does INT 13h AH=02 (CHS) for the
one-shot VBR chain read, trusting the BIOS to honor the disk's
raw geometry. - ECHS-translated CHS is therefore invalid on every modern target.
The Linux v0.6.3 fix matched empirical behavior (booted 4/8
previously broken VHDs); the Windows path just never caught up.
Fix
src/dosforge/disk.py — removed the ECHS-doubling loop.
partition_chs_heads now uses footer.heads directly, matching the
Linux _rewrite_mbr_partition_entry_for_footer behavior.
partition_chs_heads = footer.heads
partition_chs_spt = footer.sectors_per_trackXT-class layouts (compaq2, msdos33+MFM, ibm8088+dos33+MFM)
take a separate code path (_rewrite_mbr_for_xt_class) and are
unaffected.
Verified end-to-end on Windows
Fresh FreeDOS FAT32 1 GiB VHD before vs. after:
| Field | v0.9.51 (broken) | v0.9.52 (fixed) |
|---|---|---|
| Start CHS bytes | 20 21 00 (head=32) |
00 21 02 (head=0) |
| INT 13h AH=02 result | "invalid head" error | LBA 2048 read OK |
| 86Box AUTO IDE | Blinking cursor | Boots into FreeDOS |
| MS-DOS 7.10 FAT16 | "Missing operating system" | Boots into DOS |
Files changed
src/dosforge/disk.py— removedpartition_chs_heads
ECHS-doubling loop in_create_and_prepare_vhd_no_kernel;
expanded the comment to document the cross-platform consistency
requirement.pyproject.toml+src/dosforge/__init__.py— 0.9.51 → 0.9.52.
Cross-platform parity
After this release, both Linux and Windows paths encode the MBR
partition CHS using the VHD footer's actual geometry. No ECHS
bit-shift translation on either side.
Carried forward
- v0.9.51 Windows GUI Combobox wheel + focus polish
- v0.9.50 Stamp release artifacts with correct version
- v0.9.49 MartyPC-Xebec preset auto-defaults to FAT12
- v0.9.48 MartyPC compatibility expansion
- v0.9.47 IBM 8088 'DOS Version' picker + PC-DOS 5.x boot mode
- v0.9.37 end_chs LBA-marker fix (companion to this start_chs fix)