I was studying x86 assembly programming for DOS in my old book, and among a discussion on interrupts, I saw the 13h one. The book said that I can use it to format a drive. But unfortunately, there's no more information provided on how to do it in my book.
I became very curious, and tried to use it to myself, but it isn't working. How can I format the floppy diskette, in drive A:, using 16-bit x86 assembly? Is it simple to do? I'm using TASM to compile and link, and running in MS-DOS.
Perhaps there is a way other than using int 13h
?
int 13h
is the appropriate way to do it, but rather than calling a DOS service, you're actually using it to call a ROM BIOS service. I don't think DOS provides any service to format a disk. An application program generally leaves such low-level manipulation of the FAT to the operating system, using only the OS-provided services to do high-level read/write operations.Specifically,
int 13h
, service05h
formats a disk track. (The service number goes in theAH
register when you invoke the interrupt.) Note that this service formats a single track, not the entire disk at once. You have to call this service multiple times to format an entire disk. The nice thing about this is that it allows you to specify different characteristics for each track—and even each sector on a track (some old-school copy-protection schemes used this by creating tracks with oddball formatting).The parameters for service
05h
are basically the same as those for every other disk read/write service, except that you don't need to specify a sector number (normally passed inCL
), since you cannot format individual sectors. Here's a list of the required parameters for floppy-disk services:DL
DH
CH
CL
(not used for format!)AL
ES:BX
If the interrupt returns with the carry flag (
CF
) clear, then no error occurred and theAH
register will contain 0. IfCF
is set, then an error occurred and theAH
register contains the error code.In the words of Peter Norton, from The New Programmer's Guide to the IBM PC and PS/2:
The complete process of formatting a diskette track is rather complex and involves slightly more than just calling service
05h
. You need to do the following:Call service
17h
to set the type of the diskette to be formatted. (This only needs to be done once, before beginning an operation.)Call service
18h
to set the media type for the format.Create a table of address marks for the track to be formatted, in the manner described in the quotation above. There must be a 4-byte entry in the table for each sector.
Finally, call service
05h
to format the track.Optionally, follow up by calling service
04h
to verify the formatting process. This verifies that the sector can be found and read, and that the cyclical redundancy check (CRC) is correct. DOS'sformat.com
does this to verify each track after it is formatted, but disk drives are typically reliable enough that verification is not really necessary.All of these disk I/O services use the same parameters as were listed above, although, as with service
05h
, some of them may be ignored. Search online for an interrupt guide to obtain more detailed information. For example, here is a complete list of ROM BIOS disk I/O services. And here is another. The aforequoted guide by Peter Norton is also excellent, if you can find an old copy lying around somewhere, like maybe Amazon?(Note that things are slightly different for formatting hard disks, and for the ESDI drives in PS/2s, you have to use an entirely different service for formatting—
1Ah
.)Update: It turns out that there may be a DOS API to do this, after all. Unfortunately, I don't know that it really makes things all that much simpler. The key is to use IOCTL.
The IOCTL API is defined by DOS, but it is actually implemented/handled by device drivers, which means that support is determined by the driver vendor and version, rather than the version of DOS. If you're using a VM environment, it should support this, but I haven't actually tested it.
DOS function
44h
is device I/O control (IOCTL), so you setAH
to44h
before callingINT 21h
(a DOS interrupt).To format, you want IOCTL for block devices. The block IOCTL functions require at least DOS 3.2 or later (some require even higher versions). They allow not only accessing entire tracks at a time, but also support a formatting function. They're accessed using the subfunction
0Dh
, so you'd setAL
to0Dh
.Putting this together, you would simply set
AX
to440Dh
and callINT 21h
. The minor code for the format function is42h
, which is placed inCL
.In summary, the DOS block IOCTL function to format a track on a logical drive would be called as follows:
AX
==440Dh
CL
==42h
CH
==08h
(block device category)BX
== drive number (0 = default, 1 = A:, 2 = B:, etc.)DS:DX
== address of anIoctlFmtVrfyTrackRec
structure that indicates the head and cylinder number to be formattedIf the carry flag is set when the function returns, then
AX
contains an error code.Unfortunately, I can't find any documentation for
IoctlFmtVrfyTrackRec
online, aside from this page. This stuff predated the web and very little has been uploaded there. :-( You really need a book like Advanced MS-DOS Programming, which I don't have a copy of, either.I did manage to turn up this document on Scribd, which claims to be an implementation of format using IOCTL, written by Pierre Desloover. I haven't tested it.