How It Works -- CHS Translation Plus BIOS Types, LBA and Other Good Stuff Version 4a by Hale Landis (landis@sugs.tware.com) THE "HOW IT WORKS" SERIES This is one of several How It Works documents. The series currently includes the following: * How It Works -- CHS Translation * How It Works -- Master Boot Record * How It Works -- DOS Floppy Boot Sector * How It Works -- OS2 Boot Sector * How It Works -- Partition Tables Introduction (READ THIS!) ------------------------- This is very technical. Please read carefully. There is lots of information here that can sound confusing the first time you read it. Why is an understanding of how a BIOS works so important? The basic reason is that the information returned by INT 13H AH=08H is used by FDISK, it is used in the partition table entries within a partition record (like the Master Boot Record) that are created by FDISK, and it is used by the small boot program that FDISK places into the Master Boot Record. The information returned by INT 13H AH=08H is in cylinder/head/sector (CHS) format -- it is not in LBA format. The boot processing done by your computer's BIOS (INT 19H and INT 13H) is all CHS based. Read this so that you are not confused by all the false information going around that says "LBA solves the >528MB problem". Read this so that you understand the possible data integrity problem that a WD EIDE type BIOS creates. Any BIOS that has a "LBA mode" in the BIOS setup could be a WD EIDE BIOS. Be very careful and NEVER chage the "LBA mode" setting after you have partitioned and installed your software. History ------- Changes between this version and the preceeding version are marked by "!" at left margin of the first line of a changed or new paragraph. Version 4 -- BIOS Types 8 and 10 updated. Version 3 -- New BIOS types found and added to this list. More detailed information is listed for each BIOS type. A section describing CHS translation was added. Version 2 -- A rewrite of version 1 adding BIOS types not included in version 1. Version 1 -- First attempt to classify the BIOS types and describe what each does or does not do. Definitions ----------- * 528MB - The maximun drive capacity that is supported by 1024 cylinders, 16 heads and 63 sectors (1024x16x63x512). This is the limit for CHS addressing in the original IBM PC/XT and IBM PC/AT INT 13H BIOS. * 8GB - The maximum drive capacity that can be supported by 1024 cylinders, 256 heads and 63 sectors (1024x256x63x512). This is the limit for the BIOS INT 13H AH=0xH calls. * ATA - AT Attachment -- The real name of what is widely known as IDE. * CE Cylinder - Customer Engineering cylinder. This is the last cylinder in P-CHS mode. IBM has always reserved this cylinder for use of disk diagnostic programs. Many BIOS do not account for it correctly. It is of questionable value these days and probably should be considered obsolete. However, since there is no industry wide agreement, beware. There is no CE Cylinder reserved in the L-CHS address. Also beware of diagnostic programs that don't realize they are operating in L-CHS mode and think that the last L-CHS cylinder is the CE Cylinder. * CHS - Cylinder/Head/Sector. This is the traditional way to address sectors on a disk. There are at least two types of CHS addressing: the CHS that is used at the INT 13H interface and the CHS that is used at the ATA device interface. In the MFM/RLL/ESDI and early ATA days the CHS used at the INT 13H interface was the same as the CHS used at the device interface. Today we have CHS translating BIOS types that can use one CHS at the INT 13H interface and a different CHS at the device interface. These two types of CHS will be called the logical CHS or L-CHS and the physical CHS or P-CHS in this document. L-CHS is the CHS used at the INT 13H interface and P-CHS is the CHS used at the device interface. The L-CHS used at the INT 13 interface allows up to 256 heads, up to 1024 cylinders and up to 63 sectors. This allows support of up to 8GB drives. This scheme started with either ESDI or SCSI adapters many years ago. The P-CHS used at the device interface allows up to 16 heads up to 65535 cylinders, and up to 63 sectors. This allows access to 2^28 sectors (136GB) on an ATA device. When a P-CHS is used at the INT 13H interface it is limited to 1024 cylinders, 16 heads and 63 sectors. This is where the old 528MB limit originated. ATA devices may also support LBA at the device interface. LBA allows access to approximately 2^28 sectors (137GB) on an ATA device. A SCSI host adapter can convert a L-CHS directly to an LBA used in the SCSI read/write commands. On a PC today, SCSI is also limited to 8GB when CHS addressing is used at the INT 13H interface. * EDPT - Enhanced fixed Disk Parameter Table -- This table returns additional information for BIOS drive numbers 80H and 81H. The EDPT for BIOS drive 80H is pointed to by INT 41H. The EDPT for BIOS drive 81H is pointed to by INT 46H. The EDPT is a fixed disk parameter table with an AxH signature byte. This table format returns two sets of CHS information. One set is the L-CHS and is probably the same as returned by INT 13H AH=08H. The other set is the P-CHS used at the drive interface. This type of table allows drives with >1024 cylinders or drives >528MB to be supported. The translated CHS will have <=1024 cylinders and (probably) >16 heads. The CHS used at the drive interface will have >1024 cylinders and <=16 heads. It is unclear how the IBM defined CE cylinder is accounted for in such a table. Compaq probably gets the credit for the original definition of this type of table. * FDPT - Fixed Disk Parameter Table - This table returns additional information for BIOS drive numbers 80H and 81H. The FDPT for BIOS drive 80H is pointed to by INT 41H. The FDPT for BIOS drive 81H is pointed to by INT 46H. A FDPT does not have a AxH signature byte. This table format returns a single set of CHS information. The L-CHS information returned by this table is probably the same as the P-CHS and is also probably the same as the L-CHS returned by INT 13H AH=08H. However, not all BIOS properly account for the IBM defined CE cylinder and this can cause a one or two cylinder difference between the number of cylinders returned in the AH=08H data and the FDPT data. IBM gets the credit for the original definition of this type of table. * LBA - Logical Block Address. Another way of addressing sectors that uses a simple numbering scheme starting with zero as the address of the first sector on a device. The ATA standard requires that cylinder 0, head 0, sector 1 address the same sector as addressed by LBA 0. LBA addressing can be used at the ATA interface if the ATA device supports it. LBA addressing is also used at the INT 13H interface by the AH=4xH read/write calls. * L-CHS -- Logical CHS. The CHS used at the INT 13H interface by the AH=0xH calls. See CHS above. * MBR - Master Boot Record (also known as a partition table) - The sector located at cylinder 0 head 0 sector 1 (or LBA 0). This sector is created by an "FDISK" utility program. The MBR may be the only partition table sector or the MBR can be the first of multiple partition table sectors that form a linked list. A partition table entry can describe the starting and ending sector addresses of a partition (also known as a logical volume or a logical drive) in both L-CHS and LBA form. Partition table entries use the L-CHS returned by INT 13H AH=08H. Older FDISK programs may not compute valid LBA values. * OS - Operating System. * P-CHS -- Physical CHS. The CHS used at the ATA device interface. This CHS is also used at the INT 13H interface by older BIOS's that do not support >1024 cylinders or >528MB. See CHS above. Background and Assumptions -------------------------- First, please note that this is written with the OS implementor in mind and that I am talking about the possible BIOS types as seen by an OS during its hardware configuration search. It is very important that you not be confused by all the misinformation going around these days. All OS's that want to be co-resident with another OS (and that is all of the PC based OS's that I know of) MUST use INT 13H to determine the capacity of a hard disk. And that capacity information MUST be determined in L-CHS mode. Why is this? Because: 1) FDISK and the partition tables are really L-CHS based, and 2) MS/PC DOS uses INT 13H AH=02H and AH=03H to read and write the disk and these BIOS calls are L-CHS based. The boot processing done by the BIOS is all L-CHS based. During the boot processing, all of the disk read accesses are done in L-CHS mode via INT 13H and this includes loading the first of the OS's kernel code or boot manager's code. Second, because there can be multiple BIOS types in any one system, each drive may be under the control of a different type of BIOS. For example, drive 80H (the first hard drive) could be controlled by the original system BIOS, drive 81H (the second drive) could be controlled by a option ROM BIOS and drive 82H (the third drive) could be controlled by a software driver. Also, be aware that each drive could be a different type, for example, drive 80H could be an MFM drive, drive 81H could be an ATA drive, drive 82H could be a SCSI drive. Third, not all OS's understand or use BIOS drive numbers greater than 81H. Even if there is INT 13H support for drives 82H or greater, the OS may not use that support. Fourth, the BIOS INT 13H configuration calls are: * AH=08H, Get Drive Parameters -- This call is restricted to drives up to 528MB without CHS translation and to drives up to 8GB with CHS translation. For older BIOS with no support for >1024 cylinders or >528MB, this call returns the same CHS as is used at the ATA interface (the P-CHS). For newer BIOS's that do support >1024 cylinders or >528MB, this call returns a translated CHS (the L-CHS). The CHS returned by this call is used by FDISK to build partition records. * AH=41H, Get BIOS Extensions Support -- This call is used to determine if the IBM/Microsoft Extensions or if the Phoenix Enhanced INT 13H calls are supported for the BIOS drive number. * AH=48H, Extended Get Drive Parameters -- This call is used to determine the CHS geometries, LBA information and other data about the BIOS drive number. * the FDPT or EDPT -- While not actually a call, but instead a data area, the FDPT or EDPT can return additional information about a drive. * other tables -- The IBM/Microsoft extensions provide a pointer to a drive parameter table via INT 13H AH=48H. The Phoenix enhancement provides a pointer to a drive parameter table extension via INT 13H AH=48H. These tables are NOT the same as the FDPT or EDPT. Note: The INT 13H AH=4xH calls duplicate the older AH=0xH calls but use a different parameter passing structure. This new structure allows support of drives with up to 2^64 sectors (really BIG drives). While at the INT 13H interface the AH=4xH calls are LBA based, these calls do NOT require that the drive support LBA addressing. CHS Translation Algorithms -------------------------- NOTE: Before you send me email about this, read this entire section. Thanks! As you read this, don't forget that all of the boot processing done by the system BIOS via INT 19H and INT 13H use only the INT 13H AH=0xH calls and that all of this processing is done in CHS mode. First, lets review all the different ways a BIOS can be called to perform read/write operations and the conversions that a BIOS must support. ! * An old BIOS (like BIOS type 1 below) does no CHS translation and does not use LBA. It only supports the AH=0xH calls: INT 13H (L-CHS == P-CHS) ATA AH=0xH --------------------------------> device (L-CHS) (P-CHS) * A newer BIOS may support CHS translation and it may support LBA at the ATA interface: INT 13H L-CHS ATA AH=0xH --+--> to --+----------------> device (L-CHS) | P-CHS | (P-CHS) | | | | P-CHS | +--> to --+ | LBA | | | | L-CHS | ATA +--> to -----------------+---> device LBA (LBA) * A really new BIOS may also support the AH=4xH in addtion to the older AH\0xH calls. This BIOS must support all possible combinations of CHS and LBA at both the INT 13H and ATA interfaces: INT 13H ATA AH=4xH --+-----------------------------> device (LBA) | (LBA) | | LBA +--> to ---------------+ P-CHS | | INT 13H L-CHS | ATA AH=0xH --+--> to --+------------+---> device (L-CHS) | P-CHS | (P-CHS) | | | | P-CHS | +--> to --+ | LBA | | | | L-CHS | ATA +--> to -----------------+---> device LBA (LBA) You would think there is only one L-CHS to P-CHS translation algorithm, only one L-CHS to LBA translation algorithm and only one P-CHS to LBA translation algorithm. But this is not so. Why? Because there is no document that standardizes such an algorithm. You can not rely on all BIOS's and OS's to do these translations the same way. The following explains what is widely accepted as the "correct" algorithms. An ATA disk must implement both CHS and LBA addressing and must at any given time support only one P-CHS at the device interface. And, the drive must maintain a strick relationship between the sector addressing in CHS mode and LBA mode. Quoting the ATA-2 document: LBA = ( (cylinder * heads_per_cylinder + heads ) * sectors_per_track ) + sector - 1 where heads_per_cylinder and sectors_per_track are the current translation mode values. This algorithm can also be used by a BIOS or an OS to convert a L-CHS to an LBA as we'll see below. This algorithm can be reversed such that an LBA can be converted to a CHS: cylinder = LBA / (heads_per_cylinder * sectors_per_track) temp = LBA % (heads_per_cylinder * sectors_per_track) head = temp / sectors_per_track sector = temp % sectors_per_track + 1 While most OS's compute disk addresses in an LBA scheme, an OS like DOS must convert that LBA to a CHS in order to call INT 13H. Technically an INT 13H should follow this process when converting an L-CHS to a P-CHS: 1) convert the L-CHS to an LBA, 2) convert the LBA to a P-CHS, If an LBA is required at the ATA interface, then this third step is needed: 3) convert the P-CHS to an LBA. All of these conversions are done by normal arithmetic. However, while this is the technically correct way to do things, certain short cuts can be taken. It is possible to convert an L-CHS directly to a P-CHS using bit a bit shifting algorithm. This combines steps 1 and 2. And, if the ATA device being used supports LBA, steps 2 and 3 are not needed. The LBA value produced in step 1 is the same as the LBA value produced in step 3. AN EXAMPLE Lets look at an example. Lets say that the L-CHS is 1000 cylinders 10 heads and 50 sectors, the P-CHS is 2000 cylinders, 5 heads and 50 sectors. Lets say we want to access the sector at L-CHS 2,4,3. * step 1 converts the L-CHS to an LBA, lba = 1202 = ( ( 2 * 10 + 4 ) * 50 ) + 3 - 1 * step 2 converts the LBA to the P-CHS, cylinder = 4 = ( 1202 / ( 5 * 50 ) temp = 202 = ( 1202 % ( 5 * 50 ) ) head = 4 = ( 202 / 50 ) sector = 3 = ( 202 % 50 ) + 1 * step 3 converts the P-CHS to an LBA, lba = 1202 = ( ( 4 * 5 + 4 ) * 50 ) + 3 - 1 Most BIOS (or OS) software is not going to do all of this to convert an address. Most will use some other algorithm. There are many such algorithms. BIT SHIFTING INSTEAD If the L-CHS is produced from the P-CHS by 1) dividing the P-CHS cylinders by N, and 2) multiplying the P-CHS heads by N, where N is 2, 4, 8, ..., then this bit shifting algorithm can be used and N becomes a bit shift value. This is the most common way to make the P-CHS geometry of a >528MB drive fit the INT 13H L-CHS rules. Plus this algorithm maintains the same sector ordering as the more complex algorithm above. Note the following: Lcylinder = L-CHS cylinder being accessed Lhead = L-CHS head being accessed Lsector = L-CHS sector being accessed Pcylinder = the P-CHS cylinder being accessed Phead = the P-CHS head being accessed Psector = P-CHS sector being accessed NPH = is the number of heads in the P-CHS N = 2, 4, 8, ..., the bit shift value The algorithm, which can be implemented using bit shifting instead of multiply and divide operations is: Pcylinder = ( Lcylinder * N ) + ( Lhead / NPH ); Phead = ( Lhead % NPH ); Psector = Lsector; A BIT SHIFTING EXAMPLE Lets apply this to our example above (L-CHS = 1000,10,50 and P-CHS = 2000, 5, 50) and access the same sector at at L-CHS 2,4,3. Pcylinder = 4 = ( 2 * 2 ) + ( 4 / 5 ) Phead = 4 = ( 4 % 5 ) Psector = 3 = 3 As you can see, this produces the same P-CHS as the more complex method above. SO WHAT IS THE PROBLEM? The basic problem is that there is no requirement that a CHS translating BIOS followed these rules. There are many other algorithms that can be implemented to perform a similar function. Today, there are at least two popular implementions: the Phoenix implementation (described above) and the non-Phoenix implementations. SO WHY IS THIS A PROBLEM IF IT IS HIDDEN INSIDE THE BIOS? Because a protected mode OS that does not want to use INT 13H must implement the same CHS translation algorithm. If it doesn't, your data gets scrambled. WHY USE CHS AT ALL? In the perfect world of tomorrow, maybe only LBA will be used. But today we are faced with the following problems: * Some drives >528MB don't implement LBA. * Some drives are optimized for CHS and may have lower performance when given commands in LBA mode. Don't forget that LBA is something new for the ATA disk designers who have worked very hard for many years to optimize CHS address handling. And not all drive designs require the use of LBA internally. * The L-CHS to LBA conversion is more complex and slower than the bit shifting L-CHS to P-CHS conversion. * DOS, FDISK and the MBR are still CHS based -- they use the CHS returned by INT 13H AH=08H. Any OS that can be installed on the same disk with DOS must understand CHS addressing. * The BIOS boot processing and loading of the first OS kernel code is done in CHS mode -- the CHS returned by INT 13H AH=08H is used. * Microsoft has said that their OS's will not use any disk capacity that can not also be accessed by INT 13H AH=0xH. These are difficult problems to overcome in today's industry environment. The result: chaos. DANGER TO YOUR DATA! See the description of BIOS Type 7 below to understand why a WD EIDE BIOS is so dangerous to your data. The BIOS Types -------------- I assume the following: a) All BIOS INT 13H support has been installed by the time the OS starts its boot processing. I'm don't plan to cover what could happen to INT 13H once the OS starts loading its own device drivers. b) Drives supported by INT 13H are numbered sequentially starting with drive number 80H (80H-FFH are hard drives, 00-7FH are floppy drives). And remember, any time a P-CHS exists it may or may not account for the CE Cylinder properly. I have identified the following types of BIOS INT 13H support as seen by an OS during its boot time hardware configuration determination: BIOS Type 1 Origin: Original IBM PC/XT. BIOS call support: INT 13H AH=0xH and FDPT for BIOS drives 80H and 81H. There is no CHS translation. INT 13H AH=08H returns the P-CHS. The FDPT should contain the same P-CHS. Description: Supports up to 528MB from a table of drive descriptions in BIOS ROM. No support for >1024 cylinders or drives >528MB or LBA. Support issues: For >1024 cylinders or >528MB support, either an option ROM with an INT 13H replacement (see BIOS types 4-7) -or- a software driver (see BIOS type 8) must be added to the system. BIOS Type 2 Origin: Unknown, but first appeared on systems having BIOS drive type table entries defining >1024 cylinders. Rumored to have originated at the request of Novell or SCO. BIOS call support: INT 13H AH=0xH and FDPT for BIOS drives 80H and 81H. INT 13H AH=08H should return a L-CHS with the cylinder value limited to 1024. Beware, many BIOS perform a logical AND on the cylinder value. A correct BIOS will limit the cylinder value as follows: cylinder = cylinder > 1024 ? 1024 : cylinder; An incorrect BIOS will limit the cylinder value as follows (this implementation turns a 540MB drive into a 12MB drive!): cylinder = cylinder & 0x03ff; The FDPT will return a P-CHS that has the full cylinder value. Description: For BIOS drive numbers 80H and 81H, this BIOS type supports >1024 cylinders or >528MB without using a translated CHS in the FDPT. INT 13H AH=08H truncates cylinders to 1024 (beware of buggy implementations). The FDPT can show >1024 cylinders thereby allowing an OS to support drives >528MB. May convert the L-CHS or P-CHS directly to an LBA if the ATA device supports LBA. Support issues: Actual support of >1024 cylinders is OS specific -- some OS's may be able to place OS specific partitions spanning or beyond cylinder 1024. Usually all OS boot code must be within first 1024 cylinders. The FDISK program of an OS that supports such partitions uses an OS specific partition table entry format to identify these paritions. There does not appear to be a standard (de facto or otherwise) for this unusual partition table entry. Apparently one method is to place -1 into the CHS fields and use the LBA fields to describe the location of the partition. This DOES NOT require the drive to support LBA addressing. Using an LBA in the partition table entry is just a trick to get around the CHS limits in the partition table entry. It is unclear if such a partition table entry will be ignored by an OS that does not understand what it is. For an OS that does not support such partitions, either an option ROM with an INT 13H replacement (see BIOS types 4-7) -or- a software driver (see BIOS type 8) must be added to the system. Note: OS/2 can place HPFS partitions and Linux can place Linux partitions beyond or spanning cylinder 1024. (Anyone know of other systems that can do the same?) BIOS Type 3 Origin: Unknown, but first appeared on systems having BIOS drive type table entires defining >1024 cylinders. Rumored to have originated at the request of Novell or SCO. BIOS call support: INT 13H AH=0xH and FDPT for BIOS drives 80H and 81H. INT 13H AH=08H can return an L-CHS with more than 1024 cylinders. Description: This BIOS is like type 2 above but it allows up to 4096 cylinders (12 cylinder bits). It does this in the INT 13H AH=0xH calls by placing two most significant cylinder bits (bits 11 and 10) into the upper two bits of the head number (bits 7 and 6). Support issues: Identification of such a BIOS is difficult. As long as the drive(s) supported by this type of BIOS have <1024 cylinders this BIOS looks like a type 2 BIOS because INT 13H AH=08H should return zero data in bits 7 and 6 of the head information. If INT 13H AH=08H returns non zero data in bits 7 and 6 of the head information, perhaps it can be assumed that this is a type 3 BIOS. For more normal support of >1024 cylinders or >528MB, either an option ROM with an INT 13H replacement (see BIOS types 4-7) -or- a software driver (see BIOS type 8) must be added to the system. Note: Apparently this BIOS type is no longer produced by any BIOS vendor. BIOS Type 4 Origin: Compaq. Probably first appeared in systems with ESDI drives having >1024 cylinders. BIOS call support: INT 13H AH=0xH and EDPT for BIOS drives 80H and 81H. If the drive has <1024 cylinders, INT 13H AH=08H returns the P-CHS and a FDPT is built. If the drive has >1024 cylinders, INT 13H AH=08H returns an L-CHS and an EDPT is built. Description: Looks like a type 2 BIOS when an FDPT is built. Uses CHS translation when an EDPT is used. May convert the L-CHS directly to an LBA if the ATA device supports LBA. Support issues: This BIOS type may support up to four drives with a EDPT (or FDPT) for BIOS drive numbers 82H and 83H located in memory following the EDPT (or FDPT) for drive 80H. Different CHS translation algorithms may be used by the BIOS and an OS. BIOS Type 5 Origin: The IBM/Microsoft BIOS Extensions document. For many years this document was marked "confidential" so it did not get wide spread distribution. BIOS call support: INT 13H AH=0xH, AH=4xH and EDPT for BIOS drives 80H and 81H. INT 13H AH=08H returns an L-CHS. INT 13H AH=41H and AH=48H should be used to get P-CHS configuration. The FDPT/EDPT should not be used. In some implementations the FDPT/EDPT may not exist. Description: A BIOS that supports very large drives (>1024 cylinders, >528MB, actually >8GB), and supports the INT 13H AH=4xH read/write functions. The AH=4xH calls use LBA addressing and support drives with up to 2^64 sectors. These calls do NOT require that a drive support LBA at the drive interface. INT 13H AH=48H describes the L-CHS used at the INT 13 interface and the P-CHS or LBA used at the drive interface. This BIOS supports the INT 13 AH=0xH calls the same as a BIOS type 4. Support issues: While the INT 13H AH=4xH calls are well defined, they are not implemented in many systems shipping today. Currently undefined is how such a BIOS should respond to INT 13H AH=08H calls for a drive that is >8GB. Different CHS translation algorithms may be used by the BIOS and an OS. Note: Support of LBA at the drive interface may be automatic or may be under user control via a BIOS setup option. Use of LBA at the drive interface does not change the operation of the INT 13 interface. BIOS Type 6 Origin: The Phoenix Enhanced Disk Drive Specification. BIOS call support: INT 13H AH=0xH, AH=4xH and EDPT for BIOS drives 80H and 81H. INT 13H AH=08H returns an L-CHS. INT 13H AH=41H and AH=48H should be used to get P-CHS configuration. INT 13H AH=48H returns the address of the Phoenix defined "FDPT Extension" table. Description: A BIOS that supports very large drives (>1024 cylinders, >528MB, actually >8GB), and supports the INT 13H AH=4xH read/write functions. The AH=4xH calls use LBA addressing and support drives with up to 2^64 sectors. These calls do NOT require that a drive support LBA at the drive interface. INT 13H AH=48H describes the L-CHS used at the INT 13 interface and the P-CHS or LBA used at the drive interface. This BIOS supports the INT 13 AH=0xH calls the same as a BIOS type 4. The INT 13H AH=48H call returns additional information such as host adapter addresses, DMA support, LBA support, etc, in the Phoenix defined "FDPT Extension" table. Phoenix says this this BIOS need not support the INT 13H AH=4xH read/write calls but this BIOS is really an extension/enhancement of the original IBM/MS BIOS so most implementations will probably support the full set of INT 13H AH=4xH calls. Support issues: Currently undefined is how such a BIOS should respond to INT 13H AH=08H calls for a drive that is >8GB. Different CHS translation algorithms may be used by the BIOS and an OS. Note: Support of LBA at the drive interface may be automatic or may be under user control via a BIOS setup option. Use of LBA at the drive interface does not change the operation of the INT 13 interface. BIOS Type 7 Origin: Described in the Western Digital Enhanced IDE Implementation Guide. BIOS call support: INT 13H AH=0xH and FDPT or EDPT for BIOS drives 80H and 81H. An EDPT with a L-CHS of 16 heads and 63 sectors is built when "LBA mode" is enabled. An FDPT is built when "LBA mode" is disabled. Description: Supports >1024 cylinders or >528MB using a EDPT with a translated CHS *** BUT ONLY IF *** the user requests "LBA mode" in the BIOS setup *** AND *** the drive supports LBA. As long as "LBA mode" is enabled, CHS translation is enabled using a L-CHS with <=1024 cylinders, 16, 32, 64, ..., heads and 63 sectors. Disk read/write commands are issued in LBA mode at the ATA interface but other commands are issued in P-CHS mode. Because the L-CHS is determined by table lookup based on total drive capacity and not by a multiply/divide of the P-CHS cylinder and head values, it may not be possible to use the simple (and faster) bit shifting L-CHS to P-CHS algorithms. When "LBA mode" is disabled, this BIOS looks like a BIOS type 2 with an FDPT. The L-CHS used is taken either from the BIOS drive type table or from the device's Identify Device data. This L-CHS can be very different from the L-CHS returned when "LBA mode" is enabled. This BIOS may support FDPT/EDPT for up to four drives in the same manner as described in BIOS type 4. The basic problem with this BIOS is that the CHS returned by INT 13H AH=08H changes because of a change in the "LBA mode" setting in the BIOS setup. This should not happen. This use or non-use of LBA at the ATA interface should have no effect on the CHS returned by INT 13H AH=08H. This is the only BIOS type know to have this problem. Support issues: If the user changes the "LBA mode" setting in BIOS setup, INT 13H AH=08H and the FDPT/EDPT change which may cause *** DATA CORRUPTION ***. The user should be warned to not change the "LBA mode" setting in BIOS setup once the drive has been partitioned and software installed. Different CHS translation algorithms may be used by the BIOS and an OS. BIOS Type 8 Origin: Unknown. Perhaps Ontrack's Disk Manager was the first of these software drivers. Another example of such a driver is Micro House's EZ Drive. BIOS call support: Unknown (anyone care to help out here?). Mostly likely only INT 13H AH=0xH are support. Probably a FDPT or EDPT exists for drives 80H and 81H. ! Description: A software driver that "hides" in the MBR such that it is loaded into system memory before any OS boot processing starts. These drivers can have up to three parts: a part that hides in the MBR, a part that hides in the remaining sectors of cylinder 0, head 0, and an OS device driver. The part in the MBR loads the second part of the driver from cylinder 0 head 0. The second part provides a replacement for INT 13H that enables CHS translation for at least the boot drive. Usually the boot drive is defined in CMOS setup as a type 1 or 2 (5MB or 10MB drive). Once the second part of the driver is loaded, this definition is changed to describe the true capacity of the drive and INT 13H is replaced by the driver's version of INT 13H that does CHS translation. In some cases the third part, an OS specific device driver, must be loaded to enable CHS translation for devices other than the boot device. ! I don't know the details of how these drivers respond to INT 13H AH=08H or how they set up drive parameter tables (anyone care to help out here?). Some of these drivers convert the L-CHS to an LBA, then they add a small number to the LBA and finally they convert the LBA to a P-CHS. This in effect skips over some sectors at the front of the disk. Support issues: Several identified -- Some OS installation programs will remove or overlay these drivers; some of these drivers do not perform CHS translation using the same algorithms used by the other BIOS types; special OS device drivers may be required in order to use these software drivers For example, under MS Windows the standard FastDisk driver (the 32-bit disk access driver) must be replaced by a driver that understands the Ontrack, Micro House, etc, version of INT 13H. Different CHS translation algorithms may be used by the driver and an OS. ! The hard disk vendors have been shipping these drivers with their drives over 528MB during the last year and they have been ignoring the statements of Microsoft and IBM that these drivers would not be supported in future OS's. Now it appears that both Microsoft and IBM are in a panic trying to figure out how to support some of these drivers in WinNT, Win95 and OS/2. It is unclear what the outcome of this will be at this time. ! NOTE: THIS IS NOT A PRODUCT ENDORSEMENT! An alternate solution for an older ISA system is one of the BIOS replacement cards. This cards have a BIOS option ROM. AMI makes such a card called the "Disk Extender". This card replaces the motherboard's INT 13H BIOS with a INT 13H BIOS that does some form of CHS translation. Another solution for older VL-Bus systems is an ATA-2 (EIDE) type host adapter card that provides a option ROM with an INT 13H replacement. BIOS Type 9 Origin: SCSI host adapters. BIOS call support: Probably INT 13H AH=0xH and FDPT for BIOS drives 80H and 81H, perhaps INT 13H AH=4xH. Description: Most SCSI host adapters contain an option ROM that enables INT 13 support for the attached SCSI hard drives. It is possible to have more than one SCSI host adapter, each with its own option ROM. The CHS used at the INT 13H interface is converted to the LBA that is used in the SCSI commands. INT 13H AH=08H returns a CHS. This CHS will have <=1024 cylinders, <=256 heads and <=63 sectors. The FDPT probably will exist for SCSI drives with BIOS drive numbers of 80H and 81H and probably indicates the same CHS as that returned by INT 13H AH=08H. Even though the CHS used at the INT 13H interface looks like a translated CHS, there is no need to use a EDPT since there is no CHS-to-CHS translation used. Other BIOS calls (most likely host adapter specific) must be used to determine other information about the host adapter or the drives. The INT 13H AH=4xH calls can be used to get beyond 8GB but since there is little support for these calls in today's OS's, there are probably few SCSI host adapters that support these newer INT 13H calls. Support issues: Some SCSI host adapters will not install their option ROM if there are two INT 13H devices previously installed by another INT 13H BIOS (for example, two MFM/RLL/ESDI/ATA drives). Other SCSI adapters will install their option ROM and use BIOS drive numbers greater than 81H. Some older OS's don't understand or use BIOS drive numbers greater than 81H. SCSI adapters are currently faced with the >8GB drive problem. BIOS Type 10 Origin: A european system vendor. BIOS call support: INT 13H AH=0xH and FDPT for BIOS drives 80H and 81H. Description: This BIOS supports drives >528MB but it does not support CHS translation. It supports only ATA drives with LBA capability. INT 13H AH=08H returns an L-CHS. The L-CHS is converted directly to an LBA. The BIOS sets the ATA drive to a P-CHS of 16 heads and 63 sectors using the Initialize Drive Parameters command but it does not use this P-CHS at the ATA interface. ! Support issues: OS/2 will probably work with this BIOS as long as the drive's power on default P-CHS mode uses 16 heads and 63 sectors. Because there is no EDPT, OS/2 uses the ATA Identify Device power on default P-CHS, described in Identify Device words 1, 3 and 6 as the current P-CHS for the drive. However, this may not represent the correct P-CHS. A newer drive will have the its current P-CHS information in Identify Device words 53-58 but for some reason OS/2 does not use this information. ---------------------------------------------------------------------- How it Works -- Partition Tables Version 1b by Hale Landis (landis@sugs.tware.com) THE "HOW IT WORKS" SERIES This is one of several How It Works documents. The series currently includes the following: * How It Works -- CHS Translation * How It Works -- Master Boot Record * How It Works -- DOS Floppy Boot Sector * How It Works -- OS2 Boot Sector * How It Works -- Partition Tables PARTITION SECTOR/RECORD/TABLE BASICS FDISK creates all partition records (sectors). The primary purpose of a partition record is to hold a partition table. The rules for how FDISK works are unwritten but so far most FDISK programs (DOS, OS/2, WinNT, etc) seem to follow the same basic idea. First, all partition table records (sectors) have the same format. This includes the partition table record at cylinder 0, head 0, sector 1 -- what is known as the Master Boot Record (MBR). The last 66 bytes of a partition table record contain a partition table and a 2 byte signature. The first 446 bytes of these sectors usually contain a program but only the program in the MBR is ever executed (so extended partition table records could contain something other than a program in the first 466 bytes). See "How It Works -- The Master Boot Record". Second, extended partitions are "nested" inside one another and extended partition table records form a "linked list". I will attempt to show this in a diagram below. PARTITION TABLE ENTRY FORMAT Each partition table entry is 16 bytes and contains things like the start and end location of a partition in CHS, the start in LBA, the size in sectors, the partition "type" and the "active" flag. Warning: older versions of FDISK may compute incorrect LBA or size values. And note: When your computer boots itself, only the CHS fields of the partition table entries are used (another reason LBA doesn't solve the >528MB problem). The CHS fields in the partition tables are in L-CHS format -- see "How It Works -- CHS Translation". There is no central clearing house to assign the codes used in the one byte "type" field. But codes are assigned (or used) to define most every type of file system that anyone has ever implemented on the x86 PC: 12-bit FAT, 16-bit FAT, HPFS, NTFS, etc. Plus, an extended partition also has a unique type code. Note: I know of no complete list of all the type codes that have been used to date. However, I try to include such a list in a future version of this document. The 16 bytes of a partition table entry are used as follows: +--- Bit 7 is the active partition flag, bits 6-0 are zero. | | +--- Starting CHS in INT 13 call format. | | | | +--- Partition type byte. | | | | | | +--- Ending CHS in INT 13 call format. | | | | | | | | +-- Starting LBA. | | | | | | | | | | +-- Size in sectors. | | | | | | v <--+---> v <--+--> v v 0 1 2 3 4 5 6 7 8 9 A B C D E F DH DL CH CL TB DL CH CL LBA..... SIZE.... 80 01 01 00 06 0e be 94 3e000000 0c610900 1st entry 00 00 81 95 05 0e fe 7d 4a610900 724e0300 2nd entry 00 00 00 00 00 00 00 00 00000000 00000000 3rd entry 00 00 00 00 00 00 00 00 00000000 00000000 4th entry Bytes 0-3 are used by the small program in the Master Boot Record to read the first sector of an active partition into memory. The DH, DL, CH and CL above show which x86 register is loaded when the MBR program calls INT 13H AH=02H to read the active partition's boot sector. See "How It Works -- Master Boot Record". These entries define the following partitions: 1) The first partition, a primary partition DOS FAT, starts at CHS 0H,1H,1H (LBA 3EH) and ends at CHS 294H,EH,3EH with a size of 9610CH sectors. 2) The second partition, an extended partition, starts at CHS 295H,0H,1H (LBA 9614AH) and ends at CHS 37DH,EH,3EH with a size of 34E72H sectors. 3) The third and fourth table entries are unused. PARTITION TABLE RULES Keep in mind that there are NO written rules and NO industry standards on how FDISK should work but here are some basic rules that seem to be followed by most versions of FDISK: 1) In the MBR there can be 0-4 "primary" partitions, OR, 0-3 primary partitions and 0-1 extended partition entry. 2) In an extended partition there can be 0-1 "secondary" partition entries and 0-1 extended partition entries. 3) Only 1 primary partition in the MBR can be marked "active" at any given time. 4) In most versions of FDISK, the first sector of a partition will be aligned such that it is at head 0, sector 1 of a cylinder. This means that there may be unused sectors on the track(s) prior to the first sector of a partition and that there may be unused sectors following a partition table sector. For example, most new versions of FDISK start the first partition (primary or extended) at cylinder 0, head 1, sector 0. This leaves the sectors at cylinder 0, head 0, sectors 2...n as unused sectors. This same layout may be seen on the first track of an extended partition. See example 2 below. Also note that software drivers like Ontrack's Disk Manager depend on these unused sectors because these drivers will "hide" their code there (in cylinder 0, head 0, sectors 2...n). This is also a good place for boot sector virus programs to hang out. 5) The partition table entries (slots) can be used in any order. Some versions of FDISK fill the table from the bottom up and some versions of FDISK fill the table from the top down. Deleting a partition can leave an unused entry (slot) in the middle of a table. 6) And then there is the "hack" that some newer OS's (OS/2 and Linux) use in order to place a partition spanning or passed cylinder 1024 on a system that does not have a CHS translating BIOS. These systems create a partition table entry with the partition's starting and ending CHS information set to all FFH. The starting and ending LBA information is used to describe the location of the partition. The LBA can be converted back to a CHS -- most likely a CHS with more than 1024 cylinders. Since such a CHS can't be used by the system BIOS, these partitions can not be booted or accessed until the OS's kernel and hard disk device drivers are loaded. It is not known if the systems using this "hack" follow the same rules for the creation of these type of partitions. There are NO written rules as to how an OS scans the partition table entries so each OS can have a different method. For DOS, this means that different versions could assign different drive letters to the same FAT file system partitions. PARTITION NESTING What do I mean when I say the partitions are "nested" within each other? Lets look at this example: M = Master Boot Record (and any unused sectors on the same track) E = Extended partition record (and any unused sectors on the same track) pri = a primary partition (first sector is a "boot" sector) sec = a secondary partition (first sector is a "boot" sector) |<----------------the entire disk-------------->| | | |M | | | | E<---rest of 1st ext part---------->| | | | E<---rest of 2nd ext part---->| The first extended partition is described in the MBR and it occupies the entire disk following the primary partition. The second extended partition is described in the first extended partition record and it occupies the entire disk following the first secondary partition. PARTITION TABLE LINKING What do I mean when I say the partition records (tables) form a "linked" list? This means that the MBR has an entry that describes (points to) the first extended partition, the first extended partition table has an entry that describes (points to) the second extended partition table, and so on. There is, in theory, no limited to out long this linked list is. When you ask FDISK to show the DOS "logical drives" it scans the linked list looking for all of the DOS FAT type partitions that may exist. Remember that in an extended partition table, only two entries of the four can be used (rule 2 above). And one more thing... Within a partition, the layout of the file system data varies greatly. However, the first sector of a partition is expected to be a "boot" sector. A DOS FAT file system has: a boot sector, first FAT sectors, second FAT sectors, root directory sectors and finally the file data area. See "How It Works -- OS2 Boot Sector". EXAMPLE 1 A disk containing four DOS FAT partitions (C, D, E and F): |<---------------------the entire disk------------------->| | | |M<---C:---> | | | | E<---D:---><-rest of 1st ext part------------>| | | | E<---E:---><-rest of 2nd ext part->| | | | E<---------F:---------->| EXAMPLE 2 So here is an example of a disk with two primary partitions, one DOS FAT and one OS/2 HPFS, plus an extended partition with another DOS FAT: |<------------------the entire disk------------------>| | | |M | | | | | | | | E| Or in more detail ('n' is the highest cylinder, head or sector number number allowed in the indicated field of the CHS)... +-------------------------------------+ CHS=0,0,1 | Master Boot Record containing | | partition table search program and | | a partition table | | +---------------------------------+ | | | DOS FAT partition description | | points to CHS=0,1,1 | +---------------------------------+ | points to CHS=a | | OS/2 HPFS partition description | | | +---------------------------------+ | | | unused table entry | | | +---------------------------------+ | | | extended partition entry | | points to CHS=b | +---------------------------------+ | +-------------------------------------+ CHS=0,0,2 | the rest of "track 0" -- this is | : to | where the software drivers such as | : normally CHS=0,0,n | Ontrack's Disk Manager or Micro | : unused | House's EZ Drive are located. | : +-------------------------------------+ CHS=0,1,1 | Boot sector for the DOS FAT | : | partition | : a DOS FAT +-------------------------------------+ : file CHS=0,1,2 | rest of the DOS FAT partition | : system to | (FAT table, root directory and | : CHS=x-1,n,n | user data area) | : +-------------------------------------+ CHS=x,0,1 | Boot sector for the OS/2 HPFS | : | file system partition | : an OS/2 +-------------------------------------+ : HPFS file CHS=x,0,2 | rest of the OS/2 HPFS file system | : system to | partition | : CHS=y-1,n,n | | : +-------------------------------------+ CHS=y,0,1 | Partition record for the extended | | partition containing a partition | | record program (never executed) and | | a partition table | | +---------------------------------+ | | | DOS FAT partition description | | points to CHS=b+1 | +---------------------------------+ | | | unused table entry | | | +---------------------------------+ | | | unused table entry | | | +---------------------------------+ | | | unused table entry | | | +---------------------------------+ | +-------------------------------------+ CHS=y,0,2 | the rest of the first track of the | : normally to | extended partition | : unused CHS=y,0,n | | : +-------------------------------------+ CHS=y,1,1 | Boot sector for the DOS FAT | : | partition | : a DOS FAT +-------------------------------------+ : file CHS=y,1,2 | rest of the DOS FAT partition | : system to | (FAT table, root directory and | : CHS=n,n,n | user data area) | : +-------------------------------------+ EXAMPLE 3 Here is a partition record from an extended partition (the first sector of an extended partition). Note that it contains no program code. It contains only the partition table and the signature data. OFFSET 0 1 2 3 4 5 6 7 8 9 A B C D E F *0123456789ABCDEF* 000000 00000000 00000000 00000000 00000000 *................* 000010 TO 0001af SAME AS ABOVE 0001b0 00000000 00000000 00000000 00000001 *................* 0001c0 8195060e fe7d3e00 0000344e 03000000 *.....}>...4N....* 0001d0 00000000 00000000 00000000 00000000 *................* 0001e0 00000000 00000000 00000000 00000000 *................* 0001f0 00000000 00000000 00000000 000055aa *..............U.* NOTES Thanks to yue@heron.Stanford.EDU (Kenneth C. Yue) for pointing out that in V0 of this document I did not properly describe the unused sectors normally found around the partition table sectors. ----------------------------------------------------------------------- How It Works -- Master Boot Record Version 1a by Hale Landis (landis@sugs.tware.com) THE "HOW IT WORKS" SERIES This is one of several How It Works documents. The series currently includes the following: * How It Works -- CHS Translation * How It Works -- Master Boot Record * How It Works -- DOS Floppy Boot Sector * How It Works -- OS2 Boot Sector * How It Works -- Partition Tables MASTER BOOT RECORD This article is a disassembly of a Master Boot Record (MBR). The MBR is the sector at cylinder 0, head 0, sector 1 of a hard disk. An MBR is created by the FDISK program. The FDISK program of all operating systems must create a functionally similar MBR. The MBR is first of what could be many partition sectors, each one containing a four entry partition table. At the completion of your system's Power On Self Test (POST), INT 19 is called. Usually INT 19 tries to read a boot sector from the first floppy drive. If a boot sector is found on the floppy disk, the that boot sector is read into memory at location 0000:7C00 and INT 19 jumps to memory location 0000:7C00. However, if no boot sector is found on the first floppy drive, INT 19 tries to read the MBR from the first hard drive. If an MBR is found it is read into memory at location 0000:7c00 and INT 19 jumps to memory location 0000:7c00. The small program in the MBR will attempt to locate an active (bootable) partition in its partition table. If such a partition is found, the boot sector of that partition is read into memory at location 0000:7C00 and the MBR program jumps to memory location 0000:7C00. Each operating system has its own boot sector format. The small program in the boot sector must locate the first part of the operating system's kernel loader program (or perhaps the kernel itself or perhaps a "boot manager program") and read that into memory. INT 19 is also called when the CTRL-ALT-DEL keys are used. On most systems, CTRL-ALT-DEL causes an short version of the POST to be executed before INT 19 is called. ===== Where stuff is: The MBR program code starts at offset 0000. The MBR messages start at offset 008b. The partition table starts at offset 00be. The signature is at offset 00fe. Here is a summary of what this thing does: If an active partition is found, that partition's boot record is read into 0000:7c00 and the MBR code jumps to 0000:7c00 with SI pointing to the partition table entry that describes the partition being booted. The boot record program uses this data to determine the drive being booted from and the location of the partition on the disk. If no active partition table enty is found, ROM BASIC is entered via INT 18. All other errors cause a system hang, see label HANG. NOTES (VERY IMPORTANT): 1) The first byte of an active partition table entry is 80. This byte is loaded into the DL register before INT 13 is called to read the boot sector. When INT 13 is called, DL is the BIOS device number. Because of this, the boot sector read by this MBR program can only be read from BIOS device number 80 (the first hard disk). This is one of the reasons why it is usually not possible to boot from any other hard disk. 2) The MBR program uses the CHS based INT 13H AH=02H call to read the boot sector of the active partition. The location of the active partition's boot sector is in the partition table entry in CHS format. If the drive is >528MB, this CHS must be a translated CHS (or L-CHS, see my BIOS TYPES document). No addresses in LBA form are used (another reason why LBA doesn't solve the >528MB problem). ===== Here is the entire MBR record (hex dump and ascii). OFFSET 0 1 2 3 4 5 6 7 8 9 A B C D E F *0123456789ABCDEF* 000000 fa33c08e d0bc007c 8bf45007 501ffbfc *.3.....|..P.P...* 000010 bf0006b9 0001f2a5 ea1d0600 00bebe07 *................* 000020 b304803c 80740e80 3c00751c 83c610fe *...<.t..<.u.....* 000030 cb75efcd 188b148b 4c028bee 83c610fe *.u......L.......* 000040 cb741a80 3c0074f4 be8b06ac 3c00740b *.t..<.t.....<.t.* 000050 56bb0700 b40ecd10 5eebf0eb febf0500 *V.......^.......* 000060 bb007cb8 010257cd 135f730c 33c0cd13 *..|...W.._s.3...* 000070 4f75edbe a306ebd3 bec206bf fe7d813d *Ou...........}.=* 000080 55aa75c7 8bf5ea00 7c000049 6e76616c *U.u.....|..Inval* 000090 69642070 61727469 74696f6e 20746162 *id partition tab* 0000a0 6c650045 72726f72 206c6f61 64696e67 *le.Error loading* 0000b0 206f7065 72617469 6e672073 79737465 * operating syste* 0000c0 6d004d69 7373696e 67206f70 65726174 *m.Missing operat* 0000d0 696e6720 73797374 656d0000 00000000 *ing system......* 0000e0 00000000 00000000 00000000 00000000 *................* 0000f0 TO 0001af SAME AS ABOVE 0001b0 00000000 00000000 00000000 00008001 *................* 0001c0 0100060d fef83e00 00000678 0d000000 *......>....x....* 0001d0 00000000 00000000 00000000 00000000 *................* 0001e0 00000000 00000000 00000000 00000000 *................* 0001f0 00000000 00000000 00000000 000055aa *..............U.* ===== Here is the disassembly of the MBR... This sector is initially loaded into memory at 0000:7c00 but it immediately relocates itself to 0000:0600. BEGIN: NOW AT 0000:7C00, RELOCATE 0000:7C00 FA CLI disable int's 0000:7C01 33C0 XOR AX,AX set stack seg to 0000 0000:7C03 8ED0 MOV SS,AX 0000:7C05 BC007C MOV SP,7C00 set stack ptr to 7c00 0000:7C08 8BF4 MOV SI,SP SI now 7c00 0000:7C0A 50 PUSH AX 0000:7C0B 07 POP ES ES now 0000:7c00 0000:7C0C 50 PUSH AX 0000:7C0D 1F POP DS DS now 0000:7c00 0000:7C0E FB STI allow int's 0000:7C0F FC CLD clear direction 0000:7C10 BF0006 MOV DI,0600 DI now 0600 0000:7C13 B90001 MOV CX,0100 move 256 words (512 bytes) 0000:7C16 F2 REPNZ move MBR from 0000:7c00 0000:7C17 A5 MOVSW to 0000:0600 0000:7C18 EA1D060000 JMP 0000:061D jmp to NEW_LOCATION NEW_LOCATION: NOW AT 0000:0600 0000:061D BEBE07 MOV SI,07BE point to first table entry 0000:0620 B304 MOV BL,04 there are 4 table entries SEARCH_LOOP1: SEARCH FOR AN ACTIVE ENTRY 0000:0622 803C80 CMP BYTE PTR [SI],80 is this the active entry? 0000:0625 740E JZ FOUND_ACTIVE yes 0000:0627 803C00 CMP BYTE PTR [SI],00 is this an inactive entry? 0000:062A 751C JNZ NOT_ACTIVE no 0000:062C 83C610 ADD SI,+10 incr table ptr by 16 0000:062F FECB DEC BL decr count 0000:0631 75EF JNZ SEARCH_LOOP1 jmp if not end of table 0000:0633 CD18 INT 18 GO TO ROM BASIC FOUND_ACTIVE: FOUND THE ACTIVE ENTRY 0000:0635 8B14 MOV DX,[SI] set DH/DL for INT 13 call 0000:0637 8B4C02 MOV CX,[SI+02] set CH/CL for INT 13 call 0000:063A 8BEE MOV BP,SI save table ptr SEARCH_LOOP2: MAKE SURE ONLY ONE ACTIVE ENTRY 0000:063C 83C610 ADD SI,+10 incr table ptr by 16 0000:063F FECB DEC BL decr count 0000:0641 741A JZ READ_BOOT jmp if end of table 0000:0643 803C00 CMP BYTE PTR [SI],00 is this an inactive entry? 0000:0646 74F4 JZ SEARCH_LOOP2 yes NOT_ACTIVE: MORE THAN ONE ACTIVE ENTRY FOUND 0000:0648 BE8B06 MOV SI,068B display "Invld prttn tbl" DISPLAY_MSG: DISPLAY MESSAGE LOOP 0000:064B AC LODSB get char of message 0000:064C 3C00 CMP AL,00 end of message 0000:064E 740B JZ HANG yes 0000:0650 56 PUSH SI save SI 0000:0651 BB0700 MOV BX,0007 screen attributes 0000:0654 B40E MOV AH,0E output 1 char of message 0000:0656 CD10 INT 10 to the display 0000:0658 5E POP SI restore SI 0000:0659 EBF0 JMP DISPLAY_MSG do it again HANG: HANG THE SYSTEM LOOP 0000:065B EBFE JMP HANG sit and stay! READ_BOOT: READ ACTIVE PARITION BOOT RECORD 0000:065D BF0500 MOV DI,0005 INT 13 retry count INT13RTRY: INT 13 RETRY LOOP 0000:0660 BB007C MOV BX,7C00 0000:0663 B80102 MOV AX,0201 read 1 sector 0000:0666 57 PUSH DI save DI 0000:0667 CD13 INT 13 read sector into 0000:7c00 0000:0669 5F POP DI restore DI 0000:066A 730C JNB INT13OK jmp if no INT 13 0000:066C 33C0 XOR AX,AX call INT 13 and 0000:066E CD13 INT 13 do disk reset 0000:0670 4F DEC DI decr DI 0000:0671 75ED JNZ INT13RTRY if not zero, try again 0000:0673 BEA306 MOV SI,06A3 display "Errr ldng systm" 0000:0676 EBD3 JMP DISPLAY_MSG jmp to display loop INT13OK: INT 13 ERROR 0000:0678 BEC206 MOV SI,06C2 "missing op sys" 0000:067B BFFE7D MOV DI,7DFE point to signature 0000:067E 813D55AA CMP WORD PTR [DI],AA55 is signature correct? 0000:0682 75C7 JNZ DISPLAY_MSG no 0000:0684 8BF5 MOV SI,BP set SI 0000:0686 EA007C0000 JMP 0000:7C00 JUMP TO THE BOOT SECTOR WITH SI POINTING TO PART TABLE ENTRY Messages here. 0000:0680 ........ ........ ......49 6e76616c * Inval* 0000:0690 69642070 61727469 74696f6e 20746162 *id partition tab* 0000:06a0 6c650045 72726f72 206c6f61 64696e67 *le.Error loading* 0000:06b0 206f7065 72617469 6e672073 79737465 * operating syste* 0000:06c0 6d004d69 7373696e 67206f70 65726174 *m.Missing operat* 0000:06d0 696e6720 73797374 656d00.. ........ *ing system. * Data not used. 0000:06d0 ........ ........ ......00 00000000 * .....* 0000:06e0 00000000 00000000 00000000 00000000 *................* 0000:06f0 00000000 00000000 00000000 00000000 *................* 0000:0700 00000000 00000000 00000000 00000000 *................* 0000:0710 00000000 00000000 00000000 00000000 *................* 0000:0720 00000000 00000000 00000000 00000000 *................* 0000:0730 00000000 00000000 00000000 00000000 *................* 0000:0740 00000000 00000000 00000000 00000000 *................* 0000:0750 00000000 00000000 00000000 00000000 *................* 0000:0760 00000000 00000000 00000000 00000000 *................* 0000:0770 00000000 00000000 00000000 00000000 *................* 0000:0780 00000000 00000000 00000000 00000000 *................* 0000:0790 00000000 00000000 00000000 00000000 *................* 0000:07a0 00000000 00000000 00000000 00000000 *................* 0000:07b0 00000000 00000000 00000000 0000.... *............ * The partition table starts at 0000:07be. Each partition table entry is 16 bytes. This table defines a single primary partition which is also an active (bootable) partition. 0000:07b0 ........ ........ ........ ....8001 * ....* 0000:07c0 0100060d fef83e00 00000678 0d000000 *......>....x....* 0000:07d0 00000000 00000000 00000000 00000000 *................* 0000:07e0 00000000 00000000 00000000 00000000 *................* 0000:07f0 00000000 00000000 00000000 0000.... *............ * The last two bytes contain a 55AAH signature. 0000:07f0 ........ ........ ........ ....55aa *..............U.* --------------------------------------------------------------------- How It Works -- DOS Floppy Disk Boot Sector Version 1a by Hale Landis (landis@sugs.tware.com) THE "HOW IT WORKS" SERIES This is one of several How It Works documents. The series currently includes the following: * How It Works -- CHS Translation * How It Works -- Master Boot Record * How It Works -- DOS Floppy Boot Sector * How It Works -- OS2 Boot Sector * How It Works -- Partition Tables DOS FLOPPY DISK BOOT SECTOR This article is a disassembly of a floppy disk boot sector for a DOS floppy. The boot sector of a floppy disk is located at cylinder 0, head 0, sector 1. This sector is created by a floppy disk formating program, such as the DOS FORMAT program. The boot sector of a FAT hard disk partition has a similar layout and function. Basically a bootable FAT hard disk partition looks like a big floppy during the early stages of the system's boot processing. At the completion of your system's Power On Self Test (POST), INT 19 is called. Usually INT 19 tries to read a boot sector from the first floppy drive. If a boot sector is found on the floppy disk, the that boot sector is read into memory at location 0000:7C00 and INT 19 jumps to memory location 0000:7C00. However, if no boot sector is found on the first floppy drive, INT 19 tries to read the MBR from the first hard drive. If an MBR is found it is read into memory at location 0000:7c00 and INT 19 jumps to memory location 0000:7c00. The small program in the MBR will attempt to locate an active (bootable) partition in its partition table. If such a partition is found, the boot sector of that partition is read into memory at location 0000:7C00 and the MBR program jumps to memory location 0000:7C00. Each operating system has its own boot sector format. The small program in the boot sector must locate the first part of the operating system's kernel loader program (or perhaps the kernel itself or perhaps a "boot manager program") and read that into memory. INT 19 is also called when the CTRL-ALT-DEL keys are used. On most systems, CTRL-ALT-DEL causes an short version of the POST to be executed before INT 19 is called. ===== Where stuff is: The BIOS Parameter Block (BPB) starts at offset 0. The boot sector program starts at offset 3e. The messages issued by this program start at offset 19e. The DOS hidden file names start at offset 1e6. The boot sector signature is at offset 1fe. Here is a summary of what this thing does: 1) Copy Diskette Parameter Table which is pointed to by INT 1E. 2) Alter the copy of the Diskette Parameter Table. 3) Alter INT 1E to point to altered Diskette Parameter Table. 4) Do INT 13 AH=00, disk reset call. 5) Compute sector address of root directory. 6) Read first sector of root directory into 0000:0500. 7) Confirm that first two directory entries are for IO.SYS and MSDOS.SYS. 8) Read first 3 sectors of IO.SYS into 0000:0700 (or 0070:0000). 9) Leave some information in the registers and jump to IO.SYS at 0070:0000. NOTE: This program uses the CHS based INT 13H AH=02 to read the FAT root directory and to read the IO.SYS file. If the drive is >528MB, this CHS must be a translated CHS (or L-CHS, see my BIOS TYPES document). Except for internal computations no addresses in LBA form are used, another reason why LBA doesn't solve the >528MB problem. ===== Here is the entire sector in hex and ascii. OFFSET 0 1 2 3 4 5 6 7 8 9 A B C D E F *0123456789ABCDEF* 000000 eb3c904d 53444f53 352e3000 02010100 *.<.MSDOS5.0.....* 000010 02e00040 0bf00900 12000200 00000000 *...@............* 000020 00000000 0000295a 5418264e 4f204e41 *......)ZT.&NO NA* 000030 4d452020 20204641 54313220 2020fa33 *ME FAT12 .3* 000040 c08ed0bc 007c1607 bb780036 c5371e56 *.....|...x.6.7.V* 000050 1653bf3e 7cb90b00 fcf3a406 1fc645fe *.S.>|.........E.* 000060 0f8b0e18 7c884df9 894702c7 073e7cfb *....|.M..G...>|.* 000070 cd137279 33c03906 137c7408 8b0e137c *..ry3.9..|t....|* 000080 890e207c a0107cf7 26167c03 061c7c13 *.. |..|.&.|...|.* 000090 161e7c03 060e7c83 d200a350 7c891652 *..|...|....P|..R* 0000a0 7ca3497c 89164b7c b82000f7 26117c8b *|.I|..K|. ..&.|.* 0000b0 1e0b7c03 c348f7f3 0106497c 83164b7c *..|..H....I|..K|* 0000c0 00bb0005 8b16527c a1507ce8 9200721d *......R|.P|...r.* 0000d0 b001e8ac 0072168b fbb90b00 bee67df3 *.....r........}.* 0000e0 a6750a8d 7f20b90b 00f3a674 18be9e7d *.u... .....t...}* 0000f0 e85f0033 c0cd165e 1f8f048f 4402cd19 *._.3...^....D...* 000100 585858eb e88b471a 48488a1e 0d7c32ff *XXX...G.HH...|2.* 000110 f7e30306 497c1316 4b7cbb00 07b90300 *....I|..K|......* 000120 505251e8 3a0072d8 b001e854 00595a58 *PRQ.:.r....T.YZX* 000130 72bb0501 0083d200 031e0b7c e2e28a2e *r..........|....* 000140 157c8a16 247c8b1e 497ca14b 7cea0000 *.|..$|..I|.K|...* 000150 7000ac0a c07429b4 0ebb0700 cd10ebf2 *p....t).........* 000160 3b16187c 7319f736 187cfec2 88164f7c *;..|s..6.|....O|* 000170 33d2f736 1a7c8816 257ca34d 7cf8c3f9 *3..6.|..%|.M|...* 000180 c3b4028b 164d7cb1 06d2e60a 364f7c8b *.....M|.....6O|.* 000190 ca86e98a 16247c8a 36257ccd 13c30d0a *.....$|.6%|.....* 0001a0 4e6f6e2d 53797374 656d2064 69736b20 *Non-System disk * 0001b0 6f722064 69736b20 6572726f 720d0a52 *or disk error..R* 0001c0 65706c61 63652061 6e642070 72657373 *eplace and press* 0001d0 20616e79 206b6579 20776865 6e207265 * any key when re* 0001e0 6164790d 0a00494f 20202020 20205359 *ady...IO SY* 0001f0 534d5344 4f532020 20535953 000055aa *SMSDOS SYS..U.* ===== The first 62 bytes of a boot sector are known as the BIOS Parameter Block (BPB). Here is the layout of the BPB fields and the values they are assigned in this boot sector: db JMP instruction at 7c00 size 2 = eb3c db NOP instruction 7c02 1 90 db OEMname 7c03 8 'MSDOS5.0' dw bytesPerSector 7c0b 2 0200 db sectPerCluster 7c0d 1 01 dw reservedSectors 7c0e 2 0001 db numFAT 7c10 1 02 dw numRootDirEntries 7c11 2 00e0 dw numSectors 7c13 2 0b40 (ignore numSectorsHuge) db mediaType 7c15 1 f0 dw numFATsectors 7c16 2 0009 dw sectorsPerTrack 7c18 2 0012 dw numHeads 7c1a 2 0002 dd numHiddenSectors 7c1c 4 00000000 dd numSectorsHuge 7c20 4 00000000 db driveNum 7c24 1 00 db reserved 7c25 1 00 db signature 7c26 1 29 dd volumeID 7c27 4 5a541826 db volumeLabel 7c2b 11 'NO NAME ' db fileSysType 7c36 8 'FAT12 ' ===== Here is the boot sector... The first 3 bytes of the BPB are JMP and NOP instructions. 0000:7C00 EB3C JMP START 0000:7C02 90 NOP Here is the rest of the BPB. 0000:7C00 ......4d 53444f53 352e3000 02010100 * MSDOS5.0.....* 0000:7C10 02e00040 0bf00900 12000200 00000000 *...@............* 0000:7C20 00000000 0000295a 5418264e 4f204e41 *......)ZT.&NO NA* 0000:7C30 4d452020 20204641 54313220 2020.... *ME FAT12 * Now pay attention here... The 11 bytes starting at 0000:7c3e are immediately overlaid by information copied from another part of memory. That information is the Diskette Parameter Table. This data is pointed to by INT 1E. This data is: 7c3e = Step rate and head unload time. 7c3f = Head load time and DMA mode flag. 7c40 = Delay for motor turn off. 7c41 = Bytes per sector. 7c42 = Sectors per track. 7c43 = Intersector gap length. 7c44 = Data length. 7c45 = Intersector gap length during format. 7c46 = Format byte value. 7c47 = Head settling time. 7c48 = Delay until motor at normal speed. The 11 bytes starting at 0000:7c49 are also overlaid by the following data: 7c49 - 7c4c = diskette sector address (as LBA) of the data area. 7c4d - 7c4e = cylinder number to read from. 7c4f - 7c4f = sector number to read from. 7c50 - 7c53 = diskette sector address (as LBA) of the root directory. START: START OF BOOT SECTOR PROGRAM 0000:7C3E FA CLI interrupts off 0000:7C3F 33C0 XOR AX,AX set AX to zero 0000:7C41 8ED0 MOV SS,AX SS is now zero 0000:7C43 BC007C MOV SP,7C00 SP is now 7c00 0000:7C46 16 PUSH SS also set ES 0000:7C47 07 POP ES to zero The INT 1E vector is at 0000:0078. Get the address that the vector points to into the DS:SI registers. 0000:7C48 BB7800 MOV BX,0078 BX is now 78 0000:7C4B 36 SS: 0000:7C4C C537 LDS SI,[BX] DS:SI is now [0:78] 0000:7C4E 1E PUSH DS save DS:SI -- 0000:7C4F 56 PUSH SI saves param tbl addr 0000:7C50 16 PUSH SS save SS:BX -- 0000:7C51 53 PUSH BX saves INT 1E address Move the diskette param table to 0000:7c3e. 0000:7C52 BF3E7C MOV DI,7C3E DI is address of START 0000:7C55 B90B00 MOV CX,000B count is 11 0000:7C58 FC CLD clear direction 0000:7C59 F3 REPZ move the diskette param 0000:7C5A A4 MOVSB table to 0000:7c3e 0000:7C5B 06 PUSH ES also set DS 0000:7C5C 1F POP DS to zero Alter some of the diskette param table data. 0000:7C5D C645FE0F MOV BYTE PTR [DI-02],0F change head settle time at 0000:7c47 0000:7C61 8B0E187C MOV CX,[7C18] sectors per track 0000:7C65 884DF9 MOV [DI-07],CL save at 0000:7c42 Change INT 1E so that it points to the altered Diskette param table at 0000:7c3e. 0000:7C68 894702 MOV [BX+02],AX change INT 1E segment 0000:7C6B C7073E7C MOV WORD PTR [BX],7C3E change INT 1E offset Call INT 13 with AX=0000, disk reset, so that the new diskette param table is used. 0000:7C6F FB STI interrupts on 0000:7C70 CD13 INT 13 do diskette reset call 0000:7C72 7279 JB TALK jmp if any error Detemine the starting sector address of the root directory as an LBA. 0000:7C74 33C0 XOR AX,AX AX is now zero 0000:7C76 3906137C CMP [7C13],AX number sectros zero? 0000:7C7A 7408 JZ SMALL_DISK yes 0000:7C7C 8B0E137C MOV CX,[7C13] number of sectors 0000:7C80 890E207C MOV [7C20],CX save in huge num sects SMALL_DISK: 0000:7C84 A0107C MOV AL,[7C10] number of FAT tables 0000:7C87 F726167C MUL WORD PTR [7C16] number of fat sectors 0000:7C8B 03061C7C ADD AX,[7C1C] number of hidden sectors 0000:7C8F 13161E7C ADC DX,[7C1E] number of hidden sectors 0000:7C93 03060E7C ADD AX,[7C0E] number of reserved sectors 0000:7C97 83D200 ADC DX,+00 number of reserved sectors 0000:7C9A A3507C MOV [7C50],AX save start addr 0000:7C9D 8916527C MOV [7C52],DX of root dir (as LBA) 0000:7CA1 A3497C MOV [7C49],AX save start addr 0000:7CA4 89164B7C MOV [7C4B],DX of root dir (as LBA) Determine sector address of first sector in the data area as an LBA. 0000:7CA8 B82000 MOV AX,0020 size of a dir entry (32) 0000:7CAB F726117C MUL WORD PTR [7C11] number of root dir entries 0000:7CAF 8B1E0B7C MOV BX,[7C0B] bytes per sector 0000:7CB3 03C3 ADD AX,BX 0000:7CB5 48 DEC AX 0000:7CB6 F7F3 DIV BX 0000:7CB8 0106497C ADD [7C49],AX add to start addr 0000:7CBC 83164B7C00 ADC WORD PTR [7C4B],+00 of root dir (as LBA) Read the first root dir sector into 0000:0500. 0000:7CC1 BB0005 MOV BX,0500 addr to read into 0000:7CC4 8B16527C MOV DX,[7C52] get start of address 0000:7CC8 A1507C MOV AX,[7C50] of root dir (as LBA) 0000:7CCB E89200 CALL CONVERT call conversion routine 0000:7CCE 721D JB TALK jmp is any error 0000:7CD0 B001 MOV AL,01 read 1 sector 0000:7CD2 E8AC00 CALL READ_SECTORS read 1st root dir sector 0000:7CD5 7216 JB TALK jmp if any error 0000:7CD7 8BFB MOV DI,BX addr of 1st dir entry 0000:7CD9 B90B00 MOV CX,000B count is 11 0000:7CDC BEE67D MOV SI,7DE6 addr of file names 0000:7CDF F3 REPZ is this "IO.SYS"? 0000:7CE0 A6 CMPSB 0000:7CE1 750A JNZ TALK no 0000:7CE3 8D7F20 LEA DI,[BX+20] addr of next dir entry 0000:7CE6 B90B00 MOV CX,000B count is 11 0000:7CE9 F3 REPZ is this "MSDOS.SYS"? 0000:7CEA A6 CMPSB 0000:7CEB 7418 JZ FOUND_FILES they are equal TALK: Display "Non-System disk..." message, wait for user to hit a key, restore the INT 1E vector and then call INT 19 to start boot processing all over again. 0000:7CED BE9E7D MOV SI,7D9E "Non-System disk..." 0000:7CF0 E85F00 CALL MSG_LOOP display message 0000:7CF3 33C0 XOR AX,AX INT 16 function 0000:7CF5 CD16 INT 16 read keyboard 0000:7CF7 5E POP SI get INT 1E vector's 0000:7CF8 1F POP DS address 0000:7CF9 8F04 POP [SI] restore the INT 1E 0000:7CFB 8F4402 POP [SI+02] vector's data 0000:7CFE CD19 INT 19 CALL INT 19 to try again SETUP_TALK: 0000:7D00 58 POP AX pop junk off stack 0000:7D01 58 POP AX pop junk off stack 0000:7D02 58 POP AX pop junk off stack 0000:7D03 EBE8 JMP TALK now talk to the user FOUND_FILES: Compute the sector address of the first sector of IO.SYS. 0000:7D05 8B471A MOV AX,[BX+1A] get starting cluster num 0000:7D08 48 DEC AX subtract 1 0000:7D09 48 DEC AX subtract 1 0000:7D0A 8A1E0D7C MOV BL,[7C0D] sectors per cluster 0000:7D0E 32FF XOR BH,BH 0000:7D10 F7E3 MUL BX multiply 0000:7D12 0306497C ADD AX,[7C49] add start addr of 0000:7D16 13164B7C ADC DX,[7C4B] root dir (as LBA) Read IO.SYS into memory at 0000:0700. IO.SYS is 3 sectors long. 0000:7D1A BB0007 MOV BX,0700 address to read into 0000:7D1D B90300 MOV CX,0003 read 3 sectors READ_LOOP: Read the first 3 sectors of IO.SYS (IO.SYS is much longer than 3 sectors). 0000:7D20 50 PUSH AX save AX 0000:7D21 52 PUSH DX save DX 0000:7D22 51 PUSH CX save CX 0000:7D23 E83A00 CALL CONVERT call conversion routine 0000:7D26 72D8 JB SETUP_TALK jmp if error 0000:7D28 B001 MOV AL,01 read one sector 0000:7D2A E85400 CALL READ_SECTORS read one sector 0000:7D2D 59 POP CX restore CX 0000:7D2E 5A POP DX restore DX 0000:7D2F 58 POP AX restore AX 0000:7D30 72BB JB TALK jmp if any INT 13 error 0000:7D32 050100 ADD AX,0001 add one to the sector addr 0000:7D35 83D200 ADC DX,+00 add one to the sector addr 0000:7D38 031E0B7C ADD BX,[7C0B] incr mem addr by sect size 0000:7D3C E2E2 LOOP READ_LOOP read next sector Leave information in the AX, BX, CX and DX registers for IO.SYS to use. Finally, jump to IO.SYS at 0070:0000. 0000:7D3E 8A2E157C MOV CH,[7C15] media type 0000:7D42 8A16247C MOV DL,[7C24] drive number 0000:7D46 8B1E497C MOV BX,[7C49] get start addr of 0000:7D4A A14B7C MOV AX,[7C4B] root dir (as LBA) 0000:7D4D EA00007000 JMP 0070:0000 JUMP TO 0070:0000 MSG_LOOP: This routine displays a message using INT 10 one character at a time. The message address is in DS:SI. 0000:7D52 AC LODSB get message character 0000:7D53 0AC0 OR AL,AL end of message? 0000:7D55 7429 JZ RETURN jmp if yes 0000:7D57 B40E MOV AH,0E display one character 0000:7D59 BB0700 MOV BX,0007 video attrbiutes 0000:7D5C CD10 INT 10 display one character 0000:7D5E EBF2 JMP MSG_LOOP do again CONVERT: This routine converts a sector address (an LBA) to a CHS address. The LBA is in DX:AX. 0000:7D60 3B16187C CMP DX,[7C18] hi part of LBA > sectPerTrk? 0000:7D64 7319 JNB SET_CARRY jmp if yes 0000:7D66 F736187C DIV WORD PTR [7C18] div by sectors per track 0000:7D6A FEC2 INC DL add 1 to sector number 0000:7D6C 88164F7C MOV [7C4F],DL save sector number 0000:7D70 33D2 XOR DX,DX zero DX 0000:7D72 F7361A7C DIV WORD PTR [7C1A] div number of heads 0000:7D76 8816257C MOV [7C25],DL save head number 0000:7D7A A34D7C MOV [7C4D],AX save cylinder number 0000:7D7D F8 CLC clear carry 0000:7D7E C3 RET return SET_CARRY: 0000:7D7F F9 STC set carry RETURN: 0000:7D80 C3 RET return READ_SECTORS: The caller of this routine supplies: AL = number of sectors to read ES:BX = memory location to read into and CHS address to read from in memory locations 7c25 and 7C4d-7c4f. 0000:7D81 B402 MOV AH,02 INT 13 read sectors 0000:7D83 8B164D7C MOV DX,[7C4D] get cylinder number 0000:7D87 B106 MOV CL,06 shift count 0000:7D89 D2E6 SHL DH,CL shift upper cyl left 6 bits 0000:7D8B 0A364F7C OR DH,[7C4F] or in sector number 0000:7D8F 8BCA MOV CX,DX move to CX 0000:7D91 86E9 XCHG CH,CL CH=cyl lo, CL=cyl hi + sect 0000:7D93 8A16247C MOV DL,[7C24] drive number 0000:7D97 8A36257C MOV DH,[7C25] head number 0000:7D9B CD13 INT 13 read sectors 0000:7D9D C3 RET return Data not used. 0000:7D90 ca86e98a 16247c8a 36257ccd 13c3.... *.....$|.6%|... * Messages here. 0000:7D90 ........ ........ ........ ....0d0a * ..* 0000:7Da0 4e6f6e2d 53797374 656d2064 69736b20 *Non-System disk * 0000:7Db0 6f722064 69736b20 6572726f 720d0a52 *or disk error..R* 0000:7Dc0 65706c61 63652061 6e642070 72657373 *eplace and press* 0000:7Dd0 20616e79 206b6579 20776865 6e207265 * any key when re* 0000:7De0 6164790d 0a00.... ........ ........ *ady... * MS DOS hidden file names (first two root directory entries). 0000:7De0 ........ ....494f 20202020 20205359 * IO SY* 0000:7Df0 534d5344 4f532020 20535953 000055aa *SMSDOS SYS..U.* The last two bytes contain a 55AAH signature. 0000:7Df0 ........ ........ ........ ....55aa * U.* --------------------------------------------------------------------- How It Works -- OS2 Boot Sector Version 1a by Hale Landis (landis@sugs.tware.com) THE "HOW IT WORKS" SERIES This is one of several How It Works documents. The series currently includes the following: * How It Works -- CHS Translation * How It Works -- Master Boot Record * How It Works -- DOS Floppy Boot Sector * How It Works -- OS2 Boot Sector * How It Works -- Partition Tables OS2 BOOT SECTOR Note: I'll leave it to someone else to provide you with a disassembly of an OS/2 HPFS boot sector, or a Linux boot sector, or a WinNT boot sector, etc. This article is a disassembly of a floppy or hard disk boot sector for OS/2. Apparently OS/2 uses the same boot sector for both environments. Basically a bootable FAT hard disk partition looks like a big floppy during the early stages of the system's boot processing. This sector is at cylinder 0, head 0, sector 1 of a floppy or it is the first sector within a FAT hard disk partition. OS/2 floppy disk and hard disk boot sectors are created by the OS/2 FORMAT program. At the completion of your system's Power On Self Test (POST), INT 19 is called. Usually INT 19 tries to read a boot sector from the first floppy drive. If a boot sector is found on the floppy disk, the that boot sector is read into memory at location 0000:7C00 and INT 19 jumps to memory location 0000:7C00. However, if no boot sector is found on the first floppy drive, INT 19 tries to read the MBR from the first hard drive. If an MBR is found it is read into memory at location 0000:7c00 and INT 19 jumps to memory location 0000:7c00. The small program in the MBR will attempt to locate an active (bootable) partition in its partition table. If such a partition is found, the boot sector of that partition is read into memory at location 0000:7C00 and the MBR program jumps to memory location 0000:7C00. Each operating system has its own boot sector format. The small program in the boot sector must locate the first part of the operating system's kernel loader program (or perhaps the kernel itself or perhaps a "boot manager program") and read that into memory. INT 19 is also called when the CTRL-ALT-DEL keys are used. On most systems, CTRL-ALT-DEL causes an short version of the POST to be executed before INT 19 is called. ===== Where stuff is: The BIOS Parameter Block (BPB) starts at offset 0. The boot sector program starts at offset 46. The messages issued by this program start at offset 198. The OS/2 boot loader file name starts at offset 1d5. The boot sector signature is at offset 1fe. Here is a summary of what this thing does: 1) If booting from a hard disk partition, skip to step 6. 2) Copy Diskette Parameter Table which is pointed to by INT 1E to the top of memory. 3) Alter the copy of the Diskette Parameter Table. 4) Alter INT 1E to point to altered Diskette Parameter Table at the top of memory. 5) Do INT 13 AH=00, disk reset call so that the altered Diskette Parameter Table is used. 6) Compute sector address of the root directory. 7) Read the entire root directory into memory starting at location 1000:0000. 8) Search the root directory entires for the file OS2BOOT. 9) Read the OS2BOOT file into memory at 0800:0000. 10) Do a far return to enter the OS2BOOT program at 0800:0000. NOTES: This program uses the CHS based INT 13H AH=02 to read the FAT root directory and to read the OS2BOOT file. If the drive is >528MB, this CHS must be a translated CHS (or L-CHS, see my BIOS TYPES document). Except for internal computations no addresses in LBA form are used, another reason why LBA doesn't solve the >528MB problem. ===== Here is the entire sector in hex and ascii. OFFSET 0 1 2 3 4 5 6 7 8 9 A B C D E F *0123456789ABCDEF* 000000 eb449049 424d2032 302e3000 02100100 *.D.IBM 20.0.....* 000010 02000200 00f8d800 3e000e00 3e000000 *........>...>...* 000020 06780d00 80002900 1c0c234e 4f204e41 *.x....)...#NO NA* 000030 4d452020 20204641 54202020 20200000 *ME FAT ..* 000040 00100000 0000fa33 db8ed3bc ff7bfbba *.......3.....{..* 000050 c0078eda 803e2400 00753d1e b840008e *.....>$..u=..@..* 000060 c026ff0e 1300cd12 c1e0068e c033ff33 *.&...........3.3* 000070 c08ed8c5 367800fc b90b00f3 a41fa118 *....6x..........* 000080 0026a204 001e33c0 8ed8a378 008c067a *.&....3....x...z* 000090 001f8a16 2400cd13 a0100098 f7261600 *....$........&..* 0000a0 03060e00 5091b820 00f72611 008b1e0b *....P.. ..&.....* 0000b0 0003c348 f7f35003 c1a33e00 b800108e *...H..P...>.....* 0000c0 c033ff59 890e4400 58a34200 33d2e873 *.3.Y..D.X.B.3..s* 0000d0 0033db8b 0e11008b fb51b90b 00bed501 *.3.......Q......* 0000e0 f3a65974 0583c320 e2ede335 268b471c *..Yt... ...5&.G.* 0000f0 268b571e f7360b00 fec08ac8 268b571a *&.W..6......&.W.* 000100 4a4aa00d 0032e4f7 e203063e 0083d200 *JJ...2.....>....* 000110 bb00088e c333ff06 57e82800 8d360b00 *.....3..W.(..6..* 000120 cbbe9801 eb03bead 01e80900 bec201e8 *................* 000130 0300fbeb feac0ac0 7409b40e bb0700cd *........t.......* 000140 10ebf2c3 50525103 061c0013 161e00f7 *....PRQ.........* 000150 361800fe c28ada33 d2f7361a 008afa8b *6......3..6.....* 000160 d0a11800 2ac34050 b402b106 d2e60af3 *....*.@P........* 000170 8bca86e9 8a162400 8af78bdf cd1372a6 *......$.......r.* 000180 5b598bc3 f7260b00 03f85a58 03c383d2 *[Y...&....ZX....* 000190 002acb7f afc31200 4f532f32 20212120 *.*......OS/2 !! * 0001a0 53595330 31343735 0d0a0012 004f532f *SYS01475.....OS/* 0001b0 32202121 20535953 30323032 350d0a00 *2 !! SYS02025...* 0001c0 12004f53 2f322021 21205359 53303230 *..OS/2 !! SYS020* 0001d0 32370d0a 004f5332 424f4f54 20202020 *27...OS2BOOT * 0001e0 00000000 00000000 00000000 00000000 *................* 0001f0 00000000 00000000 00000000 000055aa *..............U.* ===== The first 62 bytes of a boot sector are known as the BIOS Parameter Block (BPB). Here is the layout of the BPB fields and the values they are assigned in this boot sector: db JMP instruction at 7c00 size 2 = eb44 db NOP instruction 7c02 1 90 db OEMname 7c03 8 'IBM 20.0' dw bytesPerSector 7c0b 2 0200 db sectPerCluster 7c0d 1 01 dw reservedSectors 7c0e 2 0001 db numFAT 7c10 1 02 dw numRootDirEntries 7c11 2 0200 dw numSectors 7c13 2 0000 (use numSectorsHuge) db mediaType 7c15 1 f8 dw numFATsectors 7c16 2 00d8 dw sectorsPerTrack 7c18 2 003e dw numHeads 7c1a 2 000e dd numHiddenSectors 7c1c 4 00000000 dd numSectorsHuge 7c20 4 000d7806 db driveNum 7c24 1 80 db reserved 7c25 1 00 db signature 7c26 1 29 dd volumeID 7c27 4 001c0c23 db volumeLabel 7c2b 11 'NO NAME ' db fileSysType 7c36 8 'FAT ' ===== Here is the boot sector... The first 3 bytes of the BPB are JMP and NOP instructions. 0000:7C00 EB44 JMP START 0000:7C02 90 NOP Here is the rest of the BPB. 0000:7C00 eb449049 424d2032 302e3000 02100100 *.D.IBM 20.0.....* 0000:7C10 02000200 00f8d800 3e000e00 3e000000 *........>...>...* 0000:7C20 06780d00 80002900 1c0c234e 4f204e41 *.x....)...#NO NA* 0000:7C30 4d452020 20204641 54202020 20200000 *ME FAT ..* Additional data areas. 0000:7C30 ........ ........ ........ ....0000 * ..* 0000:7C40 00100000 0000.... ........ ........ *...... * Note: 0000:7c3e (DS:003e) = number of sectors in the FATs and root dir. 0000:7c42 (DS:0042) = number of sectors in the FAT. 0000:7c44 (DS:0044) = number of sectors in the root dir. START: START OF BOOT SECTOR PROGRAM 0000:7C46 FA CLI interrupts off 0000:7C47 33DB XOR BX,BX zero BX 0000:7C49 8ED3 MOV SS,BX SS now zero 0000:7C4B BCFF7B MOV SP,7BFF SP now 7bff 0000:7C4E FB STI interrupts on 0000:7C4F BAC007 MOV DX,07C0 set DX to 0000:7C52 8EDA MOV DS,DX 07c0 Are we booting from a floppy or a hard disk partition? 0000:7C54 803E240000 CMP BYTE PTR [0024],00 is driveNum in BPB 00? 0000:7C59 753D JNZ NOT_FLOPPY jmp if not zero We are booting from a floppy. The Diskette Parameter Table must be copied and altered... Diskette Parameter Table is pointed to by INT 1E. This program moves this table to high memory, alters the table, and changes INT 1E to point to the altered table. This table contains the following data: ????:0000 = Step rate and head unload time. ????:0001 = Head load time and DMA mode flag. ????:0002 = Delay for motor turn off. ????:0003 = Bytes per sector. ????:0004 = Sectors per track. ????:0005 = Intersector gap length. ????:0006 = Data length. ????:0007 = Intersector gap length during format. ????:0008 = Format byte value. ????:0009 = Head settling time. ????:000a = Delay until motor at normal speed. Compute a valid high memory address. 0000:7C5B 1E PUSH DS save DS 0000:7C5C B84000 MOV AX,0040 set ES 0000:7C5F 8EC0 MOV ES,AX to 0040 (BIOS data area) 0000:7C61 26 ES: reduce system memory 0000:7C62 FF0E1300 DEC WORD PTR [0013] size by 1024 0000:7C66 CD12 INT 12 get system memory size 0000:7C68 C1E06 SHL AX,06 shift AX (mult by 64) 0000:7C6B 8EC0 MOV ES,AX move to ES 0000:7C6D 33FF XOR DI,DI zero DI Move the diskette param table to high memory. 0000:7C6F 33C0 XOR AX,AX zero AX 0000:7C71 8ED8 MOV DS,AX DS now zero 0000:7C73 C5367800 LDS SI,[0078] DS:SI = INT 1E vector 0000:7C77 FC CLD clear direction 0000:7C78 B90B00 MOV CX,000B count is 11 0000:7C7B F3 REPZ copy diskette param table 0000:7C7C A4 MOVSB to top of memory Alter the number of sectors per track in the diskette param table in high memory. 0000:7C7D 1F POP DS restore DS 0000:7C7E A11800 MOV AX,[0018] get sectorsPerTrack from BPB 0000:7C81 26 ES: alter sectors per track 0000:7C82 A20400 MOV [0004],AL in diskette param table Change INT 1E to point to altered diskette param table and do a INT 13 disk reset call. 0000:7C85 1E PUSH DS save DS 0000:7C86 33C0 XOR AX,AX AX now zero 0000:7C88 8ED8 MOV DS,AX DS no zero 0000:7C8A A37800 MOV [0078],AX alter INT 1E vector 0000:7C8D 8C067A00 MOV [007A],ES to point to altered diskette param table 0000:7C91 1F POP DS restore DS 0000:7C92 8A162400 MOV DL,[0024] driveNum from BPB 0000:7C96 CD13 INT 13 diskette reset NOT_FLOPPY: Compute the location and the size of the root directory. Read the entire root directory into memory. 0000:7C98 A01000 MOV AL,[0010] get numFAT 0000:7C9B 98 CBW make into a word 0000:7C9C F7261600 MUL WORD PTR [0016] mult by numFatSectors 0000:7CA0 03060E00 ADD AX,[000E] add reservedSectors 0000:7CA4 50 PUSH AX save 0000:7CA5 91 XCHG CX,AX move to CX 0000:7CA6 B82000 MOV AX,0020 dir entry size 0000:7CA9 F7261100 MUL WORD PTR [0011] mult by numRootDirEntries 0000:7CAD 8B1E0B00 MOV BX,[000B] get bytesPerSector 0000:7CB1 03C3 ADD AX,BX add 0000:7CB3 48 DEC AX subtract 1 0000:7CB4 F7F3 DIV BX div by bytesPerSector 0000:7CB6 50 PUSH AX save number of dir sectors 0000:7CB7 03C1 ADD AX,CX add number of fat sectors 0000:7CB9 A33E00 MOV [003E],AX save 0000:7CBC B80010 MOV AX,1000 AX is now 1000 0000:7CBF 8EC0 MOV ES,AX ES is now 1000 0000:7CC1 33FF XOR DI,DI DI is now zero 0000:7CC3 59 POP CX get number dir sectors 0000:7CC4 890E4400 MOV [0044],CX save 0000:7CC8 58 POP AX get number fat sectors 0000:7CC9 A34200 MOV [0042],AX save 0000:7CCC 33D2 XOR DX,DX DX now zero 0000:7CCE E87300 CALL READ_SECTOR read 1st sect of root dir 0000:7CD1 33DB XOR BX,BX BX is now zero 0000:7CD3 8B0E1100 MOV CX,[0011] number of root dir entries DIR_SEARCH: SEARCH FOR OS2BOOT. Search the root directory for the file name OS2BOOT. 0000:7CD7 8BFB MOV DI,BX DI is dir entry addr 0000:7CD9 51 PUSH CX save CX 0000:7CDA B90B00 MOV CX,000B count is 11 0000:7CDD BED501 MOV SI,01D5 addr of "OS2BOOT" 0000:7CE0 F3 REPZ is 1st dir entry 0000:7CE1 A6 CMPSB for "OS2BOOT"? 0000:7CE2 59 POP CX restore CX 0000:7CE3 7405 JZ FOUND_OS2BOOT jmp if OS2BOOT 0000:7CE5 83C320 ADD BX,+20 incr to next dir entry 0000:7CE8 E2ED LOOP DIR_SEARCH try again FOUND_OS2BOOT: FOUND OS2BOOT. OS2BOOT was found. Get the starting cluster number and convert to a sector address. Read OS2BOOT into memory and finally do a far return to enter the OS2BOOT program. 0000:7CEA E335 JCXZ FAILED1 JMP if CX zero. 0000:7CEC 26 ES: get the szie of 0000:7CED 8B471C MOV AX,[BX+1C] the OS2BOOT file 0000:7CF0 26 ES: from the OS2BOOT 0000:7CF1 8B571E MOV DX,[BX+1E] directory entry 0000:7CF4 F7360B00 DIV WORD PTR [000B] div by bytesPerSect 0000:7CF8 FEC0 INC AL add 1 0000:7CFA 8AC8 MOV CL,AL num sectors OS2BOOT 0000:7CFC 26 ES: get the starting 0000:7CFD 8B571A MOV DX,[BX+1A] cluster number 0000:7D00 4A DEC DX subtract 1 0000:7D01 4A DEC DX subtract 1 0000:7D02 A00D00 MOV AL,[000D] sectorsPerCluster 0000:7D05 32E4 XOR AH,AH mutiply 0000:7D07 F7E2 MUL DX to get LBA 0000:7D09 03063E00 ADD AX,[003E] add number of FAT sectors 0000:7D0D 83D200 ADC DX,+00 to LBA 0000:7D10 BB0008 MOV BX,0800 set ES 0000:7D13 8EC3 MOV ES,BX to 0800 0000:7D15 33FF XOR DI,DI set ES:DI to entry point 0000:7D17 06 PUSH ES address of 0000:7D18 57 PUSH DI OS2BOOT 0000:7D19 E82800 CALL READ_SECTOR read OS2BOOT into memory 0000:7D1C 8D360B00 LEA SI,[000B] set DS:SI 0000:7D20 CB RETF "far return" to OS2BOOT FAILED1: OS2BOOT WAS NOT FOUND. 0000:7D21 BE9801 MOV SI,0198 "SYS01475" message 0000:7D24 EB03 JMP FAILED3 FAILED2: ERROR FROM INT 13. 0000:7D26 BEAD01 MOV SI,01AD "SYS02025" message FAILED3: OUTPUT ERROR MESSAGES. 0000:7D29 E80900 CALL MSG_LOOP display message 0000:7D2C BEC201 MOV SI,01C2 "SYS02027" message 0000:7D2F E80300 CALL MSG_LOOP display message 0000:7D32 FB STI interrupts on HANG: HANG THE SYSTEM! 0000:7D33 EBFE JMP HANG sit and stay! MSG_LOOP: DISPLAY AN ERROR MESSAGE. Routine to display the message text pointed to by SI. 0000:7D35 AC LODSB get next char of message 0000:7D36 0AC0 OR AL,AL end of message? 0000:7D38 7409 JZ RETURN jmp if yes 0000:7D3A B40E MOV AH,0E write 1 char 0000:7D3C BB0700 MOV BX,0007 video attributes 0000:7D3F CD10 INT 10 INT 10 to write 1 char 0000:7D41 EBF2 JMP MSG_LOOP do again RETURN: 0000:7D43 C3 RET return READ_SECTOR: ROUTINE TO READ SECTORS. Read sectors into memory. Read multiple sectors but don't read across a track boundary. The caller supplies the following: DX:AX = sector address to read (as LBA) CX = number of sectors to read ES:DI = memory address to read into 0000:7D44 50 PUSH AX save lower part of LBA 0000:7D45 52 PUSH DX save upper part of LBA 0000:7D46 51 PUSH CX save number of sect to read 0000:7D47 03061C00 ADD AX,[001C] add numHiddenSectors 0000:7D4B 13161E00 ADC DX,[001E] to LBA 0000:7D4F F7361800 DIV WORD PTR [0018] div by sectorsPerTrack 0000:7D53 FEC2 INC DL add 1 to sector number 0000:7D55 8ADA MOV BL,DL save sector number 0000:7D57 33D2 XOR DX,DX zero upper part of LBA 0000:7D59 F7361A00 DIV WORD PTR [001A] div by numHeads 0000:7D5D 8AFA MOV BH,DL save head number 0000:7D5F 8BD0 MOV DX,AX save cylinder number 0000:7D61 A11800 MOV AX,[0018] sectorsPerTrack 0000:7D64 2AC3 SUB AL,BL sub sector number 0000:7D66 40 INC AX add 1 0000:7D67 50 PUSH AX save number of sector to rea d 0000:7D68 B402 MOV AH,02 INT 13 read sectors 0000:7D6A B106 MOV CL,06 shift count 0000:7D6C D2E6 SHL DH,CL shift high cyl left 0000:7D6E 0AF3 OR DH,BL or in sector number 0000:7D70 8BCA MOV CX,DX move cyl/sect to CX 0000:7D72 86E9 XCHG CH,CL swap cyl/sect 0000:7D74 8A162400 MOV DL,[0024] driveNum 0000:7D78 8AF7 MOV DH,BH head number 0000:7D7A 8BDF MOV BX,DI memory addr to read into 0000:7D7C CD13 INT 13 INT 13 read sectors call 0000:7D7E 72A6 JB FAILED2 jmp if any error 0000:7D80 5B POP BX get number of sectors read 0000:7D81 59 POP CX restore CX 0000:7D82 8BC3 MOV AX,BX number of sector to AX 0000:7D84 F7260B00 MUL WORD PTR [000B] multiply by sector size 0000:7D88 03F8 ADD DI,AX add to memory address 0000:7D8A 5A POP DX restore upper part of LBA 0000:7D8B 58 POP AX resotre lower part of LBA 0000:7D8C 03C3 ADD AX,BX add number of sector just 0000:7D8E 83D200 ADC DX,+00 read to LBA 0000:7D91 2ACB SUB CL,BL decr requested num of sect 0000:7D93 7FAF JG READ_SECTOR jmp if not zero 0000:7D95 C3 RET return Data not used. 0000:7D90 ........ ....1200 ........ ........ * .. * Messages here. 0000:7D90 ........ ........ 4f532f32 20212120 * OS/2 !! * 0000:7Da0 53595330 31343735 0d0a0012 004f532f *SYS01475.....OS/* 0000:7Db0 32202121 20535953 30323032 350d0a00 *2 !! SYS02025...* 0000:7Dc0 12004f53 2f322021 21205359 53303230 *..OS/2 !! SYS020* 0000:7Dd0 32370d0a 00...... ........ ........ *27... * OS/2 loader file name. 0000:7Dd0 ........ ..4f5332 424f4f54 20202020 * OS2BOOT * Data not used. 0000:7De0 00000000 00000000 00000000 00000000 *................* 0000:7Df0 00000000 00000000 00000000 0000.... *.............. * The last two bytes contain a 55AAH signature. 0000:7Df0 ........ ........ ........ ....55aa * U.*