Technical Info on FIPS 
---------------------- 
 
FIPS was written in C++ V2.0 with the Turbo C++ 1.0 compiler. 
It should compile with any newer C++ compiler (perhaps after minor changes 
to the BIOS calls). 
 
If you're a C++ wizard, don't look too closely at the code, this is my first 
C++ program, so it is far from acceptable (too much public data, some ini- 
tializers and assignment operators are missing etc.). Constructive Critizism 
is always welcome however. 
 
How FIPS works: 
 
FIPS uses the BIOS interrupts 13h 00h (reset disks), 13h 02h (read sector), 
13h 08h (get drive parameters), 13h 03h (write sector) and 13h 04h (verify 
sector). 
 
Here is the sequence of function calls in main: 
 
evaluate_argument_vector 
  read the commandline arguments and set the global variables accordingly 
notice 
  display copyright notice and version number 
ask_for_drive_number 
  let the user choose the drive (if more than 1) 
harddrive.reset 
  reset harddrive 
harddrive.rootsector->read 
  read the sector 0,0,1 of the chosen drive into an array of unsigned char 
hd.partition_table().get 
  extract the necessary information from the rootsector (see below - The 
  Rootsector) 
hd.print_partition_table 
  print the information 
hd.check 
  check if everything is ok (see below - The Rootsector) 
ask_for_partition_number 
  let the user choose the partition 
partition->bootsector->read 
  read the first sector of the chosen partition to another array 
partition->bpb().get 
  extract info from the bootsector (see below - The Bootsector) 
partition->print_bpb 
  print the info 
partition->info().get 
  calculate no. of clusters, starting sector of FATs etc. 
partition->check 
  check bootsector (see below - The Bootsector) 
fat1.check_against(fat2) 
  check if FAT 1 is identical to FAT 2 (see below - The FAT) 
save_root_and_boot 
  write root- and bootsector to floppy disk (optional) 
ask_for_new_start_cylinder 
  ask the user for the first cylinder of the new partition 
fat2.check_empty 
  check if chosen part of partition is empty (see below - The FAT) 
hd.calculate_new_root 
  from the chosen start cylinder calculate the new partition table 
  Note that the partition entries will be moved to the beginning of the par-  
  tition table, so that the new partition will be the last one and the drive 
  names will not change. 
hd.partition_table.put 
  write the new partition table into the rootsector-buffer 
hd.partition_table.get,hd.print_partition_table,hd.check 
  check if new rootsector is ok 
partition->calculate_new_boot 
  put new number of sectors in bootsector info 
partition->bpb()->put 
  write new bootsector info into bootsector-buffer 
partition->bpb()->get,partition->print_bpb,partition->check 
  check if new bootsector is ok 
ask_for_write_permission 
  ask if user wants to proceed 
harddrive.rootsector->writE 
  write the changed root sector to the disk 
partition->bootsector->write 
  write the changed boot sector to the disk 
 
 
The Rootsector 
-------------- 
 
The rootsector is the first sector on every hard disk. It contains the 
program that loads the bootsector of the bootable partition and the 
partition table. The last two bytes of the Rootsector must be 55 aa (hex). 
The partition table begins at 1be. It contains 4 * 16 Bytes for the four 
possible partitions. 
All numbers are zero based except the start/end-sector number (may be 1-63). 
One partition entry contains the following: 
 
1 Byte - Bootable Flag. Must be 0 (not bootable) or 80h (bootable). 
	 At most one Partition may be bootable at a time. 
	 (somewhere I read the bootable flag may also be 81h for the 
	 second drive - does anybody know anything about that?) 
 
1 Byte - Start Head. The number of the head of the first sector of the 
	 partition. 
 
2 Bytes - Start Sector + Cylinder. The Bits are as follows: 
 
			CCSSSSSS CCCCCCCC 
 
	  where the first byte contains the sector number (1 - 63), and 
	  the high two bits of the cylinder number. The second byte con- 
	  tains the low eight bits of the cylinder number. 
 
1 Byte - System Indicator. For DOS this may be: 
 
	1 - 12-bit FAT, 16-bit sector number 
	4 - 16-bit FAT, 16-bit sector number 
	5 - Extended Partition 
	6 - 16-bit FAT, 32-bit sector number 
 
1 Byte - End Head. Head Number of the last sector of the partition 
 
2 Bytes - End Sector + Cylinder. Same format as Start Sector + Cylinder 
 
4 Bytes - First Sector. Number of the first sector of the partition. This 
	  corresponds to the Start Head, Sector + Cylinder. High Byte 
	  comes first. 
 
4 Bytes - Total number of Sectors. 
 
The function check_rootsector_validity checks the following: 
 
- Signature Bytes (55 aa) in the last two bytes of the sector 
- not more than one bootable partition 
- Bootable flag is 0 or 80h 
- Start/End sector of a partition is not 0 
- Start/End sector & head are not greater than drive geometry allows 
- Start cylinder * sectors * heads + start head * sectors + start sector - 1 
  = first sector (where sectors is no. of sectors per track, heads is 
  no. of heads of the drive) 
- End cylinder * sectors * heads + end head * sector + end sector = first 
  sector + number of sectors 
- if System Indicator is 0, all other bytes of partition entry are 0 
- all partitions except the first begin on cylinder boundaries (head = 0, 
  sectors = 1) 
- all partition end on cylinder boundaries 
- partitions don't overlap 
- no free space between partitions 
 
 
The Bootsector 
-------------- 
 
The bootsector is the first sector of every partition. It contains the 
program that boots the operating system and the bios parameter block. 
The last two bytes must again contain 55 aa. The information in the 
bootsector is the following: 
 
00  3 bytes  jump instruction ('eb xx 90' or 'e9 xx xx') 
03  8 bytes  OEM name and version - f.ex. MSDOS5.0 
0b  2 bytes  bytes per sector - should be 512 
0d  1 byte   sectors per cluster - power of two 
0e  2 bytes  reserved sectors - typically 1 (bootsector) 
10  1 byte   number of FATs - must be 2 
11  2 bytes  number of rootdirectory entries - typically 512 
13  2 bytes  number of sectors (short) - 0, if BIGDOS partition 
15  1 byte   media descriptor - typically f8h 
16  2 bytes  sectors per FAT - varies 
18  2 bytes  sectors per track 
1a  2 bytes  number of heads 
1c  2 bytes  number of hidden sectors (low) 
 
- extended BPB since DOS 4.0 - 
 
1e  2 bytes  number of hidden sectors (high) 
20  4 bytes  number of sectors (long) 
24  1 byte   physical drive number - 80h or 81h 
25  1 byte   reserved 
26  1 byte   signature - 29h 
 
The function check_bootsector_validity checks the following: 
 
- correct jump instruction 
- signature bytes 55 aa in the last two bytes of the sector 
- bytes per sector = 512 
- sectors per cluster is power of two 
- reserved sectors = 1 
- number of FATs = 2 
- number of rootdirectory entries is multiple of 16 
- media descriptor = f8h 
- sectors per fat <= 256 
- sectors per fat big enough to hold complete FAT 
- sectors per track matches BIOS info 
- number of heads matches BIOS info 
- hidden sectors = start sector 
- signature = 29h, if BIGDOS 
- physical drive number = actual drive number 
- number of sectors matches partition info 
- system indicator byte in rootsector matches partition type 
 
 
The FAT 
------- 
 
The File Allocation Table contains the information how the clusters of the 
disk are linked to files. Every directory entry contains a pointer to the 
first cluster of the file. The corresponding cluster entry in the FAT contains 
a pointer to the next cluster, or an EOF marker (FFFF for 16-bit FATs, FFF for 
12-bit FATs) if the cluster is the last one of the file. 
Bad clusters are marked with FFF7 or FF7. Empty clusters are marked with 0. 
The first cluster on the disk is cluster number 2, it begins at the first 
sector after the root directory. The FAT entries for the clusters 0 and 1 
contain the media descriptor byte (usually F8h for harddisk) and two or three 
FFh bytes. 
There exist two copies of the FAT on a normal DOS partition, these two copies 
must be identical. FAT 2 is the primary FAT. 
 
The function check_fat_validity checks if the two FATs are identical and if 
the entries 0 and 1 contain what they are supposed to. 
 
The function check_fat_empty checks if the cluster entries that cover the new 
partition contain either 0 (empty) or FFF7 (Bad cluster). 
 
 
------------------------------------------------------------------------------ 
 
I hope you find this information useful. If you found anything not to be exact 
or have additions, please let me know asap. If you have any information about 
unusual formats (sectors sizes other than 512, more than 2 hard disks etc.) 
please contact me so I can incorporate these in the next release. 
 
Arno Schaefer 
schaefer@rbg.informatik.th-darmstadt.de