Table of Contents
Early mid October work on serboot, lDOS kernel, lDebug
2026-10-18
This week I worked on the serial boot disk loader application donated by Neil H. Gray, added a few patches to the lDOS kernel, and reviewed over 200 changesets to be then pushed into the default (non-experimental) lDebug repo.
Serial boot disk loader (serboot)
These programs were originally developed by a SvarDOS user and provided under the MIT license for hosting on our hgweb server. I changed a lot of the details of how they work. The individual changesets:
- Initial commit, by Neil H. Gray
- Second revision, by Neil H. Gray
- Add a final linebreak to config.h file.
- Add a lot of debugging output to client, disabled by default.
- Add a lot of debugging output to server, in addition to the usual output, disabled by default.
- Add to diagnostic server output if debugging output enabled.
- Add a usleep call to delay writing to serial port. This helped reduce errors on the dosemu2 setup.
- Use O_NONBLOCK to open serial device file, loop on read timeout, and don't return on timeout. This seemed to help as well.
- Fix int 11h handler to place result in AX.
- Add FIFO setup from lDebug serialp.asm source text. This seems to have resulted in a usable connection for the dosemu2 setup.
- Add an assembler warning indicating the size of the (transient) client program.
- In the server, parse a parameter for the serial device file's name.
- Drop int 11h hook and storing the int 3 handler. Int 11h should work just fine as the ROM-BIOS's default handler to return the modified equipment word from the BIOS Data Area. The int 3 address wasn't used anywhere.
- Drop variables used to store the original int 11h and int 3 vectors.
- Don't hardcode the resident handler size to 2 KiB. Calculate it automatically from the resident size.
- Set the stack initially in client init.
- Relocate boot loader from client source to 200h:0. Reduces the resident size. Also, add an actual error message if loading the boot sector fails. (The loader must be relocated because it is initially loaded to the 07C00h area, which it will overwrite when reading the fda boot sector loader.)
- Fix ecm error: Actually return AH to the int 13h caller. This requires modifying the int 13h handler stack frame. (Error in the trivial optimisations changeset. For shame.)
- Fix to actually write the status to
byte [40h:41h]. Due to using AX to address the segment, this always wrote zero. - Simplify the unit check (just check for below NUM_DRIVES, not for HDD vs diskette) and pass all HDD requests to the prior handler.
- Don't hardcode any serial port addresses. Despite the presence of a define for the base address, a few spots retained a hardcoded COM1 port address.
- Move protocol defines to the shared config.h file.
- In the server, use CMD defines for the dispatcher.
- New loader stub of 128 Bytes and boot by using a regular server command, which the server replies to using a SLIP packet. The stub is optimised a lot to fit in 128 Bytes. The big advantage is that the server can be restarted whenever the client is idle, and will serve subsequent requests just fine. I wasn't able to get a server restart to work with the mandatory boot loader sending used previously, albeit the readme claimed it was possible. A consequence of the change is that the server should be started before the client.
- In the server handle the boot and diagnostic error commands only if the expected length is used. This avoids sending the boot image on an int 13h function FEh call.
- Return error 01h and CY for unknown int 13h function numbers, do not pass them to prior handler. This makes lDOS's boot loader work even with
_LBA _LBA_SKIP_CHECK _LBA_HDD_ONLY=0which will try int 13h function 42h (LBA read sector) to read from the load unit, without first checking function 41h (LBA detect). - Pass along a ds:si -> 16 NUL bytes for partition table entry info detection. lDOS loaders already skipped their detection for diskette units but there's no harm in this change.
- Do not check NUM_DRIVES in the LBA installation check function. It is already handled by the initial unit check.
- Observe a status from int 13h function 08h command sent to server.
- In transient client query maximum amount of units using int 13h function 08h, and patch the resident client and the equipment word accordingly.
- In the server allow gaps between configured units.
- Add a shutting down notice to two server error messages.
- Parse -s switch for serial port file name.
- Line wrap a long line and correct a comment in readme.
- Pass the initial CRC value to the CRC calculation function. This is in preparation for dropping the malloc allocation just for calculating a CRC from a complete buffer.
- Calculate CRC without a complete buffer. In this revision, the CRC is calculated both ways and compared.
- Drop the malloc and old CRC calculation in send_slip_packet.
- Rework the client and server and their protocols, use error and status codes for all functions.
- Check the read and write functions for bounds errors and return error codes if detected.
- Implement CRC on the client side, and drop exception for a client sending all-zeroes instead of the expected CRC. (This required editing the loader stub to add a hardcoded CRC for its CMD_BOOT command packet.)
- Update readme with latest revision of the stub.
- Reverse sending of the REQ_WRITE_NEXT and REQ_WRITE_END requests. The server sends them now, to indicate it is ready to receive data. This is to prepare for the next changeset.
- Implement read/write retries on errors. This adds the REQ_READ_RETRY and REQ_WRITE_RETRY requests which are sent to request retrying the last sector's worth of data.
- On unexpected lack of read end request, don't break out of the server's main server dispatch loop.
- Add -R and -W switches to inject an error for reading or writing data, which should cause retrying.
- Add -C switch to inject more than one error, all in a row.
- Calculate a CRC for the CMD_DIAG_ERROR packet sent by client on errors.
- In the client read another acknowledgement packet after sending the CMD_DIAG_ERROR packet. Apparenly it would hang without this read.
- Shut down the server if the read function returns zero. Combined with the
O_NONBLOCKopen flag, a zero indicates that the handle's file was deleted. - Pass the sector adjustment (s) to chs_to_lba so it actually calculates the LBA for every sector accessed. Previously, it would repeatedly calculate the LBA sector number for the first sector and then add the s variable to the returned LBA sector number. (Regardless, this is just hardening because the initial call to chs_to_lba should already error out if the requested number of sectors overflows the drive capacity.)
- Add mak.sh script to invoke the build.
- In the server, use functions rather than casts to access little-endian words.
- In the FAT scan, ignore any root directory entries with the label attribute set. Previously only ignored LFN entries (attribute == 0Fh).
- Return "[Reserved]" for accessing sectors between boot sector and first FAT.
- In the FAT scan, support FAT16 as well as FAT12.
The FAT scan is interesting for a few reasons. Its purpose is solely to display what file is being accessed in the normal terminal output of the server. It likely doesn't cope well with fragmented files. Finally, if a file is created, written, or deleted while the server runs without being restarted, then the file map initially stored may easily become desynced. Despite these shortcomings, I left it in for now.
- Detect image size. This allows common image sizes such as 160 KiB, 180 KiB, 320 KiB, 360 KiB, 720 KiB, 1200 KiB, 1440 KiB, and 2880 KiB. Given accurate geometry in the BPB and a cylinder-aligned size it also allows for larger images, tested with a 32 MiB image initialised using mkfs.vfat on the server. (This required some kernel updates.)
- Delete handling for functions 18h and 41h. The function 41h handler just returned the same error as the default, whereas the function 18h handler seems to have mistakenly returned the geometry rather than taking it as an input.
- Keep track of AT or PS/2 diskette types, to be returned in BL from function 08h.
- Use a packet for function 08h, written by the server and read by the client, to indicate the geometry and size of a disk unit as used by the server.
- Use dosdiska.img as first filename, and corresponding ones for drives B:, C:, D:.
- Return server errors on most functions when an uninitialised unit is specified.
- In the server, sleep after read function returns < 0, to avoid eating a lot of CPU time while the server is running.
- Add the -u switch to allow configuring the read timeout sleep time.
- Raise read delay default value from 40 to 4000, reducing server load more.
ident86
lDOS kernel
- Update lmacros macro collection from lmacros repo. A few edits to lmacros1.mac previously added to the msdos4 repo are retained.
- Improve CHS arithmetic for an edge case. Unclear how much this is really needed, but it may be hit by a non-pathological use case. The pathological case in which it was detected concerned reading 129 sectors in a single int 13h call. With the new bounds checks of serboot, this read was rejected with an error 09h. The kernel then splits up the read request into several reads. With this patch, that works, albeit both serboot and the kernel operate on the buffer offset only and will thus corrupt the beginning of the buffer segment upon wrapping around the segment's end. (Ticket #1031.)
- Update lDOS version to 2026 October. Rather prematurely so.
- Correct a typo in a comment ("higu" to "high").
- Fix new CHS arithmetic handling to reset DS and DI upon errors, and add notes for CY needing to be set in error cases. (That particular error case is probably never reached, as an earlier scan will fail if no matching UPB is found.)
- Support diskettes with >255 cylinders and >65_535 sectors. Due to an underflow when truncating exactly 65_536 sectors to 16 bits, a divide overflow could be reached. The divide error was not unique to the underflow case however, any calculated disk size > 0AAAAh sectors would do. This result came about due to assuming that diskettes are so small they're to be formatted as FAT12 disks with 1 Sector per Cluster. The calculated FAT size is likely not used in normal operation. (Ticket #1032.)
- Read the BPB in PROCESS_OTHER of msbio/msinit.nas, commented out. This was an attempt to support the 32 MiB superfloppy format available from serboot. It was disabled prior to committing the changes though. This spot is not the correct place to read the BPB.
- In msbio/msdisk.nas MOVBPB allow the full range of BPB values, including amounts of sectors >65_535 and 256 CHS Heads geometry. (Other values were supported with some earlier hacks already.) After MOVBPB, only the hidden sectors are forcibly zeroed now. (Ticket #1033.)
- Fix: Write the copies of FAT sectors, not only the first FAT's sectors. This is a longstanding bug that would silently let the FAT copies become stale upon FAT writes. Randomly found during serboot tests. (Ticket #1034.)
lDebug
- Empty changeset: Note that we're merging the past 8 weeks' changes from the ldebug.exp repo to ldebug repo.
- Empty changeset: Note that we're rebuilding after the current build failed due to the new subrepos.
I wrote more about the subrepo failure in a bug ticket, ticket #1029.
wwwecm scripts
- Add symsnip repo as a dependency. The lack of this could have caused a build failure, but this was masked by the worse build failures due to the subrepo errors.
webecm
- Note that hgweb is password protected again. This measure was an attempt to deal with additional server load due to scrapers.
webpushbx
- Add section hgweb on the login required for the hgweb service.
Bugtracker
Adds 15 new bugs (tickets #1020 to #1034) concerning the debugger, Extensions for lDebug, and the lDOS kernel.
