BENEATH DISK OPERATIONS FOR IBM PCs AND COMPATIBLES (Full Book!)
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ BENEATH DISK OPERATIONS ³
³ ³
³ FOR IBM PCs AND COMPATIBLES ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
Jean J. DRABBE
University of Brussels
Department of Mathematics
Campus Plaine - CP 211
1050 Brussels - BELGIUM
TRADEMARK INFORMATION
Disk Explorer is a registered trademark of Quaid Software Limited
Flu_shot+ is a registered trademark of Software Concepts Design
IBM is a registered trademark of Internation Business Machines Corporation
Intel is a registered trademark of Intel Corporation
Microsoft is a registered trademark of Microsoft Corporation
Turbo Pascal is a registered trademark of of Borland International Inc.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ PREFACE ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
This text is intended to conver technicalities about diskettes;
a diskette contains much more information than just data!
Understanding the extra information is required e.g.
. to examine non standard diskettes
. to format (and write to) non standard diskettes
. to repair damaged diskettes
The disk controller being ultimately in charge of all read/write
operations, its capabilities will be discussed in-depth. It can
perform much more operations than generally thought.
Most of the diskette operations make use of the Direct Memory
Access (DMA) capability of the system. The processor only has to
initialize the operation; the DMA controller handles the rest.
Details about the DMA set-up will be described in due course.
I assume that readers have some familiarity with the MS-DOS
operating system, with 8086/8088 assembly language programming
and with Turbo Pascal (preferably version 4.0 or later).
I shall often refer the reader to Thom Hogan's book :
The Programmer's PC Sourcebook
(Reference Tables for IBM PCs and Compatibles,
PS/2 Machines and DOS)
Microsoft Press - 1988
Hogan's book is, in my opinion, the best primary source of basic
hardware and software information that is currently available.
And last, but not least :
ÚÄÄÄÄ Warning ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ ONLY write-protected or scratch diskettes ³
³ should be used when testing programs that ³
³ involve disk operations ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ CONTENTS ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
I. STANDARD DISKETTES PHYSICAL STRUCTURE
1. Generalities
2. Logical sector numbers
3. Sectors reserved for the operating system
4. The boot sector
5. The root directory
6. The file allocation tables
7. The fine structure of tracks
8. Angular positions
9. Clock bits
II. THE STANDARD INTERRUPT INT 13h
1. Generalities
2. INT 13h functions
3. Calling INT 13h functions from Turbo Pascal
4. Functions 0 and 1
5. Functions 2..4
6. Function 5
7. The disk base table
8. Changing entries in the disk base table
9. Playing tricks with INT 13h
III. INSTALLING NEW INT 13h FUNCTIONS, A FIRST STEP
1. Generalities
2. Planning our work
3. Turning the disk drive motor on
4. Recalibrating the read/write head
5. Moving the read/write head
6. Reading CHRN fields
IV. THE LDC READ TRACK OPERATION
1. Generalities
2. Direct access memory (DMA)
3. The read track phases
4. Experimenting with the read track operation
5. Positioning the read/write head on the beginning of a track
V. THE LDC FORMAT OPERATION AND OTHER LDC OPERATIONS
1. The complete LDC format operation
2. Aborted format operations
3. Other LDC operations
4. Hidden sectors
APPENDIX A CYCLIC REDUNDANCY CODES
APPENDIX B DISK SPACE USED BY SECTORS
APPENDIX C THE STRANGE CASE OF N = 0
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ CHAPTER I ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ STANDARD DISKETTES PHYSICAL STRUCTURE ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
1. GENERALITIES
Before a new diskette can be used with the computer, it must be
formatted (MS-DOS has an external command FORMAT which will format
diskettes). Formatting is a process that writes organizational infor-
mation on the diskette so that the operating system can read and
write files on it. Details about the "organizational" information
will be given in section 7 of this chapter.
For the time being, let us describe how a standard 5.25-inch,
double side, double density (DS/DD) diskette is organized for data
recording.
Both sides are divided into concentric circles called tracks or
cylinders ; there are 40 tracks, numbered from 0 to 39 on each
side.
Each track is further divided into segments, called sectors ; there
are 9 sectors numbered from 1 to 9 for each track.
So, the total number of sectors on a DS/DD 5.25-inch diskette is
2 * 40 * 9 = 720 .
The standard storage capacity of a sector is 512 bytes ( = 0.5 Kbytes)
and, therefore the storage capacity for a standard DS/DD 5.25-inch
diskette is 720 * 512 bytes = 360K bytes.
The disk drive uses two read/write heads (one for each side) to access
data on a diskette. One is called head 0 and the other one is called
head 1.
To specify a sector one has to give three parameters :
C : the cylinder or track of the sector (0 <= C <= 39) ;
H : the side of the disk, or equivalently the disk drive head
to be used to access the sector (0 or 1) ;
R : the sector number within the track it belongs to
(1 <= R <= 9).
Now, what about other disk types ?
The following table describes their organization.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ size (inches) ³ 5.25 ³ 5.25 ³ 3.5 ³ 3.5 ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´
³ density ³ double ³ high ³ double ³ high ³
³ ³ 48 TPI ³ 96 TPI ³ 135 TPI ³ ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´
³ sides ³ 2 ³ 2 ³ 2 ³ 2 ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´
³ tracks ³ ³ ³ ³ ³
³ per side ³ 40 ³ 80 ³ 80 ³ 80 ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´
³ sectors ³ ³ ³ ³ ³
³ per track ³ 9 ³ 15 ³ 9 ³ 18 ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´
³ sectors ³ ³ ³ ³ ³
³ per disk ³ 720 ³ 2400 ³ 1440 ³ 2880 ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´
³ bytes ³ ³ ³ ³ ³
³ per sector ³ 512 ³ 512 ³ 512 ³ 512 ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´
³ bytes ³ ³ ³ ³ ³
³ per disk ³ 360K ³ 1.2M ³ 720K ³ 1.44M ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÙ
From now on, our discussion will be restricted to 360K (5.25-inch /
DS/DD) disks. This is not a real loss of generality because the
adaptation to other disk types is straightforward.
2. LOGICAL SECTOR NUMBERS
Remember, so far we need three parameters C H R to specify a
sector. There is another way of doing it : using logical sector
numbers (lsn) in the range 0..719.
lsn 0 is assigned to sector C = 0 H = 0 R = 1
lsn 1 is assigned to sector C = 0 H = 0 R = 2
... . .. ........ .. ...... ..... ..... .....
lsn 8 is assigned to sector C = 0 H = 0 R = 9
lsn 9 is assigned to sector C = 0 H = 1 R = 1
lsn 10 is assigned to sector C = 0 H = 1 R = 2
... .. .. ........ .. ...... ..... ..... .....
lsn 17 is assigned to sector C = 0 H = 1 R = 9
lsn 18 is assigned to sector C = 1 H = 0 R = 1
... .. .. ........ .. ...... ..... ..... .....
More generally :
lsn = (C * 18) + (H * 9) + R - 1
and conversely :
C = lsn div 18
H = (lsn div 9) mod 2
R = (lsn mod 9) + 1
For readers who are not afraid of elementary mathematics :
lsns correpond to a lexicographic ordering of sectors according to
(C,H,R).
3. SECTORS "RESERVED" FOR THE OPERATING SYSTEM
Even when a diskette is formatted without the /S option, not all
of the 720 sectors are available to the user for file storage.
The operating system wants its share :
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ sector lsn 0 (C = 0 H = 0 R = 1) is the boot sector ³
³--------------------------------------------------------------------³
³ sector lsn 1 and lsn 2 (C = 0 H = 0 R = 2,3) are for ³
³ the first File Allocation Table (FAT1) ³
³--------------------------------------------------------------------³
³ sector lsn 3 and lsn 4 (C = 0 H = 0 R = 4,5) are for ³
³ the second File Allocation Table (FAT2) ³
³--------------------------------------------------------------------³
³ sector lsn 5 to lsn 11 (C = 0 H = 0 R = 6) to ³
³ (C = 0 H = 1 R = 3) are ³
³ for the root directory ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ see sections 4 - 6 for information about these sectors ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The operating system is not too greedy ; it wants a share consisting
of 12 sectors (6 Kbytes) and therefore 360Kbytes - 6 Kbytes =
354 Kbytes are available to the user (starting from lsn 12).
A cluster is a group of two consecutive sectors ("consecutive sectors"
means "sectors whose lsns are consecutive numbers"). They are numbered
from 2 to 355.
cluster 2 consists of sectors lsn 12 and lsn 13
cluster 3 consists of sectors lsn 14 and lsn 15
....................................................
More generally :
cluster k consists of sectors lsn (k - 2) * 2 + 12
and lsn (k - 2) * 2 + 13 .
Clusters are allocation units used to assign disk space to files.
The number of clusters needed to write a file of size s (bytes)
is (s + 1023) div 1024 .
4. THE BOOT SECTOR
Sector lsn 0 (C = 0 H = 0 R = 1) is the boot sector.
It contains :
(a) a bootstrap program which reads the first root directory sector
to see if the (hidden files) IO.SYS and MSDOS.SYS are present
(if the system uses PC-DOS these files are named IBMBIO.COM
and IBMDOS.COM). If they are present IO.SYS is loaded into memory
and executed. Otherwise the bootstrap displays the (well known)
message :
Non-System disk or disk error
Replace and strike any key when ready .
(b) a parameter table starting at the offset 0Bh :
ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄ¿
³ offset ³ length ³ description ³ standard ³
³ (hex) ³ ³ ³ value ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 0Bh ³ word ³ number of bytes per sector ³ 200h=512 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 0Dh ³ byte ³ number of sectors per cluster ³ 2 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 0Eh ³ word ³ number of reserved (boot) sectors ³ 1 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 10h ³ byte ³ number of FATs ³ 2 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 11h ³ word ³ number of root directory entries ³ 70h=112 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 13h ³ word ³ total number of sectors on disk ³ 2D0h=720 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 15h ³ byte ³ media descriptor or disk ID byte (*) ³ FDh ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 16h ³ word ³ number of sectors per FAT ³ 2 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 18h ³ word ³ number of sectors per track ³ 9 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 1Ah ³ word ³ number of heads ³ 1 ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´
³ 1Ch ³ word ³ number of hidden sectors ³ 0 ³
ÀÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÙ
(*) see Hogan's Sourcebook (2.37) for non 360K disks ID byte
Remark : I think that it is instructive to spend a couple of hours to
disassemble the contents of the boot sector and I advice the
reader to do it.
5. THE ROOT DIRECTORY
The root directory occupies 7 sectors. It contains 112 entries ;
each of them is composed of 32 bytes (see Hogan's Sourcebook (2.33)
for information about directory entries layout).
If the disk is bootable, the first directory entry describes the file
IO.SYS and the second directory entry describes the file MSDOS.SYS.
Bytes 1Ah and 1Bh of a directory entry indicate the first cluster
assigned to the file.
What about the other clusters (if any) ?
The File Allocation Table (to be discussed in the next section) is to
be used to locate them.
When a file is erased its directory entry is left intact except for
the first byte (the first character of the file name) which is
changed into E5h . Of course, such a directory entry can be
overwritten if additional files are stored to the diskette.
Note that there are no sectors reserved for subdirectories and that
subdirectoy entries have the same format as root directory entries.
6. THE FILE ALLOCATION TABLES (FATs)
There are two File Allocation Tables occupying two sectors each.
Under normal circumstances, both are identical.
If they are not, the situation is quite often a nightmare (except if
it is known for sure that only one is corrupted) because the FATs
contain vital information about cluster allocation to files.
For the sake of keeping explanations as simple as possible (I hope!)
we need an example. Here is a hexadecimal dump of the (first) FAT of
a disk (1024 = 400h bytes) :
0 1 2 3 4 5 6 7 8 9 A B C D E F
0000 FD FF FF 03 40 00 05 60 00 07 80 00 09 A0 00 0B
0010 C0 00 0D E0 00 0F 00 01 11 F0 FF 13 40 01 15 60
0020 01 17 80 01 19 A0 01 1B C0 01 1D E0 01 1F 00 02
0030 21 20 02 23 40 02 25 60 02 27 80 02 29 A0 02 2B
0040 C0 02 2D F0 FF 2F 00 03 31 20 03 33 40 03 35 60
0050 03 37 80 03 39 A0 03 3B C0 03 3D E0 03 3F 00 04
0060 41 20 04 43 40 04 45 F0 FF FF 8F 04 49 F0 FF 4B
0070 C0 04 4D E0 04 4F 00 05 51 20 05 53 F0 FF 55 60
0080 05 57 F0 FF 59 A0 05 5B F0 FF 5D E0 05 5F 00 06
0090 61 20 06 63 F0 FF 65 60 06 67 80 06 69 A0 06 6B
00A0 C0 06 6D E0 06 6F 00 07 71 20 07 FF 4F 07 75 60
00B0 07 77 80 07 79 A0 07 7B C0 07 7D F0 FF 7F 00 08
00C0 FF 2F 08 83 40 08 85 60 08 87 80 08 89 A0 08 8B
00D0 C0 08 8D E0 08 FF 0F 09 91 20 09 93 40 09 95 60
00E0 09 97 F0 FF 99 A0 09 9B C0 09 9D E0 09 9F 00 0A
00F0 FF FF FF A3 40 0A A5 60 0A A7 80 0A FF AF 0A FF
0100 CF 0A AD E0 0A AF 00 0B B1 20 0B B3 40 0B B5 60
0110 0B B7 80 0B B9 A0 0B FF CF 0B BD E0 0B BF 00 0C
0120 C1 20 0C C3 40 0C C5 60 0C C7 80 0C C9 A0 0C CB
0130 C0 0C CD E0 0C CF 00 0D D1 20 0D D3 40 0D D5 60
0140 0D D7 80 0D D9 A0 0D DB C0 0D DD E0 0D DF 00 0E
0150 E1 20 0E E3 40 0E E5 F0 FF E7 80 0E E9 A0 0E EB
0160 C0 0E ED E0 0E FF 0F 0F F1 20 0F F3 40 0F F5 60
0170 0F F7 F0 FF F9 A0 0F FB C0 0F FD F0 FF FF F0 FF
0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
.... .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
03F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
The first three bytes of the FAT do not seem to be of any use.
Remember that there are 354 clusters (numbered from 2 to 163h).
The FAT provides a 12-bit entry for each cluster (12-bit numbers can
be written as 3-digit hexadecimal numbers).
The following algorithm may be used to get the entry for cluster k :
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ (i) get the word w at the offset (k * 3) div 2 ³
³ (keeping in mind that words are stored byte swapped, ³
³ i.e. least significant byte first) ³
³ ³
³ (ii) if k is even then get rid of the first hex digit of w ³
³ if k is odd then get rid of the last hex digit of w ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
Using the algorithm and the sample FAT above, one get the results :
cluster no ³ 12-bit entry
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
002h ³ 003h
003h ³ 004h
004h ³ 005h
005h ³ 006h
006h ³ 007h
007h ³ 008h
008h ³ 009h
009h ³ 00Ah
00Ah ³ 00Bh
00Bh ³ 00Ch
00Ch ³ 00Dh
00Dh ³ 00Eh
00Eh ³ 00Fh
00Fh ³ 010h
010h ³ 011h
011h ³ FFFh
.... . ....
100h ³ 000h
.... . ....
The values of the FAT 12-bit entries are interpreted as follows :
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ value ³ meaning ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 000h ³ cluster available (i.e. unused cluster) ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ FF0h..FF6h ³ reserved cluster ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ FF7h ³ cluster marked bad ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ FF8h..FFFh ³ last cluster of file ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 002h..163h ³ next cluster in file ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
Now, using the directory (or subdirectory) entry for a file and the
FAT, it is quite easy to trace the chain of cluster used by that file.
For example, the first root directory entry of the disk from which the
sample FAT above comes from is for the (standard system) file IO.SYS.
The first directory entry shows that the starting cluster for IO.SYS
is cluster 2. Tracing through the FAT, one realizes that
the 2nd cluster for IO.SYS is cluster 3 (because the 12-bit entry
for cluster 2 is 3)
the 3rd cluster for IO.SYS is cluster 4 (because the 12-bit entry
for cluster 3 is 4)
...................................................................
the last cluster for IO.SYS is cluster 11h
(because the 12-bit entry
for cluster 11h is 0) .
So, IO.SYS occupies contiguous clusters (as required by the bootstrap
program). For other files there is no contiguity requirement.
When a file is erased, all its clusters are freed (i.e. the correspon-
ding FAT 12-bit entries are changed into 000).
7. THE FINE STRUCTURE OF TRACKS
When access is given to a disk, it rotates quite fast ; its speed
is 300 rpm (in other words, only 60/300 = 0.2 second is required to
perform a complete revolution).
The data transfer rate is 250Kbits/second (therefore 8/250000 =
32 microseconds are required to read/write a byte).
The sector (512 data bytes) is the fundamental unit of disk informa-
tion.
When a sector read/write operation is performed, the read/write head
is mechanically positioned to the proper track. Now, the disk
controller has to find the location of the sector to be used.
This can be done because, in addition to its 512 data bytes, each
sector includes a certain amount of overhead information which
provides sector identification bytes.
The analysis of the fine structure of sectors (to be described below)
also reveals the presence of a gap. This gap provides both an interval
for switching the drive electronics from reading or writing and
compensation for rotational speed.
It turns out that each sector actually uses 574 bytes!
The fine structure of a sector
ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ 00 ³ ³
³ .. ³ 12 bytes of 00 ³
³ 00 ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ A1h ³ ³
³ A1h ³ 3 bytes of A1h ³
³ A1h ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ FEh ³ 1 byte of FEh ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ C ³ Cylinder No (1 byte) ³
³ H ³ Head No (1 byte) ³
³ R ³ Sector No (1 byte) ³
³ N ³ data size byte (1 byte) (*) ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ CRC1 ³ 2 Cyclic Redundancy Check bytes ³
³ CRC2 ³ (**) ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 4Eh ³ G G ³
³ .. ³ A 22 bytes of 4Eh A ³
³ 4Eh ³ P P ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 00 ³ ³
³ .. ³ 12 bytes of 00 ³
³ 00 ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ A1h ³ ³
³ A1h ³ 3 bytes of A1h ³
³ A1h ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ FBh ³ 1 byte of FBh ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ data ³ 512 bytes ³
³ bytes ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ CRC3 ³ 2 Cyclic Redundancy Check bytes ³
³ CRC4 ³ (**) ³
ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
(*) the standard value of N is 2, meaning that there are
128*2^N = 512 data bytes ;
(**) CRCs are used to detect errors ; as some mathematics is involved,
they will be discussed in Appendix A.
Although tracks are circles they all have a starting point. This fact
needs some explanation :
There is a hole in a diskette near the central hub (index hole). While
the diskette rotates a photo-sensor detects its passage and sends a
signal to the controller defining the start of track information.
Whe are now ready to describe the fine structure of a track.
The fine structure of a track
ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ 4Eh ³ ³
³ .. ³ 80 bytes of 4Eh ³
³ 4Eh ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 00 ³ ³
³ .. ³ 12 bytes of 00 ³
³ 00 ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ C2h ³ ³
³ C2h ³ 3 bytes of C2h ³
³ C2h ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ FCh ³ 1 byte of FCh ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 4Eh ³ ³
³ .. ³ 50 bytes of 4Eh ³
³ 4Eh ³ ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ sector ³ ³
³ 1 ³ 574 bytes ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 4Eh ³ G 80 bytes of 4Eh G ³
³ .. ³ A A ³
³ 4Eh ³ P gap between sectors 1 and 2 P ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ sector ³ ³
³ 2 ³ 574 bytes ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 4Eh ³ G 80 bytes of 4Eh G ³
³ .. ³ A A ³
³ 4Eh ³ P gap between sectors 2 and 3 P ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
/ / /
/ / /
/ / /
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ sector ³ ³
³ 9 ³ 574 bytes ³
ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 4eh ³ bytes of 4Eh ³
³ .. ³ ³
³ 4Eh ³ to end of track ³
ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
8. ANGULAR POSITIONS
We already know that it takes 0.2 second for a diskette to perform
a complete revolution and that the transfer rate is 250Kbits/second.
Therefore a track holds * about *
250000 * 0.2 / 8 = 6250 bytes
(9 * 512 data bytes and organizational bytes). We said * about *
because the disk speed can vary (the drive electronics can cope with
small variations of the rotational speed).
So, a track can be regarded as an array[0..6249] of byte .
Looking at the above table one realizes that
sector 1 starts at the offset 146
sector 2 starts at the offset 146 + 654
and, more generally :
sector R starts at the offset 146 + (R - 1) * 654 .
Let us define the angular position (expressed in degrees) of the byte
at offset i by the formula :
i * 360 / 6250 .
For programming reasons (to be discussed later on), it is easier (and
more reliable) to locate the CHRN field of a sector (rather than
its starting point).
The CHRN field of sector 1 starts at the offset 162 and, more
generally the CHRN field of sector R starts at the offset :
162 + (R - 1) * 654 .
Thus we have :
sector ³ angular position of CHRN
³ field (degrees)
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
1 ³ about 9
2 ³ about 47
3 ³ about 85
4 ³ about 122
5 ³ about 160
6 ³ about 198
7 ³ about 235
8 ³ about 273
9 ³ about 311
We have devoted a section to angular positions because some disk
utilities (e.g. Disk Explorer - Quaid Software Ltd) provide the user
with such information.
9. CLOCK BITS
Of course, any write operation turns out to write bits to the
diskette. For example, writing two (consecutive) bytes of CBh
amounts to writing the sequence of (standard) bits :
1 1 0 0 1 0 1 1 1 1 0 0 1 0 1 1
For technical reasons (aimed at storage efficiency) the disk drive
technology adds extra bits (clock bits) between each pair of standard
bits.
The clock bit is 1 between two 0 bits and 0 between any other
pair of bits.
So, in the example given above
standard bits 1 1 0 0 1 0 1 1 1 1 0 0 1 0 1 1
clock bits 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
the actual recording is 1 0 1 0 0 1 0 0 1 0 0 0 1 0 1 0 1 0 1 ...
There are exceptions to the rule on clock bits :
the 6 bytes of A1h in the fine structure of a sector
(see section 7)
the 3 bytes of C2h in the fine structure of a track
(see section 7)
contain some "wrong" clock bits (some 1 clock bits are changed to 0).
It is (of course) quite easy to read the (512 * 9) data bytes on a
track.
What about reading * all * the bytes on a track ?
Although the disk controller is able to read organizational bytes, it
does not mean that the programmer can easily have access to non data
bytes. The disk controller acts like a black box within the computer,
executing procedures of its own and revealing (through ports) * only
some * of its results to the computer (just as local variables are
not accessible from the main program in Pascal).
If one turns to non standard (tricky) reading methods, the results are
partially unreliable. This is because shifts can occur and clock bits
rather than normal bits are read.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ CHAPTER II ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ THE STANDARD INTERRUPT 13h ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
1. GENERALITIES
A large variety of disk-access services is available under MS-DOS
(via INT 21h functions) to assembly language programmers.
Roughly speaking, the Turbo Pascal disk related facilities and the
INT 21h disk services are equivalent.
With very few exceptions the INT 21h services (for assembly language
programmers) or the Turbo Pascal build-in disk facilies are best
suited for disk standard operations such as handling files.
When it comes to examine diskettes, to repair them and to spot
abnormalities used for copy protection, lower level techniques are
often required. Interrupt 13h provides useful tools. Its procedures
reside in ROM.
At first glance, its capabilities seem rather poor. Wait and see !
I do not claim that the standard ROM based INT 13h is THE disk
problem solver. In fact, the next chapters will be devoted to show
how to improve its capabilities.
One thing at a time !
Usually, while writing a program, one has not to worry about where the
global variables are located in memory when the program is executed.
Although INT 13h is not too fastidious, it requires some care about
disk data transfer areas (buffers). This is because INT 13h uses a
capability of the system known as Direct Memory Access (DMA) and has
to comply with the DMA requirements.
To explain the restriction imposed by the DMA we need some terminology.
Page 0 of memory is the 64K-segment starting at the (absolute) address
0000h:0000h and ending at the (absolute) address 0000h:FFFFh
----------------------------- boundary -------------------------------
Page 1 of memory is the 64K-segment starting at the (absolute) address
1000h:0000h and ending at the (absolute) address 1000h:FFFFh
----------------------------- boundary -------------------------------
Page 2 of memory is the 64K-segment starting at the (absolute) address
2000h:0000h and ending at the (absolute) address 2000h:FFFFh
----------------------------- boundary -------------------------------
......................................................................
The restriction imposed by the DMA is :
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ The buffer may NOT cross a page boundary ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
For example, a 20-byte buffer starting at the abslute address
0000:FFF0h is not allowed (it would start in page 0 and end in page 1).
2. INT 13h FUNCTIONS
A total of six different functions are available through INT 13h
to access diskettes. They are :
function 0 : reset diskette system
function 1 : get diskette system status
function 2 : read sectors
function 3 : write sectors
function 4 : verify sectors
function 5 : format a track
Various registers are used to call INT 13h (some functions do not use
all the registers shown in the following description) :
Register contents to call INT 13h
ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ Reg ³ contents ³
ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ AH ³ function number (0..5) ³
ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ AL ³ number of sectors to be read/written ³
³ ³ (1..9 for standard diskettes) ³
ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ES ³ segment of buffer ³
ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ BX ³ offset of buffer ³
ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ CH ³ track number (normally 0..39) ³
ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ CL ³ sector number (1..9 for standard diskettes) ³
ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ DH ³ diskette side (0 or 1) ³
ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ DL ³ drive number (0 = drive A: 1 = drive B: ) ³
ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
All INT 13h calls return
CF = 0 AH = 0 if there was no error
CF = 1 AH = error code if there was an error
See Hogan's Sourcebook (4.041) for information about INT 13h error
codes.
The contents of AH returned by INT 13h functions is also stored at the
absolute address 0000:0441h .
3. CALLING INT 13h FROM TURBO PASCAL
In assembly language, it is quite simple to load registers with
values and to call an interrupt. Turbo Pascal provides an easy method
(close to assembly language) to execute an interrupt.
It uses the DOS unit (in TURBO.TPL) and a REGISTERS-type variable
(REGISTERS is defined in the interface section of the DOS unit).
Here is an example:
program example_int13h;
uses dos;
var
regs:registers;
result:byte;
buffer:array[0..buffer_size-1] of byte; (* see remark below *)
.......
.......................................
with regs do
begin
ah:=function_number;
al:=number_sectors;
es:=seg(buffer);
bx:=ofs(buffer);
ch:=track_number;
cl:=sector_number;
dh:=side;
dl:=drive;
end;
intr($13,regs);
(* to move the error code into result : *)
result:=mem[0:$441];
.......................................
.......................................
.......................................
end.
Remark : buffer may not cross a page boundary.
I confess, I often use a quick and dirty trick ; I declare buffer to
reside at a specific address in memory :
buffer:array[0..buffer_size-1] of byte absolute $7000:0000;
(when writing small programs which do not involve pointers).
There are, of course, much better ways :
If buffer_size is nn , one could declare a 'large' buffer :
buffer:array[0..2*nn-1];
and use only a part of it (to be determined by the program at
runtime).
Other methods involving heap management are also available.
4. FUNCTIONS 0 AND 1
We shall never use function 1 (get diskette system status) because
it does not do much more than to move the contents of memory location
0000:0441h into AL.
On the contrary, function 0 (reset diskette system) is very important.
It resets the disk controller and recalibrates the drive's read/write
head.
Function 0 should always be called after any failed read, write,
verify or format request to ensure that the error-causing condition is
cleared in the controller.
Function 0 only uses AH ( = 0 ) and DL.
From now on, we assume that all Turbo Pascal programs calling INT 13h
include a procedure RSET (we may not use RESET because it is a
reserved word) :
procedure rset;
begin
regs.ah:=0; (* just as in the example in section 3, *)
regs.dl:=drive; (* regs is a registers-type variable *)
intr($13,regs);
end;
After any other Int 13h drive operations, something like :
error:=mem[0:$441]; (* save error code *)
if (error <> 0) then rset; (* error=0 means no error *)
should be executed.
5. FUNCTIONS 2..4
From a programming point of view, function 2 (read sectors),
function 3 (write sectors) and function 4 (verify sectors) are all
similar. They use all registers shown in section 2.
The verify operation is identical to the read operation, except that
the data are thrown away rather than stored into memory.
Nevertheless it requires ES:BX to be initiazed properly (no page
boundary crossing). As no buffer is really needed, an absolute
declaration such as
buffer:byte absolute $7000:0000;
will not cause any problem.
The verify operation is often used to try spotting bad areas on the
diskette.
The read operation and the write operation are data transfer
operations performing exactly what one expects.
Read, write and verify operations may involve several sectors.
For example, if the read function is called with AL=3 CL=4
sectors 4 to 6 will be read consecutively. This means that the
buffer should be (at least) of size 512 * 3 = 1536 (for standard
diskettes).
If we want to read, write or verify more than one sector, every sector
should be on the same track and on the same side. In other words, (for
standard diskettes) : 1 <= AL <= 9 - CL + 1 .
As an error may appear because the drive motor has not reached a
working speed at the time of the request, it is recommended to try
read, write and verify operations three times before assuming an error
is real (and, of course, to use the reset operation between tries).
EXERCISE Write a program that verifies all sectors on a diskette.
[Hint : first write a procedure verify(t,h,s,n:byte) that
verifies n sectors starting with sector s on track t / head h ].
Such a program will turn out to be useful to spot bad sectors and non
standard sectors.
6. FUNCTION 5
Function 5 formats * one track * on * one side * of a diskette.
All registers shown in section 2 are used except AL and CL.
The format operation writes organizational bytes (see Chapter I -
section 7) as well as data bytes (all data bytes are identical).
One may wonder why a buffer (pointed to by ES:BX) is required to
perform a format operation. In fact the buffer must hold the CHRN
4-byte fields written on the track.
So, for a standard track, 36 bytes are required and one can use :
for i:=0 to 8 do
begin
buffer[4*i]:=track;
buffer[4*i+1]:=head;
buffer[4*i+2]:=i+1;
buffer[4*i+3]:=2;
end;
In fact the format operation * does not check anything * about the
values held in the buffer.
One can take advantage of this 'weakness' to write anything one likes
in the CHRN fieds. Of course, sophisticated techniques are required
when it comes to read/write sectors with strange CHRN fields.
Some copy protection methods format a track with nine identical CHRN
fields and write nine different data fields. It is obvious that it is
rather difficult to copy such a diskette.
If a track (say track 10 / head 0) is formatted with the following
CHRN fields
10 0 1 2
10 0 2 2
10 0 3 2
10 0 4 2
10 0 5 2
10 0 6 2
10 0 7 2
10 0 9* 2 * non standard
10 0 8* 2 * order
and all other tracks are formatted in the standard way, DISKCOPY will
not realize that the diskette is non standard and will agree to copy
to a standard destination disk. DISKCOMP will display : 'diskettes
compare ok ' .
This is an example of a quite simple (though 'cruel') copy protection
method.
We will learn how to read CHRN fields in Chapter III.
7. THE DISK BASE TABLE
One can raise many questions that are unanswered in the previous
sections. For example, how does the format operation know that nine
CHRN fields are to be written on a track?
The * dword * at memory location 0000:0078h is a pointer to the
11-byte Disk Base Table.
The overall operation of INT 13h is controlled by parameters in this
table.
Disk Base Table
ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ offset ³ descriptions ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 00h ³ first specify byte ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 01h ³ second specify byte ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 02h ³ wait time until motor turned off ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 03h ³ number of bytes per sector code ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 04h ³ number of sectors per track ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 05h ³ read/write gap length ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 06h ³ data length when sector length not specified ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 07h ³ format gap length ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 08h ³ fill byte for formatting ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 09h ³ head-settle time ³
ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ 0Ah ³ motor start-up time ³
ÀÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The first specify byte, the second specify byte, the head-settle time
and the motor start-up time are 'technology' bytes. They should NEVER
be changed.
The wait time until motor turned off parameter specifies how long the
diskette motor is to be left running after each operation (the motor
is left on in case the diskette is needed again). The value is in
units of clock ticks (about 1/18.2 second). We will never need to
change this parameter.
The number of bytes per sector code is used by INT 13h to determine
the actual number of data bytes per sector. If the code is n then
the actual number of data bytes per sector is 128 * 2^n.
The standard code is 2 (i.e. 512 data bytes). This parameter
often needs to be changed for non standard diskettes.
Strange things may happen when the code is 0 (see Appendix C :
'The Strange Case of N = 0').
For non standard diskettes, the number of sectors per track may be
different from the normal value 9.
The format gap length (normal value : 80 = 50h) is the number of bytes
of 4Eh written between sectors when a track is formatted (see the fine
structure of tracks in Chapter I - section 7).
It does not seem safe to use a value smaller than 12.
The read/write gap length is used when reading or writing. It tells
INT 13h how long to wait before looking for the next sector so that it
can avoid reading some of the (nonsense) bytes of 4Eh in the gap
between sectors.
The normal value is 42 = 2Ah.
Changing the read/write gap length to 8 will usually produce good
results even for non standard diskettes.
Obviously, the read/write gap must be smaller than the format gap.
We shall never need to change the value (255 = FFh) of the parameter
'data length when sector length not specified'. See Appendix C :
'The Strange Case of N = 0'.
The fill byte for formatting provides the data value that is stored
in each data byte of the sectors when a track is formatted.
It can be changed to anything.
8. CHANGING ENTRIES IN THE DISK BASE TABLE
It is not difficult to change entries in the Disk Base Table. Good
programming practice requires that all entries are restored to their
original value before a program terminates (even in case of
termination due to a runtime error). This requirement implies that the
original values should be stored somewhere.
The following program demonstrates how to work out things in Pascal
(the reader is referred to TURBO PASCAL OWNER'S HANDBOOK for
information about exit procedures).
program ........;
................
var
table_seg,table_ofs:word; (* to store table address *)
copy_table:array [0..10] of byte (* to store original values *)
exit_save:pointer;
.................
.................
(* $F+ *) (* compiler directive *)
procedure restore_table;
begin
for i:=0 to 10 do mem[table_seg:table_ofs + i]:= copy_table[i];
exitproc:=exit_save;
end;
(* $F- *) (* compiler directive *)
...............................
...............................
(* to change byte at offset k in table : *)
mem[table_seg:table_ofs + k]:=......;
...............................
...............................
begin (* main *)
table_seg:=memw[0:$7a]; (* get table *)
table_ofs:=memw[0:$78]; (* address *)
for i:=0 to 10 do copy_table[i]:=mem[table_seg:table ofs + i];
(* save original table *)
exit_save:=exitproc;
exitproc:=@restore_table;
........................
........................
end.
9. PLAYING TRICKS WITH INT 13h
We are now ready to experiment with some non standard diskettes
(using a scratch disk !!!).
We shall give two examples.
EXAMPLE 1 : (a) We format track 10 / head 0 with the following CHRN
fields
10 0 1 1
10 0 R 2 (2 <= R <=9)
(using the standard Disk Parameter Table).
(b) We read track 10 / head 0 / sector 2 using the standard Disk
Parameter Table. The error code should be 00 (no error).
(c) We read track 10 / head 0 / sector 1 using the standard Disk
Parameter Table. The read operation shows an error code 04
(meaning : sector not found).
The read operation first tries to locate the sector by reading CHRN
fields (until the right one is found or until all have been read).
In the present case, it is looking for C = 10 H = 0 R = 1 (as
requested) and * N = 2 * (the value of byte 3 in the Disk
Parameter Table; it is not possible to pass a sector length code
through the registers shown in section 2).
(d) Let us change byte 3 of the Disk Parameter Table (number of bytes
per sector code) into 01 and try reading again track 10 /
head 0 / sector 1.
The read operation now shows an error code 10h (meaning :
CRC error).
This is because the track has been formatted under control of the
standard Disk Base Table and therefore each sector contains 512 data
bytes. When we read track 10 / head 0 / sector 1 using our modified
Disk Parameter Table, only 128 * 2^1 = 256 bytes are read.
Of course, reading the first 256 bytes out of 512 is not a real
problem! We need to remember that a CRC word is written after the data
bytes when a write or format operation is executed. The CRC (word) is
a mathematical function (to be discussed in Appendix A) of the data
bytes * and * of the number of data bytes.
In our case, the disk controller reads the first 256 bytes and
interprets the two next bytes as a CRC; it tells INT 13h that a bad
CRC is detected.
(e) Using the same Disk Parameter Table as in (d), let us write any
256 bytes we like to track 10 / head 0 / sector 1 .
The write operation should show an error code 00 (no error).
A subsequent read operation shows an error code 00.
This is because the rewriting operations does not only updates data
byte; the disk controller also synthetizes a new, correct CRC.
EXAMPLE 2 : (a) Starting with a standard Disk Base Table, we change
its byte 4 (number of sector per track) to 11.
We format track 10 / head 0 with the following CHRN fields
10 0 R 2 (1 <= R <= 11) .
(b) Using the same Disk Base Table as in (a), we read track 10 /
head 0 / sector 1 . The read operation shows an error 04
(meaning : sector not found).
If we try any other sector R with 2 <= R <= 10 the read
operation still shows an error 04 .
What about sector 11 ?
Surprisingly, no error is shown.
The explanation uses facts described in Chapter 1 - sections 8 and 9.
The angular position of the CHRN field of sector 10 is
(162 + 9 * 654) * 36 / 625 = 348ø and the angular position of the
CHRN field of sector 11 is (162 + 6540) * 36 / 625 = 386ø .
So, during one diskette complete revolution the first ten CHRN fields
are written to the disk.
The 574 bytes for sector 11 are written while the diskette is
performing a * second * revolution. After these 574 bytes, bytes of
4Eh are written * to the end * of the track overwritting previous
disk bytes!
NOTE : When one tries to read a sector R and
R > number of sectors per track (byte 4 of the Disk
Base Table)
problems may occur. For such cases it is often useful to change byte 4
of the Disk Base Table to FFh.
REMARK : INT 13h should NEVER be used to try to read a sector whose
CHRN field is such that
C <> the real track number
or H <> the real head number .
More sophisticated techniques are required to attempt such readings.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ CHAPTER III ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ INSTALLING NEW INT 13h FUNCTIONS ³
³ ³
³ A FIRST STEP ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
1. GENERALITIES
We shall devote this entire chapter to one problem :
Read the CHRN field of all sectors present on a given track.
Such an aim might look rather limited. In fact, we will have to
introduce various techniques that are needed to solve more
sophisticated problems.
When we call the standard INT 13h to read or write a sector, we do not
need to worry about turning the disk drive motor on, about moving the
read/write head to the desired track : INT 13h takes care of such disk
drive control operations.
Before trying to install functions of our own, we must realize that
nothing comes for free ; the disk controller does exactly what it is
told to do and nothing more.
Of course, we could think of using some routines in ROM. The trouble
is that their location depend on the brand (and model) of the
computer. So, to ensure portability, we must give up the idea of
taking advantage of routines in ROM.
The reader might wonder why we want to expand INT 13h capabilities
rather than install independent services. Well, that is just a choice.
It is neither easier nor more difficult than other approaches.
Anyway, whatever the approach is, the core of the implementation
remains the same.
As we want to provide INT 13h with a new service, we need a new
function number. We choose FFh (almost arbitrarily).
Let us recall a well known technique.
There is a standard method to provide an interrupt with additional
services : one install a new interrupt function dispatcher using a TSR
(Terminate and Stay Resident) program. An appropriate .COM file will
do the job.
Of course, the installation part of the program should not be kept
resident ; it may be thrown away as soon as the installation is
completed.
Quite obviously, the interrupt function dispatcher should direct all
pre-existent services calls to the original dispatcher ; therefore we
need to save a pointer to the original dispatcher.
The following program demonstrates a skeleton method of implementing
a new INT 13h.
code segment
assume cs:code, ds:code
org 100h
start: jmp install
...............................
...............................
old_int13 dd ?
new_int13 proc far
cmp ah,0ffh
je new_service
jmp cs:old_int13
new_service:
; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
; ³ ³
; ³ new service ³
; ³ instructions ³
; ³ ³
; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
new_int13 endp
install:
mov ax,3513h ; get original
int 21h ; int vector
mov word ptr old_int13,bx ; and save
mov word ptr old_int13+2,es ; it
mov ax,2513h ; set
mov dx,offset new_int13 ; new
int 21h ; int vector
mov dx,offset install ; evaluate
add dx,15 ; amount of memory
mov cl,4 ; memory to reserve
shr dx,cl ; (in paragraphs)
mov ax,3100h ; terminate and
int 21h ; stay resident
code ends
end start
The installation part of the program above is a quick and dirty one :
it does not verify that the resident part is not already installed.
2. PLANNING OUR WORK
Before going into details, let us remember that this chapter is
devoted to the implementation of an INT 13h new service (function FFh)
to read the CHRN field of all sectors present on a given track.
The hard work is, of course, to fill in the box marked 'new service
instructions' in the program shown in section 1.
Several steps will be required :
(A) Turn the disk drive motor on
(B) Recalibrate the read/write head
(C) Position the read/write head over the desired track
(D) Read CHRN fields
All these steps will be performed at the lowest possible level. The
computer operating system will not be kept informed of what we will
be doing.
There is only a small price to pay the operating system for keeping
it ignorant :
ÚÄÄÄ The price to pay the operating system ÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ Just after exiting from INT 13h / function FFh ³
³ and wathever the reason for exiting is : ³
³ ³
³ a disk drive RESET (INT 13h / function 0) MUST ³
³ be performed. ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
REMARK : INT 13h / function FFh requires parameters (drive, track,
head). Just as for the standard INT 13h, the calling program
can use registers to pass parameters.
INT 13h / function FFh also needs a data area of its own to store its
results.
This data area can also be used to save the parameters passed to
INT 13h / function FFh.
Therefore the first instructions of INT 13h / function FFh could look
like :
jmp over_data
drive db ?
track db ?
head db ?
results db .... dup (?)
over_data: push ds
push cs
pop ds
; -- push all registers to be preserved
mov drive,dl
mov track,ch
mov head,dh
..................
..................
Of course, the last instructions to be executed should return a
pointer to the results (e.g. through ES:BX) and an error code (e.g.
through AH).
NOTE : Various procedures will be described in the next sections. Some
(easy) work is required to put all the pieces together.
We leave that to the reader.
3. TURNING THE DISK DRIVE MOTOR ON
Only one parameter is required : the drive number (0 = drive A:
1 = drive B:).
We need to access the disk drive DIGITAL OUTPUT REGISTER (DOR) through
port 3F2h.
To turn the motor of drive 0 on, the bit setting of the DOR must be
changed into
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ bit number ³
³ ³
³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³
ÃÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄ´
³ 0 ³ 0 ³ 0 ³ 1 ³ 1 ³ 1 ³ 0 ³ 0 ³
ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ
To turn the motor of drive 1 on, the bit setting of the DOR must be
changed into
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ bit number ³
³ ³
³ 7 ³ 6 ³ 5 ³ 4 ³ 3 ³ 2 ³ 1 ³ 0 ³
ÃÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄ´
³ 0 ³ 0 ³ 1 ³ 0 ³ 1 ³ 1 ³ 0 ³ 1 ³
ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ
The byte at memory location 0:440h holds the count down until the
disk drive motor is shut off. As we do not know for how long the disk
drive is required, it is safer to set the counter to the highest
possible value : FFh.
The computer hardware decrements this counter about 18.2 times per
second.
So, unless we need the motor to be left on for more than about
14 seconds (255/18.2), we do not need to worry any more about this
counter.
We are now ready to put it all together :
motor_on proc near
xor ax,ax
mov es,ax
cli
mov byte ptr es:[440h],0ffh
sti
mov cl,drive
mov al,10h
shl al,cl
or al,cl
or al,0ch
mov dx,3f2h
out dx,al
; -- wait for motor to come to speed (500 milliseconds)
mov al,3
xor cx,cx
m1: loop m1
dec al
jnz m1
ret
motor_on endp
4. RECALIBRATING THE READ/WRITE HEAD
(a) The recalibrate operation retracts the read/write head to
track 0.
It belongs to a group of disk controller operations which can only be
accessed at low level. Operations in this group will be used quite
often and they all require similar programming methods. Let us call
them LDC operations.
Before looking into the details of the recalibrate operation, we want
to discuss some generalities about LDC operations.
LDC operations make use of two disk controller registers :
. the DATA register (through port 3F5h)
. the STATUS register (through port 3F4h)
The disk controller operates in three phases when dealing with LDC
operations :
. the command phase
. the execution phase
. the result phase
There is nothing to be said about the execution phase ; the disk drive
electronics performs the requested operation.
Some LDC operations have no result phase (i.e. the disk controller
does not return any result). The recalibrate operation is an example.
The general requirements of the command phase are :
ÚÄÄÄ command phase requirements ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ send an appropriate sequence of bytes to the ³
³ DATA register (after receiving all bytes in the ³
³ sequence the disk controller will enter into ³
³ the execution phase) ³
³ ³
³ -------------------- BEWARE -------------------- ³
³ ³
³ before sending EACH byte : ³
³ ³
³ check if the DATA register is ready to accept ³
³ it, i.e. make sure ³
³ ³
³ that bit 6 of the STATUS register is 0 (*) ³
³ AND that bit 7 of the STATUS register is 1 (*) ³
³ ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ (*) allowing for up to 65536 retries ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
If the command phase fails, despite all the allowed retries, an
error code must be IRETurned to the calling program. The calling
program should save the error code, perform a RESET operation (as
explained in section 2) and take proper action (error message, retry,
program termination).
Most command phase failures are due to program bugs!
The command phase sequence required by the recalibrate operation is
the 2-byte sequence :
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³ ³
³ 07 ³ drive number ³
³ ³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
That is all we need to know to write a recalibrate procedure :
recalibrate proc near
mov ah,7
call out_to_nec ; send contents of AH
; to DATA register
jc in_out_error
mov ah,drive
call out_to_nec
jc in_out_error
; -- wait for head to settle (30 milliseconds)
mov cx,4000h
r1: loop r1
ret
in_out_error: mov ah,.. ; error code
; ... .....
; ... .....
; IRETURN TO CALLING PROGRAM
recalibrate endp
; out_to_nec send contents of AH to DATA register
; returns CF = 0 if success
; CF = 1 if failure
out_to_nec proc near
clc
mov dx,3f4h ; STATUS reg port
xor cx,cx
out1: in al,dx
test al,40h ; bit 6 of STATUS reg
jz out4
loop out1
out2: stc
ret
out4: xor cx,cx
out5: in al,dx
test al,80h ; bit 7 of STATUS reg
jnz out6
loop out5
jmp out2
out6: mov al,ah
inc dx
out dx,al
ret
out_to_nec endp
(b) The recalibrate operation has no result phase. Why? Well, I do
not know. I could not find any explanation in any manual.
How does one know the read/write head is actually retracted to
track 0 after a recalibrate operation. There is only one way : by
performing a LDC operation known as the 'sense interrupt status'
operation.
The command phase requires a 1-byte sequence to perform a sense
interrupt status operation. It is
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ 08 ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
Before looking into the details of the result phase for a sense
interrupt status operation, we want to discuss some generalities about
result phases.
The disk drive controller provides up to 7 result bytes (the exact
number depends on the LDC operation).
ALL result phase bytes MUST be read (the disk controller will not
accept any new command until they are read).
Let us decribe how the result bytes are to be read :
ÚÄÄÄ to read the result phase bytes : ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ read an appropriate number of bytes from the ³
³ DATA register ³
³ ³
³ -------------------- BEWARE -------------------- ³
³ ³
³ before reading EACH byte : ³
³ ³
³ check if the DATA register is ready to confide ³
³ its secrets, i.e. make sure ³
³ ³
³ that bit 6 of the STATUS register is 1 (*) ³
³ AND that bit 7 of the STATUS register is 1 (*) ³
³ ³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ (*) allowing for up to 65536 retries ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
If the appropriate number of bytes cannot be read from the DATA
register, an error code should be IRETurned to the calling program ...
(just as for command phase failure).
The number of result phase bytes is 2 for the sense interrupt status
operation.
Let us call the first one ST0
the second one PCN (Present Cylinder Number).
If a sense interrupt status operation is performed right after a
recalibrate operation then
PCN should be 00
bit 7 of ST0 should be 0
bit 6 of ST0 should be 0
bit 5 of ST0 should be 1
bit 4 of ST0 should be 0
bit 3 of ST0 should be 0
If any of these conditions is not satisfied, an error code should be
IRETurned to the calling program to report a recalibrate failure.
The calling program should try recalibrating three times before
assuming an error is real.
We end this section with a procedure that demonstrates how to read the
result phase bytes :
read_results proc near
mov cx,.. ; number of bytes to read
mov bx,offset some_where
rr1: push cx
call in_from_nec
jnc rr2
jmp in_out_error ; see part (a)
rr2: mov [bx],al
inc bx
pop cx
loop rr1
ret
read_results endp
; in_from_nec read one byte from DATA register
; returns CF = 0 byte in AL if success
; CF = 1 if failure
in_from_nec proc near
clc
xor cx,cx
mov dx,3f4h ; STATUS reg port
in2: in al,dx
test al,80h ; bit 7 of STATUS reg
jnz in4
loop in2
in3: stc
ret
in4: xor cx,cx
in5: in al,dx
test al,40h ; bit 6 of STATUS reg
jnz in6
loop in5
jmp in3
in6: inc dx
in al,dx
ret
in_from_nec endp
5. MOVING THE READ/WRITE HEAD
The disk controller provides us with a LDC operation known as the
seek operation.
The seek operation positions the read/write head over the desired
track.
Its command phase requires a 3-byte sequence
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³ ³ ³
³ 0Fh ³ (head * 4) + drive ³ track ³
³ ³ ³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
The seek operation has no result phase.
The only way to check if the read/write head is actually over the
desired track is to perform a sense interrupt status operation
(section 4(b)) ; it should return :
PCN = desired track number
bit 7 of ST0 = 0
bit 6 of ST0 = 0
bit 5 of ST0 = 1
bit 4 of ST0 = 0
bit 3 of ST0 = 0
We shall not discuss the seek operation any further. It is quite
similar to the recalibrate operation.
6. READING CHRN FIELDS
The LDC operation known as 'read ID' reads a CHRN field.
To be more precise :
It keeps reading bytes until a CHRN field is found.
This DOES NOT mean that read ID tries to locate the first CHRN field
on a track. Otherwise we would never be able to read all CHRN fields!
As one guesses, to read all CHRN fields one performs read ID
operations in a loop.
Fifty readings are commonly sufficient to catch all CHRN fiels.
There is no entry in the Guiness Book of Records about CHRN fields.
So I shall just mention that the record I know about is 34 CHRN
fields.
The command phase requires a 2-byte sequence
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³ ³
³ 4Ah ³ (head * 4) + drive ³
³ ³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The result phase provides 7 bytes :
the first result byte is called ST0
the second result byte is called ST1
the third result byte is called ST2
the four last result bytes hold the 4-byte CHRN field read
by read ID .
The reader is referred to Hogan's Sourcebook (8.19) for a complete
description of ST0, ST1 and ST2.
As far as LDC operations are concerned that is all we need to write a
procedure that reads all CHRN fields on a track (using programming
methods described in section 4). Just a moment, please!
So far some questions are left unanswered :
(a) Suppose that there are exactly 11 CHRN fields on the track
being examined. If we perform 50 read ID operations, some CHRN
fields will be read 4 times and the other ones will be read 5
times. How does one find the exact number of CHRN fields?
(b) It is natural to demand that readings should start at the
beginning of a track rather than 'somewhere'.
The problem raised in (b) cannot be solved by standard methods
(we need tricky techniques to be covered in Chapter IV).
Let us answer question (a).
Suppose that we have got a 'high precision clock' so that immediately
after each CHRN field is found we read (and save) the 'exact' time.
After reading fifty CHRN fields we can look closely at the results
(including the time readings). If we know how long it takes a diskette
to perform a complete revolution, it becomes quite easy to determine
the exact number of CHRN fields on the track and what they are.
As we know that there are about 6250 bytes on a track, it is also
quite easy to determine approximately how many bytes there are between
two consecutive CHRN fields.
The system board contains an Intel 8253/8254 timer chip. It provides
three 16-bit counters that may be used for timing or counting in the
system. Each of the counters decrements once every 839 nanoseconds
(the frequency is 1.19318 MHz). That is more than we need!
Details about the 8253 may be found in D.J. BRADLEY's book 'Assembly
Language for the IBM Personal Computer' (Prentice-Hall).
It takes about 32 microseconds to read/write a byte from/to the
diskette. Therefore we do not really need the 8353 timer high
precision.
Other 'clocks' are available.
Let us give an example.
The system board has an Intel 8237 DMA chip. One of its functions is
to refresh memory (it constantly restores the charge in the RAM memory
cells). Refresh cycles occur every 15 microseconds (approximately).
The DMA has a word count register (accessible through port 1) reserved
for the memory refresh function. It is decremented every 15
microseconds (approximately) ; although the exact delay between two
consecutive decrements may vary from one computer to another, it is a
constant for each computer.
So the DMA chip provides us with a nice 'clock'. Reading the word
count register through port 1 is a bit tricky.
Here is a reading procedure :
read_time proc near
xor cx,cx
rdt1: cli
out 0ch,al ; tricky part
; make DMA happy
in al,1
mov ah,al
jmp short rdt2
rdt2: in al,1
sti
or ah,ah
jnz rdt3
loop rdt1
rdt3: xchg ah,al
ret ; time in AX
read_time endp
We can determine how long it takes the diskette to perform a complete
revolution (whatever 'high precision clock' we use) by experimenting
on a standard diskette.
We are done!
NOTE : Interesting information about the RAM refresh cycle may be
found in B. Roemmele's excellent article :
Instant Speedup for your PC
PC Magazine July 1988 pp 331-346.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ CHAPTER IV ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ THE LDC READ TRACK OPERATION ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
1. GENERALITIES
We shall devote this chapter to the LDC operation known as 'read
track'. It is a very interesting operation mainly because playing
tricks with it is rather easy; in some cases, that is the only way to
read strange sectors and sometimes even organizational bytes.
Details will be given in section 4.
For the time being, let us mention that this operation can be used to
read all the data bytes on a track.
The read track operation can be implemented as a new INT 13h service,
say function FEh. About half of the hard work is already done : we
shall make use of several procedures that come with INT 13h / function
FFh (see Chapter III).
The disk controller has no internal buffer. Therefore when it comes to
read or write data bytes, we shall make use of the Direct Memory
Access capability of the system (DMA). That is what section 2 is all
about.
2. DIRECT MEMORY ACCESS (DMA)
The DMA provides several services. We already know about one : the
memory refresh function (see Chapter III - section 6).
Let us now examine another one.
With some devices, particularly disk drives, it is more sensible to
transfer a whole block of data at a time, rather than to transfer it
byte by byte.
The hardware is designed in such a way that the disk drive controller
transfers data to or from memory without the intervention of IN or OUT
instructions.
The IN and/or OUT instructions are still needed to initiate the
transfer, to specify things like the number of bytes to transfer and
the memory address for the transfer.
After the transfer is initiated, the disk drive controller handles all
the details and does not send the ready bit until the entire transfer
is complete.
This type of transfer is called 'Direct Memory Access Transfer'.
WHILE a DMA transfer is in progress, the processor can continue
executing other instructions. This is simply wonderful!
The instructions could be something like 'abort the transfer
immediately after 25 bytes are written to the disk'.
Although aborted operations require precise timings and are often
rather difficult to monitor, there are first-class rewards such as
writing bad CRC words and formatting only a part of a track.
More about aborted operations later on.
Here are the parameters required by the DMA :
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ DMA PARAMETERS ³
³ ³
ÃÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ thru ³ ³
³ port ³ description ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 0Bh ³ DMA command code : ³
³ ³ 46h = read ³
³ ³ 42h = verify ³
³ ³ 4Ah = write ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 0Ch ³ DMA command code just as above ³
³ ³ (one way to make DMA happy is to pass ³
³ ³ the command code through ports ³
³ ³ 0Bh and 0Ch ) ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 05h ³ Number of bytes to transfer MINUS 1 ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 04h ³ Low 16 bits of transfer ABSOLUTE ³
³ ³ address ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 81h ³ High 4 bits of transfer ABSOLUTE ³
³ ³ address ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 0Ah ³ Enable DMA channel 2 by writing 2 to ³
³ ³ port 0Ah (channel 2 is reserved for ³
³ ³ disk operations) ³
³ ³ ³
ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄ Remember ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ No page crossing ! ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The following procedure initializes the DMA for disk operations :
init_dma proc near
mov al,dma_cmd_code
out 0ch,al
out 0bh,al
mov ax,buffer_segment
mov cl,4
rol ax,cl
mov ch,al
and al,0f0h
add ax,buffer_offset
jnc no_carry
inc ch
no_carry: push ax
out 4,al
mov al,ah
out 4,al
mov al,ch
and al,0fh
out 81h,al
mov ax,number_bytes
dec ax
push ax
out 5,al
mov al,ah
out 5,al
pop cx
pop ax
add ax,cx
mov al,2
out 0ah,al
jnc dma_end
jmp dma_error
dma_end: ret
dma_error:
; PAGE CROSSING
; tell calling program
; the requested operation
; cannot be performed
init_dma endp
3. THE READ TRACK PHASES
The command phase 9-byte sequence is as follows :
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ read track command phase sequence ³
³ ³
ÃÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ byte ³ ³
³ no ³ description ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 01 ³ MUST be 42h ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 02 ³ (4 * head) + drive ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 03 ³ track number ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 04 ³ head number ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 05 ³ sector number; does not seem to be of ³
³ ³ any use ³
³ ³ may be set to 01 ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 06 ³ data size code ³
³ ³ code n means 128 * 2^n bytes/sector ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 07 ³ number of sectors/track ³
³ ³ if in doubt it should be set to FFh ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 08 ³ read/write gap length ³
³ ³ it tells the disk controller how ³
³ ³ many bytes to skip before looking for ³
³ ³ the next sector so that it can avoid ³
³ ³ reading some of the nonsense bytes of ³
³ ³ 4Eh in the gap between sectors ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 09 ³ known as the DTL byte; does not seem ³
³ ³ to be of any real use : see ³
³ ³ Appendix C ³
³ ³ ³
ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The result phase provides 7 bytes. Details are given in Hogan's
Sourcebook (8.19). The result bytes MUST be read (see Chapter III
- section 4) after the entire transfer is complete. That leaves us
with the question :
How does one know that the operation is complete?
When it is complete the disk controller invokes a diskette interrupt
which sets bit 7 of a status byte located at 0000:043Eh .
So one has to keep polling this byte until bit 7 is set then reset
the bit to 0 and continue on the next step.
The following procedure demonstrates how things can be worked out :
wait_int proc near
mov dh,2
xor ax,ax
mov es,ax
mov bx,43eh
mov cx,ax
wi1: mov dl,es:[bx]
test dl,80h
jnz wi2
loop wi1
dec dh
jnz wi1
jmp time_out
wi2: and byte ptr es:[bx],7fh
ret
time_out:
; time out error
; tell the calling program
wait_int endp
We conclude this section by recalling the steps involved in a read
track operation :
(A) Turn the disk drive motor on (if necessary)
(B) Recalibrate the read/write head (if necessary)
(C) Position the read/write head over the desired track
(if necessary)
(D) Initialize the DMA
(E) Command phase
(F) Wait for the transfer to be complete
(G) Read the result phase bytes
4. EXPERIMENTING WITH THE READ TRACK OPERATION
Let us denote
the number of bytes to be read (DMA parameter) by NB
the number of sectors/track (command phase parameter) by EOT
the sector size code (command phase parameter) by NN
the read/write gap (command phase parameter) by GL
the minimum of NB and EOT * 128 * 2^NN by NR
Starting from the * beginning * of a track, the read track operation
reads what it thinks are NR data bytes. It assumes that all sectors
are of size 128 * 2^NN (whether this is true or not). After reading
bytes from a sector, it looks for the next sector and reads from that
sector until NR bytes are read.
The best way of making things clear is to carry out a few experiments.
Let us start by (re)formatting a disk using the standard FORMAT
program (the one on the System Disk).
NO files should be written to the experimentation disk!
EXPERIMENT 1
Call read track with NB = 1200h track = 0
EOT = 9 head = 0
NN = 2
GL = 2Ah
The result phase bytes do not show any error and the buffer contains
the actual 200h * 9 = 1200h data bytes on track 0/head 0.
EXPERIMENT 2
Call read track with NB = 1210h track = 0
EOT = 9 head = 0
NN = 2
GL = 2Ah
The result phase bytes show an 'end of cylinder' error. That is
because NB > EOT * 128 * 2^NN . In other words, the calling
parameters are inconsistent : because of the value of NB the disk
controller tries to access a tenth sector although EOT = 9 !
The buffer contains the actual 1200h data bytes just as with
experiment 1.
EXPERIMENT 3
Call read track with NB = 11F0h track = 0
EOT = 9 head = 0
NN = 2
GL = 2Ah
The result phase bytes do not show any error and the buffer contains
11F0h data bytes (all the data bytes from sectors 1 to 8 and 1F0h
bytes from sector 9).
No CRC error is reported because although only 1F0h bytes from
sector 9 are sent to the data bus, the disk controller reads
* internally * the complete sector and then performs a CRC check.
EXPERIMENT 4
Call read track with NB = 2400h track = 14
EOT = 9 head = 0
NN = 3
GL = 8
The result bytes show a data field CRC error
and a 'no data' error.
The 'no data' error means that during the execution of the command,
the starting sector could not be found. Such an error is reported
because read track is called with NN = 3 so that the disk controller
expects the first CHRN field to be 14 00 01 03 .
As our experimentation disk is a standard one the first CHRN field is
in fact 14 00 01 02 !
The reason for the data field CRC error will become obvious quite
soon.
Let us look at the data buffer.
Bytes 0000 to 01FF are all of the same value (format fill byte).
As NN = 3 the disk controller assumes that sectors are of data length
1024 (= 400h). Therefore when dealing with sector 1 it reads the real
512 data bytes and the next 512 disk bytes (non real data bytes)
whether they are organizational bytes or bytes from sector 2.
Assuming that we are lucky (because some non real data bytes may be
bit shifted and in error) that is exactly what we can see when looking
at the data buffer :
bytes ³ are
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
0200h and 0201h ³ the data field CRC bytes for sector 1
0202h to 0251h ³ bytes of 4Eh (gap between sectors 1 and 2)
0252h to 025Dh ³ bytes of OO
025Eh to 0260h ³ bytes of A1h
0261h ³ byte of FEh
0262h to 0265h ³ the CHRN field bytes for sector 2 (14 00 02 02)
0266h and 0267h ³ the CHRN field CRC bytes for sector 2
0268h to 027Dh ³ bytes of 4Eh
027Eh to 0289h ³ bytes of 00
028Ah to 028Ch ³ bytes of A1h
028Dh ³ byte of FBh
028Eh to 03FFh ³ data bytes from sector 2
Now what is the next CHRN field found after reading the first
1024 bytes? 14 00 03 02 of course!
Some easy calculation show that :
the real data ³ may be found (in the data buffer)
for sector ³ at offset
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
1 ³ 0000h to 01FFh
2 ³ 1400h to 15FFh
3 ³ 0400h to 05FFh
4 ³ 1800h to 19FFh
5 ³ 0800h to 09FFh
6 ³ 1C00h to 1DFFh
7 ³ 0C00h to 0DFFh
8 ³ 2000h to 21FFh
9 ³ 1000h to 11FFh
Remark : The bit shift condition mentioned above may occur on any
track but it is much more likely to occur when a sector is
rewritten (the rotation rate may differ slightly from the last time we
wrote that sector so that the length of the sector will differ from
its previous length, possibly destroying a small part of the gap after
the sector or alternately allowing a few bits to survive). That is the
the reason why we make use of a newly (re)formatted disk without any
file written to it.
The reader should carry out the same experiment with track 0/head 0
(this one is rewritten by the FORMAT program as it reserves some
sectors for the operating system); more bit shifts will appear.
Sometimes things may even be worse : clock bits are read rather than
the 'real' bits.
Nevertheless, such conditions never occur when reading real data
bytes.
There is no cure when clock bits are read.
A data buffer shift procedure turns out to be very useful to deal with
bit shifts.
EXPERIMENT 5
Call read track with NB = 2400h track = 14
EOT = 9 head = 0
NN = 3
GL = 255
The result bytes show a data field CRC error
and a 'no data' error (of course).
The following CHRN fields may be found in the data buffer :
offset ³ CHRN field
ÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
0262h ³ 14 00 02 02
0662h ³ 14 00 05 02
0A62h ³ 14 00 08 02
0E62h ³ 14 00 02 02
1262h ³ 14 00 05 02
1662h ³ 14 00 08 02
1A62h ³ 14 00 02 02
1E62h ³ 14 00 05 02
2262h ³ 14 00 08 02
and
the real data ³ may be found (in the data buffer)
for sector ³ at offset
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
1 ³ 0000h to 01FFh
1 ³ 0C00h to 0DFFh
1 ³ 1800h to 19FFh
4 ³ 0400h to 05FFh
4 ³ 1000h to 11FFh
4 ³ 1C00h to 1DFFh
7 ³ 0800h to 09FFh
7 ³ 1400h to 15FFh
7 ³ 2000h to 21FFh
The reason for the repeats is that the disk controller is instructed
to skip 255 bytes after reading each 1024-byte block.
EXPERIMENT 6
Let us first reformat track 14/head 0 using INT 13h/function 05. The
format function calling parameters are standard except for the
order of the CHRN fields :
14 00 01 02
14 00 03 02
14 00 02 02
14 00 04 02
14 00 05 02
14 00 06 02
14 00 07 02
14 00 08 02
14 00 09 02
Next, using INT 13h/function 3 let us write a message, say
'This is sector R', in each sector R (1 <= R <= 9).
Call read track with NB = 1200h track = 14
EOT = 9 head = 0
NN = 2
GL = 2Ah
The result phase bytes show a 'no data' error due to the non standard
order of sectors.
The data buffer shows :
This is sector 1 at offset 0000h
This is sector 3 at offset 0200h
This is sector 2 at offset 0400h
................ .................
This confirms that the read track operation reads sectors in the disk
physical order.
WARNING : Read track aborts if it does not find the data mark
3 bytes of A1h + FBh (Chapter I - section 7) when
attempting to read a sector.
An example is given in Chapter V - section 4.
5. POSITIONING THE READ/WRITE HEAD ON THE BEGINNING OF A TRACK
In this section we shall answer question (b) raised in Chapter III-
section 6.
The trick is as follows :
We instruct the disk controller to perform a 'wrong' read track
operation; 'wrong' means that we make the disk controller to think the
recording method is an old one (not used any more). It tries to read
bytes starting at the beginning of the track. After one complete
revolution it will stop searching. That is the right time to take over
(as the read/write head is again at the beginning of the track).
As it would be a waste of time we must find a way around the necessity
to read the result phase bytes. The only reasonable way is to perform
a disk controller reset. That can be done by resetting bits of the DOR
register (Chapter III - section 3) :
reset proc near
mov dx,3f2h
mov cl,drive
mov al,10h
shl al,cl
or al,cl
or al,8
out dx,al
or al,4
jmp rs1
rs1: out dx,al
ret
reset endp
Now, the 'wrong' read track operation is quite similar to the standard
one. We only need to change the first byte in the command phase
sequence to 02 and set the number of bytes to be read (DMA
parameter) to 8 .
We conclude by putting things together :
(A) Turn the disk motor on (if necessary)
(B) Recalibrate the read/write head (if necessary)
(C) Position the read/write head over the desired track
(if necessary)
(D) Initialize the DMA
(E) Command phase
(F) Wait for the transfer to be 'complete', i.e. allow the disk
controller to realize nothing can be read
(wait_int procedure in section 3)
(G) Perform a disk controller reset
(H) Carry on IMMEDIATELY
e.g. read CHRN fields in a loop
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ CHAPTER V ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ THE LDC FORMAT OPERATION ³
³ ³
³ AND OTHER LDC OPERATIONS ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
1. THE COMPLETE LDC FORMAT OPERATION
Although there is no point in performing complete LDC format
operations (because that is just what INT 13h/function 5 does),some
almost trivial modification will allow us to perform what we are
really interested in : ABORTED format operations.
The complete technique involves the following steps :
(A) Turn the disk drive motor on (if necessary)
(B) Recalibrate the read/write head (if necessary)
(C) Position the read/write head over the desired track
(if necessary)
(D) Initialize the DMA (see below)
(E) Command phase (see below)
(F) Wait for the operation to be complete
(wait_int procedure; see Chapter IV - section 3)
(G) Read the result phase bytes (see below)
The DMA initialization step is quite standard (see Chapter IV -
section 2); the DMA command code is of course 4Ah (write) and the
number of bytes to transfer is 4 * (number of sectors per track).
The command phase requires a 6-byte sequence as follows :
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ format track command phase sequence ³
³ ³
ÃÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ byte ³ ³
³ no ³ description ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 01 ³ MUST be 4Dh ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 02 ³ (4 * head) + drive ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 03 ³ data size code ³
³ ³ code n means 128 * 2^n bytes/sector ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 04 ³ number of sectors/track ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 05 ³ format gap length ³
³ ³ (number of bytes of 4Eh written ³
³ ³ between sectors) ³
³ ³ ³
ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³ ³ ³
³ 06 ³ format fill byte ³
³ ³ (the data value stored in each byte ³
³ ³ of the sectors when a track is ³
³ ³ formatted) ³
³ ³ ³
ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The result phase provides 7 bytes. Details are given in Hogan's
Sourcebook (8.19). The result bytes MUST be read (unless a disk
controller reset is performed).
2. ABORTED FORMAT OPERATIONS
A format operation may be aborted any time. All that is needed is
to perform a disk controller reset (see chapter IV - section 5).
The abortion is usually performed in the following circumstances :
. While the CRC bytes for the last CHRN field are being written.
This is the only way to 'write' a bad CRC word for a CHRN field.
Such sectors are called 'hidden sectors' because they are not
spotted by the standard method described in Chapter III. We shall
discuss hidden sectors in section 4.
. Just after the CRC bytes for the last CHRN field are written.
This is the way to ensure that a sector has no data marks
(3 bytes of A1h + FBh); see Chapter I - section 7.
. While the data bytes are being written or while the CRC bytes for
the data field are being written. These are ways to 'write' a bad
CRC word for a data field.
. Just after the last sector is written (see example 1 below).
To play such tricks we need to know when the last CHRN field is about
to be written. That is when the DMA counter (accessible through
port 5) holds a value of FFFFh .
The following procedure may be used :
; abort the wait_int procedure may NOT be used when
; dealing with aborted operations because it
; waits for the operation to be complete!
abort proc near
mov dh,2 ; or any suitable value
xor cx,cx
ab1: in al,5
mov ah,al
in al,5
cmp ax,0ffffh
je ab2
loop ab1
dec dh
jnz ab1
jmp ab_error
ab2:
;
; delay (depending on one wants to do)
;
; perform a disk controller reset
;
ret
ab_error:
;
; time out error
;
; tell the calling program
;
abort endp
WARINING: Issuing an aborted format command may occasionally cause a
'glitch' on the opposite side of the diskette (same track).
This is probably due to a hardware bug.
Let us denote
the number of sectors/track (command phase parameter) by EOT
the sector size code (command phase parameter) by NN
the format gap length (command phase parameter) by FGL
We are now ready to give a few examples.
EXAMPLE 1
We want track 21/head 0 to contain 12 sectors as follows:
CHRN field ³ CHRN ³ true data ³ data ³
³ CRC ³ size ³ CRC ³ remarks
ÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
21 00 01 02 ³ ok ³ 512 ³ ok ³
21 00 02 02 ³ ok ³ 512 ³ ok ³
21 00 03 02 ³ ok ³ 512 ³ ok ³
21 00 04 02 ³ ok ³ 512 ³ ok ³
21 00 05 02 ³ ok ³ 512 ³ ok ³
21 00 06 02 ³ ok ³ 512 ³ ok ³
21 00 07 02 ³ ok ³ 512 ³ ok ³
21 00 08 02 ³ ok ³ 512 ³ ok ³
21 00 09 02 ³ ok ³ 512 ³ ok ³
21 00 10 01 ³ ok ³ 256 ³ ok ³
21 33 12 02 ³ bad ³ --- ³ -- ³ no data; just hidden sect
Two passes are required to format such a track.
(a) Call format with EOT = 12 track = 21
FGL = 233 head = 0
NN = 1
CHRN fields 21 00 01 02
21 00 02 02
21 00 03 02
21 00 04 02
21 00 05 02
21 00 06 02
21 00 07 02
21 00 08 02
21 00 09 02
21 00 10 01
21 33 12 02
ABORT while CRC bytes for last CHRN field.
are being written
(b) Call format with EOT = 9 track = 21
FGL = 32 head = 0
NN = 2
CHRN fields 21 00 01 02
21 00 02 02
21 00 03 02
21 00 04 02
21 00 05 02
21 00 06 02
21 00 07 02
21 00 08 02
21 00 09 02
ABORT just after the last sector is written.
Some elementary arithmetic is necessary to determine the FGL values.
The table in Appendix B may be helpful.
EXAMPLE 2
We want track 22/head 0 to contain 9 sectors as follows:
CHRN field ³ CHRN ³ true data ³ data ³
³ CRC ³ size ³ CRC ³ remarks
ÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
22 00 01 02 ³ ok ³ 512 ³ ok ³ wrong angular position (*)
22 00 02 02 ³ ok ³ 512 ³ ok ³
22 00 03 02 ³ ok ³ 512 ³ ok ³
22 00 04 02 ³ ok ³ 512 ³ ok ³
22 00 05 02 ³ ok ³ 512 ³ ok ³
22 00 06 02 ³ ok ³ 512 ³ ok ³
22 00 07 02 ³ ok ³ 512 ³ ok ³
22 00 08 02 ³ ok ³ 512 ³ ok ³
22 00 09 02 ³ ok ³ 512 ³ bad ³
(*) we want the angular position of the first CHRN field to be 25ø
Call format with EOT = 19 track = 22
FGL = 80 head = 0
NN = 2
CHRN fields 22 00 01 02
22 00 02 02
22 00 03 02
22 00 04 02
22 00 05 02
22 00 06 02
22 00 07 02
22 00 08 02
22 00 09 02
22 00 10 02
22 00 01 02
22 00 02 02
22 00 03 02
22 00 04 02
22 00 05 02
22 00 06 02
22 00 07 02
22 00 08 02
22 00 09 02
ABORT while the CRC bytes for the last sector
data bytes are being written.
This trick is used by some copy protection methods.
Note that some of the data bytes for sector 9 are at the beginning of
the track while the other ones are at the end of the track.
The data CRC error in sector 9 will be corrected if this sector is
rewritten (unless an aborted write operation is performed).
EXAMPLE 3
This example demonstrates an overwriting technique that is often
quite useful.
We want track 23/head 0 to contain 7 sectors as follows:
CHRN field ³ CHRN ³ true data ³ data ³
³ CRC ³ size ³ CRC ³ remarks
ÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
23 00 01 01 ³ ok ³ 256 ³ ok ³
23 00 02 02 ³ ok ³ 512 ³ ok ³
23 00 03 03 ³ ok ³ 1024 ³ ok ³
23 00 04 03 ³ ok ³ 1024 ³ ok ³
23 00 05 03 ³ ok ³ 1024 ³ ok ³
23 00 06 02 ³ ok ³ 512 ³ ok ³
23 00 07 04 ³ ok ³ --- ³ -- ³ no data; CHRN field only
Call format with EOT = 15 track = 23
FGL = 85 head = 0
NN = 1
CHRN fields 23 00 01 01
23 00 02 02
23 00 21 01
23 00 03 03
23 00 31 01
23 00 32 01
23 00 04 03
23 00 41 01
23 00 42 01
23 00 05 03
23 00 51 01
23 00 52 01
23 00 06 02
23 00 61 01
23 00 07 04
ABORT just after CRC bytes for the last
CHRN field are written.
Writing the appropriate number of bytes to sectors 1..6 will destroy
the unwanted CHRN fields (INT 13h/function 3 may be used).
EXERCISE
Format track track 24/head 0 as follows:
CHRN field ³ CHRN ³ true data ³ data ³
³ CRC ³ size ³ CRC ³ remarks
ÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
24 00 01 02 ³ ok ³ 512 ³ ok ³
24 00 02 02 ³ ok ³ 512 ³ ok ³
24 00 03 02 ³ ok ³ 512 ³ ok ³
24 00 04 02 ³ ok ³ 512 ³ ok ³
24 00 05 02 ³ ok ³ 512 ³ ok ³
24 00 06 02 ³ ok ³ 512 ³ ok ³
24 00 07 02 ³ ok ³ 512 ³ ok ³
24 00 08 02 ³ ok ³ 512 ³ ok ³
24 00 09 02 ³ ok ³ --- ³ -- ³ no data; CHRN field only.
24 00 10 02 ³ ok ³ 512 ³ ok ³ CHRN fields for sectors
³ ³ ³ ³ 9 and 10 must be 7ø apart
3. OTHER LDC OPERATIONS
The disk controller accepts some other useful operations :
. Read data
. Write data
. Read deleted data
. Write deleted data
From a programming point of view these operations are quite similar
to the read track operation (Chapter IV). Details may be found in
Hogan's Sourcebook (8.18).
They may be aborted (using the same technique as described for
format).
Just a few words about 'deleted' data. The terminology is misleading.
Deleted data are not physically erased! They are just marked as
deleted (i.e. the normal data mark 3 bytes of A1h + FBh is changed
into 3 bytes of A1h + FAh . That is the secret!).
EXERCISE
Disassemble the INT 13h ROM routines.
It is not a trivial exercise but it is quite rewarding.
4. HIDDEN SECTORS
First we want to know how read track deals with hidden sectors.
Let us carry out the following experiment:
(a) We need a brand new diskette (because we do not want leftovers
from previous format operations).
Call format with EOT = 9 track = 21
FGL = 80 head = 0
NN = 2
CHRN fields 21 00 01 02
21 00 02 02
21 00 03 02
21 00 04 02
21 00 05 02
21 00 06 02
21 00 07 02
21 00 08 02
21 00 09 02
ABORT while the CRC bytes for the last
CHRN field are being written
Next call format with EOT = 1 track = 21
FGL = 80 head = 0
NN = 2
CHRN field 27 12 13 14
ABORT while the CRC bytes for the
CHRN field are being written
Track 21/head 0 now contains two hidden sectors.
(b) Call read track with NB = 1200h track = 21
EOT = 9 head = 0
NN = 2
GL = 2Ah
The result phase bytes show CRC errors and a missing address mark
error. The data buffer contains the data bytes form sectors 1..8.
Next call read track with NB = 2400h track = 21
EOT = 9 head = 0
NN = 3
GL = 2Ah
The result phase bytes show CRC errors and a missing address mark
error. 1000h bytes are transferred to the data buffer.
CONCLUSION : Read track does not mind CHRN fields with bad CRC but it
aborts when it does not find a data mark.
REMARK : There is a way around the brand new disk requirement
mentioned above. Reformatting a track with one sector of
size code 6 does not leave any CHRN field or data mark.
We now discuss a difficult problem : finding hidden sectors.
The technique described in Chapter III does not report the CHRN fields
with bad CRC.
Read track may sometimes help to report the existence of a hidden
sector but it does not generally allows to identify such a sector.
The read command is useful to confirm the existence of a hidden sector
(if we know its CHRN field) because the result phase bytes show
a CRC error for the CHRN field.
I confess I do not know of a general method to spot all hidden sectors
on a track.
I shall describe what I know about it. Comments from readers will be
most welcome.
Suppose that c h r n , c' h' r' n' are the nth and the (n+1)th
visible CHRN fields. We discuss a method to spot an in between hidden
sector provided :
. the CHRN fields are not too close to each other
. the hidden sector CHRN field is not of c h r n
(i) Position the read/write head on the beginning of the track (using
the technique described in Chapter IV - section 5)
(ii) Position the read/write head a few bytes further than the nth
CHRN field (by reading n CHRN fields)
(iii) Issue a read CHRN command. This operation MUST be aborted so
that the disk controller is not given any chance to read the
(n+1)th CHRN field. The timing is of course critical!
(iv) The previous step being an aborted operation we do not know
about the result phase bytes. They are kept secret by the disk
controller. So we want it to confide its secret.
The trick is to issue a 'wrong' read CHRN command (change the
first byte in the command phase sequence to OAh ). The four
last result phase bytes provide us with a CHRN field. If it is
not of c h r n then we have found a hidden sector (if it is
of c' h' r' n' we could retry with a shorter delay in
step (iii), just to be sure).
REMARK : Searching for all hidden sectors on a track can take a 'long'
time. So it is good practice to revitalize the motor shut off
count down byte at memory location 0000:0440h.
This is quite easy :
revital proc near
xor ax,ax
mov es,ax
cli
or es:[0440h],0ffh
sti
ret
revital endp
Turning the motor off when disk accesses are no longer needed can be
done in a similar way : setting the motor shut off count down byte to
a small value (say 25h) is a good way to do it.
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ APPENDIX A ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ CYCLIC REDUNDANCY CODES ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
1. GENERALITIES
Coding theory is concerned with the transmission of information.
During transmission a message may be slightly changed (due to a
'noisy' channel). Building some appropriately chosen redundancy in
the message is a standard way to allow the receiver to detect some
transmission errors.
For example, to transmit a 'true' 200-byte message one can send
202 bytes, the two final bytes being used as a word whose value is
the sum of the 'true' message bytes.
We will not discuss general coding theory. Only one very special case
will be covered. Sorry, ... Some algebra is involved.
Let us denote the 2-element set [0,1] by F[2] (this is no standard
mathematical notation ; it is just easier to type in).
We need new addition and substraction operations for F[2] (we want
a + b and a - b to be in F[2] when a and b are).
We define a new + operation by the following table :
+ ³ 0 1
ÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ
0 ³ 0 1
³
1 ³ 1 0
Note that this is just the truth-table for XOR .
Now, the only reasonable way to define a new - (minus) operation is
a - b = a + b (for all a, b in F[2] ).
This is not an error; we really mean it!
What about multiplication ?
That is not difficult : we keep the standard one. Another way to put
it : the multiplication table is just the truth-table for AND .
So, division does not deserve any explanation.
Let us say that a polynomial is * over * F[2] whenever all its
coefficients are in F[2] .
We can work with polynomials over F[2] just as we have learned in
high school algebra, except that the new + operation should be
used whenever coefficients are to be summed.
Here are a few examples :
(x^2 + 1) (x^2 + x + 1) = x^4 + x^3 + x + 1 ;
(x + 1) (x^15 + x^14 + x^13 + x^12 + x^4 + x^3 + x^2 + x + 1) =
x^16 + x^12 + x^5 + 1 ;
Dividing x^3 + x^2 + x by x + 1 , we find :
x^2 + 1 <--- quotient
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
x + 1 ³ x^3 + x^2 + x
x^3 + x^2
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
x
x + 1
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
1 <--- remainder
The following polynomial (known as the CRC-CCITT polynomial) is very
important for diskette operations (as will appear in section 2) :
ÚÄÄÄ CRC-CCITT polynomial ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ x^16 + x^12 + x^5 + 1 ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
2. GENERATING CYCLIC REDUNDANCY CHECK WORDS
(a) Let us assume that array_data is an array[0..nn - 1] of
bytes. We want to regard array_data as a polynomial over
F[2].
Writing in a row the binary representation of all bytes of array_data
provides us with a sequence of nn * 8 bits:
b[i] (0 <= i <= 8 * nn - 1) .
Now, the polynomial we are looking for is just the sum of all
monomials
b[i] . x^(8 * nn - 1 - i).
Let us give an example to show all this is much simpler than it looks.
Assuming that array_data is a 3-byte array and that
array_data[0] = F0h array_data[1] = 10h array_data[2] = 21h ,
we find that the binary representation sequence is
F0h 10h 21h
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
1 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1
and that the corresponding polynomial is
x^23 + x^22 + x^21 + x^20 + x^12 + x^5 + 1 .
(b) Let array_data be as above. We denote the corresponding polynomial
(as defined in (a)) by p(x).
Let r(x) be the * remainder * of the division of
x^16 . p(x) by the CRC-CCITT polynomial.
The degree of r(x) is, of course, less than 16 and therefore r(x)
corresponds to a word w .
We call w the 'TCRC word for array_data' (T stands for temporary).
TCRC words may be evaluated quite easily : assembly language provides
SHL and XOR instructions and nothing more is required!
Here is a skech of a TCRC program :
array_data db ..............
size_of_array dw ....
tcrc_word dw ?
..............................................
..............................................
mov cx,size_of_array
mov ax,0 ; (*) line marked for
; further reference
mov bx,offset array_data
again:
xor ah,[bx]
call partial
inc bx
loop again
mov tcrc_word,ax
....................
....................
partial proc near
push cx
mov cx,8
p1: shl ax,1
jnc p2
xor ax,1021h
p2: loop p1
pop cx
ret
partial endp
(c) The disk controller uses a variant of TCRC words : CRC words.
CRC words may be evaluated almost like TCRC words ; we only need to
change the line marked (*) in the program above into
mov ax,0ffffh
We also need to know that the disk controller writes and reads CRC
words in an unconventional way :
* Most significant byte first *
* Least significant byte last *
We are now able to describe the bytes CRC1, CRC2, CRC3 and CRC4 in
the fine structure of a sector (Chapter I - section 7).
(i) CRC1 and CRC2 hold the CRC word of the 8-byte array :
A1h A1h A1h FEh C H R N .
(ii) CRC3 and CRC4 hold the CRC word of the
(4 + (number of data bytes))-byte array:
A1h A1h A1h FBh data bytes .
That's all!
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ APPENDIX B ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ DISK SPACE USED BY SECTORS ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The fine structure of sectors (Chapter I - section 7) shows that a
sector requires
62 + 128 * 2^N + size of format gap
disk bytes.
Some disk utilities display the measure (expressed in degrees) of the
arc used by a sector (about 36/625 * number of disk bytes).
The following table gives the measure of sector arcs for N in [0..4]
and format gap in [6..255].
The table is useful to try guessing the size of the format gap when
N and sector arc are known.
Gap N=0 N=1 N=2 N=3 N=4
---------------------------------------------------------
06h 11.3 18.7 33.5 62.9 121.9
07h 11.4 18.8 33.5 63.0 122.0
08h 11.5 18.8 33.6 63.1 122.0
09h 11.5 18.9 33.6 63.1 122.1
0Ah 11.6 18.9 33.7 63.2 122.2
0Bh 11.6 19.0 33.7 63.2 122.2
0Ch 11.7 19.1 33.8 63.3 122.3
0Dh 11.7 19.1 33.9 63.4 122.3
0Eh 11.8 19.2 33.9 63.4 122.4
0Fh 11.9 19.2 34.0 63.5 122.4
10h 11.9 19.3 34.0 63.5 122.5
11h 12.0 19.3 34.1 63.6 122.6
12h 12.0 19.4 34.1 63.6 122.6
13h 12.1 19.5 34.2 63.7 122.7
14h 12.1 19.5 34.3 63.8 122.7
15h 12.2 19.6 34.3 63.8 122.8
16h 12.3 19.6 34.4 63.9 122.9
17h 12.3 19.7 34.4 63.9 122.9
18h 12.4 19.7 34.5 64.0 123.0
19h 12.4 19.8 34.6 64.0 123.0
1Ah 12.5 19.9 34.6 64.1 123.1
1Bh 12.5 19.9 34.7 64.2 123.1
1Ch 12.6 20.0 34.7 64.2 123.2
1Dh 12.7 20.0 34.8 64.3 123.3
1Eh 12.7 20.1 34.8 64.3 123.3
1Fh 12.8 20.2 34.9 64.4 123.4
20h 12.8 20.2 35.0 64.4 123.4
21h 12.9 20.3 35.0 64.5 123.5
22h 13.0 20.3 35.1 64.6 123.5
23h 13.0 20.4 35.1 64.6 123.6
24h 13.1 20.4 35.2 64.7 123.7
25h 13.1 20.5 35.2 64.7 123.7
26h 13.2 20.6 35.3 64.8 123.8
27h 13.2 20.6 35.4 64.8 123.8
28h 13.3 20.7 35.4 64.9 123.9
29h 13.4 20.7 35.5 65.0 123.9
2Ah 13.4 20.8 35.5 65.0 124.0
2Bh 13.5 20.8 35.6 65.1 124.1
2Ch 13.5 20.9 35.6 65.1 124.1
2Dh 13.6 21.0 35.7 65.2 124.2
2Eh 13.6 21.0 35.8 65.3 124.2
2Fh 13.7 21.1 35.8 65.3 124.3
30h 13.8 21.1 35.9 65.4 124.4
31h 13.8 21.2 35.9 65.4 124.4
32h 13.9 21.2 36.0 65.5 124.5
33h 13.9 21.3 36.0 65.5 124.5
34h 14.0 21.4 36.1 65.6 124.6
35h 14.0 21.4 36.2 65.7 124.6
36h 14.1 21.5 36.2 65.7 124.7
37h 14.2 21.5 36.3 65.8 124.8
Gap N=0 N=1 N=2 N=3 N=4
---------------------------------------------------------
38h 14.2 21.6 36.3 65.8 124.8
39h 14.3 21.6 36.4 65.9 124.9
3Ah 14.3 21.7 36.5 65.9 124.9
3Bh 14.4 21.8 36.5 66.0 125.0
3Ch 14.4 21.8 36.6 66.1 125.0
3Dh 14.5 21.9 36.6 66.1 125.1
3Eh 14.6 21.9 36.7 66.2 125.2
3Fh 14.6 22.0 36.7 66.2 125.2
40h 14.7 22.1 36.8 66.3 125.3
41h 14.7 22.1 36.9 66.3 125.3
42h 14.8 22.2 36.9 66.4 125.4
43h 14.9 22.2 37.0 66.5 125.4
44h 14.9 22.3 37.0 66.5 125.5
45h 15.0 22.3 37.1 66.6 125.6
46h 15.0 22.4 37.1 66.6 125.6
47h 15.1 22.5 37.2 66.7 125.7
48h 15.1 22.5 37.3 66.8 125.7
49h 15.2 22.6 37.3 66.8 125.8
4Ah 15.3 22.6 37.4 66.9 125.8
4Bh 15.3 22.7 37.4 66.9 125.9
4Ch 15.4 22.7 37.5 67.0 126.0
4Dh 15.4 22.8 37.5 67.0 126.0
4Eh 15.5 22.9 37.6 67.1 126.1
4Fh 15.5 22.9 37.7 67.2 126.1
50h 15.6 23.0 37.7 67.2 126.2
51h 15.7 23.0 37.8 67.3 126.3
52h 15.7 23.1 37.8 67.3 126.3
53h 15.8 23.1 37.9 67.4 126.4
54h 15.8 23.2 38.0 67.4 126.4
55h 15.9 23.3 38.0 67.5 126.5
56h 15.9 23.3 38.1 67.6 126.5
57h 16.0 23.4 38.1 67.6 126.6
58h 16.1 23.4 38.2 67.7 126.7
59h 16.1 23.5 38.2 67.7 126.7
5Ah 16.2 23.6 38.3 67.8 126.8
5Bh 16.2 23.6 38.4 67.8 126.8
5Ch 16.3 23.7 38.4 67.9 126.9
5Dh 16.4 23.7 38.5 68.0 126.9
5Eh 16.4 23.8 38.5 68.0 127.0
5Fh 16.5 23.8 38.6 68.1 127.1
60h 16.5 23.9 38.6 68.1 127.1
61h 16.6 24.0 38.7 68.2 127.2
62h 16.6 24.0 38.8 68.2 127.2
63h 16.7 24.1 38.8 68.3 127.3
64h 16.8 24.1 38.9 68.4 127.3
65h 16.8 24.2 38.9 68.4 127.4
66h 16.9 24.2 39.0 68.5 127.5
67h 16.9 24.3 39.0 68.5 127.5
68h 17.0 24.4 39.1 68.6 127.6
69h 17.0 24.4 39.2 68.7 127.6
Gap N=0 N=1 N=2 N=3 N=4
---------------------------------------------------------
6Ah 17.1 24.5 39.2 68.7 127.7
6Bh 17.2 24.5 39.3 68.8 127.7
6Ch 17.2 24.6 39.3 68.8 127.8
6Dh 17.3 24.6 39.4 68.9 127.9
6Eh 17.3 24.7 39.4 68.9 127.9
6Fh 17.4 24.8 39.5 69.0 128.0
70h 17.4 24.8 39.6 69.1 128.0
71h 17.5 24.9 39.6 69.1 128.1
72h 17.6 24.9 39.7 69.2 128.2
73h 17.6 25.0 39.7 69.2 128.2
74h 17.7 25.0 39.8 69.3 128.3
75h 17.7 25.1 39.9 69.3 128.3
76h 17.8 25.2 39.9 69.4 128.4
77h 17.8 25.2 40.0 69.5 128.4
78h 17.9 25.3 40.0 69.5 128.5
79h 18.0 25.3 40.1 69.6 128.6
7Ah 18.0 25.4 40.1 69.6 128.6
7Bh 18.1 25.5 40.2 69.7 128.7
7Ch 18.1 25.5 40.3 69.7 128.7
7Dh 18.2 25.6 40.3 69.8 128.8
7Eh 18.3 25.6 40.4 69.9 128.8
7Fh 18.3 25.7 40.4 69.9 128.9
80h 18.4 25.7 40.5 70.0 129.0
81h 18.4 25.8 40.5 70.0 129.0
82h 18.5 25.9 40.6 70.1 129.1
83h 18.5 25.9 40.7 70.1 129.1
84h 18.6 26.0 40.7 70.2 129.2
85h 18.7 26.0 40.8 70.3 129.2
86h 18.7 26.1 40.8 70.3 129.3
87h 18.8 26.1 40.9 70.4 129.4
88h 18.8 26.2 40.9 70.4 129.4
89h 18.9 26.3 41.0 70.5 129.5
8Ah 18.9 26.3 41.1 70.6 129.5
8Bh 19.0 26.4 41.1 70.6 129.6
8Ch 19.1 26.4 41.2 70.7 129.6
8Dh 19.1 26.5 41.2 70.7 129.7
8Eh 19.2 26.5 41.3 70.8 129.8
8Fh 19.2 26.6 41.3 70.8 129.8
90h 19.3 26.7 41.4 70.9 129.9
91h 19.3 26.7 41.5 71.0 129.9
92h 19.4 26.8 41.5 71.0 130.0
93h 19.5 26.8 41.6 71.1 130.1
94h 19.5 26.9 41.6 71.1 130.1
95h 19.6 26.9 41.7 71.2 130.2
96h 19.6 27.0 41.8 71.2 130.2
97h 19.7 27.1 41.8 71.3 130.3
98h 19.7 27.1 41.9 71.4 130.3
99h 19.8 27.2 41.9 71.4 130.4
9Ah 19.9 27.2 42.0 71.5 130.5
9Bh 19.9 27.3 42.0 71.5 130.5
Gap N=0 N=1 N=2 N=3 N=4
---------------------------------------------------------
9Ch 20.0 27.4 42.1 71.6 130.6
9Dh 20.0 27.4 42.2 71.6 130.6
9Eh 20.1 27.5 42.2 71.7 130.7
9Fh 20.2 27.5 42.3 71.8 130.7
A0h 20.2 27.6 42.3 71.8 130.8
A1h 20.3 27.6 42.4 71.9 130.9
A2h 20.3 27.7 42.4 71.9 130.9
A3h 20.4 27.8 42.5 72.0 131.0
A4h 20.4 27.8 42.6 72.0 131.0
A5h 20.5 27.9 42.6 72.1 131.1
A6h 20.6 27.9 42.7 72.2 131.1
A7h 20.6 28.0 42.7 72.2 131.2
A8h 20.7 28.0 42.8 72.3 131.3
A9h 20.7 28.1 42.8 72.3 131.3
AAh 20.8 28.2 42.9 72.4 131.4
ABh 20.8 28.2 43.0 72.5 131.4
ACh 20.9 28.3 43.0 72.5 131.5
ADh 21.0 28.3 43.1 72.6 131.6
AEh 21.0 28.4 43.1 72.6 131.6
AFh 21.1 28.4 43.2 72.7 131.7
B0h 21.1 28.5 43.2 72.7 131.7
B1h 21.2 28.6 43.3 72.8 131.8
B2h 21.2 28.6 43.4 72.9 131.8
B3h 21.3 28.7 43.4 72.9 131.9
B4h 21.4 28.7 43.5 73.0 132.0
B5h 21.4 28.8 43.5 73.0 132.0
B6h 21.5 28.8 43.6 73.1 132.1
B7h 21.5 28.9 43.7 73.1 132.1
B8h 21.6 29.0 43.7 73.2 132.2
B9h 21.6 29.0 43.8 73.3 132.2
BAh 21.7 29.1 43.8 73.3 132.3
BBh 21.8 29.1 43.9 73.4 132.4
BCh 21.8 29.2 43.9 73.4 132.4
BDh 21.9 29.3 44.0 73.5 132.5
BEh 21.9 29.3 44.1 73.5 132.5
BFh 22.0 29.4 44.1 73.6 132.6
C0h 22.1 29.4 44.2 73.7 132.6
C1h 22.1 29.5 44.2 73.7 132.7
C2h 22.2 29.5 44.3 73.8 132.8
C3h 22.2 29.6 44.3 73.8 132.8
C4h 22.3 29.7 44.4 73.9 132.9
C5h 22.3 29.7 44.5 74.0 132.9
C6h 22.4 29.8 44.5 74.0 133.0
C7h 22.5 29.8 44.6 74.1 133.0
C8h 22.5 29.9 44.6 74.1 133.1
C9h 22.6 29.9 44.7 74.2 133.2
CAh 22.6 30.0 44.7 74.2 133.2
CBh 22.7 30.1 44.8 74.3 133.3
CCh 22.7 30.1 44.9 74.4 133.3
CDh 22.8 30.2 44.9 74.4 133.4
Gap N=0 N=1 N=2 N=3 N=4
---------------------------------------------------------
CEh 22.9 30.2 45.0 74.5 133.5
CFh 22.9 30.3 45.0 74.5 133.5
D0h 23.0 30.3 45.1 74.6 133.6
D1h 23.0 30.4 45.2 74.6 133.6
D2h 23.1 30.5 45.2 74.7 133.7
D3h 23.1 30.5 45.3 74.8 133.7
D4h 23.2 30.6 45.3 74.8 133.8
D5h 23.3 30.6 45.4 74.9 133.9
D6h 23.3 30.7 45.4 74.9 133.9
D7h 23.4 30.8 45.5 75.0 134.0
D8h 23.4 30.8 45.6 75.0 134.0
D9h 23.5 30.9 45.6 75.1 134.1
DAh 23.6 30.9 45.7 75.2 134.1
DBh 23.6 31.0 45.7 75.2 134.2
DCh 23.7 31.0 45.8 75.3 134.3
DDh 23.7 31.1 45.8 75.3 134.3
DEh 23.8 31.2 45.9 75.4 134.4
DFh 23.8 31.2 46.0 75.4 134.4
E0h 23.9 31.3 46.0 75.5 134.5
E1h 24.0 31.3 46.1 75.6 134.5
E2h 24.0 31.4 46.1 75.6 134.6
E3h 24.1 31.4 46.2 75.7 134.7
E4h 24.1 31.5 46.2 75.7 134.7
E5h 24.2 31.6 46.3 75.8 134.8
E6h 24.2 31.6 46.4 75.9 134.8
E7h 24.3 31.7 46.4 75.9 134.9
E8h 24.4 31.7 46.5 76.0 134.9
E9h 24.4 31.8 46.5 76.0 135.0
EAh 24.5 31.8 46.6 76.1 135.1
EBh 24.5 31.9 46.6 76.1 135.1
ECh 24.6 32.0 46.7 76.2 135.2
EDh 24.6 32.0 46.8 76.3 135.2
EEh 24.7 32.1 46.8 76.3 135.3
EFh 24.8 32.1 46.9 76.4 135.4
F0h 24.8 32.2 46.9 76.4 135.4
F1h 24.9 32.2 47.0 76.5 135.5
F2h 24.9 32.3 47.1 76.5 135.5
F3h 25.0 32.4 47.1 76.6 135.6
F4h 25.0 32.4 47.2 76.7 135.6
F5h 25.1 32.5 47.2 76.7 135.7
F6h 25.2 32.5 47.3 76.8 135.8
F7h 25.2 32.6 47.3 76.8 135.8
F8h 25.3 32.7 47.4 76.9 135.9
F9h 25.3 32.7 47.5 76.9 135.9
FAh 25.4 32.8 47.5 77.0 136.0
FBh 25.5 32.8 47.6 77.1 136.0
FCh 25.5 32.9 47.6 77.1 136.1
FDh 25.6 32.9 47.7 77.2 136.2
FEh 25.6 33.0 47.7 77.2 136.2
FFh 25.7 33.1 47.8 77.3 136.3
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ APPENDIX C ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ THE STRANGE CASE OF N = 0 ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
The data length code N = 0 is known as the 'sector length not
specified code'.
The Disk Base Table (Chapter II - section 7) has an entry (known as)
DTL that is supposed to hold the data length to be used when N = 0.
Such a parameter is also required in the command phase of some
LDC operations (e.g. read track).
At first glance, it does not seem too difficult to guess the meaning
of all this.
When it comes to experimenting, things turn out to be rather
surprising. To be more precise let me say that I find strange results
when experimenting. Maybe this is specific to my computer brand and /
or model.
Anyway, I think that the reader should experiment :
EXPERIMENT
(a) Format track 10 / head 0 using INT 13h / function 5. Call with
data length code 00
sectors / track 09
format gap 80
fill byte F6h
CHRN fields 10 0 R 0 (1 <= R <= 9).
The DTL value is irrelevant to format operations; if the data length
code is 0, the data length is always 128.
(b) Reformat (a part of) track 10 / head 0 using an ABORTED LDC
format operation. Call with
data length code 00
sectors / track 01
fill byte F5h
CHRN field 10 0 1 0 .
The operation MUST be ABORTED immediately after the data field CRC
word is written to the disk.
(c) Use a LDC read track operation (call with N = 0) to read
track 10 / head 0.
When I do this I find
80 bytes of F5h
followed by bytes of F6h
(whatever the value of DTL is) !
No CRC error is reported.
(d) Use INT 13h / function 2 to read track 10 / head 0 / sector 1.
When I do this I find
80 bytes of F5h
followed by 48 bytes of F6h (from sector 2 )
(whatever the value of DTL is) !
No CRC error is reported.
My conclusion is (maybe it only applies to my computer) that
with N = 0 :
When it comes to read/read track operations the disk controller
does not look at the value of DTL ; it uses invariably a value of its
own : 80 = 50h.
No CRC error is returned because although only 80 bytes are sent to
the data bus, the disk controller reads * internally * the complete
sector (128 bytes) and then performs a CRC check.
What about write operations called with N = 0 ?
From my own experience they seem to be quite unreliable.
Of course, my computer capabilities are not of general interest but it
seems that readers should be warned :
ÚÄÄÄÄ Warning ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ ³
³ DO NOT take it for granted that the disk controller ³
³ supports sector sizes with N = 0. ³
³ Format operations cause no problem but ³
³ read/write operations may show 'no error' although ³
³ they do not read/write WHERE they are expected. ³
³ ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
There are some 'safe' methods to try reading/writing sectors of data
length code N = 0 (they can also be used when the CHRN field shows a
value of N that does not match the 'real' data size) :
(i) to read : use a read track operation (call with an appropriate
read/write gap and N <> 0 ).
(ii) writing is more difficult; it often involves several format/
write operations some of which are to be aborted.
Comments
Post a Comment