Geoff Chappell - Software Analyst
CURRENT WORK ITEM - PREVIEW ONLY
The BPB, standing for BIOS Parameter Block, is the structure through which the DOS kernel is told about a disk drive or about media, i.e., disks, that are accessed through a disk drive. What’s meant by a disk drive in this context is a device for accessing block storage that is organised according to one or another variant of DOS’s built-in File Allocation Table (FAT) file system. The BPB is specialised to describing the larger-scale features of this organisation—what might nowadays be called the file-system metadata.
Later versions of the DOS kernel, here meaning 3.20 and higher, expose the BPB to DOS programs through an interface for Generic IOCTL. The kernel is then just a conduit to the relevant block device driver. A program can both learn about a disk drive and its disks and configure their handling by the device driver. This was a necessary, and arguably too-long delayed, step towards standardising tools that work with disks for more than file I/O, especially the FORMAT program.
Inevitably, the BPB is used in other circumstances that can benefit from the same or similar description. Most notable is that the BPB is usefully saved at a well-known position on the disk so that the file-system metadata the kernel will need for correctly accessing files on the disk can be known with some confidence instead of having to be calculated, inferred, guessed or trusted to the user’s recognition. Though saving a BPB on each disk was not the original practice, finding one at offset 0Bh in the boot sector soon became the standard expectation, never of the DOS kernel but certainly of its built-in block device driver.
Many writers about DOS, and even specifically about the history of DOS, would have it that being on the media is the defining characteristic of the BPB. See, for instance, the opening sentence of Wikipedia’s article on the BIOS parameter block (today, 29th October 2021). However convenient this may be from modern perspectives, such as programming other (typically newer) operating systems to use disks that were formatted for DOS or to format disks for use by DOS, it was not DOS’s perspective.
This page that you read now is concerned solely with the BPB as understood by the DOS kernel. It necessarily looks a little at the other sides of interfaces to gauge what seems intended for the design, but it aims very much to ignore interpretations that are imposed retrospectively, except to dismiss them as unreasonably unhistorical. If ever these notes expand to take in the BPB as interpreted on disk, it will be as separate material about the boot sector. Note that this separation is not something I make up now as my own unhistorical revision. It was the extant interpretation when DOS was current, as in the Microsoft® MS-DOS Programmer’s Reference : version 5.0, ISBN 1-55615-329-5, by Microsoft Press in 1991, which has its definitions of the BPB and the BOOTSECTOR at opposite ends of the book.
The BPB is as old as DOS. Indeed, it is at least as old as the 86-DOS version 1.00 that PC DOS 1.00 was developed from.
True, no BPB is known to have been stored on any disk’s boot sector before PC DOS 2.00 became available, and neither is the BPB from DOS’s first version known to have been referred to as a BIOS Parameter Block until version 2.00. Yet far from not existing earlier, the BPB is essential to DOS’s disk I/O through all versions 1.xx.
Even if this had stayed obscure in the mists of pre-history because the few who bother to write about early DOS versions mostly don’t also bother to disassemble the software as their primary source, it ought to be well known by now given Microsoft’s publication of source code for MS-DOS versions 1.25 and 2.11 in 2014 at the Computer History Museum and in 2018 on GitHub. Even without source code, there’a big hint in the name. The BPB was not named as a Boot Sector This or a Boot Sector That or a Boot Parameter Block or a Boot Anything. Why has it instead always been specifically a BIOS Parameter Block?
The name BIOS Parameter Block, along with its abbreviation to BPB, is well established by formal documentation as early as IBM’s Disk Operating System manual for PC DOS 2.00 (part 6936752, January 1983), but if the BIOS in this name wasn’t already a mis-direction, it soon would be. Since at least the mid-1980s, what the term BIOS has meant for all practising DOS programmers, and perhaps even for most technically-minded computer users, is the firmware that is pre-installed in ROM with the IBM Personal Computer (PC) or with computers that offered some sort of compatibility with software written for the PC. This BIOS is present in the computer regardless of which operating system ever gets booted. It provides hardware-specific functionality that an operating system can use if it wants, and PC DOS does indeed use the BIOS instead of programming any hardware directly. This BIOS certainly has a role in DOS’s disk I/O, notably for the int 13h functions that insulate their callers from the details of drive controllers, but it has no direct role in naming the BPB.
The BIOS that names the BPB is instead a DOS component, specifically the one that first came to wide attention as the IBMBIO.COM file for PC DOS 1.00 but which is more generically named IO.SYS. Already in the first edition of the Disk Operating System manual (part 6172220, August 1981) for the IBM PC , this file was described as the “Read-Only Memory (ROM) BIOS interface module” but also as the “DOS BIOS”, the one claiming the term BIOS for IBM’s firmware, the other acknowledging older usage. Long before the PC existed, an operating system named CP/M (for a different processor) had established an architectural separation of the operating system. A lower-level component is adapted to each computer system, even by being written afresh. It abstracts the hardware (including firmware) as an I/O system so that a higher-level component can be independent of the hardware and thus be the same operating system kernel to all programs on all computers. The CP/M names for these two components are the BIOS and the BDOS. The term BDOS seems never to have caught on in DOS programming, but the term BIOS for the lower-level I/O system stuck for many years, sometimes distinguished explicitly from the ROM BIOS as the DOS BIOS but often just as the BIOS in contrast to the DOS.
To know why the BPB is the BIOS Parameter Block, ask who it is in DOS version 1.xx who tells the DOS about the disk drives and the media they may contain. The only possible answer in these versions, which have no installable device drivers, is the DOS BIOS. The BPB originated as the parameter block that the DOS BIOS provides to the DOS kernel to describe a disk drive.
To the DOS kernel in version 2.00 and higher, the BPB is a block device driver’s description of a drive or disk. The driver can be installable or it can be built in to the DOS BIOS. Either way, the kernel obtains a BPB as output from the driver’s Init and Build BPB functions (00h and 02h, respectively). A block device driver’s successful initialisation provides one BPB for each device unit, in effect, to describe each of what the driver wants the kernel to perceive as a disk drive. The kernel may then call the Build BPB function arbitrarily often, typically after a Media Check function (01h) answers negatively, to get a BPB for a specified unit’s current media, i.e., whatever disk is in the drive.
Whether a BPB is for a driver or a disk, the kernel treats it as input for preparing or updating the DPB (Drive Parameter Block) that it keeps for each drive—and then, as far as the kernel is concerned, the BPB is thrown away. This interpretation of a BPB as a BIOS structure whose only meaning to the kernel is for capturing it into a longer-lasting DOS structure is even exposed to DOS programs through int 21h function 53h. Thuogh the purpose was, at least at first, the very limited one of initialising block device drivers at the direction of a device statement in CONFIG.SYS, the relevant code is the whole of the kernel’s interpretation of a BPB and is therefore taken here as definitive from the kernel’s perspective.
See that this interface between the DOS kernel and its device drivers provides for a BPB to exist independently of any disk. See that nowhere in the interface must a BPB that’s produced for a disk have been on the disk. Nowhere does the interface require that a BPB has even the slightest role in the device driver’s possibly substantial work for reading from or writing to the disk, or for doing whatever else it is that a device driver might do with a disk—except to describe the disk to the kernel.
Obviously, a device driver’s implementation can be much easier if this BPB is used internally too, but no rule requires it and conditions have existed when some advantage can be gained from giving the kernel a logical picture of the disk that differs from the physical. For instance, when the BPB had only a 16-bit member for the disk’s capacity in sectors, disks that have 512-byte sectors but are larger than 32MB could be accommodated by a device driver which describes the disk to the kernel as having 1024-byte sectors (or larger) and translates the kernel’s I/O requests to the 512-byte sectors of the (ROM) BIOS’s int 13h interface.
Before version 2.00, there are no device drivers to install for hardware that’s too unusual for the built-in drivers of the DOS BIOS. There is instead only this BIOS, which must be changed in total if unusual hardware is to be accommodated. The DOS kernel learns about disk drives only from the BIOS and only during the kernel’s initialisation. For this, the kernel is given an initialisation table. Within are pointers to the BIOS’s description of each disk drive. In IO.ASM from the published source code for MS-DOS 1.25, each such description is labelled but its contents are defined just as a succession of bytes and words with no formal structure. Comments suggest that these descriptions were then known as DPTs. Yet each is unmistakably an early form of the BPB. When version 2.00 introduced installable device drivers, it was only natural that what block device drivers return from their initialisation is the parameter block that the BIOS had passed to the kernel’s initialisation in version 1.xx.
The oldest representation that Microsoft has published of the BIOS Parameter Block as a structure in a programming language is in a header named DOSSYM.ASM among the source files for MS-DOS 2.11. The structure is there named BPBLOCK. Microsoft follows each member’s definition with a single-line comment which is reproduced below as the Description:
Offset | Size or Type | Name | Description | Versions |
---|---|---|---|---|
00h | word | BPSECSZ | Size in bytes of physical sector | all |
02h | byte | BPCLUS | Sectors/Alloc unit | all |
03h | word | BPRES | Number of reserved sectors | all |
05h | byte | BPFTCNT | Number of FATs | all |
06h | word | BPDRCNT | Number of directory entries | all |
08h | word | BPSCCNT | Total number of sectors | all |
0Ah | byte | BPMEDIA | Media descriptor byte | 2.00 and higher |
0Bh | word | BPFTSEC | Number of sectors taken up by one FAT | 2.00 and higher |
Whatever Microsoft’s comment means about a sector being physical, what the DOS kernel understands of the sector from the BPB is that the interfaces through which the kernel can ask the BIOS or a device driver to read from or write to the disk have this sector as the smallest unit of exchange. The interfaces present the disk to the kernel as an array of these sectors, numbered from 0 up to but not including the total number of sectors. All reads and writes are in whole sectors. Whether these sectors are also the smallest block that the I/O system can read or write through the drive controller is up to the I/O system. How these sectors are laid out on the sides and tracks of a physical disk is also up to the I/O system. Whether there’s even a physical disk is up to the I/O system. The kernel sees just an array.
The remaining members of the original BPB all describe how the disk as an array of sectors is to be interpreted by the kernel in distinct regions for managing file storage. Working upwards through the array, there can be reserved sectors, FATs, a (root) directory, and then the contents of files.
The “Alloc unit” of Microsoft’s comment is commonly referred to as a cluster. The kernel exposes the contents of files with byte granularity but manages their storage on disk in whole clusters. All known kernels assume that a cluster is not just a whole number of sectors but that this number is a power of two. The last of the disk regions is treated as an array of clusters, numbered from two upwards. (That this numbering starts at two can be taken as given, but some hypothesis on this point is ventured in this page’s historical survey below.) A FAT is an array of 0-based cluster numbers indexed by 0-based cluster numbers. Looking up one cluster tells which, if any, is the next cluster for the same file. DOS started with 12-bit cluster numbers. DOS 3.00 and higher allow 16-bit cluster numbers. Recognition of 32-bit cluster numbers came with DOS 7.10 (after the integration with WIndows, which is beyond this note’s present scope).
The reserved sectors typically—indeed, advisedly but not necessarily—begin with a boot sector. More generally, the reserved sectors are those at the start of the disk which are no business of the kernel’s for its management of files. They can be the business of the I/O system. In DOS’s precursor, 86-DOS, they were not just the business of the I/O system but were the storage for both the I/O system and (except in late versions) the kernel, which thus do not appear as files.
However many reserved sectors are defined, including none, whatever follows is the first FAT. This begins the file system’s metadata, which is in two parts: the given number of FATs; and then a directory that is large enough for the given number of entries. The point to multiple FATs is to have safety copies: roughly speaking, DOS accepts any one of them when reading but insists on success for all when writing. Each FAT must be a whole number of sectors. So too must the directory. Computing how many whole sectors, especially for the FAT, is non-trivial and inevitably has quirks. These are avoided in DOS version 2.00 and higher by extending the BPB so that the FAT’s size in sectors is specified rather than computed.
Though the BPBLOCK is the oldest definition that Microsoft has published, the first that Microsoft published openly was a different assembly-language definition in the Microsoft® MS-DOS Programmer’s Reference : version 5.0. It there has the name BPB, which is consistent with documentation since PC DOS 2.00. Earlier texts from Microsoft, including the same reference for earlier DOS versions, present the BPB only with its members described in words, not as a structure with a formal definition in any programming language. The presentation below attempts to back-fit Microsoft’s names for the BPB members to earlier versions according to which members were yet meaningful to the kernel’s interpretation of a BPB from a device driver.
Offset | Size or Type | Name | Versions |
---|---|---|---|
00h | word | bpbBytesPerSec | all |
02h | byte | bpbSecPerClust | all |
03h | word | bpbResSectors | all |
05h | byte | bpbFATs | all |
06h | word | bpbRootDirEnts | all |
08h | word | bpbSectors | all |
0Ah | byte | bpbMedia | 2.00 and higher |
0Bh | word | bpbFATSecs | 2.00 and higher |
0Dh | word | bpbSecPerTrack | 3.31 and higher |
0Fh | word | bpbHeads | 3.31 and higher |
11h | dword | bpbHiddenSectors | 3.31 and higher |
15h | dword | bpbHugeSectors | 3.31 and higher |
The three members at offsets 0Dh, 0Fh and 11h (the last being originally only a word) are irrelevant to the DOS kernel. However commonly they are seen to follow the BPB in boot sectors or even as kept in memory by the built-in block device driver, they are explicitly excluded from the BPB as presented in boot sectors by Microsoft documentation up to and including the Programmer’s Reference for version 4.0. There’s surely no mistaking this point in IBM’s Disk Operating System manual for PC DOS 2.00:
The three words at the end are optional. DOS does not care about them because they are not part of the BPB.
When version 3.20 anticipated disks with too many sectors for the word at offset 08h, much of the practical value of having the BPB in the boot sector would have been lost if the BPB for the DOS kernel were extended incompatibly with what had been following the BPB when stored in boot sectors. The Programmer’s Reference for version 3.20 adds the 32-bit sector count at offset 15h as a provision for the future while still excluding it from the BPB: they are all “fields that follow the BPB.” It is here thought that this exclusion was put aside when the DOS kernel first started interpreting the 32-bit sector count, and this had the side-effect of bringing in the intervening eight bytes.
The first known use of bpbHugeSectors by a DOS kernel is in a version 3.31 from Compaq. The DOS kernel treats the 32-bit bpbHugeSectors as superseding the 16-bit bpbSectors. That a BPB reaches as far as bpbHugeSectors is indicated by zero for bpbSectors.
Other structural representations of the BPB were published by Microsoft years later when DOS was integrated into Windows. Though these came much too late to be of any practical use to DOS programmers, they do have the merit of looking more plausibly like they were extracted from Microsoft’s source code rather than confected for documentation.
Especially notable is a header named BPB.INC from the Device Driver Kit (DDK) for Windows 95. It has a copyright notice that dates at least some of its content back to 1993. What the file presents, without comments, are two very nearly identical structures named BPB and A_BPB. To these may be added—except for being outside this note’s present scope—an A_BF_BPB from the FAT32 API Reference for Windows 95 OEM Service Release 2 and later.
Offset | Size or Type | Name | Versions | Remarks |
---|---|---|---|---|
00h | word | A_BPB_BytesPerSector BPB_BytesPerSector |
3.20 and higher | |
A_BF_BPB_BytesPerSector | 7.10 and higher | |||
02h | byte | A_BPB_SectorsPerCluster BPB_SectorsPerCluster |
3.20 and higher | |
A_BF_BPB_SectorsPerCluster | 7.10 and higher | |||
03h | word | A_BPB_ReservedSectors BPB_ReservedSectors |
3.20 and higher | |
A_BF_BPB_ReservedSectors | 7.10 and higher | |||
05h | byte | A_BPB_NumberOfFATs BPB_NumberOfFATs |
3.20 and higher | |
A_BF_BPB_NumberOfFATs | 7.10 and higher | |||
06h | word | A_BPB_RootEntries BPB_RootEntries |
3.20 and higher | |
A_BF_BPB_RootEntries | 7.10 and higher | |||
08h | word | A_BPB_TotalSectors BPB_TotalSectors |
3.20 and higher | |
A_BF_BPB_TotalSectors | 7.10 and higher | |||
0Ah | byte | A_BPB_MediaDescriptor BPB_MediaDescriptor |
3.20 and higher | |
A_BF_BPB_MediaDescriptor | 7.10 and higher | |||
0Bh | word | A_BPB_SectorsPerFAT BPB_SectorsPerFAT |
3.20 and higher | |
A_BF_BPB_SectorsPerFAT | 7.10 and higher | |||
0Dh | word | A_BPB_SectorsPerTrack BPB_SectorsPerTrack |
3.20 and higher | |
A_BF_BPB_SectorsPerTrack | 7.10 and higher | |||
0Fh | word | A_BPB_Heads BPB_Heads |
3.20 and higher | |
A_BF_BPB_Heads | 7.10 and higher | |||
11h | word | A_BPB_HiddenSectors BPB_HiddenSectors |
3.20 and higher | last BPB member in 3.20 to 3.30 |
A_BF_BPB_HiddenSectors | 7.10 and higher | |||
13h | word | A_BPB_HiddenSectorsHigh | 3.20 and higher | |
BPB_HiddenSectorsHigh | 3.31 and higher | |||
A_BF_BPB_HiddenSectorsHigh | 7.10 and higher | |||
15h | word | A_BPB_BigTotalSectors | 3.20 and higher | |
BPB_BigTotalSectors | 3.31 and higher | |||
A_BF_BPB_BigTotalSectors | 7.10 and higher | |||
17h | word | A_BPB_BigTotalSectorsHigh | 3.20 and higher | |
BPB_BigTotalSectorsHigh | 3.31 and higher | last BPB member in 3.31 and higher | ||
A_BF_BPB_BigTotalSectorsHigh | 7.10 and higher | |||
19h | six bytes | A_BPB_Reserved | 3.20 and higher | last A_BPB member |
19h | word | A_BF_BPB_BigSectorsPerFat | 7.10 and higher | |
1Bh | word | A_BF_BPB_BigSectorsPerFatHi | 7.10 and higher | |
1Dh | word | A_BF_BPB_ExtFlags | 7.10 and higher | |
1Fh | word | A_BF_BPB_FS_Version | 7.10 and higher | |
21h | word | A_BF_BPB_RootDirStrtClus | 7.10 and higher | |
23h | word | A_BF_BPB_RootDirStrtClusHi | 7.10 and higher | |
25h | word | A_BF_BPB_FSInfoSec | 7.10 and higher | |
27h | word | A_BF_BPB_BkUpBootSec | 7.10 and higher | |
29h | six words | A_BF_BPB_Reserved | 7.10 and higher | last A_BF_BPB member |
In the earliest DOS versions, a DOS drive can hold different disks but all the disks in any one drive are assumed to have the same format. This is established already in the 86-DOS 1.00 that PC DOS 1.00 started its development from, and continues at least to 86-DOS 1.14. It is built into the kernel’s initialisation. This starts with ds:si addressing an initialisation table provided by the I/O system:
Offset | Size or Type | Description |
---|---|---|
00h | byte | N, as number of drives |
01h | N near pointers (relative to ds) |
array of pointers to BPBLOCK structures for successive drives |
What the kernel is to understand from each entry in this table is that the I/O system’s functions for reading and writing disks—these are the functions named BIOSREAD and BIOSWRITE in the MSDOS.ASM source file—take the 0-based index into this table as an input parameter (in al) to select which drive to access. The other parameters are a 0-based starting sector (dx), a count of sectors (cx) and a transfer address (ds:bx). Remember, to the kernel the disk is an array of sectors. How, or even if, these are mapped to sectors on sides of tracks on media in some physical device is up to the I/O system.
What the kernel presents to higher levels is that each of these drives is a DOS drive. Each, in the same sequence as given in the initialisation table, becomes accessible through a 0-based DOS drive number for use with such int 21h functions as 0Eh and 19h, through a 1-based DOS drive number in a File Control Block (FCB), and through a drive letter, A and upwards, as used in filenames and as known to users.
In programming terms, the BPBLOCK for a drive is input for creating a DPBLOCK (later named DPB). This structure, not the BPB, is what the kernel keeps about the drive. Each is followed by a buffer for caching the FAT from the drive’s current contents. These early DOS versions have no notion of receiving a BPB for a drive and later a different one for a disk in the drive. The initialised kernel will forever know only of the drives it was told about in the initialisation table and it will forever assume that all disks it accesses through any one drive have the one and only format that was specified for that drive.
Different formats of disk are possible but each must have its own DOS drive. Here, it is important to recognise that the I/O system defines these drives for the kernel but how the I/O system implements them is its own business. At the most general, these DOS drives are logical constructions that need have no direct correspondence with the physical drives that users load disks into. The interface does not itself prevent an implementation in which one physical drive is accessible through two, three or even more DOS drives, one for each format of disk that might be loaded into the physical drive.
As it happens, the extant implementations of these early DOS versions illustrate two roughly opposite attitudes to this freedom of implementation.
An 86-DOS 1.00 that has been found for inspection was built by Seattle Computer Products (SCP) for a computer system that has a Tarbell controller of two double-headed disk drives which can each take single-density or double-density 8” disks. The I/O system presents these two physical drives to the DOS kernel as six logical drives, the first four sharing one BPB, the last two sharing another. All that the DOS kernel knows about these is that drives A to D somehow access disks that have one format, and drives E and F are for disks in a second format:
Drives A, B, C and D | Drives E and F | |
---|---|---|
Sector Size (bytes): | 128 | 1024 |
Cluster Size (sectors): | 4 | 1 |
Reserved Sectors: | 52 | 1 |
Number of FATs: | 2 | 2 |
Directory Capacity (directory entries): | 64 | 128 |
Disk Capacity (sectors): | 2002 | 1232 |
From the first BPB, the kernel understands that every disk in drives A to D is an array of 128-byte sectors which are each represented by a sector number that ranges from 0 up to but not including 2002, and that this array can be reckoned in several regions: 52 reserved sectors; 2 FATs of 6 sectors each; a directory of either 8 sectors or 16 (to be explained shortly); with the remainder for file storage. From the second BPB, every disk in drives E or F is understood as an array of 1232 sectors of 1024 bytes each: 1 reserved sector; 2 FATs of 2 sectors each; a directory of either 2 or 4 sectors; and then file storage.
That the directory has two possible sizes is because the capacity is counted in entries and this early DOS allows that directory entries can be either 16 bytes or 32. That a disk uses one rather than the other is determined by the first byte in whichever FAT the kernel is able to read from the disk. This byte is the original media descriptor, in the sense that it’s stored on the media to describe the intended interpretation of its contents. To 86-DOS 1.00—and even to version 1.14, but not to the intervening PC DOS 1.00—this media descriptor in the FAT is FFh for disks that have 16-byte directory entries: anything else indicates 32-byte entries.
This first byte in the FAT is part of the FAT entry for cluster 0. Its early use as a media descriptor is qualitatively different from the use it’s put to in later versions. Here, a different media descriptor does not signify that a disk has a different FAT layout with a different BPB to describe it, only that the one BPB is to be interpreted a little differently. The variation that’s described is specifically of the directory.
Much else about the drives and their media must be known to the I/O system, of course, but since none of it is in a BPB addressed from the initialisation table, the kernel never knows. The I/O system decides (and keeps to itself) which of the DOS drives map to which of the physical drives that the user may load a disk into. For the system inspected, drives A, B and E access one of the physical drives, A using just one head, B the other and E both, and drives C, D and F follow this pattern but for the second physical drive. The I/O system is also the sole determinant of how the kernel’s sector numbers map to sectors on sides of tracks. For a disk that’s accessed through any of the DOS drives A to D, the mapping is to 26 sectors on each of 77 single-sided tracks. If instead a disk is accessed through drive E or F, the mapping is to 8 sectors on each of two sides of 77 tracks.
None of these characteristics of disk geometry or file-system metadata (putting aside the hack of the FAT’s first byte to signify the use of old-style directory entries) is stored on the media. The user is expected to know that drives A through D are pre-configured for one type of disk with one file-system format, drives E and F for a second, and there’s no way to use any third type of disk except by re-configuring the I/O system. A computer system that uses differently formatted disks would need a different I/O system—but, crucially, not a different kernel (given that the formatting keeps the FAT file system). Some measure of how much this loose coupling of I/O system and kernel is the deliberate design from the time, rather than an architecture inferred with the help of passing decades, is that source code (DOSIO.ASM) is supplied for the I/O system, presumably for customisation, but not for the kernel.
How well users of SCP’s computer system running 86-DOS 1.00 coped with six DOS drive letters for the two drives they could see to load disks into is not known, but they will mostly have been advanced users or at least have been enthusiastic hobbyists aiming to become advanced users, if not advanced programmers, and so it’s credible that they coped well enough. IBM perhaps will not have felt confident of this for users of the mass-market PC, and so PC DOS 1.00 is at the other extreme. Except for one (important) case, it presents its users with one DOS drive letter for each physical drive. Its price for this simplicity is that (for the system as IBM supplies it) all disks can have only the one format.
The IBMBIO.COM for PC DOS 1.00 learns how many floppy disk drives are present by calling int 11h in the ROM BIOS. This returns equipment flags in ax. Bit 0 is set if there are any floppy disk drives at all. Bits 6 to 7 then tell how many, 0 to 3 in the bits meaning 1 to 4 as the count. IBMBIO.COM ignores bit 0, as if to assume that IBMBIO.COM cannot be running except that it was booted from a floppy disk. The Technical Reference (part 6025008, August 1981) is plain that “the 5-1/4" Diskette Drive Adapter is capable of attaching four 5-1/4" drives, two internal, and two external”, and IBMBIO.COM certainly is written to manage as many as four.
If 2, 3 or 4 floppy disk drives are present, then IBMBIO.COM defines 2, 3 or 4 DOS drives, one for each physical drive. The exception is that if only one floppy disk drive is present, then IBMBIO.COM defines two DOS drives, both to access the one physical drive. Crucially different from the 86-DOS implementation of multiple DOS drives for each physical drive, the I/O system in PC DOS explicitly manages the mapping so that the one physical drive is accessible through only one of the two DOS drives at any one time. Attempted access through the other generates a prompt to
Insert diskette for drive x: and strike
any key when ready
Thus does the IBMBIO.COM for PC DOS 1.00 define as many as four DOS drives when initialising the kernel. It has the one hard-coded BPB for all four. The FAT format specified in this hard coding is for what has forever since been the standard 160KB disk:
Drives A and B, Drive C (If Present) Drive D (If Present) |
|
---|---|
Sector Size (bytes): | 512 |
Cluster Size (sectors): | 1 |
Reserved Sectors: | 1 |
Number of FATs: | 2 |
Directory Capacity (directory entries): | 64 |
Disk Capacity (sectors): | 320 |
This hard-coding of one FAT layout for all disks in all drives extends also to the disk geometry. Though the ROM BIOS functions for reading and writing through int 13h take a head number in dh, IBMBIO.COM hard-codes its use of this parameter to zero. To this IBMBIO.COM in this PC DOS version, all disks are single-sided with eight sectors per track.
For its part, the kernel in PC DOS 1.00 is hard-coded for 32-byte directory entries. Support for 16-byte entries was retained in 86-DOS until at least version 1.14, being dropped in version 1.20 according to comments in the published source code for MS-DOS 1.25, but it seems never to have got a look-in for PC DOS 1.00. That aside, the kernel in PC DOS 1.00 is not known to have any other constraint on the FAT formats it can work with, but it can’t ever learn of them except if booted with a replacement IBMBIO.COM.
Most users, of course, did not have a replacement IBMBIO.COM—certainly not at the time, even if they were programmers. Unlike SCP for its I/O system in 86-DOS, and even unlike IBM for its ROM BIOS, IBM did not publish source code for IBMBIO.COM.
Legend has it that the ROM BIOS for the PC was soon reverse-engineered, but the simpler DOS BIOS for the PC seems not to have been. The one had very much the greater commercial incentive, of course. With a good enough facsimile of the ROM BIOS, you get the prospect of assembling whole computers as substitutes for the PC and selling them (honestly) as capable of running all of the software that was being written for the PC. Adapting IBMBIO.COM can at best open a market in peripherals that users may add to (or change in) their PC beyond the offerings of IBM and its resellers, and it anyway has the detraction of not scaling: adding even two peripherals from different manufacturers needs that a modified IBMBIO.COM that is somehow adapted to both. Fortunately, DOS soon had installable device drivers, but soon was more than a year away.
Had anyone at the time been looking for a customisation that could be supported by adapting IBMBIO.COM, even just for their private use, then they might have perceived a suggestion in the Technical Reference. The disk drives in the original PC are there said to be “single-sided", but the Reference elsewhere shows the disk controller as allowing for two heads and the ROM BIOS as being already implemented for two heads.
With the advantage of decades of
Anyone who wanted that their original PC can use double-sided disks instead of single-sided could easily enough have adapted IBMBIO.COM, but if they wanted to use both single-sided and double-sided disks, each with its own BPB, they would have needed an adapted IBMBIO.COM that’s more like the I/O system from SCP, with different DOS drives for the different types of disk. While such a solution might have been fine for hobbyists, it plainly was not the IBM way to easy usability. To have one DOS drive per physical drive but with each capable of using different types of disk, more would have to change than just IBMBIO.COM.
The interfaces between the I/O system and kernel were changing anyway. PC DOS 1.00 had been got ready without changing the interfaces from 86-DOS, but a price was that the PC DOS 1.00 kernel calls functions in the ROM BIOS. For instance, the I/O system had no functions to call for date and time, and so the PC DOS 1.00 kernel calls int 1Ah itself. The necessary functions, named BIOSSETDATE, BIOSSETTIME and BIOSGETTIME in MSDOS.ASM, can be seen in 86-DOS version 1.14.
For PC DOS 1.10, if not earlier, the initialisation table that IBMBIO.COM passes to IBMDOS.COM in ds:si is a little more complicated:
Offset | Size or Type | Description |
---|---|---|
00h | byte | N, as number of I/O drivers |
01h | N structures | array of 3-byte structures for successive I/O drivers |
The 3-byte structure for each I/O driver is:
Offset | Size or Type | Description |
---|---|---|
00h | byte | 0-based drive number |
01h | near pointer (relative to ds) |
address of BPBLOCK for I/O driver |
Importantly, the 0-based index into the initialisation table is no longer also the DOS drive number. In effect, there are two drive numbers, one for the I/O system and one for the kernel. To the published source code for MS-DOS 1.25, nomenclature was not settled. The 0-based index into the table is an I/O driver number and the kernel keeps their count as an internal variable named NUMIO. As with earlier versions, each entry in the table, and thus each BPBLOCK, is input for creating a DPBLOCK. In this, the entry’s 0-based index and 0-based drive number becomes members named DEVNUM and DRVNUM, respectively. and the 0-based r
Importantly, the I/O system’s functions that the kernel calls for reading and writing disks still receive the 0-based index in al but this is no longer also the DOS drive number. It is instead the I/O driver number. All the kernel’s calls to these functions to read from or write to a disk in a drive must be preceded by a call to one of two other functions, one old but altered, the other new.
This was a less of a change than might be supposed, because the kernel anyway asks for a media check
Drive A I/O Driver 0, Drive B I/O Driver 2, Drive C I/O Driver 4 (If Present), Drive D I/O Driver 6 (If Present) |
Drive A I/O Driver 1, Drive B I/O Driver 3, Drive C I/O Driver 5 (If Present), Drive D I/O Driver 7 (If Present) |
|
---|---|---|
Sector Size (bytes): | 512 | 512 |
Cluster Size (sectors): | 1 | 2 |
Reserved Sectors: | 1 | 1 |
Number of FATs: | 2 | 2 |
Directory Capacity (directory entries): | 64 | 112 |
Disk Capacity (sectors): | 320 | 640 |
Drive A I/O Driver 0, Drive B I/O Driver 2 |
Drive A I/O Driver 1, Drive B I/O Driver 3 |
Drive C I/O Driver 4, Drive D I/O Driver 6 |
Drive C I/O Driver 5, Drive D I/O Driver 7 |
|
---|---|---|---|---|
Sector Size (bytes): | 128 | 1024 | 128 | 1024 |
Cluster Size (sectors): | 4 | 1 | 4 | 1 |
Reserved Sectors: | 1 | 1 | 52 | 1 |
Number of FATs: | 2 | 2 | 2 | 2 |
Directory Capacity (directory entries): | 68 | 192 | 64 | 128 |
Disk Capacity (sectors): | 2002 | 1232 | 2002 | 1232 |