This page doesn't give a full description of the FAT filesystem. It only
gives some details you need to understand because they are used in some of my
A good description of the FAT filesystem is given in The Indispensable PC Hardware Book.
There are several versions of the FAT filesystem. The one I describe in this
chapter is the first one. Later versions include VFAT and FAT32. In this
version, the files can only have a name of 8 bytes maximum plus an extension of
3 bytes maximum.
From a physical viewpoint, the data on floppy disks or hard disks is organized in tracks, heads and sectors. You can find the data on the disk if you know the track, the head and the sector where it is. The number of tracks, heads and sectors is dependent on the type of disk. FAT hides theses differences between disks by using the concept of logical sector. The physical sectors are assigned a serial number. This serial number is the logical sector number corresponding to the physical sector.
For floppy disks, the serial numbers of the physical sectors are assigned as
|Physical sector||Logical sector|
|track 0, head 0, sector 1||0|
|track 0, head 0, sector 2||1|
|track 0, head 0, sectors 3 to 18||2-17|
|track 0, head 1, sector 1||18|
|track 0, head 1, sectors 2 to 18||19-35|
|track 1, head 0, sector 1||36|
|track 1, head 0, sectors 2 to 18||37-53|
|track 1, head 1, sectors 1 to 18||54-71|
|tracks 2 to 79, all heads and sectors||72-2879|
lsn = S-1 + (T*nh + H) * spt
S = (lsn mod spt) + 1
H = (lsn / spt) mod nh
T = lsn / (spt*nh)
Sis the physical sector number
His the head number
Tis the track number
lsnis the logical sector number
sptis the number of sectors per track
nhis the number of heads
/is an integer division
modis the modulo operation
Hard disk can be divided in several partitions. Each partition is treated as
an individual FAT volume. This introduces a minor change to the assignment of
the logical sector numbers. The logical sector number 0 is not assigned to the
first physical sector of the disk but to the first sector of the partition. The
rules for assigning the next serial number remains unchanged.
The boot sector is the name for the first sector of a floppy disk (head 0,
track 0, sector 1) or for the first sector of a partition in the case of a hard
disk. This location is accessible without knowing the exact type of the disk.
This makes it appropriate for storing the disk parameters, which will then give
enough information to access the other parts of the disk.
The following table shows the structure of the boot sector :
|0h||Jump instruction to the boot routine||3 bytes|
|3h||OEM name and number||8 bytes|
|0Bh||Bytes per sector||1 WORD|
|0Dh||Sectors per cluster||1 BYTE|
|0Eh||Reserved sectors||1 WORD|
|10h||Number of FATs||1 BYTE|
|11h||Number of root directory entries||1 WORD|
|13h||Number of logical sectors in the volume||1 WORD|
|15h||Medium descriptor byte||1 BYTE|
|16h||Sectors per FAT||1 WORD|
|18h||Sectors per track||1 WORD|
|1Ah||Number of heads||1 WORD|
|1Ch||Number of hidden sectors||1 WORD|
Jump instruction to the boot routine :
The first three bytes of the boot sector are either a near jump instruction (E9xxxxh) or a short jump followed by a NOP instruction EBxx90h. This instruction makes a jump to the boot code located somewhere in the boot sector. This instruction is necessary because the execution of a PC starts with the first bytes of the boot sector (see Boot sequence of a PC).
OEM name and number :
This field contain an identity that caracterizes the manufacturer and operating system.
Bytes per sector :
This word gives the number of bytes per sector. In the PC world, this seems to be always 512.
Sectors per cluster :
This byte gives the number of sectors per cluster. You'll learn what is a cluster later.
Reserved sectors :
This word gives the number of reserved sectors. The boot sector is included in this count. This value is usually 1. DOS disks always use 1 reserved sector : the boot sector. However, there doesn't seem to be any problem to handle other values.
Number of FATs :
This bytes gives the number of FATs (File Allocation Table). Only one FAT is needed but, as the data in it is very sensitive, one or more copies are written on the disk. The number of FATs is usually two.
Number of root directory entries :
This word gives the number of root directory entries available. The number of root directory entries is fixed. This explains why you can't have more than a certain amount of files and/or subdirectories in the root directory.
Number of logical sectors in the volume :
This word gives the number of logical sectors on the disk or in the partition in the case of a hard disk. The maximum number of sectors in the volume is therefore 65535*512 for a disk with 512 bytes per sector. This gives a maximum of about 33 Mb. This is not enough for the currently available hard disks. This is the reason why the new field Big number of logical sectors in the volume has been added. If the word at offset 13h is 0, this means that Big number of logical sectors in the volume gives the number of sectors of the volume.
Medium descriptor byte :
The BIOS and DOS use this entry to determine the disk type. See Appendix A for a table with the valid values for this byte. As some values are used for several disk geometries, it is better to use the detailed information of the boot sector than the medium descriptor byte.
Sectors per FAT :
This word gives the number of sectors per FAT.
Sectors per track :
This word gives the number of sectors per track.
Number of heads :
This word gives the number of read/write heads.
Number of hidden sectors :
This word gives the number of hidden sectors.
The File Allocation Table or FAT is the structure used by the filesystem to
know where the files have been saved on the disk. The FAT links a file to the
sectors of the disk where its content has been stored.
There are two versions of FAT, one with entries of 12 bits and another with entries of 16 bits. If the entries where used to store a logical sector number, the maximum number would be 65535 and if the sectors have 512 bytes, this leads to a maximum disk capacity of 33Mb. To overcome this limitation, sectors have been grouped into clusters.
A cluster is a set of 1 or more sectors and it is the smallest storage unit.
A cluster is either free or used, it can't be shared by several files.
Clustering allows the increase of storage space because the FAT refers to
cluster numbers instead of logical sector numbers. For instance, if you put 4
sectors into each cluster, each cluster will hold 2048 bytes, the maximum
cluster number is 65535 for FAT16 and this gives a capacity of about 120
The drawback to this method is waste of storage space. If a cluster is only partially used by a file, the remaining part of the cluster contains no useful data but is unusable for other files. If you use clusters of 1 sector and the sector size is 512 bytes, this leads to a waste of maximum 511 bytes (when the file uses 1 byte of the cluster). But when the cluster size is 4 sectors with the same sector size, this leads to a waste of maximum 2047 bytes. The more sectors you group into one cluster, the more space you waste. This is especially annoying when you have a lot of small files.
The FAT is a large array of cluster numbers. Each entry of this array is
assigned a cluster : cluster number 2 is assigned to FAT entry number 2, cluster
number 3 is assigned to FAT entry number 3 and so on. The enumeration starts
with 2 because the first two entries are reserved. They are occupied by a copy
of the Medium Descriptor Byte followed by 2 bytes (12-bit FAT) or 3 bytes
(16-bit FAT) with the value FFh. As a consequence, the number of the first
cluster is 2 and not 0.
The value stored in an entry of the table indicates the current use of the related cluster. The following table shows the possible values of an entry and their meanings.
|FF0h to FF6h||FFF0h to FFF6||reserved|
|FF7h||FFF7h||bad sector, unusable|
|FF8h to FFFh||FFF8h to FFFFh||last cluster of a file/directory|
|Any other value||Any other value||next cluster of a file/directory|
|F0 FF FF||The medium descriptor byte followed by two bytes with value FFh.|
|003||Entry relative to second cluster : the cluster following cluster 2 is cluster 3.|
|004||Entry relative to third cluster : the cluster following cluster 3 is cluster 4.|
|FFF||Entry relative to fourth cluster : the cluster 4 is the last of the chain.|
To access a file, you still need to learn where to find the FAT and a given
The first FAT is right after the last reserved sector. The following formula gives the logical sector number where the first FAT starts.
lsnFAT = hs + rs
the number of the logical sector where the FAT starts,
hs is the
number of hidden sectors and
rs is the number of reserved
These two values can be found in the boot sector.
There are N copies of the FAT on the disk. N is given by the boot sector. The following formula gives the number of the logical sector where the ith copy starts.
lsnFAT[i] = hs + rs +
lsnFAT[i] is the number of the logical
sector where the ith FAT starts (0 =< i <
hs is the number of hidden sectors
rs is the
number of reserved sectors
spf is the number of sectors per
Each copy occupies the number of sectors given by the boot sector.
To obtain the logical sector number of the first sector of a cluster, the following formula can be used :
lsn = hs + rs + N*spf
+ nsird + (cln - 2)*spc
lsn is the number of the
logical sector where the cluster starts
hs is the number of
rs is the number of reserved
N is the number of FATs
spf is the
number of sectors per FAT
nsird is the number of sectors
occupied by the root directory
cln is the cluster
spc is the number of sectors per cluster
The formula is obvious when you know that the first cluster has number 2 and that it comes right after the Root Directory. The clusters follow eachother on the disk.
Only the term
nsird in the above formula is not
straightforward to compute. The following formula gives an easy way to do
nsird = (nerd*32 + bps - 1) /
nsird is the number of sectors occupied by
the Root Directory
nerd is the number of entries in the Root
bps is the number of bytes per sector
Once you've got the number of the logical sector of the first sector of a cluster, the other sectors of the cluster are obtained by incrementing the logical sector number because the sectors of a cluster follow eachother. As a consequence, the following formula gives the logical sector number of the ith sector of cluster
lsn = hs + rs + N*spf + nsird + (cln -
2)*spc + i
lsn is the number of the logical
sector of the ith sector of the cluster (0 =< i <
hs is the number of hidden sectors
the number of reserved sectors
N is the number of
spf is the number of sectors per FAT
is the number of sectors occupied by the root directory
the cluster number
spc is the number of sectors per
|16||Time of Creation/Last Change||2|
|18||Date of Creation/Last Change||2|
|1A||First Cluster of the File||2|
|Offset||Hexadecimal code||Instruction or data|
|00||EB 3E 90|
|03||29 3E 54 29 7D 49 48 43||OEM name and number|
|0B||00 02||Bytes per
The number of bytes per sector is 200h (512).
There is 1 sector per cluster
There is 1 reserved sector. This means that there are no other sectors reserved beside the boot sector.
There are 2 FATs. This means 1 original and 1 copy.
|11||E0 00||Number of root
There are 00E0h (224) entries available in the root directory.
|13||40 0B||Number of logical
sectors in the volume|
There are 0B40h (2880) logical sectors on the disk. The capacity of the disk is thus 2880*512 = 1474560 bytes.
The code F0 stands for a double sided 3"1/2 disk with 80 tracks and 18 sectors per track. This corresponds to a 1.44 Mb floppy. This gives 2*80*18 = 2880 sectors, which is consistent with the number written at offset 13h
|16||09 00||Sectors per
Each FAT occupies 9 sectors. As there are 2 FATs, 18 sectors are used to store them.
|18||12 00||Sectors per
There are 0012h (18) sectors per track. This is consistent with the Medium Descriptor Byte
|1A||02 00||Number of
There are 2 heads. This is consistent with the Medium Descriptor Byte.
|1C||00 00 00 00||Number of hidden
There are no hidden sectors. The length of this field is 4 bytes because the byte at offset 26h is equal to 29h. If it was not the case, this field would be only 2 bytes long.
|20||00 00 00 00||This field is only valid if the byte at offset 26h is 29h and if the number of sectors (word at offset 13h) is 0. In this case, it gives the number of sectors in the volume. It is used when the number of sectors is too big to be stored in a word.|
|24||00||This is the drive number. The DOS boot code uses the value stored here to know if the boot code is located on a floppy disk or on a hard disk. It needs to know this in order to know where to load the IO.SYS file from. The value of 0 here indicates the A: drive.|
|26||29||Extended Boot Record Signature|
If the value stored here is 29h, it indicates that the fields at offset 1Eh and above are valid.
|27||4D 24 F3 17||This a serial number. It has nothing to do with the serial number of the floppy given by the manufacturer. I don't know what Windows 95 writes here but it changes each time the disk is formatted.|
|2B||4E 4F 20 4E 41 4D 45 20 20 20 20||This is the volume label. In this case, the string is "NO NAME".|
|36||46 41 54 31 32 20 20 20||This is a string which identifies the filesystem. In this case, the string is "FAT12".|
|3E||F1 7D||This word is a pointer to the name of the file which will be loaded by the boot code. As the boot code is loaded at 0000:7C00h, the value 7DF1h points to offset 7DF1h - 7C00h = 1F1h of the boot sector. This is the string : "WINBOOT.SYS".|
|This is the start of the boot code. The short jump at offset 0 points to offset 40h.|
|41||33 C9||xor cx,cx|
|43||8E D1||mov ss,cx|
|45||BC FC 7B||mov sp,7BFC|
|4A||BD 78 00||mov bp,0078|
|4D||C5 76 00||lds si,[bp]|
|54||BF 22 05||mov di,0522|
|57||89 7E 00||mov [bp],di|
|5A||89 4E 02||mov [bp+02],cx|
|5D||B1 0B||mov cl,0B|
|60||F3 A4||rep movsb|
|64||BD 00 7C||mov bp,7C00|
|67||C6 45 FE 0F||mov [byte ptr di-02],0F|
|6B||8B 46 18||mov ax,[bp+18]|
|6E||88 45 F9||mov [di-07],al|
|72||38 66 24||cmp [bp+24],ah|
|75||7C 04||jl 7B|
|77||CD 13||int 13|
|79||72 3C||jc B7|
|7B||8A 46 10||mov al,[bp+10]|
|7F||F7 66 16||mul [word ptr bp+16]|
|82||03 46 1C||add ax,[bp+1C]|
|85||13 56 1E||adc dx,[bp+1E]|
|88||03 46 0E||add ax,[bp+0E]|
|8B||13 D1||adc dx,cx|
|8F||89 46 FC||mov [bp-04],ax|
|92||89 56 FE||mov [bp-02],dx|
|95||B8 20 00||mov ax,0020|
|98||8B 76 11||mov si,[bp+11]|
|9B||F7 E6||mul si|
|9D||8B 5E 0B||mov bx,[bp+0B]|
|A0||03 C3||add ax,bx|
|A3||F7 F3||div bx|
|A5||01 46 FC||add [bp-04],ax|
|A8||11 4E FE||adc [bp-02],cx|
|AD||BB 00 07||mov bx,0700|
|B0||8B FB||mov di,bx|
|B2||B1 01||mov cl,01|
|B4||E8 94 00||call 14B|
|B7||72 47||jc 100|
|B9||38 2D||cmp [di],ch|
|BB||74 19||je D6|
|BD||B1 0B||mov cl,0B|
|C0||8B 76 3E||mov si,[bp+3E]|
|C3||F3 A6||repe cmpsb|
|C6||74 4A||je 112|
|C9||74 0B||je D6|
|CB||03 F9||add di,cx|
|CD||83 C7 15||add di,0015|
|D0||3B FB||cmp di,bx|
|D2||72 E5||jl B9|
|D4||EB D7||jmp AD|
|D6||2B C9||sub cx,cx|
|D8||B8 D8 7D||mov ax,7DD8|
|DB||87 46 3E||xchg [bp+3E],ax|
|DE||3C D8||cmp al,D8|
|E0||75 99||jne 7B|
|E2||BE 80 7D||mov si,7D80|
|E7||03 F0||add si,ax|
|EA||84 C0||test al,al|
|EC||74 17||je 105|
|EE||3C FF||cmp al,FF|
|F0||74 09||je FB|
|F2||B4 0E||mov ah,0E|
|F4||BB 07 00||mov bx,0007|
|F7||CD 10||int 10|
|F9||EB EE||jmp E9|
|FB||BE 83 7D||mov si,7D83|
|FE||EB E5||jmp E5|
|100||BE 81 7D||mov si,7D81|
|103||EB E0||jmp E5|
|105||33 C0||xor ax,ax|
|107||CD 16||int 16|
|10B||8F 04||pop [word ptr si]|
|10D||8F 44 02||pop [word ptr si+02]|
|110||CD 19||int 19|
|112||BE 82 7D||mov si,7D82|
|115||8B 7D 0F||mov di,[di+0F]|
|118||83 FF 02||cmp di,0002|
|11B||72 C8||jl E5|
|11D||8B C7||mov ax,di|
|121||8A 4E 0D||mov cl,[bp+0D]|
|124||F7 E1||mul cx|
|126||03 46 FC||add ax,[bp-04]|
|129||13 56 FE||adc dx,[bp-02]|
|12C||BB 00 07||mov bx,0700|
|130||B1 04||mov cl,04|
|132||E8 16 00||call 14B|
|136||72 C8||jc 100|
|138||81 3F 4D 5A||cmp [word ptr bx],5A4D|
|13C||75 A7||jne E5|
|13E||81 BF 00 02 42 4A||cmp [word ptr bx+0200],4A42|
|144||75 9F||jne E5|
|146||EA 00 02 70 00||jmp 0070:0200|
|150||33 D2||xor dx,dx|
|152||F7 76 18||div [word ptr bp+18]|
|156||F7 76 18||div [word ptr bp+18]|
|15A||87 CA||xchg dx,cx|
|15C||F7 76 1A||div [word ptr bp+1A]|
|15F||8A F2||mov dh,dl|
|161||8A 56 24||mov dl,[bp+24]|
|164||8A E8||mov ch,al|
|166||D0 CC||ror ah,1|
|168||D0 CC||ror ah,1|
|16A||0A CC||or cl,ah|
|16C||B8 01 02||mov ax,0201|
|16F||CD 13||int 13|
|174||72 09||jc 17F|
|177||75 01||jne 17A|
|17A||03 5E 0B||add bx,[bp+0B]|
|17D||E2 CC||loop 14B|
|184||0D 0A 44 69 73 71 75 65 20 6E 6F 6E 20 73 79 73 74 65 6D 65 20 FF||The string : "Disque non systeme" preceeded by a carriage return and followed by FFh|
|19A||0D 0A 45 72 72 65 75 72 20 64 27 45 2F 53 20 20 FF||The string : "Erreur d'E/S" preceeded by a carriage return and followed by FFh.|
|1AB||0D 0A 52 65 6D 70 6C 61 63 65 7A 2D 6C 65 20 65 74 20 61 70 70 75 79 65 7A 20 73 75 72 20 75 6E 65 20 74 6F 75 63 68 65 20 20 0D 0A 00||The string : "Remplacez-le et appuyez sur une touche", preceded by a carriage return and followed by a carriage return and 0.|
|1D8||49 4F 20 20 20 20 20 20 53 59 53||The filename : "IO.SYS"|
|1E3||4D 53 44 4F 53 20 20 20 53 59 53||The filename : "MSDOS.SYS"|
|1EE||80 01 00|
|1F1||57 49 4E 42 4F 4F 54 20 53 59 53||The filename : "WINBOOT.SYS"|
|1FC||00 00 55 AA|
The code disables the interrupts while it initializes the segment registers. ss = es = 0 and sp = 7BFCh. The boot code is loaded by the bootstrap at 0000:7C00, the stack begins 4 bytes before this position. These 4 bytes, at 0000:7BFC will be used later.
The pointer at 0000:0078 is loaded into ds:si. This is the pointer to the drive parameter table.
ds, si, ss and bp are pushed onto the stack. They don't seem to be popped afterwards so I don't know what this is used for.
The address of the drive parameter table is now 0000:0522.
The drive parameter table, whose length is 12 bytes, is moved from its old location to its new location (0000:0522).
ds = 0 and bp = 7C00h. bp points to the start of the image of the boot sector. The value of bp won't change anymore, so you can keep in mind that bp points to the boot sector.
This portion of the code sets the parameters of the drive parameters table in function of the data of the boot sector of the disk.
Due to the rep movsb instruction, di points to the end of the drive parameters table.
di-02 points to the 11th byte of the table, this is the head settle time. The head settle time is set to 15 milliseconds.
bp+18 points to the number of sectors per track. di-07 points to the 4th byte of the parameter table, this is the number of sectors per track. This number is set to the number given by the boot sector.
This reenables the interrupts.
This code is a mystery for me. Anyway, for a floppy, [bp+24h] should be 0 and ah too, and the jump shouldn't be made.
As ah and dl are equal to 0, the call to interrupt 13h recalibrates the floppy drive. If the recalibration fails, a jump is made to the code at B7.
Note : the code that follows is particularly
interesting as it shows how to find the start of the Root Directory and the
start of the space where the files are stored.
The number of FATs is transferred into al. al is then sign-extended and ax is multiplied by the number of sectors per FAT. dx:ax is now the number of sectors used to store all the FATs.
The number of hidden sectors is added to dx:ax. The number of hidden sectors occupies 4 bytes because the byte at offset 26h of the boot sector is 29h. Otherwise, it would be only 2 bytes long.
The number of reserved sectors is added to dx:ax. At this stage, dx:ax is the number of the first logical sector of the Root Directory.
ax and dx are pushed onto the stack. They are also stored at 0000:7BFC and 0000:7BFE, the 4 bytes between the bottom of the stack and the boot code.
ax is loaded with the value 20h (32) because an entry of the Root Directory is 32 bytes long. si is loaded with the number of entries of the Root Directory. After ax has been multiplied by si, dx:ax is the length of the Root Directory measured in bytes.
bx is loaded with the number of bytes per sector.
bx is then added to ax and then ax is decremented by one. This is a little trick. The number of bytes used for the Root Directory is not required to be a multiple of the number of bytes per sector. If it's not a multiple, the last sector is not completely used. But even if the Root Directory only uses one byte of the last sector, this sector must be reserved. By adding the number of bytes per sector - 1 to the number of bytes of the Root Directory, you are sure to get the correct number of sectors after a division by the number of sectors per byte. In our case, the number of entries in the Root Directory is 224 and the number of bytes per sector 512. 7168 bytes are used to store the Root Directory. 7168 is exactly 14*512. 14 sectors are thus needed. If we add 511 (number of bytes per sectors - 1) to 7168, we get 7679. A division by 512 gives 14, which is the result expected. Now imagine we have 225 entries instead of 224. 7200 bytes are needed for the Root Directory. 14 full sectors are used and 32 bytes of the last sector, this means 15 sectors. We add 511 to 7200, this gives 7711. We divide this result by 512 and we get the correct answer :15.
Now let's get back to our code.
We divide dx:ax by bx. ax is now the number of sectors used by the Root Directory.
We add this value to the value stored at 0000:7BFC. The value stored there is now the number of the first logical sector that can be used to store the content of a file.
The function at 14Bh loads a logical sector of the disk. dx:ax is the number of the sector, bx is the memory location where the sector will be written and cx is the number of sectors to read.
In this case, we pop ax and dx. If you remember, this is the number of the first logical sector of the Root Directory. bx is set to 0700h. di is also set to 0700h but it is not used by the function at 14Bh. It's for a future use. cl is set to 1. One sector will thus be read from the disk.
If the carry is set, it means there was an error. The code at offset 100h handles this situation. This is why we have the instruction jc 100.
We go through the Root Directory entries to find a given file. To do so, we use the register di which points to the current position in the Root Directory. Initially, it is 0700h, the start of the Root Directory in memory.
As the content of register ch is 0, we compare [di] to 0. For the FAT filesystem, an entry starting with 0 means the end of the Root Directory. If we encounter a 0, it means that we have gone through all the directory without finding the file. The code at offset 0D6h handles this situation hence the instruction je D6.
If the entry doesn't start with 0, we compare it with the filename. We compare the 11 first bytes of the entry with the filename because these are the bytes which hold the filename.
The comparison is made by the repe cmpsb instruction. As a consequence, the registers si and di must hold the start addresses of the strings to compare. di is already pointing to the current entry of the Root Directory and si is loaded with the content of [bp+3E]. This is the word at offset 3Eh of the boot sector. si is thus equal to 1DF7h. This value corresponds to the offset 1F1h of the boot sector because 7DF1h - 7C00h = 1F1h. And at offset 1F1h of the boot sector, we find the string "WINBOOT.SYS". The file we are looking for is thus "WINBOOT.SYS". The register cl must hold the length of the strings : 11 bytes in the present case.
If we have found the file, we jump at offset 112h.
The content of tbe register si saved on the stack and then restored.
si is the number of entries in the Root Directory that have not been examined yet. We decrement it by 1 as we have just tested one entry. If si reaches 0, then there are no more entries and the file has not been found. The code at offset D6h handles this situation.
The result of the 2 additions is that di now points to the next entry of the Root Directory. di is then compared to bx. This is to make sure that we have not reached the end of the sector of the Root Directory that was loaded into memory by the call to the function at offset 14Bh. As a result of this call, bx points to the end of the loaded sector. If we are not at the end of the loaded sector, we return to offset BDh, where a new comparison is made between the file name and the entry where the new di points to.
If we are at the end of the loaded sector, we must load the next sector. Therefore we return at offset ADh. The registers dx and ax have not been modified since the last call to the function at 14Bh. As a consequence, they hold the number of the next logical sector to load.
This code is called when we reach the end of the Root Directory. cx is reset to 0. The word at offset 3Eh of the boot sector is set to 7DD8h. Remember that the offset 3Eh holds the pointer to the file name. We are now looking for another filename. This file name is located at offset 7DD8h - 7C00h = 1D8h of the boot sector. This is the string "IO.SYS".
We compare the old value of offset 3Eh with the new one. If they are the same, it means that we have already done the previous procedure before. We have looked for "IO.SYS" but we haven't found it, so we are here for the second time.
If they are not the same, then we must look for "IO.SYS" in the Root Directory. To do so, we return to the code at offset 7Bh. This means that we are almost doing everything again but with another value of the word at offset 3Eh of the boot sector.
We reach this point if the files "WINBOOT.SYS" and "IO.SYS" haven't been found. The register si is loaded with the value 7D80h. This is a pointer to offset 7D80h - 7C00h = 180h of the boot sector. The value stored there is 3.
The register ax is loaded with the content of the memory location indicated by si. ax is then added to si. ax is again loaded with the content of [si].
al is tested. If it is equal 0, the code at offset 105h is executed. If it is equal to FFh, the code at offset FBh is executed. If it is not equal to one of these values the content of al is displayed by a call to interrupt 10. After that, we return to offset E9h. The instruction lodsb loads the next character which will then be displayed. This loop only stops when al is loaded with 0 or FFh.
|F0h||3"1/2, double sided, 80 tracks, 18 sectors per track|
3"1/2, double sided, 80 tracks, 36 sectors per track
|F9h||5"1/4, double sided, 80 track, 15 sectors per track|
3"1/2, double sided, 80 tracks, 9 sectors per track
|FAh||5"1/4, single sided, 80 tracks, 8 sectors per track|
3"1/2, single sided, 80 tracks, 8 sectors per track
|FBh||5"1/4, double sided, 80 tracks, 8 sectors per track|
3"1/2, double sided, 80 tracks, 8 sectors per track
|FCh||5"1/4, single sided, 40 tracks, 9 sectors per track|
|FDh||5"1/4, double sided, 40 tracks, 9 sectors per track|
8", double sided, 77 tracks, 26 sectors per track
|FEh||5"1/4, single sided, 40 tracks, 8 sectors per track|
8", single sided, 77 tracks, 2 sectors per track
8", single sided, 77 tracks, 6 sectors per track
8", single sided, 77 track, 8 sectors per track
|FFh||5"1/4, double sided, 40 tracks, 8 sectors per track|