23-Aug-1998
 

Sector level disk drive interfacing for IBM PCs and Compatibles in C

Part II

10.0 Summary of Part I
11.0 Introduction to Part II
12.0 Standard/Non-Standard Drive Types
    12.1 Removable Media
    12.2 Fixed Media
    12.2.1 Drive Partitioning
    12.2.2 Remote Media
13.0 More on the BIOS
    13.1 Drive Parameters
14.0 Programs using the BIOS
15.0 About Part III
References
 

10.0    Summary of Part I

Before reading sectors the drive type and sector size must be determined; the drive type for which function to read with and the sector size for the sector contents. There are no hard and fast rules for determining drive type - you start with assumptions and adjust things according to results. You can assume a default sector size but this may not work for anything but floppy drives.
 
The drive geometry (track, sector and head sizes) is determined by the using DOS function calls (although using DOS is not the only way and can not always be relied upon as will be seen later). DOS data parameters (root sector location, cluster size, etc.) can be calculated from the basic parameters that DOS provides.

The way the sectors are to be read is determined based upon media type and operating system.

Here is a brief summary:
 

Get drive and sector size GET DEVICE PARAMETERS (DPB)  
  GET FREE SPACE  if DPB does not exist
Determine sector I/O function INT 25/26 floppy/hard drives for DOS/WinNT 
floppy drives for Win31 
loadable devices
  BIOS (INT 13) floppy/hard drives for DOS/Win31 
floppy drives for WinNT
  IOCTL floppy drives
Read BOOT sector   if DPB does not exist 
if removable media
Calculate DOS data    
 

11.0    Introduction to Part II

In these sections I'll first offer a brief look at the variety of drive types, removable media and drive partitioning - just to supply some background - there's no need to go into great detail. I will also provide a working program or two.
 
DISCLAIMER
I HAVE TRIED VERY HARD TO KEEP THESE DOCUMENTS CORRECT BUT 
I CANNOT GIVE ANY GARAUNTEES THAT THERE ARE NOT ANY ERRORS
 

12.0    Standard/Non-Standard Drive Types

In the beginning, there was one. And the one was a 160K floppy. But things change.

Today's PCs have basically only two standard drive types: floppy and hard. AKA removable and fixed. But standard drive types are what the BIOS says are standard. As the BIOS evolved it supported more and more drive types, yet BIOSes will always lag behind the evolution of storage devices.

To support non-standard drives, and drives larger than DOS was developed for, DOS allows for people to write loadable device drivers to provide it with a way of thinking that non-standard drives are standard ones.

What all this means is that if the drive type is not directly supported by the BIOS, the BIOS can not be used to access the drive, you have to use DOS.

12.1    Removable Media

Removable media, floppy drives in particular, presents a problem in that non-default media may be in the drive. For example, placing a 720K floppy in a 1.4M disk drive. DOS is presented with the default drive type by the BIOS, the type indicated in the BIOS (CMOS) setup. The DOS function GET DEVICE PARAMETERS just returns information that DOS has set up in memory during the BOOT process - it does not read the media. To accommodate differing media types you must check whether or not the drive supports removable media.

Removable media will almost certainly always be floppies. However, other types of removable media are increasing in popularity.
 

12.2    Fixed Media

12.2.1    Drive Partitioning

Fixed drives, for various reasons such as sizes, are presented to DOS as a partition, or a logical device. What this means is that not always will a fixed drive available to DOS be a single, specific device defined by a physical geometry. A drive to DOS can be only part of a hard drive (a drive partitioned into 2 or more logical drives). Also, although not very often under DOS, a drive can be two or more hard drives.

As with removable media, fixed media must still be looked at carefully before accessing. The rule of thumb is always: Do not assume everything.

12.2.2    Remote Media

Also under the fixed drive category are remote drives. These are CD-ROMs and network drives. (Although CD-ROMs share both removable and fixed drive characteristics they are treated as remote drives by DOS).

Remote drives are generally not accessible at the sector level. (Although CD-ROMs can be, I will not address them until much later in these tutorials).
 

13.0    More on the BIOS

The BIOS can be used for floppy drives and physical hard drives. If a hard drive is partitioned it still can only be read as a physical drive - for example, if there is only one hard drive and it is partitioned into two drives, C: and D:, the BIOS will not be aware of the D: drive. (more on this later)

13.1    Drive Parameters

In Part I all of the BIOS calls used the DOS CRTL function _bios_disk(). That function does not, however, provide you with a way to get the drive parameters from the BIOS. To do that you have to roll your own with int86().

The structure of a BIOS call is loading the CPU registers with appropriate values and then issuing the interrupt. The registers for BIOS is:

To Call:

AH     08h
DL     {drive} where {drive} is a zero based drive number
       with bit 7 clear for floppy drives and bit 7 set for hard drives.
Returns:
AH     error code if carry set
CH     tracks (low 8 bits of)
CL     sectors (in bits 0-5) and high bits of tracks (in bits 6-7)
DH     heads
And in C:

int int13getparam(int disk, int *t, int *s, int *h)
{
int tmp;
union REGS regs;

   regs.x.ax = 0x0800;           /* get drive parameters */
   regs.h.dl = (unsigned char)adjdrv(disk);
   int86(0x13,&regs,&regs);
   if (regs.x.cflag)
      return (int)regs.h.ah;

   if (regs.h.bl == 0)           /* no drive connected/not found */
      return -1;

   *h = regs.h.dh;
   *t = regs.h.ch;               /* low bits only */
   tmp = *s = regs.h.cl;         /* has high bits of track also */
   *s &= 0x3f;                   /* mask off track high bits */
   *t += (tmp >> 6) << 8;        /* shift and add track high bits */

   return 0;
}

/* floppys: 0 - 7Fh, hards: 80h - FFh */

int adjdrv(int drv)
{
   if (drv > 2)
      return drv + (0x80 - 3);
   return drv - 1;
}

What's funny here is how the BIOS provides you with the number of tracks. Due to some strange technique, probably lost to history, probably by some "clever IBM engineer", the number of tracks is split up between two registers and shared with the register for the number sectors per track: The CH register contains the low 8 bits of the number of tracks, and the CL register holds sectors per track in it's lower 6 bits, and it's upper 2 bits are the high 2 bits for the number of tracks. Whew... Here's it visually:
 

CL CH
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
t t h h h h h h t t t t t t t t
 
One other thing of note is the check for BL being equal to zero. I have not seen it documented, but at least one BIOS (mine, a version by AWARD) will return with the carry flag NOT set but with BL zero if the drive does not exist. (BL normally contains a value, greater than or equal to one, indicating the drive type.)

Note also here that I used ints for the drive parameter arguments rather than the typedef UINT16 I have used before. The reason is that C performs automatic type conversions rather well in this situation.
 

It is the register size limits that causes the "528MB Barrrier" for PC hard disks. Get Hale Landis's " How it Works" documents for more information about this and how it was solved. 
 

14.0    Programs using the BIOS

For more on INT 13h I have expanded the INT 13h interface by adding error handling (function call retries), error diagnostics (an error string rather than a number), and provides a _bios_disk() "front end" which does the read, write, reset and status functions all in one place. INT13.C

For use with INT13.C is a program that creates an "industry standard" floppy image, or writes an image to a floppy. Most similar programs I have encountered (such as RAWRITE and FDIMAGE) only write an image file to a floppy. This program will do either. F2DD2F.C

You can get them both archived. Note that this program ONLY supports the default disk type (whatever your BIOS is setup for). For those interested, here is RAWRITE.C, the most widely used file-to-disk program, and then there's another called FDIMAGE.C.
 
My simple BIOS disk editor, DISKBUG, also uses INT13.C.
 

15.0    About Part III

To finish up these Tutorials I have code for reading the FAT and Directories (like for mapping every file on the disk), and then there are physical to logical translations (like translating an absolute sector to the physical Track, Head and Sector). However, I need to re-write the code for better compatibility.

If you are interested in FAT, Directories and sector translation code you can get the DISKED source code -- it's all there albiet probably not easily discernible. For parsing just the FAT there is code for it in the libraries D_DISK and DISKLIB .
 

References

"MS-DOS(r) Programmer's Reference", Microsoft Press
"IBM ROM BIOS Quick Reference", Ray Duncan, Microsoft Press
"DOS and BIOS Functions Quick Reference", QUE Corp.
"The Official Spinrite II Companion", John M. Goodman, Ph.D., IDG Books
"The x86/MSDOS Interrupt List", Ralf Brown, http://www.pobox.com/~ralf