Added files

This commit is contained in:
Broken Pipe
2026-01-04 13:54:33 +10:00
parent 435fe91271
commit 62b6d9772b
57 changed files with 9501 additions and 3 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+802
View File
@@ -0,0 +1,802 @@
MS-DOS 2.0 Device Drivers
INTRODUCTION
In the past, DOS-device driver (BIOS for those who are
familiar with CP/M) communication has been mediated with
registers and a fixed-address jump-table. This approach
has suffered heavily from the following two observations:
o The old jump-table ideas of the past are fixed in
scope and allow no extensibility.
o The past device driver interfaces have been written
without regard for the true power of the hardware.
When a multitasking system or interrupt driven
hardware is installed a new BIOS must be written
largely from scratch.
In MSDOS 2.0, the DOS-device driver interface has changed
from the old jump-table style to one in which the device
drivers are linked together in a list. This allows new
drivers for optional hardware to be installed (and even
written) in the field by other vendors or the user himself.
This flexibility is one of the major new features of MS-DOS
2.0.
Each driver in the chain defines two entry points; the
strategy routine and the interrupt routine. The 2.0 DOS
does not really make use of two entry points (it simply calls
strategy, then immediately calls interrupt). This dual entry
point scheme is designed to facilitate future multi-tasking
versions of MS-DOS. In multi-tasking environments I/O must
be asynchronous, to accomplish this the strategy routine
will be called to queue (internally) a request and return
quickly. It is then the responsibility of the interrupt
routine to perform the actual I/O at interrupt time by picking
requests off the internal queue (set up by the strategy
routine), and process them. When a request is complete,
it is flagged as "done" by the interrupt routine. The DOS
periodically scans the list of requests looking for ones
flagged as done, and "wakes up" the process waiting for the
completion of the request.
In order for requests to be queued as above it is no
longer sufficient to pass I/O information in registers, since
many requests may be pending at any one time. Therefore
the new device interface uses data "packets" to pass request
information. A device is called with a pointer to a packet,
this packet is linked into a global chain of all pending
I/O requests maintained by the DOS. The device then links
the packet into its own local chain of requests for this
particular device. The device interrupt routine picks
requests of the local chain for processing. The DOS scans
the global chain looking for completed requests. These
packets are composed of two pieces, a static piece which
has the same format for all requests (called the static
request header), which is followed by information specific
to the request. Thus packets have a variable size and format.
At this points it should be emphasized that MS-DOS 2.0
does not implement most of these features, as future versions
will. There is no global or local queue. Only one request
is pending at any one time, and the DOS waits for this current
request to be completed. For 2.0 it is sufficient for the
strategy routine to simply store the address of the packet
at a fixed location, and for the interrupt routine to then
process this packet by doing the request and returning.
Remember: the DOS just calls the strategy routine and then
immediately calls the interrupt routine, it is assumed that
the request is completed when the interrupt routine returns.
This additional functionality is defined at this time so
that people will be aware and thinking about the future.
FORMAT OF A DEVICE DRIVER
A device driver is simply a relocatable memory image
with all of the code in it to implement the device (like
a .COM file, but not ORGed at 100 Hex). In addition it has
a special header at the front of it which identifies it as
a device, defines the strategy and interrupt entry points,
and defines various attributes. It should also be noted
that there are two basic types of devices.
The first is character devices. These are devices which
are designed to do character I/O in a serial manner like
CON, AUX, and PRN. These devices are named (ie. CON, AUX,
CLOCK, etc.), and users may open channels (FCBs) to do I/O
to them.
The second class of devices is block devices. These
devices are the "disk drives" on the system, they can do
random I/O in pieces called blocks (usually the physical
sector size) and hence the name. These devices are not
"named" as the character devices are, and therefore cannot
be "opened" directly. Instead they are "mapped" via the
drive letters (A,B,C, etc.).
Block devices also have units. In other words a single
driver may be responsible for one or more disk drives. For
instance block device driver ALPHA (please note that we cannot
actually refer to block devices by a name!) may be
responsible for drives A,B,C and D, this simply means that
it has four units (0-3) defined and therefore takes up four
drive letters. Which units correspond to which drive letters
is determined by the position of the driver in the chain
of all drivers: if driver ALPHA is the first block driver
in the device chain, and it defines 4 units (0-3), then they
will be A,B,C and D. If BETA is the second block driver
and defines three units (0-2), then they will be E,F and
G and so on. MS-DOS 2.0 is not limited to 16 block device
units, as previous versions were. The theoretical limit
is 63 (2^6 - 1), but it should be noted that after 26 the
drive letters get a little strange (like ] \ and ^). NOTE:
Character devices cannot define multiple units (this because
they have only one name).
Here is what that special device header looks like:
+--------------------------------------+
| DWORD Pointer to next device |
| (Must be set to -1) |
+--------------------------------------+
| WORD Attributes |
| Bit 15 = 1 if char device 0 if blk |
| if bit 15 is 1 |
| Bit 0 = 1 if Current sti device |
| Bit 1 = 1 if Current sto output |
| Bit 2 = 1 if Current NUL device |
| Bit 3 = 1 if Current CLOCK dev |
| Bit 4 = 1 if SPECIAL |
| Bit 14 is the IOCTL bit (see below) |
| Bit 13 is the NON IBM FORMAT bit |
+--------------------------------------+
| WORD Pointer to Device strategy |
| entry point |
+--------------------------------------+
| WORD Pointer to Device interrupt |
| entry point |
+--------------------------------------+
| 8-BYTE character device name field |
| Character devices set a device name |
| For block devices the first byte is |
| The number of units |
+--------------------------------------+
Note that the device entry points are words. They must
be offsets from the same segment number used to point to
this table. Ie. if XXX.YYY points to the start of this
table, then XXX.strategy and XXX.interrupt are the entry
points.
A word about the Attribute field. This field is used
most importantly to tell the system whether this device is
a block or character device (bit 15). Most of other bits
are used to give selected character devices certain special
treatment (NOTE: these bits mean nothing on a block device).
Let's say a user has a new device driver which he wants to
be the standard input and output. Besides just installing
the driver he needs to tell SYSINIT (and the DOS) that he
wishes his new driver to override the current sti and sto
(the "CON" device). This is accomplished by setting the
attributes to the desired characteristics, so he would set
Bits 0 and 1 to 1 (note that they are separate!!). Similarly
a new CLOCK device could be installed by setting that
attribute, see the section at the end on the CLOCK device.
NOTE: that although there is a NUL device attribute, the
NUL device cannot be re-assigned. This attribute exists
for the DOS so that it can tell if the NUL device is being
used.
The NON IBM FORMAT bit applies only to block devices
and effects the operation of the get BPB device call (see
below).
The other bit of interest is the IOCTL bit which has
meaning on character or block devices. This bit tells the
DOS whether this device can handle control strings (via the
IOCTL system call).
If a driver cannot process control strings, it should
initially set this bit to 0. This tells the DOS to return
an error if an attempt is made (via IOCTL system call) to
send or receive control strings to this device. A device
which can process control strings should initialize it to
1. For drivers of this type, the DOS will make calls to
the IOCTL INPUT and OUTPUT device functions to send and
receive IOCTL strings (see IOCTL in the SYSTEM-CALLS
document).
The IOCTL functions allow data to be sent and received
by the device itself for its own use (to set baud rate, stop
bits, form length etc., etc.), instead of passing data over
the device channel as a normal read or write does. The
interpretation of the passed information is up to the device,
but it MUST NOT simply be treated as a normal I/O.
The SPECIAL bit applies only to character drivers and
more particularly to CON drivers. The new 2.0 interface
is a much more general and consistent interface than the
old 1.25 DOS interface. It allows for a number of additional
features of 2.0. It is also slower than 1.25 if old style
"single byte" system calls are made. To make most efficient
use of the interface all applications should block their
I/O as much as possible. This means make one XENIX style
system call to output X bytes rather than X system calls
to output one byte each. Also putting a device channel in
RAW mode (see IOCTL) provides a means of putting out
characters even FASTER than 1.25. To help alleviate the
CON output speed problem for older programs which use the
1 - 12 system calls to output large amounts of data the
SPECIAL bit has been implemented. If this bit is 1 it means
the device is the CON output device, and has implemented
an interrupt 29 Hex handler, where the 29 Hex handler is
defined as follows:
Interrupt 29h handlers
Input:
Character in AL
Function:
output the character in al to the user
screen.
Output:
None
Registers:
all registers except bx must be preserved.
No registers except for al have a known or
consistent value.
If a character device implements the SPECIAL bit, it
is the responsibility of the driver to install an address
at the correct location in the interrupt table for interrupt
29 Hex as part of its INIT code. IMPLICATION: There can
be only one device driver with the SPECIAL bit set in the
system. There is no check to insure this state.
WARNING: THIS FEATURE WILL NOT BE SUPPORTED IN FUTURE VERSIONS
OF THE OPERATING SYSTEM. IMPLICATION: Any application
(not device driver) which uses INT 29H directly will
not work on future versions, YOU HAVE BEEN WARNED.
In order to "make" a device driver that SYSINIT can
install, a memory image or .EXE (non-IBM only) format file
must be created with the above header at the start. The
link field should be initialized to -1 (SYSINIT fills it
in). The attribute field and entry points must be set
correctly, and if the device is a character device, the name
field must be filled in with the name (if a block device
SYSINIT will fill in the correct unit count). This name
can be any 8 character "legal" file name. In fact SYSINIT
always installs character devices at the start of the device
list, so if you want to install a new CON device all you
have to do is name it "CON". The new one is ahead of the
old one in the list and thus preempts the old one as the
search for devices stops on the first match. Be sure to
set the sti and sto bits on a new CON device!
NOTE: Since SYSINIT may install the driver anywhere, you
must be very careful about FAR memory references. You
should NOT expect that your driver will go in the same
place every time (The default BIOS drivers are exempted
from this of course).
INSTALLATION OF DEVICE DRIVERS
Unlike past versions MS-DOS 2.0 allows new device drivers
to be installed dynamically at boot time. This is
accomplished by the new SYSINIT module supplied by Microsoft,
which reads and processes the CONFIG.SYS file. This module
is linked together with the OEM default BIOS in a similar
manner to the way FORMAT is built.
One of the functions defined for each device is INIT.
This routine is called once when the device is installed,
and never again. The only thing returned by the init routine
is a location (DS:DX) which is a pointer to the first free
byte of memory after the device driver, (like a terminate
and stay resident). This pointer method can be used to "throw
away" initialization code that is only needed once, saving
on space.
Block devices are installed the same way and also return
a first free byte pointer as above, additional information
is also returned:
o The number of units is returned, this determines
logical device names. If the current maximum logical
device letter is F at the time of the install call,
and the init routine returns 4 as the number of units,
then they will have logical names G, H, I and J.
This mapping is determined by by the position of
the driver in the device list and the number of units
on the device (stored in the first byte of the device
name field).
o A pointer to a BPB (Bios Parameter Block) pointer
array is also returned. This will be similar to
the INIT table used in previous versions, but will
have more information in it. There is one table
for each unit defined. These blocks will be used
to build a DPB (Drive Parameter Block) for each of
the units. The pointer passed to the DOS from the
driver points to an array of n word pointers to BPBs
where n is the number of units defined. In this
way if all units are the same, all of the pointers
can point to the same BPB, saving space. NOTE: this
array must be protected (below the free pointer set
by the return) since the DPB will be built starting
at the byte pointed to by the free pointer. The
sector size defined must be less than or equal to
the maximum sector size defined at default BIOS init
time. If it isn't the install will fail. One new
piece of DPB info set from this table will be a "media
descriptor byte". This byte means nothing to the
DOS, but is passed to devices so that they know what
form of a DPB the DOS is currently using for a
particular Drive-Unit.
Block devices may take several approaches; they may be
dumb or smart. A dumb device would define a unit (and
therefore a DPB) for each possible media drive combination.
Unit 0 = drive 0 single side, unit 1 = drive 0 double side,
etc. For this approach media descriptor bytes would mean
nothing. A smart device would allow multiple media per unit,
in this case the BPB table returned at init must define space
large enough to accommodate the largest possible media
supported. Smart drivers will use the "media byte" to pass
around info about what media is currently in a unit. NOTE:
If the DPB is a "hybrid" made to get the right sizes, it
should give an invalid "media byte" back to the DOS.
The BOOT (default BIOS) drivers are installed pretty
much as above. The preset device list is scanned. If block
drivers are encountered they are installed as above (with
the exception that the break is not moved since the drivers
are already resident in the BIOS). Note that the logical
drive letters are assigned in list order, thus the driver
which is to have logical A must be the first unit of the
first block device in the list. The order of character
devices is also important. There must be at least 4 character
devices defined at boot which must be the first four devices
(of either type), the first will become standard input,
standard output, and standard error output. The second will
become standard auxiliary input and output, the third will
become standard list output, and the forth will become the
date/time (CLOCK) device. Thus the BIOS device list must
look like this:
->CON->AUX->PRN->CLOCK->any other block or character devices
THE DRIVER
A device driver will define the following functions:
Command Function
Code
0 INIT
1 MEDIA CHECK (Block only, NOP for character)
2 BUILD BPB " " " " "
3 IOCTL INPUT (Only called if device has IOCTL)
4 INPUT (read)
5 NON-DESTRUCTIVE INPUT NO WAIT (Char devs only)
6 INPUT STATUS " " "
7 INPUT FLUSH " " "
8 OUTPUT (write)
9 OUTPUT (Write) with verify
10 OUTPUT STATUS " " "
11 OUTPUT FLUSH " " "
12 IOCTL OUTPUT (Only called if device has IOCTL)
As mentioned before, the first entry point is the strategy
routine which is called with a pointer to a data block. This
call does not perform the request, all it does is queue it
(save the data block pointer). The second interrupt entry
point is called immediately after the strategy call. The
"interrupt" routine is called with no parameters, its primary
function is to perform the operation based on the queued
data block and set up any returns.
The "BUILD BPB" and "MEDIA CHECK" are the interesting
new ones, these are explained by examining the sequence of
events in the DOS which occurs when a drive access call (other
than read or write) is made:
I. Turn drive letter into DPB pointer by looking
for DPB with correct driver-unit number.
II. Call device driver and request media check for
Drive-Unit. DOS passes its current Media
descriptor byte (from DPB). Call returns:
Media Not Changed
Media Changed
Not Sure
Error
Error - If an error occurs the error code should
be set accordingly.
Media Not changed - Current DPB and media byte
are OK, done.
Media Changed - Current DPB and media are wrong,
invalidate any buffers for this unit, and
goto III.
Not Sure - If there are dirty buffers for this
unit, assume DPB and media byte are OK and
done. If nothing dirty, assume media changed,
invalidate any buffers for unit, and goto
III.
NOTE: If a hybrid DPB was built at init and
an invalid Media byte was set, the driver
should return media changed when this invalid
media byte is encountered.
III. Call device driver to build BPB with media byte
and buffer.
What the driver must do at step III is determine the
correct media that is currently in the unit, and return a
pointer to a BPB table (same as for the install call). This
table will be used as at init to build a correct DPB for
the unit If the determined media descriptor byte in the table
turns out to be the same as the one passed in, then the DOS
will not build a new table, but rather just use the old one.
Therefore in this case the driver doesn't have to correctly
fill in the other entries if desired.
The build BPB call also gets a pointer to a one sector
buffer. What this buffer contains is determined by the NON
IBM FORMAT bit in the attribute field. If the bit is zero
(device is IBM format compatible) then the buffer contains
the first sector of the first FAT, in particular the FAT
ID byte is the first byte of this buffer. NOTE: It must
be true that the BPB is the same, as far as location of the
FAT is concerned, for all possible media. This is because
this first FAT sector must be read BEFORE the actual BPB
is returned. If the NON IBM FORMAT bit is set then the
pointer points to one sector of scratch space which may be
used for anything.
CALL FORMAT
When the DOS calls a device driver to perform a finction,
it passes a structure (Drive Request Structure) in ES:BX
to perform operations and does a long call to the driver's
strategy entry point. This structure is a fixed length header
(Static Request Header) followed by data pertinent to the
operation being performed. NOTE: It is the drivers
responsibility to preserve machine state.
STATIC REQUEST HEADER ->
+-----------------------------+
| BYTE length of record |
| Length in bytes of this |
| Drive Request Structure |
+-----------------------------+
| BYTE unit code |
| The subunit the operation |
| is for (minor device) |
| (no meaning on character |
| devices) |
+-----------------------------+
| BYTE command code |
+-----------------------------+
| WORD Status |
+-----------------------------+
| 8 bytes reserved here for |
| two DWORD links. One will |
| be a link for the DOS queue |
| The other for the device |
| queue |
+-----------------------------+
STATUS WORD
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+
| E | | B | D | |
| R | RESERVED | U | O | ERROR CODE (bit 15 on)|
| R | | I | N | |
+---+---+--+--+--+--+---+---+--+--+--+--+--+--+--+--+
The status word is zero on entry and is set by the driver
interrupt routine on return.
Bit 8 is the done bit, it means the operation is complete.
For the moment the Driver just sets it to one when it exits,
in the future this will be set by the interrupt routine to
tell the DOS the operation is complete.
Bit 15 is the error bit, if it is set then the low 8
bits indicate the error:
0 Write Protect violation
(NEW) 1 Unknown Unit
2 Drive not ready
(NEW) 3 Unknown command
4 CRC error
(NEW) 5 Bad Drive Request Structure length
6 Seek error
(NEW) 7 Unknown media
8 Sector not found
(NEW) 9 Printer out of paper
A Write Fault
(NEW) B Read Fault
C General Failure
Bit 9 is the busy bit which is set only by status calls (see
STATUS CALL below).
Here is the data block format for each function:
READ or WRITE - ES:BX (Including IOCTL) ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media descriptor from DPB |
+------------------------------------+
| DWORD transfer address |
+------------------------------------+
| WORD byte/sector Count |
---+------------------------------------+---
| WORD starting sector number |
| (ignored on Char Devs) |
+------------------------------------+
In addition to setting the status word, the driver must
set the Sector count to the actual number of sectors (or
bytes) transferred. NOTE: No error check is performed on
an IOCTL I/O call, driver MUST correctly set the return sector
(byte) count to the actual number of bytes transferred,
however.
NOTE: THE FOLLOWING APPLIES TO BLOCK DEVICE DRIVERS.
Under certain circumstances the BIOS may be asked to
do a write operation of 64K bytes which seems to be a "wrap
around" of the transfer address in the BIOS I/O packet. This
arises due to an optimization added to the write code in
MS-DOS. It will only manifest on user WRITEs which are within
a sector size of 64K bytes on files which are "growing" past
the current EOF. IT IS ALLOWABLE FOR THE BIOS TO IGNORE
THE BALANCE OF THE WRITE WHICH "WRAPS AROUND" IF IT SO
CHOOSES. For instance a WRITE of 10000H bytes worth of
sectors with a transfer address of XXX:1 could ignore the
last two bytes (remember that a user program can never request
an I/O of more than FFFFH bytes and cannot wrap around (even
to 0) in his transfer segment, so in this case the last two
bytes can be ignored).
NON DESRUCTIVE READ NO WAIT - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE read from device |
+------------------------------------+
This call is analogous to the console input status call
on MS-DOS 1.25. If the character device returns Busy bit
= 0 (characters in buffer), then the next character that
would be read is returned. This character is NOT removed
from the input buffer (hence the term Non Destructive Read).
In essence this call allows the DOS to look ahead one input
character.
MEDIA CHECK - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media Descriptor from DPB |
+------------------------------------+
| BYTE returned |
+------------------------------------+
In addition to setting status word, driver must set the
return byte.
Return Byte :
-1 Media has been changed
0 Don't know if media has been changed
1 Media has not been changed
If the driver can return -1 or 1 (by having a door-lock
or other interlock mechanism) the performance of MSDOS 2.0
is enhanced as the DOS need not reread the FAT for each
directory access.
BUILD BPB - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE Media Descriptor from DPB |
+------------------------------------+
| DWORD Transfer Address |
| (points to one sectors worth of |
| scratch space or first sector |
| of FAT depending on the value |
| of the NON IBM FORMAT bit) |
+------------------------------------+
| DWORD Pointer to BPB |
+------------------------------------+
If the NON IBM FORMAT bit of the device is set, then
the DWORD Transfer Address points to a one sector buffer
which can be used for any purpose. If the NON IBM FORMAT
bit is 0, then this buffer contains the first sector of the
FAT; in this case the driver must not alter this buffer (this
mode is useful if all that is desired is to read the FAT
ID byte).
If IBM compatible format is used (NON IBM FORMAT BIT
= 0), then it must be true that the first sector of the first
FAT is located at the same sector on all possible media.
This is because the FAT sector will be read BEFORE the media
is actually determined.
In addition to setting status word, driver must set the
Pointer to the BPB on return.
In order to allow for many different OEMs to read each
other's disks, the following standard is suggested: The
information relating to the BPB for a particular piece of
media is kept in the boot sector for the media. In
particular, the format of the boot sector is:
+------------------------------------+
| 3 BYTE near JUMP to boot code |
+------------------------------------+
| 8 BYTES OEM name and version |
---+------------------------------------+---
B | WORD bytes per sector |
P +------------------------------------+
B | BYTE sectors per allocation unit |
+------------------------------------+
| | WORD reserved sectors |
V +------------------------------------+
| BYTE number of FATs |
+------------------------------------+
| WORD number of root dir entries |
+------------------------------------+
| WORD number of sectors in logical |
^ | image |
| +------------------------------------+
B | BYTE media descriptor |
P +------------------------------------+
B | WORD number of FAT sectors |
---+------------------------------------+---
| WORD sectors per track |
+------------------------------------+
| WORD number of heads |
+------------------------------------+
| WORD number of hidden sectors |
+------------------------------------+
The three words at the end are optional, the DOS doesn't
care about them (since they are not part of the BPB). They
are intended to help the BIOS understand the media. Sectors
per track may be redundant (could be figured out from total
size of the disk). Number of heads is useful for supporting
different multi-head drives which have the same storage
capacity, but a different number of surfaces. Number of
hidden sectors is useful for supporting drive partitioning
schemes.
Currently, the media descriptor byte has been defined
for a small range of media:
5 1/4" diskettes:
Flag bits:
01h - on -> 2 double sided
All other bits must be on.
8" disks:
FEh - IBM 3740 format, singled-sided, single-density,
128 bytes per sector, soft sectored, 4 sectors
per allocation unit, 1 reserved sector, 2 FATs,
68 directory entries, 77*26 sectors
FDh - 8" IBM 3740 format, singled-sided,
single-density, 128 bytes per sector, soft
sectored, 4 sectors per allocation unit, 4
reserved sectors, 2 FATs, 68 directory entries,
77*26 sectors
FEh - 8" Double-sided, double-density, 1024 bytes
per sector, soft sectored, 1 sector per allocation
unit, 1 reserved sector, 2 FATs, 192 directory
entries, 77*8*2 sectors
STATUS Calls - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
All driver must do is set status word accordingly and
set the busy bit as follows:
o For output on character devices: If it is 1 on
return, a write request (if made) would wait for
completion of a current request. If it is 0, there
is no current request and a write request (if made)
would start immediately.
o For input on character devices with a buffer a return
of 1 means, a read request (if made) would go to
the physical device. If it is 0 on return, then
there are characters in the devices buffer and a
read would return quickly, it also indicates that
the user has typed something. The DOS assumes all
character devices have an input type ahead buffer.
Devices which don't have them should always return
busy = 0 so that the DOS won't hang waiting for
something to get into a buffer which doesn't exist.
FLUSH Calls - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
This call tells the driver to flush (terminate) all
pending requests that it has knowledge of. Its primary use
is to flush the input queue on character devices.
INIT - ES:BX ->
+------------------------------------+
| 13-BYTE Static Request Header |
+------------------------------------+
| BYTE # of units |
+------------------------------------+
| DWORD Break Address |
---+------------------------------------+---
| DWORD Pointer to BPB array |
| (not set by Character devices) |
+------------------------------------+
The number of units, break address, and BPB pointer are
set by the driver.
FORMAT OF BPB (Bios Parameter Block) -
+------------------------------------+
| WORD Sector size in Bytes |
| Must be at least 32 |
+------------------------------------+
| BYTE Sectors/Allocation unit |
| Must be a power of 2 |
+------------------------------------+
| WORD Number of reserved sectors |
| May be zero |
+------------------------------------+
| BYTE Number of FATS |
+------------------------------------+
| WORD Number of directory entries |
+------------------------------------+
| WORD Total number of sectors |
+------------------------------------+
| BYTE Media descriptor |
+------------------------------------+
| WORD Number of sectors occupied by |
| FAT |
+------------------------------------+
THE CLOCK DEVICE
One of the most popular add on boards seems to be "Real
Time CLOCK Boards". To allow these boards to be integrated
into the system for TIME and DATE, there is a special device
(determined by the attribute word) which is the CLOCK device.
In all respects this device defines and performs functions
like any other character device (most functions will be "set
done bit, reset error bit, return). When a read or write
to this device occurs, exactly 6 bytes are transferred. This
I/O can be thought of as transferring 3 words which correspond
exactly to the values of AX, CX and DX which were used in
the old 1.25 DOS date and time routines. Thus the first
two bytes are a word which is the count of days since 1-1-80.
The third byte is minutes, the fourth hours, the fifth
hundredths of seconds, and the sixth seconds. Reading the
CLOCK device gets the date and time, writing to it sets the
date and time.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+1657
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+813
View File
@@ -0,0 +1,813 @@
MS-DOS 2.0
Utility Extensions
The following notation is used below:
[item] item is optional.
item* item is repeated 0 or more times.
item+ item is repeated 1 or more times.
{item1 | item2}
item1 is present or item 2 is present but
not both.
<object> indicates a syntactic variable.
COMMAND invokation
COMMAND [[<drive>:]<path>] [<cttydev>] [-D] [-P] [-C <string>]
-P If present COMMAND will be permanent, otherwise
this is a transient command.
-D If present COMMAND will not prompt for DATE and
TIME when it comes up.
d: Specifies device where command will look for
COMMAND.COM current default drive if absent.
<Path> Specifies a directory on device d: root
directory if absent.
<cttydev> Name of the CTTY device. /DEV/CON if absent
and command is permanent. The /DEV/ may be left
off if AVAILDEV is TRUE (see sysinit doc).
-C <string> If present -C must be the last switch.
This causes COMMAND to try to execute the string
as if the user had typed it at the standard input.
COMMAND executes this single command string and
then exits. If the -P switch is present it is
ignored (can't have a single command, permanent
COMMAND). NOTE: ALL of the text on the command
line after the -C is just passed on. It is not
processed for more arguments, this is why -C must
be last.
COMMAND extensions
IF <condition> <command>
where <condition> is one of the following:
ERRORLEVEL <number>
true if and only if the previous program EXECed by
COMMAND had an exit code of <number> or higher.
<string1> == <string2>
true if and only if <string1> and <string2> are
identical after parameter substitution. Strings
may not have embedded delimiters.
EXIST <filename>
true if and only if <filename> exists.
NOT <condition>
true if and only if <condition> is false.
The IF statement allows conditional execution of commands.
When the <condition> is true, then the <command> is
executed otherwise, the <command> is skipped.
Examples:
IF not exist /tmp/foo ECHO Can't find file /tmp/foo
IF $1x == x ECHO Need at least one parameter
IF NOT ERRORLEVEL 3 LINK $1,,;
FOR %%<c> IN <set> DO <command>
<c> can be any character but 0,1,2,3,..,9 (so there is no
confusion with the %0 - %9 batch parameters).
<set> is ( <item>* )
The %%<c> variable is sequentially set to each member of
<set> and then <command> is evaluated. If a member of
<set> is an expression involving * and/or ?, then the
variable is set to each matching pattern from disk. In
this case only one such <item> may be in the set, any
<item>s after the first are ignored.
Example:
FOR %%f IN ( *.ASM ) DO MASM %%f;
for %%f in (FOO BAR BLECH) do REM %%f to you
NOTE: The '%%' is needed so that after Batch parameter
(%0 - %9) processing is done, there is one '%' left.
If only '%f' were there, the batch parameter processor
would see the '%' then look at 'f', decide that '%f'
was an error (bad parameter reference) and throw out
the '%f' so that FOR would never see it. If the FOR
is NOT in a batch file, then only ONE '%' should be
used.
SHIFT
Currently, command files are limited to handling 10
parameters: %0 through %9. To allow access to more than
these, the command SHIFT will perform a 'pop' of the
command line parameters:
if %0 = "foo"
%1 = "bar"
%2 = "blech"
%3...%9 are empty
then a SHIFT will result in the following:
%0 = "bar"
%1 = "blech"
%2...%9 are empty
If there are more than 10 parameters given on a command
line, then the those that appear after the 10th (%9) will
be shifted one at a time into %9 by successive shifts.
:<label>
This is essentially a no-op. It defines a label in the
batch file for a subsequent GOTO. It may also be used to
put comment lines in batch files since all lines that
start with ':' are ignored.
GOTO <label>
Causes commands to be taken from the batch file beginning
with the line after the <label> definition. If no label
has been defined, the current batch file will terminate.
Example:
:foo
REM looping...
GOTO foo
will produce a infinite sequence of messages:
'REM looping...'
NOTE: Labels are case insensitive, :FOO == :foo == :Foo
ECHO [{ON | OFF | <message>}]
Normally, commands in a BATCH file are echoed onto the
standard output as they are seen by COMMAND. ECHO OFF
turns off this feature. ECHO ON turns echoing back on.
If ON or OFF is not specified and there is text following
the command, that text (a message) is echoed to standard
output. If there are no arguments at all, the current
setting of echo (on or off) is echoed to the standard
output in the form:
ECHO is xxx
Where xxx is "on" or "off".
Redirection of standard input/standard output.
Programs that read from the keyboard and write to the
screen are said to be doing I/O to the standard input and
standard output. Using any of the following will result
in I/O to these standard devices:
Writing to default handles 1 / read from default
handle 0.
Doing byte I/O using system calls 1, 2, 6-12.
These standard devices may be redirected to/from files by
the following in command line arguments:
> <filename>
causes <filename> to be created (or truncated to
zero length) and then assigns standard output to
that file. All output from the command will be
placed in the file.
< <filename>
causes standard input to be assigned to
<filename>. All input to the command will come
from this file. If end-of-file is reached, then
system calls 1, 2, 6-12 will return ^Z , while
reading from handle 0 will return zero characters.
>> <filename>
causes <filename> to be opened (created if
necessary) and positions the write pointer at the
end of the file so that all output will be
appended to the file.
Note that the above will not appear in the command line
that the program being invoked sees.
Examples:
DIR *.ASM > FOO.LST
Sends the output of the dir command to the file
FOO.LST.
FOR %0 IN (*.ASM) DO MASM %0; >>ERRS.LST
Sends all error output from assembling every .ASM file
into the file ERRS.LST.
Piping of standard I/O
It is often useful for the output of one program to be
sent as input to another program. A typical case is a
program that produces columnar output that must later be
sorted.
The pipe feature allows this to occur naturally is the
programs do all of their I/O to the standard devices.
For example, if we had a program SORT that read all of
it's standard input, sorted it and then wrote it to the
standard output, then we could get a sorted directory
listing as follows:
DIR | SORT
The | would cause all standard output generated by the
left-hand command to be sent to the standard input of the
right-hand command.
If we wanted the sorted directory to be sent to a file, we
type:
DIR | SORT >FILE
and away it goes.
The piping feature is implemented as sequential execution
of the procedures with redirection to and from temporary
files. In the example above, the following would be an
exact equivalent:
DIR >/tmp/std1
SORT </tmp/std1 >FILE
The pipe is not a real pipe but rather a quasi-pipe
that uses temporary files to hold the input and output as
it sequentially executes the elements of the pipe. These
files are created in the current directory, of the current
drive and have the form %PIPEx%.$$$, where x will be 1 or
2. This means that any program that runs in the pipe must
be sure to restore the current directory and drive if it
has changed them, otherwise the pipe files will be lost.
VER
Prints DOS version number.
VOL [<drive>:]
Prints the volume ID of the disk in drive d:. No d: does
default drive.
CHDIR [{<drive>: | <path>}]
Change directory, or print current. directory.If no
argument is given, the current directory on the default
drive is printed. If d: alone is given, the durrent
directory of drive d is printed. Otherwise the current
directory is set to path.
NOTE:"CD" is accepted as an abbreviation.
MKDIR <path> - Make a directory.
"MD" is accepted as an abbreviation.
RMDIR <path> - Remove a directory.
"RD" is accepted as an abbreviation.
The directory must be empty except for
'.' and '..'.
<path> - A standard XENIX style path with the optional
addition of a drive spec:
A:/FOO/BAR Full path
/FOO/BAR Full path, current drive
FOO/BAR Current dir relative
A:FOO/BAR " " "
VERIFY [{ON | OFF}]
Select/deselect verify after write mode. This supliments
the V switch to the COPY command. Once turned ON, it
stays on until some program changes it (via the set verify
system call) or the VERIFY OFF command is given. If no
argument is given, the current setting of VERIFY is
printed to the standard output in the form:
VERIFY is xxx
Where xxx is "on" or "off".
PATH [<path>{;<path>}*]
Set command search paths. This allows users to set
directories that should be searched for external commands
after a search of the current directory is made. The
default value is /bin. In addition there are two special
cases: PATH all by itself with no arguments will print
the current path. Path with the single argument ';' (ie.
"PATH ;") will set the NUL path (no directories other than
the current one searched). If no argument is given, the
current value of PATH is printed to the standard output in
the form:
PATH=text of path
or
No path
NOTE: On IBM systems, the default value of path is No
path.
EXIT
For COMMANDs run without the P switch, this causes COMMAND
to return. For a normal COMMAND it causes a return to
itself.
BREAK [{ON | OFF}]
Like in CONFIG.SYS, "BREAK ON" turns on the Control C
check in the DOS function dispatcher. "BREAK OFF" turns
it off. If no argument is given the setting of BREAK is
printed to the standard output in the form:
BREAK is xxx
Where xxx is "on" or "off".
PROMPT [<prompt-text>]
Set the system prompt. MS-DOS prompts are now user
settable, all of the text on the command line is taken to
be the new prompt. If no text is present the prompt is
set to the default prompt. There are meta strings for
various special prompts. These are of the form '$c' where
c is one of the following:
$ - The '$' character.
t - The time.
d - The date.
p - The current directory of the default drive.
v - The version number.
n - The default drive.
g - The '>' character.
l - The '<' character.
b - The '|' character.
s - The ' ' character.
e - The ESC character.
_ - A CR LF sequence.
EXAMPLE:
PROMPT $n:
Would set the normal MS-DOS prompt.
PROMPT $n>
Would det the normal PC-DOS prompt.
PROMPT Time = $t$_Date = $d
Would set a two line prompt which printed
Time = (current time)
Date = (current date)
NOTE: For '$c' sequences, lower case = upper case, and
any character not on the above list is mapped to
nothing.
SET (ENVNAME)=(ENVTEXT)
Set environment strings. This command inserts strings in
COMMAND's environment. For instance:
SET PROMPT=$n>
Duplicates the function of the PROMPT command.
SET PATH=p1;p2
Duplicates the function of the PATH command.
SET foo=bar
Puts the string FOO=bar into the environment (note the
case mapping of (ENVNAME)).
NOTE: Environments are very flexible, almost anything can
be put into the environment with the SET command; the
only requirement is that a single '=' be present in
the string.
CLS
Clear screen, causes the ANSI escape sequence ESC[2J to be
sent to standard output.
CTTY /DEV/dev - Change console TTY. For instance:
CTTY /DEV/AUX
Would move all command I/O to the AUX port.
CTTY /DEV/CON
Would move it back to the normal device. The
/dev/ prefix may be left off if AVAILDEV is
TRUE (see configuration-file doc).
COMMAND internal commands take path arguments.
DIR <path>
COPY <path> <path>
DEL(ERASE) <path>
If the path is a dir, all files in that dir
are deleted.
NOTE: The "Are you sure (Y/N)" prompt for DEL and
ERASE now uses buffered standard input, so
users must type a return after their answer.
This gives them the chance to correct if they
type 'y' by mistake.
TYPE <path> (must specify a file)
FILCOM - compare two files
The FILCOM program compares two files and produces a log
of differences between them. The comparison may be made
in two fashions; either on a line-by-line basis, or on a
byte-by-byte basis.
The line-by-line compare will isolate blocks of lines that
are different between the two files and will print the
blocks from each file. The line-by-line compare is the
default when neither of the two files being compared has
the extension .EXE, .COM, or .OBJ.
The byte-by-byte compare will display exactly which bytes
are different between the two files. If either file being
compared has extension .EXE, .COM, or .OBJ then the files
will be compared in byte-by-byte mode.
RECOVER - recover files from a trashed disk.
If a sector on a disk goes bad, you can recover either the
file that contained that sector (without the sector) or
the entire disk (if the bad sector was in the directory).
To recover a particular file:
RECOVER <file-to-recover>
This will cause the file to be read sector by sector and
to be have the bad sector skipped. Note that this implies
that the allocation unit containing the bad sector will be
read as much as possible. When such a bad sector is
found, its containing allocation unit is marked as bad,
thus preventing future allocations of that bad sector.
To recover a particular disk:
RECOVER <drive-letter>:
This will cause a scan to be made of the drive's FAT for
chains of allocation units (files). A new root directory
is then written that has entries of the form FILEnnnn.
Each FILEnnnn will point to the head of one of the
allocation unit chains.
If there are more chains than directory entries in the
root, RECOVER prints a message and leaves the un-RECOVERED
chains in the FAT so that RECOVER can be run again once
some room has been made in the ROOT.
DEBUG ON MS-DOS 2.0
When 2.0 DEBUG is invoked it sets up a program header
atoffset 0 in its program work area. On previous versions it
was OK to overwrite this header with impunity: this is true
of the default header set up if no <filespec> is given to
DEBUG. If DEBUGging a .COM or .EXE file, however, you must be
careful not to tamper with the header of the program below
address 5CH, to do this will probably result in a crash. It
is also important that an attempt is not made to "restart" a
program once the "program terminated normally" message is
given. The program must be reloaded with the N and L commands
in order for it to run properly.
NEW FEATURES
The A (Assemble) Command
FORMAT: A [<address>]
PURPOSE: To assemble 8086/8087/8088 mnemonics directly into
memory.
o If a syntax error is encountered, DEBUG responds with
^ Error
and redisplays the current assembly address.
o All numeric values are hexadecimal and may be entered
as 1-4 characters.
o Prefix mnemonics must be entered in front of the opcode
to which they refer. They may also be entered on a
separate line.
o The segment override mnemonics are CS:, DS:, ES:, and
SS:
o String manipulation mnemonics must explictly state the
string size. For example, the MOVSW must be used to
move word strings and MOVSB must be used to move byte
strings.
o The mnemonic for the far return is RETF.
o The assembler will automatically assemble short, near
or far jumps and calls depending on byte displacement
to the destination address. These may be overridden
with the NEAR or FAR prefix. For example:
0100:0500 JMP 502 ; a 2 byte short jump
0100:0502 JMP NEAR 505 ; a 3 byte near jump
0100:0505 JMP FAR 50A ; a 5 byte far jump
The NEAR prefix may be abbreviated to NE but the FAR
prefix cannot be abbreviated.
o DEBUG cannot tell whether some operands refer to a word
memory location or a byte memroy location. In this case
the data type must be explicity stated with the prefix
"WORD PTR" or "BYTE PTR". DEBUG will also except the
abbreviations "WO" and "BY". For example:
NEG BYTE PTR [128]
DEC WO [SI]
o DEBUG also cannot tell whether an operand refers to a
memory location or to an immediate operand. DEBUG uses
the common convention that operands enclosed in square
brackets refer to memory. For example:
MOV AX,21 ;Load AX with 21H
MOV AX,[21] ;Load AX with the contents
;of memory location 21H
o Two popular pseudo-instructions have also been included.
The DB opcode will assemble byte values directly into
memory. The DW opcode will assemble word values directly
into memory. For example:
DB 1,2,3,4,"THIS IS AN EXAMPLE"
DB 'THIS IS A QUOTE: "'
DB "THIS IS A QUOTE: '"
DW 1000,2000,3000,"BACH"
o All forms of the register indirect commands are supported.
For example:
ADD BX,34[BP+2].[SI-1]
POP [BP+DI]
PUSH [SI]
o All opcode synonyms are supported, For example:
LOOPZ 100
LOOPE 100
JA 200
JNBE 200
o For 8087 opcodes the WAIT or FWAIT prefix must be
explictly specified. For example:
FWAIT FADD ST,ST(3) ; This lines will assemble
; a FWAIT prefix
FLD TBYTE PTR [BX] ; This line will not
FORMAT enhancements
FORMAT will now install volume id's during the format
process. DIR and CHKDSK will display these volume id's.
User programs can read the volume id on a particular drive
by doing a 'search next' with the volume id attribute. It
is impossible, using normal DOS calls, to delete a volume
id or to create another one. The only way to create a
volume id is to reformat the disk.
NOTE: On IBM systems the V switch must be given to FORMAT
to have it do Volume IDs.
CHKDSK FOR MS-DOS 2.0
MS-DOS 2.0 has a tree structured directory scheme which
did not exist on previous versions of MS-DOS. As a result
CHKDSK is a much more complex program than in previous
versions since it must perform a tree traversal to find all of
the files on a given disk. It employes a depth first
traversal in order to accomplish this.
Previous versions of CHKDSK automatically "fixed"
disks (regardless of whether it was appropriate). CHKDSK 2.00
run normally will not alter the disk in any way, it simply
reports on any inconsistencies found. To actually "fix" a
disk CHKDSK must be run with the F switch (Fix). This allows
you to perhaps take some alternate (to CHKDSK repairs) action
before letting CHKDSK loose on your disk.
CHKDSK 2.00 will report on non-contiguous allocation units
(extents) for specified files. This is handy for gaging how
"fragmented" a disk volume has become. This is done by simply
giving a filespec:
CHKDSK B:*.*
This would report extents for all files in the current
directory for drive B after doing a normal consistency check
on drive B. Files which have many extents can be copied and
renamed to restore them to a contiguous state, thus improving
I/O performance to the files.
Previous versions of CHKDSK would simply free
allocation units which were marked as used, but were not
actually part of any file. CHKDSK 2.00 will recover these
"orphan" allocation units if specified. If orphan allocation
units are found, CHKDSK prompts for free or recover. Free
just frees the orphans as previous versions did, recover will
employ allocation chain analysis to create "orphan files" in
the root directory of the disk. These files will have the
form "%ORPHAN%.l$$" where l will take on some ASCII value
greater than '@'. These files may then be inspected to see if
valuable data was contained in them. If there is not enough
room to make all of the "orphan" files, CHKDSK leaves the
unrecovered chains in the FAT so that CHKDSK can be run again
(once some entries in the ROOT have been deleted). NOTE:
Making ORPHAN files is a SLOW process.
Verbose mode. CHKDSK 2.00 may be run with the V switch
which causes a trace of the files and directories being
processed to be printed as CHKDSK runs.
FILTERS FOR MS-DOS 2.0
A filter is a utility that reads from standard input,
modifies the information in some way, then writes the result
to standard output. In this way the data is said to have been
"filtered" by the program. Since different filters can be
piped together in many different ways a few filters can take
the place of a large number of specific purpose programs. The
following describes the filters that are provided with MS-DOS
2.0:
CIPHER <key word>
Cipher reads a program from standard input, encrypts it
using the key word provided by the user, then writes the
result to standard output. To decrypt the file simply run
CIPHER again using the same keyword. For example:
A>CIPHER MYSTERY <NSA.CIA >SECRET.FIL
This command line will read file NSA.CIA, encrypt it using
the key word "MYSTERY", then write the result to file
SECRET.FIL To view the original file the following command
line could be used:
A>CIPHER MYSTERY <SECRET.FIL
This will read file SECRET.FIL, decrypt the file using the
key word "MYSTERY", then write the result to standard output,
which in this case is the console.
FGREP
This filter takes as arguments a string and optionally a
series of file names. It will send to standard output all
lines from the files specified in the command line that
contain the string.
If no files are specified FGREP will take the input from
standard in. The format for the command line invocation of
FGREP is:
FGREP [<option>] <string> <filename>*
The options available are:
/v Will cause FGREP to output all lines NOT
containing the specified string.
/c Will cause FGREP to only print the count of
lines matched in each of the files.
/n Each line matched is preceded by its relative
line number in the file.
The string argument should be enclosed in double quotes.
Two double quotes in succession are taken as a single double
quote. So,
A>FGREP "Fool""s Paradise" book1.txt book2.txt bible
will output all lines from the book1.txt, book2.txt and bible
(in that order that contain the string: Fool"s Paradise .
And,
A>dir b: | fgrep /v "DAT"
will output all names of the files in disk b: which do not
contain the string DAT .
MORE
The filter MORE reads from standard input, sends one
screen full of information to standard output and then pauses
with message:
-- More --
Pressing the RETURN key will cause another screen full of
information to be written to standard output. This process
continues until all the input data is read.
SORT [/R] [/+n]
Sort reads from standard input, sorts the data, the writes
the information to standard output. The sort is done using
the ASCII collating sequence. There are switches which allow
the user to select various options:
R - Reverse the sort, that is make "Z" come before "A"
+n - Sort starting with column "n" where n is some integer.
The default is start the comparisons with column 1,
this switch allows the user to start in any column.
example:
A>SORT /R <UNSORT.TXT >SORT.TXT
This command line will read the file UNSORT.TXT, do a reverse
sort, then write the output to file SORT.TXT
A>DIR | SORT /+14
This command line will cause the output of the directory
command to be piped to the sort filter, the sort filter will
sort starting with column 14 (This is the column the file size
starts), then send the output to the console. Thus a
directory sorted by file size will be the result. To get real
fancy:
A>DIR | SORT /+14 | MORE
will do the same thing except that MORE will give you a chance
to read the directory before it scrolls off the screen.