Home of the original IBM PC emulator for browsers.
The following document is from the Microsoft Programmer’s Library 1.3 CD-ROM.
Microsoft MS-DOS Programmer's Reference
════════════════════════════════════════════════════════════════════════════
Microsoft(R) MS-DOS(R) Programmer's Reference
Version 4.0
════════════════════════════════════════════════════════════════════════════
Information in this document is subject to change without notice and does
not represent a commitment on the part of Microsoft Corporation. The
software described in this document is furnished under a license agreement
or non-disclosure agreement. The software may be used or copied only in
accordance with the terms of the agreement. It is against the law to copy
the software on any medium except as specifically allowed in the license
or non-disclosure agreement. No part of this manual may be reproduced or
transmitted in any form or by any means, electronic or mechanical,
including photocopying and recording, for any purpose without the express
written permission of Microsoft.
(C) Copyright Microsoft Corporation, 1988. All rights reserved.
Simultaneously published in the United States and Canada.
Printed in the United States of America.
Microsoft, the Microsoft logo, MS-DOS, and XENIX are registered trademarks
of Microsoft Corporation.
IBM, IBM Personal Computer, IBM PC, and PC-DOS are registered trademarks
of International Business Machines Corporation.
INTEL is a registered trademark of Intel Corporation.
────────────────────────────────────────────────────────────────────────────
Contents
Chapter 1 System Calls
1.1 Introduction
1.1.1 System Calls That Have Been Superseded
1.1.2 How to Use This Manual
1.2 Standard Character Device I/O
1.3 Memory Management
1.4 Process Management
1.4.1 Loading and Executing a Program
1.4.2 Loading an Overlay
1.5 File and Directory Management
1.5.1 Handles
1.5.2 File-Related Function Requests
1.5.3 Device-Related Function Requests
1.5.4 Directory-Related Function Requests
1.5.5 File Attributes
1.6 Microsoft Networks
1.7 National Language Support
1.8 Miscellaneous System-Management Functions
1.9 Old System Calls
1.9.1 File Control Block (FCB)
1.10 Using the System Calls
1.10.1 Issuing an Interrupt
1.10.2 Calling a Function Request
1.10.3 Using the Calls from a High-Level Language
1.10.4 Treatment of Registers
1.10.5 Handling Errors
1.10.6 System Call Descriptions
1.11 Interrupts
1.11.1 Conditions upon Entry
1.11.2 Requirements for an Interrupt 24H Handler
1.12 Function Requests
Chapter 2 MS-DOS Device Drivers
2.1 Introduction
2.2 Format of a Device Driver
2.3 How to Create a Device Driver
2.3.1 Device Strategy Routine
2.3.2 Device Interrupt Routine
2.4 Installing Device Drivers
2.5 Device Headers
2.5.1 Pointer to Next Device Field
2.5.2 Attribute Field
2.5.3 Strategy and Interrupt Routines
2.5.4 Name Field
2.6 Request Header
2.6.1 Length of Record
2.6.2 Unit Code Field
2.6.3 Command Code Field
2.6.4 Status Field
2.7 Device Driver Functions
2.7.1 The Init Function
2.7.2 The Media Check Function
2.7.3 The Build BPB Function
2.7.4 The Read or Write Function
2.7.5 The Non-destructive Read, No Wait Function
2.7.6 The Open or Close Function
2.7.7 The Removable Media Function
2.7.8 The Status Function
2.7.9 The Flush Function
2.7.10 The Generic IOCtl Function
2.7.11 The Get/Set Logical Drive Map Function
2.8 The Media Descriptor Byte
2.9 Format of a Media Descriptor Table
2.10 The CLOCK Device
2.11 Anatomy of a Device Call
2.12 Two Sample Device Drivers
Chapter 3 MS-DOS Technical Information
3.1 Introduction
3.2 MS-DOS Initialization
3.3 The Command Processor
3.4 MS-DOS Disk Allocation
3.5 MS-DOS Disk Directory
3.6 File Allocation Table (FAT)
3.6.1 How to Use the FAT (12-Bit FAT Entries)
3.6.2 How to Use the FAT (16-Bit FAT Entries)
3.7 MS-DOS Standard Disk Formats
Chapter 4 MS-DOS Control Blocks and Work Areas
4.1 Introduction
4.2 Typical Contents of an MS-DOS Memory Map
4.3 The MS-DOS Program Segment
Chapter 5 National Language Support
5.1 Introduction
5.2 National Language Support Calls
5.3 Font Files
5.3.1 Font File Structure
Chapter 6 .Exe File Structure and Loading
6.1 Introduction
6.2 Format of a File Header
6.3 The Relocation Table
Chapter 7 Relocatable Object Module Formats
7.1 Introduction
7.1.1 Definition of Terms
7.2 Module Identification and Attributes
7.2.1 Segment Definition
7.2.2 Addressing a Segment
7.2.3 Symbol Definition
7.2.4 Indices
7.3 Conceptual Framework for Fixups
7.3.1 Self-Relative Fixup
7.3.2 Segment-Relative Fixup
7.4 Record Sequence
7.5 Introducing the Record Formats
7.5.1 Sample Record Format (SAMREC)
7.5.2 T-Module Header Record (THEADR)
7.5.3 L-Module Header Record (LHEADR)
7.5.4 List of Names Record (LNAMES)
7.5.5 Segment Definition Record (SEGDEF)
7.5.6 Group Definition Record (GRPDEF)
7.5.7 Public Names Definition Record (PUBDEF)
7.5.8 Communal Names Definition Record (COMDEF)
7.5.9 Local Symbols Record (LOCSYM)
7.5.10 External Names Definition Record (EXTDEF)
7.5.11 Line Numbers Record (LINNUM)
7.5.12 Logical Enumerated Data Record (LEDATA)
7.5.13 Logical Iterated Data Record (LIDATA)
7.5.14 Fixup Record (FIXUPP)
7.5.15 Module End Record (MODEND)
7.5.16 Comment Record (COMENT)
7.6 Microsoft Type Representations for Communal Variables
Chapter 8 Programming Hints
8.1 Introduction
8.2 Interrupts
8.3 System Calls
8.4 Device Management
8.5 Memory Management
8.6 Process Management
8.7 File and Directory Management
8.7.1 Locking Files
8.8 Miscellaneous
Figures
Figure 1.1 Example of the 8088 Registers
Figure 1.2 Sample Program with Common Skeleton
Figure 2.1 Sample Device Header
Figure 2.2 Attribute Word for Character Devices
Figure 2.3 Attribute Word for Block Devices
Figure 2.4 Request Header
Figure 2.5 Status Field
Figure 2.6 Format of a Boot Sector
Figure 2.7 Format of a Clock Device
Figure 4.1 Program Segment Prefix
Figure 5.1 Font File Structure
Figure 7.1 Location Types
Tables
Table 1.1 Standard-Character I/O Function Requests
Table 1.2 Memory Management Function Requests
Table 1.3 Process-Management Function Requests
Table 1.4 Predefined Device Handles
Table 1.5 File-Related Function Requests
Table 1.6 File-Sharing Function Requests
Table 1.7 Device-Related Function Requests
Table 1.8 Directory-Related Function Requests
Table 1.9 File Attributes
Table 1.10 Microsoft Networks Function Requests
Table 1.11 National-Language-Support Function Requests
Table 1.12 Miscellaneous System-Management Function Requests
Table 1.13 Old System Calls and Their Replacements
Table 1.14 Format of the File Control Block (FCB)
Table 1.15 Error Codes Returned in AX
Table 1.16 MS-DOS Interrupts, Numeric Order
Table 1.17 MS-DOS Interrupts, Alphabetic Order
Table 1.18 MS-DOS Function Requests, Numeric Order
Table 1.19 MS-DOS Function Requests, Alphabetic Order
Table 1.20 Bit Values for Function 29H
Table 1.21 Sharing Mode Bit Values
Table 1.22 Access Code Bit Values
Table 1.23 MS-DOS Data Bit Values
Table 1.24 Contents of the Parameter Block
Table 1.25 Contents of the Parameter Block
Table 1.26 DTA Values After Successful Find First File
Table 1.27 Allocation Strategy
Table 2.1 For Character Devices:
Table 2.2 For Block Devices:
Table 3.1 MS-DOS Standard Removable-Disk Formats
Table 3.2 MS-DOS Standard Removable-Disk Formats (High-Density)
Table 7.1 Object Module Record Formats
Table 7.2 Combination Attribute Example
────────────────────────────────────────────────────────────────────────────
Chapter 1 System Calls
1.1 Introduction
1.1.1 System Calls That Have Been Superseded
1.1.2 How to Use This Manual
1.2 Standard Character Device I/O
1.3 Memory Management
1.4 Process Management
1.4.1 Loading and Executing a Program
1.4.2 Loading an Overlay
1.5 File and Directory Management
1.5.1 Handles
1.5.2 File-Related Function Requests
1.5.3 Device-Related Function Requests
1.5.4 Directory-Related Function Requests
1.5.5 File Attributes
1.6 Microsoft Networks
1.7 National Language Support
1.8 Miscellaneous System-Management Functions
1.9 Old System Calls
1.9.1 File Control Block (FCB)
1.10 Using the System Calls
1.10.1 Issuing an Interrupt
1.10.2 Calling a Function Request
1.10.3 Using the Calls from a High-Level Language
1.10.4 Treatment of Registers
1.10.5 Handling Errors
1.10.6 System Call Descriptions
1.11 Interrupts
1.11.1 Conditions upon Entry
1.11.2 Requirements for an Interrupt 24H Handler
1.12 Function Requests
1.1 Introduction
The routines that MS-DOS uses to manage system operation and resources can
be called by any application program. Using these system calls makes it
easier to write machine-independent programs and increases the likelihood
that a program will be compatible with future versions of MS-DOS. MS-DOS
system calls fall into several categories:
■ Standard character device I/O
■ Memory management
■ Process management
■ File and directory management
■ Microsoft Network calls
■ National Language Support calls
■ Miscellaneous system functions
Applications invoke MS-DOS services by using software interrupts. The
current range of interrupts used for MS-DOS is 20H-27H; 28H-40H are
reserved. Interrupt 21H is the function request service; it provides
access to a wide variety of MS-DOS services. In some cases, the full AX
register is used to specify the requested function. Each interrupt or
function request uses values in various registers to receive or return
function-specific information.
1.1.1 System Calls That Have Been Superseded
Many system calls introduced in versions of MS-DOS earlier than 2.0 have
been superseded by function requests that are more efficient and easier to
use. Although MS-DOS still includes these old system calls, they should
not be used unless it is imperative that a program maintain
backward-compatibility with versions of MS-DOS earlier than 2.0.
A table of the pre-2.0 system calls and a description of the File Control
Block (required by some of the old calls) appear in Section 1.8, "Old
System Calls."
1.1.2 How to Use This Manual
The first part of this chapter explains how DOS manages its resources──
such as memory, files, and processes──and briefly describes the purpose of
most of the system calls. The remainder of the chapter describes each
interrupt and function request in detail.
The system-call descriptions are in numeric order, interrupts followed by
function requests. These descriptions include further detail on how MS-DOS
manages its resources.
Chapter 2 of this manual describes how to write an MS-DOS device driver.
Chapters 3 and 4 contain more detailed information about MS-DOS,
including how it manages disk space, uses control blocks, and loads and
executes relocatable programs (files with an extension of .exe).
Chapter 5 describes MS-DOS national language support.
Chapter 6 describes .exe file structure and loading procedures (for
versions of MS-DOS earlier than 2.0).
Chapter 7 describes the Intel object module format.
Chapter 8 gives some programming hints.
1.2 Standard Character Device I/O
The standard-character function requests handle all input and output to
and from character devices such as consoles, printers, and serial ports.
If a program uses these function requests, its input and output can be
redirected.
Table 1.1 lists the MS-DOS function requests for managing
standard-character input and output.
Table 1.1
Standard-Character I/O Function Requests
╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
Code Request Description
──────────────────────────────────────────────────────────────────────────
01H Read Keyboard and Gets a character from standard input and
Echo echoes it to standard output
02H Display Character Sends a character to standard output
03H Auxiliary Input Gets a character from standard auxiliary
04H Auxiliary Output Sends a character to standard auxiliary
05H Print Character Sends a character to the standard printer
Code Request Description
──────────────────────────────────────────────────────────────────────────
05H Print Character Sends a character to the standard printer
06H Direct Console I/O Gets a character from standard input or
sends a character to standard output
07H Direct Console Input Gets a character from standard input
08H Read Keyboard Gets a character from standard input
09H Display String Sends a string to standard output
0AH Buffered Keyboard Gets a string from standard input
Input
0BH Check Keyboard Reports on the status of the standard
Status input buffer
0CH Flush Buffer, Read Empties the standard input buffer and
Keyboard calls one of the other standard character
Code Request Description
──────────────────────────────────────────────────────────────────────────
Keyboard calls one of the other standard character
──────────────────────────────────────────────────────────────────────────
Although several of these standard-character I/O function requests seem to
do the same thing, they are distinguished by whether they check for
control characters or echo characters from standard input to standard
output. The detailed descriptions later in this chapter point out the
differences.
1.3 Memory Management
MS-DOS keeps track of which areas of memory are allocated by writing a
memory control block at the beginning of each. This control block
specifies the size of the memory area; the name of the process, if any,
that owns the memory area; and a pointer to the next area of memory. If
the memory area is not owned, it is available.
Table 1.2 lists the MS-DOS function requests for managing memory.
Table 1.2
Memory Management Function Requests
Code Request Description
──────────────────────────────────────────────────────────────────────────
48H Allocate Memory Requests a block of memory
49H Free Allocated Frees a block of memory previously
Memory allocated with 48H
4AH Set Block Changes the size of an allocated memory
──────────────────────────────────────────────────────────────────────────
When a process requests additional memory with Function 48H (Allocate
Memory), MS-DOS searches for a block of available memory large enough to
satisfy the request. If it finds such a block of memory, it changes the
memory control block to show the owning process. If the block of memory is
larger than the requested amount, MS-DOS changes the size field of the
memory control block to the requested amount, writes a new memory control
block at the beginning of the unneeded portion showing that it is
available, and updates the pointers to add this memory to the chain of
memory control blocks. MS-DOS then returns the segment address of the
first byte of the allocated memory to the requesting process.
When a process releases an allocated block of memory with Function 49H
(Free Allocated Memory), MS-DOS changes the memory control block to show
that it is available (not owned by any process).
When a process uses Function 4AH (Set Block) to shrink an allocated block
of memory, MS-DOS builds a memory control block for the memory being
released and adds it to the chain of memory control blocks. When a process
tries to use Function 4AH (Set Block) to expand an allocated block of
memory, MS-DOS treats it as a request for additional memory rather than
returning the segment address of the additional memory to the requesting
process. However, MS-DOS simply chains the additional memory to the
existing memory block. If MS-DOS can't find a block of available memory
large enough to satisfy a request for additional memory made with either
Function 48H (Allocate Memory) or Function 4AH (Set Block), MS-DOS
returns an error code to the requesting process.
When a program receives control, it should call Function 4AH (Set Block)
to shrink its initial memory-allocation block (the block that begins with
its Program Segment Prefix) to the minimum it requires. This frees
unneeded memory and makes the best application design for portability to
future multitasking environments.
When a program exits, MS-DOS automatically frees its initial
memory-allocation block before returning control to the calling program
(command.com is usually the calling program for application programs). DOS
frees any memory owned by the exiting process.
Any program that changes memory that is not allocated to it will most
likely destroy at least one memory-management control block. This causes a
memory-allocation error the next time MS-DOS tries to use the chain of
memory-control blocks; the only cure is to restart the system.
1.4 Process Management
MS-DOS uses several function requests to load, execute, and terminate
programs. Application programs can use these same function requests to
manage other programs.
Table 1.3 lists the MS-DOS function requests for managing processes.
Table 1.3
Process-Management Function Requests
Code Request Description
──────────────────────────────────────────────────────────────────────────
31H Keep Process Terminates a process and returns control
to the invoking process, but keeps the
terminated process in memory
4B00H, Load and Execute Loads and executes a program, or loads a
4B03H Program or Overlay program overlay without executing it
4CH End Process Returns control to the invoking process
4DH Get Return Code of Returns a code passed by an exiting child
Child Process process
62H Get PSP Returns the segment address of the current
──────────────────────────────────────────────────────────────────────────
Function 4BH (Load and Execute Program or Overlay) has two subfunctions,
4B00H (Load and Execute Program) and 4B03H (Load Overlay). The
differences between them are described in the following sections.
1.4.1 Loading and Executing a Program
When a program uses Function 4B00H (Load and Execute Program) to load and
execute another program, MS-DOS allocates memory, writes a Program Segment
Prefix (PSP) for the new program at offset 0 of the allocated memory,
loads the new program, and passes control to it. When the invoked program
exits, control returns to the calling program.
Command.com uses Function 4B00H to load and execute command files.
Application programs have the same degree of control over process
management as does command.com.
In addition to these common features, there are some differences in the
way MS-DOS loads .com and .exe files.
Loading a .Com Program
When command.com loads and executes a .com program, it allocates all
available memory to the application and sets the stack pointer 100H bytes
from the end of available memory. A .com program should set up its own
stack before shrinking its initial memory-allocation block with Function
4AH (Set Block) because the default stack is in the memory to be
released.
If a newly loaded program is allocated all of memory──as a .com program
is──or requests all of available memory by using Function 48H (Allocate
Memory), MS-DOS allocates to it the memory occupied by the transient part
of command.com. If the program changes this memory, MS-DOS must reload the
transient portion of command.com before it can continue. If a program
exits (via Function 31H, Keep Process) without releasing enough memory,
the system halts and must be reset. To minimize this possibility, a .com
program should use Function 4AH (Set Block) to shrink its initial
allocation block before doing anything else. Also, before exiting, all
programs must release all memory they allocate by using Function 48H
(Allocate Memory).
Loading a .Exe Program
When command.com loads and executes a .exe program, it allocates the size
of the program's memory image plus either the value in the MAX──ALLOC
field (offset 0CH) of the file header (if that much memory is available)
or the value in the MIN──ALLOC field (offset 0AH). The linker sets these
fields. Before passing control to the .exe file, MS-DOS uses the
relocation information in the file header to calculate the correct
relocation addresses.
For a more detailed description of how MS-DOS loads .com and .exe files,
see Chapter 3, "MS-DOS Technical Information," and Chapter 4, "MS-DOS
Control Blocks and Work Areas."
Executing a Program from Within Another Program
Since command.com builds pathnames, searches directory paths for
executable files, and relocates .exe files, the simplest way to load and
execute a program is to load and execute an additional copy of
command.com, passing it a command line that includes the /C switch, which
invokes the .com or .exe file. The description of Function 4B00H (Load
and Execute Program) describes how to do this.
1.4.2 Loading an Overlay
When a program uses Function 4B03H (Load Overlay) to load an overlay, it
must pass MS-DOS the segment address at which the overlay is to be loaded.
The program must call the overlay, which then returns directly to the
calling program. The calling program is in complete control: MS-DOS does
not write a PSP for the overlay or intervene in any other way.
MS-DOS does not check to see if the calling program owns the memory where
the overlay is to be loaded. If the calling program does not own the
memory, loading the overlay will most likely destroy a memory-control
block, causing an eventual memory-allocation error.
Therefore, a program that loads an overlay must either allow room for the
overlay when it calls Function 4AH (Set Block) to shrink its initial
memory-allocation block, or shrink its initial memory-allocation block to
the minimum and then use Function 48H (Allocate Memory) to allocate
memory for the overlay.
1.5 File and Directory Management
The MS-DOS hierarchical (multilevel) file system is similar to that of the
XENIX operating system. For a description of the multilevel directory
system and how to use it, see the MS-DOS User's Reference.
1.5.1 Handles
To create or open a file, a program passes MS-DOS a pathname and the
attribute to be assigned to the file. MS-DOS returns a 16-bit number,
called a handle. For most subsequent actions, MS-DOS requires only this
handle to identify the file.
A handle can refer to either a file or a device. MS-DOS predefines five
standard handles. These handles are always open, so you needn't open them
before you use them. Table 1.4 lists these predefined handles.
Table 1.4
Predefined Device Handles
Handle Standard device Comment
──────────────────────────────────────────────────────────────────────────
0 Input Can be redirected from command line
1 Output Can be redirected from command line
2 Error
3 Auxiliary
4 Printer
──────────────────────────────────────────────────────────────────────────
When MS-DOS creates or opens a file, it assigns the first available
handle. Since a program can have 20 open handles, including the five
predefined handles, it typically can open 15 extra files. By using
Function 46H (Force Duplicate File Handle), MS-DOS can temporarily force
any of the five predefined handles to refer to an alternate file or
device. For more information about Function 46H, see its description
later in this chapter.
1.5.2 File-Related Function Requests
MS-DOS treats a file as a string of bytes; it assumes no record structure
or access technique. An application program imposes whatever record
structure it needs on this string of bytes. Reading from or writing to a
file requires only pointing to the data buffer and specifying the number
of bytes to read or write. Table 1.5 lists the MS-DOS function requests
for managing files.
Table 1.5
File-Related Function Requests
╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
Code Request Description
──────────────────────────────────────────────────────────────────────────
3CH Create Handle Creates a file
3DH Open Handle Opens a file
3EH Close Handle Closes a file
3FH Read Handle Reads from a file
40H Write Handle Writes to a file
42H Move File Pointer Sets the read/write pointer in a file
45H Duplicate File Creates a new handle that refers to the
Code Request Description
──────────────────────────────────────────────────────────────────────────
45H Duplicate File Creates a new handle that refers to the
Handle same file as an existing handle
46H Force Duplicate File Makes an existing handle refer to the same
Handle file as another existing handle
5AH Create Temporary Creates a file with a unique name
File
5BH Create New File Attempts to create a file, but fails if a
file with the same name exists
67H Set Handle Count Increases or decreases the number of files
a program can have open at one time
68H Commit File Flushes buffered data for a file without
closing it to ensure the disk image of
──────────────────────────────────────────────────────────────────────────
Code Request Description
──────────────────────────────────────────────────────────────────────────
File Sharing
Version 3.1 of MS-DOS introduced file sharing, which let more than one
process share access to a file. File sharing operates only after the share
command has been executed to load file-sharing support. That is, you must
use the share command to take advantage of file sharing.
Table 1.6 lists the MS-DOS function requests for sharing files; if file
sharing is not in effect, these function requests cannot be used. Function
3DH (Open Handle) can operate in several modes. Here it is referred to in
the file-sharing modes, which require file sharing to be in effect.
(Compatibility mode is usable without file sharing being in effect.)
Table 1.6
File-Sharing Function Requests
Code Request Description
──────────────────────────────────────────────────────────────────────────
3DH Open Handle Opens a file by using one of the
file-sharing modes
440BH IOCtl Retry (before Interrupt 24H is issued)
Specifies how many times to retry an I/O
operation that fails due to a file-sharing
violation
5C00H Lock Locks a region of a file
5C01H Unlock Unlocks a region of a file
──────────────────────────────────────────────────────────────────────────
1.5.3 Device-Related Function Requests
I/O Control for devices is implemented with Function 44H (IOCtl), which
includes several subfunctions necessary to perform device-related tasks.
Some forms of the IOCtl function request require that the device driver be
written to support the IOCtl interface. Table 1.7 lists the MS-DOS
function requests for managing devices.
Table 1.7
Device-Related Function Requests
╓┌─┌──────────────┌─────────────────────────┌────────────────────────────────╖
Code Request Description
──────────────────────────────────────────────────────────────────────────
4400H, 4401H IOCtl Data Gets or sets device description
4402H, 4403H IOCtl Character Gets or sets character-device
control data
4404H, 4405H IOCtl Block Gets or sets block-device control
data
4406H, 4407H IOCtl Status Checks device input or output
status
4408H IOCtl Is Changeable Checks whether block device
contains removable medium
440CH Generic IOCtl (for Sets Generic IOCtl for handles
handles) and supports code pages for
Code Request Description
──────────────────────────────────────────────────────────────────────────
handles) and supports code pages for
devices or returns DCBS
information.
440DH Generic IOCtl (for Sets Generic IOCtl for devices
devices)
440EH, 440FH Get/Set IOCtl Drive Map Gets or sets logical drive map
──────────────────────────────────────────────────────────────────────────
Some forms of the IOCtl function request can be used only with Microsoft
Networks; these forms are listed in Section 1.6, "Microsoft Networks."
1.5.4 Directory-Related Function Requests
A directory entry is a 32-byte record that includes the file's name,
extension, date and time of last change, and size. An entry in a
subdirectory is identical to an entry in the root directory. Directory
entries are described in detail in Chapter 3.
The root directory on a disk has room for a fixed number of entries: 64 on
a standard single-sided disk, 112 on a standard double-sided disk. For
hard disks, the number of directories depends on the DOS partition size. A
subdirectory is simply a file with a unique attribute; there can be as
many subdirectories on a disk as space allows. The depth of a directory
structure, therefore, is limited only by the amount of storage on a disk
and the maximum pathname length of 64 characters. Pre-2.0 disks appear to
have only a root directory that contains files but no subdirectories.
Table 1.8 lists the MS-DOS function requests for managing directories.
Table 1.8
Directory-Related Function Requests
╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
Code Request Description
──────────────────────────────────────────────────────────────────────────
39H Create Directory Creates a subdirectory
3AH Remove Directory Deletes a subdirectory
Code Request Description
──────────────────────────────────────────────────────────────────────────
3AH Remove Directory Deletes a subdirectory
3BH Change Current Changes the current directory
Directory
41H Delete Directory Deletes a file
Entry (Unlink)
43H Get/Set File Retrieves or changes the attributes of a
Attributes (Chmod) file
47H Get Current Returns current directory for a given
Directory drive
4EH Find First File Searches a directory for the first entry
that matches a filename
4FH Find Next File Searches a directory for the next entry
that matches a filename
Code Request Description
──────────────────────────────────────────────────────────────────────────
that matches a filename
56H Change Directory Renames a file
Entry
57H Get/Set Date/Time of Changes the time and date of last change
File in a directory entry
──────────────────────────────────────────────────────────────────────────
1.5.5 File Attributes
Table 1.9 describes the file attributes and how they are represented in
the attribute byte of the directory entry (offset 0BH). The attributes can
be inspected or changed with Function 43H (Get/Set File Attributes
[Chmod]).
Table 1.9
File Attributes
Code Description
──────────────────────────────────────────────────────────────────────────
00H Normal; can be read or written without
restriction
01H Read-only; cannot be opened for write; a file
with the same name cannot be created
02H Hidden; not found by directory search
04H System; not found by directory search
08H VolumeID; only one file can have this attribute;
it must be in the root directory
10H Subdirectory
20H Archive; set whenever the file is changed, or
──────────────────────────────────────────────────────────────────────────
The VolumeID (08H) and Subdirectory (10H) attributes cannot be changed
with Function 43H (Get/Set File Attributes [Chmod]).
1.6 Microsoft Networks
Microsoft Networks consists of a server and one or more workstations.
MS-DOS maintains an assign list that keeps track of which workstation disk
drives and devices have been redirected to the server. For a description
of the operation and use of the network, see the Microsoft Networks
Manager's Guide and Microsoft Networks User's Guide.
Table 1.10 lists the MS-DOS function requests for managing a Microsoft
Networks workstation.
Table 1.10
Microsoft Networks Function Requests
╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
Code Request Description
──────────────────────────────────────────────────────────────────────────
4409H IOCtl Is Redirected Checks whether a drive letter refers to a
Block local or redirected drive
Code Request Description
──────────────────────────────────────────────────────────────────────────
Block local or redirected drive
440AH IOCtl Is Redirected Checks whether a device name refers to a
Handle local or redirected device
5E00H Get Machine Name Gets the network name of the workstation
5E02H Set Printer Setup Defines a string of control characters to
be added at the beginning of each file
that is sent to a network printer
5F02H Get Assign-List Gets an entry from the assign list, which
Entry shows the workstation drive letter or
device name and the network name of the
directory or device on the server to which
the entry is reassigned
5F03H Make Network Redirects a workstation drive or device to
Connection a server directory or device
Code Request Description
──────────────────────────────────────────────────────────────────────────
Connection a server directory or device
5F04H Delete Network Cancels the redirection of a workstation
Connection drive or device to a server directory or
──────────────────────────────────────────────────────────────────────────
1.7 National Language Support
National language support of MS-DOS includes these major features:
■ Country-dependent information
■ Support for national keyboard layouts
■ Programming interfaces for national language support
■ Utility commands
Country-dependent information is available on a per-country basis and
includes the following:
■ Time, date, and currency
■ Lowercase-to-uppercase character-conversion tables
■ Collating sequence for character sorting
■ Valid single-byte characters used in filenames
Keyboard support for different keyboard layouts is provided and
selectable.
Table 1.11 lists the MS-DOS national-language-support system calls that
allow applications to use the country-dependent information just
described.
Table 1.11
National-Language-Support Function Requests
Code Request Description
──────────────────────────────────────────────────────────────────────────
65H Get Extended Country Returns standard country information,
Information pointer to uppercase table, pointer to
filename uppercasing table, or pointer to
collating table.
66H Get/Set Global Code Gets or sets the code page used by the
Page kernel and all devices.
──────────────────────────────────────────────────────────────────────────
1.8 Miscellaneous System-Management Functions
The remaining system calls manage other system functions and resources
such as drives, addresses, and the clock. Table 1.12 lists the MS-DOS
function requests for managing miscellaneous system resources and
operations.
Table 1.12
Miscellaneous System-Management Function Requests
╓┌─┌─────────┌─────────────────────┌─────────────────────────────────────────╖
Code Request Description
──────────────────────────────────────────────────────────────────────────
0DH Reset Disk Empties all file buffers
0EH Select Disk Sets the default drive
19H Get Current Disk Returns the default drive
1AH Set Disk Transfer Establishes the disk I/O buffer
Address
1BH Get Default Drive Returns disk-format data
Data
1CH Get Drive Data Returns disk-format data
25H Set Interrupt Vector Sets interrupt-handler address
29H Parse File Name Checks string for valid filename
Code Request Description
──────────────────────────────────────────────────────────────────────────
29H Parse File Name Checks string for valid filename
2AH Get Date Returns system date
2BH Set Date Sets system date
2CH Get Time Returns system time
2DH Set Time Sets system time
2EH Set/Reset Verify Turns disk verify on or off
Flag
2FH Get Disk Transfer Returns system-disk-I/O-buffer address
Address
30H Get MS-DOS Version Returns MS-DOS version number
Number
33H CONTROL+C Check Returns CONTROL+C check status
Code Request Description
──────────────────────────────────────────────────────────────────────────
33H CONTROL+C Check Returns CONTROL+C check status
35H Get Interrupt Vector Returns address of interrupt handler
36H Get Disk Free Space Returns disk-space data
38H Get/Set Country Data Sets current country or retrieves country
information
54H Get Verify State Returns status of disk verify
──────────────────────────────────────────────────────────────────────────
1.9 Old System Calls
Most of the superseded system calls deal with files. Table 1.13 lists
these old calls and the function requests that have superseded them.
Although MS-DOS still includes these old system calls, they should not be
used unless a program must maintain backward-compatibility with earlier
versions of MS-DOS.
Table 1.13
Old System Calls and Their Replacements
╓┌─┌──────────┌─────────────────────────┌──────────┌─────────────────────────╖
Old System Call Has Been Superseded By
Code Function Code Function
──────────────────────────────────────────────────────────────────────────
00H Terminate Program 4CH End Process
0FH Open File 3DH Open Handle
10H Close File 3EH Close Handle
11H Search for First Entry 4EH Find First File
12H Search for Next Entry 4FH Find Next File
13H Delete File 41H Delete Directory Entry
14H Sequential Read 3FH Read Handle
15H Sequential Write 40H Write Handle
16H Create File 3CH Create Handle
5AH Create Temporary File
5BH Create New File
Old System Call Has Been Superseded By
Code Function Code Function
──────────────────────────────────────────────────────────────────────────
5BH Create New File
17H Rename File 56H Change Directory Entry
21H Random Read 3FH Read Handle
22H Random Write 40H Write Handle
23H Get File Size 42H Move File Pointer
24H Set Relative Record 42H Move File Pointer
26H Create New PSP 4B00H, Load and Execute Program
4B03H or Overlay
27H Random Block Read 42H Move File Pointer
3FH Read Handle
28H Random Block Write 42H Move File Pointer
40H Write Handle
Code Interrupt Code Function
──────────────────────────────────────────────────────────────────────────
20H Program Terminate 4CH End Process
27H Terminate But Stay 31H Keep Process
Resident
Old System Call Has Been Superseded By
Code Function Code Function
──────────────────────────────────────────────────────────────────────────
Resident
──────────────────────────────────────────────────────────────────────────
1.9.1 File Control Block (FCB)
The old file-related function requests require that a program maintain a
File Control Block (FCB) for each file; this control block contains such
information as a file's name, size, record length, and pointer to current
record. MS-DOS does most of this housekeeping for the newer,
handle-oriented function requests.
Some descriptions of the old function requests refer to unopened and
opened FCBs. An unopened FCB contains only a drive specifier and filename.
An opened FCB contains all fields filled by Function 0FH (Open File).
The Program Segment Prefix (PSP) includes room for two FCBs at offsets 5CH
and 6CH. For a description of how to use the PSP and FCB calls, see
Chapter 4, "MS-DOS Control Blocks and Work Areas." Table 1.14 describes
the FCB fields.
Table 1.14
Format of the File Control Block (FCB)
Offset
Hex Dec Bytes Field
──────────────────────────────────────────────────────────────────────────
00H 0 1 Drive Number
01H 1 8 Filename
09H 9 3 Extension
0CH 12 2 Current Block
0EH 14 2 Record Size
10H 16 4 File Size
14H 20 2 Date of Last Write
16H 22 2 Time of Last Write
18H 24 8 Reserved
20H 32 1 Current Record
21H 33 4 Relative Record
──────────────────────────────────────────────────────────────────────────
Fields of the FCB
Drive Number (offset 00H): Specifies the disk drive; 1 means drive A and 2
means drive B. If you use the FCB to create or open a file, you can set
this field to 0 to specify the default drive; Function 0FH (Open File)
sets the field to the number of the default drive.
Filename (offset 01H): Eight characters, left-aligned and padded (if
necessary) with blanks. If you specify a reserved device name (such as
PRN), do not put a colon at the end.
Extension (offset 09H): Three characters, left-aligned and padded (if
necessary) with blanks. This field can be all blanks (no extension).
Current Block (offset 0CH): Points to the block (group of 128 records)
that contains the current record. This field and the Current Record field
(offset 1FH) make up the record pointer. This field is set to zero by the
Open File system call.
Record Size (offset 0EH): The size of a logical record, in bytes. Set to
128 by the Open File system call. If the record size is not 128 bytes, you
must set this field after opening the file.
File Size (offset 10H): The size of the file, in bytes. The first word of
this 4-byte field is the low-order part of the size.
Date of Last Write (offset 14H): The date the file was created or last
updated. The year, month, and day are mapped into two bytes as follows:
Offset 15H Offset 14H
|Y|Y|Y|Y|Y|Y|Y|M| |M|M|M|D|D|D|D|D|
15 9 8 5 4 0
Time of Last Write (offset 16H): The time the file was created or last
updated. The hour, minutes, and seconds are mapped into two bytes as
follows:
Offset 17H Offset 16H
|H|H|H|H|H|M|M|M| |M|M|M|S|S|S|S|S|
15 11 10 5 4 0
Reserved (offset 18H): These fields are reserved for use by MS-DOS.
Current Record (offset 20H): Points to one of the 128 records in the
current block. This field and the Current Block field (offset 0CH) make up
the record pointer. The Open File system call does not initialize this
field. You must set it before doing a sequential read or write to the
file.
Relative Record (offset 21H): Points to the currently selected record,
counting from the beginning of the file (starting with 0). The Open File
system call does not initialize this field. You must set it before doing a
random read or write to the file. If the record size is less than 64
bytes, both words of this field are used; if the record size is 64 bytes
or more, only the first three bytes are used.
──────────────────────────────────────────────────────────────────────────
Note
If you use the FCB at offset 5CH of the Program Segment Prefix, the last
byte of the Relative Record field is the first byte of the unformatted
parameter area that starts at offset 80H. This is the default Disk
Transfer Area.
──────────────────────────────────────────────────────────────────────────
Extended FCB
The Extended File Control Block is used to create or search for directory
entries of files with special attributes. It adds the following 7-byte
prefix to the FCB:
Name Bytes Offset
──────────────────────────────────────────────────────────────────────────
Flag byte (FFH) 1 07H
Reserved 5 06H
Attribute byte 1 01H
──────────────────────────────────────────────────────────────────────────
File attributes are described earlier in this chapter in Section 1.5.5,
"File Attributes."
──────────────────────────────────────────────────────────────────────────
Note
You must remember to point to the beginning of the extended FCB if you
are using Functions 0FH-16H with extended FCBs.
──────────────────────────────────────────────────────────────────────────
1.10 Using the System Calls
The remainder of this chapter describes how to use the system calls in
application programs, and it lists the calls in numeric and alphabetic
order, describing each call in detail.
1.10.1 Issuing an Interrupt
MS-DOS reserves Interrupts 28H through 3FH for its own use, and maintains
the table of interrupt-handler addresses (the vector table) in locations
80H-FCH. Also, in case you need to write your own routines for three
particular MS-DOS interrupt handlers (Program Terminate, CONTROL+C, and
Critical Error), this chapter includes descriptions of each. Function
requests have superseded most of these interrupts.
To issue an interrupt, move any required data into the registers and give
the INT instruction with the number of the interrupt you want.
1.10.2 Calling a Function Request
A function request is an MS-DOS routine for managing system resources. Use
the following procedure to call a function request:
1. Move any required data into the registers.
2. Move the function number into AH.
3. Move the action code, if required, into AL.
4. Issue Interrupt 21H.
1.10.3 Using the Calls from a High-Level Language
The system calls can be executed from any high-level language whose
modules can be linked with assembly-language modules. In addition to this
linking technique, you can:
■ Use the Interrupt 86 function of C to call a function request directly.
■ Use the DOSXQQ function of Pascal to call a function request directly.
■ Use the CALL statement or USER function to execute the required
assembly-language code from the BASIC interpreter.
1.10.4 Treatment of Registers
When MS-DOS takes control after a function request, it switches to an
internal stack, and preserves any registers not used to return information
(except AX). The calling program's stack must be large enough to
accommodate the interrupt system──at least 128 bytes in addition to other
needs.
1.10.5 Handling Errors
Most of the function requests introduced with MD-DOS version 2.0 or later
set the Carry flag if there is an error, identifying the specific error by
returning a number in the AX register. Table 1.15 lists these error codes
and their meanings.
Table 1.15
Error Codes Returned in AX
╓┌─┌──────────────┌──────────────────────────────────────────────────────────╖
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 Invalid function code
2 File not found
3 Path not found
4 Too many open files (no open handles left)
5 Access denied
6 Invalid handle
7 Memory control blocks destroyed
8 Insufficient memory
9 Invalid memory block address
10 Invalid environment
11 Invalid format
12 Invalid access code
13 Invalid data
14 Reserved
15 Invalid drive
Code Meaning
──────────────────────────────────────────────────────────────────────────
15 Invalid drive
16 Attempt to remove the current directory
17 Not same device
18 No more files
19 Disk is write-protected
20 Bad disk unit
21 Drive not ready
22 Invalid disk command
23 CRC error
24 Invalid length (disk operation)
25 Seek error
26 Not an MS-DOS disk
27 Sector not found
28 Out of paper
29 Write fault
30 Read Fault
31 General failure
Code Meaning
──────────────────────────────────────────────────────────────────────────
31 General failure
32 Sharing violation
33 Lock violation
34 Wrong disk
35 FCB unavailable
36 Sharing buffer exceeded
37 Reserved
38 Handle end-of-file operation not completed
39-49 Reserved
50 Network request not supported
51 Remote computer not listening
52 Duplicate name on network
53 Network name not found
54 Network busy
55 Network device no longer exists
56 Net BIOS command limit exceeded
57 Network adapter hardware error
58 Incorrect response from network
Code Meaning
──────────────────────────────────────────────────────────────────────────
58 Incorrect response from network
59 Unexpected network error
60 Incompatible remote adapter
61 Print queue full
62 Queue not full
63 Not enough space for print file
64 Network name was deleted
65 Access denied
66 Network device type incorrect
67 Network name not found
68 Network name limit exceeded
69 Net BIOS session limit exceeded
70 Temporarily paused
71 Network request not accepted
72 Print or disk redirection is paused
73-79 Reserved
Code Meaning
──────────────────────────────────────────────────────────────────────────
80 File Exists
81 Reserved
82 Cannot make
83 Interrupt 24 failure
84 Out of structures
85 Already assigned
86 Invalid password
87 Invalid parameter
88 Net write fault
89 Function not supported by network
90 Required system component not installed
──────────────────────────────────────────────────────────────────────────
To handle error conditions, put the following statement immediately after
calls that return errors:
JC <error>
<Error> represents the label of an error-handling routine that gets the
specific error condition by checking the value in AX. This routine then
takes appropriate action.
Some of the older system calls return a value in a register that specifies
whether the operation was successful. To handle such errors, check the
error code and take the appropriate action.
Extended Error Codes
Versions of MS-DOS after 2.0 have added new error messages. Any programs
that use the older system calls cannot use these new error messages. To
avoid incompatibility, MS-DOS maps these new error codes to the old error
code that most closely matches the new one.
Function 59H (Get Extended Error) has been added so that these new calls
can be used. It provides as much detail as possible about the most recent
error code returned by MS-DOS. The description of Function 59H lists the
new, more detailed error codes and shows how to use this function request.
1.10.6 System Call Descriptions
Most system calls require that you move information into one or more
registers before issuing the call that returns information in the
registers. The description of each system call in this chapter includes
the following:
■ A diagram of the 8088 registers that shows their contents before and
after the system call
■ A more complete description of the register contents required before
the system call
■ A description of the processing performed
■ A more complete description of the register contents after the system
call
■ An example of how to use the system call
The following figure is a sample illustration of the 8088 registers,
showing how the information is presented. Shaded areas indicate that the
register receives or returns information used by the call.
┌───────┬───────┐
AX:│ AH │ AL │
├───────┼───────┤
BX:│ BH │ BL │
├───────┼───────┤
CX:│ CH │ CL │
├───────┼───────┤
DX:│ DH │ DL │
└───────┴───────┘
┌───────────────┐
│ SP │
├───────────────┤
│ BP │
├───────────────┤
│ SI │
├───────────────┤
│ DI │
└───────────────┘
┌───────────────┐
│ SP │
├───────┬───────┤
│FLAGS H│FLAGS L│
└───────┴───────┘
┌───────────────┐
│ CS │
├───────────────┤
│ DS │
├───────────────┤
│ SS │
├───────────────┤
│ ES │
└───────────────┘
Figure 1.1 Example of the 8088 Registers
Sample Programs
The sample programs show only data declarations and the code that you need
to use the system calls. Unless stated otherwise, each example assumes a
common program skeleton that defines the segments and returns control to
MS-DOS. Each sample program is intended to be executed as a .com file.
Figure 1.2 shows a complete sample program. The unshaded portion shows
what appears in this chapter; the shaded portions are the common skeleton.
------------------------------------------------------------
code segment
assume cs:code,ds:code,es:nothing,ss:nothing
org 100H
start: jmp begin
;
filename db "b:\textfile.asc",0
buffer db 129 dup (?)
handle dw ?
;
begin: open_handle filename,0 ; Open the file
jc error_open ; Routine not shown
mov handle,ax ; Save handle
read_line: read_handle handle,buffer,128 ; Read 128 bytes
jc error_read ; Routine not shown
cmp ax,0 ; End of file?
je return ; Yes, go home
mov bx,ax ; No, AX bytes read
mov buffer[bx],"$" ; To terminate string
display buffer ; See Function 09H
jmp read_line ; Get next 128 bytes
return: end_process 0 ; Return to MS-DOS
last_inst: ; To mark next byte
;
code ends
end start
------------------------------------------------------------
Figure 1.2 Sample Program with Common Skeleton
A macro has been defined for each system call to allow the examples to be
more complete programs, rather than isolated uses of the system calls.
These macros, plus some general-purpose ones, are used in the sample
programs. For instance, the sample program in the preceding figure
includes four such macros: open_handle, read_handle, display, and
end_process. All the macro definitions are listed at the end of this
chapter.
The macros assume the environment for a .com program as described in
Chapter 4; in particular, they assume that all the segment registers
contain the same value. To conserve space, the macros generally leave
error checking to the main code and do not protect registers. This keeps
the macros short, yet useful. You may find that such macros are a
convenient way to include system calls in your assembly-language programs.
Error Handling in Sample Programs
Whenever a system call returns an error code, the sample program shows a
test for the error condition and a jump to an error routine. To conserve
space, the error routines themselves aren't shown. Some error routines
might simply display a message and continue processing. For more serious
errors, the routine might display a message and end the program
(performing any required housekeeping, such as closing files).
Tables 1.16 through 1.19 list the Interrupts and Function Requests in
numeric and alphabetic order.
Table 1.16
MS-DOS Interrupts, Numeric Order
Interrupt Description
──────────────────────────────────────────────────────────────────────────
20H Program Terminate
21H Function Request
22H Terminate Process Exit Address
23H CONTROL+C Handler Address
24H Critical-Error-Handler Address
25H Absolute Disk Read
26H Absolute Disk Write
27H Terminate But Stay Resident
28H-3FH Reserved
──────────────────────────────────────────────────────────────────────────
Table 1.17
MS-DOS Interrupts, Alphabetic Order
Description Interrupt
──────────────────────────────────────────────────────────────────────────
Absolute Disk Read 25H
Absolute Disk Write 26H
CONTROL+C Handler Address 23H
Critical-Error-Handler Address 24H
Function Request 21H
Program Terminate 20H
Reserved 28H-3FH
Terminate Process Exit Address 22H
Terminate But Stay Resident 27H
──────────────────────────────────────────────────────────────────────────
Table 1.18
MS-DOS Function Requests, Numeric Order
╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
Function Description
──────────────────────────────────────────────────────────────────────────
00H Terminate Program
01H Read Keyboard And Echo
02H Display Character
03H Auxiliary Input
Function Description
──────────────────────────────────────────────────────────────────────────
03H Auxiliary Input
04H Auxiliary Output
05H Print Character
06H Direct Console I/O
07H Direct Console Input
08H Read Keyboard
09H Display String
0AH Buffered Keyboard Input
0BH Check Keyboard Status
0CH Flush Buffer, Read Keyboard
0DH Reset Disk
0EH Select Disk
0FH Open File
10H Close File
11H Search For First Entry
12H Search For Next Entry
13H Delete File
14H Sequential Read
15H Sequential Write
Function Description
──────────────────────────────────────────────────────────────────────────
15H Sequential Write
16H Create File
17H Rename File
18H Reserved
19H Get Current Disk
1AH Set Disk Transfer Address
1BH Get Default Drive Data
1CH Get Drive Data
1DH-20H Reserved
21H Random Read
22H Random Write
23H Get File Size
24H Set Relative Record
25H Set Interrupt Vector
26H Create New PSP
27H Random Block Read
28H Random Block Write
29H Parse File Name
2AH Get Date
Function Description
──────────────────────────────────────────────────────────────────────────
2AH Get Date
2BH Set Date
2CH Get Time
2DH Set Time
2EH Set/Reset Verify Flag
2FH Get Disk Transfer Address
30H Get MS-DOS Version Number
31H Keep Process
32H Reserved
33H CONTROL+C Check
34H Reserved
35H Get Interrupt Vector
36H Get Disk Free Space
37H Reserved
38H Get/Set Country Data
39H Create Directory
3AH Remove Directory
3BH Change Current Directory
3CH Create Handle
Function Description
──────────────────────────────────────────────────────────────────────────
3CH Create Handle
3DH Open Handle
3EH Close Handle
3FH Read Handle
40H Write Handle
41H Delete Directory Entry (Unlink)
42H Move File Pointer
43H Get/Set File Attributes (Chmod)
4400H, 4401H IOCtl Data
4402H, 4403H IOCtl Character
4404H, 4405H IOCtl Block
4406H, 4407H IOCtl Status
4408H IOCtl Is Changeable
4409H IOCtl Is Redirected Block
440AH IOCtl Is Redirected Handle
440BH IOCtl Retry
440CH Generic IOCtl (for code page functions)
440DH Generic IOCtl (for devices)
440EH Get IOCtl Drive Map
Function Description
──────────────────────────────────────────────────────────────────────────
440EH Get IOCtl Drive Map
440FH Set IOCtl Drive Map
45H Duplicate File Handle
46H Force Duplicate File Handle
47H Get Current Directory
48H Allocate Memory
49H Free Allocated Memory
4AH Set Block
4B00H, 4B03H Load and Execute Program or Overlay
4CH End Process
4DH Get Return Code of Child Process
4EH Find First File
4FH Find Next File
50H-53H Reserved
54H Get Verify State
55H Reserved
56H Change Directory Entry
57H Get/Set Date/Time of File
58H Get/Set Allocation Strategy
Function Description
──────────────────────────────────────────────────────────────────────────
58H Get/Set Allocation Strategy
59H Get Extended Error
5AH Create Temporary File
5BH Create New File
5C00H, 5C01H Lock/Unlock Files
5DH Reserved
5E00H Get Machine Name
5E02H Set Printer Setup
5E03H Get Printer Setup
5F02H Get Assign-List Entry
5F03H Make Network Connection
5F04H Delete Network Connection
60H-61H Reserved
62H Get PSP
63H,64H Reserved
65H Get Extended Country Information
66H Get/Set Global Code Page
67H Set Handle Count
68H Commit File
Function Description
──────────────────────────────────────────────────────────────────────────
68H Commit File
69H-6BH Reserved
6CH Extended Open/Create
6DH-7FH Reserved
──────────────────────────────────────────────────────────────────────────
Table 1.19
MS-DOS Function Requests, Alphabetic Order
╓┌─┌───────────────────────────────────────────────────────┌─────────────────╖
Description Function
──────────────────────────────────────────────────────────────────────────
Allocate Memory 48H
Auxiliary Input 03H
Auxiliary Output 04H
Buffered Keyboard Input 0AH
Change Current Directory 3BH
Change Directory Entry 56H
Check Keyboard Status 0BH
Description Function
──────────────────────────────────────────────────────────────────────────
Check Keyboard Status 0BH
Close File 10H
Close Handle 3EH
Commit FIle 68H
CONTROL+C Check 33H
Create Directory 39H
Create File 16H
Create Handle 3CH
Create New File 5BH
Create New PSP 26H
Create Temporary File 5AH
Delete Directory Entry (Unlink) 41H
Delete File 13H
Delete Network Connection 5F04H
Direct Console I/O 06H
Direct Console Input 07H
Display Character 02H
Display String 09H
Duplicate File Handle 45H
Description Function
──────────────────────────────────────────────────────────────────────────
Duplicate File Handle 45H
End Process 4CH
Extended Open/Create 6CH
Find First File 4EH
Find Next File 4FH
Flush Buffer, Read Keyboard 0CH
Force Duplicate File Handle 46H
Free Allocated Memory 49H
Generic IOCtl (for devices) 440DH
Generic IOCtl (for code page functions) 440CH
Get Assign-List Entry 5F02H
Get Current Directory 47H
Get Current Disk 19H
Get Date 2AH
Get Default Drive Data 1BH
Get Disk Free Space 36H
Get Disk Transfer Address 2FH
Get Drive Data 1CH
Get Extended Country Information 65H
Description Function
──────────────────────────────────────────────────────────────────────────
Get Extended Country Information 65H
Get Extended Error 59H
Get File Size 23H
Get Interrupt Vector 35H
Get IOCtl Drive Map 440EH
Get Machine Name 5E00H
Get MS-DOS Version Number 30H
Get PSP 62H
Get Printer Setup 5E03H
Get Return Code of Child Process 4DH
Get Time 2CH
Get Verify State 54H
Get/Set Allocation Strategy 58H
Get/Set Country Data 38H
Get/Set Date/Time Of File 57H
Get/Set File Attributes (Chmod) 43H
Get/Set Global Code Page 66H
IOCtl Block 4404H, 4405H
IOCtl Character 4402H, 4403H
Description Function
──────────────────────────────────────────────────────────────────────────
IOCtl Character 4402H, 4403H
IOCtl Data 4400H, 4401H
IOCtl Is Changeable 4408H
IOCtl Is Redirected Block 4409H
IOCtl Is Redirected Handle 440AH
IOCtl Retry 440BH
IOCtl Status 4406H, 4407H
Keep Process 31H
Load and Execute Program 4B00H
Load Overlay 4B03H
Lock/Unlock Files 5C00H, 5C01H
Make Network Connection 5F03H
Move File Pointer 42H
Open File 0FH
Open Handle 3DH
Parse File Name 29H
Print Character 05H
Random Block Read 27H
Random Block Write 28H
Description Function
──────────────────────────────────────────────────────────────────────────
Random Block Write 28H
Random Read 21H
Random Write 22H
Read Handle 3FH
Read Keyboard 08H
Read Keyboard And Echo 01H
Remove Directory 3AH
Rename File 17H
Reserved 18H
Reserved 1DH-20H
Reserved 32H
Reserved 34H
Reserved 37H
Reserved 50H-53H
Reserved 55H
Reserved 5DH
Reserved 60H-61H
Reserved 63H, 64H
Reserved 69H-6BH
Description Function
──────────────────────────────────────────────────────────────────────────
Reserved 69H-6BH
Reserved 6DH-7FH
Reset Disk 0DH
Search for First Entry 11H
Search for Next Entry 12H
Select Disk 0EH
Sequential Read 14H
Sequential Write 15H
Set Block 4AH
Set Date 2BH
Set Disk Transfer Address 1AH
Set Handle Count 67H
Set Interrupt Vector 25H
Set IOCtl Drive Map 440FH
Set Printer Setup 5E02H
Set Relative Record 24H
Set Time 2DH
Set/Reset Verify Flag 2EH
Terminate Program 00H
Description Function
──────────────────────────────────────────────────────────────────────────
Terminate Program 00H
Write Handle 40H
──────────────────────────────────────────────────────────────────────────
A detailed description of each system call follows. These calls are listed
in numeric order, interrupts first, followed by function requests.
──────────────────────────────────────────────────────────────────────────
Note
Unless stated otherwise, in the system call descriptions──both text and
code──all numbers are in hexadecimal.
──────────────────────────────────────────────────────────────────────────
1.11 Interrupts
The following pages describe Interrupts 20H-27H.
────────────────────────────────────────────────────────────────────────────
Program Terminate (Interrupt 20H)
────────────────────────────────────────────────────────────────────────────
Call:
CS
Segment address of Program Segment Prefix
Return:
None
Comments:
Interrupt 20H terminates the current process and returns control to its
parent process. It also closes all open file handles and clears the disk
cache. When this interrupt is issued, CS must contain the segment address
of the Program Segment Prefix.
Interrupt 20H is provided only for compatibility with MS-DOS versions
prior to 2.0. New programs should use Function 4CH (End Process), which
permits returning a completion code to the parent process and does not
require CS to contain the segment address of the Program Segment Prefix.
The following exit addresses are restored from the Program Segment Prefix:
Offset Exit Address
──────────────────────────────────────────────────────────────────────────
0AH Program terminate
0EH CONTROL+C
12H Critical error
──────────────────────────────────────────────────────────────────────────
All file buffers are flushed to disk.
──────────────────────────────────────────────────────────────────────────
Note
You should close all files that have changed in length before issuing
this interrupt. If you do not close a changed file, its length may not
be recorded correctly in the directory. See Functions 10H and 3EH for
a description of the Close File system calls. If sharing is loaded, you
should remove all locks before using Interrupt 20H. See Function 5C00H
(Lock) for more information.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
terminate macro
int 20H
endm
Example:
The following program displays a message and returns to MS-DOS.
message db "displayed by INT20H example". 0DH, 0AH, "$"
;
begin: display message ; see Function 09H
terminate ; THIS INTERRUPT
code ends
end start
────────────────────────────────────────────────────────────────────────────
Function Request (Interrupt 21H)
────────────────────────────────────────────────────────────────────────────
Call:
AH
Function number
Other registers
As specified in individual function
Return:
None
Comments:
As specified in individual function. Interrupt 21H causes MS-DOS to carry
out the function request whose number is in AH. See Section 1.12,
"Function Requests," for a description of the MS-DOS functions.
Example:
To call the Get Time function:
mov ah,2CH ; Get Time is Function 2CH
int 21H ; MS-DOS function request
────────────────────────────────────────────────────────────────────────────
Terminate Process Exit Address (Interrupt 22H)
────────────────────────────────────────────────────────────────────────────
This interrupt may be issued only by MS-DOS; user programs must never
issue it. If you must write your own terminate interrupt handler, use
Function 35H (Get Interrupt Vector) to get the address of the standard
routine, save the address, then use Function 25H (Set Interrupt Vector)
to change the Interrupt 22H entry in the vector table so that it points to
your routine.
When a program terminates, MS-DOS transfers control to the routine that
starts at the address in the Interrupt 22H entry in the vector table. When
MS-DOS creates a program segment, it copies this address into the Program
Segment Prefix, starting at offset 0AH.
────────────────────────────────────────────────────────────────────────────
CONTROL+C Handler Address (Interrupt 23H)
────────────────────────────────────────────────────────────────────────────
When you type CONTROL+C or CONTROL+BREAK (on IBM-compatibles), MS-DOS
transfers control as soon as possible to the routine that starts at the
address in the Interrupt 23H entry in the vector table. When MS-DOS
creates a program segment, it copies the address currently in the
interrupt table into the Program Segment Prefix, starting at offset 0EH.
This interrupt may be issued only by MS-DOS; user programs must never
issue it. If you must write your own CONTROL+C interrupt handler, use
Function 35H (Get Interrupt Vector) to get the address of the standard
routine, save the address, then use Function 25H (Set Interrupt Vector)
to change the Interrupt 23H entry in the vector table to point to your
routine.
If the CONTROL+C routine preserves all registers, it can end with an IRET
instruction (return from interrupt) to continue program execution. If a
user-written interrupt program returns with a long return, the program
uses the carry flag to determine whether or not the program will abort. If
the carry flag is set, it will abort; otherwise, execution will continue
as with a return by IRET.
If a user-written CONTROL+BREAK routine interrupts function calls 09H,
0AH, or buffered I/O, and if it continues execution with an IRET, then I/O
continues from the start of the line. MS-DOS always outputs a CONTROL+C to
the screen when it issues an Interrupt 23H. There is no way to turn this
off.
When the interrupt occurs, all registers are set to the value they had
when the original call to MS-DOS was made. There are no restrictions on
what a CONTROL+C handler can do──including calling MS-DOS functions──as
long as the program restores the registers.
If a CONTROL+C interrupts Function 09H or 0AH (Display String or Buffered
Keyboard Input), the three-byte sequence 03H-0DH-0AH (usually displayed as
C followed by a carriage-return) is sent to the display and the function
resumes at the beginning of the next line.
Suppose a program uses Function 4BH (Load and Execute Program or Overlay)
to create a second Program Segment Prefix and execute a second program,
which then changes the CONTROL+C address in the vector table. MS-DOS
restores this CONTROL+C vector to its original value before returning
control to the calling program.
────────────────────────────────────────────────────────────────────────────
critical-error-handler address (Interrupt 24H)
────────────────────────────────────────────────────────────────────────────
If a critical error occurs during execution of an I/O function
request (this often means a fatal disk error), MS-DOS transfers control to
the routine at the address in the Interrupt 24H entry in the vector table.
When MS-DOS creates a program segment, it copies this address into the
Program Segment Prefix, starting at offset 12H.
This interrupt may be issued only by MS-DOS; user programs must never
issue it. If you must write your own critical-error interrupt handler, use
Function 35H (Get Interrupt Vector) to get the address of the standard
routine, save the address, then use Function 25H (Set Interrupt Vector)
to change the Interrupt 24H entry in the vector table to point to your
routine.
MS-DOS does not issue Interrupt 24H if a failure occurs during execution
of Interrupt 25H (Absolute Disk Read) or Interrupt 26H (Absolute Disk
Write). A command.com error routine handles these errors. This routine
retries the disk operation, then gives you the choice of aborting the
operation, retrying it, allowing the system call to fail and the
application process to continue, or ignoring the error.
The following topics describe the requirements of an Interrupt 24H
routine, including the error codes, registers, and stack.
1.11.1 Conditions upon Entry
After retrying an I/O error five times, MS-DOS issues Interrupt 24H,
unless a File Allocation Table (FAT) or directory sector is involved. In
those cases, DOS performs three retries. The interrupt handler receives
control with interrupts disabled. AX and DI contain error codes, and BP
contains the offset (to the segment address in SI) of a Device Header
control block that describes the device on which the error occurred.
1.11.2 Requirements for an Interrupt 24H Handler
To issue the "Abort, Retry, Fail or Ignore" prompt to a user, a
user-written critical-error handler should first push the flags and
execute a FAR call to the address of the standard Interrupt 24H handler
(the user program that changed the Interrupt 24H vector also should have
saved this address). After a user responds to the prompt, MS-DOS returns
control to the user-written routine.
──────────────────────────────────────────────────────────────────────────
Note
There are source applications which will have trouble handling critical
errors, since this changes the stack frame.
──────────────────────────────────────────────────────────────────────────
The error handler can then do its processing. However, before it does
anything else, it must preserve BX, CX, DX, DS, ES, SS, and SP. Also, the
error handler may use only function calls 01H-0CH (inclusive) and 59H (if
it uses any others, the error handler destroys the MS-DOS stack and leaves
MS-DOS in an unstable state). The contents of the Device Header should not
be changed.
It is recommended that the Interrupt 24H routine fail critical errors and
let the application test for an extended error code when the Interrupt
21H routine returns.
User Stack
This call uses the user stack that contains the following (starting with
the top of the stack):
IP MS-DOS registers from issuing Interrupt 24H
CS
FLAGS
AX User registers at time of original
BX INT 21H
CX
DX
SI
DI
BP
DS
ES
IP From the original INT 21H
CS from the user to MS-DOS
FLAGS
The registers are set such that if the user-written error handler issues
an IRET, MS-DOS responds according to the value in AL:
AL Action
──────────────────────────────────────────────────────────────────────────
0 Ignore the error.
1 Retry the operation.
2 Abort the program by issuing Interrupt 23H.
3 Fail the system call that is in progress.
──────────────────────────────────────────────────────────────────────────
Notice that the ignore option may cause unexpected results, such as
causing MS-DOS to behave as if an operation had completed successfully.
Disk Error Code in AX
If bit 7 of AH is 0, the error occurred on a disk drive. AL contains the
failing drive (0=A, 1=B, etc.). Bit 0 of AH specifies whether the error
occurred during a read or write operation (0=read, 1=write), and bits 1
and 2 of AH identify the area of the disk where the error occurred:
Bits 1-2 Location of error
──────────────────────────────────────────────────────────────────────────
00 MS-DOS area
01 File Allocation Table
10 Directory
11 Data area
──────────────────────────────────────────────────────────────────────────
Bits 3-5 of AH specify valid responses to the error prompt:
Bit Value Response
──────────────────────────────────────────────────────────────────────────
3 0 Fail not allowed
1 Fail allowed
4 0 Retry not allowed
1 Retry allowed
5 0 Ignore not allowed
1 Ignore allowed
──────────────────────────────────────────────────────────────────────────
If you specify Retry but it isn't allowed, MS-DOS changes it to Fail. If
you specify Ignore but it isn't allowed, MS-DOS changes it to Fail. If you
specify Fail but it isn't allowed, MS-DOS changes it to Abort. The Abort
response is always allowed.
Other Device Error Code in AX
If bit 7 of AH is 1, either the memory image of the File Allocation Table
(FAT) is bad or an error occurred on a character device. The device header
pointed to by BP:SI contains a WORD of attribute bits that identify the
type of device and, therefore, the type of error.
The word of attribute bits is at offset 04H of the Device Header. Bit 15
specifies the type of device (0=block, 1=character).
If bit 15 is 0 (block device), the error was a bad memory image of the
FAT.
If bit 15 is 1 (character device), the error was on a character device. DI
contains the error code, the contents of AL are undefined, and bits 0-3 of
the attribute word have the following meaning:
Bit Meaning if Set
──────────────────────────────────────────────────────────────────────────
0 Current standard input
1 Current standard output
2 Current null device
3 Current clock device
──────────────────────────────────────────────────────────────────────────
See Chapter 2, "MS-DOS Device Drivers," for a complete description of the
Device Header control block.
Error Code in DI
The high byte of DI is undefined. The low byte contains the following
error codes:
Error code Description
──────────────────────────────────────────────────────────────────────────
0 Attempt to write on write-protected disk
1 Unknown unit
2 Drive not ready
3 Unknown command
4 CRC error in data
5 Bad drive request structure length
6 Seek error
7 Unknown media type
8 Sector not found
9 Printer out of paper
A Write fault
B Read fault
C General failure
──────────────────────────────────────────────────────────────────────────
A user-written Interrupt 24H handler can use Function 59H (Get Extended
Error) to get detailed information about the error that caused the
interrupt to be issued.
────────────────────────────────────────────────────────────────────────────
Absolute Disk Read (Interrupt 25H)
────────────────────────────────────────────────────────────────────────────
Call:
AL
Drive number
DS:BX
Disk Transfer Address or
Far pointer to parameter packet if CX = -1
CX
Number of sectors or -1
DX
Beginning relative sector
Return:
AL
Error code if CF=1
FLAGS
CF = 0 if successful
= 1 if not successful
AX
0207 if attempt made to access partition larger
than 32 megabytes with MS-DOS 3.3 or earlier.
Comments:
The registers must contain the following:
Register Contents
──────────────────────────────────────────────────────────────────────────
AL Drive number (0=A, 1=B, etc.)
DS:BX Offset of Disk Transfer Address or far pointer to
parameter packet if CX = -1
CX Number of sectors to read or -1
DX Beginning relative sector
──────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────
Warning
Avoid using this function unless absolutely necessary. Instead, you
should access files through normal MS-DOS function requests. There is no
guarantee of upward compatibility for the Absolute Disk I/O in future
releases of MS-DOS.
──────────────────────────────────────────────────────────────────────────
If CX = -1, DS:BX is the far pointer to the parameter packet. The
parameter packet API provides access to partitions larger than 32
megabytes. The parameter packet contains:
Starting sector number dd ?
Number of sectors dw ?
Transfer address dd ?
Interrupt 25H transfers control to the device driver and reads from the
disk to the Disk-Transfer Address the number of sectors specified in CX.
The interrupt has the same requirements as and processes identically to
Interrupt 26H (Absolute Disk Write), except that it reads data rather
than writes it. Also, since this interrupt does not check your input
parameters too closely, make sure they are reasonable. If you use
unreasonable parameters, you may get strange results or cause your system
to crash.
──────────────────────────────────────────────────────────────────────────
Note
This call destroys all registers except the segment registers. So before
issuing the interrupt, save any registers that your program uses.
──────────────────────────────────────────────────────────────────────────
The system pushes the flags at the time of the call; they are still there
upon return. To prevent uncontrolled growth, be sure to pop the stack upon
return.
If the disk operation is successful, the Carry Flag (CF) is 0. If the disk
operation is not successful, CF is 1 and AL contains the MS-DOS error code
(see Interrupt 24H earlier in this section for the codes and their
meanings).
Macro Definition:
abs_disk_read macro disk,buffer,num_sectors,first_sector
mov al,disk
mov bx,offset buffer
mov cx,num_sectors
mov dx,first_sector
int 25H
popf
endm
Example:
The following program copies the contents of a single-sided disk in drive
A to the disk in drive B.
prompt db "Source in A, target in B",0DH,0AH
db "Any key to start. $"
first dw 0
buffer db 60 dup (512 dup (?)) ; 60 sectors
;
begin: display prompt ; see Function 09H
read_kbd ; see Function 08H
mov cx,6 ; copy 6 groups of
; 60 sectors
copy: push cx ; save the loop counter
abs_disk_read 0,buffer,60,first ; THIS INTERRUPT
abs_disk_write 1,buffer,60,first ; see INT 26H
add first,60 ; do the next 60 sectors
pop cx ; restore the loop counter
loop copy
The following code is an example of reading the absolute sector with
Interrupt 25H.
mov al, 'C'-'A' ; select drive C:
mov cx,-1 ; request new absolute format
mov bx,code ; set ds:bx up to point to parameter
mov ds,bx ; packet with sector number, length
mov bx,offset par_pck ; and transfer address information
int 25H ; do operation
jc error_on_read ; check for errors
par_pck:
dd 12345H ; absolute sector number to read=12345H
dw 2 ; number of sectors to read
dd buffer ; transfer address
buffer db 1024 dup (0) ; target buffer for read
────────────────────────────────────────────────────────────────────────────
Absolute Disk Write (Interrupt 26H)
────────────────────────────────────────────────────────────────────────────
Call:
AL
Drive number
DS:BX
Disk Transfer Address or
Far pointer to parameter packet if CX = -1
CX
Number of sectors or -1
DX
Beginning relative sector
Return:
AL
Error code if CF = 1
FLAGS
CF = 0 if successful
= 1 if not successful
Comments:
──────────────────────────────────────────────────────────────────────────
Warning
Avoid using this function unless absolutely necessary. Instead, you
should access files through normal MS-DOS function requests. There is no
guarantee of upward compatibility for the Absolute Disk I/O in future
releases of MS-DOS.
──────────────────────────────────────────────────────────────────────────
The registers must contain the following:
Register Contents
──────────────────────────────────────────────────────────────────────────
AL Drive number (0=A, 1=B, etc.)
DS:BX Offset of Disk Transfer Address or far pointer to
parameter packet if CX = -1
CX Number of sectors to write or -1
DX Beginning relative sector
──────────────────────────────────────────────────────────────────────────
This interrupt transfers control to MS-DOS. The number of sectors
specified in CX is written from the Disk Transfer Address to the disk. Its
requirements and processing are identical to Interrupt 25H (Absolute Disk
Read), except data is written to the disk rather than read from it. Also,
since Interrupt 26H does not check your input parameters too closely, make
sure they are reasonable. If you use unreasonable parameters, you may get
strange results or cause your system to crash.
If CX = -1, DS:BX is the far pointer to the parameter packet. The
parameter packet contains:
Starting sector number dd ?
Number of sectors dw ?
Transfer address dd ?
──────────────────────────────────────────────────────────────────────────
Note
This call destroys all registers except the segment registers. So before
issuing the interrupt, be sure to save any registers your program uses.
──────────────────────────────────────────────────────────────────────────
The system pushes the flags at the time of the call; they are still there
upon return. To prevent uncontrolled growth, be sure to pop the stack upon
return.
If the disk operation is successful, the Carry Flag (CF) is 0. If the disk
operation is not successful, CF is 1 and AL contains the MS-DOS error code
(see Interrupt 24H for the codes and their meanings).
Macro Definition:
abs_disk_write macro disk,buffer,num_sectors,first_sector
mov al,disk
mov bx,offset buffer
mov cx,num_sectors
mov dx,first_sector
int 26H
popf
endm
Example:
The following program copies the contents of a single-sided disk in drive
A to the disk in drive B, verifying each write. It uses a buffer of 32
kilobytes.
off equ 0
on equ 1
;
prompt db "Source in A, target in B",0DH,0AH
db "Any key to start. $"
first dw 0
buffer db 60 dup (512 dup (?)) ; 60 sectors
;
begin: display prompt ; see Function 09H
read_kbd ; see Function 08H
verify on ; see Function 2EH
mov cx,6 ; copy 6 groups of 60 sectors
copy: push cx ; save the loop counter
abs_disk_read 0,buffer,60,first ; see INT 25H
abs_disk_write 1,buffer,60,first ; THIS INTERRUPT
add first,60 ; do the next 60 sectors
pop cx ; restore the loop counter
loop copy
verify off ; see Function 2EH
The following code is an example of writing the absolute sector with
Interrupt 26H.
mov al,'C'-'A' ; select drive C:
mov cx,-1 ; request new absolute format
mov bx,code ; set ds:bx up to point to parameter
mov ds,bx ; packet with sector number, length
mov bx,offset par_pck ; and transfer address information
int 26H ; do operation
jc error_on_write ; check for errors
par_pck:
dd 12345H ; absolute sector number to write=12345H
dw 2 ; number of sectors to write
dd buffer ; transfer address
buffer db 1024 dup (0) ; target buffer for write
────────────────────────────────────────────────────────────────────────────
Terminate But Stay Resident (Interrupt 27H)
────────────────────────────────────────────────────────────────────────────
Call:
CS:DX
Pointer to first byte following
last byte of code.
Return:
None
Comments:
This interrupt is provided only for compatibility with MS-DOS versions
prior to 2.0. Unless your resident program must be compatible with MS-DOS
versions before 2.0, you should use Function 31H (Keep Process) to
install it. Function 31H lets programs larger than 64K remain resident
and allows return information to be passed.
However, Interrupt 27H, which is often used to install device-specific
interrupt handlers, forces programs that are up to 64K to remain resident
after they terminate.
DX must contain the offset (from the segment address in CS) of the first
byte that follows the last byte of code in the program. When Interrupt 27H
is executed, the program terminates and control returns to MS-DOS, but the
program is not overlaid by other programs. Files left open are not closed.
When the interrupt is called, CS must contain the segment address of the
Program Segment Prefix (the value of DS and ES when execution started).
.Exe programs that are loaded into high memory must not use this
interrupt. Similarly, since it restores the Interrupt 22H, 23H, and
24H vectors, you should not use Interrupt 27H to install new CONTROL+C or
critical-error handlers.
Macro Definition:
stay_resident macro last_instruc
mov dx,offset last_instruc
inc dx
int 27H
endm
Example:
Since the most common use of Interrupt 27H is to install a
machine-specific routine, there is no general example that applies. The
macro definition, however, shows the calling syntax.
1.12 Function Requests
The following pages describe function calls 00H-68H.
────────────────────────────────────────────────────────────────────────────
Terminate Program (Function 00H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 00H
CS
Segment address of
Program Segment Prefix
Return:
None
Comments:
Function 00H performs the same function as Interrupt 20H. It terminates
the current process and returns control to its parent process. It also
closes all open file handles and clears the disk cache. When this
interrupt is issued, CS must contain the segment address of the Program
Segment Prefix.
The CS register must contain the segment address of the Program Segment
Prefix before you call this interrupt.
The following exit addresses are restored from the specified offsets in
the Program Segment Prefix:
Offset Exit Address
──────────────────────────────────────────────────────────────────────────
0AH Program terminate
0EH CONTROL+C
12H Critical error
──────────────────────────────────────────────────────────────────────────
All file buffers are flushed to disk.
──────────────────────────────────────────────────────────────────────────
Warning
Close all files that have changed in length before calling this
function. If you do not close a changed file, its length is not
correctly recorded in the directory. See Function 10H for a description
of the Close File system call.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
terminate_program macro
xor ah,ah
int 21H
endm
Example:
The following program displays a message and returns to MS-DOS. It uses
only the opening portion of the sample program skeleton shown in Figure
1.2.
message db "Displayed by FUNC00H example", 0DH,0AH,"$"
;
begin: display message ; see Function 09H
terminate_program ; THIS FUNCTION
code ends
end start
────────────────────────────────────────────────────────────────────────────
Read Keyboard and Echo (Function 01H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 01H
Return:
AL
Character typed
Comments:
Function 01H waits for a character to be read from standard input, then
echoes the character to standard output and returns it in AL. If the
character is CONTROL+C, it executes Interrupt 23H.
Macro Definition:
read_kbd_and_echo macro
mov ah, 01H
int 21H
endm
Example:
The following program displays and prints characters as you type them. If
you press the ENTER key, the program sends a linefeed/carriage-return
sequence to both the display and the printer.
begin: read_kbd_and_echo ; THIS FUNCTION
print_char al ; see Function 05H
cmp al,0DH ; is it a CR?
jne begin ; no, print it
print_char 0AH ; see Function 05H
display_char 0AH ; see Function 02H
jmp begin ; get another character
────────────────────────────────────────────────────────────────────────────
Display Character (Function 02H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 02H
DL
Character to be displayed
Return:
None
Comments:
Function 02H sends the character in DL to standard output. If you press
CONTROL+C, it issues Interrupt 23H.
Macro Definition:
display_char macro character
mov dl,character
mov ah,02H
int 21H
endm
Example:
The following program converts lowercase characters to uppercase before
displaying them.
begin: read_kbd ; see Function 08H
cmp al,"a"
jl uppercase ; don't convert
cmp al,"z"
jg uppercase ; don't convert
sub al,20H ; convert to ASCII code
; for uppercase
uppercase: display_char al ; THIS FUNCTION
jmp begin: ; get another character
────────────────────────────────────────────────────────────────────────────
Auxiliary Input (Function 03H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 03H
Return:
AL
Character from auxiliary device
Comments:
Function 03H waits for a character from standard auxiliary devices (AUX,
COM1, COM2, COM3, COM4), then returns the character in AL. This system
call does not return a status or error code.
If you press CONTROL+C, it issues Interrupt 23H.
Macro Definition:
aux_input macro
mov ah,03H
int 21H
endm
Example:
The following program prints characters as soon as it receives them from
the auxiliary device. It stops printing when it receives an end-of-file
character (ASCII 26, or CONTROL+Z).
begin: aux_input ; THIS FUNCTION
cmp al,1AH ; end of file?
je return ; yes, all done
print_char al ; see Function 05H
jmp begin ; get another character
────────────────────────────────────────────────────────────────────────────
Auxiliary Output (Function 04H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 04H
DL
Character for auxiliary device
Return:
None
Comments:
Function 04H sends the character in DL to standard auxiliary. This system
call does not return a status or error code.
If you press CONTROL+C, it issues Interrupt 23H.
Macro Definition:
aux_output macro character
mov dl,character
mov ah,04H
int 21H
endm
Example:
The following program gets a series of strings of up to 80 bytes from the
keyboard and sends each string to the auxiliary device. It stops when you
type a null string (carriage-return only).
string db 81 dup(?) ; see Function 0AH
;
begin: get_string 80,string ; see Function 0AH
cmp string[1],0 ; null string?
je return ; yes, all done
mov cx, word ptr string[1] ; get string length
mov bx,0 ; set index to 0
send_it: aux_output string[bx+2] ; THIS FUNCTION
inc bx ; bump index
loop send_it ; send another character
jmp begin ; get another string
────────────────────────────────────────────────────────────────────────────
Print Character (Function 05H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 05H
DL
Character for printer
Return:
None
Comments:
Function 05H sends the character in DL to the standard printer. If you
press CONTROL+C, it issues Interrupt 23H. This function does not return a
status or error code.
Macro Definition:
print_char macro character
mov dl,character
mov ah,05H
int 21H
endm
Example:
The following program prints a walking test pattern on the printer. It
stops if you press CONTROL+C.
line_num db 0
;
begin: mov cx,60 ; print 60 lines
start_line: mov bl,33 ; first printable ASCII
; character (!)
add bl,line_num ; to offset one character
push cx ; save number-of-lines counter
mov cx,80 ; loop counter for line
print_it: print_char bl ; THIS FUNCTION
inc bl ; move to next ASCII character
cmp bl,126 ; last printable ASCII
; character (~)
jl no_reset ; not there yet
mov bl,33 ; start over with (!)
no_reset: loop print_it ; print another character
print_char 0DH ; carriage return
print_char 0AH ; linefeed
inc line_num ; to offset 1st char. of line
pop cx ; restore #-of-lines counter
loop start_line ; print another line
────────────────────────────────────────────────────────────────────────────
Direct Console I/O (Function 06H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 06H
DL
See text
Return:
AL
If DL = FFH before call,
then zero flag not set means AL
has character from standard input.
Zero flag set means there was not
a character to get, and AL = 0.
Comments:
The action of Function 06H depends on the value in DL when the function is
called:
Value in DL Action
──────────────────────────────────────────────────────────────────────────
FFH If a character has been read from standard input, it is
returned in AL and the zero flag is cleared (0); if a
character has not been read, the zero flag is set (1).
Not FFH The character in DL is sent to standard output.
──────────────────────────────────────────────────────────────────────────
This function does not check for CONTROL+C.
Macro Definition:
dir_console_io macro switch
mov dl,switch
mov ah,06H
int 21H
endm
Example:
The following program sets the system clock to 0 and displays the time
continuously. When you type any character, the display freezes; when you
type any character again, the clock is reset to 0 and the display starts
again.
time db "00:00:00.00",0DH,0AH,"$" ; see Function 09H
; ; for explanation of $
;
begin: set_time 0,0,0,0 ; see Function 2DH
read_clock: get_time ; see Function 2CH
CONVERT ch,time ; see end of chapter
CONVERT cl,time[3] ; see end of chapter
CONVERT dh,time[6] ; see end of chapter
CONVERT dl,time[9] ; see end of chapter
display time ; see Function 09H
dir_console_io FFH ; THIS FUNCTION
cmp al,0 ; character typed?
jne stop ; yes, stop timer
jmp read_clock ; no, keep timer
; running
stop: read_kbd ; see Function 08H
jmp begin ; start over
────────────────────────────────────────────────────────────────────────────
Direct Console Input (Function 07H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 07H
Return:
AL
Character from keyboard
Comments:
Function 07H waits for a character to be read from standard input, then
returns it in AL. This function does not echo the character or check for
CONTROL+C. (For a keyboard input function that echoes or checks for
CONTROL+C, see Function 01H or 08H.)
Macro Definition:
dir_console_input macro
mov ah,07H
int 21H
endm
Example:
The following program prompts for a password (eight characters maximum)
and places the characters into a string without echoing them.
password db 8 dup(?)
prompt db "Password: $" ; see Function 09H for
; explanation of $
begin: display prompt ; see Function 09H
mov cx,8 ; maximum length of password
xor bx,bx ; so BL can be used as index
get_pass: dir_console_input ; THIS FUNCTION
cmp al,0DH ; was it a carriage return?
je return ; yes, all done
mov password[bx],al ; no, put character in string
inc bx ; bump index
loop get_pass ; get another character
────────────────────────────────────────────────────────────────────────────
Read Keyboard (Function 08H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 08H
Return:
AL
Character from keyboard
Comments:
Function 08H waits for a character to be read from standard input, then
returns it in AL. If you press CONTROL+C, it issues Interrupt 23H. This
function does not echo the character. (For a keyboard input function that
echoes the character or checks for CONTROL+C, see Function 01H.)
Macro Definition:
read_kbd macro
mov ah,08H
int 21H
endm
Example:
The following program prompts for a password (eight characters maximum)
and places the characters into a string without echoing them.
password db 8 dup(?)
prompt db "Password: $" ; see Function 09H
; for explanation of $
begin: display prompt ; see Function 09H
mov cx,8 ; maximum length of password
xor bx,bx ; BL can be an index
get_pass: read_kbd ; THIS FUNCTION
cmp al,0DH ; was it a carriage return?
je return ; yes, all done
mov password[bx],al ; no, put char. in string
inc bx ; bump index
loop get_pass ; get another character
────────────────────────────────────────────────────────────────────────────
Display String (Function 09H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 09H
DS:DX
Pointer to string to be displayed
Return:
None
Comments:
Function 09H sends to standard output a string that ends with "$" (the $
is not displayed).
The DX register must contain the offset (from the segment address in DS)
of the string.
Macro Definition:
display macro string
mov dx,offset string
mov ah,09H
int 21H
endm
Example:
The following program displays the hexadecimal code of the key that is
typed.
table db "0123456789ABCDEF"
result db " - 00H",0DH,0AH,"$" ; see text for
; explanation of $
begin: read_kbd_and_echo ; see Function 01H
xor ah,ah ; clear upper byte
convert ax,16,result[3] ; see end of chapter
display result ; THIS FUNCTION
jmp begin ; do it again
────────────────────────────────────────────────────────────────────────────
Buffered Keyboard Input (Function 0AH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 0AH
DS:DX
Pointer to input buffer
Return:
None
Comments:
Function 0AH gets a string from standard input. DX must contain the offset
(from the segment address in DS) of an input buffer of the following form:
Byte Contents
──────────────────────────────────────────────────────────────────────────
1 Maximum number of characters in buffer, including the
carriage return (you must set this value).
2 Actual number of characters typed, not counting the
carriage return (the function sets this value).
3-n Buffer; must be at least as long as the number in byte
──────────────────────────────────────────────────────────────────────────
Characters are read from standard input and placed in the buffer beginning
at the third byte until an ENTER character (ASCII 0DH) is read. If the
buffer fills to one less than the maximum, additional characters read are
ignored and ASCII 07H (Bel) is sent to standard output until an ENTER
character is read. If you type the string at the console, it can be edited
as it is being entered. If you press CONTROL+C, it issues Interrupt 23H.
MS-DOS sets the second byte of the buffer to the number of characters read
(not counting the carriage return).
Macro Definition:
get_string macro limit,string
mov dx,offset string
mov string,limit
mov ah,0AH
int 21H
endm
Example:
The following program gets a 16-byte (maximum) string from the keyboard
and fills a 24-line by 80-character screen with it.
buffer label byte
max_length db ? ; maximum length
chars_entered db ? ; number of chars.
string db 17 dup (?) ; 16 chars + CR
strings_per_line dw 0 ; how many strings
; fit on line
crlf db 0DH,0AH
;
begin: get_string 17,buffer ; THIS FUNCTION
xor bx,bx ; so byte can be
; used as index
mov bl,chars_entered ; get string length
mov buffer[bx+2],"$" ; see Function 09H
mov al,50H ; columns per line
cbw
div chars_entered ; times string fits
; on line
xor ah,ah ; clear remainder
mov strings_per_line,ax ; save col. counter
mov cx,24 ; row counter
display_screen: push cx ; save it
mov cx,strings_per_line ; get col. counter
display_line: display string ; see Function 09H
loop display_line
display crlf ; see Function 09H
pop cx ; get line counter
loop display_screen ; display 1 more line
────────────────────────────────────────────────────────────────────────────
Check Keyboard Status (Function 0BH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 0BH
Return:
AL
00H = no characters in type-ahead buffer
FFH = characters in type-ahead buffer
Comments:
Function 0BH checks whether characters are available from standard input
(if standard input has not been redirected, it checks the type-ahead
buffer). If characters are available, AL returns FFH; if not, AL returns
0. If CONTROL+C is in the buffer, it issues Interrupt 23H.
Macro Definition:
check_kbd_status macro
mov ah,0BH
int 21H
endm
Example:
The following program displays the time continuously until you press any
key:
time db "00:00:00.00",0DH,0AH,"$"
.
.
begin: get_time ; see Function 2CH
byte_to_dec ch,time ; see end of chapter
byte_to_dec cl,time[3] ; see end of chapter
byte_to_dec dh,time[6] ; see end of chapter
byte_to_dec dl,time[9] ; see end of chapter
display time ; see Function 09H
check_kbd_status ; THIS FUNCTION
cmp al,0FFH ; has a key been typed?
je return ; yes, go home
jmp begin ; no, keep displaying
; time
────────────────────────────────────────────────────────────────────────────
Flush Buffer, Read Keyboard (Function 0CH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 0CH
AL
1, 6, 7, 8, or 0AH = the
corresponding function
is called.
Any other value = no
further processing.
Return:
AL
00H = Type-ahead buffer
was flushed; no other
processing performed.
Comments:
Function 0CH empties the standard input buffer (if standard input has not
been redirected, Function 0CH empties the type-ahead buffer). Further
processing depends on the value in AL when the function is called.
AL Action
──────────────────────────────────────────────────────────────────────────
1,6,7,8, or 0AH The corresponding MS-DOS function is executed.
Any other value No further processing; AL returns 0.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
flush_and_read_kbd macro switch
mov al,switch
mov ah,0CH
int 21H
endm
Example:
The following program both displays and prints characters as you type
them. If you press the ENTER key, the program sends a
carriage-return/linefeed sequence to both the display and the printer.
begin: flush_and_read_kbd 1 ; THIS FUNCTION
print_char al ; see Function 05H
cmp al,0DH ; is it a carriage return?
jne begin ; no, print it
print_char 0AH ; see Function 05H
display_char 0AH ; see Function 02H
jmp begin ; get another character
────────────────────────────────────────────────────────────────────────────
Reset Disk (Function 0DH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 0DH
Return:
None
Comments:
Function 0DH flushes all file buffers to ensure that the internal buffer
cache matches the disks in the drives. It writes out buffers that have
been modified and marks all buffers in the internal cache as free. This
function request is normally used to force a known state of the system;
CONTROL+C interrupt handlers should call this function.
This function does not update directory entries; you must close changed
files to update their directory entries (see Function 10H, Close File).
Macro Definition:
reset_disk macro
mov ah,0DH
int 21H
endm
Example:
The following program flushes all file buffers and selects disk A.
begin: reset_disk
select_disk "A"
────────────────────────────────────────────────────────────────────────────
Select Disk (Function 0EH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 0EH
DL
Logical drive number
(0 = A, 1 = B, etc.)
Return:
AL
Number of logical drives
Comments:
Function 0EH selects the drive specified in DL (0=A, 1=B, etc.) as the
current logical drive. AL returns the number of logical drives.
──────────────────────────────────────────────────────────────────────────
Note
For future compatibility, treat the value returned in AL with care. For
example, if AL returns 5, it is not safe to assume that drives A, B, C,
D, and E are all valid drive designators.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
select_disk macro disk
mov dl,disk[-64]
mov ah,0EH
int 21H
endm
Example:
The following program toggles between drive A and drive B to select the
current drive (in a two-drive system).
begin: current_disk ; see Function 19H
cmp al,00H ; drive A: selected?
je select_b ; yes, select B
select_disk "A" ; THIS FUNCTION
jmp return
select_b: select_disk "B" ; THIS FUNCTION
────────────────────────────────────────────────────────────────────────────
Open File (Function 0FH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 0FH
DS:DX
Pointer to unopened FCB
Return:
AL
00H = Directory entry found
FFH = No directory entry found
Comments:
Function 0FH opens a file. DX must contain the offset (from the segment
address in DS) of an unopened File Control Block (FCB). This call searches
the disk directory for the named file.
If the call finds a directory entry for the file, AL returns 0 and the FCB
is filled as follows:
■ If the drive code was 0 (current drive), it is changed to the actual
drive used (1=A, 2=B, etc.). This lets you change the current drive
without interfering with subsequent operations on this file.
■ Current Block (offset 0CH) is set to 0.
■ Record Size (offset 0EH) is set to the system default of 128.
■ File Size (offset 10FH), Date of Last Write (offset 14H), and Time of
Last Write (offset 16H) are set from the directory entry.
Before performing a sequential disk operation on the file, you must set
the Current Record field (offset 20H). Before performing a random disk
operation on the file, you must set the Relative Record field (offset
21H). If the default record size (128 bytes) is not correct, set it to the
correct length.
If the call doesn't find a directory entry for the file, or if the file
has the hidden or system attribute, AL returns FFH.
Macro Definition:
open macro fcb
mov dx,offset fcb
mov ah,0FH
int 21H
endm
Example:
The following program prints a file named textfile.asc that is on the disk
in drive B. If a partial record is in the buffer at end-of-file, the
routine that prints the partial record prints characters until it
encounters an end-of-file mark (ASCII 26, or CONTROL+Z).
fcb db 2,"TEXTFILEASC"
db 26 dup (?)
buffer db 128 dup (?)
;
begin: set_dta buffer ; see Function 1AH
open fcb ; THIS FUNCTION
read_line: read_seq fcb ; see Function 14H
cmp al,02H ; end of file?
je all_done ; yes, go home
cmp al,00H ; more to come?
jg check_more ; no, check for partial
; record
mov cx,80H ; yes, print the buffer
xor si,si ; set index to 0
print_it: print_char buffer[si] ; see Function 05H
inc si ; bump index
loop print_it ; print next character
jmp read_line ; read another record
check_more: cmp al,03H ; part. record to print?
jne all_done ; no
mov cx,80H ; yes, print it
xor si,si ; set index to 0
find_eof: cmp buffer[si],26 ; end-of-file mark?
je all_done ; yes
print_char buffer[si] ; see Function 05H
inc si ; bump index to next
; character
loop find_eof
all_done: close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Close File (Function 10H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 10H
DS:DX
Pointer to opened FCB
Return:
AL
00H = Directory entry found
FFH = No directory entry found
Comments:
Function 10H closes a file. DX must contain the offset (to the segment
address in DS) of an opened FCB. This call searches the disk directory for
the file named in the FCB. If it finds a directory entry for the file, it
compares the location of the file with the corresponding entries in the
FCB. The call then updates the directory entry, if necessary, to match the
FCB, and AL returns 0.
After you change a file, you must call this function to update the
directory entry. You should close any FCB (even one for a file that has
not been changed) when you no longer need access to a file.
If this call doesn't find a directory entry for the file, AL returns FFH.
Macro Definition:
close macro fcb
mov dx,offset fcb
mov ah,10H
int 21H
endm
Example:
The following program checks the first byte of the file named mod1.bas in
drive B to see if it is FFH and, if it is, prints a message.
message db "Not saved in ASCII format",0DH,0AH,"$"
fcb db 2,"MOD1 BAS"
db 26 dup (?)
buffer db 128 dup (?)
;
begin: set_dta buffer ; see Function 1AH
open fcb ; see Function 0FH
read_seq fcb ; see Function 14H
cmp buffer,0FFH ; is first byte FFH?
jne all_done ; no
display message ; see Function 09H
all_done: close fcb ; THIS FUNCTION
────────────────────────────────────────────────────────────────────────────
Search for First Entry (Function 11H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 11H
DS:DX
Pointer to unopened FCB
Return:
AL
00H = Directory entry found
FFH = No directory entry found
Comments:
Function 11H searches the disk directory for the first matching filename.
DX must contain the offset (from the segment address in DS) of an unopened
FCB. The filename in the FCB can include wildcard characters. To search
for hidden or system files, DX must point to the first byte of an extended
FCB prefix.
If this call does not find a directory entry for the filename in the FCB,
AL returns FFH.
But if the call does find a directory entry for the filename in the FCB,
AL returns 0 and the call creates an unopened FCB of the same type (normal
or extended) at the Disk Transfer Address as follows:
1. If the search FCB was normal, the first byte at the Disk Transfer
Address is set to the drive number used in the search (1=A, 2=B, etc.)
and the next 32 bytes contain the directory entry.
2. If the search FCB was extended, the first byte at the Disk Transfer
Address is set to FFH, the next 5 bytes are set to 00H, and the
following byte is set to the value of the attribute byte in the search
FCB. The remaining 33 bytes are the same as the result of the normal
FCB (drive number and 32 bytes of directory entry).
If you use Function 12H (Search for Next Entry) to continue searching for
matching filenames, you must not alter or open the original FCB at DS:DX.
The attribute field is the last byte of the extended FCB fields that
precede the FCB (see Extended FCB in Section 1.9.1). If the attribute
field is zero, Function 11H searches only normal file entries. It does not
search directory entries for hidden files, system files, volume label, and
subdirectories.
If the attribute field is hidden file, system file, or subdirectory entry
(02H, 04H, or 10H), or any combination of those values, this call also
searches all normal file entries. To search all directory entries except
the volume label, set the attribute byte to 16H (hidden file and system
file and subdirectory entry).
If the attribute field is Volume ID (08H), the call searches only the
volume label entry.
Macro Definition:
search_first macro fcb
mov dx,offset fcb
mov ah,11H
int 21H
endm
Example:
The following program verifies the existence of a file named report.asm on
the disk in drive B.
yes db "FILE EXISTS.$"
no db "FILE DOES NOT EXIST.$"
crlf db 0DH,0AH,"$"
fcb db 2,"REPORT *ASM"
db 26 dup (?)
buffer db 128 dup (?)
;
begin: set_dta buffer ; see Function 1AH
search_first fcb ; THIS FUNCTION
cmp al,0FFH ; directory entry found?
je not_there ; no
display yes ; see Function 09H
jmp continue
not_there: display no ; see Function 09H
continue: display crlf ; see Function 09H
────────────────────────────────────────────────────────────────────────────
Search for Next Entry (Function 12H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 12H
DS:DX
Pointer to unopened FCB
Return:
AL
00H = Directory entry found
FFH = No directory entry found
Comments:
After you use Function 11H (Search for First Entry), you can use Function
12H to find any additional directory entries that match a filename
(containing wildcard characters). Function 12H searches the disk directory
for the next matching name. DX must contain the offset (from the segment
address in DS) of an FCB specified in a previous call to Function 11H. To
search for hidden or system files, DX must point to the first byte of an
extended FCB prefix──one that includes the appropriate attribute value.
If the call does not find a directory entry for the filename in the FCB,
AL returns FFH.
But if the call does find a directory entry for the filename in the FCB,
AL returns 0 and the call creates an unopened FCB of the same type (normal
or extended) at the Disk Transfer Address (see Function 11H for a
description of how the unopened FCB is formed).
Macro Definition:
search_next macro fcb
mov dx,offset fcb
mov ah,12H
int 21H
endm
Example:
The following program displays the number of files on the disk in drive B.
message db "No files",0DH,0AH,"$"
files db 0
fcb db 2,"???????????"
db 26 dup (?)
buffer db 128 dup (?)
;
begin: set_dta buffer ; see Function 1AH
search_first fcb ; see Function 11H
cmp al,0FFH ; directory entry found?
je all_done ; no, no files on disk
inc files ; yes, increment file
; counter
search_dir: search_next fcb ; THIS FUNCTION
cmp al,0FFH ; directory entry found?
je done ; no
inc files ; yes, increment file
; counter
jmp search_dir ; check again
done: convert files,10,message ; see end of chapter
all_done: display message ; see Function 09H
────────────────────────────────────────────────────────────────────────────
Delete File (Function 13H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 13H
DS:DX
Pointer to unopened FCB
Return:
AL
00H = Directory entry found
FFH = No directory entry found
Comments:
Function 13H deletes a file. DX must contain the offset (from the segment
address in DS) of an unopened FCB. This call searches the directory for a
matching filename. The filename in the FCB can contain wildcard
characters.
If the call does not find a matching directory entry, AL returns FFH.
But if the call does find a matching directory entry, AL returns 0 and the
call deletes the entry from the directory. If the filename contains a
wildcard character, the call will delete all files that match.
Do not delete open files.
Macro Definition:
delete macro fcb
mov dx,offset fcb
mov ah,13H
int 21H
endm
Example:
The following program deletes each file on the disk in drive B that was
last written before December 31, 1982.
year dw 1982
month db 12
day db 31
files db 0
message db "No files deleted.",0DH,0AH,"$"
fcb db 2,"???????????"
db 26 dup (?)
buffer db 128 dup (?)
;
begin: set_dta buffer ; see Function 1AH
search_first fcb ; see Function 11H
cmp al,0FFH ; directory entry found?
jne compare ; yes
jmp all_done ; no, no files on disk
compare: convert_date buffer ; see end of chapter
cmp cx,year ; next several lines
jg next ; check date in directory
cmp dl,month ; entry against date
jg next ; above & check next file
cmp dh,day ; if date in directory
jge next ; entry isn't earlier.
delete buffer ; THIS FUNCTION
inc files ; bump deleted-files
; counter
next: search_next fcb ; see Function 12H
cmp al,00H ; directory entry found?
je compare ; yes, check date
cmp files,0 ; any files deleted?
je all_done ; no, display No files
; message.
convert files,10,message ; see end of chapter
all_done: display message ; see Function 09H
────────────────────────────────────────────────────────────────────────────
Sequential Read (Function 14H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 14H
DS:DX
Pointer to opened FCB
Return:
AL
00H = Read completed successfully
01H = EOF
02H = DTA too small
03H = EOF, partial record
Comments:
Function 14H reads a record from a specified file. DX must contain the
offset (from the segment address in DS) of an opened FCB. This call loads
the record pointed to by the Current Block field (offset 0CH) and Current
Record (offset 20H) field at the Disk Transfer Address, then increments
the Current Block and Current Record fields.
The length of the record is taken from the Record Size field (offset 0EH)
of the FCB.
AL returns a code that describes the processing:
Code Meaning
──────────────────────────────────────────────────────────────────────────
0 Read completed successfully
1 End-of-file; no data in the record
2 Not enough room at the Disk Transfer Address to read
one record; read canceled
3 End-of-file; a partial record was read and padded to
──────────────────────────────────────────────────────────────────────────
Macro Definition:
read_seq macro fcb
mov dx,offset fcb
mov ah,14H
int 21H
endm
Example:
The following program displays a file named textfile.asc that is on the
disk in drive B; its function is similar to the MS-DOS type command. If a
partial record is in the buffer at end-of-file, the routine that displays
the partial record displays characters until it encounters an end-of-file
mark (ASCII 26, or CONTROL+Z).
fcb db 2,"TEXTFILEASC"
db 26 dup (?)
buffer db 128 dup (?),"$"
;
begin: set_dta buffer ; see Function 1AH
open fcb ; see Function 0FH
read_line: read_seq fcb ; THIS FUNCTION
cmp al,02H ; DTA too small?
je all_done ; yes
cmp al,00H ; end-of-file?
jg check_more ; yes
display buffer ; see Function 09H
jmp read_line ; get another record
check_more: cmp al,03H ; partial record in buffer?
jne all_done ; no, go home
xor si,si ; set index to 0
find_eof: cmp buffer[si],26 ; is character EOF?
je all_done ; yes, no more to display
display_char buffer[si] ; see Function 02H
inc si ; bump index
jmp find_eof ; check next character
all_done: close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Sequential Write (Function 15H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 15H
DS:DX
Pointer to opened FCB
Return:
AL
00H = Write completed successfully
01H = Disk full
02H = DTA too small
Comments:
Function 15H writes a record to a specified file. DX must contain the
offset (from the segment address in DS) of an opened FCB. This call writes
the record pointed to by the Current Block field (offset 0CH) and Current
Record field (offset 20H) at the Disk Transfer Address, then increments
the Current Block and Current Record fields.
The record size is taken from the value of the Record Size field (offset
0EH) of the FCB. If the record size is less than a sector, the call writes
the data at the Disk Transfer Address to an MS-DOS buffer; MS-DOS writes
the buffer to disk when it contains a full sector of data, when the file
is closed, or when Function 0DH (Reset Disk) is issued.
AL returns a code that describes the processing:
Code Meaning
──────────────────────────────────────────────────────────────────────────
0 Write completed successfully
1 Disk full; write canceled
2 Not enough room at the Disk Transfer Address to write
──────────────────────────────────────────────────────────────────────────
Macro Definition:
write_seq macro fcb
mov dx,offset fcb
mov ah,15H
int 21H
endm
Example:
The following program creates a file named dir.tmp on the disk in drive B
containing the disk number (0=A, 1=B, etc.) and filename from each
directory entry on the disk.
record_size equ 0EH ; offset of Record Size
; field in FCB
fcb1 db 2,"DIR TMP"
db 26 dup (?)
fcb2 db 2,"???????????"
db 26 dup (?)
buffer db 128 dup (?)
;
begin: set_dta buffer ; see Function 1AH
search_first fcb2 ; see Function 11H
cmp al,0FFH ; directory entry found?
je all_done ; no, no files on disk
create fcb1 ; see Function 16H
mov fcb1[record_size],12
; set record size to 12
write_it: write_seq fcb1 ; THIS FUNCTION
cmp al,0 ; write successful?
jne all_done ; no, go home
search_next fcb2 ; see Function 12H
cmp al,FFH ; directory entry found?
je all_done ; no, go home
jmp write_it ; yes, write the record
all_done: close fcb1 ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Create File (Function 16H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 16H
DS:DX
Pointer to unopened FCB
Return:
AL
00H = Empty directory found
FFH = No empty directory available
Comments:
Function 16H creates a file. DX must contain the offset (from the segment
address in DS) of an unopened FCB. MS-DOS searches the directory for an
entry that matches the specified filename or, if there is no matching
entry, an empty entry.
If MS-DOS finds a matching entry, it opens the file and sets the length to
zero (in other words, if you try to create a file that already exists,
MS-DOS erases it and creates a new, empty file). If MS-DOS doesn't find a
matching entry but does find an empty directory entry, it opens the file
and sets its length to zero. In either case, the call creates the file,
and AL returns 0. If MS-DOS doesn't find a matching entry and there is no
empty entry, the call doesn't create the file, and AL returns FFH.
You can assign an attribute to the file by using an extended FCB with the
attribute byte set to the appropriate value (see "Extended FCB" in Section
1.9.1).
Macro Definition:
create macro fcb
mov dx,offset fcb
mov ah,16H
int 21H
endm
Example:
The following program creates a file named dir.tmp on the disk in drive B
containing the disk number (0 = A, 1 = B, etc.) and filename from each
directory entry on the disk.
record_size equ 0EH ; offset of Record Size
; field of FCB
fcb1 db 2,"DIR TMP"
db 26 dup (?)
fcb2 db 2,"???????????"
db 26 dup (?)
buffer db 128 dup (?)
;
begin: set_dta buffer ; see Function 1AH
search_first fcb2 ; see Function 11H
cmp al,0FFH ; directory entry found?
je all_done ; no, no files on disk
create fcb1 ; THIS FUNCTION
mov fcb1[record_size],12
; set record size to 12
write_it: write_seq fcb1 ; see Function 15H
cmp al,0 ; write successful
jne all_done ; no, go home
search_next fcb2 ; see Function 12H
cmp al,FFH ; directory entry found?
je all_done ; no, go home
jmp write_it ; yes, write the record
all_done: close fcb1 ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Rename File (Function 17H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 17H
DS:DX
Pointer to modified FCB in the following
nonstandard format:
Byte(s) Contents
───────────────────────────────────────────────────────────────────────
00H Drive number
01H-08H Old filename (padded with blanks, if necessary)
09H-0BH Old file extension (padded with blanks, if necessary)
0CH-10H Zeroed out
11H-18H New filename (padded with blanks, if necessary)
19H-1BH New file extension (padded with blanks, if necessary)
11CH-24H Zeroed out
───────────────────────────────────────────────────────────────────────
Return:
AL
00H = Directory entry found
FFH = No directory entry found
or destination already exists
Comments:
Function 17H changes the name of an existing file. DX must contain the
offset (from the segment address in DS) of an FCB with the drive number
and filename filled in, followed by a second filename at offset 11H. DOS
searches the disk directory for an entry that matches the first filename.
This filename can contain wildcard characters.
If MS-DOS finds a matching directory entry and there is no directory entry
that matches the second filename, it changes the filename in the directory
entry to match the second filename in the modified FCB. AL then returns
zero. If the second filename does contain a wildcard character, this call
does not change the corresponding characters in the filename of the
directory entry. You cannot use this function request to rename a hidden
file, a system file, or a subdirectory. If MS-DOS does not find a matching
directory entry or if it finds an entry for the second filename, AL
returns FFH.
Macro Definition:
rename macro fcb,newname
mov dx,offset fcb
mov ah,17H
int 21H
endm
Example:
The following program prompts for the name of a file and a new name; it
then renames the file.
fcb db 37 dup (?)
prompt1 db "Filename: $"
prompt2 db "New name: $"
reply db 15 dup(?)
crlf db 0DH,0AH,"$"
;
begin: display prompt1 ; see Function 09H
get_string 15,reply ; see Function 0AH
display crlf ; see Function 09H
parse reply[2],fcb ; see Function 29H
display prompt2 ; see Function 09H
get_string 15,reply ; see Function 0AH
display crlf ; see Function 09H
parse reply[2],fcb[16]
; see Function 29H
rename fcb ; THIS FUNCTION
────────────────────────────────────────────────────────────────────────────
Get Current Disk (Function 19H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 19H
Return:
AL
Currently selected drive
(0 = A, 1 = B, etc.)
Comments:
Function 19H returns the current drive in AL (0=A, 1=B, etc.).
Macro Definition:
current_disk macro
mov ah,19H
int 21H
endm
Example:
The following program displays the default drive in a two-drive system.
message db "Current disk is $"
crlf db 0DH,OAH,"$"
;
begin: display message ; see Function 09H
current_disk ; THIS FUNCTION
cmp al,00H ; is it disk A?
jne disk_b ; no, it's disk B:
display_char "A" ; see Function 02H
jmp all_done
disk_b: display_char "B" ; see Function 02H
all_done: display crlf ; see Function 09H
────────────────────────────────────────────────────────────────────────────
Set Disk Transfer Address (Function 1AH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 1AH
DS:DX
Disk Transfer Address
Return:
None
Comments:
Function 1AH sets the Disk Transfer Address. DX must contain the offset
(from the segment address in DS) of the Disk Transfer Address. Disk
transfers cannot wrap around from the end of the segment to the beginning,
nor can they overflow into another segment.
If you do not set the Disk Transfer Address, MS-DOS defaults to offset 80H
in the Program Segment Prefix. You can check the current Disk Transfer
Address with Function 2FH (Get Disk Transfer Address).
Macro Definition:
set_dta macro buffer
mov dx,offset buffer
mov ah,1AH
int 21H
endm
Example:
The following program prompts for a letter, converts it to its alphabetic
sequence (A=1, B=2, etc.), then reads and displays the corresponding
record from a file named alphabet.dat that is on the disk in drive B. The
file contains 26 records, each 28 bytes long.
record_size equ 0EH ; offset of Record Size
; field of FCB
relative_record equ 21H ; offset of Relative Record
; field of FCB
fcb db 2,"ALPHABETDAT"
db 26 dup (?)
buffer db 28 dup(?),"$"
prompt db "Enter letter: $"
crlf db 0DH,0AH,"$"
;
begin: set_dta buffer ; THIS FUNCTION
open fcb ; see Function 0FH
mov fcb[record_size],28 ; set record size
get_char: display prompt ; see Function 09H
read_kbd_and_echo ; see Function 01H
cmp al,0DH ; just a CR?
je all_done ; yes, go home
sub al,41H ; convert ASCII
; code to record #
mov fcb[relative_record],al
; set relative record
display crlf ; see Function 09H
read_ran fcb ; see Function 21H
display buffer ; see Function 09H
display crlf ; see Function 09H
jmp get_char ; get another character
all_done: close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Get Default Drive Data (Function 1BH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 1BH
Return:
AL
Sectors per cluster
CX
Bytes per sector
DX
Clusters per drive
DS:BX
Pointer to FAT ID byte
Comments:
Function 1BH retrieves data about the disk in the default drive. The data
returns in the following registers:
Register Contents
──────────────────────────────────────────────────────────────────────────
AL Number of sectors in a cluster (allocation unit)
CX Number of bytes in a sector
DX Number of clusters on the disk
──────────────────────────────────────────────────────────────────────────
BX returns the offset (to the segment address in DS) of the first byte of
the File Allocation Table (FAT), which identifies the type of disk in the
drive:
Value Type of Drive
──────────────────────────────────────────────────────────────────────────
FF Double-sided disk, 8 sectors per track, 40 tracks per side
FE Single-sided disk, 8 sectors per track, 40 tracks per side
FD Double-sided disk, 9 sectors per track, 40 tracks per side
FC Single-sided disk, 9 sectors per track, 40 tracks per side
F9 Double-sided disk, 15 sectors per track, 40 tracks per side
F9 Double-sided disk, 9 sectors per track, 80 tracks per side
F8 Fixed disk
──────────────────────────────────────────────────────────────────────────
This call is similar to Function 36H (Get Disk Free Space), except that
it returns the address of the FAT ID byte in BX instead of the number of
available clusters. It is also similar to Function 1CH (Get Drive Data),
except that it returns data on the disk in the default drive instead of on
the disk in a specified drive. For a description of how MS-DOS stores data
on a disk, including a description of the File Allocation Table, see
Chapter 3, "MS-DOS Technical Information."
──────────────────────────────────────────────────────────────────────────
Warning
The FAT ID byte is no longer adequate to identify the type of drive
being used. See Chapter 2, "MS-DOS Device Drivers," for more details.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
def_drive_data macro
push ds
mov ah,1BH
int 21H
mov al,byte ptr[bx]
pop ds
endm
Example:
The following program displays a message that tells whether the default
drive is a floppy disk or a hard disk drive.
stdout equ 1
;
msg db "Default drive is "
dskt db "disk."
fixed db "fixed."
crlf db ODH,OAH
;
begin: write_handle stdout,msg,17 ; display message
jc write_error ; routine not shown
def_drive_data ; THIS FUNCTION
cmp byte ptr [bx],0F8H ; check FAT ID byte
jne disk ; it's a disk
write_handle stdout,fixed,6 ; see Function 40H
jc write_error ; see Function 40H
jmp short all_done ; clean up & go home
disk: write_handle stdout,dskt,9 ; see Function 40H
all_done: write_handle stdout,crlf,2 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Get Drive Data (Function 1CH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 1CH
DL
Drive (0=default, 1=A, etc.)
Return:
AL
0FFH if drive number is invalid;
otherwise, sectors per cluster
CX
Bytes per sector
DX
Clusters per drive
DS:BX
Pointer to FAT ID byte
Comments:
Function 1CH retrieves data about the disk in the specified drive. DL must
contain the drive number (0=default, 1=A, etc.). The data returns in the
following registers:
Register Contents
──────────────────────────────────────────────────────────────────────────
AL Number of sectors in a cluster (allocation unit)
CX Number of bytes in a sector
DX Number of clusters on the disk
──────────────────────────────────────────────────────────────────────────
BX returns the offset (to the segment address in DS) of the first byte of
the File Allocation Table (FAT), which identifies the type of disk in the
drive:
Value Type of Drive
──────────────────────────────────────────────────────────────────────────
FF Double-sided disk, 8 sectors per track, 40 tracks per side
FE Single-sided disk, 8 sectors per track, 40 tracks per side
FD Double-sided disk, 9 sectors per track, 40 tracks per side
FC Single-sided disk, 9 sectors per track, 40 tracks per side
F9 Double-sided disk, 15 sectors per track, 40 tracks per side
F9 Double-sided disk, 9 sectors per track, 80 tracks per side
F8 Fixed disk
──────────────────────────────────────────────────────────────────────────
If the drive number in DL is invalid, AL returns 0FFH.
──────────────────────────────────────────────────────────────────────────
Warning
The FAT ID byte is no longer adequate to identify the type of drive
being used. See Chapter 2, "MS-DOS Device Drivers," for more details.
──────────────────────────────────────────────────────────────────────────
This call is similar to Function 36H (Get Disk Free Space), except that
it returns the address of the FAT ID byte in BX instead of the number of
available clusters. It is also similar to Function 1BH (Get Default Drive
Data), except that it returns data on the disk in the drive specified in
DL instead of the disk in the default drive. For a description of how
MS-DOS stores data on a disk, including a description of the File
Allocation Table, see Chapter 3, "MS-DOS Technical Information."
Macro Definition:
drive_data macro drive
push ds
mov dl,drive
mov ah,1BH
int 21H
mov al, byte ptr[bx]
pop ds
endm
Example:
The following program displays a message that tells whether drive B is a
floppy disk or a hard disk drive.
stdout equ 1
:
msg db "Drive B is "
dskt db "disk."
fixed db "fixed."
crlf db ODH,OAH
;
begin: write_handle stdout,msg,11 ; display message
jc write_error ; routine not shown
drive_data 2 ; THIS FUNCTION
cmp byte ptr [bx],0F8H ; check FAT ID byte
jne disk ; it's a disk
write_handle stdout,fixed,6 ; see Function 40H
jc write_error ; routine not shown
jmp all_done ; clean up & go home
disk: write_handle stdout,dskt,9 ; see Function 40H
all_done: write_handle stdout,crlf,2 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Random Read (Function 21H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 21H
DS:DX
Pointer to opened FCB
Return:
AL
0 = Read completed successfully
1 = End of file, record empty
2 = DTA too small
3 = End of file, partial record
Comments:
Function 21H reads (into the Disk Transfer Address) the record pointed to
by the Relative Record field (offset 21H) of the FCB. DX must contain the
offset (from the segment address in DS) of an opened FCB. The Current
Block field (offset 0CH) and Current Record field (offset 20H) are set to
agree with the Relative Record field (offset 21H). The record is then
loaded at the Disk Transfer Address. The record length is taken from the
Record Size field (offset 0EH) of the FCB.
AL returns a code that describes the processing:
Code Meaning
──────────────────────────────────────────────────────────────────────────
0 Read completed successfully
1 End-of-file; no data in the record
2 Not enough room at the Disk Transfer Address to read
one record; read canceled
3 End-of-file; a partial record was read and padded to
──────────────────────────────────────────────────────────────────────────
Macro Definition:
read_ran macro fcb
mov dx,offset fcb
mov ah,21H
int 21H
endm
Example:
The following program prompts for a letter, converts it to its alphabetic
sequence (A = 1, B = 2, etc.), then reads and displays the corresponding
record from a file named alphabet.dat that is on the disk in drive B. The
file contains 26 records, each 28 bytes long.
record_size equ 0EH ; offset of Record Size
; field of FCB
relative_record equ 21H ; offset of Relative Record
; field of FCB
fcb db 2,"ALPHABETDAT"
db 26 dup (?)
buffer db 28 dup(?),"$"
prompt db "Enter letter: $"
crlf db 0DH,0AH,"$"
;
begin: set_dta buffer ; see Function 1AH
open fcb ; see Function 0FH
mov fcb[record_size],28 ; set record size
get_char: display prompt ; see Function 09H
read_kbd_and_echo ; see Function 01H
cmp al,0DH ; just a CR?
je all_done ; yes, go home
sub al,41H ; convert ASCII code
; to record #
mov fcb[relative_record],al ; set relative
; record
display crlf ; see Function 09H
read_ran fcb ; THIS FUNCTION
display buffer ; see Function 09H
display crlf ; see Function 09H
jmp get_char ; get another char.
all_done: close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Random Write (Function 22H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 22H
DS:DX
Pointer to opened FCB
Return:
AL
00H = Write completed successfully
01H = Disk full
02H = DTA too small
Comments:
Function 22H writes (from the Disk Transfer Address) the record pointed to
by the Relative Record field (offset 21H) of the FCB. DX must contain the
offset from the segment address in DS of an opened FCB. The Current Block
(offset 0CH) and Current Record (offset 20H) fields are set to agree with
the Relative Record field (offset 21H). This record is then written from
the Disk Transfer Address.
The record length is taken from the Record Size field (offset 0EH) of the
FCB. If the record size is less than a sector, the data at the Disk
Transfer Address is written to a buffer. The buffer is written to a disk
when it contains a full sector of data, or when a program closes the file,
or when it issues Function 0DH (Reset Disk).
AL returns a code that describes the processing:
Code Meaning
──────────────────────────────────────────────────────────────────────────
0 Write completed successfully
1 Disk is full
2 Not enough room at the Disk Transfer Address to write
──────────────────────────────────────────────────────────────────────────
Macro Definition:
write_ran macro fcb
mov dx,offset fcb
mov ah,22H
int 21H
endm
Example:
The following program prompts for a letter, converts it to its alphabetic
sequence (A = 1, B = 2, etc.), then reads and displays the corresponding
record from a file named alphabet.dat that is on the disk in drive B.
After displaying the record, it prompts you to enter a changed record. If
you type a new record, it is written to the file, but if you just press
the ENTER key, the record is not replaced. The file contains 26 records,
each 28 bytes long.
record_size equ 0EH ; offset of Record Size
; field of FCB
relative_record equ 21H ; offset of Relative Record
; field of FCB
fcb db 2,"ALPHABETDAT"
db 26 dup (?)
buffer db 28 dup(?),0DH,0AH,"$"
prompt1 db "Enter letter: $"
prompt2 db "New record (ENTER for no change): $"
crlf db 0DH,0AH,"$"
reply db 28 dup (32)
blanks db 26 dup (32)
;
begin: set_dta buffer ; see Function 1AH
open fcb ; see Function 0FH
mov fcb[record_size],28 ; set record size
get_char: display prompt1 ; see Function 09H
read_kbd_and_echo ; see Function 01H
cmp al,0DH ; just a carriage return?
je all_done ; yes, go home
sub al,41H ; convert ASCII
; code to record #
mov fcb[relative_record],al
; set relative record
display crlf ; see Function 09H
read_ran fcb ; THIS FUNCTION
display buffer ; see Function 09H
display crlf ; see Function 09H
display prompt2 ; see Function 09H
get_string 27,reply ; see Function 0AH
display crlf ; see Function 09H
cmp reply[1],0 ; was anything typed
; besides CR?
je get_char ; no
; get another char.
xor bx,bx ; to load a byte
mov bl,reply[1] ; use reply length as
; counter
move_string blanks,buffer,26 ; see chapter end
move_string reply[2],buffer,bx ; see chapter end
write_ran fcb ; THIS FUNCTION
jmp get_char ; get another character
all_done: close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Get File Size (Function 23H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 23H
DS:DX
Pointer to unopened FCB
Return:
AL
00H = Directory entry found
FFH = No directory entry found
Comments:
Function 23H returns the size of a specified file. DX must contain the
offset (from the segment address in DS) of an unopened FCB.
If there is a directory entry that matches the specified file, MS-DOS
divides the File Size field (offset 10H) of the directory entry by the
Record Size field (offset 0EH) of the FCB, puts the result in the Relative
Record field (offset 21H) of the FCB, and returns 0 in AL.
You must set the Record Size field of the FCB to the correct value before
calling this function. If the Record Size field is not an even divisor of
the File Size field, the value set in the Relative Record field is rounded
up, yielding a value larger than the actual number of records.
If this call does not find a matching directory, AL returns FFH.
Macro Definition:
file_size macro fcb
mov dx,offset fcb
mov ah,23H
int 21H
endm
Example:
The following program prompts for the name of a file, opens the file to
fill in the Record Size field of the FCB, issues a File Size system call,
and displays the record length and number of records.
fcb db 37 dup (?)
prompt db "File name: $"
msg1 db "Record length: ",0DH,0AH,"$"
msg2 db "Records: ",0DH,0AH,"$"
crlf db 0DH,0AH,"$"
reply db 17 dup(?)
;
begin: display prompt ; see Function 09H
get_string 17,reply ; see Function 0AH
cmp reply[1],0 ; just a CR?
jne get_length ; no, keep going
jmp all_done ; yes, go home
get_length: display crlf ; see Function 09H
parse reply[2],fcb ; see Function 29H
open fcb ; see Function 0FH
file_size fcb ; THIS FUNCTION
mov ax,word ptr fcb[33] ; get record length
convert ax,10,msg2[9] ; see end of chapter
mov ax,word ptr fcb[14] ; get record number
convert ax,10,msg1[15] ; see end of chapter
display msg1 ; see Function 09H
display msg2 ; see Function 09H
all_done: close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Set Relative Record (Function 24H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 24H
DS:DX
Pointer to opened FCB
Return:
None
AL=00H
Relative Record field is modified in FCB.
Comments:
Function 24H sets the Relative Record field (offset 21H) to the file
address specified by the Current Block field (offset 0CH) and Current
Record field (offset 20H). DX must contain the offset (from the segment
address in DS) of an opened FCB. You use this call to set the file pointer
before a Random Read or Write (Functions 21H, 22H, 27H, or 28H).
Macro Definition:
set_relative_record macro fcb
mov dx,offset fcb
mov ah,24H
int 21H
endm
Example:
The following program copies a file using the Random Block Read and Random
Block Write system calls. It speeds the copy by setting the record length
equal to the file size and the record count to 1, and by using a buffer of
32 kilobytes. It positions the file pointer by setting the Current Record
field (offset 20H) to 1 and using Function 24H (Set Relative Record) to
make the Relative Record field (offset 21H) point to the same record that
the combination of the Current Block field (offset 0CH) and Current Record
field (offset 20H) points to.
current_record equ 20H ; offset of Current Record
; field of FCB
fil_size equ 10H ; offset of File Size
; field of FCB
fcb db 37 dup (?)
filename db 17 dup(?)
prompt1 db "File to copy: $" ; see Function 09H for
prompt2 db "Name of copy: $" ; explanation of $
crlf db 0DH,0AH,"$"
file_length dw ?
buffer db 32767 dup(?)
;
begin: set_dta buffer ; see Function 1AH
display prompt1 ; see Function 09H
get_string 15,filename ; see Function 0AH
display crlf ; see Function 09H
parse filename[2],fcb ; see Function 29H
open fcb ; see Function 0FH
mov fcb[current_record],0 ; set Current Record
; field
set_relative_record fcb ; THIS FUNCTION
mov ax,word ptr fcb[fil_size] ; get file size
mov file_length,ax ; save it for
; ran_block_write
ran_block_read fcb,1,ax ; see Function 27H
display prompt2 ; see Function 09H
get_string 15,filename ; see Function 0AH
display crlf ; see Function 09H
parse filename[2],fcb ; see Function 29H
create fcb ; see Function 16H
mov fcb[current_record],0 ; set Current Record
; field
set_relative_record fcb ; THIS FUNCTION
mov ax,file_length ; get original file
ran_block_write fcb,1,ax ; see Function 28H
close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Set Interrupt Vector (Function 25H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 25H
AL
Interrupt number
DS:DX
Pointer to interrupt-handling
routine
Return:
None
Comments:
Function 25H sets the address in the interrupt vector table for the
specified interrupt.
AL must contain the number of the interrupt. DX must contain the offset
(to the segment address in DS) of the interrupt-handling routine.
To avoid compatibility problems, programs should never set an interrupt
vector directly and should never use Interrupt 25H to read directly from
memory. To get a vector, use Function 35H (Get Interrupt Vector), and to
set a vector, use Function 25H, unless your program must be compatible
with MS-DOS versions earlier than 2.0.
Macro Definition:
set_vector macro interrupt,handler_start
mov al,interrupt
mov dx,offset handler_start
mov ah,25H
endm
Example:
Because interrupts tend to be machine-specific, no example is shown.
────────────────────────────────────────────────────────────────────────────
Create New PSP (Function 26H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 26H
DX
Segment address of new PSP
Return:
None
Comments:
This function request has been superseded. Use Function 4B00H or 4B03H
(Load and Execute Program or Overlay) to run a child process, unless your
program must be compatible with MS-DOS versions earlier than 2.0.
Function 26H creates a new Program Segment Prefix. DX must contain the
segment address where the new PSP is to be created.
Macro Definition:
create_psp macro seg_addr
mov dx,seg_addr
mov ah,26H
endm
Example:
Because Functions 4B00H (Load and Execute Program) and 4B03H (Load
Overlay) have superseded this function request, no example is shown.
────────────────────────────────────────────────────────────────────────────
Random Block Read (Function 27H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 27H
DS:DX
Pointer to opened FCB
CX
Number of blocks to read
Return:
AL
0 = Read completed successfully
1 = End of file, empty record
2 = DTA too small
3 = End of file, partial record
CX
Number of blocks read
Comments:
Function 27H reads one or more records from a specified file to the Disk
Transfer Address. DX must contain the offset (to the segment address in
DS) of an opened FCB. CX must contain the number of records to read.
Reading starts at the record specified by the Relative Record field
(offset 21H); you must set this field with Function 24H (Set Relative
Record) before calling this function.
DOS calculates the number of bytes to read by multiplying the value in CX
by the Record Size field (offset 0EH) of the FCB.
CX returns the number of records read. The Current Block field (offset
0CH), Current Record field (offset 20H), and Relative Record field (offset
21H) are set to address the next record.
If you call this function with CX=0, no records are read. AL returns a
code that describes the processing:
Code Meaning
──────────────────────────────────────────────────────────────────────────
0 Read completed successfully
1 End-of-file; no data in the record
2 Not enough room at the Disk Transfer Address to read
one record; read canceled
3 End-of-file; a partial record was read and padded to
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ran_block_read macro fcb,count,rec_size
mov dx,offset fcb
mov cx,count
mov word ptr fcb[14],rec_size
mov ah,27H
int 21H
endm
Example:
The following program copies a file by using Function 27H (Random Block
Read). This program speeds the copy process by specifying a record count
of 1 and a record length equal to the file size, and by using a buffer of
32 kilobytes; the file is read as a single record (compare to the sample
program for Function 28H that specifies a record length of 1 and a record
count equal to the file size).
current_record equ 20H ; offset of Current Record field
fil_size equ 10H ; offset of File Size field
;
fcb db 37 dup (?)
filename db 17 dup(?)
prompt1 db "File to copy: $" ; see Function 09H for
prompt2 db "Name of copy: $" ; explanation of $
crlf db 0DH,0AH,"$"
file_length dw ?
buffer db 32767 dup(?)
;
begin: set_dta buffer ; see Function 1AH
display prompt1 ; see Function 09H
get_string 15,filename ; see Function 0AH
display crlf ; see Function 09H
parse filename[2],fcb ; see Function 29H
open fcb ; see Function 0FH
mov fcb[current_record],0 ; set Current
; Record field
set_relative_record fcb ; see Function 24H
mov ax, word ptr fcb[fil_size]
; get file size
mov file_length,ax ; save it
ran_block_read fcb,1,ax ; THIS FUNCTION
display prompt2 ; see Function 09H
get_string 15,filename ; see Function 0AH
display crlf ; see Function 09H
parse filename[2],fcb ; see Function 29H
create fcb ; see Function 16H
mov fcb[current_record],0; set current
; Record field
set_relative_record fcb ; see Function 24H
ran_block_write fcb,1,ax ; see Function 28H
close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Random Block Write (Function 28H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 28H
DS:DX
Pointer to opened FCB
CX
Number of blocks to write
(0 = set File Size field)
Return:
AL
00H = Write completed successfully
01H = Disk full
02H = End of segment
CX
Number of blocks written
Comments:
Function 28H writes one or more records to a specified file from the Disk
Transfer Address. DX must contain the offset (to the segment address in
DS) of an opened FCB; CX must contain either the number of records to
write or 0.
If CX is not 0, the specified number of records is written to the file,
starting at the record specified in the Relative Record field (offset 21H)
of the FCB. If CX is 0, no records are written, but MS-DOS sets the File
Size field (offset 10H) of the directory entry to the value in the
Relative Record field (offset 21H) of the FCB. To satisfy this new file
size, disk allocation units are allocated or released, as required.
MS-DOS calculates the number of bytes to write by multiplying the value in
CX by the Record Size field (offset 0EH) of the FCB. CX returns the number
of records written; the Current Block field (offset 0CH), Current Record
field (offset 20H), and Relative Record (offset 21H) field are set to
address the next record. AL returns a code that describes the processing:
Code Meaning
──────────────────────────────────────────────────────────────────────────
0 Write completed successfully
1 Disk full. No records written
2 Not enough room at the Disk Transfer Address to write
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ran_block_write macro fcb,count,rec_size
mov dx,offset fcb
mov cx,count
mov word ptr fcb[14],rec_size
mov ah,28H
int 21H
endm
Example:
The following program copies a file using Function 27H (Random Block
Read) and Function 28H (Random Block Write). This program speeds the copy
process by specifying a record count equal to the file size and a record
length of 1, and by using a buffer of 32 kilobytes. The file is copied
quickly with one disk access each to read and write (compare to the sample
program of Function 27H, which specifies a record count of 1 and a record
length equal to file size).
current_record equ 20H ; offset of Current Record field
fil_size equ 10H ; offset of File Size field
;
fcb db 37 dup (?)
filename db 17 dup(?)
prompt1 db "File to copy: $" ; see Function 09H for
prompt2 db "Name of copy: $" ; explanation of $
crlf db 0DH,0AH,"$"
num_recs dw ?
buffer db 32767 dup(?)
;
begin: set_dta buffer ; see Function 1AH
display prompt1 ; see Function 09H
get_string 15,filename ; see Function 0AH
display crlf ; see Function 09H
parse filename[2],fcb ; see Function 29H
open fcb ; see Function 0FH
mov fcb[current_record],0; set Current
Record field
set_relative_record fcb ; see Function 24H
mov ax, word ptr fcb[fil_size]
; get file size
mov num_recs,ax ; save it
ran_block_read fcb,num_recs,1 ; THIS FUNCTION
display prompt2 ; see Function 09H
get_string 15,filename ; see Function 0AH
display crlf ; see Function 09H
parse filename[2],fcb ; see Function 29H
create fcb ; see Function 16H
mov fcb[current_record],0 ; set Current
; Record field
set_relative_record fcb ; see Function 24H
ran_block_write fcb,num_recs,1 ; see Function 28H
close fcb ; see Function 10H
────────────────────────────────────────────────────────────────────────────
Parse File Name (Function 29H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 29H
AL
Controls parsing (see text)
DS:SI
Pointer to string to parse
ES:DI
Pointer to buffer for unopened FCB
Return:
AL
00H = No wildcard characters
01H = Wildcard characters used
FFH = Drive letter invalid
DS:SI
Pointer to first byte past
string that was parsed
ES:DI
Pointer to unopened FCB
Comments:
Function 29H parses a string for a filename of the form
drive:filename.extension. SI must contain the offset (to the segment
address in DS) of the string to parse; DI must contain the offset (to the
segment address in ES) of an area of memory large enough to hold an
unopened FCB. If the string contains a valid filename, this call creates a
corresponding unopened FCB at ES:DI.
AL controls the parsing. Bits 4-7 must be 0; bits 0-3 have the following
meaning:
Table 1.20
Bit Values for Function 29H
╓┌─┌───────────┌────────────┌────────────────────────────────────────────────╖
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 0 Stops parsing if a file separator is encountered
1 Ignores leading separators
1 0 Sets the drive number in the FCB to 0 (current
drive) if the string does not contain a drive
number
1 Leaves the drive number in the FCB unchanged if
the string does not contain a drive number
2 0 Sets the filename in the FCB to eight blanks if
the string does not contain a filename
1 Leaves the filename in the FCB unchanged if the
string does not contain a filename
3 0 Sets the extension in the FCB to three blanks if
the string does not contain an extension
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
the string does not contain an extension
1 Leaves the extension in the FCB unchanged if the
──────────────────────────────────────────────────────────────────────────
If the string contains a filename or extension that includes an asterisk
(*), all remaining characters in the name or extension are set to question
marks (?).
Filename Separators:
: ; . , = + / " [ ] \ < > | space tab
Filename terminators include all the filename separators, plus any control
character. A filename cannot contain a filename terminator, since, if the
call encounters one, parsing stops.
If the string contains a valid filename:
■ AL returns 1 if the filename or extension contains a wildcard character
(* or ?); AL returns 0 if neither the filename nor extension contains a
wildcard character.
■ DS:SI points to the first character following the parsed string.
■ ES:DI points to the first byte of the unopened FCB.
If the drive letter is invalid, AL returns FFH. If the string does not
contain a valid filename, ES:DI+1 points to a blank.
Macro Definition:
parse macro string,fcb
mov si,offset string
mov di,offset fcb
push es
push ds
pop es
mov al,0FH ; bits 0-3 on
mov ah,29H
int 21H
pop es
endm
Example:
The following program verifies the existence of the file named in reply to
the prompt.
fcb db 37 dup (?)
prompt db "Filename: $"
reply db 17 dup(?)
yes db "File exists",0DH,0AH,"$"
no db "File does not exist",0DH,0AH,"$"
crlf db 0DH,0AH,"$"
;
begin: display prompt ; see Function 09H
get_string 15,reply ; see Function 0AH
parse reply[2],fcb ; THIS FUNCTION
display crlf ; see Function 09H
search_first fcb ; see Function 11H
cmp al,0FFH ; dir. entry found?
je not_there ; no
display yes ; see Function 09H
jmp return
not_there: display no
────────────────────────────────────────────────────────────────────────────
Get Date (Function 2AH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 2AH
Return:
CX
Year (1980-2099)
DH
Month (1-12)
DL
Day (1-31)
AL
Day of week (0=Sun., 6=Sat.)
Comments:
Function 2AH returns the current date set in the operating system as
binary numbers in CX and DX:
Register Contents
──────────────────────────────────────────────────────────────────────────
CX Year (1980-2099)
DH Month (1=January, 2=February, etc.)
DL Day of month (1-31)
AL Day of week (0=Sunday, 1=Monday, etc.)
──────────────────────────────────────────────────────────────────────────
Macro Definition:
get_date macro
mov ah,2AH
int 21H
endm
Example:
The following program gets the date, increments the day, increments the
month or year, if necessary, and sets the new date.
month db 31,28,31,30,31,30,31,31,30,31,30,31
;
begin: get_date ; THIS FUNCTION
inc dl ; increment day
xor bx,bx ; so BL can be used as index
mov bl,dh ; move month to index register
dec bx ; month table starts with 0
cmp dl,month[bx] ; past end of month?
jle month_ok ; no, set new date
mov dl,1 ; yes, set day to 1
inc dh ; and increment month
cmp dh,12 ; past end of year?
jle month_ok ; no, set new date
mov dh,1 ; yes, set month to 1
inc cx ; increment year
month_ok: set_date cx,dh,dl ; see Function 2AH
────────────────────────────────────────────────────────────────────────────
Set Date (Function 2BH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 2BH
CX
Year (1980-2099)
DH
Month (1-12)
DL
Day (1-31)
Return:
AL
00H = Date was valid
FFH = Date was invalid
Comments:
Function 2BH sets the date in the operating system (and in the CMOS clock,
if one exists). Registers CX and DX must contain a valid date in binary:
Register Contents
──────────────────────────────────────────────────────────────────────────
CX Year (1980-2099)
DH Month (1=January, 2=February, etc.)
DL Day of month (1-31)
──────────────────────────────────────────────────────────────────────────
If the date is valid, the call sets it and AL returns 0. If the date is
not valid, the function aborts and AL returns FFH.
Macro Definition:
set_date macro year,month,day
mov cx,year
mov dh,month
mov dl,day
mov ah,2BH
int 21H
endm
Example:
The following program gets the date, increments the day, increments the
month or year, if necessary, and sets the new date.
month db 31,28,31,30,31,30,31,31,30,31,30,31
;
begin: get_date ; see Function 2AH
inc dl ; increment day
xor bx,bx ; so BL can be used as index
mov bl,dh ; move month to index register
dec bx ; month table starts with 0
cmp dl,month[bx] ; past end of month?
jle month_ok ; no, set the new date
mov dl,1 ; yes, set day to 1
inc dh ; and increment month
cmp dh,12 ; past end of year?
jle month_ok ; no, set the new date
mov dh,1 ; yes, set the month to 1
inc cx ; increment year
month_ok: set_date cx,dh,dl ; THIS FUNCTION
────────────────────────────────────────────────────────────────────────────
Get Time (Function 2CH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 2CH
Return:
CH
Hour (0-23)
CL
Minutes (0-59)
DH
Seconds (0-59)
DL
Hundredths (0-99)
Comments:
Function 2CH returns the current time set in the operating system (and
sets the CMOS clock, if one exists) as binary numbers in CX and DX:
Register Contents
──────────────────────────────────────────────────────────────────────────
CH Hour (0-23)
CL Minutes (0-59)
DH Seconds (0-59)
DL Hundredths of a second (0-99)
──────────────────────────────────────────────────────────────────────────
Depending on how your hardware keeps time, some of these fields may be
irrelevant. As an example, many CMOS clock chips do not resolve more than
seconds. In such a case, the value in DL will probably always be 0.
Macro Definition:
get_time macro
mov ah,2CH
int 21H
endm
Example:
The following program displays the time continuously until you press any
key.
time db "00:00:00.00",0DH,"$"
;
begin: get_time ; THIS FUNCTION
byte_to_dec ch,time ; see end of chapter
byte_to_dec cl,time[3] ; see end of chapter
byte_to_dec dh,time[6] ; see end of chapter
byte_to_dec dl,time[9] ; see end of chapter
display time ; see Function 09H
check_kbd_status ; see Function 0BH
cmp al,0FFH ; has a key been pressed?
je return ; yes, terminate
jmp begin ; no, display time
────────────────────────────────────────────────────────────────────────────
Set Time (Function 2DH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 2DH
CH
Hour (0-23)
CL
Minutes (0-59)
DH
Seconds (0-59)
DL
Hundredths (0-99)
Return:
AL
00H = Time was valid
FFH = Time was invalid
Comments:
Function 2DH sets the time in the operating system. Registers CX and DX
must contain a valid time in binary:
Register Contents
──────────────────────────────────────────────────────────────────────────
CH Hour (0-23)
CL Minutes (0-59)
DH Seconds (0-59)
DL Hundredths of a second (0-99)
──────────────────────────────────────────────────────────────────────────
Depending on how your hardware keeps time, some of these fields may be
irrelevant. As an example, many CMOS clock chips do not resolve more than
seconds. In such a case, the value in DL will not be relevant.
If the time is valid, the call sets it and AL returns 0. If the time is
not valid, the function aborts and AL returns FFH.
Macro Definition:
set_time macro hour,minutes,seconds,hundredths
mov ch,hour
mov cl,minutes
mov dh,seconds
mov dl,hundredths
mov ah,2DH
int 21H
endm
Example:
The following program sets the system clock to 0 and displays the time
continuously. When you type a character, the display freezes; when you
type another character, the clock is reset to 0 and the display starts
again.
time db "00:00:00.00",0DH,0AH,"$"
;
begin: set_time 0,0,0,0 ; THIS FUNCTION
read_clock: get_time ; see Function 2CH
byte_to_dec ch,time ; see end of chapter
byte_to_dec cl,time[3] ; see end of chapter
byte_to_dec dh,time[6] ; see end of chapter
byte_to_dec dl,time[9] ; see end of chapter
display time ; see Function 09H
dir_console_io 0FFH ; see Function 06H
cmp al,00H ; was a char. typed?
jne stop ; yes, stop the timer
jmp read_clock ; no keep timer on
stop: read_kbd ; see Function 08H
jmp begin ; keep displaying time
────────────────────────────────────────────────────────────────────────────
Set/Reset Verify Flag (Function 2EH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 2EH
AL
0 = Do not verify
1 = Verify
Return:
None
Comments:
Function 2EH tells MS-DOS whether or not to verify each disk write. If AL
is 1, verify is on; if AL is 0, verify is off. MS-DOS checks this flag
each time it writes to a disk.
The flag is normally off; you may wish to turn it on when writing critical
data to disk. Because disk errors are rare and verification slows writing,
you will probably want to leave it off at other times. You can check the
setting with Function 54H (Get Verify State).
Macro Definition:
verify macro switch
mov al,switch
mov ah,2EH
int 21H
endm
Example:
The following program copies the contents of a single-sided disk in drive
A to the disk in drive B, verifying each write. It uses a buffer of 32
kilobytes.
on equ 1
off equ 0
;
prompt db "Source in A, target in B",0DH,0AH
db "Any key to start. $"
first dw 0
buffer db 60 dup (512 dup(?)) ; 60 sectors
;
begin: display prompt ; see Function 09H
read_kbd ; see Function 08H
verify on ; THIS FUNCTION
mov cx,6 ; copy 60 sectors
; 6 times
copy: push cx ; save counter
abs_disk_read 0,buffer,60,first ; see Int 25H
abs_disk_write 1,buffer,64,first ; see Int 26H
add first,60 ; do next 60 sectors
pop cx ; restore counter
loop copy ; do it again
verify off ; THIS FUNCTION
────────────────────────────────────────────────────────────────────────────
Get Disk Transfer Address (Function 2FH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 2FH
Return:
ES:BX
Pointer to Disk Transfer Address
Comments:
Function 2FH returns the segment address of the current Disk Transfer
Address in ES and the offset in BX.
Macro Definition:
get_dta macro
mov ah,2fH
int 21H
endm
Example:
The following program displays the current Disk Transfer Address in the
form: segment:offset.
message db "DTA -- : ",0DH,0AH,"$"
sixteen db 10H
temp db 2 dup (?)
;
begin: get_dta ; THIS FUNCTION
mov word ptr temp,ex ; To access each byte
convert temp[1],sixteen,message[07H] ; See end of
convert temp,sixteen,message[09H] ; chapter for
convert bh,sixteen,message[0CH] ; description
convert bl,sixteen,message[0EH] ; of CONVERT
display message ; See Function 09H
────────────────────────────────────────────────────────────────────────────
Get MS-DOS Version Number (Function 30H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 30H
Return:
AL
Major version number
AH
Minor version number
BH
OEM serial number
BL:CX
24-bit user (serial) number
Comments:
Function 30H returns the MS-DOS version number. AL returns the major
version number; AH returns the minor version number. (For example, MS-DOS
3.0 returns 3 in AL and 0 in AH.)
If AL returns 0, the MS-DOS version is earlier than 2.0.
Macro Definition:
get_version macro
mov ah,30H
int 21H
endm
Example:
The following program displays the MS-DOS version if it is 1.28 or
greater.
message db "MS-DOS Version . ",0DH,0AH,"$"
ten db 0AH ; For CONVERT
;
begin: get_version ; THIS FUNCTION
cmp al,0 ; 1.28 or later?
jng return ; No, go home
convert al,ten,message[0FH] ; See end of chapter
convert ah,ten,message[12H] ; for description
display message ; See Function 9
────────────────────────────────────────────────────────────────────────────
Keep Process (Function 31H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 31H
AL
Return code
DX
Memory size, in paragraphs
Return:
None
Comments:
Function 31H makes a program remain resident after it terminates. You can
use it to install device-specific interrupt handlers. But unlike Interrupt
27H (Terminate But Stay Resident), this function request allows more than
64K bytes to remain resident and does not require CS to contain the
segment address of the Program Segment Prefix. You should use Function 31H
to install a resident program unless your program must be compatible with
MS-DOS versions earlier than 2.0.
DX must contain the number of paragraphs of memory required by the program
(one paragraph = 16 bytes). AL contains an exit code.
Be careful when using this function with .exe programs. The value in DX
must be the total size to remain resident, not just the size of the code
segment which is to remain resident. A typical error is to forget about
the 100H-byte program-header-prefix and give a value in DX that doesn't
account for the size of this prefix. MS-DOS terminates the current process
and tries to set the memory allocation to the number of paragraphs in DX.
No other allocation blocks belonging to the process are released.
By using Function 4DH (Get Return Code of Child Process), the parent
process can retrieve the process's exit code from AL. (You can test this
exit code by using the if command with errorlevel.)
Macro Definition:
keep_process macro return_code,last_byte
mov al,return_code
mov dx,offset last_byte
mov cl,4
shr dx,cl
inc dx
mov ah,31H
int 21H
endm
Example:
Because the most common use of this call is to install a machine-specific
routine, an example is not shown. The macro definition, however, shows the
calling syntax.
────────────────────────────────────────────────────────────────────────────
CONTROL+C Check (Function 33H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 33H
AL
0 = Get state of CONTROL+C
1 = Set state of CONTROL+C
5 = Query DOS boot drive
DL (if AL=1)
0 = Off
1 = On
Return:
DL (if AL=0)
0 = Off
1 = On
DL (if AL=5)
1 = A, 2 = B, etc.
AL
FFH = error (AL was neither 0, 1, nor 5
when call was made)
Comments:
Function 33H gets or sets the state of CONTROL+C (or CONTROL+BREAK for IBM
compatibles) checking in MS-DOS and can query the DOS boot drive. AL must
contain a code that specifies the requested action:
Code Meaning
──────────────────────────────────────────────────────────────────────────
0 Current state of CONTROL+C checking in DL
1 Set state of CONTROL+C checking to the value in DL
5 Query DOS boot drive in DL
──────────────────────────────────────────────────────────────────────────
If AL is 0, DL returns the current state (0=off, 1=on). If AL is 1, the
value in DL specifies the state to be set (0=off, 1=on). If AL is neither
0, 1, nor 5, AL returns FFH and the state of CONTROL+C checking is
unaffected.
MS-DOS normally checks for CONTROL+C only when carrying out certain
function requests in the 01H through 0CH group (see the description of
specific calls for details). When CONTROL+C checking is on, MS-DOS checks
for CONTROL+C when carrying out any function request. For example, if
CONTROL+C checking is off, all disk I/O proceeds without interruption, but
if it is on, the CONTROL+C interrupt is issued at the function request
that initiates the disk operation.
──────────────────────────────────────────────────────────────────────────
Note
Programs that use Function 06H (Direct Console I/O) or 07H (Direct
Console Input) to read CONTROL+C as data must ensure that the CONTROL+C
checking is off.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ctrl_c_ck macro action,state
mov al,action
mov dl,state
mov ah,33H
int 21H
endm
Example:
The following program displays a message that tells whether CONTROL+C
checking is on or off:
message db "CONTROL+C checking ","$"
on db "on","$",0DH,0AH,"$"
off db "off","$",0DH,0AH,"$"
;
begin: display message ; See Function 09H
ctrl_c_ck 0 ; THIS FUNCTION
cmp dl,0 ; Is checking off?
jg ck_on ; No
display off ; See Function 09H
jmp return ; Go home
ck_on: display on ; See Function 09H
To query the DOS boot drive value, add the following programs segment:
mov AH,33H ; Query DOS value
mov AL,05H ; DOS boot drive
int 21H
jc ERROR ; DL=Boot drive (A=1)
────────────────────────────────────────────────────────────────────────────
Get Interrupt Vector (Function 35H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 35H
AL
Interrupt number
Return:
ES:BX
Pointer to interrupt routine
Comments:
Function 35H gets the address from the interrupt-vector table for the
specified interrupt. AL must contain the number of an interrupt.
ES returns the segment address of the interrupt handler; BX returns the
offset.
To avoid compatibility problems, programs should never read an interrupt
vector directly from memory, nor set an interrupt vector by writing it
into memory. Use this function request to get a vector and Function 25H
(Set Interrupt Vector) to set a vector, unless your program must be
compatible with MS-DOS versions earlier than 2.0.
Macro Definition:
get_vector macro interrupt
mov al,interrupt
mov ah,35H
int 21H
endm
Example:
The following program displays the segment and offset (CS:IP) for the
handler for Interrupt 25H (Absolute Disk Read).
message db "Interrupt 25H -- CS:0000 IP:0000"
db 0DH,0AH,"$"
vec_seg db 2 dup (?)
vec_off db 2 dup (?)
;
begin: push es ; save ES
get_vector 25H ; THIS FUNCTION
mov ax,es ; INT25H segment in AX
pop es ; save ES
convert ax,16,message[20] ; see end of chapter
convert bx,16,message[28] ; see end of chapter
display message ; See Function 9
────────────────────────────────────────────────────────────────────────────
Get Disk Free Space (Function 36H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 36H
DL
Drive (0=default, 1=A, etc.)
Return:
AX
0FFFFH if drive number is invalid;
otherwise, sectors per cluster
BX
Available clusters
CX
Bytes per sector
DX
Clusters per drive
Comments:
Function 36H returns the number of clusters available on the disk in the
specified drive and the information necessary to calculate the number of
bytes available on the disk. DL must contain a drive number (0=default,
1=A, etc.). If the drive number is valid, MS-DOS returns the information
in the following registers:
Register Contents
──────────────────────────────────────────────────────────────────────────
AX Sectors per cluster
BX Available clusters
CX Bytes per sector
DX Total clusters
──────────────────────────────────────────────────────────────────────────
If the drive number is invalid, AX returns 0FFFFH.
This call supersedes Functions 1BH and 1CH in earlier MS-DOS versions.
Macro Definition:
get_disk_space macro drive
mov dl,drive
mov ah,36H
int 21H
endm
Example:
The following program displays space information for the disk in drive B.
message db " clusters on drive B.",0DH,0AH ; DX
db " clusters available.",0DH,0AH ; BX
db " sectors per cluster.",0DH,0AH ; AX
db " bytes per sector,",0DH,0AH,"$" ; CX
;
begin: get_disk_space 2 ; THIS FUNCTION
convert ax,10,message[55] ; see end of chapter
convert bx,10,message[28] ; see end of chapter
convert cx,10,message[83] ; see end of chapter
convert dx,10,message ; see end of chapter
display message ; See Function 09H
────────────────────────────────────────────────────────────────────────────
Get Country Data (Function 38H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 38H
AL
00H = Current country
1-0FEH = Country code
0FFH = BX contains country code
BX (if AL = 0FFH)
Country code 255 or higher
DS:DX
Pointer to 32-byte memory area
Return:
Carry set:
AX
2 = Invalid country code
DS:DX
Segment:offset pointer to 32-byte memory area
Carry not set:
BX
Country code
Comments:
Function 38H gets the country-dependent information that MS-DOS uses to
control the keyboard and display, or it sets the currently defined country
(to set the country code, see the next function request description, Set
Country Data). To get the information, DX must contain the offset (from
the segment address in DS) of a 32-byte memory area to which the country
data returns. AL specifies the country code:
Value in AL Meaning
──────────────────────────────────────────────────────────────────────────
00H Retrieves information about the country currently set
1 to 0FEH Retrieves information about the country identified by
this code
0FFH Retrieves information about the country identified by
the code in BX
──────────────────────────────────────────────────────────────────────────
BX must contain the country code if the code is 255 or greater. The
country code is usually the international telephone-prefix code. The
country-dependent information returns in the following form:
Offset
Hex Decimal Field Name Length in bytes
──────────────────────────────────────────────────────────────────────────
00H 0 Date format 2 (word)
02H 2 Currency symbol 5 (ASCIZ string)
07H 7 Thousands separator 2 (ASCIZ string)
09H 9 Decimal separator 2 (ASCIZ string)
0BH 11 Date separator 2 (ASCIZ string)
0DH 13 Time separator 2 (ASCIZ string)
0FH 15 Bit field 1
10H 16 Currency places 1
11H 17 Time format 1
12H 18 Case-map call address 4 (DWORD)
16H 22 Data-list separator 2 (ASCIZ string)
18H 24 Reserved 10
──────────────────────────────────────────────────────────────────────────
Date Format:
0 = USA (month/day/year)
1 = Europe (day/month/year)
2 = Japan (year/month/day)
Bit Field:
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 0 Currency symbol precedes amount
1 Currency symbol follows amount
1 0 No space between symbol and amount
1 One space between symbol and amount
──────────────────────────────────────────────────────────────────────────
All other bits are undefined.
Time Format:
0 = 12-hour clock
1 = 24-hour clock
Currency Places:
Specifies the number of places that appear after the decimal point on
currency amounts.
Case-Mapping Call Address:
Specifies the segment and offset of a FAR procedure that performs
country-specific lowercase-to-uppercase mapping on character values from
80H to 0FFH. You call it with the character to be mapped in AL. If there
is an uppercase code for the character, it is returned in AL; if there is
not, or if you call it with a value less than 80H in AL, AL returns
unchanged. AL and the FLAGS are the only altered registers.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 Invalid country code (no table for it).
──────────────────────────────────────────────────────────────────────────
Macro Definition:
get_country macro country,buffer
local gc_01
mov dx,offset buffer
mov ax,country
cmp ax,OFFH
jl gc_01
mov al,OFFh
mov bx,country
gc_01: mov ah,38h
int 21H
endm
Example:
The following program displays the time and date in the format appropriate
to the current country code, and the number 999,999 and 99/100 as a
currency amount with the proper currency symbol and separators.
time db " : : ",5 dup (20H),"$"
date db " / / ",5 dup (20H),"$"
number db "999?999?99",0DH,0AH,"$"
data_area db 32 dup (?)
;
begin: get_country 0,data_area ; THIS FUNCTION
get_time ; See Function 2CH
byte_to_dec ch,time ; See end of chapter
byte_to_dec cl,time[03H] ; for description of
byte_to_dec dh,time[06H] ; CONVERT macro
get_date ; See Function 2AH
sub cx,1900 ; Want last 2 digits
byte_to_dec cl,date[06H] ; See end of chapter
cmp word ptr data_area,0 ; Check country code
jne not_usa ; It's not USA
byte_to_dec dh,date ; See end of chapter
byte_to_dec dl,date[03H] ; See end of chapter
jmp all_done ; Display data
not_usa: byte_to_dec dl,date ; See end of chapter
byte_to_dec dh,date[03H] ; See end of chapter
all_done: mov al,data_area[07H] ; Thousand separator
mov number[03H],al ; Put in NUMBER
mov al,data_area[09H] ; Decimal separator
mov number[07H],al ; Put in AMOUNT
display time ; See Function 09H
display date ; See Function 09H
display_char data_area[02H] ; See Function 02H
display number ; See Function 09H
────────────────────────────────────────────────────────────────────────────
Set Country Data (Function 38H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 38H
DX = -1 (0FFFFH)
AL
Country code less than 255, or
0FFH if the country code is in BX
BX (if AL=0FFH)
Country code 255 or higher
Return:
Carry set:
AX
2 = Invalid country code
Carry not set:
No error
Comments:
Function 38H sets the country code that MS-DOS uses to control the
keyboard and the display, or it retrieves the country-dependent
information (to get the country data, see the previous function request
description, Get Country Data). To set the information, DX must contain
0FFFFH. AL must contain either the country code, if it is less than 255,
or 255 to indicate that the country code is in BX. If AL contains 0FFH, BX
must contain the country code.
The country code is usually the international telephone prefix-code. See
"Get Country Data" for a description of the country data and how it is
used.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 Invalid country code (no table for it).
──────────────────────────────────────────────────────────────────────────
Macro Definition:
set_country macro country
local sc_01
mov dx,0FFFFH
mov ax,country
cmp ax,0FFH
jl sc_01
mov bx,country
mov al,0ffh
sc_01: mov ah,38H
int 21H
endm
Example:
The following program sets the country code to the United Kingdom (44).
uk equ 44
;
begin: set_country uk ; THIS FUNCTION
jc error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Create Directory (Function 39H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 39H
DS:DX
Pointer to pathname
Return:
Carry set:
AX
2 = File not found
3 = Path not found
5 = Access denied
Carry not set:
No error
Comments:
Function 39H creates a new subdirectory. DX must contain the offset (from
the segment address in DS) of an ASCIZ string that specifies the pathname
of the new subdirectory.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 File not found
3 Path not found
5 No room in the parent directory, a file with the same
name exists in the current directory, or the path
──────────────────────────────────────────────────────────────────────────
Macro Definition:
make_dir macro path
mov dx,offset path
mov ah,39H
int 21H
endm
Example:
The following program adds a subdirectory named new_dir to the root
directory on the disk in drive B and changes the current directory to
new_dir. The program then changes the current directory back to the
original directory and then deletes new_dir. It displays the current
directory after each step to confirm the changes.
old_path db "b:",0,63 dup (?)
new_path db "b:\new_dir",0
buffer db "b:",0,63 dup (?)
;
begin: get_dir 2,old_path[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz old_path ; See end of chapter
make_dir new_path ; THIS FUNCTION
jc error_make ; Routine not shown
change_dir new_path ; See Function 3BH
jc error_change ; Routine not shown
get_dir 2,buffer[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz buffer ; See end of chapter
change_dir old_path ; See Function 3BH
jc error_change ; Routine not shown
rem_dir new_path ; See Function 3AH
jc error_rem ; Routine not shown
get_dir 2,buffer[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz buffer ; See end of chapter
────────────────────────────────────────────────────────────────────────────
Remove Directory (Function 3AH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 3AH
DS:DX
Pointer to pathname
Return:
Carry set:
AX
2 = File not found
3 = Path not found
5 = Access denied
16 = Current directory
Carry not set:
No error
Comments:
Function 3AH deletes a subdirectory. DX must contain the offset (from the
segment address in DS) of an ASCIZ string that specifies the pathname of
the subdirectory you want to delete.
The subdirectory must not contain any files. You cannot erase the current
directory. If there is an error, the carry flag (CF) is set and the error
code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 File not found
3 Path not found
5 Directory not empty, or path doesn't specify a
directory, or it specifies the root directory, or it is
invalid
16 Path specifies current directory
──────────────────────────────────────────────────────────────────────────
Macro Definition:
rem_dir macro path
mov dx,offset path
mov ah,3AH
int 21H
endm
Example:
The following program adds a subdirectory named new_dir to the root
directory on the disk in drive B and changes the current directory to
new_dir. The program then changes the current directory back to the
original directory and deletes new_dir. It displays the current directory
after each step to confirm the changes.
old_path db "b:",0,63 dup (?)
new_path db "b:\new_dir",0
buffer db "b:",0,63 dup (?)
;
begin: get_dir 2,old_path[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz old_path ; See end of chapter
make_dir new_path ; See Function 39H
jc error_make ; Routine not shown
change_dir new_path ; See Function 3BH
jc error_change ; Routine not shown
get_dir 2,buffer[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz buffer ; See end of chapter
change_dir old_path ; See Function 3BH
jc error_change ; Routine not shown
rem_dir new_path ; THIS FUNCTION
jc error_rem ; Routine not shown
get_dir 2,buffer[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz buffer ; See end of chapter
────────────────────────────────────────────────────────────────────────────
Change Current Directory (Function 3BH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 3BH
DS:DX
Pointer to pathname
Return:
Carry set:
AX
2 = File not found
3 = Path not found
Carry not set:
No error
Comments:
Function 3BH changes the current directory. DX must contain the offset
(from the segment address in DS) of an ASCIZ string that specifies the
pathname of the new current directory.
The directory string is limited to 64 characters.
If any member of the path doesn't exist, the path is unchanged. If there
is an error, the carry flag (CF) is set and the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 File not found
3 Path either doesn't exist or it specifies a file
──────────────────────────────────────────────────────────────────────────
Macro Definition:
change_dir macro path
mov dx,offset path
mov ah,3BH
int 21H
endm
Example:
The following program adds a subdirectory named new_dir to the root
directory that is on the disk in drive B and changes the current directory
to new_dir. The program then changes the current directory back to the
original directory and deletes new_dir. It displays the current directory
after each step to confirm the changes.
old_path db "b:",0,63 dup (?)
new_path db "b:\new_dir",0
buffer db "b:",0,63 dup (?)
;
begin: get_dir 2,old_path[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz old_path ; See end of chapter
make_dir new_path ; See Function 39H
jc error_make ; Routine not shown
change_dir new_path ; THIS FUNCTION
jc error_change ; Routine not shown
get_dir 2,buffer[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz buffer ; See end of chapter
change_dir old_path ; See Function 3BH
jc error_change ; Routine not shown
rem_dir new_path ; See Function 3AH
jc error_rem ; Routine not shown
get_dir 2,buffer[03H] ; See Function 47H
jc error_get ; Routine not shown
display_asciz buffer ; See end of chapter
────────────────────────────────────────────────────────────────────────────
Create Handle (Function 3CH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 3CH
DS:DX
Pointer to pathname
CX
File attribute
Return:
Carry set:
AX
2 = File not found
3 = Path not found
4 = Too many open files
5 = Access denied
Carry not set:
AX
Handle
Comments:
Function 3CH creates a file and assigns it the first available handle. DX
must contain the offset (from the segment address in DS) of an ASCIZ
string that specifies the pathname of the file to be created. CX must
contain the attribute to be assigned to the file, as described under "File
Attributes" earlier in this chapter.
If the specified file does not exist, this function creates it. But if the
file already exists, it is truncated to a length of 0. Function 3CH then
assigns the attribute in CX to the file and opens it for read/write. AX
returns the file handle. If there is an error, the carry flag (CF) is set
and the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 File not found
3 Path is invalid
4 Too many open files (no handle available)
5 Directory is full, a directory with the same name
exists, or a file with the same name exists with more
──────────────────────────────────────────────────────────────────────────
Macro Definition:
create_handle macro path,attrib
mov dx,offset path
mov cx,attrib
mov ah,3CH
int 21H
endm
Example:
The following program creates a file named dir.tmp, containing the name
and extension of each file in the current directory, on the disk in drive
B.
srch_file db "b:*.*",0
tmp_file db "b:dir.tmp",0
buffer db 43 dup (?)
handle dw ?
;
begin: set_dta buffer ; See Function 1AH
find_first_file srch_file,16H ; See Function 4EH
cmp ax,12H ; Directory empty?
je all_done ; Yes, go home
create_handle tmp_file,0 ; THIS FUNCTION
jc error ; Routine not shown
mov handle,ax ; Save handle
write_it: write_handle handle,buffer[1EH],12 ; Function 40H
find_next_file ; See Function 4FH
cmp ax,12H ; Another entry?
je all_done ; No, go home
jmp write_it ; Yes, write record
all_done: close_handle handle ; See Function 3EH
────────────────────────────────────────────────────────────────────────────
Open Handle (Function 3DH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 3DH
AL
Access code (see text)
DS:DX
Pointer to pathname
Return:
Carry set:
AX
2 = File not found
3 = Path not found
4 = Too many open files
5 = Access denied
12 = Invalid access
Carry not set:
No error
Comments:
Function 3DH opens any file, including hidden and system files, for input
or output. DX contains the offset (from the segment address in DS) of an
ASCIZ string that specifies the pathname of the file to be opened. AL
contains a code that specifies how the file is to be opened. This code is
described later under "Controlling Access to the File."
If there is no error, AX returns the file handle. MS-DOS sets the
read/write pointer to the first byte of the file.
Controlling Access to the File
The value in AL is made up of three parts that specify whether the file is
to be opened for read, write, or both (access code); what access other
processes have to the file (sharing mode); and whether a child process
inherits the file (inherit bit).
┌───┬───────────┬───────────────┐
Bit │ 7 │ 6 5 4 │ 3 2 1 0 │
└───┴───────────┴───────────────┘
\_/ \_________/ \______________/
│ │ │
│ │ └────────> Access code
│ │
│ └──────────────────────> Sharing mode
│
└──────────────────────────────> Inherit bit
Inherit Bit
The high-order bit (bit 7) specifies whether the file is inherited by a
child process created with Function 4B00H or 4B03H (Load and Execute
Program or Overlay). If the bit is 0, the child process inherits the file;
if the bit is 1, it doesn't.
Sharing Mode
The sharing mode bits (bits 4-6) specify what access, if any, other
processes have to the open file. It can have the following values:
Table 1.21
Sharing Mode Bit Values
Bits 4-6 Sharing Mode Description
──────────────────────────────────────────────────────────────────────────
000 Compatibility On a given machine, any process can open
the file any number of times with this
mode. Fails if the file has been opened
with any of the other sharing modes.
001 Deny both Fails if the file has been opened in
compatibility mode or for read or write
access, even if by the current process.
010 Deny write Fails if the file has been opened in
compatibility mode or for write access by
any other process.
011 Deny read Fails if the file has been opened in
compatibility mode or for read access by
any other process.
100 Deny none Fails if the file has been opened in
──────────────────────────────────────────────────────────────────────────
Access Code
The access code (bits 0-3) specifies how the file is to be used. It can
have the following values:
Table 1.22
Access Code Bit Values
Access
Bits 0-3 Allowed Description
──────────────────────────────────────────────────────────────────────────
0000 Read Fails if the file has been opened in deny read
or deny both sharing mode.
0001 Write Fails if the file has been opened in deny write
or deny both sharing mode.
0010 Both Fails if the file has been opened in deny read,
──────────────────────────────────────────────────────────────────────────
If there is an error, the carry flag (CF) is set and the error code is
returned in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 Specified file is invalid or doesn't exist
3 Specified path is invalid or doesn't exist
4 No handles are available in the current process or the
internal system tables are full
5 Program attempted to open a directory or VolumeID, or
tried to open a read-only file for writing
12 Access code (bits 0-3 of AL) not 0, 1, or 2
──────────────────────────────────────────────────────────────────────────
If this system call fails because of a file-sharing error, MS-DOS issues
Interrupt 24H with error code 2 (Drive Not Ready). A subsequent Function
59H (Get Extended Error) returns the extended error code that specifies a
sharing violation.
When opening a file, it is important to inform MS-DOS of any operations
that other processes may perform on this file (sharing mode). The default
(compatibility mode) denies all other processes access to the file, unless
they also attempt to open the file in compatibility mode. The following
table shows the effect of opening a file with compatibility mode set:
Type of File Opening Read-Only File Not Read-Only
──────────────────────────────────────────────────────────────────────────
First open for read, write, or Succeeds Succeeds
both by machine/process "N"
Subsequent opens by machine or Succeeds Succeeds
process "N"
An open by another machine or Succeeds Fails
process
──────────────────────────────────────────────────────────────────────────
Files may be read-only with the MS-DOS attrib command or by a read-only
share over the network.
It may be all right for other processes to continue to read the file while
your process is operating on it. In this case, you should specify "Deny
Write," which inhibits other processes from writing to your files but
allows them to read from these files.
Similarly, it is important for you to specify what operations your process
will perform ("Access" mode). If another process has the file open with
any sharing mode other than "Deny" mode, then the default mode
("Read/Write") causes the open request to fail. If you only want to read
the file, your open request succeeds unless all other processes have
specified "Deny" mode or "Deny write."
Macro Definition:
open_handle macro path,access
mov dx, offset path
mov al, access
mov ah, 3DH
int 21H
endm
Example:
The following program prints a file named textfile.asc that is on the disk
in drive B.
file db "b:textfile.asc",0
buffer db ?
handle dw ?
;
begin: open_handle file,0 ; THIS FUNCTION
mov handle,ax ; Save handle
read_char: read_handle handle,buffer,1 ; Read 1 character
jc error_read ; Routine not shown
cmp ax,0 ; End of file?
je return ; Yes, go home
print_char buffer ; See Function 05H
jmp read_char ; Read another
────────────────────────────────────────────────────────────────────────────
Close Handle (Function 3EH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 3EH
BX
Handle
Return:
Carry set:
AX
6 = Invalid handle
Carry not set:
No error
Comments:
Function 3EH closes a file opened with Function 3DH (Open Handle) or
3CH (Create Handle). BX must contain the handle of the open file that you
want to close.
If there is no error, MS-DOS closes the file and flushes all internal
buffers. If there is an error, the carry flag (CF) is set and the error
code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
6 Handle not open or invalid
──────────────────────────────────────────────────────────────────────────
Macro Definition:
close_handle macro handle
mov bx,handle
mov ah,3EH
int 21H
endm
Example:
The following program creates a file named dir.tmp, containing the
filename and extension of each file in the current directory, in the
current directory on the disk in drive B.
srch_file db "b:*.*",0
tmp_file db "b:dir.tmp",0
buffer db 43 dup (?)
handle dw ?
;
begin: set_dta buffer ; See Function 1AH
find_first_file srch_file,16H ; See Function 4EH
cmp ax,12H ; Directory empty?
je all_done ; Yes, go home
create_handle tmp_file,0 ; See Function 3CH
jc error_create ; Routine not shown
mov handle,ax ; Save handle
write_it: write_handle handle,buffer[1EH],12 ; See Function
jc error_write ; 40H
find_next_file ; See Function 4FH
cmp ax,12H ; Another entry?
je all_done ; No, go home
jmp write_it ; Yes, write record
all_done: close_handle handle ; See Function 3EH
jc error_close ; Routine not shown
────────────────────────────────────────────────────────────────────────────
Read Handle (Function 3FH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 3FH
BX
Handle
CX
Bytes to read
DS:DX
Pointer to buffer
Return:
Carry set:
AX
5 = Access denied
6 = Invalid handle
Carry not set:
AX
Bytes read
Comments:
Function 3FH reads from the file or device associated with the specified
handle. BX must contain the handle. CX must contain the number of bytes to
be read. DX must contain the offset (to the segment address in DS) of the
buffer.
If there is no error, AX returns the number of bytes read; if you attempt
to read starting at end of file, AX returns 0. The number of bytes
specified in CX is not necessarily transferred to the buffer; if you use
this call to read from the keyboard, for example, it reads only up to the
first carriage-return.
If you use this function request to read from standard input, you can
redirect the input.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
5 Handle not open for reading
6 Handle not open or invalid
──────────────────────────────────────────────────────────────────────────
Macro Definition:
read_handle macro handle,buffer,bytes
mov bx,handle
mov dx,offset buffer
mov cx,bytes
mov ah,3FH
int 21H
endm
Example:
The following program displays a file named textfile.asc that is on the
disk in drive B.
filename db "b:\textfile.asc",0
buffer db 129 dup (?)
handle dw ?
;
begin: open_handle filename,0 ; See Function 3DH
jc error_open ; Routine not shown
mov handle,ax ; Save handle
read_file: read_handle buffer,file_handle,128
jc error_open ; Routine not shown
cmp ax,0 ; End of file?
je return ; Yes, go home
mov bx,ax ; # of bytes read
mov buffer[bx],"$" ; Make a string
display buffer ; See Function 09H
jmp read_file ; Read more
────────────────────────────────────────────────────────────────────────────
Write Handle (Function 40H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 40H
BX
Handle
CX
Bytes to write
DS:DX
Pointer to buffer
Return:
Carry set:
AX
5 = Access denied
6 = Invalid handle
Carry not set:
AX
Bytes written
Comments:
Function 40H writes to the file or device associated with the specified
handle. BX must contain the handle. CX must contain the number of bytes to
be written. DX must contain the offset (to the segment address in DS) of
the data to be written.
If you set CX to zero, the file will be truncated at the current position
of the file pointer. MS-DOS will not perform the write if the handle is
read-only.
If there is no error, AX returns the number of bytes written. Be sure to
check AX after performing a write. If its value is less than the number in
CX when the call was made, it indicates an error, even though the carry
flag isn't set. If AX contains 0, and if the target is a disk file, the
disk is full.
If you use this function request to write to standard output, you can
redirect the output. If you call this request with CX=0, the file size is
set to the value of the read/write pointer. To satisfy the new file size,
allocation units are allocated or released, as required. If there is an
error, the carry flag (CF) is set and the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
5 Handle not open for writing
6 Handle not open or invalid
──────────────────────────────────────────────────────────────────────────
Macro Definition:
write_handle macro handle,buffer,bytes
mov bx,handle
mov dx,offset buffer
mov cx,bytes
mov ah,40H
int 21H
endm
Example:
The following program creates a file named dir.tmp, containing the
filename and extension of each file in the current directory, in the
current directory on the disk in drive B.
srch_file db "b:*.*",0
tmp_file db "b:dir.tmp",0
buffer db 43 dup (?)
handle dw ?
;
begin: set_dta buffer ; See Function 1AH
find_first_file srch_file,16H ; Check directory
cmp ax,12H ; Directory empty?
je return ; Yes, go home
create_handle tmp_file,0 ; See Function 3CH
jc error_create ; Routine not shown
mov handle,ax ; Save handle
write_it: write_handle handle,buffer[1EH],12 ; THIS FUNCTION
jc error_write ; Routine not shown
find_next_file ; Check directory
cmp ax,12H ; Another entry?
je all_done ; No, go home
jmp write_it ; Yes, write record
all_done: close_handle handle ; See Function 3EH
jc error_close ; Routine not shown
────────────────────────────────────────────────────────────────────────────
Delete Directory Entry [Unlink] (Function 41H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 41H
DS:DX
Pointer to pathname
Return:
Carry set:
AX
2 = File not found
3 = Path not found
5 = Access denied
Carry not set:
No error
Comments:
Function 41H erases a file by deleting its directory entry. DX must
contain the offset (from the segment address in DS) of an ASCIZ string
that specifies the pathname of the file that you want to delete. You
cannot use wildcard characters.
If the file exists and is not read-only, the call deletes it. If there is
an error, the call sets the carry flag (CF) and the error code returns in
AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 File doesn't exist, or specifies a directory
3 Path is invalid
5 File is read-only
──────────────────────────────────────────────────────────────────────────
To delete a file with the read-only attribute, first change its attribute
to 0 with Function 43H (Get/Set File Attributes).
Macro Definition:
delete_entry macro path
mov dx,offset path
mov ah,41H
int 21H
endm
Example:
The following program deletes all files, dated before December 31, 1986,
from the disk in drive B.
year db 1986
month db 12
day db 31
files db ?
message db "NO FILES DELETED.",0DH,0AH,"$"
path db "b:*.*", 0
buffer db 43 dup (?)
;
begin: set_dta buffer ; See Function 1AH
select_disk "B" ; See Function 0EH
find_first_file path,0 ; See Function 4EH
jnc compare ; got one
jmp all_done ; no match, go home
compare: convert_date buffer[-1] ; See end of chapter
cmp cx,year ; After 1986?
jg next ; Yes, don't delete
cmp dl,month ; After December?
jg next ; Yes, don't delete
cmp dh,day ; 31st or after?
jge next ; Yes, don't delete
delete_entry buffer[1EH] ; THIS FUNCTION
jc error_delete ; Routine not shown
inc files ; Bump file counter
next: find_next_file ; Check directory
jnc compare ; Go home if done
how_many: cmp files,0 ; Was directory empty?
je all_done ; Yes, go home
convert files,10,message ; See end of chapter
all_done: display message ; See Function 09H
select_disk "A" ; See Function 0EH
────────────────────────────────────────────────────────────────────────────
Move File Pointer (Function 42H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 42H
AL
Method of moving
BX
Handle
CX:DX
Distance in bytes (offset)
Return:
Carry set:
AX
1 = Invalid function
6 = Invalid handle
Carry not set:
DX:AX
New read/write pointer location
Comments:
Function 42H moves the read/write pointer of the file associated with the
specified handle. BX must contain the handle. CX and DX must contain a
32-bit offset (CX contains the most significant byte). AL must contain a
code that specifies how to move the pointer:
Code Cursor Moved to
──────────────────────────────────────────────────────────────────────────
0 Beginning of file plus the offset
1 Current pointer location plus the offset
2 End of file plus the offset
──────────────────────────────────────────────────────────────────────────
DX and AX return the new location of the read/write pointer (a 32-bit
integer; DX contains the most significant byte). You can determine the
length of a file by setting CX:DX to 0, AL to 2, and calling this
function. DX:AX returns the offset of the byte following the last byte in
the file (size of the file in bytes). If there is an error, the carry flag
(CF) is set and the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 0, 1, or 2
6 Handle not open
──────────────────────────────────────────────────────────────────────────
Macro Definition:
move_ptr macro handle,high,low,method
mov bx,handle
mov cx,high
mov dx,low
mov al,method
mov ah,42H
int 21H
endm
Example:
The following program prompts for a letter, converts it to its alphabetic
sequence (A=1, B=2, etc.), then reads and displays the corresponding
record from the file named alphabet.dat that is in the current directory
on the disk in drive B. The file contains 26 records, each 28 bytes long.
file db "b:alphabet.dat",0
buffer db 28 dup (?),"$"
prompt db "Enter letter: $"
crlf db 0DH,0AH,"$"
handle db ?
record_length dw 28
;
begin: open_handle file,0 ; See Function 3DH
jc error_open ; Routine not shown
mov handle,ax ; Save handle
get_char: display prompt ; See Function 09H
read_kbd_and_echo ; See Function 01H
sub al,41h ; Convert to sequence
mul byte ptr record_length ; Calculate offset
move_ptr handle,0,ax,0 ; THIS FUNCTION
jc error_move ; Routine not shown
read_handle handle,buffer,record_length
jc error_read ; Routine not shown
cmp ax,0 ; End of file?
je return ; Yes, go home
display crlf ; See Function 09H
display buffer ; See Function 09H
display crlf ; See Function 09H
jmp get_char ; Get another character
────────────────────────────────────────────────────────────────────────────
Get/Set File Attributes (Function 43H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 43H
AL
0 = Get attributes
1 = Set attributes
CX (if AL=1)
Attributes to be set
DS:DX
Pointer to pathname
Return:
Carry set:
AX
1 = Invalid function
2 = File not found
3 = Path not found
5 = Access denied
Carry not set:
CX
Attribute byte (if AL=0)
Comments:
Function 43H gets or sets the attributes of a file. DX must contain the
offset (from the segment address in DS) of an ASCIZ string that specifies
the pathname of a file. AL must specify whether to get or set the
attribute (0=get, 1=set).
If AL is 0 (get the attribute), the attribute byte returns in CX. If AL is
1 (set the attribute), CX must contain the attributes to be set. See
Section 1.5.5, "File Attributes," for a description of the attributes.
You cannot change the VolumeID bit (08H) or the Subdirectory bit (10H) of
the attribute byte with this function.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 0 or 1
2 File doesn't exist
3 Path invalid
5 Attribute in CX cannot be changed (Subdirectory or
──────────────────────────────────────────────────────────────────────────
Macro Definition:
change_attr macro path,action,attrib
mov dx,offset path
mov al,action
mov cx,attrib
mov ah,43H
int 21H
endm
Example:
The following program displays the attributes assigned to the file named
report.asm that is in the current directory on the disk in drive B.
header db 15 dup (20h),"Read-",0DH,0AH
db "Filename Only Hidden "
db "System Volume Sub-Dir Archive"
db 0DH,0AH,0DH,0AH,"$"
path db "b:report.asm",3 dup (0),"$"
attribute dw ?
blanks db 9 dup (20h),"$"
;
begin: change_attr path,0,0 ; THIS FUNCTION
jc error_mode ; Routine not shown
mov attribute,cx ; Save attribute byte
display header ; See Function 09H
display path ; See Function 09H
mov cx,6 ; Check 6 bits (0-5)
mov bx,1 ; Start with bit 0
chk_bit: test attribute,bx ; Is the bit set?
jz no_attr ; No
display_char "X" ; See Function 02H
jmp short next_bit ; Done with this bit
no_attr: display_char 20h ; See Function 02H
next_bit: display blanks ; See Function 09H
shl bx,1 ; Move to next bit
loop chk_bit ; Check it
────────────────────────────────────────────────────────────────────────────
IOCtl Data (Function 44H, Codes 0 and 1)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL
0 = Get device data
1 = Set device data
BX
Handle
DX
Device data (see text)
Return:
Carry set:
AX
1 = Invalid function
6 = Invalid handle
Carry not set:
DX
Device data
Comments:
Function 44H, Codes 0 and 1, either gets or sets the data MS-DOS uses to
control the device. AL must contain 0 to get the data or 1 to set it. BX
must contain the handle. If AL is 1, DH must contain 0.
The device-data word is specified or returned in DX. If bit 7 of the data
is 1, the handle refers to a device and the other bits have the meanings
shown in Table 1.23.
Table 1.23
MS-DOS Data Bit Values
╓┌─┌──────────┌────────────────────┌─────────────────────────────────────────╖
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 1 Console input device
1 1 Console output device
2 1 Null device
3 1 Clock device
4 1 Reserved
5 1 Don't check for control characters
0 Check for control characters
6 0 End of file on input
8-10 Reserved
11 1 Device understands open/close
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
11 1 Device understands open/close
12 Reserved
13 1 Device supports output until busy
14 1 Device can process control strings sent
with Functions 4402H and 4403H (IOCtl
character); bit can be read only, but not
set
15 Reserved
──────────────────────────────────────────────────────────────────────────
You must set the reserved bits to zero.
The control characters referred to in the description of bit 5 are
CONTROL+C, CONTROL+P, CONTROL+S, and CONTROL+Z. To read these characters
as data, instead of as control characters, you must set bit 5 and use
either Function 33H, CONTROL+C Check, or the MS-DOS break command to turn
off CONTROL+C checking.
If bit 7 of DX is 0, the handle refers to a file and the other bits have
the following meanings:
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0-5 Drive number (0=A, 1=B, etc.)
6 0 The file has been written
8-15 Reserved
──────────────────────────────────────────────────────────────────────────
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 0 or 1, or AL is 1 but DH is not 0
6 Handle in BX not open or is invalid
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ioctl_data macro code,handle
mov bx,handle
mov al,code
mov ah,44H
int 21H
endm
Example:
The following program gets the device data for standard output, sets the
bit that specifies not to check for control characters (bit 5), and then
clears the bit.
get equ 0
set equ 1
stdout equ 1
;
begin: ioctl_data get,stdout ; THIS FUNCTION
jc error ; routine not shown
mov dh,0 ; clear DH
or dl,20H ; set bit 5
ioctl_data set,stdout ; THIS FUNCTION
jc error ; routine not shown
;
; <control characters now treated as data, or "raw mode">
;
ioctl_data get,stdout ; THIS FUNCTION
jc error ; routine not shown
mov dh,0 ; clear DH
and dl,0DFH ; clear bit 5
ioctl_data set,stdout ; THIS FUNCTION
;
; <control characters now interpreted, or "cooked mode">
;
────────────────────────────────────────────────────────────────────────────
IOCtl Character (Function 44H, Codes 2 and 3)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL
2 = Send control data
3 = Receive control data
BX
Handle
CX
Bytes to read or write
DS:DX
Pointer to buffer
Return:
Carry set:
AX
1 = Invalid function
6 = Invalid handle
Carry not set:
AX
Bytes transferred
Comments:
Function 44H, Codes 2 and 3, sends or receives control data to or from a
character device. AL must contain 2 to send data or 3 to receive. BX must
contain the handle of a character device, such as a printer or serial
port. CX must contain the number of bytes to be read or written. DX must
contain the offset (to the segment address in DS) of the data buffer.
AX returns the number of bytes transferred. The device driver must support
the IOCtl interface. If there is an error, the carry flag (CF) is set and
the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 2 or 3, or device cannot perform the specified
function
6 Handle in BX not open or doesn't exist
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ioctl_char macro code,handle,buffer
mov bx,handle
mov dx,offset buffer
mov al,code
mov ah,44H
int 21H
endm
Example:
No general example is applicable, since processing of IOCtl control data
depends on the device being used, as well as the device driver.
────────────────────────────────────────────────────────────────────────────
IOCtl Block (Function 44H, Codes 4 and 5)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL
4 = Send control data
5 = Receive control data
BL
Drive number (0=default, 1=A, etc.)
CX
Bytes to read or write
DS:DX
Pointer to buffer
Return:
Carry set:
AX
1 = Invalid function
5 = Invalid drive
Carry not set:
AX
Bytes transferred
Comments:
Function 44H, Codes 4 and 5, sends or receives control data to or from a
block device. AL must contain 4 to send data or 5 to receive. BL must
contain the drive number (0=default, 1=A, etc.). CX must contain the
number of bytes to be read or written. DX must contain the offset (to the
segment address in DS) of the data buffer.
AX returns the number of bytes transferred. The device driver must support
the IOCtl interface. To determine whether or not it does, use Function
4400H to get the device data, and test bit 14; if the bit is set, the
driver supports IOCtl. If there is an error, the carry flag (CF) is set
and the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 4 or 5, or device cannot perform the specified
function
5 Number in BL not a valid drive number
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ioctl_status macro code,drive,buffer
mov bl,drive
mov dx,offset buffer
mov al,code
mov ah,44H
int 21H
endm
Example:
No general example is applicable, since processing of IOCtl control data
depends on the device being used, as well as the device driver.
────────────────────────────────────────────────────────────────────────────
IOCtl Status (Function 44H, Codes 6 and 7)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL
6 = Check input status
7 = Check output status
BX
Handle
Return:
Carry set:
AX
1 = Invalid function
5 = Access denied
6 = Invalid handle
13 = Invalid data
Carry not set:
AL
00H = Not ready
0FFH = Ready
Comments:
Function 44H, Codes 6 and 7, checks whether or not the file or device
associated with a handle is ready. AL must contain 6 to check whether the
handle is ready for input or 7 to check whether the handle is ready for
output. BX must contain the handle.
AL returns the status:
Meaning for Meaning for Meaning for
Value Device Input File Output File
──────────────────────────────────────────────────────────────────────────
00H Not ready Pointer is at EOF Ready
0FFH Ready Ready Ready
──────────────────────────────────────────────────────────────────────────
An output file always returns ready, even if the disk is full. bp If there
is an error, the carry flag (CF) is set and the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 6 or 7
5 Access denied
6 Number in BX not a valid, open handle
13 Invalid data
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ioctl_status macro code,handle
mov bx,handle
mov al,code
mov ah,44H
int 21H
endm
Example:
The following program displays a message that tells whether the file
associated with handle 6 is ready for input or whether it is at
end-of-file.
stdout equ 1
;
message db "File is "
ready db "ready."
at_eof db "at EOF."
crlf db ODH,OAH
;
begin: write_handle stdout,message,8 ; display message
jc write_error ; routine not shown
ioctl_status 6 ; THIS FUNCTION
jc ioctl_error ; routine not shown
cmp al,0 ; check status code
jne not_eof ; file is ready
write_handle stdout,at_eof,7 ; see Function 40H
jc write_error ; routine not shown
jmp all_done ; clean up & go home
not_eof: write_handle stdout,ready,6 ; see Function 40H
all_done: write_handle stdout,crlf,2 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
IOCtl Is Changeable (Function 44H, Code 08H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL = 08H
BL
Drive number (0=default, 1=A, etc.)
Return:
Carry set:
AX
1 = Invalid function
15 = Invalid drive
Carry not set:
AX
0 = Changeable
1 = Not changeable
Comments:
Function 44H, Code 08H, checks whether a drive contains a removable or
nonremovable disk. BL must contain the drive number (0=default, 1=A,
etc.). AX returns 0 if the disk can be changed, 1 if it cannot.
This call lets a program determine whether or not to issue a message to
change disks.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 Device does not support this call
15 Number in BL not a valid drive number
──────────────────────────────────────────────────────────────────────────
When the call returns error 1 (because the driver doesn't support it), the
caller assumes that the driver cannot be changed.
Macro Definition:
ioctl_change macro drive
mov bl, drive
mov al, 08H
mov ah, 44H
int 21H
endm
Example:
The following program checks whether or not the current drive contains a
removable disk. If not, processing continues; if so, the program prompts
the user to replace the disk in the current drive.
stdout equ 1
;
message db "Please replace disk in drive "
drives db "ABCD"
crlf db 0DH,0AH
;
begin: ioctl_change 0 ; THIS FUNCTION
jc ioctl_error ; routine not shown
cmp ax,0 ; current drive changeable?
jne continue ; no, continue processing
write_handle stdout,message,29 ; see Function 40H
jc write_error ; routine not shown
current_disk ; see Function 19H
xor bx,bx ; clear index
mov bl,al ; get current drive
display_char drives[bx] ; see Function 02H
write_handle stdout,crlf,2 ; see Function 40H
jc write_error ; routine not shown
continue:
; (Further processing here)
────────────────────────────────────────────────────────────────────────────
IOCtl Is Redirected Block (Function 44H, Code 09H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL = 09H
BL
Drive number (0=default, 1=A, etc.)
Return:
Carry set:
AX
1 = Invalid function code
15 = Invalid drive number
Carry not set:
DX
Device-attribute bits
Comments:
Function 44H, Code 09H, checks whether a drive letter refers to a drive on
a Microsoft Networks workstation (local) or is redirected to a server
(remote). BL must contain the drive number (0=default, 1=A, etc.).
If the block device is local, DX returns the attribute word from the
device header. If the block device is remote, only bit 12 (1000H) is set;
the other bits are 0 (reserved).
An application program should not test bit 12, because applications should
not make distinctions between local and remote files (or devices).
Programs should be written so that they will be independent of the
location of a device that has been removed.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 File sharing must be loaded to use this system call
15 Number in BL not a valid drive number
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ioctl_rblock macro drive
mov bl, drive
mov al, 09H
mov ah, 44H
int 21H
endm
Example:
The following program checks whether or not drive B is local or remote and
displays the appropriate message.
stdout equ 1
;
message db "Drive B: is "
loc db "local."
rem db "remote."
crlf db 0DH,0AH
;
begin: write_handle stdout,message,12 ; display message
jc write_error ; routine not shown
ioctl_rblock 2 ; THIS FUNCTION
jc ioctl_error ; routine not shown
test dx,1000h ; bit 12 set?
jnz not_loc ; yes, it's remote
write_handle stdout,loc,6 ; see Function 40H
jc write_error ; routine not shown
jmp done
not_loc: write_handle stdout,rem,7 ; see Function 40H
jc write_error ; routine not shown
done: write_handle stdout,crlf,2 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
IOCtl Is Redirected Handle (Function 44H, Code 0AH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL = 0AH
BX
Handle
Return:
Carry set:
AX
1 = Invalid function code
6 = Invalid handle
Carry not set:
DX
IOCtl bit field
Comments:
Function 44H, Code 0AH, checks whether a handle refers to a file or a
device on a Microsoft Networks workstation (local) or is redirected to a
server (remote). BX must contain the file handle. DX returns the IOCtl bit
field; bit 15 is set if the handle refers to a remote file or device.
An application program should not test bit 15, because applications should
not make distinctions between local and remote files (or devices).
Programs should be written so that they will be independent of the
location of a device that has been removed.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 Network must be loaded to use this system call
6 Handle in BX not a valid, open handle
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ioctl_rhandle macro handle
mov bx, handle
mov al, 0AH
mov ah, 44H
int 21H
endm
Example:
The following program checks whether handle 5 refers to a local or remote
file or a device and displays the appropriate message.
stdout equ 1
;
message db "Handle 5 is "
loc db "local."
rem db "remote."
crlf db 0DH,0AH
;
begin: write_handle stdout,message,12; display message
jc write_error ; routine not shown
ioctl_rhandle 5 ; THIS FUNCTION
jc ioctl_error ; routine not shown
test dx,8000h ; bit 15 set?
jnz not_loc ; yes, it's remote
write_handle stdout,loc,6 ; see Function 40H
jc write_error ; routine not shown
jmp done
not_loc: write_handle stdout,rem,7 ; see Function 40H
jc write_error ; routine not shown
done: write_handle stdout,crlf,2 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
IOCtl Retry (Function 44H, Code 0BH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL = 0BH
DX
Number of retries
CX
Wait time
Return:
Carry set:
AX
1 = Invalid function code
Carry not set:
No error
Comments:
Function 44H, Code 0BH, specifies how many times MS-DOS should retry a
disk operation that fails because of a file-sharing violation. DX must
contain the number of retries. CX controls the pause between retries.
MS-DOS retries this type of disk operation three times, unless you use
this system call to specify a different number. After the specified number
of retries, MS-DOS issues Interrupt 24H (Critical-Error-Handler Address)
for the requesting process.
The effect of the delay parameter in CX is machine-dependent because it
specifies how many times MS-DOS should execute an empty loop. The actual
time varies, depending on the processor and clock speed. You can determine
the effect on your machine by using debug. Set the number of retries to 1
and then time several values of CX. If there is an error, the carry flag
(CF) is set and the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 File sharing must be loaded to use this system call
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ioctl_retry macro retries, wait
mov dx, retries
mov cx, wait
mov al, 0BH
mov ah, 44H
int 21H
endm
Example:
The following program sets the number of sharing retries to 10 and
specifies a delay of 1000 between retries.
begin: ioctl_retry 10,1000 ; THIS FUNCTION
jc error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Generic IOCtl (for Handles) (Function 44H, Code 0CH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL = 0CH
BX
Handle
CH = 05H
Category code (printer device)
CL
Function (minor) code
DS:DX
Pointer to data buffer
Return:
Carry set:
AX
1 = Invalid function code
-- = Any device error
Carry not set:
No error
Comments:
This call loads and selects code pages for devices on a per-device basis.
It also sets or gets the output iteration count for a printer that
supports "PRINT 'TIL BUSY."
The video functions (type=display) are supported only if ansi.sys has been
installed. If ansi.sys is not installed, mode sets the video state
directly. This information reflects the latest mode command or any changes
made by use of BIOS. This call uses BIO to get and set the states.
The MS-DOS 4.0 mode command sets the values through this interface and the
DOS utilities access the information through this interface.
The category code may be one of the following:
Code Meaning
──────────────────────────────────────────────────────────────────────────
00 Unknown device
01 Serial printer
03 Console (display) device
05 Parallel printer
──────────────────────────────────────────────────────────────────────────
The function code may be one of the following:
Code Meaning
──────────────────────────────────────────────────────────────────────────
45H Sets iteration count for printer
4AH Selects code page
4CH Starts prepare list
4DH Ends prepare list
5FH Sets display device
65H Gets iteration count for printer
6AH Query code page selected
6BH Query code page prepare list
7FH Gets display character (screen width, length, and
color)
──────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────
Note
DS:DX points to a word that contains the new value for the total number
of output iterations performed before proceeding. Thus, DS:DX points to
a word that contains the character iteration count for the "PRINT 'TIL
BUSY" loop. This is the number of times the device driver will wait for
the device to signal "ready" before acknowledging "Device busy."
──────────────────────────────────────────────────────────────────────────
Macro Definition:
ioctl_handles macro handle,function,category,buffer
mov ch,05H
mov cl,function
mov dx,offset buffer
mov bx,handle
mov ah,44H
mov al,0CH
int 21H
endm
Example:
The following program obtains device characteristics.
mov ax,440CH ; Handle based generic IOCTL
mov bx,handle ; Handle of open device
mov ch,03H ; Type = display
mov cl,7FH ; Subfunction for get
lds dx,buffer ; Info buffer
int 21H
jc error
buffer label byte ; Return buffer
db 0 ; Info level (set to 0
; before call)
db 0 ; reserved (")
; for type display
dw 7*2 ; length of data
dw flags ; control flags
; 0001H=intense (vs blink)
; display mode
; 1=text
; 2=APA
db 0 ; reserved
dw colors ; # of colors (monochrome=0)
dw width ; width of display (pixels)
dw length ; length of display (pixels)
dw cols ; width of display (chars)
dw rows ; length of display (lines)
To fetch code-page information, return the DBCS range vector and add the
following:
mov ax=440Ch ; Handle generic IOCTL
mov cx,036AH ; Query display
mov bx,handle
lds dx,buffer ; change buffer content
int 21H
jc error
Buffer Label Word
dw end-start ; length
start:
dw codepage ; code page
db s1,e1 ; DBCS range
db 0,0 ; end of list
──────────────────────────────────────────────────────────────────────────
Note
Some device drivers may only support the codepage value. As a result,
the user of this call must check the returned length before assuming the
DBCS information is present. The display.sys and printer.sys device
drivers do not need to support the DBCS information. Only the drivers
supplied with the Asian MS-DOS 4.0 will provide this support.
──────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────
Generic IOCtl (for Devices) (Function 44H, Code 0DH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL = 0DH
BL
Drive number
(0 = default, 1 = A, etc.)
CH = 08H
Category (major) code
CL
Function (minor) code
DS:DX
Pointer to parameter block -1
Return:
Carry set:
AX
1 = Invalid function code
2 = Invalid drive
- = Any device error
Carry not set:
No error
Comments:
The function code may be one of the following:
Code Meaning
──────────────────────────────────────────────────────────────────────────
40 Set device parameters
41 Write track on logical device
42 Format track on logical device
60 Get device parameters
61 Read track on logical device
62 Verify track on logical device
──────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────
Note
You must issue "Set Parameters Device" before you can read, write,
format, or verify a logical drive.
──────────────────────────────────────────────────────────────────────────
You should use the following procedure when you want to read, write,
format, or verify a logical drive:
1. Save drive parameters using "Get Device Parameters."
2. Set desired drive parameters using "Set Device Parameters."
3. Perform the I/O operation.
4. Restore the original drive parameters using "Set Device Parameters."
Set Device Parameters (Function 440DH, CL=40H)
When CL=40H, the parameter block has the following field format:
┌────────────────────────────────────┐
│ BYTE Special Functions │
├────────────────────────────────────┤
│ BYTE Device Type │
├────────────────────────────────────┤
│ WORD Device Attributes │
├────────────────────────────────────┤
│ WORD Number of Cylinders │
├────────────────────────────────────┤
│ BYTE Media Type │
├────────────────────────────────────┤
│ Device BPB │
├────────────────────────────────────┤
│ Track Layout │
└────────────────────────────────────┘
These fields have the following meanings:
Special Functions
╓┌─┌──────────┌─────────┌────────────────────────────────────────────────────╖
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 0 The Device BPB (BIOS Parameter Block) field contains
the new default BPB for this device. If a previous
Set Device Parameters call set this bit, Build BPB
returns the actual media BPB otherwise, it returns
the default BPB for the device.
1 All subsequent Build BPB requests return the device
BPB.
1 0 Read all fields of the parameter block.
1 Ignore all fields of the parameter block except for
the Track Layout field.
2 0 The sectors in the track may not all be the same
size. (You should not use this setting.)
1 The sectors in the track are all the same size and
the sector numbers range between 1 and the total
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
the sector numbers range between 1 and the total
number of sectors actually in the track. You should
always set this bit.
3-7 0 These bits must be zero.
──────────────────────────────────────────────────────────────────────────
Device Type
This byte describes the physical device and is set by the device. When
set, it has the following meanings:
Value Meaning
──────────────────────────────────────────────────────────────────────────
0 320/360kilobytes
1 1.2 megabytes
2 720 kilobytes
3 8-inch, single-density
4 8-inch, double-density
5 Hard disk
6 Tape drive
7 1.44 megabytes
──────────────────────────────────────────────────────────────────────────
Device Attributes
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 The media is removable.
0 1 The media is not removable.
1 0 Disk change-line is not supported (no door lock
support).
1 Disk change-line is supported (door lock
support).
2-7 0 These bits must be zero.
──────────────────────────────────────────────────────────────────────────
Number of Cylinders
This field indicates the maximum number of cylinders that the physical
device can support. This information is set by the device.
Media Type
For drives that may contain different media, this field (which is
device-dependent) indicates which media the drive expects.
For a 1.2-megabyte disk, bit zero has the following meaning:
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 0 Quad-density, 1.2-megabyte disk
1 Double-density, 320/360-kilobyte disk
──────────────────────────────────────────────────────────────────────────
The default media type is a quad-density, 1.2-megabyte disk.
Device BPB
If bit 0 of the Special Functions field is clear, the BPB in this field is
the new default BPB for the device.
If bit 0 of the Special Functions field is set, the device driver returns
the BPB from this field for subsequent Build BPB requests.
Track Layout
This field contains a table of variable length for each logical device and
indicates the expected layout of the sectors on the media track. The field
has the following format:
┌──────────────────────────────────────────────┐
│ WORD Sector Count -- total # of sectors │
├──────────────────────────────────────────────┤
│ WORD Sector Number -- sector #1 │
├──────────────────────────────────────────────┤
│ WORD Sector Size -- sector #1 │
├──────────────────────────────────────────────┤
│ WORD Sector Number -- sector #2 │
├──────────────────────────────────────────────┤
│ WORD Sector Size -- sector #2 │
└──────────────────────────────────────────────┘
.
.
.
┌──────────────────────────────────────────────┐
│ WORD Sector Number -- sector #n │
├──────────────────────────────────────────────│
│ WORD Sector Size -- sector #n │
└──────────────────────────────────────────────┘
The Sector Count field indicates the total number of sectors. Each sector
number must be unique and in the range of 1 to sector count (n).
If bit 2 of the Special Functions field is set, all sector sizes must be
the same.
Get Device Parameters (Function 440DH, CL=60H)
When CL=60H, the parameter block has the same field layout as for CL=40H.
However, some of the fields have different meanings. These are described
as follows:
Special Functions
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 0 Returns the default BPB for the device.
1 Returns the BPB that Build BPB would return.
1-7 0 These bits must be zero.
──────────────────────────────────────────────────────────────────────────
Track Layout
The Get Device Parameters call does not use this field.
Read/Write Track on Logical Drive (Function 440DH, CL=61H/CL=41H)
To write to a track on a logical drive, set CL=41H. To read a track on a
logical drive, set CL=61H.
When CL=41H or 61H, the parameter block has the following format:
┌──────────────────────────────┐
│ BYTE Special Functions │
├──────────────────────────────┤
│ WORD Head │
├──────────────────────────────┤
│ WORD Cylinder │
├──────────────────────────────┤
│ WORD First Sector │
├──────────────────────────────┤
│ WORD Number of Sectors │
├──────────────────────────────│
│ DWORD Transfer Address │
└──────────────────────────────┘
These fields are described as follows:
Special Functions
This byte must be zero.
Head
This field contains the number of the head on which you perform the write
or read.
Cylinder
This field contains the number of the cylinder on which you perform the
write or read.
First Sector
This field contains the number of the first sector on which you perform
the write or read. Sectors are numbered starting with zero, so the fourth
sector is numbered 3.
Number of Sectors
This field contains the total number of sectors.
Transfer Address
This field contains the address for storing the data to be written or the
data just read.
Format/Verify Track on Logical Drive (Function 440DH, CL=42H/CL=62H)
To format and verify a track on a logical drive, set CL=42H. To verify a
track on a logical drive, set CL=62H.
When CL=42H or 62H, the parameter block has the following format:
┌──────────────────────────────┐
│ BYTE Special Functions │
├──────────────────────────────┤
│ WORD Head │
│──────────────────────────────┤
│ WORD Cylinder │
└──────────────────────────────┘
These fields are described as follows:
Special Functions
This byte must be zero.
Head
This field contains the number of the head on which you perform the format
or verify.
Cylinder
This field contains the number of the cylinder on which you perform the
format or verify.
────────────────────────────────────────────────────────────────────────────
Get/Set IOCtl Drive Map (Function 44H, Codes 0EH and 0FH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 44H
AL
OEH = Get logical drive map
OFH = Set logical drive map
BX
Drive number
(0 = default, 1 = A, etc.)
Return:
Carry set:
AX
1 = Invalid function code
5 = Invalid drive
Carry not set:
AL = Logical drive mapped onto physical drive
(= 0 if only one drive is
assigned to this physical drive)
Comments:
MS-DOS supports the mapping of multiple logical drives onto a single
physical block device. Get IOCtl Drive Map lets you query the DOS about
which logical drive is currently mapped onto the corresponding physical
device. Set IOCtl Drive Map alters the device that is currently mapped
onto the physical device. These functions are only useful if there is more
than one logical block device mapped onto a single physical device.
A possible use for these functions is with applications that want to
disable the DOS prompt in order to place the correct floppy disk in the
drive when accessing the other logical drive.
To detect whether or not a logical device currently owns the physical
device to which it is mapped, a program needs to check the value in AL
after calling Function 440EH or 440FH (Get/Set IOCtl Drive Map).
────────────────────────────────────────────────────────────────────────────
Duplicate File Handle (Function 45H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 45H
BX
Handle
Return:
Carry set:
AX
4 = Too many open files
6 = Invalid handle
Carry not set:
AX
New handle
Comments:
Function 45H creates an additional handle for a file. BX must contain the
handle of an open file.
MS-DOS returns the new handle in AX. The new handle refers to the same
file as the handle in BX, with the file pointer at the same position.
After you use this function request, moving the read/write pointer of
either handle also moves the pointer for the other handle. You usually use
this function request to redirect standard input (handle 0) and standard
output (handle 1). For a description of standard input, standard output,
and the advantages and techniques of manipulating them, see Software Tools
by Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publishing Co.,
1976).
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
4 Too many open files (no handle available)
6 Handle not open or is invalid
──────────────────────────────────────────────────────────────────────────
Macro Definition:
xdup macro handle
mov bx,handle
mov ah,45H
int 21H
endm
Example:
The following program redirects standard output (handle 1) to a file named
dirfile, invokes a second copy of command.com to list the directory (which
writes the directory to dirfile), and then restores standard input to
handle 1.
pgm_file db "command.com",0
cmd_line db 9,"/c dir /w",0dH
parm_blk db 14 dup (0)
path db "dirfile",0
dir_file dw ? ; For handle
sav_stdout dw ? ; For handle
;
begin: set_block last_inst ; See Function 4AH
jc error_setblk ; Routine not shown
create_handle path,0 ; See Function 3CH
jc error_create ; Routine not shown
mov dir_file,ax ; Save handle
xdup 1 ; THIS FUNCTION
jc error_xdup ; Routine not shown
mov sav_stdout,ax ; Save handle
xdup2 dir_file,1 ; See Function 46H
jc error_xdup2 ; Routine not shown
exec pgm_file,cmd_line,parm_blk ; See Function 4BH
jc error_exec ; Routine not shown
xdup2 sav_stdout,1 ; See Function 46H
jc error_xdup2 ; Routine not shown
close_handle sav_stdout ; See Function 3EH
jc error_close ; Routine not shown
close_handle dir_file ; See Function 3EH
jc error_close ; Routine not shown
────────────────────────────────────────────────────────────────────────────
Force Duplicate File Handle (Function 46H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 46H
BX
Handle
CX
Second handle
Return:
Carry set:
AX
4 = Too many open files
6 = Invalid handle
Carry not set:
No error
Comments:
Function 46H forces a specified handle to refer to the same file as a
second handle already associated with an open file. BX must contain the
handle of the open file; CX must contain the second handle.
On return, the handle in CX now refers to the same file at the same
position as the handle in BX. If the file referred to by the handle in CX
was open at the time of the call, this function closes it.
After you use this call, moving the read/write pointer of either handle
also moves the pointer for the other handle. Normally, you would use this
function request to redirect standard input (handle 0) and standard output
(handle 1). For a description of standard input, standard output, and the
advantages and techniques of manipulating them, see Software Tools by
Brian W. Kernighan and P.J. Plauger (Addison-Wesley Publishing Co., 1976).
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
4 Too many open files (no handle available)
6 Handle not open or is invalid
──────────────────────────────────────────────────────────────────────────
Macro Definition:
xdup2 macro handle1,handle2
mov bx,handle1
mov cx,handle2
mov ah,46H
int 21H
endm
Example:
The following program redirects standard output (handle 1) to a file named
dirfile, invokes a second copy of command.com to list the directory (which
writes the directory to dirfile), and then restores standard input to
handle 1.
pgm_file db "command.com",0
cmd_line db 9,"/c dir /w",0dH
parm_blk db 14 dup (0)
path db "dirfile",0
dir_file dw ? ; For handle
sav_stdout dw ? ; For handle
;
begin: set_block last_inst ; See Function 4AH
jc error_setblk ; Routine not shown
create_handle path,0 ; See Function 3CH
jc error_create ; Routine not shown
mov dir_file,ax ; Save handle
xdup 1 ; See Function 45H
jc error_xdup ; Routine not shown
mov sav_stdout,ax ; Save handle
xdup2 dir_file,1 ;
jc error_xdup2 ; Routine not shown
exec pgm_file,cmd_line,parm_blk ; See Function 4BH
jc error_exec ; Routine not shown
xdup2 sav_stdout,1 ; THIS FUNCTION
jc error_xdup2 ; Routine not shown
close_handle sav_stdout ; See Function 3EH
jc error_close ; Routine not shown
close_handle dir_file ; See Function 3EH
jc error_close ; Routine not shown
────────────────────────────────────────────────────────────────────────────
Get Current Directory (Function 47H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 47H
DS:SI
Pointer to 64-byte memory area
DL
Drive number
(0 = default, 1 = A, etc.)
Return:
Carry set:
AX
15 = Invalid drive number
Carry not set:
No error
Comments:
Function 47H returns the pathname of the current directory on a specified
drive. DL must contain a drive number (0=default, 1=A, etc.). SI must
contain the offset (from the segment address in DS) of a 64-byte memory
area.
MS-DOS places an ASCIZ string in the memory area, consisting of the path
(starting from the root directory) of the current directory for the drive
specified in DL. The string does not begin with a backslash and does not
include the drive letter.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
15 Number in DL not a valid drive number
──────────────────────────────────────────────────────────────────────────
Macro Definition:
get_dir macro drive,buffer
mov dl,drive
mov si,offset buffer
mov ah,47H
int 21H
endm
Example:
The following program displays the current directory that is on the disk
in drive B.
disk db "b:\#"
buffer db 64 dup (?)
;
begin: get_dir 2,buffer ; THIS FUNCTION
jc error_dir ; Routine not shown
display disk ; See Function 09H
display_asciz buffer ; See end of chapter
────────────────────────────────────────────────────────────────────────────
Allocate Memory (Function 48H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 48H
BX
Paragraphs of memory requested
Return:
Carry set:
AX
7 = Memory-control blocks damaged
8 = Insufficient memory
BX
Paragraphs of memory available
Carry not set:
AX
Segment address of allocated memory
Comments:
Function 48H tries to allocate the specified amount of memory to the
current process. BX must contain the number of paragraphs of memory (one
paragraph is 16 bytes).
If sufficient memory is available to satisfy the request, AX returns the
segment address of the allocated memory (the offset is 0). If sufficient
memory is not available, BX returns the number of paragraphs of memory in
the largest available block.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
7 Memory-control blocks damaged (a user program changed
memory that didn't belong to it)
8 Not enough free memory to satisfy the request
──────────────────────────────────────────────────────────────────────────
Macro Definition:
allocate_memory macro bytes
mov bx,bytes
mov cl,4
shr bx,cl
inc bx
mov ah,48H
int 21H
endm
Example:
The following program opens the file named textfile.asc, calculates its
size with Function 42H (Move File Pointer), allocates a block of memory
the size of the file, reads the file into the allocated memory block, and
then frees the allocated memory.
path db "textfile.asc",0
msg1 db "File loaded into allocated memory block.",
0DH,0AH
msg2 db "Allocated memory now being freed
(deallocated).",0DH,0AH
handle dw ?
mem_seg dw ?
file_len dw ?
;
begin: open_handle path,0
jc error_open ; Routine not shown
mov handle,ax ; Save handle
move_ptr handle,0,0,2 ; See Function 42H
jc error_move ; Routine not shown
mov file_len,ax ; Save file length
set_block last_inst ; See Function 4AH
jc error_setblk ; Routine not shown
allocate_memory file_len ; THIS FUNCTION
jc error_alloc ; Routine not shown
mov mem_seg,ax ; Save address of new memory
move_ptr handle,0,0,0 ; See Function 42H
jc error_move ; Routine not shown
push ds ; Save DS
mov ax,mem_seg ; Get segment of new memory
mov ds,ax ; Point DS at new memory
read_handle cs:handle,0,cs:file_len ; Read file into
; new memory
pop ds ; Restore DS
jc error_read ; Routine not shown
; (CODE TO PROCESS FILE GOES HERE)
write_handle stdout,msg1,42 ; See Function 40H
jc write_error ; Routine not shown
free_memory mem_seg ; See Function 49H
jc error_freemem ; Routine not shown
write_handle stdout,msg2,49 ; See Function 40H
jc write_error ; Routine not shown
────────────────────────────────────────────────────────────────────────────
Free Allocated Memory (Function 49H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 49H
ES
Segment address of memory to be
freed
Return:
Carry set:
AX
7 = Memory-control blocks damaged
9 = Incorrect segment
Carry not set:
No error
Comments:
Function 49H frees (makes available) a block of memory previously
allocated with Function 48H (Allocate Memory). ES must contain the
segment address of the memory block to be freed.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
7 Memory-control blocks damaged (a user program changed
memory that didn't belong to it)
9 Memory pointed to by ES was not allocated with
Function 48H
──────────────────────────────────────────────────────────────────────────
Macro Definition:
free_memory macro seg_addr
mov ax,seg_addr
mov es,ax
mov ah,49H
int 21H
endm
Example:
The following program opens a file named textfile.asc, calculates its size
with Function 42H (Move File Pointer), allocates a block of memory the
size of the file, reads the file into the allocated memory block, and then
frees the allocated memory.
path db "textfile.asc",0
msg1 db "File loaded into allocated memory block.",
0DH,0AH
msg2 db "Allocated memory now being freed
(deallocated).",0DH,0AH
handle dw ?
mem_seg dw ?
file_len dw ?
;
begin: open_handle path,0
jc error_open ; Routine not shown
mov handle,ax ; Save handle
move_ptr handle,0,0,2 ; See Function 42H
jc error_move ; Routine not shown
mov file_len,ax ; Save file length
set_block last_inst ; See Function 4AH
jc error_setblk ; Routine not shown
allocate_memory file_len ; See Function 48H
jc error_alloc ; Routine not shown
mov mem_seg,ax ; Save address of new memory
mov_ptr handle,0,0,0 ; See Function 42H
jc error_move ; Routine not shown
push ds ; Save DS
mov ax,mem_seg ; Get segment of new memory
mov ds,ax ; Point DS at new memory
read_handle handle,code,file_len ; Read file into
; new memory
pop ds ; Restore DS
jc error_read ; Routine not shown
; (CODE TO PROCESS FILE GOES HERE)
write_handle stdout,msg1,42 ; See Function 40H
jc write_error ; Routine not shown
free_memory mem_seg ; THIS FUNCTION
jc error_freemem ; Routine not shown
write_handle stdout,msg2,49 ; See Function 40H
jc write_error ; Routine not shown
────────────────────────────────────────────────────────────────────────────
Set Block (Function 4AH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 4AH
BX
Paragraphs of memory
ES
Segment address of memory area
Return:
Carry set:
AX
7 = Memory-control blocks damaged
8 = Insufficient memory
9 = Incorrect segment
BX
Paragraphs of memory available
Carry not set:
No error
Comments:
Function 4AH changes the size of a memory-allocation block. ES must
contain the segment address of the memory block. BX must contain the new
size of the memory block, in paragraphs (one paragraph is 16 bytes).
MS-DOS attempts to change the size of the memory block. If the call fails
on a request to increase memory, BX returns the maximum size (in
paragraphs) to which the block can be increased.
Since MS-DOS allocates all available memory to a .com program, you would
use this call most often to reduce the size of a program's initial
memory-allocation block.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
7 Memory-control blocks destroyed (a user program changed
memory that didn't belong to it)
8 Not enough free memory to satisfy the request
9 Wrong address in ES (the memory block it points to
──────────────────────────────────────────────────────────────────────────
The following macro shrinks the initial memory-allocation block of a .com
program. It takes as a parameter the offset of the first byte following
the last instruction of a program (LAST_INST in the sample programs), uses
it to calculate the number of paragraphs in the program, and then adds 17
to the result: one to round up and 16 to set aside 256 bytes for a stack.
It then sets up SP and BP to point to this stack.
Macro Definition:
set_block macro last_byte
mov bx,offset last_byte
mov cl,4
shr bx,cl
add bx,17
mov ah,4AH
int 21H
mov ax,bx
shl ax,cl
dec ax
mov sp,ax
mov bp,sp
endm
Example:
The following program invokes a second copy of command.com and executes a
dir (directory) command.
pgm_file db "command.com",0
cmd_line db 9,"/c dir /w",0DH
parm_blk db 14 dup (?)
reg_save db 10 dup (?)
;
begin: set_block last_inst ; THIS FUNCTION
exec pgm_file,cmd_line,parm_blk,0 ; See Function 4BH
────────────────────────────────────────────────────────────────────────────
Load and Execute Program (Function 4BH, Code 00H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 4BH
AL = 00H
DS:DX
Pointer to pathname
ES:BX
Pointer to parameter block
Return:
Carry set:
AX
1 = Invalid function
2 = File not found
3 = Path not found
4 = Too many open files
5 = Access denied
8 = Insufficient memory
10 = Bad environment
11 = Bad format
Carry not set:
No error
Comments:
Function 4BH, Code 00H, loads and executes a program. DX must contain the
offset (from the segment address in DS) of an ASCIZ string that specifies
the drive and pathname of an executable program file. BX must contain the
offset (from the segment address in ES) of a parameter block. AL must
contain 0.
There must be enough free memory for MS-DOS to load the program file.
MS-DOS allocates all available memory to a program when it loads it, so
you must free some memory with Function 4AH (Set Block) before using this
function request to load and execute another program. Unless you or MS-DOS
needs the memory for some other purpose, you should shrink the memory to
the minimum amount required by the current process before issuing this
request. MS-DOS creates a Program Segment Prefix for the program being
loaded and sets the terminate and CONTROL+C addresses to the instruction
that immediately follows the call to Function 4BH in the invoking program.
The parameter block consists of four addresses:
Table 1.24
Contents of the Parameter Block
Offset Length
(Hex) (Bytes) Description
──────────────────────────────────────────────────────────────────────────
00 2 (word) Segment address of the environment to be
passed; 00H means copy the parent
program's environment
02 4 (dword) Segment: Offset of command line to be
placed at offset 80H of the new Program
Segment Prefix. Must be a correctly formed
command line no longer than 128 bytes
06 4 (dword) Segment: Offset of FCB to be placed at
offset 5CH of the new Program Segment
Prefix (the Program Segment Prefix is
described in Chapter 4, "MS-DOS Control
Blocks and Work Areas")
0A 4 (dword) Segment: Offset of FCB to be placed at
offset 6CH of the new Program Segment
──────────────────────────────────────────────────────────────────────────
All open files of a program are available to the newly loaded program,
giving the parent program control over the definition of standard input,
output, auxiliary, and printer devices. For example, a program could write
a series of records to a file, open the file as standard input, open a
second file as standard output, and then use Function 4BH, Code 00H, (Load
and Execute Program) to load and execute a program that takes its input
from standard input, sorts records, and writes to standard output.
The loaded program also receives an environment, a series of ASCIZ strings
of the form parameter=value (for example, verify= on). The environment
must begin on a paragraph boundary, be less than 32 kilobytes long, and
end with a byte of 00H (that is, the final entry consists of an ASCIZ
string followed by two bytes of 00H). Following the last byte of zeros is
a set of initial arguments passed to a program containing a word count
followed by an ASCIZ string. If the call finds the file in the current
directory, the ASCIZ string contains the drive and pathname of the
executable program as passed to Function 4BH. If the call finds the file
in the path, it concatenates the filename with the path information. (A
program may use this area to determine from where it was loaded.) If the
word-environment address is 0, the loaded program either inherits a copy
of the parent program's environment or receives a new environment built
for it by the parent. Place the segment address of the environment at
offset 2CH of the new Program Segment Prefix. To build an environment for
the loaded program, put it on a paragraph boundary and place the segment
address of the environment in the first word of the parameter block. To
pass a copy of the parent's environment to the loaded program, put 00H in
the first word of the parameter block.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 0 or 3
2 Program file not found
3 Path invalid or not found
4 Too many open files (no handle available)
5 Directory full, a directory with the same name exists,
or a file with the same name exists
8 Not enough memory to load the program
10 Environment appears longer than 32 kilobytes
11 Program file is a .exe file that contains internally
──────────────────────────────────────────────────────────────────────────
Executing Another Copy of Command.com
Since command.com builds pathnames, searches command paths for program
files, and relocates .exe files, the simplest way to load and execute
another program is to load and execute an additional copy of command.com,
passing it a command line that includes the /c switch, which invokes the
.com or .exe file.
This action requires 17 kilobytes of available memory, so a program that
does it should be sure to shrink its initial memory-allocation block with
Function 4AH (Set Block). The following is the format of a command line
that contains the /c switch:
length,/c command,0DH
where:
Length is the length of the command line, counting the length byte but not
the ending carriage-return (0DH).
Command is any valid MS-DOS command.
0DH is a carriage-return character.
If a program executes another program directly──naming it as the program
file to Function 4BH instead of command.com──it must perform all the
processing normally done by command.com.
Macro Definition:
exec macro path,command,parms
mov dx,offset path
mov bx,offset parms
mov word ptr parms[02H],offset command
mov word ptr parms[04H],cs
mov word ptr parms[06H],5CH
mov word ptr parms[08H],es
mov word ptr parms[0AH],6CH
mov word ptr parms[0CH],es
mov al,0
mov ah,4BH
int 21H
endm
Example:
The following program invokes a second copy of command.com and executes a
dir (directory) command by using the /w (wide) switch:
pgm_file db "command.com",0
cmd_line db 9,"/c dir /w",0DH
parm_blk db 14 dup (?)
reg_save db 10 dup (?)
;
begin:
set_block last_inst ; See Function 4AH
exec pgm_file,cmd_line,parm_blk,0 ; THIS FUNCTION
────────────────────────────────────────────────────────────────────────────
Load Overlay (Function 4BH, Code 03H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 4BH
AL = 03H
DS:DX
Pointer to pathname
ES:BX
Pointer to parameter block
Return:
Carry set:
AX
1 = Invalid function
2 = File not found
3 = Path not found
4 = Too many open files
5 = Access denied
8 = Insufficient memory
10 = Bad environment
Carry not set:
No error
Comments:
Function 4BH, Code 03H, loads a program segment (overlay). DX must contain
the offset (from the segment address in DS) of an ASCIZ string that
specifies the drive and pathname of the program file. BX must contain the
offset (from the segment address in ES) of a parameter block. AL must
contain 3.
MS-DOS assumes that since the invoking program is loading into its own
address space, it requires no free memory. This call does not create a
Program Segment Prefix. The parameter block is four bytes long:
Table 1.25
Contents of the Parameter Block
Offset Length
(Hex) (Bytes) Description
──────────────────────────────────────────────────────────────────────────
00 2 (word) Segment address at which program is to be
loaded
02 2 (word) Relocation factor; usually the same as the
first word of the parameter block (for a
description of a .exe file and of
relocation, see Chapter 6, ".Exe File
──────────────────────────────────────────────────────────────────────────
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 00H or 03H
2 Program file not found
3 Path invalid or not found
4 Too many open files (no handle available)
5 Directory is full, a directory with the same name
exists, or a file with the same name exists
8 Not enough memory to load the program
10 Environment appears longer than 32 kilobytes
──────────────────────────────────────────────────────────────────────────
Macro Definition:
exec_ovl macro path,parms,seg_addr
mov dx,offset path
mov bx,offset parms
mov parms,seg_addr
mov parms[02H],seg_addr
mov al,3
mov ah,4BH
int 21H
endm
Example:
The following program opens a file named textfile.asc, redirects standard
input to that file, loads more.com as an overlay, and calls an overlay
named bit.com, which reads textfile.asc as standard input. The overlay
must establish its own addressability and end with a FAR return.
stdin equ 0
;
file db "TEXTFILE.ASC",0
cmd_file db "\bit.com",0
parm_blk dw 4 dup (?)
overlay label dword
dw 0
handle dw ?
new_mem dw ?
;
begin: set_block last_inst ; see Function 4AH
jc setblock_error ; routine not shown
allocate_memory 2000 ; see Function 48H
jc allocate_error ; routine not shown
mov new_mem,ax ; save seg of memory
open_handle file,0 ; see Function 3DH
jc open_error ; routine not shown
mov handle,ax ; save handle
xdup2 handle,stdin ; see Function 45H
jc dup2_error ; routine not shown
close_handle handle ; see Function 3EH
jc close_error ; routine not shown
mov ax,new_mem ; addr of new memory
exec_ovl cmd_file,parm_blk,ax ; THIS FUNCTION
jc exec_error ; routine not shown
call overlay ; call the overlay
free_memory new_mem ; see Function 49H
jc free_error ; routine not shown
;
────────────────────────────────────────────────────────────────────────────
End Process (Function 4CH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 4CH
AL
Return code
Return:
None
Comments:
Function 4CH terminates a process and returns to MS-DOS. AL contains a
return code that can be retrieved by the parent process with Function
4DH (Get Return Code of Child Process) or the if command, using
errorlevel.
MS-DOS closes all open handles, ends the current process, and returns
control to the invoking process.
This function request doesn't require CS to contain the segment address of
the Program Segment Prefix. You should use it to end a program (rather
than Interrupt 20H or a jump to location 0) unless your program must be
compatible with MS-DOS versions earlier than 2.0.
──────────────────────────────────────────────────────────────────────────
Note
If you use file sharing, you must remove all locks issued by this
process or DOS will be in an uncertain state.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
end_process macro return_code
mov al,return_code
mov ah,4CH
int 21H
endm
Example:
The following program displays a message and returns to MS-DOS with a
return code of 8. It uses only the opening portion of the sample program
skeleton shown at the beginning of this chapter.
message db "Displayed by FUNC_4CH example",0DH,0AH,"$"
;
begin: display message ; See Function 09H
end_process 8 ; THIS FUNCTION
code ends
end code
────────────────────────────────────────────────────────────────────────────
Get Return Code of Child Process (Function 4DH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 4DH
Return:
AX
Return code
Comments:
Function 4DH retrieves the return code specified when a child process
terminates via either Function 31H (Keep Process) or Function 4CH (End
Process). The code returns in AL. AH returns a code that specifies why the
program ended:
Code Meaning
──────────────────────────────────────────────────────────────────────────
0 Normal termination
1 Terminated by CONTROL+C
2 Critical device error
3 Function 31H (Keep Process)
──────────────────────────────────────────────────────────────────────────
This call can retrieve the exit code only once.
Macro Definition:
ret_code macro
mov ah,4DH
int 21H
endm
Example:
No example is included for this function request because the meaning of a
return code varies.
────────────────────────────────────────────────────────────────────────────
Find First File (Function 4EH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 4EH
DS:DX
Pointer to pathname
CX
Attributes to match
Return:
Carry set:
AX
2 = File not found
3 = Path not found
18 = No more files
Carry not set:
No error
Comments:
Function 4EH searches the current or specified directory for the first
entry that matches the specified pathname. DX must contain the offset
(from the segment address in DS) of an ASCIZ string that specifies the
pathname, which can contain wildcard characters. CX must contain the
attribute to be used in searching for the file, as described in Section
1.5.5, "File Attributes."
If the attribute field is hidden file, system file, or subdirectory entry
(02H, 04H, or 10H), or any combination of these values, all normal file
entries are also searched. To search all directory entries except the
volume label, set the attribute byte to 16H (hidden file, system file, and
directory entry). If this function finds a directory entry that matches
the name and attribute, it fills the current DTA as follows:
Table 1.26
DTA Values After Successful Find First File
Offset Length Description
──────────────────────────────────────────────────────────────────────────
00H 21 Reserved for subsequent Function 4FH (Find Next File)
15H 1 Attribute found
16H 2 Time file was last written
18H 2 Date file was last written
1AH 2 Low word of file size
1CH 2 High word of file size
1EH 13 Name and extension of the file, followed by 00H. All
blanks are removed; if there is an extension, it is
preceded by a period. (Volume labels include a period
──────────────────────────────────────────────────────────────────────────
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 Specified file invalid or doesn't exist
3 Specified path invalid or doesn't exist
18 No matching directory entry found
──────────────────────────────────────────────────────────────────────────
Macro Definition:
find_first_file macro path,attrib
mov dx,offset path
mov cx,attrib
mov ah,4EH
int 21H
endm
Example:
The following program displays a message that specifies whether a file
named report.asm exists in the current directory on the disk in drive B.
yes db "File exists.",0DH,0AH,"$"
no db "File does not exist.",0DH,0AH,"$"
path db "b:report.asm",0
buffer db 43 dup (?)
;
begin: set_dta buffer ; See Function 1AH
find_first_file path,0 ; THIS FUNCTION
jc error_findfirst ; Routine not shown
cmp al,12H ; File found?
je not_there ; No
display yes ; See Function 09H
jmp return ; All done
not_there: display no ; See Function 09H
────────────────────────────────────────────────────────────────────────────
Find Next File (Function 4FH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 4FH
Return:
Carry set:
AX
18 = No more files
Carry not set:
No error
Comments:
Function 4FH searches for the next directory entry that matches the name
and attributes specified in a previous Function 4EH (Find First File).
The current DTA must contain the information filled in by Function 4EH
(Find First File).
If the function finds a matching entry, it fills the current DTA just as
it did for Find First File (see Function 4EH (Find First File)).
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 Specified path invalid or doesn't exist
18 No matching directory entry found
──────────────────────────────────────────────────────────────────────────
Macro Definition:
find_next_file macro
mov ah,4FH
int 21H
endm
Example:
The following program displays the number of files contained in the
current directory on the disk in drive B.
message db "No files",0DH,0AH,"$"
files dw ?
path db "b:*.*",0
buffer db 43 dup (?)
;
begin: set_dta buffer ; See Function 1AH
find_first_file path,0 ; See Function 4EH
jc error_findfirst ; Routine not shown
cmp al,12H ; Directory empty?
je all_done ; Yes, go home
inc files ; No, bump file counter
search_dir: find_next_file ; THIS FUNCTION
jc error_findnext ; Routine not shown
cmp al,12H ; Any more entries?
je done ; No, go home
inc files ; Yes, bump file counter
jmp search_dir ; And check again
done: convert files,10,message ; See end of chapter
all_done: display message ; See Function 09H
────────────────────────────────────────────────────────────────────────────
Get Verify State (Function 54H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 54H
Return:
AL
0 = No verify after write
1 = Verify after write
Comments:
Function 54H checks whether MS-DOS verifies write operations to disk
files. The status returns in AL: 0 if verify is off, 1 if verify is on.
You can set the verify status with Function 2EH (Set/Reset Verify Flag).
Macro Definition:
get_verify macro
mov ah,54H
int 21H
endm
Example:
The following program displays the verify status:
message db "Verify ","$"
on db "on.",0DH,0AH,"$"
off db "off.",0DH,0AH,"$"
;
begin: display message ; See Function 09H
get_verify ; THIS FUNCTION
cmp al,0 ; Is flag off?
jg ver_on ; No, it's on
display off ; See Function 09H
jmp return ; Go home
ver_on: display on ; See Function 09H
────────────────────────────────────────────────────────────────────────────
Change Directory Entry (Function 56H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 56H
DS:DX
Pointer to pathname
ES:DI
Pointer to second pathname
Return:
Carry set:
AX
2 = File not found
3 = Path not found
5 = Access denied
17 = Not same device
Carry not set:
No error
Comments:
Function 56H renames a file by changing its directory entry. DX must
contain the offset (from the segment address in DS) of an ASCIZ string
that contains the pathname of the entry to be changed. DI must contain the
offset (from the segment address in ES) of an ASCIZ string that contains a
second pathname to which the first is to be changed.
If a directory entry for the first pathname exists, it is changed to the
second pathname.
The directory paths need not be the same; in effect, you can move the file
to another directory by renaming it. You cannot use this function request
to copy a file to another drive, however; if the second pathname specifies
a drive, the first pathname must specify or default to the same drive.
You cannot use this function request to rename an open file, a hidden
file, a system file, or a subdirectory, because it may corrupt your disk.
If there is an error, the carry flag (CF) is set and the error code
returns in AX.
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 One of files is invalid or not open
3 One of paths is invalid or not open
5 First pathname specifies a directory, second pathname
specifies an existing file; or second directory entry
could not be opened
17 Both files not on the same drive
──────────────────────────────────────────────────────────────────────────
Macro Definition:
rename_file macro old_path,new_path
mov dx,offset old_path
push ds
pop es
mov di,offset new_path
mov ah,56H
int 21H
endm
Example:
The following program prompts for the name of a file and a new name, then
renames the file.
prompt1 db "Filename: $"
prompt2 db "New name: $"
old_path db 15,?,15 dup (?)
new_path db 15,?,15 dup (?)
crlf db 0DH,0AH,"$"
;
begin: display prompt1 ; See Function 09H
get_string 15,old_path ; See Function 0AH
xor bx,bx ; To use BL as index
mov bl,old_path[1] ; Get string length
mov old_path[bx+2],0 ; Make an ASCIZ string
display crlf ; See Function 09H
display prompt2 ; See Function 09H
get_string 15,new_path ; See Function 0AH
xor bx,bx ; To use BL as index
mov bl,new_path[1] ; Get string length
mov new_path[bx+2],0 ; Make an ASCIZ string
display crlf ; See Function 09H
rename_file old_path[2],new_path[2]; THIS FUNCTION
jc error_rename ; Routine not shown
────────────────────────────────────────────────────────────────────────────
Get/Set Date/Time of File (Function 57H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 57H
AL = Function code
0 = Get date and time
1 = Set date and time
BX
Handle
CX (if AL = 1)
Time to be set
DX (if AL = 1)
Date to be set
Return:
Carry set:
AX
1 = Invalid function
6 = Invalid handle
Carry not set:
CX (if AL = 0)
Time file last written
DX (if AL = 0)
Date file last written
Comments:
Function 57H gets or sets the time and date when a file was last written.
To get the time and date, AL must contain 0; the time and date return in
CX and DX. To set the time and date, AL must contain 1; CX and DX must
contain the time and date. BX must contain the file handle. The time and
date are in the form described in "Fields of the FCB" in Section 1.9.1.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL not 0 or 1
6 Handle in BX invalid or not open
──────────────────────────────────────────────────────────────────────────
Macro Definition:
get_set_date_time macro handle,action,time,date
mov bx,handle
mov al,action
mov cx,word ptr time
mov dx,word ptr date
mov ah,57H
int 21H
endm
Example:
The following program gets the date of a file named report.asm in the
current directory on the disk in drive B, increments the day, increments
the month and/or year, if necessary, and sets the new date of the file.
month db 31,28,31,30,31,30,31,31,30,31,30,31
path db "b:report.asm",0
handle dw ?
time db 2 dup (?)
date db 2 dup (?)
;
begin: open_handle path,0 ; See Function 3DH
mov handle,ax ; Save handle
get_set_date_time handle,0,time,date ; THIS FUNCTION
jc error_time ; Routine not shown
mov word ptr time,cx ; Save time
mov word ptr date,dx ; Save date
convert_date date[-24] ; See end of chapter
inc dh ; Increment day
xor bx,bx ; To use BL as index
mov bl,dl ; Get month
cmp dh,month[bx-1] ; Past last day?
jle month_ok ; No, go home
mov dh,1 ; Yes, set day to 1
inc dl ; Increment month
cmp dl,12 ; Is it past December?
jle month_ok ; No, go home
mov dl,1 ; Yes, set month to 1
inc cx ; Increment year
month_ok: pack_date date ; See end of chapter
get_set_date_time handle,1,time,date ; THIS FUNCTION
jc error_time ; Routine not shown
close_handle handle ; See Function 3EH
jc error_close ; Routine not shown
────────────────────────────────────────────────────────────────────────────
Get/Set Allocation Strategy (Function 58H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 58H
AL
0 = Get strategy
1 = Set strategy
BX (AL = 1)
0 = First fit
1 = Best fit
2 = Last fit
Return:
Carry set:
AX
1 = Invalid function code
Carry not set:
AX (AL = 0)
0 = First fit
1 = Best fit
2 = Last fit
Comments:
Function 58H gets or sets the strategy that MS-DOS uses to allocate memory
when a process requests it. If AL contains 0, the strategy is returned in
AX. If AL contains 1, BX must contain the strategy. The three possible
strategies are shown in the following table.
Table 1.27
Allocation Strategy
Value Name Description
──────────────────────────────────────────────────────────────────────────
0 First fit MS-DOS starts searching at the lowest
available block and allocates the first
block it finds (the allocated memory is
the lowest available block). This is the
default strategy.
1 Best fit MS-DOS searches each available block and
allocates the smallest available block
that satisfies the request.
2 Last fit MS-DOS starts searching at the highest
available block and allocates the first
block it finds (the allocated memory is
──────────────────────────────────────────────────────────────────────────
You can use this function request to control how MS-DOS uses its memory
resources.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 AL doesn't contain 0 or 1, or BX doesn't contain 0, 1,
or 2.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
alloc_strat macro code,strategy
mov bx,strategy
mov al,code
mov ah,58H
int 21H
endm
Example:
The following program displays the memory-allocation strategy in effect,
then forces subsequent memory allocations to the top of memory by setting
the strategy to last fit (code 2).
get equ 0
set equ 1
stdout equ 1
last_fit equ 2
;
first db "First fit ",0DH,0AH
best db "Best fit ",0DH,0AH
last db "Last fit ",0DH,0AH
;
begin: alloc_strat get ; THIS FUNCTION
jc alloc_error ; routine not shown
mov cl,4 ; multiply code by 16
shl ax,cl ; to calculate offset
mov dx,offset first ; point to first msg
add dx,ax ; add to base address
mov bx,stdout ; handle for write
mov cs,16 ; write 16 bytes
mov ah,40h ; write handle
int 21H ; system call
; jc write_error ; routine not shown
alloc_strat set,last_fit ; THIS FUNCTION
; jc alloc_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Get Extended Error (Function 59H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 59H
BX = 00H
Return:
AX
Extended-error code
BH
Error class (see text)
BL
Suggested action (see text)
CH
Locus (see text)
CL, DX, SI, DI, DS, ES destroyed
Comments:
Function 59H retrieves an extended-error code for the preceding system
call. Each release of MS-DOS extends the error codes to cover new
capabilities. These new codes are mapped to a simpler set of error codes
based on MS-DOS Version 2.0, so that existing programs can continue to
operate correctly. Notice that this call destroys all registers except
CS:IP and SS:SP.
A user-written Interrupt 24H (Critical-Error Handler Address) can use
Function 59H to get detailed information about the error that caused the
interrupt to be issued.
The input BX is a version indicator that specifies for what level of error
handling the application was written. The current level is 00H.
The extended-error code consists of four separate codes in AX, BH, BL, and
CH that give as much detail as possible about the error and suggest how
the issuing program should respond.
BH──Error Class
BH returns a code that describes the class of error that occurred:
╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
Class Description
──────────────────────────────────────────────────────────────────────────
1 Out of a resource, such as storage or channels
2 Not an error, but a temporary situation (such as a
locked region in a file) that is expected to end
3 Authorization problem
4 Internal error in system software
5 Hardware failure
6 System software failure not the fault of the active
process (could be caused by missing or incorrect
configuration files, for example)
7 Application program error
8 File or item not found
Class Description
──────────────────────────────────────────────────────────────────────────
9 File or item of invalid format or type, or that is
otherwise invalid or unsuitable
10 Interlocked file or item
11 Wrong disk in drive, bad spot on disk, or other problem
with storage medium
12 Other error
──────────────────────────────────────────────────────────────────────────
BL──Suggested Action
BL returns a code that suggests how the issuing program can respond to the
error:
Action Description
──────────────────────────────────────────────────────────────────────────
1 Retry, then prompt user
2 Retry after a Pause
3 If user entered data such as drive letter or filename,
prompt for it again
4 Terminate with cleanup
5 Terminate immediately; system so unhealthy that program
should exit as soon as possible without taking time to
close files and update indexes
6 Error is informational
7 Prompt user to perform some action, such as changing
──────────────────────────────────────────────────────────────────────────
CH──Locus
CH returns a code that provides additional information to help locate the
area involved in the failure. This code is particularly useful for
hardware failures (BH=5).
Locus Description
──────────────────────────────────────────────────────────────────────────
1 Unknown
2 Related to random-access block devices, such as a disk
drive
3 Related to Network
4 Related to serial-access character devices, such as a
printer
5 Related to random-access memory
──────────────────────────────────────────────────────────────────────────
Your programs should handle errors by noting the error return from the
original system call and then issuing this system call to get the
extended-error code. If the program does not recognize the extended-error
code, it should respond to the original error code.
This system call is available during Interrupt 24H and may be used to
return network-related errors.
Macro Definition:
get_error macro
mov ah, 59H
int 21H
endm
Example:
Since this function request provides such detailed information, a general
example is not practical. User programs can interpret the various codes to
determine what sort of messages or prompts should be displayed, what
action to take, and whether or not to terminate the program if recovery
from the errors isn't possible.
────────────────────────────────────────────────────────────────────────────
Create Temporary File (Function 5AH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5AH
CX
Attribute
DS:DX
Pointer to pathname, followed by a
byte of 0, and then by 13 bytes of memory
Return:
Carry set:
AX
2 = File not found
3 = Path not found
4 = Too many open files
5 = Access denied
Carry not set:
AX
Handle
Comments:
Function 5AH creates a file with a unique name. DX must contain the offset
(from the segment address in DS) of an ASCIZ string that specifies a
pathname and 13 bytes of memory (to hold the filename). CX must contain
the attribute to be assigned to the file, as described in Section 1.5.5,
"File Attributes."
MS-DOS creates a unique filename and appends it to the pathname pointed to
by DS:DX, creates the file and opens it in compatibility mode, then
returns the file handle in AX. A program that needs a temporary file
should use this function request to avoid name conflicts.
When the creating process exits, MS-DOS does not automatically delete a
file created with Function 5AH. When you no longer need the file, you
should delete it. If there is an error, the carry flag (CF) is set and the
error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 File is invalid or doesn't exist
3 Directory pointed to by DS:DX is invalid or doesn't
exist
4 Too many open files (no handle available)
5 Access denied
──────────────────────────────────────────────────────────────────────────
Macro Definition:
create_temp macro pathname,attrib
mov cx,attrib
mov dx,offset pathname
mov ah,5AH
int 21H
endm
Example:
The following program creates a temporary file in the directory named
\wp\docs, copies a file named textfile.asc that is in the current
directory into the temporary file, and then closes both files.
stdout equ 1
;
file db "TEXTFILE.ASC",0
path db "\WP\DOCS",0
temp db 13 dup (0)
open_msg db " opened.",0DH,0AH
crl_msg db " created.",0DH,0AH
rd_msg db " read into buffer.",0DH,0AH
wr_msg db "Buffer written to "
cl_msg db "Files closed.",0DH,0AH
crlf db 0DH,0AH
handle1 dw ?
handle2 dw ?
buffer db 512 dup (?)
;
begin: open_handle file,0 ; see Function 3DH
jc open_error ; routine not shown
mov handle1,ax ; save handle
write_handle stdout,file,12 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,open_msg,10 ; see Function 40H
jc write_error ; routine not shown
create_temp path,0 ; THIS FUNCTION
jc create_error ; routine not shown
mov handle2,ax ; save handle
write_handle stdout,path,8 ; see Function 40H
jc write_error ; routine not shown
display_char "" ; see Function 02H
write_handle stdout,temp,12 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,crl_msg,11 ; See Function 40H
jc write_error ; routine not shown
read_handle handle1,buffer,512 ; see Function 3FH
jc read_error ; routine not shown
write_handle stdout,file,12 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,rd_msg,20 ; see Function 40H
jc write_error ; routine not shown
write_handle handle2,buffer,512 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,wr_msg,18 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,temp,12 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,crlf,2 ; see Function 40H
jc write_error ; routine not shown
close_handle handle1 ; see Function 3EH
jc close_error ; routine not shown
close_handle handle2 ; see Function 3EH
jc close_error ; routine not shown
write_handle stdout,cl_msg,15 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Create New File (Function 5BH)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5BH
CX
Attribute
DS:DX
Pointer to pathname
Return:
Carry set:
AX
2 = File not found
3 = Path not found
4 = Too many open files
5 = Access denied
80 = File already exists
Carry not set:
AX
Handle
Comments:
Function 5BH creates a new file. DX must contain the offset (from the
segment address in DS) of an ASCIZ string that specifies a pathname. CX
contains the attribute to be assigned to the file, as described in Section
1.5.5, "File Attributes."
If there is no existing file with the same filename, MS-DOS creates the
file, opens it in compatibility mode, and returns the file handle in AX.
This function request fails if the specified file exists, unlike Function
3CH (Create Handle), which, under the same circumstances, truncates the
file to a length of 0. In a multitasking system, the existence of a file
is used as a semaphore; you can use this system call as a test-and-set
semaphore. If there is an error, the carry flag (CF) is set and the error
code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
2 File is invalid or doesn't exist
3 Directory pointed to by DS:DX is invalid or doesn't
exist
4 No free handles are available in the current process,
or internal system tables are full
5 Access denied
80 File with the same specification pointed to by DS:DX
──────────────────────────────────────────────────────────────────────────
Macro Definition:
create_new macro pathname,attrib
mov cx, attrib
mov dx, offset pathname
mov ah, 5BH
int 21H
endm
Example:
The following program attempts to create a new file named report.asm in
the current directory. If the file already exists, the program displays an
error message and returns to MS-DOS. If the file doesn't exist and there
are no other errors, the program saves the handle and continues
processing.
err_msg db "FILE ALREADY EXISTS",0DH,0AH,"$"
path db "report.asm",0
handle dw ?
;
begin: create_new path,0 ; THIS FUNCTION
jnc continue ; further processing
cmp ax,80 ; file already exist?
jne error ; routine not shown
display err_msg ; see Function 09H
jmp return ; return to MS-DOS
continue: mov handle,ax ; save handle
;
; (further processing here)
────────────────────────────────────────────────────────────────────────────
Lock (Function 5CH, Code 00H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5CH
AL = 00H
BX
Handle
CX:DX
Offset of region to be locked
SI:DI
Length of region to be locked
Return:
Carry set:
AX
1 = Invalid function code
6 = Invalid handle
33 = Lock violation
36 = Sharing buffer exceeded
Carry not set:
No error
Comments:
Function 5CH, Code 00H, denies all access (read or write) by any other
process to the specified region of the file. BX must contain the handle of
the file that contains the region to be locked. CX:DX (a four-byte
integer) must contain the offset in the file of the beginning of the
region. SI:DI (a four-byte integer) must contain the length of the region.
If another process attempts to use (read or write) a locked region, MS-DOS
retries three times; if the retries fail, MS-DOS issues Interrupt 24H for
the requesting process. You can change the number of retries with Function
440BH (IOCtl Retry).
The locked region can be anywhere in the file. For instance, locking
beyond the end of the file is not an error. A region should be locked for
only a brief period, so if it is locked for more than ten seconds you
should consider it to be an error. Function 45H (Duplicate File Handle)
and Function 46H (Force Duplicate File Handle) duplicate access to any
locked region. Passing an open file to a child process with Function
4B00H (Load and Execute Program) does not duplicate access to locked
regions.
──────────────────────────────────────────────────────────────────────────
Warning
If a program closes a file that contains a locked region or terminates
with an open file that contains a locked region, the result is
undefined.
──────────────────────────────────────────────────────────────────────────
Programs that might be terminated by Interrupt 23H (CONTROL+C Handler
Address) or Interrupt 24H (Critical-Error-Handler Address) should trap
these interrupts and unlock any locked regions before exiting.
Programs should not rely on being denied access to a locked region. A
program can determine the status of a region (locked or unlocked) by
attempting to lock the region and examining the error code.
If there is an error, the carry flag (CF) is set and the error code is
returned in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 File sharing must be loaded to use this function
request.
6 The handle in BX is not a valid, open handle.
33 All or part of the specified region is already locked.
36 There is no more room for lock entries in the buffer.
Refer to the share command in the MS-DOS User's
Reference for information on allocating more lock
──────────────────────────────────────────────────────────────────────────
Macro Definition:
lock macro handle,start,bytes
mov bx, handle
mov cx, word ptr start
mov dx, word ptr start+2
mov si, word ptr bytes
mov di, word ptr bytes+2
mov al, 0
mov ah, 5CH
int 21H
endm
Example:
The following program opens a file named finalrpt in "Deny None" mode and
locks two portions of it: the first 128 bytes and bytes 1024 through 5119.
After some (unspecified) processing, it unlocks the same portions and
closes the file.
stdout equ 1
;
start1 dd 0
lgth1 dd 128
start2 dd 1023
lgth2 dd 4096
file db "FINALRPT",0
op_msg db " opened.",0DH,0AH
11_msg db "First 128 bytes locked.",0DH,0AH
12_msg db "Bytes 1024-5119 locked.",0DH,0AH
u1_msg db "First 128 bytes unlocked.",0DH,0AH
u2_msg db "Bytes 1024-5119 unlocked.",0DH,0AH
cl_msg db " closed.:,0DH,0AH
handle dw ?
;
begin: open_handle file,01000010b ; see Function 3DH
jc open_error ; routine not shown
write_handle stdout,file,8 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,op_msg,10 ; see Function 40H
jc write_error ; routine not shown
mov handle,ax ; save handle
lock handle,start1,lgth1 ; THIS FUNCTION
jc lock_error ; routine not shown
write_handle stdout,11_msg,25 ; see Function 40H
jc write_error ; routine not shown
lock handle,start2,lgth2 ; THIS FUNCTION
jc lock_error ; routine not shown
write_handle stdout,12_msg,25 ; see Function 40H
jc write_error ; routine not shown
;
; ( Further processing here )
;
unlock handle,start1,lgth1 ; See Function 5C01H
jc unlock_error ; routine not shown
write_handle stdout,ul_msg,27 ; see Function 40H
jc write_error ; routine not shown
unlock handle,start2,lgth2 ; See Function 5C01H
jc unlock_error ; routine not shown
write_handle stdout,u2_msg,27 ; See Function 40H
jc write_error ; routine not shown
close_handle handle ; See Function 3EH
jc close_error ; routine not shown
write_handle stdout,file,8 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,cl_msg,10 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Unlock (Function 5CH, Code 01H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5CH
AL = 01H
BX
Handle
CX:DX
Offset of area to be unlocked
SI:DI
Length of area to be unlocked
Return:
Carry set:
AX
1 = Invalid function code
6 = Invalid handle
33 = Lock violation
36 = Sharing buffer exceeded
Carry not set:
No error
Comments:
Function 5CH, Code 01H, unlocks a region previously locked by the same
process. BX must contain the handle of the file that contains the region
to be unlocked. CX:DX (a four-byte integer) must contain the offset in the
file of the beginning of the region. SI:DI (a four-byte integer) must
contain the length of the region. The offset and length must be exactly
the same as the offset and length specified in the previous Function
5C00H (Lock).
The description of Function 5C00H (Lock) describes how to use locked
regions. If there is an error, the carry flag (CF) is set and the error
code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 File sharing must be loaded to use this function
request.
6 The handle in BX is not a valid, open handle.
33 The region specified is not identical to one that was
previously locked by the same process.
36 There is no more room for lock entries in the buffer.
Refer to the share command in the MS-DOS User's
Reference for information on allocating more lock
──────────────────────────────────────────────────────────────────────────
You should issue Function 59H (Get Extended Error) to list the possible
errors returned by this function.
Macro Definition:
unlock macro handle,start,bytes
mov bx, handle
mov cx, word ptr start
mov dx, word ptr start+2
mov si, word ptr bytes
mov di, word ptr bytes+2
mov al, 1
mov ah, 5CH
int 21H
endm
Example:
The following program opens a file named finalrpt in "Deny None" mode and
locks two portions of it: the first 128 bytes and bytes 1024 through 5119.
After some (unspecified) processing, it unlocks the same portions and
closes the file.
stdout equ 1
;
start1 dd 0
lgth1 dd 128
start2 dd 1023
lgth2 dd 4096
file db "FINALRPT",0
op_msg db " opened.",0DH,0AH
11_msg db "First 128 bytes locked.",0DH,0AH
12_msg db "Bytes 1024-5119 locked.",0DH,0AH
u1_msg db "First 128 bytes unlocked.",0DH,0AH
u2_msg db "Bytes 1024-5119 unlocked.",0DH,0AH
cl_msg db " closed.",0DH,0AH
handle dw ?
;
begin: open_handle file,01000010b ; see Function 3DH
jc open_error ; routine not shown
write_handle stdout,file,8 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,op_msg,10 ; see Function 40H
jc write_error ; routine not shown
mov handle,ax ; save handle
lock handle,start1,lgth1 ; See Function 5C00H
jc lock_error ; routine not shown
write_handle stdout,11_msg,25 ; see Function 40H
jc write_error ; routine not shown
lock handle,start2,lgth2 ; See Function 5C00H
jc lock_error ; routine not shown
write_handle stdout,12_msg,25 ; see Function 40H
jc write_error ; routine not shown
;
; ( Further processing here )
;
unlock handle,start1,lgth1 ; THIS FUNCTION
jc unlock_error ; routine not shown
write_handle stdout,u1_msg,27 ; see Function 40H
jc write_error ; routine not shown
unlock handle,start2,lgth2 ; THIS FUNCTION
jc unlock_error ; routine not shown
write_handle stdout,u2_msg,27 ; see Function 40H
jc write_error ; routine not shown
close_handle handle ; See Function 3EH
jc close_error ; routine not shown
write_handle stdout,file,8 ; see Function 40H
jc write_error ; routine not shown
write_handle stdout,cl_msg,10 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Get Machine Name (Function 5EH, Code 00H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5EH
AL = 0
DS:DX
Pointer to 16-byte buffer
Return:
Carry set:
AX
1 = Invalid function code
Carry not set:
CX
Identification number of local
computer
CH
Validity of machine name:
00H = invalid
nonzero = valid
CL
NETBIOS number assigned to machine name
DS:DX
Segment:offset of ASCIZ machine name
Comments:
Function 5EH, Code 00H, retrieves the net name of the local computer. DX
must contain the offset (to the segment address in DS) of a 16-byte
buffer. Microsoft Networks must be running.
MS-DOS returns the local computer name (a 16-byte ASCIZ string, padded
with blanks) in the buffer pointed to by DS:DX. CX returns the
identification number of the local computer. If the network was never
installed, the CH register returns with zero and the value in the CL
register is invalid. If there is an error, the carry flag (CF) is set and
the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 Microsoft Networks must be running to use this function
request.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
get_machine_name macro buffer
mov dx,offset buffer
mov al,0
mov ah,5EH
int 21H
endm
Example:
The following program displays the name of a Microsoft Networks
workstation.
stdout equ 1
;
msg db "Netname: "
mac_name db 16 dup (?),0DH,0AH
;
begin: get_machine_name mac_name ; THIS FUNCTION
jc name_error ; routine not shown
write_handle stdout,msg,27 ; see Function 40H
jc write_error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Get/Set Printer Setup (Function 5EH, Codes 02H and 03H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5EH
AL
02H = Set printer setup string
03H = Get printer setup string
BX
Assign-list index
If AL = 02H
CX
Length of setup string
DS:SI
Pointer to setup string
If AL = 03H
ES:DI = Segment: offset of 64-byte buffer
to receive string
Return:
Carry set:
AX
1 = Invalid function code
Carry not set:
CX = Length of printer setup string in bytes
(if AL=03H)
ES:DI = Segment:offset of ASCII printer setup
string (if AL=03H)
Comments:
Function 5EH, Code 02H, defines a string of control characters that MS-DOS
adds to the beginning of each file sent to the network printer. BX must
contain the index into the assign list that identifies the printer (entry
0 is the first entry). CX must contain the length of the string. SI must
contain the offset (to the segment address in DS) of the string itself.
Microsoft Networks must be running.
MS-DOS adds the setup string to the beginning of each file sent to the
printer, which is specified by the assign-list index in BX. This function
request lets each program that shares a printer have its own printer
configuration. You can use Function 5F02H (Get Assign-List Entry) to
determine which entry in the assign list refers to the printer. If there
is an error, the carry flag (CF) is set and the error code returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 Microsoft Networks must be running to use this function
request.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
printer_setup macro index,lgth,string
mov bx, index
mov cx, lgth
mov dx, offset string
mov al, 2
mov ah, 5EH
int 21H
endm
Example:
The following program defines a printer-setup string that consists of the
control character to print expanded type on Epson-compatible printers. The
printer cancels this mode at the first carriage return, so the effect is
to print the first line of each file sent to the network printer as a
title in expanded characters. The setup string is one character. This
example assumes that the printer is the entry number 3 (the fourth entry)
in the assign list. Use Function 5F02H (Get Assign-List Entry) to
determine this value.
setup db 0EH
;
begin: printer_setup 3,1,setup ; THIS FUNCTION
jc error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Get Assign-List Entry (Function 5FH, Code 02H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5FH
AL = 02H
BX
Assign-list index
DS:SI
Pointer to buffer for local name
ES:DI
Pointer to buffer for remote name
Return:
Carry set:
AX
1 = Invalid function code
18 = No more files
Carry not set:
BL
3 = Printer
4 = Drive
CX
Stored user value
Comments:
Function 5FH, Code 02H, retrieves the specified entry from the network
list of assignments. BX must contain the assign-list index (entry 0 is the
first entry). SI must contain the offset (to the segment address in DS) of
a 16-byte buffer for the local name. DI must contain the offset (to the
segment address in ES) of a 128-byte buffer for the remote name. Microsoft
Networks must be running.
MS-DOS puts the local name in the buffer pointed to by DS:SI and the
remote name in the buffer pointed to by ES:DI. The local name can be a
null ASCIZ string. BL returns 3 if the local device is a printer or 4 if
the local device is a drive. CX returns the stored user value set with
Function 5F03H (Make Network Connection). The contents of the assign list
can change between calls. You can use this function request to retrieve
any entry, or to make a copy of the complete list by stepping through the
table. To detect the end of the assign list, check for error code 18 (no
more files), as you would when stepping through a directory by using
Functions 4EH (Find First File) and 4FH (Find Next File).
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 Microsoft Networks must be running to use this function
request.
18 The index passed in BX is greater than the number of
──────────────────────────────────────────────────────────────────────────
Macro Definition:
get_list macro index,local,remote
mov bx, index
mov si, offset local
mov di, offset remote
mov al,2
mov ah, 5FH
int 21H
endm
Example:
The following program displays the assign list on a Microsoft Networks
workstation, showing the local name, remote name, and device type (drive
or printer) for each entry.
stdout equ 1
printer equ 3
;
local_nm db 16 dup (?),2 dup (20h)
remote_nm db 128 dup (?),2 dup (20h)
header db "Local name",8 dup (20h)
db "Remote name",7 dup (20h)
db "Device Type"
crlf db 0dh,0ah,0dh,0ah
drive_msg db "drive"
print_msg db "printer"
index dw ?
;
begin: write_handle stdout,header,51 ; see Function 40H
jc write_error ; routine not shown
mov index,0 ; assign list index
ck_list: get_list index,local_nm,remote_nm ; THIS FUNCTION
jnc got_one ; got an entry
error: cmp ax,18
je last_one ; yes
jmp error ; routine not shown
got_one: push bx ; save device type
write_handle stdout,local_nm,148 ; see Function 40H
jc write_error ; routine not shown
pop bx ; get device type
cmp bl,printer ; is it a printer?
je prntr ; yes
write_handle stdout,drive_msg,5 ; see Function 40H
jc write_error ; routine not shown
jmp get_next ; finish message
prntr: write_handle stdout,print_msg,7 ; see Function 40H
jc write_error ; routine not shown
get_next: write_handle stdout,crlf,2 ; see Function 40H
jc write_error ; routine not shown
inc index ; bump index
jmp ck_list ; get next entry
last_one: write_handle stdout,crlf,4 ; see Function 40H
jc write_error ; routine not shown
;
────────────────────────────────────────────────────────────────────────────
Make Network Connection (Function 5FH, Code 03H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5FH
AL = 03H
BL
3 = Printer
4 = Drive
CX
User value
DS:SI
Pointer to name of source device
ES:DI
Pointer to name of destination
device
Return:
Carry set:
AX
1 = Invalid function code
5 = Access denied
3 = Path not found
8 = Insufficient memory
(Other errors particular to the
network may occur.)
Carry not set:
No error
Comments:
Function 5FH, Code 03H, redirects a printer or disk drive (source device)
to a network directory (destination device). BL must contain 3 if the
source device is a printer or 4 if it is a disk drive. SI must contain the
offset (to the segment address in DS) of an ASCIZ string that specifies
the name of the printer, or a drive letter followed by a colon, or a null
string (one byte of 00H). DI must contain the offset (to the segment
address in ES) of an ASCIZ string that specifies the name of a network
directory. CX contains a user-specified 16-bit value that MS-DOS
maintains. Microsoft Networks must be running. The destination string must
be an ASCIZ string of the following form:
machine-name pathname 00H password 00H
where:
Machine-name is the net name of the server that contains the network
directory.
Pathname is the alias of the network directory (not the directory path) to
which the source device is to be redirected.
00H is a null byte.
Password is the password for access to the network directory. If no
password is specified, both null bytes must immediately follow the
pathname.
If BL=3, the source string must be PRN, LPT1, LPT2, or LPT3. This function
buffers and sends all output for the named printer to the remote-printer
spooler named in the destination string.
If BL=4, the source string can be either a drive letter followed by a
colon, or a null string. If the source string contains a valid drive
letter and colon, this call redirects all subsequent drive-letter
references to the network directory named in the destination string. If
the source string is a null string, MS-DOS attempts to grant access to the
network directory with the specified password.
The maximum length of the destination string is 128 bytes. You can
retrieve the value in CX by using Function 5F02H (Get Assign-List Entry).
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 Microsoft Networks must be running to use this function
request; the value in BX is not 1 to 4, the source
string is in the wrong format; the destination string
is in the wrong format; or the source device is already
redirected.
3 The network directory path is invalid or doesn't exist.
5 The network directory/password combination is not
valid. This does not mean that the password itself was
invalid; the directory might not exist on the server.
8 There is not enough memory for string substitutions.
──────────────────────────────────────────────────────────────────────────
Macro Definition:
redir macro device,value,source,destination
mov bl, device
mov cx, value
mov si, offset source
mov es, seg destination
mov di, offset destination
mov al, 03H
mov ah, 5FH
int 21H
endm
Example:
The following program redirects two drives and a printer from a
workstation to a server named harold. It assumes the machine name,
directory names, and driver letters shown:
Local drive Netname
or printer on server Password
E: WORD none
F: COMM fred
PRN: PRINTER quick
printer equ 3
drive equ 4
;
local_1 db "e:",0
local_2 db "f:",0
local_3 db "prn",0
remote_1 db "\harold\word",0,0
remote_2 db "\harold\comm",0,"fred",0
remote_3 db "\harold\printer",0,"quick",0
;
begin: redir local_1,remote_1,drive,0 ; THIS FUNCTION
jc error ; routine not shown
redir local_2,remote_2,drive,0 ; THIS FUNCTION
jc error ; routine not shown
redir local_3,remote_3,printer,0 ; THIS FUNCTION
jc error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Delete Network Connection (Function 5FH, Code 04H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 5FH
AL = 04H
DS:SI
Pointer to name of source device
Return:
Carry set:
AX
1 = Invalid function code
15 = Redirection paused on server
(Other errors particular to the network
may occur.)
Carry not set:
No error
Comments:
Function 5FH, Code 04H, cancels the redirection of a printer or disk drive
(source device) to a network directory (destination device) made with
Function 5F03H (Make Network Connection). SI must contain the offset (to
the segment address in DS) of an ASCIZ string that specifies the name of
the printer or drive whose redirection is to be canceled. Microsoft
Networks must be running.
The ASCIZ string pointed to by DS:SI can contain one of three values:
■ The letter of a redirected drive, followed by a colon. Cancels the
redirection and restores the drive to its physical meaning.
■ The name of a redirected printer (PRN, LPT1, LPT2, LPT3, or their
machine-specific equivalents). Cancels the redirection and restores the
printer name to its physical meaning.
■ A string starting with \\ (2 backslashes). Terminates the connection
between the local machine and the network directory.
If there is an error, the carry flag (CF) is set and the error code
returns in AX:
Code Meaning
──────────────────────────────────────────────────────────────────────────
1 Microsoft Networks must be running to use this function
request; or the ASCIZ string names a nonexistent source
device.
15 Disk or printer redirection on the network server is
──────────────────────────────────────────────────────────────────────────
Macro Definition:
cancel_redir macro local
mov si, offset local
mov al, 4
mov ah, 5FH
int 21H
endm
Example:
The following program cancels the redirection of drives E and F and the
printer (PRN) of a Microsoft Networks workstation. It assumes that these
local devices were redirected previously.
local_1 db "e:",0
local_2 db "f:",0
local_3 db "prn",0
;
begin: cancel_redir local_1 ; THIS FUNCTION
jc error ; routine not shown
cancel_redir local_2 ; THIS FUNCTION
jc error ; routine not shown
cancel_redir local_3 ; THIS FUNCTION
jc error ; routine not shown
────────────────────────────────────────────────────────────────────────────
Get PSP (Function 62H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 62H
Return:
BX
Segment address of the Program
Segment Prefix of the current process
Comments:
Function 62H retrieves the segment address of the currently active process
(the start of the Program Segment Prefix). The address returns in BX.
Macro Definition:
get_psp macro
mov ah, 62H
int 21H
endm
Example:
The following program displays the segment address of its Program Segment
Prefix (PSP) in hexadecimal.
msg db "PSP segment address: H",0DH,0AH,"$"
;
begin: get_psp ; THIS FUNCTION
convert bx,16,msg[21] ; see end of chapter
display msg ; see Function 09H
────────────────────────────────────────────────────────────────────────────
Get Extended Country Information (Function 65H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 65H
AL
Function (minor) code
BX
Code page (-1 = active CON device)
CX
Amount of data to return
DX
Country ID for which information is to be returned
(-1=default country)
ES:DI
Address of country information buffer
Return:
Carry set:
1 = Buffer has been filled
2 = File not found
Carry not set:
ES:DI = Pointer to country information buffer
Comments:
Function 65H retrieves standard country information. This information
includes country ID, code page, date and time format, currency symbol,
separators (for thousands, decimals, data list, date and time) currency
format flags, digits in currency, and case-mapping information. The
function code passed in AL may be one of the following:
Code Description
──────────────────────────────────────────────────────────────────────────
1 Return standard information
2 Return pointer to uppercase table
4 Return pointer to filename uppercase table
6 Return pointer to collating table
7 Selects the Double Byte Character Set (DBCS)
──────────────────────────────────────────────────────────────────────────
Only the information for the default country is kept in the kernel.
Country-dependent information for all other countries is contained in the
country.sys file. The MS-DOS nlsfunc command is used to access the
country-dependent information in country.sys using this call. If the
country code and code page number do not match, or if either is invalid,
error code 2 is returned to AX. If CX is less than 5, error code 1 is
returned. If the amount of information requested is greater than the value
of CX, only CX bytes are returned and no error is reported.
If AL = 1, the buffer is filled with the following information:
db 1 ; Information ID
dw ? ; Size (<=38)
dw ? ; Country ID
dw ? ; Code page
If AL = 2, the buffer is filled with the following information:
db 2 ; Information ID
dd ? ; Double-word pointer to uppercase table
If AL = 4, the buffer is filled with the following information:
db 4 ; Information ID
dd ? ; Double-word pointer to filename uppercase table
Both of these tables consist of a length field (two bytes) followed by 128
uppercase values for the upper 128 ASCII characters. The following formula
is used to compute the address of an uppercase equivalent in the table:
Address of outchar = inchar - (256-table──len) = table──start
where:
Parameter Meaning
──────────────────────────────────────────────────────────────────────────
inchar Character to be generated
table──len Length of list of uppercase values (two bytes)
table──start Starting address of uppercase table
outchar Uppercase value for inchar
──────────────────────────────────────────────────────────────────────────
If inchar is greater than or equal to (256 - table──len), then there is an
uppercase equivalent in the table; otherwise, there is not.
If AL = 6, the buffer is filled with the following information:
db 6 ; Information ID
dd ? ; Double-word pointer to collating sequence
The table is 258 bytes long. The first word is the length of the table.
The rest of the table is 256 ASCII values in the appropriate order.
────────────────────────────────────────────────────────────────────────────
Get/Set Global Code Page (Function 66H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 66H
AL
Function (minor) code
BX
Code page to set (AL = 2)
Return:
Carry set:
AX
02 = File not found
65 = Device not selected
Carry not set:
No error
Comments:
Function 66H gets or sets the code page used by the kernel and all
devices. If no other code page has been set, this function gets the
default code page from DX. If another code page is set, this function
retrieves the active code page from BX.
The MS-DOS nlsfunc command and country.sys must be on the system if this
function is to be used to change the global code page. The function code
may be one of the following:
Code Description
──────────────────────────────────────────────────────────────────────────
1 Get code page
2 Set code page
──────────────────────────────────────────────────────────────────────────
MS-DOS gets the new code page from the country.sys file. Devices must be
prepared for code page switching before a code page can be selected. To
prepare a device, a device driver that supports code-page switching must
be installed by using the device command in the config.sys file. The user
must also use the prepare keyword with the MS-DOS mode command to prepare
the device for code-page switching.
The code page selected must be compatible with the country code specified
in the config.sys file. If MS-DOS cannot read country.sys or another
specified country information file, error code 02 is returned to AX.
────────────────────────────────────────────────────────────────────────────
Set Handle Count (Function 67H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 67H
BX
Number of allowed handles
Return:
Carry set:
AX
Carry not set:
No error
Comments:
Function 67H increases or decreases the number of files a program can have
open at one time. The maximum number of file handles is 64K. If less than
20 are specified, the minimum handle number, 20, is assumed. If this call
is used to reduce the number of allowed handles, the new limit does not
take affect until any handles above the new limit are closed.
The user should use Function 4AH (Set Block) to allocate memory for the
extended handle list if BX is greater than 255. The maximum number for the
value of the config.sys command files is 255.
────────────────────────────────────────────────────────────────────────────
Commit File (Function 68H)
────────────────────────────────────────────────────────────────────────────
Call:
AH = 68H
BX
File handle
Return:
Carry set:
AX = error
Carry not set
No error
Comments:
Function 68H flushes all buffered data for a file without closing it.
Using this call is more efficient than using the traditional close-open
sequence, and is more effective for network environments. This call makes
sure that the disk image of a file is current.
; Macro Definitions for MS-DOS System Call Examples
;
; *******************
; Interrupts
; *******************
; Interrupt 25H
ABS_DISK_READ macro disk,buffer,num_sectors,first_sector
mov al,disk
mov bx,offset buffer
mov cx,num_sectors
mov dx,first_sector
int 25H
popf
endm
; Interrupt 26H
ABS_DISK_WRITE macro disk,buffer,num_sectors,first_sector
mov al,disk
mov bx,offset buffer
mov cx,num_sectors
mov dx,first_sector
int 26H
popf
endm
; Interrupt 27H
STAY_RESIDENT macro last_instruc
mov dx,offset last_instruc
inc dx
int 27H
endm
;
;
; *******************
; Function Requests
; *******************
; Function Request 00H
TERMINATE_PROGRAM macro
xor ah,ah
int 21H
endm
; Function Request 01H
READ_KBD_AND_ECHO macro
mov ah,01H
int 21H
endm
; Function Request 02H
DISPLAY_CHAR macro character
mov dl,character
mov ah,02H
int 21H
endm
; Function Request 03H
AUX_INPUT macro
mov ah,03H
int 21H
endm
; Function Request 04H
AUX_OUTPUT macro
mov ah,04H
int 21H
endm
; Function Request 05H
PRINT_CHAR macro character
mov dl,character
mov ah,05H
int 21H
endm
; Function Request 06H
DIR_CONSOLE_IO macro switch
mov dl,switch
mov ah,06H
int 21H
endm
; Function Request 07H
DIR_CONSOLE_INPUT macro
mov ah,07H
int 21H
endm
; Function Request 08H
READ_KBD macro
mov ah,08H
int 21H
endm
; Function Request 09H
DISPLAY macro string
mov dx,offset string
mov ah,09H
int 21H
endm
; Function Request 0AH
GET_STRING macro limit,string
mov dx,offset string
mov string,limit
mov ah,0AH
int 21H
endm
; Function Request 0BH
CHECK_KBD_STATUS macro
mov ah,0BH
int 21H
endm
; Function Request 0CH
FLUSH_AND_READ_KBD macro switch
mov al,switch
mov ah,0CH
int 21H
endm
; Function Request 0DH
RESET_DISK macro
mov ah,0DH
int 21H
endm
; Function Request 0EH
SELECT_DISK macro disk
mov dl,disk[-65]
mov ah,0EH
int 21H
endm
; Function Request 0FH
OPEN macro fcb
mov dx,offset fcb
mov ah,0FH
int 21H
endm
; Function Request 10H
CLOSE macro fcb
mov dx,offset fcb
mov ah,10H
int 21H
endm
; Function Request 11H
SEARCH_FIRST macro fcb
mov dx,offset fcb
mov ah,11H
int 21H
endm
; Function Request 12H
SEARCH_NEXT macro fcb
mov dx,offset fcb
mov ah,12H
int 21H
endm
; Function Request 13H
DELETE macro fcb
mov dx,offset fcb
mov ah,13H
int 21H
endm
; Function Request 14H
READ_SEQ macro fcb
mov dx,offset fcb
mov ah,14H
int 21H
endm
; Function Request 15H
WRITE_SEQ macro fcb
mov dx,offset fcb
mov ah,15H
int 21H
endm
; Function Request 16H
CREATE macro fcb
mov dx,offset fcb
mov ah,16H
int 21H
endm
; Function Request 17H
RENAME macro fcb,newname
mov dx,offset fcb
mov ah,17H
int 21H
endm
; Function Request 19H
CURRENT_DISK macro
mov ah,19H
int 21H
endm
; Function Request 1AH
SET_DTA macro buffer
mov dx,offset buffer
mov ah,1AH
endm
; Function Request 1BH
DEF_DRIVE_DATA macro
mov ah,1BH
int 21H
endm
; Function Request 1CH
DRIVE_DATA macro drive
mov dl,drive
mov ah,1CH
int 21H
endm
; Function Request 21H
READ_RAN macro fcb
mov dx,offset fcb
mov ah,21H
int 21H
endm
; Function Request 22H
WRITE_RAN macro fcb
mov dx,offset fcb
mov ah,22H
int 21H
endm
; Function Request 23H
FILE_SIZE macro fcb
mov dx,offset fcb
mov ah,23H
int 21H
endm
; Function Request 24H
SET_RELATIVE_RECORD macro fcb
mov dx,offset fcb
mov ah,24H
int 21H
endm
; Function Request 25H
SET_VECTOR macro interrupt,handler_start
mov al,interrupt
mov dx,offset handler_start
mov ah,25H
int 21H
endm
; Function Request 26H
CREATE_PSP macro seg_addr
mov dx,offset seg_addr
mov ah,26H
int 21H
endm
; Function Request 27H
RAN_BLOCK_READ macro fcb,count,rec_size
mov dx,offset fcb
mov cx,count
mov word ptr fcb[14],rec_size
mov ah,27H
int 21H
endm
; Function Request 28H
RAN_BLOCK_WRITE macro fcb,count,rec_size
mov dx,offset fcb
mov cx,count
mov word ptr fcb[14],rec_size
mov ah,28H
int 21H
endm
; Function Request 29H
PARSE macro string,fcb
mov si,offset string
mov di,offset fcb
push es
push ds
pop es
mov al,0FH
mov ah,29H
int 21H
pop es
endm
; Function Request 2AH
GET_DATE macro
mov ah,2AH
int 21H
endm
; Function Request 2BH
SET_DATE macro year,month,day
mov cx,year
mov dh,month
mov dl,day
mov ah,2BH
int 21H
endm
; Function Request 2CH
GET_TIME macro
mov ah,2CH
int 21H
endm
; Function Request 2DH
SET_TIME macro hour,minutes,seconds,hundredths
mov ch,hour
mov cl,minutes
mov dh,seconds
mov dl,hundredths
mov ah,2DH
int 21H
endm
; Function Request 2EH
VERIFY macro switch
mov al,switch
mov ah,2EH
int 21H
endm
; Function Request 2FH
GET_DTA macro
mov ah,2FH
int 21H
endm
; Function Request 30H
GET_VERSION macro
mov ah,30H
int 21H
endm
; Function Request 31H
KEEP_PROCESS macro return_code,last_byte
mov al,return_code
mov dx,offset last_byte
mov cl,4
shr dx,cl
inc dx
mov ah,31H
int 21H
endm
; Function Request 33H
CTRL_C_CK macro action,state
mov al,action
mov dl,state
mov ah,33H
int 21H
endm
; Function Request 35H
GET_VECTOR macro interrupt
mov al,interrupt
mov ah,35H
int 21H
endm
; Function Request 36H
GET_DISK_SPACE macro drive
mov dl,drive
mov ah,36H
int 21H
endm
; Function Request 38H
GET_COUNTRY macro country,buffer
local gc_01
mov dx,offset buffer
mov ax,country
cmp ax,0FFH
jl gc_01
mov al,0ffh
mov bx,country
gc_01: mov ah,38H
int 21H
endm
; Function Request 38H
SET_COUNTRY macro country
local sc_01
mov dx,0FFFFH
mov ax,country
cmp ax,0FFH
jl sc_01
mov al,0ffh
mov bx,country
sc_01: mov ah,38H
int 21H
endm
; Function Request 39H
MAKE_DIR macro path
mov dx,offset path
mov ah,39H
int 21H
endm
; Function Request 3AH
REM_DIR macro path
mov dx,offset path
mov ah,3AH
int 21H
endm
; Function Request 3BH
CHANGE_DIR macro path
mov dx,offset path
mov ah,3BH
int 21H
endm
; Function Request 3CH
CREATE_HANDLE macro path,attrib
mov dx,offset path
mov cx,attrib
mov ah,3CH
int 21H
endm
; Function Request 3DH
OPEN_HANDLE macro path,access
mov dx,offset path
mov al,access
mov ah,3DH
int 21H
endm
; Function Request 3EH
CLOSE_HANDLE macro handle
mov bx,handle
mov ah,3EH
int 21H
endm
; Function Request 3FH
READ_HANDLE macro handle,buffer,bytes
mov bx,handle
mov dx,offset buffer
mov cx,bytes
mov ah,3FH
int 21H
endm
; Function Request 40H
WRITE_HANDLE macro handle,buffer,bytes
mov bx,handle
mov dx,offset buffer
mov cx,bytes
mov ah,40H
int 21H
endm
; Function Request 41H
DELETE_ENTRY macro path
mov dx,offset path
mov ah,41H
int 21H
endm
; Function Request 42H
MOVE_PTR macro handle,high,low,method
mov bx,handle
mov cx,high
mov dx,low
mov al,method
mov ah,42H
int 21H
endm
; Function Request 43H
CHANGE_MODE macro path,action,attrib
mov dx,offset path
mov al,action
mov cx,attrib
mov ah,43H
int 21H
endm
; Function Request 4400H,01H
IOCTL_DATA macro code,handle
mov bx,handle
mov al,code
mov ah,44H
int 21H
endm
; Function Request 4402H,03H
IOCTL_CHAR macro code,handle,buffer
mov bx,handle
mov dx,offset buffer
mov al,code
mov ah,44H
int 21H
endm
; Function Request 4404H,05H
IOCTL_STATUS macro code,drive,buffer
mov bl,drive
mov dx,offset buffer
mov al,code
mov ah,44H
int 21H
endm
; Function Request 4406H,07H
IOCTL_STATUS macro code,handle
mov bx,handle
mov al,code
mov ah,44H
int 21H
endm
; Function Request 4408H
IOCTL_CHANGE macro drive
mov bl,drive
mov al,08H
mov ah,44H
int 21H
endm
; Function Request 4409H
IOCTL_RBLOCK macro drive
mov bl,drive
mov al,09H
mov ah,44H
int 21H
endm
; Function Request 440AH
IOCTL_RHANDLE macro handle
mov bx,handle
mov al,0AH
mov ah,44H
int 21H
endm
; Function Request 440BH
IOCTL_RETRY macro retries,wait
mov dx,retries
mov cx,wait
mov al,0BH
mov ah,44H
int 21H
endm
; Function Request 440CH
GENERIC_IOCTL_HANDLES macro handle,function,category,buffer
mov ch,05H
mov cl,function
mov dx,offset buffer
mov bx,handle
mov ah,44H
mov al,0CH
int 21H
endm
; Function Request 440DH
GENERIC_IOCTL_BLOCK macro drive_num,function,category,parm_blk
mov ch,08H
mov cl,function
mov dx,offset parm_blk - 1
mov bx,drive_num
mov ah,44H
mov al,0DH
int 21H
endm
; Function Request 440EH
IOCTL_GET_DRIVE_MAP macro logical_drv
mov bx,logical_drv
mov ah,44H
mov al,0EH
int 21H
endm
; Function Request 440FH
IOCTL_SET_DRIVE_MAP macro logical_drv
mov bx,logical_drv
mov ah,44H
mov al,0FH
int 21H
endm
; Function Request 45H
XDUP macro handle
mov bx,handle
mov ah,45H
int 21H
endm
; Function Request 46H
XDUP2 macro handle1,handle2
mov bx,handle1
mov cx,handle2
mov ah,46H
int 21H
endm
; Function Request 47H
GET_DIR macro drive,buffer
mov dl,drive
mov si,offset buffer
mov ah,47H
int 21H
endm
; Function Request 48H
ALLOCATE_MEMORY macro bytes
mov bx,bytes
mov cl,4
shr bx,cl
inc bx
mov ah,48H
int 21H
endm
; Function Request 49H
FREE_MEMORY macro seg_addr
mov ax,seg_addr
mov es,ax
mov ah,49H
int 21H
endm
; Function Request 4AH
SET_BLOCK macro last_byte
mov bx,offset last_byte
mov cl,4
shr bx,cl
add bx,17
mov ah,4AH
int 21H
mov ax,bx
shl ax,cl
dec ax
mov sp,ax
mov bp,sp
endm
; Function Request 4B00H
EXEC macro path,command,parms
mov dx,offset path
mov bx,offset parms
mov word ptr parms[02h],offset command
mov word ptr parms[04h],cs
mov word ptr parms[06h],5ch
mov word ptr parms[08h],es
mov word ptr parms[0ah],6ch
mov word ptr parms[0ch],es
mov al,0
mov ah,4BH
int 21H
endm
; Function Request 4B03H
EXEC_OVL macro path,parms,seg_addr
mov dx,offset path
mov bx,offset parms
mov parms,seg_addr
mov parms[02H],seg_addr
mov al,3
mov ah,4BH
int 21H
endm
; Function Request 4CH
END_PROCESS macro return_code
mov al,return_code
mov ah,4CH
int 21H
endm
; Function Request 4DH
RET_CODE macro
mov ah,4DH
int 21H
endm
; Function Request 4EH
FIND_FIRST_FILE macro path,attrib
mov dx,offset path
mov cx,attrib
mov ah,4EH
int 21H
endm
; Function Request 4FH
FIND_NEXT_FILE macro
mov ah,4FH
int 21H
endm
; Function Request 54H
GET_VERIFY macro
mov ah,54H
int 21H
endm
; Function Request 56H
RENAME_FILE macro old_path,new_path
mov dx,offset old_path
push ds
pop es
mov di,offset new_path
mov ah,56H
int 21H
endm
; Function Request 57H
GET_SET_DATE_TIME macro handle,action,time,date
mov bx,handle
mov al,action
mov cx,word ptr time
mov dx,word ptr date
mov ah,57H
int 21H
endm
; Function Request 58H
ALLOC_STRAT macro code,strategy
mov bx,strategy
mov al,code
mov ah,58H
int 21H
endm
; Function Request 59H
GET_ERROR macro
mov ah,59
int 21H
endm
; Function Request 5AH
CREATE_TEMP macro pathname,attrib
mov cx,attrib
mov dx,offset pathname
mov ah,5AH
int 21H
endm
; Function Request 5BH
CREATE_NEW macro pathname,attrib
mov cx,attrib
mov dx,offset pathname
mov ah,5BH
int 21H
endm
; Function Request 5C00H
LOCK macro handle,start,bytes
mov bx,handle
mov cx,word ptr start
mov dx,word ptr start+2
mov si,word ptr bytes
mov di,word ptr bytes+2
mov al,0
mov ah,5CH
int 21H
endm
; Function Request 5C01H
UNLOCK macro handle,start,bytes
mov bx,handle
mov cx,word ptr start
mov dx,word ptr start+2
mov si,word ptr bytes
mov di,word ptr bytes+2
mov al,1
mov ah,5CH
int 21H
endm
; Function Request 5E00H
GET_MACHINE_NAME macro buffer
mov dx,offset buffer
mov al,0
mov ah,5EH
int 21H
endm
; Function Request 5E02H
PRINTER_SETUP macro index,lgth,string
mov bx,index
mov cx,lgth
mov dx,offset string
mov al,2
mov ah,5EH
int 21H
endm
; Function Request 5F02H
GET_LIST macro index,local,remote
mov bx,index
mov si,offset local
mov di,offset remote
mov al,2
mov ah,5FH
int 21H
endm
; Function Request 5F03H
REDIR macro device,value,source,destination
mov bl,device
mov cx,value
mov si,offset source
mov es,seg destination
mov di,offset destination
mov al,03H
mov ah,5FH
int 21H
endm
; Function Request 5F04H
CANCEL_REDIR macro local
mov si,offset local
mov al,4
mov ah,5FH
int 21H
endm
; Function Request 62H
GET_PSP macro
mov ah,62H
int 21H
endm
;
;
; *******************
; General
; *******************
;
DISPLAY_ASCIZ macro asciz_string
local search,found_it
mov bx,offset asciz_string
search:
cmp byte ptr [bx],0
je found_it
inc bx
jmp short search
found_it:
mov byte ptr [bx],"$"
display asciz_string
mov byte ptr [bx],0
display_char 0DH
display_char 0AH
endm
;
MOVE_STRING macro source,destination,count
push es
push ds
pop es
assume es:code
mov si,offset source
mov di,offset destination
mov cx,count
rep movs es:destination,source
assume es:nothing
pop es
endm
;
CONVERT macro value,base,destination
local table,start
jmp start
table db "0123456789ABCDEF"
start:
push ax
push bx
push dx
mov al,value
xor ah,ah
xor bx,bx
div base
mov bl,al
mov al,cs:table[bx]
mov destination,al
mov bl,ah
mov al,cs:table[bx]
mov destination[1],al
pop dx
pop bx
pop ax
endm
;
CONVERT_TO_BINARY macro string,number,value
local ten,start,calc,mult,no_mult
jmp start
ten db 10
start:
mov value,0
xor cx,cx
mov cl,number
xor si,si
calc:
xor ax,ax
mov al,string[si]
sub al,48
cmp cx,2
jl no_mult
push cx
dec cx
mult:
mul cs:ten
loop mult
pop cx
no_mult:
add value,ax
inc si
loop calc
endm
;
CONVERT_DATE macro dir_entry
mov dx,word ptr dir_entry[24]
mov cl,5
shr dl,cl
mov dh,dir_entry[24]
and dh,1FH
xor cx,cx
mov cl,dir_entry[25]
shr cl,1
add cx,1980
endm
;
PACK_DATE macro date
local set_bit
;
; On entry: DH=day, DL=month, CX=(year-1980)
;
sub cx,1980
push cx
mov date,dh
mov cl,5
shl dl,cl
pop cx
jnc set_bit
or cl,80h
set_bit:
or date,dl
rol cl,1
mov date[1],cl
endm
;
────────────────────────────────────────────────────────────────────────────
Chapter 2 MS-DOS Device Drivers
2.1 Introduction
2.2 Format of a Device Driver
2.3 How to Create a Device Driver
2.3.1 Device Strategy Routine
2.3.2 Device Interrupt Routine
2.4 Installing Device Drivers
2.5 Device Headers
2.5.1 Pointer to Next Device Field
2.5.2 Attribute Field
2.5.3 Strategy and Interrupt Routines
2.5.4 Name Field
2.6 Request Header
2.6.1 Length of Record
2.6.2 Unit Code Field
2.6.3 Command Code Field
2.6.4 Status Field
2.7 Device Driver Functions
2.7.1 The Init Function
2.7.2 The Media Check Function
2.7.3 The Build BPB Function
2.7.4 The Read or Write Function
2.7.5 The Non-destructive Read, No Wait Function
2.7.6 The Open or Close Function
2.7.7 The Removable Media Function
2.7.8 The Status Function
2.7.9 The Flush Function
2.7.10 The Generic IOCtl Function
2.7.11 The Get/Set Logical Drive Map Function
2.8 The Media Descriptor Byte
2.9 Format of a Media Descriptor Table
2.10 The CLOCK Device
2.11 Anatomy of a Device Call
2.12 Two Sample Device Drivers
2.1 Introduction
The io.sys file comprises the "resident" device drivers, which form the
MS-DOS BIOS. These drivers are called upon by MS-DOS to handle
input/output (I/O) requests initiated by application programs.
One of the most powerful features of MS-DOS is the ability to add new
devices such as printers, plotters, and mouse input devices without
rewriting the BIOS. The MS-DOS BIOS is configurable; that is, new drivers
can be added and existing drivers can be preempted. Nonresident, or
installable, device drivers may be easily added at boot time by including
a device command line in the config.sys file.
At boot time, a minimum of five resident device drivers must be present.
These drivers are in a linked list: the header of each one contains a
DWORD pointer to the next. The last driver in the chain has an end-of-list
marker of -1, -1 (all bits on).
Each driver in the chain has two entry points: the strategy entry point
and the interrupt entry point. MS-DOS does not take advantage of the two
entry points: it calls the strategy routine, then immediately calls the
interrupt routine.
The dual entry points will accomodate future multitasking versions of
MS-DOS. In multitasking environments, I/O must be asynchronous; to
accomplish this, the strategy routine will be called to (internally) queue
a request and return quickly. It is then the responsibility of the
interrupt routine to perform the I/O at interrupt time by getting requests
from the internal queue and processing them. When a request is completed,
it is flagged as "done" by the interrupt routine. MS-DOS periodically
scans the list of requests looking for those that are flagged as done, and
"wakes up" the process waiting for the completion of the request.
When requests are queued in this manner, it is no longer sufficient to
pass I/O information in registers, since many requests may be pending at
any time. Therefore, the MS-DOS device interface uses "packets" to pass
request information. These request packets vary in size and format, and
are composed of two parts:
1. The static request header section, which has the same format for all
requests
2. A section which has information specific to the type of request
A driver is called with a pointer to a packet. In multitasking versions,
this packet will be linked into a global chain of all pending I/O requests
maintained by MS-DOS.
MS-DOS does not implement a global or local queue. Only one request is
pending at any one time. The strategy routine must store the address of
the packet at a fixed location, and the interrupt routine, which is called
immediately after the strategy routine, should process the packet by
completing the request and returning. It is assumed that the request is
completed when the interrupt routine returns.
To make a device driver that sysinit can install, a .bin (core image) or
.exe format file must be created with the device driver header at the
beginning of the file. The link field should be initialized to -1 (sysinit
fills it in). Device drivers which are part of the BIOS should have their
headers point to the next device in the list and the last header should be
initialized to -1,-1. The BIOS must be a .bin (core image) format file.
The .exe format installable device drivers may be used in non-IBM versions
of MS-DOS. On the IBM Personal Computer, the .exe loader is located in
command.com, which is not present at the time that installable devices are
being loaded.
2.2 Format of a Device Driver
A device driver is a program segment responsible for communication between
DOS and the system hardware. It has a special header at the beginning
identifying it as a device driver, defining entry points, and describing
various attributes of the device.
──────────────────────────────────────────────────────────────────────────
Note
For device drivers, the file must not use the ORG 100H (like .com
files). Because it does not use the Program Segment Prefix (PSP), the
device driver is simply loaded; therefore, the file must have an origin
of zero (ORG 0 or no ORG statement).
──────────────────────────────────────────────────────────────────────────
There are two kinds of device drivers:
■ Character device drivers
■ Block device drivers
Character devices perform serial character I/O. Examples are the console,
communications port, and printer. These devices are named (i.e., CON, AUX,
CLOCK, etc.), and programs may open channels (handles or file control
blocks) to do I/O to them.
Block devices include all the disk drives on the system. They can perform
random I/O in structured pieces called blocks (usually the physical sector
size). These devices are not named as the character devices are and,
therefore, cannot be opened directly. Instead they have unit numbers and
are identified by drive letters such as A, B, and C.
A single block device driver may be responsible for one or more logically
contiguous disk drives. For example, block device driver ALPHA may be
responsible for drives A, B, C, and D. This means that it has four units
defined (0-3) and, therefore, takes up four drive letters. The position of
the driver in the list of all drivers determines which units correspond to
which driver letters. If driver ALPHA is the first block driver in the
device list, and it defines four 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. The theoretical limit is 63, but
it should be noted that the device installation code will not allow the
installation of a device if it would result in a drive letter greater than
Z (5AH). All block device drivers present in the standard resident BIOS
will be placed ahead of installable block device drivers in the list.
──────────────────────────────────────────────────────────────────────────
Note
Because they have only one name, character devices cannot define
multiple units.
──────────────────────────────────────────────────────────────────────────
2.3 How to Create a Device Driver
To create a device driver that MS-DOS can install, you must create a
binary file (.com or .exe format) with a device header at the beginning of
the file. Notice that for device drivers, the code should not be
originated at 100H, but at 0. The device header contains a link field (a
pointer to the next device header) that should be -1, unless there is more
than one device driver in the file. The attribute field and entry points
must be set correctly.
If it is a character device, the name field should be filled in with the
name of that character device. The name can be any legal eight-character
filename. If the name is less than eight characters, it should be padded
out to eight characters with spaces (20H). Notice that device names do not
include colons (:). The fact that CON is the same as CON: is a property of
the default MS-DOS command interpreter (command.com) and not of the device
driver or the MS-DOS interface. All character device names are handled in
this way.
MS-DOS always processes installable device drivers before handling the
default devices; so, to install a new CON device, simply name the device
CON. Remember to set the standard input device and standard output device
bits in the attribute word on a new CON device. The scan of the device
list stops on the first match, so the installable device driver takes
precedence.
It is not possible to replace the resident disk block device driver with
an installable device driver the same way you can replace the other device
drivers in the BIOS. Block drivers can be used only for devices not
directly supported by the default disk drivers in AE@%
database installed. As an example, if your SQL Server is named sql_svr,
e
Note
Because MS-DOS can install the driver anywhere in memory, care must be
taken when making far memory references. You should not expect that your
driver will always be loaded in the same place every time.
──────────────────────────────────────────────────────────────────────────
2.3.1 Device Strategy Routine
The device strategy routine, which is called by MS-DOS for each device
driver service request, is primarily responsible for queuing these
requests in the order in which they are to be processed by the device
interrupt routine. Such queuing can be a very important performance
feature in a multitasking environment, or where asynchronous I/O is
supported. As MS-DOS does not currently support these facilities, only one
request can be serviced at a time, and this routine is usually very short.
In the coding examples in Section 2.12, "Two Sample Device Drivers," each
request is simply stored in a single pointer area.
2.3.2 Device Interrupt Routine
The device interrupt routine contains the code necessary to process the
service request. It may interface to the hardware, or it may use ROM BIOS
calls. It usually consists of a series of procedures that handle the
specific command codes to be supported as well as some exit and
error-handling routines. See the coding examples in Section 2.12, "Two
Sample Device Drivers."
2.4 Installing Device Drivers
MS-DOS allows new device drivers to be installed dynamically at boot time.
This is accomplished by initialization code in the io.sys file that reads
and processes the config.sys file.
MS-DOS calls upon the device drivers to perform their function in the
following manner:
1. MS-DOS makes a FAR call to the strategy entry.
2. MS-DOS passes device driver information in a request header to the
strategy routine.
3. MS-DOS makes a FAR call to the interrupt entry.
This calling structure is designed to be easily upgraded to support any
future multitasking environment.
2.5 Device Headers
A device header is required at the beginning of a device driver. A device
header looks like this:
┌──────────────────────────────────────┐
│ DWORD Pointer to next device │
│ (Usually set to -1 if this driver │
│ is the last or only driver in the │
│ file) │
├──────────────────────────────────────┤
│ WORD Attributes │
├──────────────────────────────────────┤
│ 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. │
└──────────────────────────────────────┘
Figure 2.1 Sample Device Header
Notice that the device entry points are words. They must be offsets from
the same segment number used to point to this table. For example, if
xxx:yyy points to the start of this table, then xxx:strategy and
xxx:interrupt are the entry points.
The device header fields are described in the following section.
2.5.1 Pointer to Next Device Field
The pointer to the next device header field is a double-word field (offset
followed by segment) that is set by MS-DOS to point at the next driver in
the system list at the time the device driver is loaded. It is important
that this field be set to -1 prior to load (when it is on the disk as a
file) unless there is more than one device driver in the file. If there is
more than one driver in the file, the first word of the double-word
pointer should be the offset of the next driver's device header.
──────────────────────────────────────────────────────────────────────────
Note
If there is more than one device driver in the file, the last driver in
the file must have the pointer to the next device header field set to
-1.
──────────────────────────────────────────────────────────────────────────
2.5.2 Attribute Field
The attribute field is used to identify the type of device for which this
driver is responsible. In addition to distinguishing between block and
character devices, these bits are used to give selected character devices
special treatment. (Notice that if a bit in the attribute word is defined
only for one type of device, a driver for the other type of device must
set that bit to 0.)
Table 2.1
For Character Devices:
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 1 Device is console input (sti) device
1 1 Device is console output (sto) device
2 1 Device is nul device
3 1 Device is clock device
4-5 Reserved (must be 0)
6 1 Device supports 3.2 functions
7-10 Reserved (must be 0)
11 1 Device understands Open/Close
12 Reserved (must be 0)
13 1 Device supports Output Until Busy (OUB)
14 1 Device supports IOCtl control strings
15 1 Character device
──────────────────────────────────────────────────────────────────────────
Table 2.2
For Block Devices:
Bit Value Meaning
──────────────────────────────────────────────────────────────────────────
0 Reserved (must be 0)
1 1 Device supports 32-bit sector addressing
2-5 Reserved (must be 0)
6 1 Device supports 3.2 functions and Generic
IOCtl function calls
7-10 Reserved (must be 0)
11 1 Device understands Open/Close/Removable
Media
12 Reserved (must be 0)
13 1 Device determines the media by examining
the FATID byte
14 1 Device supports IOCtl control strings
15 0 Block device
──────────────────────────────────────────────────────────────────────────
For example, assume that you have a new device driver that you want to use
as the standard input and output. In addition to installing the driver,
you must tell MS-DOS that you want the new driver to override the current
standard input and standard output (the CON device). This is accomplished
by setting the attributes to the desired characteristics, so you would set
bits 0 and 1 to 1 (notice that they are separate). Similarly, a new CLOCK
device could be installed by setting that attribute. (Refer to Section
2.10, "The CLOCK Device," in this chapter for more information.) Although
there is a NUL device attribute, the NUL device cannot be reassigned. This
attribute exists so that MS-DOS can determine if the NUL device is being
used.
Bit 13 for block devices affects the operation of the Build BPB (BIOS
Parameter Block) device call. If set, it requires the first sector of the
FAT always to reside in the same place. This bit has a different meaning
on character devices. It indicates that the device implements the Output
Until Busy device call.
The IOCtl bit (bit 14) has meaning on character and block devices. The
IOCtl functions allow data to be sent and received by the device for its
own use (to set baud rate, stop bits, form length, 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 be treated as normal I/O. This bit tells MS-DOS whether the device can
handle control strings by using the IOCtl system call, Function 44H.
If a driver cannot process control strings, it should initially set this
bit to 0. This tells MS-DOS to return an error if an attempt is made (via
Function 44H) to send or receive control strings to this device. A device
which can process control strings should initialize the IOCtl bit to 1.
For drivers of this type, MS-DOS will make calls to the IOCtl input and
output device functions to send and receive IOCtl strings. The IOCtl
functions allow data to be sent and received by the device for its own use
(for example, to set baud rate, stop bits, and form length), instead of
passing data over the device channel as does a normal read or write. The
interpretation of the passed information is up to the device, but it must
not be treated as a normal I/O request.
The Open/Close/Removable Media bit (bit 11) signals to MS-DOS 3.x and
later versions whether this driver supports additional MS-DOS 3.x
functionality. To support these old drivers, it is necessary to detect
them. This bit was reserved in MS-DOS 2.x, and is 0. All new devices
should support the Open, Close, and Removable Media calls and set this bit
to 1. Since MS-DOS 2.x never makes these calls, the driver will be
backward-compatible.
The MS-DOS 3.2 bit (bit 6) signals whether the device supports logical
drive mapping via Function 440EH (Get Logical Drive Map) and Function
440FH (Set Logical Drive Map). This bit also supports generic IOCtl
functions via Function 440CH (Generic IOCtl for Handles) and Function
440DH (Generic IOCtl for Block Devices).
Bit 1 for block devices indicates the driver's ability to manipulate
32-bit sector addresses. If bit 1 = 1, 32-bit sector addressing is
supported. If bit 1 is set, the sector number field of all requests is a
DWORD added to the end of the request header. The old WORD length sector
number should be -1.
The driver requests affected are:
■ BUILD BPD command 2
■ INPUT/OUTPUT command 3 ,4, 8, 9, and 12
■ GENERIC IOCTL command 19
If bit 1 for block devices is 0, only 16-bit sector addressing is
available.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ C │ I │ │ │ O │ │ │ │ │ 3 │ │ │ C │ N │ S │ S │
│ H │ O │ │ │ P │ │ │ │ │ . │ │ │ L │ U │ T │ T │
│ R │ C │ │ │ N │ │ │ │ │ 2 │ │ │ K │ L │ O │ I │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
Figure 2.2 Attribute Word for Character Devices
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ │ I │ F │ │ O │ │ │ │ │ 3 │ │ │ │ │ > │ │
│ │ O │ A │ │ P │ │ │ │ │ . │ │ │ │ │ 3 │ │
│ │ C │ T │ │ N │ │ │ │ │ 2 │ │ │ │ │ 2 │ │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
Figure 2.3 Attribute Word for Block Devices
2.5.3 Strategy and Interrupt Routines
These two fields are the pointers to the entry points of the strategy and
interrupt routines. They are word values, so they must be in the same
segment as the device header.
2.5.4 Name Field
This is an eight-byte field that contains the name of a character device
or the number of units of a block device. If the field refers to a block
device, the number of units can be put in the first byte. This is
optional, because MS-DOS will fill in this location with the value
returned by the driver's Init code. For more information, see Section
2.4, "Installing Device Drivers."
2.6 Request Header
When MS-DOS calls a device driver to perform a function, it passes a
request header in ES:BX to the strategy entry point. This is a fixed
length header, followed by data pertinent to the operation being
performed. Notice that it is the device driver's responsibility to
preserve the machine state (for example, save all registers, including
flags, on entry, and restore them on exit). There is enough room on the
stack when the strategy or interrupt routine is called to do about 20
pushes. If more room on the stack is needed, the driver should set up its
own stack.
The following figure illustrates a request header.
REQUEST HEADER ->
┌─────────────────────────────┐
│ BYTE Length of record │
│ Length in bytes of this │
│ request header │
├─────────────────────────────┤
│ BYTE Unit code │
│ The subunit the operation │
│ is for (minor device) │
│ (no meaning on character │
│ devices) │
├─────────────────────────────┤
│ BYTE Command code │
├─────────────────────────────┤
│ WORD Status │
├─────────────────────────────┤
│ 8 BYTES Reserved │
│ │
└─────────────────────────────┘
Figure 2.4 Request Header
The request header fields are described below.
2.6.1 Length of Record
This field contains the length (in bytes) of the request header.
2.6.2 Unit Code Field
The unit code field identifies which unit in your device driver the
request is for. For example, if your device driver has three units
defined, then the possible values of the unit code field would be 0, 1,
and 2.
2.6.3 Command Code Field
The command code field in the request header can have the following
values:
╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
Code Function
──────────────────────────────────────────────────────────────────────────
0 Init
1 Media Check (Block devices only)
2 Build BPB (Block devices only)
3 IOCtl Input (Only called if device has IOCtl)
4 Input (Read)
5 Non-destructive Read, No Wait (Character devices only)
6 Input Status (Character devices only)
7 Input Flush (Character devices only)
8 Output (Write)
9 Output (Write) with Verify
10 Output Status (Character devices only)
11 Output Flush (Character devices only)
Code Function
──────────────────────────────────────────────────────────────────────────
11 Output Flush (Character devices only)
12 IOCtl Output (Only called if device has IOCtl)
13 Device Open (Only called if Open/Close/Removable Media
bit set)
14 Device Close (Only called if Open/Close/Removable Media
bit set)
15 Removable Media (Only called if Open/Close/Removable
Media bit set and device is block)
16 Output Until Busy (Only called if bit 13 is set on
character devices)
19 Generic IOCtl Request
23 Get Logical Device
24 Set Logical Device
──────────────────────────────────────────────────────────────────────────
2.6.4 Status Field
The following figure illustrates the status field in the request header.
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 │ │ S │ N │ │
│ │ │ Y │ E │ │
└───┴───────────────┴───┴───┴───────────────────────┘
Figure 2.5 Status Field
The status word is zero on entry and is set by the driver interrupt
routine on return.
Bit 8 is the done bit. When set, it means the operation has completed. The
driver sets it to 1 when it exits.
Bit 15 is the error bit. If it is set, then the low eight bits indicate
the error. The errors are as follows:
Error Meaning
──────────────────────────────────────────────────────────────────────────
0 Write protect violation
1 Unknown unit
2 Drive not ready
3 Unknown command
4 CRC error
5 Bad drive request structure length
6 Seek error
7 Unknown media
8 Sector not found
9 Printer out of paper
──────────────────────────────────────────────────────────────────────────
Error Meaning
──────────────────────────────────────────────────────────────────────────
A Write fault
B Read fault
C General failure
D Reserved
E Reserved
F Invalid disk change
──────────────────────────────────────────────────────────────────────────
Bit 9 is the busy bit, which is set only by Status calls and the Removable
Media call.
2.7 Device Driver Functions
Device drivers may perform all or some of these general functions. In some
cases, these functions break down into several command codes, for specific
cases. Each of the following general functions is described in this
section.
■ Init
■ Media Check
■ Build BPB
■ Read, or Write, or Write Until Busy, or Write with Verify, or Read
IOCtl, or Write IOCtl
■ Non-destructive Read, No Wait
■ Open or Close (3.x)
■ Removable Media (3.x)
■ Status
■ Flush
■ Generic IOCtl
■ Get or Set Logical Device
All strategy routines are called with ES:BX pointing to the request
header. The interrupt routines get the pointers to the request header from
the queue that the strategy routines store them in. The command code in
the request header tells the driver which function to perform and what
data follows the request header.
──────────────────────────────────────────────────────────────────────────
Note
All DWORD pointers are stored offset first, then segment.
──────────────────────────────────────────────────────────────────────────
2.7.1 The Init Function
Command code = 0
INIT - ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Request header │
├────────────────────────────────────┤
│ BYTE Number of units │
├────────────────────────────────────┤
│ DWORD End Address │
├────────────────────────────────────┤
│ DWORD Pointer to BPB array │
│ (Not set by character devices) │
├────────────────────────────────────┤
│ BYTE Block device number │
└────────────────────────────────────┘
One of the functions defined for each device driver is Init. This routine
is called only once when the device is installed. The Init routine must
return the end address, which is a DWORD pointer to the end of the portion
of the device driver to remain resident. To save space, you can use this
pointer method to delete initialization code that is needed only once.
The number of units, end address, and BPB pointer are to be set by the
driver. However, on entry for installable device drivers, the DWORD that
is to be set by the driver to the BPB array (on block devices) points to
the character after the "=" on the line in config.sys that caused this
device driver to be loaded. This allows drivers to scan the config.sys
invocation line for parameters that might be passed to the driver. This
line is terminated by an ENTER or a linefeed character. This data is
read-only and allows the device to scan the config.sys command line for
arguments.
device=\dev\vt52.sys /l
│
└─────BPB address points here
Also, for block devices only, the drive number assigned to the first unit
defined by this driver (A=0) is contained in the block device number
field. This is also read-only.
──────────────────────────────────────────────────────────────────────────
Note
The Init routine can issue only Functions 01H-0CH, 25H, 30H, and
35H.
──────────────────────────────────────────────────────────────────────────
For installable character devices, the end address parameter must be
returned. This is a pointer to the first available byte of memory above
the driver and may be used to throw away initialization code.
Block devices must return the following information:
1. The number of units. MS-DOS uses this number to determine 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 the position of the driver in the device list,
and by the number of units on the device (stored in the first byte of
the device name field).
2. A DWORD pointer to an array of word offsets (pointers) to BPBs (BIOS
Parameter Blocks). The BPBs passed by the device driver are used by
MS-DOS to create an internal structure. There must be one entry in this
array for each unit defined by the device driver. In this way, if all
units are the same, all the pointers can point to the same BPB, thereby
saving space. If the device driver defines two units, then the DWORD
pointer points to the first of two one-word offsets which in turn point
to BPBs. The format of the BPB is described in Section 2.7.3, "The
Build BPB Function."
Notice that this array of word offsets must be protected (below the
free pointer set by the return), since an internal DOS structure will
be built starting at the byte pointed to by the free pointer. The
defined sector size must be less than or equal to the maximum sector
size defined by the resident device drivers (BIOS) during
initialization. If it isn't, the installation will fail.
3. The media descriptor byte. This byte means nothing to MS-DOS, but is
passed to devices so that they know what parameters MS-DOS is currently
using for a particular drive.
──────────────────────────────────────────────────────────────────────────
Note
If there are multiple device drivers in a single file, MS-DOS uses the
ending address returned by the last Init function called. All device
drivers in a single file should return the same ending address. All
devices in a single file should be grouped together low in memory with
the initialization code for all devices following it in memory.
──────────────────────────────────────────────────────────────────────────
2.7.2 The Media Check Function
Command Code = 1
MEDIA CHECK - ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Request header │
├────────────────────────────────────┤
│ BYTE Media descriptor from BPB │
├────────────────────────────────────┤
│ BYTE Returned │
│────────────────────────────────────┤
│ Returned DWORD pointer to previous │
│ Volume ID if bit 11 set and │
│ Disk Changed is returned │
└────────────────────────────────────┘
The Media Check function is used only with block devices. It is called
when there is a pending drive-access call other than a file read or write,
such as Open, Close, delete, and rename. Its purpose is to determine
whether the media in the drive has been changed. If the driver can assure
that the media has not been changed (through a door-lock or other
interlock mechanism), MS-DOS performance is enhanced, because MS-DOS does
not need to reread the FAT and invalidate in-memory buffers for each
directory access.
When a disk-access call to the DOS occurs (other than a file read or
write), the following sequence of events takes place:
1. The DOS converts the drive letter into a unit number of a particular
block device.
2. The device driver is then called to request a media check on that
subunit to see if the disk might have been changed. MS-DOS passes the
old media descriptor byte. The driver returns one of the following:
Return Meaning
───────────────────────────────────────────────────────────────────────
(1) Media not changed
(0) Don't know if changed
(-1) Media changed
value Error (value is a standard error code value)
───────────────────────────────────────────────────────────────────────
If the media has not been changed, MS-DOS proceeds with the disk
access.
If the value returned is -1, and there are any disk sectors that have
been modified and not written back out to the disk for this unit,
MS-DOS assumes that the disk has not been changed and proceeds. MS-DOS
invalidates any other buffers for the unit and does a Build BPB call
(see Step 3, following).
If the media has been changed, MS-DOS invalidates all buffers
associated with this unit including buffers with modified data that are
waiting to be written, and requests a new BIOS Parameter Block via the
Build BPB call (see Step 3).
3. Once the BPB has been returned, MS-DOS corrects its internal structure
for the drive from the new BPB and proceeds with the access after
reading the directory and the FAT.
Notice that the previous media ID byte is passed to the device driver. If
the old media ID byte is the same as the new one, the disk might have been
changed and a new disk may be in the drive; therefore, all FAT, directory,
and data sectors that are buffered in memory for the drive are considered
invalid.
If the driver has bit 11 of the device attribute word set to 1, and the
driver returns -1 (Media Changed), the driver must set the DWORD pointer
to the previous Volume ID field. If the DOS determines that "Media
changed" is an error based on the state of the DOS buffer cache, the DOS
will generate a 0FH error on behalf of the device. If the driver does not
implement volume ID support, but has bit 11 set, it should set a static
pointer to the string "NO NAME" ,0. It is not possible for a user to
change a disk in less than two seconds. So when Media Check occurs within
two seconds of a disk access, the driver reports "Media not changed (1)."
This improves performance tremendously.
──────────────────────────────────────────────────────────────────────────
Note
If the media ID byte in the returned BPB is the same as the previous
media ID byte, MS-DOS will assume that the format of the disk is the
same (even though the disk may have been changed) and will skip the step
of updating its internal structure. Therefore, all BPBs must have unique
media bytes regardless of FAT ID bytes.
──────────────────────────────────────────────────────────────────────────
2.7.3 The Build BPB Function
Command code = 2
BUILD BPB - ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Request header │
├────────────────────────────────────┤
│ BYTE Media descriptor from BPB │
├────────────────────────────────────┤
│ DWORD Transfer address │
│ (Points to one sector worth of │
│ scratch space or first sector │
│ of FAT depending on the value │
│ of Bit 13 in the device attribute │
│ word.) │
├────────────────────────────────────┤
│ DWORD Pointer to BPB │
└────────────────────────────────────┘
The Build BPB function is used with block devices only. As described in
the Media Check function, the Build BPB function will be called any time
that a preceding Media Check call indicates that the disk has been or
might have been changed. The device driver must return a pointer to a BPB.
This is different from the Init call where the device driver returns a
pointer to an array of word offsets to BPBs. The Build BPB call gets a
DWORD pointer to a one-sector buffer. The contents of this buffer are
determined by the non-FAT ID bit (bit 13) in the attribute field. If the
bit is zero, then the buffer contains the first sector of the first FAT.
The FAT ID byte is the first byte of this buffer. In this case, the driver
must not alter this buffer. Notice that the location of the FAT must be
the same for all possible media because this first FAT sector must be read
before the actual BPB is returned. If the non-FAT ID bit is set, the
pointer points to one sector of scratch space (which may be used for
anything). For information on how to construct the BPB, see Section 2.8,
"The Media Descriptor Byte," and Section 2.9, "Format of a Media
Descriptor Table."
MS-DOS 4.0 includes additional support for devices that have door-locks or
some other means of telling when a disk has been changed. There is an
error that can be returned from the device driver (error 15). The error
means "the disk has been changed when it shouldn't have been," and the
user is prompted for the correct disk using a volume ID. The driver may
generate this error on read or write. The DOS may generate the error on
Media Check calls if the driver reports media changed and there are
buffers in the DOS buffer cache that need to be flushed to the previous
disk.
For drivers that support this error, the Build BPB function is a trigger
that causes a new volume ID to be read off the disk. This action indicates
that the disk has been legally changed. A volume ID is placed on a disk by
the format command and is simply an entry in the root directory of the
disk that has the Volume ID attribute. It is stored by the driver as an
ASCIZ string.
The requirement that the driver return a volume ID does not exclude some
other volume identifier scheme as long as the scheme uses ASCIZ strings. A
NUL (nonexistent or unsupported) volume ID is by convention the following
string:
DB "NO NAME ",0
2.7.4 The Read or Write Function
Command codes = 3,4,8,9,12, and 16
READ OR WRITE (Including IOCtl) or
OUTPUT UNTIL BUSY - ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Request header │
├────────────────────────────────────┤
│ BYTE Media descriptor from BPB │
├────────────────────────────────────┤
│ DWORD Transfer address │
├────────────────────────────────────┤
│ WORD Byte/sector count │
├────────────────────────────────────┤
│ WORD Starting sector number │
│ or -1 if the drive supports │
│ greater than 16-bit sector │
│ addresses │
│ (Ignored on character devices) │
├────────────────────────────────────┤
│ DWORD pointer to the Volume ID │
├────────────────────────────────────┤
│ Starting sector number │
│ (high-word first) if WORD starting │
│ sector number is -1 │
│ or │
│ Returned DWORD pointer to requested│
│ Volume ID if error 0FH │
└────────────────────────────────────┘
Code Request
──────────────────────────────────────────────────────────────────────────
3 IOCtl read
4 Read (block or character device)
8 Write (block or character device)
9 Write with Verify
12 IOCtl Write
16 Output Until Busy (character device only)
──────────────────────────────────────────────────────────────────────────
The driver must perform the Read or Write call depending on which command
code is set. Block devices read or write sectors; character devices read
or write bytes.
When I/O completes, the device driver must set the status word and report
the number of sectors or bytes successfully transferred. This should be
done even if an error prevented the transfer from being completed. Setting
the error bit and error code alone is not sufficient. In addition to
setting the status word, the driver must set the sector count to the
actual number of sectors (or bytes) transferred. No error check is
performed on an IOCtl I/O call. The device driver must always set the
return byte/sector count to the actual number of bytes/sectors
successfully transferred.
If the verify switch is on, the device driver will be called with command
code 9 (Write with Verify). Your device driver will be responsible for
verifying the write.
If the driver returns error code 0FH (Invalid disk change), it must return
a DWORD pointer to an ASCIZ string (which is the correct volume ID).
Returning this error code triggers the DOS to prompt the user to re-insert
the disk. The device driver should have read the volume ID as a result of
the Build BPB function.
Drivers may maintain a reference count of open files on the disk by
monitoring the Open and Close functions. This allows the driver to
determine when to return error 0FH. If there are no open files (reference
count = 0), and the disk has been changed, the I/O is okay. If there are
open files, however, an 0FH error may exist.
The Output Until Busy call is a speed optimization on character devices
only for print spoolers. The device driver is expected to output all the
characters possible until the device returns busy. Under no circumstances
should the device driver block during this function. Notice that it is not
an error for the device driver to return the number of bytes output as
being less than the number of bytes requested (or = 0).
The Output Until Busy call allows spooler programs to take advantage of
the "burst" behavior of most printers. Many printers have on-board RAM
buffers that typically hold a line or a fixed amount of characters. These
buffers fill up without the printer going busy, or going busy for a short
period (less than ten instructions) between characters. A line of
characters can be output quickly to the printer, after which the printer
is busy for a long time while the characters are being printed. This new
device call allows background spooling programs to use this burst behavior
efficiently. Rather than take the overhead of a device driver call for
each character, or risk getting stuck in the device driver outputting a
block of characters, this call allows a burst of characters to be output
without the device driver having to wait for the device to be ready.
The Following Applies to Block Device Drivers:
Under certain circumstances, the BIOS may be asked to perform a write
operation of 64 kilobytes, which seems to be a "wrap-around" of the
transfer address in the BIOS I/O packet. This request, which arises due to
an optimization added to the write code in MS-DOS, will manifest itself
only on user writes that are within a sector size of 64 kilobytes on files
"growing" past the current end-of-file (EOF) mark. It is allowable for the
BIOS to ignore the balance of the write that "wraps around" if it so
chooses. For example, a write of 10000H bytes-worth of sectors with a
transfer address of xxx:1 could ignore the last two bytes. A user program
can never request an I/O of more than FFFFH bytes and cannot wrap around
(even to 0) in the transfer segment. Therefore, in this case, the last two
bytes can be ignored.
MS-DOS maintains two FATs. If the DOS has problems reading the first, it
automatically tries the second before reporting the error. The BIOS is
responsible for all retries.
Although the command.com handler does no automatic retries, there are
applications that have their own Interrupt 24H handlers that do automatic
retries on certain types of Interrupt 24H errors before reporting them.
2.7.5 The Non-destructive Read, No Wait Function
Command code = 5
NON-DESTRUCTIVE READ NO WAIT - ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Request header │
├────────────────────────────────────┤
│ BYTE Read from device │
└────────────────────────────────────┘
The Non-destructive Read, No Wait function allows MS-DOS to look ahead one
input character. The device sets the done bit in the status word.
If the character device returns busy bit = 0 (there are characters in the
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"). If the character device returns busy bit = 1,
there are no characters in the buffer.
2.7.6 The Open or Close Function
Command codes = 13 and 14
OPEN or CLOSE - ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Static request header │
└────────────────────────────────────┘
The Open and Close functions are called by MS-DOS only if the device
driver sets the Open/Close/Removable Media attribute bit in the device
header. They are designed to inform the device about current file activity
on the device. On block devices, they can be used to manage local
buffering. The device can keep a reference count. Every Open causes the
device to increment the count, every Close to decrement. When the count
goes to zero, it means there are no open files on the device. Therefore,
the device should flush any buffers that have been written to that may
have been used inside the device, because it is now "legal" for the user
to change the media on a removable media drive.
There are problems with this mechanism on block devices because programs
that use FCB calls can open files without closing them. It is, therefore,
advisable to reset the count to zero without flushing the buffers when the
answer to "Has the media been changed?" is yes, and the Build BPB call is
made to the device.
These calls are more useful on character devices. The Open call, for
instance, can be used to send a device initialization string. On a
printer, this could cause a string for setting font and page size
characteristics to be sent to the printer so that it would always be in a
known state at the start of an I/O stream. Using IOCtl to set these pre-
and post- strings provides a flexible mechanism of serial I/O device
stream control. The reference count mechanism can also be used to detect a
simultaneous access error. It may be desirable to disallow more than one
Open on a device at any given time. In this case, a second Open would
result in an error.
Notice that since all processes have access to stdin, stdout, stderr,
stdaux, and stdprn (handles 0,1,2,3,4), the CON, AUX, and PRN devices are
always open.
2.7.7 The Removable Media Function
Command code = 15
REMOVABLE MEDIA - ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Static request header │
└────────────────────────────────────┘
The Removable Media function is called by MS-DOS only if the device driver
sets the Open/Close/Removable Media attribute bit in the device header.
This call is given only to block devices by a subfunction of the IOCtl
system call. It is sometimes desirable for a utility to know whether it is
dealing with a nonremovable media drive (such as a hard disk), or a
removable media drive (like a floppy). An example is the format command,
which prints different versions of some of the prompts.
The information is returned in the busy bit of the status word. If the
busy bit is 1, then the media is nonremovable. If the busy bit is 0, then
the media is removable. Notice that the error bit is not checked. It is
assumed that this call always succeeds.
2.7.8 The Status Function
Command codes = 6 and 10
STATUS Calls ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Request header │
└────────────────────────────────────┘
The Status function returns information to the DOS as to whether data is
waiting for input or output. All the driver must do is set the status word
and the busy bit as follows:
■ For output on character devices ── if the driver sets bit 9 to 1 on
return, it informs the DOS that 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.
■ For input on character devices with a buffer ── A return of 1 implies
that no characters are buffered and that a read request (if made) would
go to the physical device. If it is 0 on return, then there are
characters in the device buffer and a read would not be blocked. A
return of 0 implies that the user has typed something. MS-DOS assumes
that all character devices have an input type-ahead buffer.
Devices that do not have a type-ahead buffer should always return busy = 0
so that the DOS will not "hang" waiting for something to get into a
non-existent buffer.
2.7.9 The Flush Function
Command codes = 7 and 11
FLUSH Calls - ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Request header │
└────────────────────────────────────┘
The Flush function tells the driver to flush (terminate) all pending
requests. This call is used to flush the input queue on character devices.
The device driver performs the flush function, sets the status word, and
returns.
2.7.10 The Generic IOCtl Function
Command code = 19
ES:BX ->
┌────────────────────────────────────┐
│ 13-BYTE Static request header │
├────────────────────────────────────┤
│ BYTE Category (Major) code │
├────────────────────────────────────┤
│ BYTE Function (Minor) code │
├────────────────────────────────────┤
│ WORD (SI) Contents │
├────────────────────────────────────┤
│ WORD (DI) Contents │
├────────────────────────────────────┤
│ DWORD Pointer to data buffer │
└────────────────────────────────────┘
The Generic IOCtl function provides a generic, expandable IOCtl facility
that replaces and makes the Read IOCtl and Write IOCtl device driver
functions obsolete. The MS-DOS 2.0 IOCtl functions remain to support
existing uses of the IOCtl system call (Subfunctions 2, 3, 4, and 5), but
new device drivers should use this generic MS-DOS IOCtl facility. The
Generic IOCtl function contains both a category and function code. The DOS
examines the category field in order to intercept and obey device commands
that are actually serviced by the DOS code; all other command categories
are forwarded to the device driver for servicing.
For more information on these category and function codes, refer to
Function 440CH (Generic IOCtl for Handles) and Function 440DH (Generic
IOCtl for Block Devices) in Chapter 1, "System Calls."
2.7.11 The Get/Set Logical Drive Map Function
Command codes = 23 (Get) or 24 (Set)
┌────────────────────────────────────────┐
│ 13-BYTE Static request header │
├────────────────────────────────────────┤
│ BYTE Input (unit code) │
├────────────────────────────────────────┤
│ BYTE Output (last device referenced)│
├────────────────────────────────────────┤
│ BYTE Command code │
├────────────────────────────────────────┤
│ WORD Status │
├────────────────────────────────────────┤
│ DWORD Reserved │
└────────────────────────────────────────┘
The Get/Set Logical Drive Map function is called by MS-DOS only if the
device driver sets the DOS 3.2 attribute bit in the device header. The
call is issued only to block devices by the subfunction of the IOCtl
system call. The logical drive to be mapped is passed in the Unit field of
the header to the device driver. The device driver returns the current
logical drive owner of the physical device that maps to the requested
physical drive. To detect whether or not a logical device currently owns
the physical device to which it is mapped, a program needs to verify that,
after a call of Function 440EH or 440FH (Get/Set Logical Drive Map), the
value of the Unit field is unchanged.
2.8 The Media Descriptor Byte
In MS-DOS, the media descriptor byte is used to inform the DOS that a
different type of media is present. The media descriptor byte can be any
value between 0 and FFH. It does not have to be the same as the FAT ID
byte. The FAT ID byte, which is the first byte of the FAT, was used in
MS-DOS 1.00 to distinguish between different types of disk media, and may
be used as well under 2.x and 3.x disk device drivers. However, FAT ID
bytes have significance only for block device drivers where the non-FAT ID
bit is not set (0).
Values of the media descriptor byte or the FAT ID byte have no
significance to MS-DOS. They are passed to the device driver so that
programs can determine the media type.
2.9 Format of a Media Descriptor Table
The MS-DOS file system uses a linked list of pointers (one for each
cluster or allocation unit) called the File Allocation Table (FAT). Unused
clusters are represented by zero and end-of-file by FFFH (or FFFFH on
units with 16-bit FAT entries). No valid entry should ever point to a zero
entry, but if one does, the first FAT entry (which would be pointed to by
a zero entry) was reserved and set to end of chain. Eventually, several
end of chain values were defined ([F]FF8H[F]FFFH), and these were used to
distinguish different types of media.
A preferable technique is to write a complete media descriptor table in
the boot sector and use it for media identification. To ensure backward
compatibility for systems whose drivers do not set the non-FAT ID bit
(including the IBM PC implementation), it is also necessary to write the
FAT ID bytes during the format process.
To allow more flexibility for supporting many different disk formats in
the future, it is recommended that the information relating to the BPB for
a particular piece of media be kept in the boot sector. Figure 2.6 shows
the format of such a boot sector.
┌────────────────────────────────────┐
│ 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 │
├────────────────────────────────────┤
│ BYTE Number of FATs │
├────────────────────────────────────┤
│ WORD Number of root dir entries │
├────────────────────────────────────┤
│ WORD Number of sectors in logical │
↑ │ | image or 0 │
├────────────────────────────────────┤
B │ BYTE Media descriptor │
P ├────────────────────────────────────┤
B │ WORD Number of FAT sectors │
├────────────────────────────────────┤
│ WORD Sectors per track │
├────────────────────────────────────┤
│ WORD Number of heads │
├────────────────────────────────────┤
│ WORD Number of hidden sectors │
├────────────────────────────────────┤
│ WORD High order number of hidden │
│ sectors │
├────────────────────────────────────┤
│ DWORD Number of logical sectors │
└────────────────────────────────────┘
Figure 2.6 Format of a Boot Sector
Although MS-DOS does not use the five fields that follow the BPB, these
fields may be used by a device driver to help it understand the media.
The "Sectors per track" and "Number of heads" fields are useful for
supporting different media that may have the same logical layout, but a
different physical layout (for example, 40-track, double-sided versus
80-track, single-sided). "Sectors per track" tells the device driver how
the logical disk format is laid out on the physical disk. The "Number of
hidden sectors" and "High order number of hidden sectors" fields may be
used to support drive-partitioning schemes.
The "Number of logical sectors" field tells the device driver how many
sectors to reserve if the "Number of sectors in logical image" field is
zero. (Notice that this is intended for supporting devices that access
more than 32 megabytes.)
The following procedure is recommended for media determination by NON FAT
ID format drivers:
1. Read the boot sector of the drive into the one-sector scratch space
pointed to by the DWORD transfer address.
2. Determine if the first byte of the boot sector is an E9H or EBIT (the
first byte of a 3-byte NEAR or 2-byte SHORT jump) or an EBH (the first
byte of a 2-byte jump followed by an NOP). If so, a BPB is located
beginning at offset 3. Return a pointer to it.
3. If the boot sector does not have a BPB table, it is probably a disk
formatted under a 1.x version of MS-DOS and probably uses a FAT ID byte
for determining media.
The driver may optionally attempt to read the first sector of the FAT
into the one-sector scratch area and read the first byte to determine
media type based upon whatever FAT ID bytes may have been used on disks
that are expected to be read by this system. Return a pointer to a
hard-coded BPB.
2.10 The CLOCK Device
MS-DOS assumes that some sort of clock is available in the system. This
may either be a CMOS real-time clock or an interval timer that is
initialized at boot time by the user. The CLOCK device defines and
performs functions like any other character device, except that it is
identified by a bit in the attribute word. The DOS uses this bit to
identify it; consequently, the CLOCK device may take any name. The IBM
implementation uses the name $CLOCK so as not to conflict with existing
files named clock.
The CLOCK device is unique in that MS-DOS will read or write a 6-byte
sequence that encodes the date and time. A write to this device will set
the date and time; a read will get the date and time. Figure 2.7
illustrates the binary time format used by the CLOCK device:
byte 0 byte 1 byte 2 byte 3 byte 4 byte 5
┌────────┬────────┬─────────┬────────┬────────┬─────────┐
│ │ │ │ │ │ │
│days since 1-1-80│ minutes │ hours │ sec/100│ seconds │
│low byte|hi byte │ │ │ │ │
└─────────────────┴─────────┴────────┴────────┴─────────┘
Figure 2.7 Format of a Clock Device
2.11 Anatomy of a Device Call
The following steps illustrate what happens when MS-DOS calls on a block
device driver to perform a Write request:
1. MS-DOS writes a request packet in a reserved area of memory.
2. MS-DOS calls the strategy entry point of the block device driver.
3. The device driver saves the ES and BX registers (ES:BX points to the
request packet) and does a FAR return.
4. MS-DOS calls the interrupt entry point.
5. The device driver retrieves the pointer to the request packet and reads
the command code (offset 2) to determine that this is a Write request.
The device driver converts the command code to an index into a dispatch
table and control passes to the Write routine.
6. The device driver reads the unit code (offset 1) to determine which
disk drive it is supposed to write to.
7. Since the command is a disk Write, the device driver must get the
transfer address (offset 14), the sector count (offset 18), and the
start sector (offset 20) in the request packet.
8. The device driver translates the first logical sector number into a
track, head, and sector number.
9. The device driver writes the specified number of sectors, starting at
the beginning sector on the drive defined by the unit code (the subunit
defined by this device driver), and transfers data from the transfer
address indicated in the request packet. Notice that this may involve
multiple Write commands to the disk controller.
10.After the transfer is complete, the device driver must report the
status of the request to MS-DOS by setting the done bit in the status
word (offset 3 in the request packet). It reports the number of sectors
actually transferred in the sector count area of the request packet.
11.If an error occurs, the driver sets the done bit and the error bit in
the status word and fills in the error code in the lower half of the
status word. The number of sectors actually transferred must be written
in the request header. It is not sufficient just to set the error bit
of the status word.
12.The device driver does a FAR return to MS-DOS.
The device drivers should preserve the state of MS-DOS. This means that
all registers (including flags) should be preserved. The direction flag
and interrupt enable bits are critical. When the interrupt entry point in
the device driver is called, MS-DOS has room for about 40 to 50 bytes on
its internal stack. Your device driver should switch to a local stack if
it uses extensive stack operations.
2.12 Two Sample Device Drivers
The following two examples illustrate a block device driver program and a
character device driver program. These examples are provided as guides for
writing your own device drivers. However, since device drivers are
hardware-dependent, your device drivers will differ.
Block Device Driver
; ********************* A Block Device *******************
Title 5.25-inch Disk Driver
; This driver is intended to drive up to four 5.25-inch
; drives hooked to a single disk controller. All standard
; IBM PC formats are supported.
FALSE EQU 0
TRUE EQU NOT FALSE
; The I/O port address of the disk controller
DISK EQU 0E0H
; DISK+0
; 1793 Command/Status
; DISK+1
; 1793 Track
; DISK+2
; 1793 Sector
; DISK+3
; 1793 Data
; DISK+4
; Aux Command/Status
; DISK+5
; Wait Sync
; Back side select bit
BACKBIT EQU 04H
; 5 1/4" select bit
SMALBIT EQU 10H
; Double Density bit
DDBIT EQU 08H
; Done bit in status register
DONEBIT EQU 01H
; Use table below to select head step speed.
; Step times for 5" drives
; are double that shown in the ; Step value 1771 1793
;
; 0 6ms 3ms
; 1 6ms 6ms
; 2 10ms 10ms
; 3 20ms 15ms
;
STPSPD EQU 1
NUMERR EQU ERROUT-ERRIN
CR EQU 0DH
LF EQU 0AH
CODE SEGMENT
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:NOTHING
; -----------------------------------------------------
;
; Device Header
;
DRVDEV LABEL WORD
DW -1,-1
DW 0000 ; IBM format-compatible, Block
DW STRATEGY
DW DRV$IN
DRVMAX DB 4
DRVTBL LABEL WORD
DW DRV$INIT
DW MEDIA$CHK
DW GET$BPB
DW CMDERR
DW DRV$READ
DW EXIT
DW EXIT
DW EXIT
DW DRV$WRIT
DW DRV$WRIT
DW EXIT
DW EXIT
DW EXIT
; ------------------------------------
;
; Strategy
PTRSAV DD 0
STRATP PROC FAR
STRATEGY:
MOV WORD PTR [PTRSAV],BX
MOV WORD PTR [PTRSAV+2],ES
RET
STRATP ENDP
; --------------------------------------
;
; Main Entry
CMDLEN = 0 ; Length of this command
UNIT = 1 ; Subunit specified
CMDC = 2 ; Command Code
STATUS = 3 ; Status
MEDIA = 13 ; Media Descriptor
TRANS = 14 ; Transfer Address
COUNT = 18 ; Count of blocks or characters
START = 20 ; First block to transfer
DRV$IN:
PUSH SI
PUSH AX
PUSH CX
PUSH DX
PUSH DI
PUSH BP
PUSH DS
PUSH ES
PUSH BX
LDS BX,[PTRSAV] ; Get pointer to I/O packet
MOV AL,BYTE PTR [BX].UNIT ; AL = Unit Code
MOV AH,BYTE PTR [BX].MEDIA ; AH = Media Descrip
MOV CX,WORD PTR [BX].COUNT ; CX = Count
MOV DX,WORD PTR [BX].START ; DX = Start Sector
PUSH AX
MOV AL,BYTE PTR [BX].CMDC ; Command code
CMP AL,15
JA CMDERRP ; Bad command
CBW
SHL AX,1 ; 2 times command =
; word table index
MOV SI,OFFSET DRVTBL
ADD SI,AX ; Index into table
POP AX ; Get back media
; and unit
LES DI,DWORD PTR [BX].TRANS ; ES:DI = Transfer
; Address
PUSH CS
POP DS
ASSUME DS:CODE
JMP WORD PTR [SI] ; GO DO COMMAND
; ----------------------------------------------------------
;
; EXIT - All Routines return through this path
;
ASSUME DS:NOTHING
CMDERRP:
POP AX ; Clean stack
CMDERR:
MOV AL,3 ; Unknown command error
JMP SHORT ERR$EXIT
ERR$CNT:LDS BX,[PTRSAV]
SUB WORD PTR [BX].COUNT,CX ; # OF SUCCESS. I/Os
ERR$EXIT:
; AL has error code
MOV AH,10000001B ; Mark error return
JMP SHORT ERR1
EXITP PROC FAR
EXIT: MOV AH,00000001B
ERR1: LDS BX,[PTRSAV]
MOV WORD PTR [BX].STATUS,AX
; Mark Operation
CompleteE
POP BX
POP ES
POP DS
POP BP
POP DI
POP DX
POP CX
POP AX
POP SI
RET ; Restore REGS and return
EXITP ENDP
CURDRV DB -1
TRKTAB DB -1,-1,-1,-1
SECCNT DW 0
DRVLIM = 8 ; Number of sectors on device
SECLIM = 13 ; Maximum Sector
HDLIM = 15 ; Maximum Head
; WARNING - preserve order of drive and curhd!
DRIVE DB 0 ; Physical Drive Code
CURHD DB 0 ; Current Head
CURSEC DB 0 ; Current Sector
CURTRK DW 0 ; Current Track
;
MEDIA$CHK: ; Always indicates Don't know
ASSUME DS:CODE
TEST AH,00000100B ; Test if Media Removable
JZ MEDIA$EXT
XOR DI,DI ; Say I Don't know
MEDIA$EXT:
LDS BX,[PTRSAV]
MOV WORD PTR [BX].TRANS,DI
JMP EXIT
BUILD$BPB:
ASSUME DS:CODE
MOV AH,BYTE PTR ES:[DI] ; Get FAT ID Byte
CALL BUILDBP ; Translate
SETBPB: LDS BX,[PTRSAV]
MOV [BX].MEDIA,AH
MOV [BX].COUNT,DI
MOV [BX].COUNT+2,CS
JMP EXIT
BUILDBP:
ASSUME DS:NOTHING
; AH is media byte on entry
; DI points to correct BPB on return
PUSH AX
PUSH CX
PUSH DX
PUSH BX
MOV CL,AH ; Save Media
AND CL,0F8H ; Normalize
CMP CL,0F8H ; Compare with Good Media Byte
JZ GOODID
MOV AH,0FEH ; Default to 8-sector,
; Single-sided
GOODID:
MOV AL,1 ; Set number of FAT sectors
MOV BX,64*256+8 ; Set Dir Entries and Sector Max
MOV CX,40*8 ; Set Size of Drive
MOV DX,01*256+1 ; Set Head Limit & Sec/All Unit
MOV DI,OFFSET DRVBPB
TEST AH,00000010B ; Test for 8 OR 9 Sectors
JNZ HAS8 ; NZ = has 8 sectors
INC AL ; Inc Number of FAT sectors
INC BL ; Inc Sector Max
ADD CX,40 ; Increase Size
HAS8: TEST AH,00000001B ; Test for 1 or 2 Heads
JZ HAS1 ; Z = 1 Head
ADD CX,CX ; Double Size of Disk
MOV BH,112 ; Increase # of Dir Entries
INC DH ; Inc Sec/All Unit
INC DL ; Inc Head Limit
HAS1: MOV BYTE PTR [DI].2,DH
MOV BYTE PTR [DI].6,BH
MOV WORD PTR [DI].8,CX
MOV BYTE PTR [DI].10,AH
MOV BYTE PTR [DI].11,AL
MOV BYTE PTR [DI].13,BL
MOV BYTE PTR [DI].15,DL
POP BX
POP DX
POP CX
POP AX
RET
; ----------------------------------------------------------
;
; Disk I/O Handlers
;
; ENTRY:
; AL = Drive Number (0-3)
; AH = Media Descriptor
; CX = Sector Count
; DX = First Sector
; DS = CS
; ES:DI = Transfer Address
; EXIT:
; IF Successful Carry Flag = 0
; ELSE CF=1 AND AL contains (MS-DOS) Error Code,
CX # sectors NOT transferred
DRV$READ:
ASSUME DS:CODE
JCXZ DSKOK
CALL SETUP
JC DSK$IO
CALL DISKRD
JMP SHORT DSK$IO
DRV$WRIT:
ASSUME DS:CODE
JCXZ DSKOK
CALL SETUP
JC DSK$IO
CALL DISKWRT
ASSUME DS:NOTHING
DSK$IO: JNC DSKOK
JMP ERR$CNT
DSKOK: JMP EXIT
SETUP:
ASSUME DS:CODE
; Input same as above
; On output
; ES:DI = Trans addr
; DS:BX Points to BPB
; Carry set if error (AL is error code (MS-DOS))
; else
; [DRIVE] = Drive number (0-3)
; [SECCNT] = Sectors to transfer
; [CURSEC] = Sector number of start of I/O
; [CURHD] = Head number of start of I/O ; Set
; [CURTRK] = Track # of start of I/O ; Seek performed
; All other registers destroyed
XCHG BX,DI ; ES:BX = Transfer Address
CALL BUILDBP ; DS:DI = PTR to B.P.B
MOV SI,CX
ADD SI,DX
CMP SI,WORD PTR [DI].DRVLIM
; Compare Against Drive Max
JBE INRANGE
MOV AL,8
STC
RET
INRANGE:
MOV [DRIVE],AL
MOV [SECCNT],CX ; Save Sector Count
XCHG AX,DX ; Set Up Logical Sector
; For Divide
XOR DX,DX
DIV WORD PTR [DI].SECLIM ; Divide by Sec per Track
INC DL
MOV [CURSEC],DL ; Save Current Sector
MOV CX,WORD PTR [DI].HDLIM ; Get Number of Heads
XOR DX,DX ; Divide Tracks by Heads per Cylinder
DIV CX
MOV [CURHD],DL ; Save Current Head
MOV [CURTRK],AX ; Save Current Track
SEEK:
PUSH BX ; Xaddr
PUSH DI ; BPB pointer
CALL CHKNEW ; Unload head if change drives
CALL DRIVESEL
MOV BL,[DRIVE]
XOR BH,BH ; BX drive index
ADD BX,OFFSET TRKTAB ; Get current track
MOV AX,[CURTRK]
MOV DL,AL ; Save desired track
XCHG AL,DS:[BX] ; Make desired track current
OUT DISK+1,AL ; Tell Controller current track
CMP AL,DL ; At correct track?
JZ SEEKRET ; Done if yes
MOV BH,2 ; Seek retry count
CMP AL,-1 ; Position Known?
JNZ NOHOME ; If not home head
TRYSK:
CALL HOME
JC SEEKERR
NOHOME:
MOV AL,DL
OUT DISK+3,AL ; Desired track
MOV AL,1CH+STPSPD ; Seek
CALL DCOM
AND AL,98H ; Accept not rdy, seek, & CRC errors
JZ SEEKRET
JS SEEKERR ; No retries if not ready
DEC BH
JNZ TRYSK
SEEKERR:
MOV BL,[DRIVE]
XOR BH,BH ; BX drive index
ADD BX,OFFSET TRKTAB ; Get current track
MOV BYTE PTR DS:[BX],-1 ; Make current track
; unknown
CALL GETERRCD
MOV CX,[SECCNT] ; Nothing transferred
POP BX ; BPB pointer
POP DI ; Xaddr
RET
SEEKRET:
POP BX ; BPB pointer
POP DI ; Xaddr
CLC
RET
; ---------------------------------------------
;
; Read
;
DISKRD:
ASSUME DS:CODE
MOV CX,[SECCNT]
RDLP:
CALL PRESET
PUSH BX
MOV BL,10 ; Retry count
MOV DX,DISK+3 ; Data port
RDAGN:
MOV AL,80H ; Read command
CLI ; Disable for 1793
OUT DISK,AL ; Output read command
MOV BP,DI ; Save address for retry
JMP SHORT RLOOPENTRY
RLOOP:
STOSB
RLOOPENTRY:
IN AL,DISK+5 ; Wait for DRQ or INTRQ
SHR AL,1
IN AL,DX ; Read data
JNC RLOOP
STI ; Ints OK now
CALL GETSTAT
AND AL,9CH
JZ RDPOP ; Ok
MOV DI,BP ; Get back transfer
DEC BL
JNZ RDAGN
CMP AL,10H ; Record not found?
JNZ GOT_CODE ; No
MOV AL,1 ; Map it
GOT_CODE:
CALL GETERRCD
POP BX
RET
RDPOP:
POP BX
LOOP RDLP
CLC
RET
; ---------------------------------------------
;
; Write
;
DISKWRT:
ASSUME DS:CODE
MOV CX,[SECCNT]
MOV SI,DI
PUSH ES
POP DS
ASSUME DS:NOTHING
WRLP:
CALL PRESET
PUSH BX
MOV BL,10 ; Retry count
MOV DX,DISK+3 ; Data port
WRAGN:
MOV AL,0A0H ; Write command
CLI ; Disable for 1793
OUT DISK,AL ; Output write command
MOV BP,SI ; Save address for retry
WRLOOP:
IN AL,DISK+5
SHR AL,1
LODSB ; Get data
OUT DX,AL ; Write data
JNC WRLOOP
STI ; Ints OK now
DEC SI
CALL GETSTAT
AND AL,0FCH
JZ WRPOP ; Ok
MOV SI,BP ; Get back transfer
DEC BL
JNZ WRAGN
CALL GETERRCD
POP BX
RET
WRPOP:
POP BX
LOOP WRLP
CLC
RET
PRESET:
ASSUME DS:NOTHING
MOV AL,[CURSEC]
CMP AL,CS:[BX].SECLIM
JBE GOTSEC
MOV DH,[CURHD]
INC DH
CMP DH,CS:[BX].HDLIM
JB SETHEAD ; Select new head
CALL STEP ; Go on to next track
XOR DH,DH ; Select head zero
SETHEAD:
MOV [CURHD],DH
CALL DRIVESEL
MOV AL,1 ; First sector
MOV [CURSEC],AL ; Reset CURSEC
GOTSEC:
OUT DISK+2,AL ; Tell controller which sector
INC [CURSEC] ; We go on to next sector
RET
STEP:
ASSUME DS:NOTHING
MOV AL,58H+STPSPD ; Step in w/ update, no verify
CALL DCOM
PUSH BX
MOV BL,[DRIVE]
XOR BH,BH ; BX drive index
ADD BX,OFFSET TRKTAB ; Get current track
INC BYTE PTR CS:[BX] ; Next track
POP BX
RET
HOME:
ASSUME DS:NOTHING
MOV BL,3
TRYHOM:
MOV AL,0CH+STPSPD ; Restore with verify
CALL DCOM
AND AL,98H
JZ RET3
JS HOMERR ; No retries if not ready
PUSH AX ; Save real error code
MOV AL,58H+STPSPD ; Step in w/ update no verify
CALL DCOM
DEC BL
POP AX ; Get back real error code
JNZ TRYHOM
HOMERR:
STC
RET3: RET
CHKNEW:
ASSUME DS:NOTHING
MOV AL,[DRIVE] ; Get disk drive number
MOV AH,AL
XCHG AL,[CURDRV] ; Make new drive current.
CMP AL,AH ; Changing drives?
JZ RET1 ; No
; If changing drives, unload head so the head load delay
; one-shot will fire again. Do it by seeking to the same
; track with the H bit reset.
;
IN AL,DISK+1 ; Get current track number
OUT DISK+3,AL ; Make it the track to seek
MOV AL,10H ; Seek and unload head
DCOM:
ASSUME DS:NOTHING
OUT DISK,AL
PUSH AX
AAM ; Delay 10 microseconds
POP AX
GETSTAT:
IN AL,DISK+4
TEST AL,DONEBIT
JZ GETSTAT
IN AL,DISK
RET1: RET
DRIVESEL:
ASSUME DS:NOTHING
; Select the drive based on current info
; Only AL altered
MOV AL,[DRIVE]
OR AL,SMALBIT + DDBIT ; 5 1/4" IBM PC disks
CMP [CURHD],0
JZ GOTHEAD
OR AL,BACKBIT ; Select side 1
GOTHEAD:
OUT DISK+4,AL ; Select drive and side
RET
GETERRCD:
ASSUME DS:NOTHING
PUSH CX
PUSH ES
PUSH DI
PUSH CS
POP ES ; Make ES the local segment
MOV CS:[LSTERR],AL ; Terminate list w/ error code
MOV CX,NUMERR ; Number of error conditions
MOV DI,OFFSET ERRIN ; Point to error conditions
REPNE SCASB
MOV AL,NUMERR-1[DI] ; Get translation
STC ; Flag error condition
POP DI
POP ES
POP CX
RET ; and return
; *********************************************************
; BPB for an IBM floppy disk, Various parameters are
; patched by BUILDBP to reflect the type of Media
; inserted
; This is a 9-sector, single-side BPB
DRVBPB:
DW 512 ; Physical sector size in bytes
DB 1 ; Sectors/allocation unit
DW 1 ; Reserved sectors for DOS
DB 2 ; # of allocation tables
DW 64 ; Number directory entries
DW 9*40 ; Number 512-byte sectors
DB 11111100B ; Media descriptor
DW 2 ; Number of FAT sectors
DW 9 ; Sector limit
DW 1 ; Head limit
INITAB DW DRVBPB ; Up to four units
DW DRVBPB
DW DRVBPB
DW DRVBPB
ERRIN: ; DISK ERRORS RETURNED FROM THE CONTROLLER
DB 80H ; No response
DB 40H ; Write protect
DB 20H ; Write Fault
DB 10H ; SEEK error
DB 8 ; CRC error
DB 1 ; Mapped from 10H
; (record not found) on Read
LSTERR DB 0 ; All other errors
ERROUT: ; RETURNED ERROR CODES CORRESPONDING TO ABOVE
DB 2 ; No response
DB 0 ; Write Attempt
; On Write-protected disk
DB 0AH ; Write fault
DB 6 ; SEEK Failure
DB 4 ; Bad CRC
DB 8 ; Sector not found
DB 12 ; General error
DRV$INIT:
;
; Determine number of physical drives by reading config.sys
;
ASSUME DS:CODE
PUSH DS
LDS SI,[PTRSAV]
ASSUME DS:NOTHING
LDS SI,DWORD PTR [SI.COUNT] ; DS:SI points to
; config.sys
SCAN_LOOP:
CALL SCAN_SWITCH
MOV AL,CL
OR AL,AL
JZ SCAN4
CMP AL,"s"
JZ SCAN4
WERROR: POP DS
ASSUME DS:CODE
MOV DX,OFFSET ERRMSG2
WERROR2: MOV AH,9
INT 21H
XOR AX,AX
PUSH AX ; No units
JMP SHORT ABORT
BADNDRV:
POP DS
MOV DX,OFFSET ERRMSG1
JMP WERROR2
SCAN4:
ASSUME DS:NOTHING
; BX is number of floppies
OR BX,BX
JZ BADNDRV ; User error
CMP BX,4
JA BADNDRV ; User error
POP DS
ASSUME DS:CODE
PUSH BX ; Save unit count
ABORT: LDS BX,[PTRSAV]
ASSUME DS:NOTHING
POP AX
MOV BYTE PTR [BX].MEDIA,AL ; Unit count
MOV [DRVMAX],AL
MOV WORD PTR [BX].TRANS,OFFSET DRV$INIT ; SET
; BREAK ADDRESS
MOV [BX].TRANS+2,CS
MOV WORD PTR [BX].COUNT,OFFSET INITAB
; SET POINTER TO BPB ARRAY
MOV [BX].ceOUNT+2,CS
JMP EXIT
;
; Put switch in CL, value in BX
;
SCAN_SWITCH:
XOR BX,BX
MOV CX,BX
LODSB
CMP AL,10
JZ NUMRET
CMP AL,"-"
JZ GOT_SWITCH
CMP AL,"/"
JNZ SCAN_SWITCH
GOT_SWITCH:
CMP BYTE PTR [SI+1],":"
JNZ TERROR
LODSB
OR AL,20H ; Convert to lowercase
MOV CL,AL ; Get switch
LODSB ; Skip ":"
;
; Get number pointed to by [SI]
;
; Wipes out AX,DX only BX returns number
;
GETNUM1:LODSB
SUB AL,"0"
JB CHKRET
CMP AL,9
JA CHKRET
CBW
XCHG AX,BX
MOV DX,10
MUL DX
ADD BX,AX
JMP GETNUM1
CHKRET: ADD AL,"0"
CMP AL," "
JBE NUMRET
CMP AL,"-"
JZ NUMRET
CMP AL,"/"
JZ NUMRET
TERROR:
POP DS ; Get rid of return address
JMP WERROR
NUMRET: DEC SI
RET
ERRMSG1 DB "SMLDRV: Bad number of drives",13,10,"$"
ERRMSG2 DB "SMLDRV: Invalid parameter",13,10,"$"
CODE ENDS
END
Character Device Driver
The following program illustrates a character device driver program.
; ******************** A Character Device *******************
Title VT52 Console for 2.0 (IBM)
; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; IBM Addresses for I/O
;
; ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
CR=13 ; Carriage-Return
BACKSP=8 ; BACKSPACE
ESC=1BH
BRKADR=6CH ; 006C Break vector address
ASNMAX=200 ; Size of key assignment buffer
CODE SEGMENT BYTE
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
; ----------------------------------------------------------
;
; C O N - Console Device Driver
;
CONDEV: ; Header for device "CON"
DW -1,-1
DW 1000000000010011B ; CON IN AND CON OUT
DW STRATEGY
DW ENTRY
DB 'CON '
; -----------------------------------------------------------
;
; Command JUMP Tables
CONTBL:
DW CON$INIT
DW EXIT
DW EXIT
DW CMDERR
DW CON$READ
DW CON$RDND
DW EXIT
DW CON$FLSH
DW CON$WRIT
DW CON$WRIT
DW EXIT
DW EXIT
CMDTABL DB 'A'
DW CUU ; cursor up
DB 'B'
DW CUD ; cursor down
DB 'C'
DW CUF ; cursor forward
DB 'D'
DW CUB ; cursor back
DB 'H'
DW CUH ; cursor position
DB 'J'
DW ED ; erase display
DB 'K'
DW EL ; erase line
DB 'Y'
DW CUP ; cursor position
DB 'j'
DW PSCP ; save cursor position
DB 'k'
DW PRCP ; restore cursor position
DB 'y'
DW RM ; reset mode
DB 'x'
DW SM ; set mode
DB 00
PAGE
; ---------------------------------------------------
;
; Device entry point
;
CMDLEN = 0 ; Length of this command
UNIT = 1 ; Subunit Specified
CMD = 2 ; Command Code
STATUS = 3 ; Status
MEDIA = 13 ; Media Descriptor
TRANS = 14 ; Transfer Address
COUNT = 18 ; Count of blocks or characters
START = 20 ; First block to transfer
PTRSAV DD 0
STRATP PROC FAR
STRATEGY:
MOV WORD PTR CS:[PTRSAV],BX
MOV WORD PTR CS:[PTRSAV+2],ES
RET
STRATP ENDP
ENTRY:
PUSH SI
PUSH AX
PUSH CX
PUSH DX
PUSH DI
PUSH BP
PUSH DS
PUSH ES
PUSH BX
LDS BX,CS:[PTRSAV] ; GET POINTER TO I/O PACKET
MOV CX,WORD PTR DS:[BX].COUNT ; CX = COUNT
MOV AL,BYTE PTR DS:[BX].CMD
CBW
MOV SI,OFFSET CONTBL
ADD SI,AX
ADD SI,AX
CMP AL,11
JA CMDERR
LES DI,DWORD PTR DS:[BX].TRANS
PUSH CS
POP DS
ASSUME DS:CODE
JMP WORD PTR [SI] ; GO DO COMMAND
PAGE
; =====================================================
; =
; = Subroutines Shared by Multiple Devices
; =
; =====================================================
; -----------------------------------------------------
;
; EXIT - All routines return through this path
;
BUS$EXIT: ; Device Busy Exit
MOV AH,00000011B
JMP SHORT ERR1
CMDERR:
MOV AL,3 ; Unknown command error
ERR$EXIT:
MOV AH,10000001B ; Mark error Return
JMP SHORT ERR1
EXITP PROC FAR
EXIT: MOV AH,00000001B
ERR1: LDS BX,CS:[PTRSAV]
MOV WORD PTR [BX].STATUS,AX ; Mark
; Operation Complete
POP BX
POP ES
POP DS
POP BP
POP DI
POP DX
POP CX
POP AX
POP SI
RET ; Restore REGS and Return
EXITP ENDP
; -----------------------------------------------
;
; BREAK Key Handling
;
BREAK:
MOV CS:ALTAH,3 ; Indicate BREAK key Set
INTRET: IRET
PAGE
;
; WARNING - Variables are very order dependent,
so be careful when adding new ones!
;
WRAP DB 0 ; 0 = WRAP, 1 = NO WRAP
STATE DW S1
MODE DB 3
MAXCOL DB 79
COL DB 0
ROW DB 0
SAVCR DW 0
ALTAH DB 0 ; Special key handling
; -------------------------------------------------------
;
; CHROUT - Write out Char in AL using current attribute
;
ATTRW LABEL WORD
ATTR DB 00000111B ; Character Attribute
BPAGE DB 0 ; Base Page
base dw 0b800h
chrout: cmp al,13
jnz trylf
mov [col],0
jmp short setit
trylf: cmp al,10
jz lf
cmp al,7
jnz tryback
torom:
mov bx,[attrw]
and bl,7
mov ah,14
int 10h
ret5: ret
tryback:
cmp al,8
jnz outchr
cmp [col],0
jz ret5
dec [col]
jmp short setit
outchr:
mov bx,[attrw]
mov cx,1
mov ah,9
int 10h
inc [col]
mov al,[col]
cmp al,[maxcol]
jbe setit
cmp [wrap],0
jz outchr1
dec [col]
ret
outchr1:
mov [col],0
lf: inc [row]
cmp [row],24
jb setit
mov [row],23
call scroll
setit: mov dh,row
mov dl,col
xor bh,bh
mov ah,2
int 10h
ret
scroll: call getmod
cmp al,2
jz myscroll
cmp al,3
jz myscroll
mov al,10
jmp torom
myscroll:
mov bh,[attr]
mov bl,' '
mov bp,80
mov ax,[base]
mov es,ax
mov ds,ax
xor di,di
mov si,160
mov cx,23*80
cld
cmp ax,0b800h
jz colorcard
rep movsw
mov ax,bx
mov cx,bp
rep stosw
sret: push cs
pop ds
ret
colorcard:
mov dx,3dah
wait2: in al,dx
test al,8
jz wait2
mov al,25h
mov dx,3d8h
out dx,al ; turn off video
rep movsw
mov ax,bx
mov cx,bp
rep stosw
mov al,29h
mov dx,3d8h
out dx,al ; turn on video
jmp sret
GETMOD: MOV AH,15
INT 16 ; get column information
MOV BPAGE,BH
DEC AH
MOV WORD PTR MODE,AX
RET
; ------------------------------------------------------
;
; Console Read Routine
;
CON$READ:
JCXZ CON$EXIT
CON$LOOP:
PUSH CX ; Save Count
CALL CHRIN ; Get Char in AL
POP CX
STOSB ; Store Char at ES:DI
LOOP CON$LOOP
CON$EXIT:
JMP EXIT
; ---------------------------------------------------------
;
; Input Single Char into AL
;
CHRIN: XOR AX,AX
XCHG AL,ALTAH ; Get Character & Zero ALTAH
OR AL,AL
JNZ KEYRET
INAGN: XOR AH,AH
INT 22
ALT10:
OR AX,AX ; Check for non-key after BREAK
JZ INAGN
OR AL,AL ; Special case?
JNZ KEYRET
MOV ALTAH,AH ; Store special key
KEYRET: RET
; ----------------------------------------------------------
;
; Keyboard Non-destructive Read, No Wait
;
CON$RDND:
MOV AL,[ALTAH]
OR AL,AL
JNZ RDEXIT
RD1: MOV AH,1
INT 22
JZ CONBUS
OR AX,AX
JNZ RDEXIT
MOV AH,0
INT 22
JMP CON$RDND
RDEXIT: LDS BX,[PTRSAV]
MOV [BX].MEDIA,AL
EXVEC: JMP EXIT
CONBUS: JMP BUS$EXIT
; ----------------------------------------------------------
;
; Keyboard Flush Routine
;
CON$FLSH:
MOV [ALTAH],0 ; Clear out holding buffer
PUSH DS
XOR BP,BP
MOV DS,BP ; Select segment 0
MOV DS:BYTE PTR 41AH,1EH ; Reset KB queue head
; pointer
MOV DS:BYTE PTR 41CH,1EH ; Reset tail pointer
POP DS
JMP EXVEC
; ----------------------------------------------------------
;
; Console Write Routine
;
CON$WRIT:
JCXZ EXVEC
PUSH CX
MOV AH,3 ; Set current cursor position
XOR BX,BX
INT 16
MOV WORD PTR [COL],DX
POP CX
CON$LP: MOV AL,ES:[DI] ; Get Char
INC DI
CALL OUTC ; Output Char
LOOP CON$LP ; Repeat until all through
JMP EXVEC
COUT: STI
PUSH DS
PUSH CS
POP DS
CALL OUTC
POP DS
IRET
OUTC: PUSH AX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH ES
PUSH BP
CALL VIDEO
POP BP
POP ES
POP DI
POP SI
POP DX
POP CX
POP AX
RET
; ----------------------------------------------------------
;
; Output Single Char in AL to Video Device
;
VIDEO: MOV SI,OFFSET STATE
JMP [SI]
S1: CMP AL,ESC ; Escape sequence?
JNZ S1B
MOV WORD PTR [SI],OFFSET S2
RET
S1B: CALL CHROUT
S1A: MOV WORD PTR [STATE],OFFSET S1
RET
S2: PUSH AX
CALL GETMOD
POP AX
MOV BX,OFFSET CMDTABL-3
S7A: ADD BX,3
CMP BYTE PTR [BX],0
JZ S1A
CMP BYTE PTR [BX],AL
JNZ S7A
JMP WORD PTR [BX+1]
MOVCUR: CMP BYTE PTR [BX],AH
JZ SETCUR
ADD BYTE PTR [BX],AL
SETCUR: MOV DX,WORD PTR COL
XOR BX,BX
MOV AH,2
INT 16
JMP S1A
CUP: MOV WORD PTR [SI],OFFSET CUP1
RET
CUP1: SUB AL,32
MOV BYTE PTR [ROW],AL
MOV WORD PTR [SI],OFFSET CUP2
RET
CUP2: SUB AL,32
MOV BYTE PTR [COL],AL
JMP SETCUR
SM: MOV WORD PTR [SI],OFFSET S1A
RET
CUH: MOV WORD PTR COL,0
JMP SETCUR
CUF: MOV AH,MAXCOL
MOV AL,1
CUF1: MOV BX,OFFSET COL
JMP MOVCUR
CUB: MOV AX,00FFH
JMP CUF1
CUU: MOV AX,00FFH
CUU1: MOV BX,OFFSET ROW
JMP MOVCUR
CUD: MOV AX,23*256+1
JMP CUU1
PSCP: MOV AX,WORD PTR COL
MOV SAVCR,AX
JMP SETCUR
PRCP: MOV AX,SAVCR
MOV WORD PTR COL,AX
JMP SETCUR
ED: CMP BYTE PTR [ROW],24
JAE EL1
MOV CX,WORD PTR COL
MOV DH,24
JMP ERASE
EL1: MOV BYTE PTR [COL],0
EL: MOV CX,WORD PTR [COL]
EL2: MOV DH,CH
ERASE: MOV DL,MAXCOL
MOV BH,ATTR
MOV AX,0600H
INT 16
ED3: JMP SETCUR
RM: MOV WORD PTR [SI],OFFSET RM1
RET
RM1: XOR CX,CX
MOV CH,24
JMP EL2
CON$INIT:
int 11h
and al,00110000b
cmp al,00110000b
jnz iscolor
mov [base],0b000h ; look for bw card
iscolor:
cmp al,00010000b ; look for 40 col mode
ja setbrk
mov [mode],0
mov [maxcol],39
setbrk:
XOR BX,BX
MOV DS,BX
MOV BX,BRKADR
MOV WORD PTR [BX],OFFSET BREAK
MOV WORD PTR [BX+2],CS
MOV BX,29H*4
MOV WORD PTR [BX],OFFSET COUT
MOV WORD PTR [BX+2],CS
LDS BX,CS:[PTRSAV]
MOV WORD PTR [BX].TRANS,OFFSET CON$INIT
; SET BREAK ADDRESS
MOV [BX].TRANS+2,CS
JMP EXIT
CODE ENDS
END
────────────────────────────────────────────────────────────────────────────
Chapter 3 MS-DOS Technical Information
3.1 Introduction
3.2 MS-DOS Initialization
3.3 The Command Processor
3.4 MS-DOS Disk Allocation
3.5 MS-DOS Disk Directory
3.6 File Allocation Table (FAT)
3.6.1 How to Use the FAT (12-Bit FAT Entries)
3.6.2 How to Use the FAT (16-Bit FAT Entries)
3.7 MS-DOS Standard Disk Formats
3.1 Introduction
This chapter describes how MS-DOS initializes and how it allocates disk
space for the root directory, the File Allocation Tables (FAT), and the
data area. For programmers writing installable device drivers, this
chapter explains MS-DOS disk directory entries and File Allocation Tables.
At the end of the chapter, Tables 3.1 and 3.2 describe MS-DOS standard
formats for floppy disks.
3.2 MS-DOS Initialization
MS-DOS initialization consists of several steps. When you reset your
computer or turn on its power, the ROM (Read Only Memory) BIOS is invoked
and performs hardware checks and initialization. The ROM BIOS then
examines drive A for the boot sector. If it locates a boot sector, the ROM
BIOS reads it into low memory and gives it control. If it doesn't find the
boot sector, the ROM BIOS then looks in the active partition of the hard
disk. If it still doesn't find the boot sector, then the ROM BIOS invokes
ROM BASIC.
On a removable disk (3.5-inch, 5.25-inch, or 8-inch disk), the boot sector
is always located on track 0, sector 1, side 0 of the disk. On a hard
disk, the boot sector begins on the first sector of the MS-DOS partition.
The hard disk boot sector also includes a partition table. This table
identifies the active MS-DOS partition and any other partitions, such as
an extended MS-DOS partition, on the hard disk. Notice that extended
MS-DOS partitions are not bootable.
The boot sector then reads the following files, in the order listed:
io.sys
msdos.sys
──────────────────────────────────────────────────────────────────────────
Note
Versions of MS-DOS prior to 3.3 required the io.sys file to be
contiguous. This is no longer a requirement.
──────────────────────────────────────────────────────────────────────────
Next, the system initialization routine SYSINIT loads all of the resident
device drivers. Then, it searches for a config.sys file on the boot disk.
SYSINIT allocates memory for buffers and files, based on settings in the
config.sys file or system default settings. If the config.sys file
specifies any installable device drivers, these are installed next.
Finally, SYSINIT executes the MS-DOS command processor, command.com.
3.3 The Command Processor
The command processor command.com consists of three parts:
■ A resident part resides in memory immediately following msdos.sys and
its data area. This part contains routines to process Interrupts 22H
(Terminate Process Exit Address), 23H (CONTROL+C Exit Address), and 24H
(Critical-Error-Handler Address), as well as a routine to reload the
transient part, if needed. All standard MS-DOS error handling is done
within this part of command.com. This includes displaying error
messages and processing the Abort, Retry, Fail, or Ignore messages.
■ An initialization part follows the resident part. During startup, the
initialization part is given control; it contains the processor setup
routine in the autoexec.bat file. The initialization part determines
the segment address at which programs can be loaded, and because it is
no longer needed, is overlaid by the first program that command.com
loads.
■ A transient part is loaded at the high end of memory. This part
contains all the internal command processors and the batch file
processor.
The transient part of the command processor produces the system prompt
(A>, for example), reads commands from the keyboard (or from batch
files), and causes them to be executed. For external commands, the
transient part builds a command line and issues Function 4B00H (Load
and Execute Program) to load and transfer control to the program.
3.4 MS-DOS Disk Allocation
The area on a disk partitioned for use by MS-DOS is formatted as follows:
1. Reserved area──variable size
2. First copy of File Allocation Table──variable size
3. Additional copies of File Allocation Table──variable size (optional)
4. Root directory──variable size
5. File data area
Space for a file in the data area is not preallocated. The space is
allocated one cluster at a time. A cluster consists of one or more
consecutive sectors (the number of sectors in a cluster must be a power of
2); the cluster size is determined at format time. All the clusters for a
file are "chained" together in the File Allocation Table, discussed in
greater detail in Section 3.6, "File Allocation Table (FAT)." MS-DOS
normally keeps a second copy of the FAT for consistency, except in the
case of reliable storage such as a virtual RAM disk. Should the disk
develop a bad sector in the middle of the first FAT, MS-DOS can use the
second. This avoids loss of data due to an unreadable FAT.
3.5 MS-DOS Disk Directory
The format utility builds the root directory for all disks. This
directory's location on the disk and the maximum number of entries are
dependent on the media. Specifications for standard removable-disk formats
are outlined later in this chapter. Notice, however, that MS-DOS regards
directories, other than the root directory, as files, so there is no limit
to the number of files that the subdirectories under the root directory
may contain. All directory entries are 32 bytes in length and are in the
following format (notice that byte offsets are in hexadecimal):
Byte Function
──────────────────────────────────────────────────────────────────────────
0-7 Filename. Eight characters, left-aligned and padded, if
necessary, with blanks. The first byte of this field
indicates the file status as follows:
╓┌─┌──────────────────┌─────────────────┌────────────────────────────────────╖
Byte Status
──────────────────────────────────────────────────────────────────────────
00H The directory entry has never been
used. This is used to limit the
length of directory searches, for
performance reasons.
05H The first character of the filename
contains an E5H character.
2EH The entry is for a directory. If the
second byte is also 2EH, the cluster
field contains the cluster number of
this directory's parent directory
(0000H if the parent directory is the
root directory). Otherwise, bytes 01H
Byte Status
──────────────────────────────────────────────────────────────────────────
root directory). Otherwise, bytes 01H
through 0AH are all spaces, and the
cluster field contains the cluster
number of this directory.
E5H The file was used, but it has since
been erased.
Any other character is the first character of a
filename.
8-0A Filename extension.
0B File attribute. The attribute byte is mapped as follows
──────────────────────────────────────────────────────────────────────────
╓┌─┌──────────────────┌─────────────────┌────────────────────────────────────╖
Byte Contents
──────────────────────────────────────────────────────────────────────────
Byte Contents
──────────────────────────────────────────────────────────────────────────
01H File is marked read-only. An attempt
to open the file for writing using
Function 3DH (Open Handle) results
in an error code being returned. This
value can be used in programs along
with the other attributes in this
list. Attempts to delete the file
with Function 13H (Delete File) or
Function 41H (Delete Directory
Entry) will also fail.
02H Hidden file. The file is excluded
from normal directory searches.
04H System file. The file is excluded
from normal directory searches.
08H The entry contains the volume label
in the first 11 bytes. The entry
contains no other usable information
Byte Contents
──────────────────────────────────────────────────────────────────────────
contains no other usable information
(except date and time of creation)
and may exist only in the root
directory.
10H The entry defines a subdirectory and
is excluded from normal directory
searches.
20H Archive bit. The bit is set to "on"
whenever the file has been written to
and closed.
Note: The system files (io.sys and
msdos.sys) are marked as read-only,
hidden, and system files. Files can
be marked hidden when they are
created. Also, you may change the
read-only, hidden, system, and
Byte Contents
──────────────────────────────────────────────────────────────────────────
read-only, hidden, system, and
archive attributes through Function
43H (Get/Set File Attributes).
──────────────────────────────────────────────────────────────────────────
╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
Byte Function
──────────────────────────────────────────────────────────────────────────
0C-15 Reserved.
16-17 Time the file was created or last updated. The hour,
minutes, and seconds are mapped into two bytes as
follows (bit 7 on the left, 0 on the right):
Offset 17H
| H | H | H | H | H | M | M | M |
Offset 16H
Byte Function
──────────────────────────────────────────────────────────────────────────
Offset 16H
| M | M | M | S | S | S | S | S |
where:
H is the binary number of hours (0-23).
M is the binary number of minutes (0-59).
S is the binary number of two-second increments.
18-19 Date the file was created or last updated. The year,
month, and day are mapped into two bytes as follows:
Offset 19H
| Y | Y | Y | Y | Y | Y | Y | M |
Offset 18H
| M | M | M | D | D | D | D | D |
Byte Function
──────────────────────────────────────────────────────────────────────────
| M | M | M | D | D | D | D | D |
where:
Y is the year, 0-119 (1980-2099).
M is the month (1-12).
D is the day of the month (1-31).
──────────────────────────────────────────────────────────────────────────
Byte Function
──────────────────────────────────────────────────────────────────────────
1A-1B Starting cluster; the number of the first cluster in
the file.
■ Notice that the first cluster for data space on all
disks is cluster 002.
■ The cluster number is stored with the least
significant byte first.
■ For details about converting cluster numbers to
logical sector numbers, see Sections 3.6.1 and 3.6.2.
1C-1F File size in bytes. The first word of this four-byte
──────────────────────────────────────────────────────────────────────────
3.6 File Allocation Table (FAT)
This section explains how MS-DOS allocates disk space in the data area for
a file by using the File Allocation Table to convert the clusters of a
file to logical sector numbers. The device driver is then responsible for
locating the logical sector on the disk. Programs should use the MS-DOS
file management function calls for accessing files. Programs that access
the FAT are not guaranteed to be upwardly-compatible with future releases
of MS-DOS. The following information is useful to system programmers who
wish to write installable device drivers.
The File Allocation Table is an array of 12-bit entries (1.5 bytes) for
each cluster on the disk. For disks containing more than 4085 clusters, a
16-bit FAT entry is used.
The first two FAT entries are reserved; however, the device driver may use
the first byte as a FAT ID byte for determining media. For hard disks, the
value of this byte is F8H. See Tables 3.1 and 3.2 for the media byte
descriptors used for 8-inch, 5.25-inch, and 3.5-inch disks.
The third FAT entry, which starts at byte offset 4, begins the mapping of
the data area (cluster 002). The operating system does not always
sequentially write (to the disk) files in the data area. Instead, the
system allocates the data area one cluster at a time, skipping over
clusters it has already allocated. The first free cluster following the
last cluster allocated for that file is the next cluster allocated,
regardless of its physical location on the disk. This permits the most
efficient use of disk space, since if you erase old files, you can free
clusters, which the operating system can then allocate for new files. Each
FAT entry contains three or four hexadecimal characters, depending on
whether it is a 12-bit or 16-bit entry:
Entry Contents
──────────────────────────────────────────────────────────────────────────
(0)000 If the cluster is unused and available.
(F)FF7 The cluster has a bad sector in it if it is not part of
any cluster chain. MS-DOS will not allocate such a
cluster. So for its report, the chkdsk command counts
the number of bad clusters, which are not part of any
allocation chain.
(F)FF8-FFF The last cluster of a file.
(X)XXX Any other characters that are the cluster number of the
next cluster in the file. The number of the first
──────────────────────────────────────────────────────────────────────────
The File Allocation Table always begins on the first sector after the
reserved sectors. If the FAT is larger than one sector, the sectors are
contiguous. The operating system usually writes two copies of the FAT to
preserve data integrity. MS-DOS reads the FAT into one of its buffers,
whenever needed (open, read, write, etc.). The operating system also gives
this buffer a high priority to keep it in memory as long as possible.
3.6.1 How to Use the FAT (12-Bit FAT Entries)
To get the starting cluster of a file, examine its directory entry (in the
FAT). Then, to locate each subsequent cluster of the file, follow these
steps:
1. Multiply the cluster number just used by 1.5 (each FAT entry is 1.5
bytes in length).
2. The whole part of the product is an offset into the FAT, pointing to
the entry that maps the cluster just used. That entry contains the
cluster number of the next cluster of the file.
3. Use a MOV instruction to move the word at the calculated FAT offset
into a register.
4. If the last cluster used was an even number, keep the low-order 12 bits
of the register by using the AND operator with 0FFFH and the register.
If the last cluster used was an odd number, keep the high-order 12 bits
by using the SHR instruction to shift the register right four bits.
5. If the resultant 12 bits are 0FF8H-0FFFH, the file contains no more
clusters. Otherwise, the 12 bits contain the number of the next cluster
in the file.
To convert the cluster to a logical sector number (relative sector, such
as that used by Interrupts 25H and 26H (Absolute Disk Read/Write) and by
debug), follow these steps:
1. Subtract two from the cluster number.
2. Multiply the result by the number of sectors per cluster.
3. To this result, add the logical sector number of the beginning of the
data area.
3.6.2 How to Use the FAT (16-Bit FAT Entries)
To get the starting cluster of a file, examine its directory entry (in the
FAT). Then, to find the next file cluster, follow these steps:
1. Multiply the cluster number last used by 2 (each FAT entry is 2 bytes).
2. Use a MOV WORD instruction to move the word at the calculated FAT
offset into a register.
3. If the resultant 16 bits are 0FFF8-0FFFH, no more clusters are in the
file. Otherwise, the 16 bits contain the number of the next cluster in
the file.
3.7 MS-DOS Standard Disk Formats
MS-DOS arranges data clusters on a disk to minimize head movement. MS-DOS
then allocates all the space on one track (or cylinder) before moving to
the next. It uses the sequential sectors on the lowest-numbered head, then
all the sectors on the next head, and so on, until it has used all the
sectors on all the heads of the track.
The size of the MS-DOS partition on a hard disk determines the size of the
FAT and root directory. Likewise, the type of floppy disk (tracks per
side, sectors per track, etc.) determines how MS-DOS uses the disk. The
removable disk formats listed in Tables 3.1 and 3.2 are standard and
should be readable in the appropriate standard drive.
Table 3.1
MS-DOS Standard Removable-Disk Formats
Disk Size in inches 5.25 8
──────────────────────────────────────────────────────────────────────────
WORD no. heads 1 1 2 2 1 2 1
Tracks/side 40 40 40 40 77 77 77
WORD sectors/track 8 9 8 9 26 26 8
WORD bytes/sector 512 512 512 512 128 128 024
BYTE sectors/ cluster 1 1 2 2 4 4 1
WORD reserved sectors 1 1 1 1 1 4 1
Byte no. FATs 2 2 2 2 2 2 2
WORD root directory entries 64 64 112 112 68 68 192
WORD no. sectors 320 360 640 720 2002 2002 616
BYTE media descriptor FE FC FF FD FE☼ FD FE☼
WORD sectors/FAT 1 2 1 2 6 6 2
WORD no. hidden sectors 0 0 0 0 0 0 0
──────────────────────────────────────────────────────────────────────────
Table 3.2
MS-DOS Standard Removable-Disk Formats (High-Density)
Disk Size in inches 3.5 or 5.25 3.5 5.25
──────────────────────────────────────────────────────────────────────────
WORD no. heads 1 2 2 2 2 2
──────────────────────────────────────────────────────────────────────────
Tracks/side 80 80 80 80 80 80
WORD sectors/track 8 9 8 9 18 15
WORD bytes/sector 512 512 512 512 512 512
BYTE sectors/cluster 2 2 2 2 1 1
WORD reserved sectors 1 1 1 1 1 1
BYTE no. FATs 2 2 2 2 2 2
WORD root dir entries 112 112 112 112 224 224
WORD no. sectors 640 720 1280 1440 2880 2400
BYTE media descriptor☼ FA FC FB F9 F0 F9
WORD sectors/FAT 1 2 2 3 9 7
WORD no. hidden sectors 0 0 0 0 0 0
──────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────
Chapter 4 MS-DOS Control Blocks and Work Areas
4.1 Introduction
4.2 Typical Contents of an MS-DOS Memory Map
4.3 The MS-DOS Program Segment
4.1 Introduction
This chapter describes a typical MS-DOS memory map and explains how a
program is loaded into memory. It also describes the structure of an
MS-DOS program segment and the contents of segment registers for .exe and
.com program files.
4.2 Typical Contents of an MS-DOS Memory Map
A typical MS-DOS memory map contains the following information:
┌─────────────────────────────────────────────────────┐
│ ROM and Video Buffers │
├─────────────────────────────────────────────────────┤
│ Transient Part of COMMAND.COM │
├─────────────────────────────────────────────────────┤
│ │
│ │
│ │
│ │
│ Transient Program Area │
├─────────────────────────────────────────────────────┤
│ │
│ │
│ │
│ │
│ External Commands and Utilities │
│ │
├─────────────────────────────────────────────────────┤
│ Resident Part of COMMAND.COM │
├─────────────────────────────────────────────────────┤
│ MS-DOS buffers, control areas, & installed drivers │
├─────────────────────────────────────────────────────┤
│ │
│ MSDOS.SYS │
├─────────────────────────────────────────────────────┤
│ IO.SYS and resident device drivers │
├─────────────────────────────────────────────────────┤
│ Interrupt Vectors │
0 └─────────────────────────────────────────────────────┘
During system initialization, MS-DOS loads the io.sys and msdos.sys files
into low memory (Notice that in MS-DOS 4.0, the msdos.sys file is not
required to be written contiguously to the disk). The io.sys system file
is the MS-DOS interface to hardware. The msdos.sys system file includes
MS-DOS interrupt handlers and service routines (Interrupt 21H functions).
Next, the system initialization routine loads the resident and installable
device drivers. Above the installable device drivers, MS-DOS writes the
resident part of command.com. This part includes interrupt handlers for
Interrupts 22H (Terminate Process Exit Address), 23H (CONTROL+C Handler
Address), 24H (Critical-Error-Handler Address) and code to reload the
transient part. The transient part of command.com is reloaded into high
memory. It includes the command interpreter, the internal MS-DOS commands,
and the batch processor.
External command and utility (.com and .exe) files are loaded into the
transient program area. MS-DOS also allocates 256 bytes of user stack used
with .com files. User memory is allocated from the lowest end of available
memory that fulfills the allocation request.
4.3 The MS-DOS Program Segment
When you type an external command or execute a program through Function
4B00H or 4B03H (Load and Execute Program or Overlay, also called EXEC),
MS-DOS determines the lowest available free memory address to use as the
start of the program. The memory starting at this address is called the
Program Segment.
The EXEC system call sets up the first 256 bytes of the Program Segment
for the program being loaded into memory. The program is then loaded
following this block. A .exe file with minalloc and maxalloc both set to
zero is loaded as high as possible.
At offset 0 within the Program Segment, MS-DOS builds the Program Segment
Prefix control block. The program returns from EXEC by one of five
methods:
■ By issuing an Interrupt 21H with AH=4CH (End Process)
■ By issuing an Interrupt 21H with AH=31H (Keep Process)
■ By a long jump to offset 0 in the Program Segment Prefix
■ By issuing an Interrupt 20H (Progam Terminate) with CS:0 pointing at
the PSP
■ By issuing an Interrupt 21H with register AH=0 and with CS:0 pointing
at the PSP
──────────────────────────────────────────────────────────────────────────
Note
The first two methods are preferred for functionality, compatibility,
and efficiency in future versions of MS-DOS.
──────────────────────────────────────────────────────────────────────────
All five methods transfer control to the program that issued the EXEC
call. The first two methods return a completion code. They also restore
the addresses of Interrupts 22H, 23H, and 24H (Terminate Process Exit
Address, CONTROL+C Handler Address, and Critical-Error-Handler Address)
from the values saved in the Program Segment Prefix of the terminating
program. Control then passes to the terminate address.
If a program returns to command.com, control transfers to the resident
portion. If the program is a batch file (in process), it continues.
Otherwise, command.com performs a checksum on the transient part, reloads
it if necessary, issues the system prompt, and waits for you to type
another command.
When a program receives control, the following conditions are in effect:
For All Programs:
■ The segment address of the passed environment is at offset 2CH in the
Program Segment Prefix.
■ The environment is a series of ASCII strings (totaling less than 32K)
in the form:
NAME=parameter
■ A byte of zeros terminates each string, and another byte of zeros
terminates the set of strings.
Following the last byte of zeros is a set of initial arguments that the
operating system passes to a program. This set of arguments contains a
word count followed by an ASCII string. If the file is in the current
directory, the ASCII string contains the drive and pathname of the
executable program as passed to the EXEC function call. If the file is
not in the current directory, EXEC concatenates the name of the file
with the name of the path. Programs may use this area to determine
where the program was loaded.
■ The environment built by the command processor contains at least a
comspec=string (the parameters on comspec define the path that MS-DOS
uses to locate command.com on the disk). The last path and prompt
commands issued are also in the environment, along with any environment
strings you have defined with the MS-DOS set command.
■ EXEC passes a copy of the invoking process environment. If your
application uses a "keep process" concept, you should be aware that the
copy of the environment passed to you is static. That is, it will not
change even if you issue subsequent set, path, or prompt commands.
Conversely, any modification of the passed environment by the
application is not reflected in the parent process environment. For
instance, a program cannot change the MS-DOS environment values as the
set command does.
■ The Disk Transfer Address (DTA) is set to 80H (default DTA in the
Program Segment Prefix). The Program Segment Prefix contains file
control blocks at 5CH and 6CH. MS-DOS formats these blocks using the
first two parameters that you typed when entering the command. If
either parameter contained a pathname, then the corresponding FCB
contains only the valid drive number. The filename field is not valid.
■ An unformatted parameter area at 81H contains all the characters typed
after the command (including leading and embedded delimiters), with the
byte at 80H set to the number of characters. If you type <, >, or
parameters on the command line, they do not appear in this area (nor
the filenames associated with them). Redirection of standard input and
output is transparent to applications.
■ Register AX indicates whether the drive specifiers (entered with the
first two parameters) are valid, as follows:
AL=FF if the first parameter contained an invalid drive specifier
(otherwise AL=00)
AH=FF if the second parameter contained an invalid drive specifier
(otherwise AH=00)
■ Offset 2 (one word) contains the segment address of the first byte of
unavailable memory. Programs must not modify addresses beyond this
point unless these addresses were obtained by allocating memory via
Function 48H (Allocate Memory).
For Executable (.exe) Programs:
■ DS and ES registers point to the Program Segment Prefix.
■ CS,IP,SS, and SP registers contain the values that Microsoft link sets
in the .exe image.
For Executable (.com) Programs:
■ All four segment registers contain the segment address of the initial
allocation block that starts with the Program Segment Prefix control
block.
■ .com programs allocate all of user memory. If the program invokes
another program through Function 4B00H or 4B03H (EXEC), it must first
free some memory through Function 4AH (Set Block) to provide space for
the program being executed.
■ The Instruction Pointer (IP) is set to 100H.
■ The Stack Pointer register is set to the end of the program's segment.
■ A .com program places a word of zeros on top of the stack. Then, by
doing a RET instruction last, your program can exit to command.com.
This method assumes, however, that you have maintained your stack and
code segments.
Figure 4.1 illustrates the format of the Program Segment Prefix. All
offsets are in hexadecimal.
(Offsets in Hex)
0 ┌─────────────┬─────────────┬─────────────────────────────┐
│ │ End of │ │
│ INT 20H │ alloc. │ Reserved │
│ │ block │ 04H │
8 ├─────────────┼─────────────┴──────────┬──────────────────┤
│ │ Terminate address │ CONTROL+C exit │
│ Reserved │ (IP, CS) │ address (IP) │
│ │ │ │
10├────────────┬┴────────────────────────┼──────────────────┤
│CONTROL+C │ Hard error exit address │ │
│exit │ (IP, CS) │ │
│address (CS)│ │ │
├────────────┴─────────────────────────┘ │
│ │
│ Used by MS-DOS │
│ │
│ 5CH │
│ │
├─────────────────────────────────────────────────────────┤
│ │
│ Formatted Parameter Area 1 formatted as standard │
│ unopened FCB 6CH │
├─────────────────────────────────────────────────────────┤
│ │
│ Formatted Parameter Area 2 formatted as standard │
│ unopened FCB (overlaid if FCB at 5CH is opened) │
80├─────────────────────────────────────────────────────────┤
│ Unformatted Parameter Area │
│ (default Disk Transfer Area) │
│ Initially contains command invocation line. │
└─────────────────────────────────────────────────────────┘
100
Figure 4.1 Program Segment Prefix
──────────────────────────────────────────────────────────────────────────
Important
Programs must not alter any part of the Program Segment Prefix below
offset 5CH.
──────────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────────────
Chapter 5 National Language Support
5.1 Introduction
5.2 National Language Support Calls
5.3 Font Files
5.3.1 Font File Structure
5.1 Introduction
National language support for this version of MS-DOS 4.0 includes these
major features:
■ Country-dependent information
■ Support for national keyboard layouts
■ Programming interfaces for national language support
■ Utility commands
Country-dependent information is available on a per-country basis and
includes the following:
■ Time, date, and currency
■ Lowercase-to-uppercase character-conversion tables
■ Collating sequence for character sorting
■ Valid single-byte characters used in filenames
Selectable keyboard support for different keyboard layouts is provided.
The MS-DOS 4.0 programming interfaces for national language support allow
applications to use the country-dependent information just described. To
access this information, applications do not need to change the current
country code of the system.
Utility commands allow the user to select the keyboard layout and system
country code.
This version of MS-DOS does not support right-to-left national languages.
5.2 National Language Support Calls
The following function calls allow an application to tailor its operation
to the current country code and to accept or change the current code page.
A country code defines the country in which you live or work. MS-DOS uses
this code to prepare and assign default code pages for your system. A code
page is a table that defines the character set you are using. A character
set is a country-specific or language-specific group of characters that
are translated from the code page table and displayed on your screen or
printer. Each code page character set contains 256 characters. The
following function calls are also used by MS-DOS 4.0 to support the
National Language requirements:
■ Function 440CH (Generic IOCtl) ── supports code page switching on a
per-device basis.
■ Function 65H (Get Extended Country Information) ── returns standard
country information and points to related case-map or collating tables.
■ Function 66H (Get/Set Global Code Page) ── gets or sets the code page
used by the kernel and by all devices.
These functions support access to country-dependent information, all of
which resides in one file named country.sys.
5.3 Font Files
Font files, also called code page information files, contain the images of
code page character sets for use by display or printer devices. These font
files are identified by a filename extension of .cpi. Four font files are
included with MS-DOS 4.0:
Font file Supported device
──────────────────────────────────────────────────────────────────────────
ega.cpi Color console used with an EGA card
lcd.cpi Liquid crystal display
4201.cpi IBM 4201 Proprinter family and IBM 4202 Proprinter
printers
4208.cpi IBM 4207 Proprinter X24 and IBM 4208 Proprinter XL24
printers
5202.cpi IBM 5202 Quietwriter III printer
──────────────────────────────────────────────────────────────────────────
5.3.1 Font File Structure
The contents of printer or display font files are structured as follows:
┌──────────────────────────────────────┐
│ 23-BYTE File Header │
├──────────────────────────────────────┤
│ WORD Information Header │
├──────────────────────────────────────┤
│ 28-BYTE Code Page Entry Header(s) │
├──────────────────────────────────────┤
│ Variable size Font Data Block(s) │
├──────────────────────────────────────┤
│ 150-BYTE Copyright Notice │
└──────────────────────────────────────┘
Figure 5.1 Font File Structure
The first code page entry header immediately follows the information
header. The copyright notice is always at the end of the file. Between
these, the file consists of arbitrarily intermingled code page entry
headers and font data blocks.
The font file fields are described in the following sections.
File Header
Each file must begin with a file header. There is only one of these
headers per file. This header identifies the file as a valid font file and
has the following format:
Length Parameter
──────────────────────────────────────────────────────────────────────────
8 BYTES File tag
8 BYTES Reserved
WORD Number of pointers
BYTE Type of pointer
2 WORDS Offset
──────────────────────────────────────────────────────────────────────────
where:
File tag begins with the byte 0FFH and is followed by the seven-byte
string "font."
Reserved is eight bytes of zeros.
Number of pointers is the number of information pointers in the header.
For MS-DOS 4.0, the value of this word should be 1.
Type of pointer is the type of information pointers in the header. For
MS-DOS 4.0, the value of this word should be 1.
Offset is the offset, in bytes, from the beginning of the file to the
information header.
Information Header
The information header begins at the offset given in the file header. It
describes how many code pages are contained in the font file. The format
of this one-word information header is:
Length Parameter
──────────────────────────────────────────────────────────────────────────
WORD Number of code pages
──────────────────────────────────────────────────────────────────────────
where:
Number of code pages is the number of code page entries in the file.
Code Page Entry Header
The number of code page entries in a font file is defined in the preceding
section, "Information Header." For each code page in the font file, there
is a code page entry header that gives general information about that code
page entry in the file. The header has the following format:
Length Parameter
──────────────────────────────────────────────────────────────────────────
WORD Length
2 WORDS Pointer
WORD Device type
8 BYTES Device subtype
WORD Code page ID
3 WORDS Reserved
2 WORDS Offset
──────────────────────────────────────────────────────────────────────────
where:
Length is the size of the code page entry header. Since this header is a
fixed size, it can be used for testing if the font file has been read in
correctly.
Pointer is a two-word pointer to the next code page entry header. The last
header will point to nothing and will have a value of 0,0.
Device type is 1 if the device is a raster display, or 2 if the device is
a printer.
Device subtype names the type of display or printer. This field also
determines the name of the font file. For example, if the subtype is
"EGA," the font file name is ega.cpi
Code page ID defines a valid three-digit code page identification number.
Valid code page numbers are 437, 850, 860, 863, and 865.
Reserved is three words of zeros.
Offset is a double-word pointer to the font data block associated with
this code page and described in the next section.
Font Data Block
The Font Data Block consists of the following fields:
┌─────────────────────────────────────────┐
│ 6-BYTE Font Data Header │
├─────────────────────────────────────────┤
│ Variable length Font Description(s) │
└─────────────────────────────────────────┘
The code page of a font data block is specified by the code page entry
header whose Offset field points to that font data block. The device type
contained in this code page entry header determines whether the font
description(s) should be interpreted as raster-style (display) fonts or
escape code sequences for particular downloadable device (printer) fonts.
The Font Data Header, the Display Font Description, and the Printer Font
Description fields are described in the following sections.
Font Data Header:
The Font Data Header indicates how many font descriptions exist for the
current code page. This header has the following fields:
Length Parameter
──────────────────────────────────────────────────────────────────────────
WORD Reserved
WORD Number of fonts
WORD Length of font data
──────────────────────────────────────────────────────────────────────────
where:
Reserved must be 1.
Number of fonts specifies the number of fonts (font descriptions) that
immediately follow this font data header. These font descriptions are all
associated with the font data block's code page. For printer devices, the
number of fonts must be equal to one.
Length of font data is equal to the sum of the sizes (in bytes) of the
font descriptions, as described in the next two sections.
Display Font Description:
Each font description for a display device begins with a header that
specifies the raster dimensions of each character in the font and the
number of characters in the font. This is followed by the raster bitmaps
for each character. The actual fields are:
Length Parameter
──────────────────────────────────────────────────────────────────────────
BYTE Height
BYTE Width
BYTE Relative height
BYTE Relative width
WORD Number of characters
Variable Bitmap
──────────────────────────────────────────────────────────────────────────
where:
Height is the number of rows in pixels that this character occupies on the
screen. Width is the number of columns in pixels that this character
occupies on the screen.
Relative height is part of the aspect ratio. This is currently unused
(zero).
Relative width is part of the aspect ratio. This is currently unused
(zero).
Number of characters is the number of characters that are defined in the
bitmap immediately following this header. Normally, the entire ASCII
character set is defined, so that this value is usually 256.
Bitmap is a sequence of bitmaps, one for each character in the font. Each
character bitmap is a packed array of bits organized in rows by columns,
starting at the upper left corner of the character's image. Since all
current display fonts are eight bits wide, the number of bytes needed to
encode this packed array is simply equal to the square area of a character
in the font divided by 8 (the number of bits per byte).
The total length of the display font description is six bytes plus the
product of the number of characters in the descriptions and the number of
bytes needed to encode a character bitmap.
Printer Font Description:
There are two formats for printer font descriptions. These vary only in
the number of control sequences present in the font description.
Unlike the display font description, the number of bytes in the printer
font description cannot be directly determined. Instead, the size of the
printer font description must be calculated from the font header's length
value. As a result, only one printer font description can be contained in
a given font data block (otherwise, the point at which the first ended and
the second printer font description began could not be determined).
The format for the printer font desription is:
Length Parameter
──────────────────────────────────────────────────────────────────────────
WORD Selection type
WORD Control sequence length
Variable Control sequence data
Variable Downloadable font data
──────────────────────────────────────────────────────────────────────────
where:
Selection type is either 1 or 2. It identifies which of the two formats
for the printer font description is being used. These existing printer
files use the following selection types:
Selection type Printer font file
───────────────────────────────────────────────────────────────────────
1 4201.cpi
2 4208.cpi
2 5202.cpi
───────────────────────────────────────────────────────────────────────
Control sequence length is the number of bytes the control sequence data
field takes. This length must always be less than 31 (bytes).
Control sequence data is used for initializing the printer with this code
page. The size of this field is defined in the control sequence length
field.
If the selection type field is 2, this control sequence information
consists of a single escape sequence that selects the font for this code
page (this font may have been downloaded).
If the selection type field is 1, this control sequence information is
further divided into two escape sequences. In this case, the control
sequence data field consists of:
Length Parameter
───────────────────────────────────────────────────────────────────────
BYTE Hardware sequence length
Variable Hardware sequence
BYTE Downloadable sequence length
Variable Downloadable sequence
───────────────────────────────────────────────────────────────────────
where:
Hardware sequence length is the number of bytes contained in the
hardware sequence.
Hardware sequence is the escape sequence that selects the hardware
(default) font of the printer.
Downloadable sequence length is the number of bytes contained in the
downloadable sequence.
Downloadable sequence is the escape sequence that selects the
downloaded font currently resident in the printer.
Notice that the total number of bytes in these subfields must be equal
to the number of bytes given by the control sequence length field in
the printer font description.
Downloadable font data consists of the escape sequence required to
download the font description. This escape sequence is highly printer
specific. The number of bytes in it is determined by subtracting the size
of the initial portion of the printer font description from the Length
field of the font data block.
Since the 4208 and 5202 printers have hardware support for code pages,
they do not need any font data to be downloaded. Therefore, this field is
nonexistent in those font files.
────────────────────────────────────────────────────────────────────────────
Chapter 6 .Exe File Structure and Loading
6.1 Introduction
6.2 Format of a File Header
6.3 The Relocation Table
6.1 Introduction
──────────────────────────────────────────────────────────────────────────
Note
This chapter describes .exe file structure and loading procedures for
systems that use a version of MS-DOS earlier than 2.0. For MS-DOS
versions 2.0 and later, use Function B00H (Load and Execute Program) to
load (or load and execute) a .exe file.
──────────────────────────────────────────────────────────────────────────
The .exe files produced by link consist of two parts:
■ Control and relocation information
■ The load module
The control and relocation information is at the beginning of the file in
an area called the header. Immediately following this header is the load
module.
6.2 Format of a File Header
The header is formatted as follows (notice that offsets are in
hexadecimal):
╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
Offset Contents
──────────────────────────────────────────────────────────────────────────
0-1 Must contain 4DH, 5AH.
2-3 Number of bytes contained in last page; useful for
reading overlays.
4-5 Size of the file in 512-byte pages, including the
header.
6-7 Number of relocation entries in table.
8-9 Size of the header in 16-byte paragraphs. Used to
Offset Contents
──────────────────────────────────────────────────────────────────────────
8-9 Size of the header in 16-byte paragraphs. Used to
locate the beginning of the load module in the file.
AH-BH Minimum number of 16-byte paragraphs required above the
end of the loaded program.
CH-DH Maximum number of 16-byte paragraphs required above the
end of the loaded program. If both minalloc and
maxalloc are 0, the program is loaded as high as
possible.
EH-FH Initial value to be loaded into stack segment before
starting program execution. Must be adjusted by
relocation.
10-11 Value to be loaded into the SP register before starting
program execution.
12-13 Negative sum of all the words in the file.
Offset Contents
──────────────────────────────────────────────────────────────────────────
12-13 Negative sum of all the words in the file.
14-15 Initial value to be loaded into the IP register before
starting program execution.
16-17 Initial value to be loaded into the CS register before
starting program execution. Must be adjusted by
relocation.
18-19 Relative byte offset from beginning of run file to
relocation table.
1AH-1BH The number of the overlay as generated by link.
──────────────────────────────────────────────────────────────────────────
6.3 The Relocation Table
The relocation table that follows the formatted area above consists of a
variable number of relocation items. Each relocation item contains two
fields: a two-byte offset value, followed by a two-byte segment value.
These two fields contain the offset into a word's load module. This item
requires modification before the module is given control. The following
steps describe this process:
1. The formatted part of the header is read into memory. Its size is 1BH.
2. MS-DOS allocates a portion of memory depending on the size of the load
module and the allocation numbers (AH-BH and CH-DH). MS-DOS then
attempts to allocate 0FFFH paragraphs. This attempt always fails and
returns the size of the largest free block. If this block is smaller
than minalloc and loadsize, there is no memory error. But if this block
is larger than maxalloc and loadsize, MS-DOS allocates (maxalloc +
loadsize). Otherwise, it allocates the largest free block of memory.
3. A Program Segment Prefix is built in the lowest part of the allocated
memory.
4. MS-DOS calculates the load module size (using offsets 4-5 and 8-9) by
subtracting the header size from the file size. The actual size is
adjusted down based on the contents of offsets 2-3. The operating
system determines (based on the setting of the high/low load switch) an
appropriate segment, called the start segment, where it loads the load
module.
5. The load module is read into memory beginning with the start segment.
6. The items in the relocation table are read into a work area.
7. MS-DOS adds the segment value of each relocation table item to the
start segment value. This calculated segment, plus offset, points to
the module to which the start segment value is added. The result is
then placed back into the word in the load module.
8. Once all relocation items have been processed, the operating system
sets the SS and SP registers, using the values in the header. MS-DOS
then adds the start segment value to SS and sets the ES and DS
registers to the segment address of the Program Segment Prefix. The
start segment value is then added to the header CS register value. The
result, along with the header IP value, is the initial CS:IP to
transfer to before starting execution of the program.
────────────────────────────────────────────────────────────────────────────
Chapter 7 Relocatable Object Module Formats
7.1 Introduction
7.1.1 Definition of Terms
7.2 Module Identification and Attributes
7.2.1 Segment Definition
7.2.2 Addressing a Segment
7.2.3 Symbol Definition
7.2.4 Indices
7.3 Conceptual Framework for Fixups
7.3.1 Self-Relative Fixup
7.3.2 Segment-Relative Fixup
7.4 Record Sequence
7.5 Introducing the Record Formats
7.5.1 Sample Record Format (SAMREC)
7.5.2 T-Module Header Record (THEADR)
7.5.3 L-Module Header Record (LHEADR)
7.5.4 List of Names Record (LNAMES)
7.5.5 Segment Definition Record (SEGDEF)
7.5.6 Group Definition Record (GRPDEF)
7.5.7 Public Names Definition Record (PUBDEF)
7.5.8 Communal Names Definition Record (COMDEF)
7.5.9 Local Symbols Record (LOCSYM)
7.5.10 External Names Definition Record (EXTDEF)
7.5.11 Line Numbers Record (LINNUM)
7.5.12 Logical Enumerated Data Record (LEDATA)
7.5.13 Logical Iterated Data Record (LIDATA)
7.5.14 Fixup Record (FIXUPP)
7.5.15 Module End Record (MODEND)
7.5.16 Comment Record (COMENT)
7.6 Microsoft Type Representations for Communal Variables
7.1 Introduction
This chapter presents the object record formats that define the
relocatable object language for the 8086, 80186, and 80286
microprocessors. The 8086 object language is the output of all language
translators that have an 8086 processor and that will be linked by the
Microsoft linker. The 8086 object language is used for input and output
for object language processors such as linkers and librarians, and in the
XENIX, PC-DOS, and MS-DOS operating systems.
The 8086 object module formats let you specify relocatable memory images
that may be linked together. These formats also allow efficient use of the
memory mapping facilities of the 8086 family of microprocessors.
The following table lists the record formats that Microsoft supports.
Their abbreviations appear in parentheses. Each is described in this
chapter.
Table 7.1
Object Module Record Formats
Symbol Definition Records
──────────────────────────────────────────────────────────────────────────
Public Names Definition Record (PUBDEF)
Communal Names Definition Record (COMDEF)
Local Symbols Record (LOCSYM)
External Names Definition Record (EXTDEF)
Line Numbers Record (LINNUM)
Data Records
Logical Enumerated Data Record (LEDATA)
Logical Iterated Data Record (LIDATA)
T-Module Header Record (THEADR)
L-Module Header Record (LHEADR)
List of Names Record (LNAMES)
Segment Definition Record (SEGDEF)
Group Definition Record (GRPDEF)
Fixup Record (FIXUPP)
Module End Record (MODEND)
Comment Record (COMENT)
──────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────
Note
If an object module contains any undefined values, the behavior of the
Microsoft linker is undefined. All undefined values should be considered
reserved by Microsoft for future use.
──────────────────────────────────────────────────────────────────────────
7.1.1 Definition of Terms
The following terms are fundamental to 8086 relocation and linkage:
OMF - Object Module Formats
MAS - Memory Address Space
The 8086 MAS is one megabyte (1,048,576 bytes). Notice that the MAS is
distinguished from actual memory, which may occupy only a portion of the
MAS.
Module
A module is an "inseparable" collection of object code and other
information produced by a translator.
T-Module
A T-module is a module created by a translator, such as Pascal or FORTRAN.
The following restrictions apply to object modules:
■ Every module should have a name. Translators provide default names
(possibly filenames or null names) for T-modules if neither the source
code nor the user specifies otherwise.
■ Every T-module in a collection of linked modules should have a
different name so that symbolic debugging systems can distinguish the
various line numbers and local symbols. The Microsoft linker does not
require or enforce this restriction.
Frame
A frame is a contiguous region of 64K of memory address space (MAS),
beginning on a paragraph boundary (i.e., on a multiple of 16 bytes) or on
a selector on the 80286 processor. This concept is useful because the
contents of the four 8086 segment registers define four (possibly
overlapping) frames; no 16-bit address in the 8086 code can access a
memory location outside the current four frames.
LSEG (Logical Segment)
A logical segment (LSEG) is a contiguous region of memory whose contents
are determined at translation time (except for address-binding). Neither
the size nor the location in MAS are necessarily determined during
translation: the size, although partially fixed, may not be final because
the linker may combine the LSEG when linking with other LSEGs, forming a
single LSEG. So that it can fit in a frame, an LSEG must not be larger
than 64K. Thus, a 16-bit offset, from the base of a frame that covers the
LSEG, may address any byte in that LSEG.
PSEG (Physical Segment)
This term is equivalent to frame. Some prefer "PSEG" to "frame" because
the terms PSEG and LSEG reflect the "physical" and "logical" nature of the
underlying segments.
Frame Number
Every frame begins on a paragraph boundary. The "paragraphs" in MAS can be
numbered from 0 through 65,535. These numbers, each of which defines a
frame, are called frame numbers.
Group
A group is a collection of LSEGs defined at translation time, whose final
locations in MAS have been constrained so that at least one frame exists
that covers (contains) every LSEG in the collection.
The notation "Gr A(X,Y,Z,)" means that LSEGs X, Y, and Z form a group
named A. That X, Y, and Z are all LSEGs in the same group does not imply
any ordering of X, Y, and Z in MAS, nor does it imply any contiguity
between X, Y, and Z.
The Microsoft linker does not currently allow an LSEG to be a member of
more than one group.
Canonic
On the 8086 processor, any location in MAS is contained in exactly 4096
distinct frames, but one of these frames can be distinguished because it
has a higher frame number. This frame is called the canonic frame of the
location. In other words, the canonic frame of a given byte is the frame
chosen so that the byte's offset from that frame lies in the range 0 to 15
(decimal).
For example, suppose FOO is a symbol defining a memory location. You would
then refer to this frame as the "canonic frame of FOO." Similarly, if S is
any set of memory locations, then a unique frame exists that has the
lowest frame number in the set of canonic frames of the locations in S.
This unique frame is called the canonic frame of the set S. You might
refer similarly to the canonic frame of an LSEG or of a group of LSEGs.
Segment Name
LSEGs are assigned segment names at translation time. These names serve
two purposes:
■ During linking, they play a role in determining which LSEGs are
combined with other LSEGs.
■ They are used in assembly source code to specify membership in groups.
Class Name
The translator may optionally assign class names to LSEGs during
translation. Classes define a partition on LSEGs: two LSEGs are in the
same class if they have the same class name.
The Microsoft linker applies the following semantics to class names: the
class name "CODE", or any class name whose suffix is "CODE", implies that
all segments of that class contain only code and may be considered
read-only. Such segments may be overlaid if you specify the module
containing the segment as part of an overlay.
Overlay Name
The linker may optionally assign an overlay name to LSEGs. The overlay
name of an LSEG is ignored by Microsoft language linkers for version 3.0
and later languages, but the standard MS-DOS linker supports it.
Complete Name
The complete name of an LSEG consists of the segment name, class name, and
overlay name. The linker combines LSEGs from different modules if their
complete names are identical.
7.2 Module Identification and Attributes
A module header record, which provides a module name, is always the first
record in a module. In addition to having a name, a module may represent a
main program and may have a specified starting address. When linking
multiple modules together, you should give only one module which has the
main attribute. If more than one main module appears, the first takes
precedence.
In summary, modules may or may not be main and may or may not have a
starting address.
7.2.1 Segment Definition
A module is a collection of object code defined by a sequence of records
that a translator produces. The object code represents contiguous regions
of memory whose contents the linker determines during translation. These
regions are LSEGs. A module defines the attributes of each LSEG. The
segment definition record (SEGDEF) is responsible for maintaining all LSEG
information (name, length, memory alignment, etc.). The linker requires
the LSEG information when you combine multiple LSEGs and when it
establishes segment addressability. The SEGDEF records must follow the
first header record.
7.2.2 Addressing a Segment
The 8086 addressing mechanism provides segment base registers from which
you may address a 64-kilobyte region of memory (a frame). There is one
code segment base register (CS), two data segment base registers (DS, ES),
and one stack segment base register (SS).
The possible number of LSEGs that may make up a memory image far exceeds
the number of available base registers. Thus, base registers may require
frequent loading. This would be the case in a modular program with many
small data and/or code LSEGs.
Since such frequent loading of base registers is undesirable, it is a good
strategy to collect many small LSEGs together into a single unit that will
fit in one memory frame. Then all the LSEGs may be addressed using the
same base register value. This addressable unit is a group (see the
definition of a group in Section 7.1.1, "Definition of Terms").
To establish addressability of objects within a group, you must explicitly
define each group in the module. The group definition record (GRPDEF)
lists constituent segments by their segment names.
The GRPDEF records within a module must follow all SEGDEF records because
GRPDEF records will reference SEGDEF records in defining a group. The
GRPDEF records must also precede all other records except header records,
which the linker must process first.
7.2.3 Symbol Definition
The Microsoft linker supports three different types of records belonging
to the class of symbol definition records. The types are public names
definition records (PUBDEFs), communal names definition records (COMDEFs),
and external names definition records (EXTDEFs). You use these record
types to define globally visible procedures and data items and to resolve
external references.
7.2.4 Indices
"Index" fields appear throughout this chapter. An index is an integer that
selects a particular item from a collection of items; for example: name
index, segment index, group index, external index, type index, etc.
──────────────────────────────────────────────────────────────────────────
Note
An index is normally a positive number. The index value zero is
reserved, and may carry a special meaning depending on the type of index
(for example, a segment index of zero specifies the "Unnamed" absolute
pseudo-segment; a type index of zero specifies the "Untyped type").
──────────────────────────────────────────────────────────────────────────
In general, indices must assume values that are quite large (that is, much
larger than 255). Nevertheless, a great number of object files contain no
indices with values greater than 50 or 100. Therefore, indices are encoded
in one or two bytes, as required.
The high-order (left-most) bit of the first (and possibly the only) byte
determines whether the index occupies one byte or two. If the bit is 0,
the index is a number between 0 and 127, occupying one byte. If the bit is
1, the index is a number between 0 and 32K-1, occupying two bytes, and is
determined as follows: the low-order eight bits are in the second byte,
and the high-order seven bits are in the first byte.
7.3 Conceptual Framework for Fixups
A fixup is a modification to object code that achieves address binding
that a translator requested and a linker performed.
──────────────────────────────────────────────────────────────────────────
Note
This is the linker's definition of fixup. Nevertheless, the linker can
modify object code (make a "fixup") that does not conform to this
definition. For example, binding code to either hardware or software
floating-point subroutines is a modification to an operation code, which
is treated as an address. The previous definition of fixup is not
intended to disallow or discourage modifications to the object code.
──────────────────────────────────────────────────────────────────────────
8086-family translators need four kinds of data to specify a fixup:
■ The place and type of a location to be fixed up.
■ One of two possible fixup modes.
■ A target, which is the memory address to which the location must refer.
■ A frame that defines a context in which the reference takes place.
Location ── There are five types of locations: a pointer, a base, an
offset, a hibyte, and a lobyte.
The vertical alignment of Figure 7.1 illustrates four points (remember
that the high-order byte of a word in 8086 memory is the byte with the
higher address):
■ A base is the high-order word of a pointer (the linker doesn't care
whether the low-order word of the pointer is present).
■ An offset is the low-order word of a pointer (the linker doesn't care
whether the high-order word follows).
■ A hibyte is the high-order half of an offset (the linker doesn't care
whether the low-order half precedes).
■ A lobyte is the low-order half of an offset (the linker doesn't care
whether the high-order half follows).
┌───────────────────┐
Pointer: │ │
└───────────────────┘
┌─────────┐
Base: │ │
└─────────┘
┌─────────┐
Offset: │ │
└─────────┘
┌────┐
Hibyte: │ │
└────┘
┌────┐
Lobyte: │ │
└────┘
Figure 7.1 Location Types
A Location is specified by two kinds of data: the location type, and where
it is located.
The location type is specified by the LOC field in the FIXUPP record's
LOCAT field; where it is located is specified by the Data Record Offset
field in the same LOCAT field.
Mode ── The Microsoft linker supports two kinds of fixups: self-relative
and segment-relative.
Self-relative fixups support the 8-bit and 16-bit offsets used in CALL,
JUMP, and SHORT-JUMP instructions. Segment-relative fixups support all
other addressing modes of the 8086.
Target ── The target is the location in MAS that the linker references.
(More explicitly, the linker considers the target the lowest byte in the
object that it is referencing.) The linker specifies a target by one of
five methods. There are three "primary" methods and three "secondary"
ones. Each primary method of specifying a target uses two kinds of data:
an index number X, and a displacement D.
Method Explanation
──────────────────────────────────────────────────────────────────────────
(T0) X is a segment index. The target is the Dth byte in the
LSEG that the segment index identifies.
(T1) X is a group index. The target is the Dth byte in the
LSEG that the group index identifies.
(T2) X is an external index. The external index identifies
the external name that (eventually) gives the address
of a byte. The Dth byte following this byte is the
──────────────────────────────────────────────────────────────────────────
Each secondary method of specifying a target uses only one item of data ──
the index number X; this assumes an implicit displacement equal to zero.
Method Explanation
──────────────────────────────────────────────────────────────────────────
(T4) X is a segment index. The target is the 0th (first)
byte in the LSEG that the segment index identifies.
(T5) X is a group index. The target is the 0th (first) byte
in the LSEG in the specified group located (eventually)
lowest in MAS.
(T6) X is an external index. The target is the byte whose
address is the external name that the external index
──────────────────────────────────────────────────────────────────────────
The following nomenclature describes a target:
Nomenclature Method
──────────────────────────────────────────────────────────────────────────
Target: SI(segment name), displacement [T0]
Target: GI(group name), displacement [T1]
Target: EI(symbol name), displacement [T2]
Target: SI (segment name) [T4]
Target: GI (group name) [T5]
Target: EI (symbol name) [T6]
──────────────────────────────────────────────────────────────────────────
The following examples illustrate how this notation is used:
Sample Nomenclature Explanation
──────────────────────────────────────────────────────────────────────────
Target: SI(CODE), 1024 The 1025th byte in the segment CODE.
Target: GI(DATAAREA) The location in MAS of a group called
DATAAREA.
Target: EI(SIN) The address of the external
subroutine SIN.
Target: EI(PAYSCHEDULE), 24 The 24th byte following the location
of an external data structure called
──────────────────────────────────────────────────────────────────────────
Frame ── Every 8086 memory reference is to a location contained within a
frame. This frame is designated by the contents of a segment register. For
the linker to form a correct, usable memory reference, it must know what
the target is, and to which frame the reference is being made. Thus, every
fixup specifies such a frame, in one of five methods. Some methods use
data, X, which is in the index number. Other methods require no data.
The five methods of specifying frames are as follows:
Method Explanation
──────────────────────────────────────────────────────────────────────────
(F0) X is a segment index. The frame is the canonic frame of
the LSEG that the segment index defines.
(F1) X is a group index. The frame is the canonic frame
defined by the group (that is, the canonic frame
defined by the LSEG in the group located (eventually)
lowest in MAS).
(F2) X is an external index. The frame is determined when
the linker finds the external name's public definition.
There are two cases:
Case Explanation
──────────────────────────────────────────────────────────────────────────
(F2a) The linker defines the symbol
relative to some LSEG, and there is
no associated group. The linker also
specifies the LSEG's canonic frame.
(F2c) Regardless of how the linker defines
the symbol, there is an associated
group. And the linker specifies the
canonic frame of the group. (The
Group Index field of the PUBDEF
──────────────────────────────────────────────────────────────────────────
Method Explanation
──────────────────────────────────────────────────────────────────────────
(F4) No X. The frame is the canonic frame of the LSEG that
contains the location.
(F5) No X. The target determines the frame. There are three
──────────────────────────────────────────────────────────────────────────
Case Explanation
──────────────────────────────────────────────────────────────────────────
(F5a) The target specifies a segment index:
in this case, the frame is determined
as in (F0).
(F5b) The target specifies a group index:
in this case, the frame is determined
as in (F1).
(F5c) The target specifies an external
index: in this case, the frame is
──────────────────────────────────────────────────────────────────────────
The nomenclature that describes frames is similar to the above
nomenclature for targets.
Nomenclature Method
──────────────────────────────────────────────────────────────────────────
Frame: SI (segment name) [F0]
Frame: GI (group name) [F1]
Frame: EI (symbol name) [F2]
Frame: Location [F4]
Frame: target [F5]
Frame: None [F6]
──────────────────────────────────────────────────────────────────────────
For an 8086 memory reference, the frame specified by a self-relative
reference is usually the canonic frame of the LSEG that contains the
location. Also, the frame specified by a segment-relative reference is the
canonic frame of the LSEG that contains the target.
7.3.1 Self-Relative Fixup
A self-relative fixup works as follows: the location implicitly defines a
memory address──namely, the address of the byte following the location
(because at the time of a self-relative reference, the 8086 IP
(Instruction Pointer) is pointing to the byte following the reference).
For 8086 self-relative references, if either the location or the target is
outside the specified frame, the linker gives a warning. Otherwise, there
is a unique l6-bit displacement that, when added to the address implicitly
defined by the location, yields the relative position of the target in the
frame.
■ If the location is an offset, the linker adds the displacement to the
location (modulo 65,536) and reports no errors.
■ If the location is a lobyte, the displacement must be within the range
{-128:127}; otherwise, the linker gives a warning. The linker adds the
displacement to the location (modulo 256).
■ If the location is a base, pointer, or hibyte, it is unclear what the
translator intended, so the linker's action is undefined.
7.3.2 Segment-Relative Fixup
A segment-relative fixup operates as follows: a nonnegative 16-bit number,
FBVAL, is defined as the frame number of the frame or selector value that
the fixup specifies. A signed 20-bit number, FOVAL, is defined as the
distance from the base of the frame to the target. If this signed 20-bit
number is less than 0 or greater than 65,535, the linker reports an error.
Otherwise, the linker uses FBVAL and FOVAL to fix up the location in the
following fashion:
■ If the location is a pointer, the linker adds FBVAL (modulo 65,536) to
the high-order word of the pointer, and adds FOVAL (modulo 65,536) to
the low-order word of the pointer.
■ If the location is a base, the linker adds FBVAL (modulo 65,536) to the
base and ignores FOVAL.
■ If the location is an offset, the linker adds FOVAL (modulo 65,536) to
the offset and ignores FBVAL.
■ If the location is a hibyte, the linker adds (FOVAL/256) (modulo 256)
to the hibyte and ignores FBVAL. (The division indicated is integer
division; that is, the linker discards the remainder.)
■ If the location is a lobyte, the linker adds (FOVAL modulo 256) (modulo
256) to the lobyte and ignores FBVAL.
7.4 Record Sequence
An object code file must contain a sequence of one or more modules, or a
library containing zero or more modules. The following syntax shows the
valid record ordering necessary to form a module. In addition, the given
semantic rules provide information about how to interpret the record
sequence.
──────────────────────────────────────────────────────────────────────────
Note
The description language used in the following syntax is defined in
WIRTH: CACM, November 1977, vol. 20, no. 11, pp. 822-823. The character
strings represented by capital letters are not literals but identifiers,
and are further defined in the record format section.
──────────────────────────────────────────────────────────────────────────
object file = tmodule
tmodule = {THEADR | LHEADR} seg-grp {component} modtail
seg_grp = {LNAMES} {SEGDEF} {EXTDEF | GRPDEF}
component = data | debug_record
data = content_def | thread_def |
PUBDEF | EXTDEF | COMDEF | LOCSYM
debug_record = LINNUM
content_def = data_record {FIXUPP}
thread_def = FIXUPP (containing only Thread fields)
data_record = LIDATA | LEDATA
modtail = MODEND
The following rules apply:
■ A FIXUPP record always refers to the previous data record.
■ All LNAMES, SEGDEF, GRPDEF, and EXTDEF records must precede all records
that refer to them.
■ Comment records may appear anywhere in a file, except as the first or
last record in a file or module, or within a content_def.
7.5 Introducing the Record Formats
The following pages present diagrams of record formats in schematic form.
Here is a sample record format that illustrates the various conventions:
7.5.1 Sample Record Format (SAMREC)
┌─────┬──────────┬─────///────┬────||||────┬─────┐
│ │ │ │ │ │
│ REC │ Record │ Name │ Number │ CHK │
│ TYP │ Length │ │ │ SUM │
│ xxH │ │ │ │ │
│ │ │ │ │ │
└─────┴──────────┼────///─────┼────||||────┴─────┘
│ │
└────rpt─────┘
The Title and Official Abbreviation
At the top of the figure is the name of the record format described, with
its official abbreviation. To promote uniformity among various programs,
including translators and debuggers, use the abbreviation in both code and
documentation. The abbreviation of the record format is always six
letters.
The Boxes
Each format is drawn with boxes of two sizes. A narrow box represents a
single byte. A plain wide box represents two bytes. The wide boxes with
three slashes in the top and bottom represent a variable number of bytes,
one or more, depending upon the content. The wide boxes with four vertical
bars in the top and bottom represent four-byte fields.
RECTYP
The first byte in each record contains a value between 0 and 255,
indicating the record type.
Record Length
The second field in each record contains the number of bytes in the
record, exclusive of the first two fields, where a field is a 16-bit
number──a low byte followed by a high byte.
Name
Any field that indicates a name has the following internal structure: the
first byte contains a number between 0 and 127, inclusive, indicating the
number of remaining bytes in the field. The remaining bytes are
interpreted as a byte string.
Most translators constrain the character set to a subset of the ASCII
character set.
Number
A four-byte number field represents a 32-bit unsigned integer, where the
first eight bits (least-significant) are stored in the first byte (lowest
address), the next eight bits are stored in the second byte, and so on.
Repeated or Conditional Fields
Some portions of a record format contain a field or series of fields that
may be repeated one or more times. Such portions are indicated by the
"repeated" or "rpt" brackets below the boxes.
Similarly, some portions of a record format are present only if some given
condition is true; these fields are indicated by similar "conditional" or
"cond" brackets below the boxes.
CHKSUM
The last field in each record is a check sum, which contains the two's
complement of the sum (modulo 256) of all other bytes in the record.
Therefore, the sum (modulo 256) of all bytes in the record is zero.
Bit Fields
Sometimes descriptions of the contents of fields are at the bit level.
Boxes with vertical lines drawn through them represent bytes or words; the
vertical lines indicate bit boundaries. Thus, the following byte
representation has three bit fields of three, one, and four bits,
respectively.
┌───────────┬───┬───────────────┐
│ │ │ │
│ │ │ │
│ │ │ │
└───────────┴───┴───────────────┘
3 1 4
7.5.2 T-Module Header Record (THEADR)
┌─────┬──────────┬─────///────┬─────┐
│ │ │ │ │
│ REC │ Record │ T- │ CHK │
│ TYP │ Length │ Module │ SUM │
│ 80H │ │ Name │ │
│ │ │ │ │
└─────┴──────────┴────///─────┴─────┘
T-Module Name
The T-Module Name field contains the name for the T-module.
7.5.3 L-Module Header Record (LHEADR)
┌─────┬──────────┬─────///────┬─────┐
│ │ │ │ │
│ REC │ Record │ L- │ CHK │
│ TYP │ Length │ Module │ SUM │
│ 82H │ │ Name │ │
│ │ │ │ │
└─────┴──────────┴────///─────┴─────┘
L-Module Name
The L-Module Name field contains the name for the L-module.
Every module output from a translator must have a T-module or L-module
header record. The linker requires a THEADR or LHEADR record to come first
in the module and ignores any others. The LHEADR record is identical to
the THEADR record, except it has a record type of 82H.
7.5.4 List of Names Record (LNAMES)
┌─────┬──────────┬─────///────┬─────┐
│ │ │ │ │
│ REC │ Record │ Name │ CHK │
│ TYP │ Length │ │ SUM │
│ 96H │ │ │ │
│ │ │ │ │
└─────┴──────────┼────///─────┼─────┘
│ │
└────rpt─────┘
The LNAMES record contains a list of names that the following SEGDEF and
GRPDEF records may use as the names of segments, classes, and/or groups.
The order of LNAMES records in a module and the order of names within each
LNAMES record imply a mapping of these names to numbers: 1, 2, 3, etc.
These numbers are used as "Name Indices" in the Segment Name Index, Class
Name Index, and Group Name Index fields of the SEGDEF and GRPDEF records.
Name
This repeatable field provides a name, which may have zero length.
7.5.5 Segment Definition Record (SEGDEF)
┌───┬────────┬───///───┬─────────┬───///───┬─///─┬─///─┬───┐
│ │ │ │ │ │ │ │ │
│REC│ Record │ Segment │ Segment │ Segment │Class│Over │CHK│
│TYP│ Length │ ATTR │ Length │ Name │Name │Lay │SUM│
│98H│ │ │ │ Index │Index│Name │ │
│ │ │ │ │ │ │Index│ │
└───┴────────┴───///───┴─────────┴───///───┴─///─┴─///─┴───┘
Segment index values 1 through 32,767, which are used in other record
types to refer to specific LSEGs, are defined implicitly by the sequence
in which SEGDEF records appear in the object file.
Segment ATTR
The Segment ATTR field provides information on various attributes of a
segment, and has the following format:
┌─────┬────────┬───────┐
│ │ │ │
│ ACB │ Frame │ Off- │
│ P │ Number │ Set │
│ │ │ │
│ │ │ │
└─────┼────────┴───────┤
│ │
└───conditional──┘
The ACBP byte contains four numbers──the A, C, B, and P attribute
specifications. This byte has the following format:
┌───────────┬───────────┬───┬───┐
│ │ │ │ │
│ A │ C │ B │ P │
│ │ │ │ │
└───────────┴───────────┴───┴───┘
A (Alignment) is a 3-bit subfield that specifies the alignment attribute
of the LSEG. The semantics are defined as follows:
Attribute Explanation
──────────────────────────────────────────────────────────────────────────
A=0 SEGDEF describes an absolute LSEG.
A=1 SEGDEF describes a relocatable, byte-aligned LSEG.
A=2 SEGDEF describes a relocatable, word-aligned LSEG.
A=3 SEGDEF describes a relocatable, paragraph-aligned LSEG.
A=4 SEGDEF describes a relocatable, page(256-byte)-aligned
LSEG.
──────────────────────────────────────────────────────────────────────────
If A=0, the Frame Number and Offset fields are present. With the Microsoft
linker, you may use absolute segments for addressing only; for example, to
define the starting address of a ROM and to define symbolic names for
addresses within the ROM. The linker ignores any data that belongs to an
absolute LSEG and issues a warning if absolute segments are defined for a
program that runs in protected mode. C (Combination) is a 3-bit subfield
that specifies the combination attribute of the LSEG. Absolute segments
(A=0) must have combination zero (C=0). For relocatable segments, the C
field encodes a number (0,1,2,3,4,5,6, or 7) that indicates how the
segment can be combined. One way to interpret this attribute is to
consider how two LSEGs are combined.
For example, suppose that X and Y are LSEGs, and that Z is the LSEG
resulting from the combination of X and Y. Let LX and LY be the lengths of
X and Y, and let MXY denote the maximum of LX, LY. Now, to accommodate the
alignment attribute of Y, let G be the length of any gap required between
the X and Y components of Z. Then, let LZ denote the length of the
(combined) LSEG, Z; let dx (0(<=dx<LX) be the offset in X of a byte and,
similarly, let dy be the offset (of a byte) in Y.
The following table gives the length LZ of the combined LSEG, Z, and the
offsets dx' and dy' in Z for the bytes corresponding to dx in X and to dy
in Y.
Table 7.2
Combination Attribute Example
C LZ dx' dy'
──────────────────────────────────────────────────────────────────────────
2 LX+LY+G dx dy+LX+G "Public"
5 LX+LY+G dx dy+LX+G "Stack"
6 MXY dx dy "Common"
──────────────────────────────────────────────────────────────────────────
Table 7.2 has no lines for C=0, 1, 3, 4, or 7. C=0 indicates that the
relocatable LSEG may not be combined. C=1 and C=3 are undefined. C=4 and
C=7 are treated the same as C=2.
B (Big) is a 1-bit subfield that, if set to 1, indicates that the segment
length is exactly 64K (65,536 bytes). In this case, the Segment Length
field must contain zero.
The P field must always be zero.
The Frame Number and Offset fields (present only for absolute segments,
A=0) specify the placement in MAS of the absolute segment. Offset is in
the range between 0 and 15, inclusive. If you want an offset value larger
than 15, you should adjust the frame number.
Segment Length
The Segment Length field gives a segment's length in bytes. This length
may be zero. If it is, the linker does not delete the segment from the
module. The Segment Length field is only large enough to hold numbers from
0 to 64K-1, inclusive. To give the segment a length of 64K, you must use
the B attribute bit in the ACBP field (see Segment ATTR in this section).
Segment Name Index
The segment name is a name that a programmer or translator assigns to the
segment; for example, CODE, DATA, MODULENAME_CODE, TAXDATA, or STACK. The
Segment Name Index field provides the segment name by indexing into the
list of names provided by the LNAMES record.
Class Name Index
The class name is a name that a programmer or translator assigns to a
segment. If none is assigned, the name is null and has a length of zero.
The purpose of a class name is to let the programmer define a "handle" to
order the LSEGs in MAS; for example, RED, WHITE, BLUE; or ROM, FASTRAM,
DISPLAYRAM. The Class Name Index field provides the class name by indexing
into the list of names provided by the LNAMES record.
Overlay Name Index
The overlay name is a name that the translator and/or the linker, at the
programmer's request, applies to a segment. The overlay name, like the
class name, may be null. The Overlay Name Index field provides the overlay
name by indexing into the list of names provided by the LNAMES record.
──────────────────────────────────────────────────────────────────────────
Note
Microsoft language linkers (versions 3.00 and later) ignore the Overlay
Name Index field, but the standard MS-DOS linker supports it.
──────────────────────────────────────────────────────────────────────────
7.5.6 Group Definition Record (GRPDEF)
┌─────┬──────────┬─────///────┬────///─────┬─────┐
│ │ │ │ │ │
│ REC │ Record │ Group │ Group │ CHK │
│ TYP │ Length │ Name │ Component │ SUM │
│ 9AH │ │ Index │ Descriptor │ │
│ │ │ │ │ │
└─────┴──────────┴──///───────┤──///───────┼─────┘
│ │
└──repeated──┘
Group Name Index
The linker may reference a collection of LSEGs with the group name. Most
importantly, when the LSEGs are eventually fixed in MAS, a frame must
exist that "covers" every LSEG of the group.
The Group Name Index field provides the group name by indexing into the
list of names provided by the LNAMES record.
Group Component Descriptor
This repeatable field has the following format:
┌─────┬────///────┐
│ │ │
│ FFH │ Segment │
│ │ Index │
│ │ │
│ │ │
└─────┴────///────┘
The first byte of the Group Component Descriptor field contains 0FFH; the
descriptor contains one field, which is a segment index that selects the
LSEG described by a preceding SEGDEF record.
7.5.7 Public Names Definition Record (PUBDEF)
┌────┬──────────┬────///──┬───///───┬───────┬──///──┬─────┐
│ │ │ │ │ │ │ │
│ REC│ Record │ Public │ Public │Public │ Type │ CHK │
│ TYP│ Length │ Base │ Name │Offset │ Index │ SUM │
│ 90H│ │ │ │ │ │ │
│ │ │ │ │ │ │ │
└────┴──────────┴────///──┼──///────┴───────┴─///───┼─────┘
│ │
└─────────repeated────────┘
The PUBDEF record provides a list of one or more public names. For each
name, three kinds of data are provided: (1) a base value for the name, (2)
the offset value of the name, and (3) the type of entity represented by
the name.
Public Base
The Public Base field has the following format:
┌────///────┬────///────┬───────────┐
│ │ │ │
│ Group │ Segment │ Frame │
│ Index │ Index │ Number │
│ │ │ │
└────///────┴────///────┼───────────┤
│ │
└conditional┘
The Group Index field has a format, which was given earlier, and contains
a number between 0 and 32,767, inclusive. A nonzero value in the Group
Index field associates a group with the public symbol and is used as
described in case (F2c) of Section 7.3, "Conceptual Framework for
Fixups." A zero value in the Group Index field indicates that there is no
associated group.
The Segment Index field has a format, which was given earlier, and
contains a number between 0 and 32,767, inclusive.
A nonzero value in the Segment Index field selects an LSEG. In this case,
the location of each public symbol defined in the record is taken as a
nonnegative displacement (given by a Public Offset field) from the first
byte of the selected LSEG. Also, the Frame Number field must be absent.
A zero value in the Segment Index field means that the defined symbols are
absolute, and that the absolute addresses of the symbols are the values in
the Public Offset field. The Group Index field is ignored. The Frame
Number field contains a frame number only if the value of the Segment
Index field is zero. The linker ignores this field.
A nonzero value in the Group Index field selects some group. This group is
taken as the "frame of reference" for references to all public symbols
defined in this record. That is, the linker performs the following
actions:
■ The linker converts any fixup of the form:
Target: EI(P)
Frame: Target
(where P is a public symbol in this PUBDEF record) to a fixup of the
form:
Target: SI(L),d
Frame: GI(G)
where SI(L) and d are provided by the Segment Index and Public Offset
fields. (The "normal" action would have the frame specifier in the new
fixup be the same as in the old fixup: Frame:Target.)
■ When the linker converts the value of a public symbol, as defined by
the Segment Index, Public Offset, and (optionally) Frame Number fields,
to a {base,offset} pair, the base part is the base of the indicated
group.
A zero value in the Group Index field selects no group. The linker does
not alter the frame specification of fixups referencing the symbol, and
takes, as the base part of the absolute value of the public symbol, the
canonic frame of the segment (either LSEG or PSEG) determined by the
Segment Index field.
Public Name
The Public Name field gives the name of the object whose location in MAS
is made available to other modules by the linker. The name must contain
one or more characters.
Public Offset
The Public Offset field is a 16-bit value. It is either the offset of the
public symbol with respect to an LSEG (if the segment index is greater
than zero), or the offset of the public symbol with respect to the
specified frame (if the segment index is equal to zero).
Type Index
The Type Index field identifies a single preceding TYPDEF (Type Definition
Record), which contains a descriptor for the type of entity represented by
the public symbol. The linker ignores this field.
7.5.8 Communal Names Definition Record (COMDEF)
┌─────┬─────┬────///────┬────///────┬──────┬──────────┬─────┐
│ │ │ │ │ │ │ │
│ REC │ REC │ Communal │ Type │ Data │ Communal │ CHK │
│ TYP │ LEN │ Name │ Index │ Seg │ Length │ SUM │
│ B0H │ │ │ │ Type │ │ │
│ │ │ │ │ │ │ │
└─────┴─────┼────///────┴────///────┴──────┴──────────┼─────┴
│ │
└───────repeated──────────────────────────┘
The COMDEF record provides a list of one or more Communal Names, which
define communal variables. A communal variable is an uninitialized public
variable whose final size and location are not fixed during compiling.
Communal variables are similar to FORTRAN common blocks in that if you are
linking object modules that each declare a communal variable, then the
size of that variable is the largest of the declared variables. In the C
language, all uninitialized public variables are communal. The following
example shows three different declarations of the same C communal
variable:
char foo[4]; /* In file a.c */
char foo[1]; /* In file b.c */
char foo[1024]; /* In file c.c */
If the objects produced from a.c, b.c, and c.c are linked together, the
linker allocates 1024 bytes for the character array "foo."
──────────────────────────────────────────────────────────────────────────
Note
This record requires that a COMENT record from the Microsoft Extensions
class appear before it in the object module.
──────────────────────────────────────────────────────────────────────────
Communal Name
The Communal Name field gives the communal variable name and must contain
one or more characters.
Communal names are treated as external names when an external name is
requested elsewhere in the module. Communal names are ordered together
with external names for the purpose of referring to an external name by
its index. (See the description of the EXTDEF record later in this
section for more details on external names.)
Type Index
The Type Index field is ignored by the Microsoft linker.
Data Segment Type
The Data Segment Type field is a single byte that describes the data
segment in which the communal variable resides. It can contain the
following values:
62H (NEAR) = the communal variable is in the default data segment.
61H (FAR) = the communal variable is not in the default data segment.
Communal Length
The Communal Length field describes the length of the communal variable
according to its data segment type.
If its value is NEAR (62H), the field represents the length in bytes.
If its value is FAR (61H), the field represents:
┌─────//────┬─────///──────┐
│ Number of │ Element size │
│ elements │ in bytes │
└────///────┴─────///──────┘
The format of all the length fields is as follows:
┌─────┐
│ │
│ 0 │
│ to │
│ 127 │
│ │
└─────┘
┌─────┬───────────┐
│ │ │
│ │ 0 │
│ 129 │ to │
│(81H)│ 64K-1 │
│ │ │
└─────┴───────────┘
┌─────┬─────────────────┐
│ │ │
│ │ 0 │
│ 132 │ to │
│(84H)│ 16M-1 │
│ │ │
└─────┴─────────────────┘
┌─────┬─────────────────┐
│ │ │
│ │ -2G-1 │
│ 136 │ to │
│(88H)│ 2G-1 │
│ │ │
└─────┴─────────────────┘
The first format (single byte), containing a value between 0 and 127,
represents the number given.
The second format, with a leading byte containing 129, represents the
number contained in the following two bytes.
The third format, with a leading byte containing 132, represents the
number contained in the following three bytes.
The fourth format, with a leading byte containing 136, represents the
number contained in the following four bytes with its sign extended if
necessary.
Link-Time Semantics
A PUBDEF matching a communal variable definition overrides the communal
variable definition. Two communal variable definitions match if the names
in their definitions match. If two matching definitions disagree on
whether a communal variable is NEAR or FAR, the linker assumes the
variable is NEAR.
If the variable is NEAR, then its size is the largest of the sizes
specified for it. If the variable is FAR, the linker issues a warning if
the array element sizes conflict. If these sizes don't conflict, the
variable's size is the element size multiplied by the largest number of
elements specified. In addition, the sum of the sizes of all NEAR
variables must not exceed 64 kilobytes, and the sum of the sizes of all
FAR variables must not exceed the size of the machine's addressable memory
space.
HUGE Communal Variables:
A FAR communal variable that is larger than 64 kilobytes (a HUGE communal
variable) resides in segments that are contiguous (on an 8086) or that
have consecutive selectors (on an 80286). No other data items reside in
the segments occupied by a HUGE communal variable.
If the linker finds matching HUGE and NEAR communal variable definitions,
it issues a warning message, since it is impossible for a NEAR variable to
be larger than 64 kilobytes.
7.5.9 Local Symbols Record (LOCSYM)
┌────┬──────────┬────///──┬───///───┬───────┬──///──┬─────┐
│ │ │ │ │ │ │ │
│ REC│ Record │ Local │ Local │ Local │ Type │ CHK │
│ TYP│ Length │ Base │ Name │Offset │ Index │ SUM │
│ 92H│ │ │ │ │ │ │
│ │ │ │ │ │ │ │
└────┴──────────┴────///──┼──///────┴───────┴─///───┼─────┘
│ │
└─────────repeated────────┘
The LOCSYM record provides information for the definition of a local
symbol, one that is visible only within the module in which it is defined.
The form and meaning of each of the fields is identical to those in the
PUBDEF record.
──────────────────────────────────────────────────────────────────────────
Note
The LOCSYM record requires that a COMENT record from the Microsoft
Extensions class appear before it in the object module. Also, it is only
recognized by Microsoft language linkers later than version 3.07.
──────────────────────────────────────────────────────────────────────────
7.5.10 External Names Definition Record (EXTDEF)
┌─────┬───────────┬────///────┬────///────┬─────┐
│ │ │ │ │ │
│ REC │ Record │ External │ Type │ CHK │
│ TYP │ Length │ Name │ Index │ SUM │
│ 8CH │ │ │ │ │
│ │ │ │ │ │
└─────┴───────────┼────///────┴────///────┼─────┘
│ │
└───────repeated────────┘
The EXTDEF record provides a list of external names and, for each name,
the type of object it represents. The linker assigns to each external name
the value provided by an identical public name or local name (if such a
name is found).
External Name
The External Name field provides the external object name, which must have
a nonzero length.
Including a name in an EXTDEF record is an implicit request to link the
object file to a module containing the same name declared as a public
symbol, unless the name is defined as a local symbol within the same
module as the EXTDEF. This request determines whether or not the external
name is referenced within some FIXUPP record in the module.
The order of EXTDEF records in a module and the order of external names
within each EXTDEF record, together with COMDEF records and communal
names, imply a mapping on the set of all external names requested by the
module; for example: 1, 2, 3, etc. So to refer to a particular external
name, the linker uses these numbers as "external indices" in the Target
Datum and/or Frame Datum fields of FIXUPP records.
External indices may not reference forward. For example, an EXTDEF
defining the kth object must precede any record referring to that object
with index k.
Type Index
The Type Index field is ignored by the Microsoft linker, except for linker
versions earlier than 3.05, and for object modules lacking the COMENT
record from the Microsoft Extensions class. For that case, refer to
Section 7.6, "Microsoft Type Representations for Communal Variables."
7.5.11 Line Numbers Record (LINNUM)
┌─────┬──────────┬─────///───┬───────────┬───────────┬─────┐
│ │ │ │ │ │ │
│ REC │ Record │ Line │ Line │ Line │ CHK │
│ TYP │ Length │ Number │ Number │ Number │ SUM │
│ 94H │ │ Base │ │ Offset │ │
│ │ │ │ │ │ │
└─────┴──────────┴────///────┼───────────┴───────────┼─────┘
│ │
└────────repeated───────┘
The LINNUM record allows a translator to relate a line number in source
code to the corresponding line in translated code.
Line Number Base
The Line Number Base field has the following format:
┌────///────┬────///────┐
│ │ │
│ Group │ Segment │
│ Index │ Index │
│ │ │
└────///────┴────///────┘
The Group Index field is ignored by the Microsoft linker.
The Segment Index field determines the location of the first byte of code
corresponding to some source line number.
Line Number
The Line Number field provides a binary line number between 0 and 32,767,
inclusive. If the high-order bit is not zero, the number is considered
undefined.
Line Number Offset
The Line Number Offset field is a 16-bit value, which is the offset of the
line number with respect to an LSEG (if the segment index is greater than
zero).
7.5.12 Logical Enumerated Data Record (LEDATA)
┌─────┬───────────┬────///────┬───────────┬─────┬─────┐
│ │ │ │ │ │ │
│ REC │ Record │ Segment │ Enumerated│ │ CHK │
│ TYP │ Length │ Index │ Data │ DAT │ SUM │
│ A0H │ │ │ offset │ │ │
│ │ │ │ │ │ │
└─────┴───────────┴────///────┴───────────┼─────┼─────┘
│ │
└─rpt─┘
The LEDATA record provides contiguous data from which the linker may
construct a portion of an 8086 memory image.
Segment Index
The Segment Index field, which must be nonzero, specifies an index
relative to the SEGDEF records that precede the LEDATA record.
Enumerated Data Offset
The Enumerated Data Offset field specifies an offset that is relative to
the base of the LSEG specified by the segment index. The field also
defines the relative location of the first byte of the DAT field.
Successive data bytes in the DAT field occupy successively higher
locations of memory.
DAT
The DAT field provides up to 1024 consecutive bytes of relocatable or
absolute data.
7.5.13 Logical Iterated Data Record (LIDATA)
┌─────┬──────────┬────///────┬───────────┬────///────┬─────┐
│ │ │ │ │ │ │
│ REC │ Record │ Segment │ Iterated │ Iterated │ CHK │
│ TYP │ Length │ Index │ Data │ Data │ SUM │
│ A2H │ │ │ Offset │ Block │ │
│ │ │ │ │ │ │
└─────┴──────────┴────///────┴───────────┼────///────┼─────┘
│ │
└─repeated──┘
The LIDATA record provides contiguous data from which the linker may
construct a portion of an 8086 memory image.
Segment Index
The Segment Index field, which must be nonzero, specifies an index that is
relative to the SEGDEF records that precede the LIDATA record.
Iterated Data Offset
The Iterated Data Offset field specifies an offset that is relative to the
base of the LSEG specified by the segment index. It also defines the
relative location of the first byte in the iterated data block. Successive
data bytes in the iterated data block occupy successively higher locations
of memory.
Iterated Data Block
This repeated field is a structure specifying the repeated data bytes. It
has the following format:
┌──────────┬────────────┬────///────┐
│ │ │ │
│ Repeat │ Block │ │
│ Count │ Count │ Content │
│ │ │ │
│ │ │ │
└──────────┴────────────┴────///────┘
──────────────────────────────────────────────────────────────────────────
Note
The linker cannot handle LIDATA records whose iterated data blocks are
larger than 512 bytes.
──────────────────────────────────────────────────────────────────────────
Repeat Count:
The Repeat Count field specifies the number of times to repeat the Content
portion of this iterated data block. The value of the Repeat Count field
must be nonzero.
Block Count:
The Block Count field specifies the number of iterated data blocks in the
Content portion of this iterated data block. If the Block Count field has
a value of zero, the Content portion of the iterated data block is
interpreted as data bytes. If the field is nonzero, the Content portion is
interpreted as that number of iterated data blocks.
Content:
The Content field may be interpreted in one of two ways, depending on the
value of the previous Block Count field.
If the Block Count field is zero, this field is a 1-byte count followed by
the indicated number of data bytes. But if the Block Count field is
nonzero, the Content field is interpreted as the first byte of another
iterated data block.
7.5.14 Fixup Record (FIXUPP)
┌─────┬───────────┬────///────┬─────┐
│ │ │ │ │
│ REC │ Record │ Thread │ CHK │
│ TYP │ Length │ or │ SUM │
│ 9CH │ │ Fixup │ │
│ │ │ │ │
└─────┴───────────┼────///────┼─────┘
│ │
└────rpt────┘
The FIXUPP record specifies zero or more fixups. Each fixup requests a
modification (fixup) to a location within the previous data record. A data
record may be followed by more than one FIXUPP record that refers to it.
Each fixup is specified by a Fixup field that specifies four kinds of
data: a location, a mode, a target, and a frame. The frame and target may
be specified completely within the Fixup field, or by reference to a
preceding Thread field.
A Thread field specifies a default target or frame that subsequently may
be referred to. Eight threads are provided──four for frame specification
and four for target specification. Once a thread has specified a target or
frame, any Fixup fields that follow (in the same or following FIXUPP
records) may refer to that target or frame until another Thread field with
the same type (target or frame) and thread number (0-3) appears (in the
same or in another FIXUPP record).
Thread
The Thread field has the following format:
┌─────┬────///────┐
│ │ │
│ TRD │ Index │
│ DAT │ │
│ │ │
└─────┼────///────│
│ │
└condiional─┘
The TRD DAT (Thread Data) field is a byte with the following internal
structure:
┌───┬───┬───┬───────────┬───────┐
│ │ │ │ │ │
│ 0 │ D │ 0 │ Method │ THRED │
│ │ │ │ │ │
└───┴───┴───┴───────────┴───────┘
The D field is one bit and defines the type of thread being used. If D=0,
this bit defines a target thread, and if D=1, it defines a frame thread.
Method is a 3-bit field containing a number between 0 and 3 (if D=0) or a
number between 0 and 6 (if D=1).
If D=0, then Method = (0, 1, 2, 4, 5, 6)mod 4, where 0, 1, 2, 4, 5, 6
indicate methods T0, T1, T2, T4, T5, and T6 of specifying a target. Thus,
Method indicates the kind of index or frame number required to specify the
target, without indicating whether the target is specified by a primary or
secondary method.
If D=1, then Method = 0, 1, 2, 4, 5, corresponding to methods F0, F1, F2,
F4, F5 of specifying a frame. Here, Method indicates the kind (if any) of
index required to specify the frame.
The THRED field contains a number between 0 and 3, inclusive, and
associates a thread number to the frame or target defined by the Thread
field.
The Index field contains a segment index, group index, or external index
depending on the specification in the Method field. If Method specifies F4
or F5, this field will not be present.
Fixup
The Fixup field has the following format:
┌───────────┬─────┬────///────┬────///────┬────///────┐
│ │ │ │ │ │
│ LOCAT │ FIX │ Frame │ Target │ Target │
│ │ DAT │ Datum │ Datum │ Dis- │
│ │ │ │ │ Placement │
│ │ │ │ │ │
└───────────┴─────┼────///────┼────///────┼────///────│
│ │ │ │
└────────────conditional────────────┘
The LOCAT field is a byte pair with the following format:
┌───┬───┬───┬───────────┬───────────────────────────────────────┐
│ │ │ │ │ │
│ 1 │ M │ 0 │ LOC │ D a t a R e c o r d O f f s e t │
│ │ │ │ │ │
├───┴───┴───┴───────────┴───────┬───────────────────────────────┤
│ │ │
└────────────lo byte────────────┴────────────hi byte────────────┘
M is a 1-bit field that specifies the mode of the fixups: self-relative
(if M=0) or segment-relative (if M=1).
──────────────────────────────────────────────────────────────────────────
Note
Self-relative fixups may not be applied to LIDATA records.
──────────────────────────────────────────────────────────────────────────
LOC is a 3-bit field indicating that the byte(s) in the preceding data
record to be fixed up are a lobyte (if LOC=0), an offset (if LOC=1), a
base (if LOC=2), a pointer (if LOC=3), a hibyte (if LOC=4), or a
"loader-resolved" offset (if LOC=5). Any other values in LOC are invalid.
The Data Record Offset field contains a number between 0 and 1023,
inclusive, that gives the relative position of the lowest order byte of
location (the actual bytes being fixed up) within the preceding data
record. The Data Record Offset value is relative to the first byte in the
data fields in the data records.
──────────────────────────────────────────────────────────────────────────
Note
If the preceding data record is an LIDATA record, it is possible for the
Data Record Offset value to designate a location within a Repeat Count
field or a Block Count field of the Iterated Data Block field. Such a
reference is an error. The linker's action on such a malformed record is
undefined.
──────────────────────────────────────────────────────────────────────────
The FIX DAT field is a byte with the following format:
┌───┬───────────┬───┬───┬───────┐
│ │ │ │ │ │
│ F │ Frame │ T │ P │ TARGT │
│ │ │ │ │ │
└───┴───────────┴───┴───┴───────┘
F is a 1-bit subfield that specifies whether the frame for this fixup is
specified by a thread (if F=1) or explicitly (if F=0).
The Frame field contains a number that is interpreted in one of two ways,
as indicated by the F bit. If F is zero, the Frame field contains a number
between 0 and 5, inclusive, corresponding to methods F0,...,F5 for
specifying a frame. If F=1, then the Frame field contains a thread number
(0-3). It specifies the frame most recently defined by a Thread field that
defined a frame thread with the same thread number. (Notice that the
Thread field may appear in the same FIXUPP record, or in an earlier one.)
T is a 1-bit field that specifies whether the target specified for this
fixup is defined by reference to a thread (T=1), or is given explicitly in
the Fixup field (T=0).
P is a 1-bit field that indicates whether the Target is specified by a
primary method (requires a target displacement, if P=0) or by a secondary
method (requires no target displacement, if P=1). Since a target thread
does not have a primary/secondary attribute, the P bit is the only field
that contains the target specification attribute.
TARGT is interpreted as a 2-bit field. When T=0, it provides a number
between 0 and 3, inclusive, corresponding to methods T0, T1, T2 or T4, T5,
T6, depending on the value of P (where P is interpreted as the high-order
bit of T0, T1, T2, T4, T5, or T6). When a thread specifies the target (if
T=1), then the TARGET field specifies a thread number (0-3).
The Frame Datum field is the "referent" portion of a frame specification,
and is a segment index, group index, or external index. The Frame Datum
field is present only when the frame is not specified by a thread (if F=0)
or explicitly by methods F4, F5, or F6.
The Target Datum field is the "referent" portion of a target
specification, and is a segment index, group index, or external index. The
Target Datum field is present only when a thread does not specify the
target (if T=0).
The Target Displacement field is the 2-byte displacement required by
primary methods of specifying targets. This field is present if P=0.
──────────────────────────────────────────────────────────────────────────
Note
All these methods are described in Section 7.3, "Conceptual Framework
for Fixups."
──────────────────────────────────────────────────────────────────────────
7.5.15 Module End Record (MODEND)
┌─────┬───────────┬─────┬────///────┬─────┐
│ │ │ │ │ │
│ REC │ Record │ MOD │ START │ CHK │
│ TYP │ Length │ TYP │ ADDRS │ SUM │
│ 8AH │ │ │ │ │
│ │ │ │ │ │
└─────┴───────────┴─────┼────///────┼─────┘
│ │
└conditional┘
The MODEND record serves two purposes. It denotes the end of a module and
indicates whether or not the module that just ended specifies an entry
point to begin execution. If it does not, the linker specifies the
execution address.
MOD TYP
The MOD TYP field specifies the attributes of the module. The bit
allocation and associated meanings are as follows:
┌───────┬───┬───┬───┬───┬───┬───┐
│ │ │ │ │ │ │ │
│ MATTR │ 0 │ 0 │ 0 │ 0 │ 0 │ 1 │
│ │ │ │ │ │ │ │
└───────┴───┴───┴───┴───┴───┴───┘
MATTR is a 2-bit field that specifies the following module attributes:
MATTR Module Attribute
──────────────────────────────────────────────────────────────────────────
0 Non-main module with no START ADDRS
1 Non-main module with START ADDRS
2 Main module with no START ADDRS
3 Main module with START ADDRS
──────────────────────────────────────────────────────────────────────────
The START ADDRS field (present only if MATTR is 1 or 3) has the following
format:
┌─────┬────///────┬────///────┬───────────┐
│ │ │ │ │
│ END │ Frame │ Target │ Target │
│ DAT │ Datum │ Datum │ Dis- │
│ │ │ │ Placement │
│ │ │ │ │
└─────┼────///────┴────///────┴───────────│
│ │
└────────────conditional────────────┘
The starting address of a module has all the attributes of any other
logical reference found in a module. The mapping of a logical starting
address to a physical starting address is done in the same manner as
mapping any other logical address to a physical address, as specified in
the discussion of fixups and the FIXUPP record. The fields of the START
ADDRS field have the same semantics as the FIX DAT, Frame Datum, Target
Datum, and Target Displacement fields in the FIXUPP record. Only primary
fixup methods are allowed. Frame method F4 is not allowed.
7.5.16 Comment Record (COMENT)
┌─────┬───────────┬───────────┬────///────┬─────┐
│ │ │ │ │ │
│ REC │ Record │ Comment │ │ CHK │
│ TYP │ Length │ Type │ Comment │ SUM │
│ 88H │ │ │ │ │
│ │ │ │ │ │
└─────┴───────────┴───────────┴────///────┴─────┘
The COMENT record allows translators to include comments in object text.
Comment Type
The Comment Type field indicates the type of comment that this record
carries, allowing you to structure comments for processes that selectively
act on comments.
The format of the Comment Type field is as follows:
┌───┬───┬───┬───┬───┬───┬───┬───┬──────────────────────┐
│ N │ N │ │ │ │ │ │ │ Comment │
│ P │ L │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │ Class │
└───┴───┴───┴───┴───┴───┴───┴───┴──────────────────────┘
The NP (NOPURGE) bit, if set to 1, indicates that this comment cannot be
purged by object file utility programs that can delete Comment records.
The NL (NOLIST) bit, if set to 1, indicates that the text in the Comment
field should not appear in the listing file of object file utility
programs that can list object Comment records.
The Comment Class field is a byte defined as follows:
╓┌─┌──────────────────┌──────────────────────────────────────────────────────╖
Value Meaning
──────────────────────────────────────────────────────────────────────────
0 Language Translator Comment (obsolete)
If the Comment field contains one of the strings "MS
PASCAL" or "FORTRAN 77," then the Comment record
enables the dsallocation switch on the Microsoft
linker.
Value Meaning
──────────────────────────────────────────────────────────────────────────
linker.
156(9CH) DOS Version
The Comment field contains a 2-byte integer that
specifies the DOS level number.
157(9DH) Memory Model
Indicates the memory model of the object module. The
Comment field contains a single byte with the values S,
M, L, or H, for SMALL, MEDIUM, LARGE, or HUGE,
respectively. This Comment record is used only by the
Microsoft XENIX linker.
158(9EH) Force Segment Ordering
Causes the linker to use a special segment ordering for
executable files. This Comment record has the same
Value Meaning
──────────────────────────────────────────────────────────────────────────
executable files. This Comment record has the same
effect as giving the dosseg switch to Microsoft
language versions of the linker.
159(9FH) Library Specifier
129(81H) Library Specifier (obsolete)
Specifies a library to add to the Microsoft linker's
library search list. The Comment field contains the
name of the library. Notice that, unlike all other name
specifications, the library name is not prefixed with
its length but is determined by the record length. The
nodefaultlibrarysearch switch causes the linker to
ignore these Comment records. The 159(9FH) class record
is ignored by XENIX versions of the Microsoft linker.
161(A1H) Microsoft Extensions
Value Meaning
──────────────────────────────────────────────────────────────────────────
Indicates that the object module contains extensions to
the original Microsoft adaptation of the Intel
Relocatable Object Module Format, such as the COMDEF
──────────────────────────────────────────────────────────────────────────
Comment
The Comment field provides the commentary information.
7.6 Microsoft Type Representations for Communal Variables
──────────────────────────────────────────────────────────────────────────
Note
Object modules not containing the COMENT record from the Microsoft
Extensions class can represent communal variable definitions only with
the obsolete method described here. Also, Microsoft language linkers
earlier than version 3.05 can recognize this method only. The newer
method uses the Communal Variable Definitions (COMDEF) record.
──────────────────────────────────────────────────────────────────────────
A communal variable is defined in the object text by an EXTDEF record and
the TYPDEF record to which it refers.
The TYPDEF record of a communal variable has the following format:
┌─────┬────────┬───┬─────///────┬─────┐
│ REC │ Record │ │ Eight │ CHK │
│ TYP │ Length │ 0 │ Leaf │ SUM │
│ 8EH │ │ │ Descriptor │ │
└─────┴────────┴───┴─────///────┴─────┘
The Eight Leaf Descriptor field has the following format:
┌───┬────///─────┐
│ E │ Leaf │
│ N │ Descriptor │
└───┴────///─────┘
The EN bitfield specifies whether the next eight leaves in the Leaf
Descriptor field are EASY (if EN = 0) or NICE (if EN = l). This byte is
always zero for TYPDEFs of communal variables. The Leaf Descriptor field
has one of the following two formats. The format for communal variables in
the default data segment (NEAR variables) is as follows:
┌──────┬─────┬────///───┬─///────┐
│ NEAR │ VAR │ Length │ VAR │
│ 62H │ TYP │ In │ SUBTYP │
│ │ │ Bits │ │
└──────┴─────┴────///───┼──///───┤
│ │
└────────┘
(optional)
The VARTYP (Variable Type) field may be either SCALAR (7BH), STRUCT (79H),
or ARRAY (77H). The linker ignores the VAR SUBTYP field (if one exists).
The format for communal variables not in the default data segment (FAR
variables) is as follows:
┌─────┬─────┬────///───┬───///───┐
│ FAR │ VAR │ Number │ Element │
│ 61H │ TYP │ of │ Type │
│ │ 77H │ Elements │ Index │
└─────┴─────┴────///───┴───///───┘
The VARTYP field must be ARRAY (77H). The Length in Bits field specifies
the Number of Elements, and the Element Type Index is an index to a
previously defined TYPDEF record whose format is that of a NEAR communal
variable.
The format for the Length in Bits or Number of Elements fields is the same
as the format of the Communal Length field of the COMDEF record.
Link-Time Semantics
All EXTDEF records referencing a TYPDEF record of one of the previously
described formats are treated as communal variables. All others are
treated as externally defined symbols for which a matching PUBDEF record
is expected.
For more information, see "Link-Time Semantics" in Section 7.5.8,
"Communal Names Definition Record (COMDEF)."
────────────────────────────────────────────────────────────────────────────
Chapter 8 Programming Hints
8.1 Introduction
8.2 Interrupts
8.3 System Calls
8.4 Device Management
8.5 Memory Management
8.6 Process Management
8.7 File and Directory Management
8.7.1 Locking Files
8.8 Miscellaneous
8.1 Introduction
This chapter describes recommended MS-DOS 4.0 programming procedures. By
using these programming hints, you can ensure compatibility with future
versions of MS-DOS.
The hints are organized in the following categories:
■ Interrupts
■ System Calls
■ Device Management
■ Memory Management
■ Process Management
■ File and Directory Management
■ Miscellaneous
8.2 Interrupts
■ Never explicitly issue Interrupt 22H (Terminate Process Exit Address).
Only the DOS should do this. To change the terminate address, use
Function 35H (Get Interrupt Vector) to get the current address and
save it, then use Function 25H (Set Interrupt Vector) to change the
Interrupt 22H entry in the vector table to point to the new terminate
address.
■ Use Interrupt 24H (Critical-Error-Handler Address) with care. The
Interrupt 24H handler must preserve the ES register.
An Interrupt 24H handler can issue only the system calls 01H-0CH.
Making any other calls destroys the MS-DOS stack and prevents
successful use of the Retry or Ignore options.
When using the Retry or Ignore options, you must preserve the SS, SP,
DS, BX, CX, and DX registers.
■ When an Interrupt 24H (Critical-Error-Handler Address) is received,
always IRET back to MS-DOS with one of the standard responses.
Programs that do not IRET from Interrupt 24H leave the system in an
unpredictable state until a function call other than 01H-0CH is made.
The Ignore option may leave incorrect or invalid data in internal
system buffers.
■ Avoid trapping Interrupt 23H (CONTROL+C Handler Address) and Interrupt
24H (Critical-Error-Handler Address). Don't rely on trapping errors
via Interrupt 24H as part of a copy protection scheme.
These methods might not be included in future releases of MS-DOS.
■ A user program must never issue Interrupt 23H (CONTROL+C Handler
Address).
Only MS-DOS may issue Interrupt 23H.
■ Save any registers that your program uses before issuing Interrupt
25H (Absolute Disk Read) or Interrupt 26H (Absolute Disk Write).
These interrupts destroy all registers except for the segment
registers.
Avoid writing or reading an interrupt vector directly to or from
memory.
■ Use Functions 25H and 35H (Set Interrupt Vector and Get Interrupt
Vector) to set and get values in the interrupt table.
8.3 System Calls
■ Use new system calls.
Avoid using system calls that have been superseded by new calls unless
the program must maintain backward compatibility with MS-DOS versions
before 2.0. See Section 1.9, "Old System Calls," for a list of these
new calls.
■ Avoid using functions 01H-0CH and 26H (Create New PSP).
Use the new "tools" approach for reading and writing on standard input
and output. Use Function 4B00H or 4B03H (Load and Execute Program or
Overlay) instead of 26H to execute a child process.
■ Use file-sharing calls if more than one process is in effect.
For more information, see "File Sharing" in Section 1.5.2,
"File-Related Function Requests."
■ Use networking calls where appropriate.
Some forms of IOCtl can only be used with Microsoft Networks. For more
information and a list of these calls, see Section 1.6, "Microsoft
Networks."
■ When selecting a disk with Function 0EH (Select Disk), treat the value
returned in AL with care.
The value in AL specifies the maximum number of logical drives; it does
not specify which drives are valid.
8.4 Device Management
■ Use installable device drivers.
MS-DOS provides a modular device driver structure for the BIOS,
allowing you to configure and install device drivers at boot time.
Block device drivers transmit a block of data at a time, while
character device drivers transmit a byte of data at a time.
Examples of both types of device drivers are given in Chapter 2,
"MS-DOS Device Drivers."
■ Use buffered I/O.
The device drivers can handle streams of data up to 64 kilobytes. To
improve performance when sending a large amount of output to the
screen, you can send it with one system call.
■ Programs that use direct console I/O via Function 06H and 07H (Direct
Console I/O and Direct Console Input) and that want to read CONTROL+C
as data should ensure that CONTROL+C checking is off.
The program should ensure that CONTROL+C checking is off by using
Function 33H (CONTROL+C Check).
■ Be compatible with international support.
To provide support for international character sets, MS-DOS recognizes
all possible byte values as significant characters in filenames and
data streams. MS-DOS versions earlier than 2.0 ignored the high bit in
the MS-DOS filename.
8.5 Memory Management
■ Use memory management.
MS-DOS keeps track of allocated memory by writing a memory control
block at the beginning of each area of memory. Programs should use
Functions 48H (Allocate Memory), 49H (Free Allocated Memory), and
4AH (Set Block) to release unneeded memory.
This allows for future compatibility. For more information, see Section
1.3, "Memory Management."
■ Use only allocated memory.
Don't directly access memory that was not provided as a result of a
system call. Do not use fixed addressing, use only relative references.
A program that uses memory that has not been allocated to it may
destroy other memory control blocks or cause other applications to
fail.
8.6 Process Management
■ Use Function 4B00H or 4B03H (Load and Execute Program or Overlay,
also known as EXEC) to load and execute programs.
EXEC is the preferred call to use when loading programs and program
overlays. Using the EXEC call instead of hard-coding information about
how to load a .exe file (or always assuming that your file is a .com
file) isolates your program from changes in .exe file formats and
future releases of MS-DOS.
■ Use Function 31H (Keep Process), instead of Interrupt 27H (Terminate
But Stay Resident).
Function 31H allows programs that are greater than 64 kilobytes to
terminate and stay resident.
■ Programs should terminate using Function 4CH (End Process).
Programs that terminate by one of the following must ensure that the CS
register contains the segment address of the PSP:
■ A long jump to offset 0 in the PSP
■ Issuing an Interrupt 20H with CS:0 pointing at the PSP
■ Issuing an Interrupt 21H with AH=0, CS:0 pointing at the PSP
■ A long call to location 50H in the PSP with AH=0
8.7 File and Directory Management
■ Use the MS-DOS file management system.
Using the MS-DOS file system ensures program compatibility with future
MS-DOS versions through compatible disk formats and consistent internal
storage.
■ Use file handles instead of FCBs.
A handle is a 16-bit number that MS-DOS returns when a file is opened
or created using Functions 3CH, 3DH, 5AH, or 5BH (Create Handle,
Open Handle, Create Temporary File, or Create New File). The MS-DOS
file-related function requests that use handles are listed in Table
1.5 in Chapter 1, "System Calls."
Although the default maximum number of open files is 20, this limit can
be raised to 64K by Function 67H (Set Handle Count). For more
information on this system call, see Chapter 1, "System Calls."
You should use these calls instead of the old file-related functions
that use FCBs (file control blocks). This is because a file operation
can simply pass its handle rather than maintaining FCB information. If
you must use FCBs, be sure the program closes them and does not move
them around in memory.
■ Close files that have changed in length before issuing an Interrupt
20H (Program Terminate), Function 00H (Terminate Program), Function
4CH (End Process), or Function 0DH (Reset Disk).
If you do not close a changed file, its length will not be recorded
correctly in the directory.
■ Close files when they are no longer needed.
Closing unneeded files increases efficiency in a networking
environment.
■ If a program does use FCBs, that program should not close an FCB file
and then continue writing to it. This practice will not work in a
network environment and is not recommended under any circumstances.
■ Change disks only if all files on the disk are closed.
If you don't close all the files, any information in internal system
buffers may be written incorrectly to a changed disk.
8.7.1 Locking Files
■ Programs should not rely on being denied access to a locked region.
To determine the status of a region, first attempt to lock it, then
examine its error code.
■ Programs should not close a file with a locked region or terminate with
an open file that contains a locked region.
The result of this procedure is undefined. Programs that might be
terminated by an Interrupt 23H or Interrupt 24H (CONTROL+C Handler
Address or Critical-Error-Handler Address) should trap these interrupts
and unlock any locked regions before exiting.
8.8 Miscellaneous
■ Avoid timing dependencies.
Various machines use CPUs of different speeds. Also, programs that rely
upon the speed of the clock for timing are not dependable in a
networking environment.
■ Use the documented interface to the operating system. If either the
hardware or media change, the operating system can use the features
without modification.
Don't use the ROM support provided by the OEM (Original Equipment
Manufacturer).
Don't directly address the video memory.
Don't use undocumented function calls, interrupts, or features.
These items may change or may not exist in future MS-DOS versions. If
you do use these features, you will make your program highly
non-portable.
■ Use the .exe format rather than the .com format.
.Exe files are relocatable; .com files are direct memory images that
load at a specific place and have no room for additional control
information. .Exe files have headers that can be expanded for
compatibility with future MS-DOS versions.
■ Use the environment to pass information to applications.
The environment allows a parent process to pass information to a child
process. The command.com file is usually the parent process to every
application, so it can easily pass default drive and path information
to the application.
────────────────────────────────────────────────────────────────────────────
Index
Numbers
80186 microprocessor
80286 microprocessor
8086 microprocessor
8086 object language
8086 object module format. See Object Module Formats (OMF)
A
Absolute Disk Read (Interrupt 25H)
Absolute Disk Write (Interrupt 26H)
Absolute segment, LSEG
ACBP byte, SEG ATTR
Address mode
Alignment attribute
Alignment subfield, SEG ATTR
Allocate Memory (Function 48H)
Application
Frame Number, protected-mode
Archive bit
Array, character
ASCII character set
ASCIZ string
Assign list
Attribute
primary
secondary
Target
Attribute byte
Attribute field
Attribute, LSEG
Alignment
Combination
SEG ATTR field, SEGDEF
AUTOEXEC file
Auxiliary Input (Function 03H)
Auxiliary Output (Function 04H)
B
base, definition
Big subfield, SEG ATTR
BIN format file
Binary line number
BIOS Parameter ^Block (BPB)
BIOS Parameter Block (BPB)
Bit 8
Bit 9
Bitfield
Block Count subfield, Iterated Data Block
Block devices
device drivers
disk drives
example
installation
Boot sector
BPB pointer
Buffered Keyboard Input (Function 0AH)
BUILD BPB
Build BPB
Busy bit
Byte, representation
C
C language
CALL instruction
Cancel Assign-List Entry (Function 5FH, Code 04H)
Canonic Frame
Canonic Frame, definition
Carry flag
Case-Mapping Call
Change Current Directory (Function 3BH)
Change Directory Entry (Function 56H)
Character array
Character device driver, example
Character devices
Character set
definition
Check Keyboard Status (Function 0BH)
CHKSUM field, SAMREC
Class Name, definition
CLOCK device
Close File (Function 10H)
Close Handle (Function 3EH)
Cluster
Code page
definition
Code segment, CS
Combination attribute
Combination subfield, SEG ATTR
COMDEF record
field
CHKSUM
Communal Length, repeated
Communal Name, repeated
Data Segment Type, repeated
Record Length
RECTYP
Type Index, repeated
length fields, format
order with respect to COMENT
purpose
schematic
COMENT record
field
CHKSUM
Comment
Comment Type
Record Length
RECTYP
order with respect to COMDEF
order with respect to LOCSYM
purpose
schematic
subfield of Comment Type
Comment Class
Command code field
Command processor
Command.com
Commands, utility, NLS
Comment class subfield, Comment Type
Comment field, COMENT
Comment record
Comment Record (COMENT)
Comment Type field, COMENT
bit settings
definition
format
Commit File (Function 68H)
Common blocks, FORTRAN
Communal Length field, COMDEF
Communal Name field, COMDEF
Communal Name, ordering with External Name
Communal names definition record. See COMDEF record
Communal Names Definition Record (COMDEF)
Communal variable
FAR
HUGE
NEAR
similarity to FORTRAN common block
uninitialized public variable
Compatibility, ensuring
Complete Name, definition
Computer language
C
FORTRAN
COMSPEC
Con device
config.sys
config.sys file
Content subfield, Iterated Data Block
Control blocks
Control information
CONTROL+C Address (Interrupt 23H)
CONTROL+C Check (Function 33H)
CONTROL+C Handler Address (Interrupt 23H)
Country code
definition
Country code, current
Country-dependent information
case conversion tables
collating sequence, character sorting
currency
date
DBCS environmental vector
keyboard support
time
valid single-byte characters
Country-dependent information, NLS
Country.sys file
Create Directory (Function 39H)
Create File (Function 16H)
Create Handle (Function 3CH)
Create New File (Function 5BH)
Create New PSP (Function 26H)
Create Temporary File (Function 5AH)
Critical Error Handler Address (Interrupt 24H)
CS register
D
DAT field, LEDATA
Data Record
Data segment
DS
ES
FAR
NEAR
Data Segment Type field, COMDEF
Delete Directory Entry (Function 41H)
Delete File (Function 13H)
Descriptor, Group Component, GRPDEF
Device control
Device drivers
block
creating
example
installable
installing
non-resident
preserving registers
resident
Device Handles
Device header
Device interrupt routine
Device management, programming hints
Device strategy routine
Device-related function requests
Direct Console Input (Function 07H)
Direct Console I/O (Function 06H)
Directory Entry
Directory-Related Function Requests
Directory-related function requests
Disk allocation
Disk Directory
Disk formats
IBM
standard MS-DOS
Disk Transfer Address (DTA)
Dispatch table
Display Character (Function 02H)
Display String (Function 09H)
Done bit
DS register
Duplicate File Handle (Function 45H)
E
Eight Leaf Descriptor field, TYPDEF
format
subfield
EN
Leaf Descriptor
Element Type Index subfield, Leaf Descriptor
EN subfield, Eight Leaf Descriptor
End address
End Process (Function 4CH)
Enumerated Data Offset field, LEDATA
Error bit
Error codes
Error Handling
Error handling
ES register
EXE device drivers
.exe files
exe files
EXE format file
EXE loader
EXTDEF record
field
CHKSUM
External Name, repeated
Record Length
RECTYP
Type Index, repeated
purpose
schematic
Extended error codes
Extended FCB
Extensions class, Microsoft
External Index
External indices
External Name
mapping
referenced in FIXUPP record
External Name field, EXTDEF
External names definition record. See EXTDEF record
External Names Definition Record (EXTDEF)
F
FAR data segment
FAR subfield, Leaf Descriptor
FAR variable format, Leaf Descriptor
FAT
FAT ID byte
FAT ID byte
FBVAL, definition
FCB
File Allocation Table
File and directory management, programming hints
File attributes
File Control Block
definition
extended
fields
format
opened
unopened
File locking, programming hints
Filename separators
Filename terminators
File-related function requests
File-sharing function requests
Find First File (Function 4EH)
Find Next File (Function 4FH)
FIX DAT subfield, Fixup
internal structure
schematic
Fixup
definition
Frame
Location
segment-relative
self-relative
Target
Fixup field, FIXUPP
data type
Frame
Location
Mode
Target
definition
schematic
subfield
LOCAT
Fixup mode
segment-relative
self-relative
FIXUP record
FIXUPP record
External Name referenced in
field
CHKSUM
Fixup, repeated
Frame Datum, conditional
Record Length
RECTYP
Target Datum, conditional
Thread, repeated
purpose
schematic
subfield of FIX DAT, Fixup
F
Frame
P
T
TARGT
subfield of Fixup
Frame Datum, conditional
Target Datum, conditional
Target Displacement, conditional
subfield of LOCAT, Fixup
Data Record Offset
LOC
M (mode)
subfield of Thread
Index, conditional
TRD DAT
subfield of TRD DAT, Thread
D
Method
THRED
FIXUPP Record (FIXUPP)
Flush
Flush Buffer, Read Keyboard (Function 0CH)
Force Duplicate File Handle (Function 46H)
Format
FORTRAN, common blocks
FORTRAN language
FOVAL, definition
Frame
definition
Frame Number
nomenclature
specifying
specifying, FIXUPP
Frame Datum field, FIXUPP
Frame Datum subfield, Fixup
External Index
Group Index
Segment Index
Frame Datum subfield, START ADDRS
Frame Number
Frame Number, conditional
Frame Number, definition
Frame Number subfield, Public Base
Frame Number subfield, SEG ATTR
Frames
Thread Number, FIXUPP
Free Allocated Memory (Function 49H)
Function Requests
alphabetic order
calling
definition
device-related
Directory-related
directory-related
file-related
file-sharing
Function 00H
Function 01H
Function 02H
Function 03H
Function 04H
Function 05H
Function 06H
Function 07H
Function 08H
Function 09H
Function 0AH
Function 0BH
Function 0CH
Function 0DH
Function 0EH
Function 0FH
Function 10H
Function 11H
Function 12H
Function 13H
Function 14H
Function 15H
Function 16H
Function 17H
Function 19H
Function 1AH
Function 1BH
Function 1CH
Function 21H
Function 22H
Function 23H
Function 24H
Function 25H
Function 26H
Function 27H
Function 28H
Function 29H
Function 2AH
Function 2BH
Function 2CH
Function 2DH
Function 2EH
Function 2FH
Function 30H
Function 31H
Function 33H
Function 35H
Function 36H
Function 38H
Function 39H
Function 3AH
Function 3BH
Function 3CH
Function 3DH
Function 3EH
Function 3FH
Function 40H
Function 41H
Function 42H
Function 43H
Function 44H, Code 08H
Function 44H, Code 09H
Function 44H, Code 0AH
Function 44H, Code 0BH
Function 44H, Code 0CH
Function 44H, Code 0DH
Function 44H, Codes 00H and 01H
Function 44H, Codes 02H and 03H
Function 44H, Codes 04H and 05H
Function 44H, Codes 06H and 07H
Function 44H, Codes 0EH and 0FH
Function 45H
Function 47H
Function 48H
Function 49H
Function 4AH
Function 4BH, Code 00H
Function 4BH, Code 03H
Function 4CH
Function 4DH
Function 4EH
Function 4FH
Function 54H
Function 56H
Function 57H
Function 58H
Function 59H
Function 5AH
Function 5BH
Function 5CH, Code 00H
Function 5CH, Code 01H
Function 5EH, Code 00H
Function 5EH, Code 02H
Function 5FH, Code 02H
Function 5FH, Code 03H
Function 5FH, Code 04H
Function 62H
Function 65H
Function 66H
Function 67H
Function 68H
Handling errors
memory management
National Language Support
Network-related
network-related
numeric order
process management
standard character I/O
system-management
Function requests
definition
Function 25H
Function 35H
Function 46H
G
Generic IOCtl for devices (Function 44H, Code 0DH)
Generic IOCtl for handles (Function 44H, Code 0CH)
Generic IOCtl Function
Get Assign List Entry (Function 5FH, Code 02H)
Get Country Data (Function 38H)
Get Current Directory (Function 47H)
Get Current Disk (Function 19H)
Get Date (Function 2AH)
Get Default Drive Data (Function 1BH)
Get Disk Free Space (Function 36H)
Get Disk Transfer Address (Function 2FH)
Get Drive Data (Function 1CH)
Get Extended Country Information (Function 65H)
Get Extended Error (Function 59H)
Get File Size (Function 23H)
Get Interrupt Vector (Function 35H)
Get Machine Name (Function 5EH, Code 00H)
Get MS-DOS Version Number (Function 30H)
Get PSP (Function 62H)
Get Return Code Child Process (Function 4DH)
Get Time (Function 2CH)
Get Verify State (Function 54H)
Get/Set Allocation Strategy (Function 58H)
Get/Set Date/Time of File (Function 57H)
Get/Set File Attributes (Function 43H)
Get/Set Global Code Page (Function 66H)
Get/Set IOCtl Drive Map (Function 44H, Codes 0EH and 0FH)
Get/Set Logical Drive Map Function
Group Component Descriptor field, GRPDEF
Group, definition
Group definition record. See GRPDEF record
Group Definition Record (GRPDEF)
Group Index
Group Index subfield, Line Number Base
Group Index subfield, Public Base
Group Name Index field, GRPDEF
GRPDEF record
definition
field
CHKSUM
Group Component Descriptor, repeated
Group Name Index
Record Length
RECTYP
schematic
H
Handles
definition
device
Handling errors
Header
hibyte, definition
Hidden files
High-Level Language
HUGE communal variable
I
IBM disk format
Index
definition
Index fields
Index Number
Index subfield, Thread
External Index
Group Index
Segment Index
Indices
Indices, external
Init
INIT code
Installable device drivers
Instruction
CALL
JUMP
SHORT-JUMP
Instruction Pointer (IP)
Internal stack
Interrupt entry point
Interrupt handlers
Interrupt routines
Interrupt-handling routine
Interrupts
21H
Address of handlers
alphabetic order
definition
Interrupt 20H
Interrupt 21H
Interrupt 22H
Interrupt 23H
Interrupt 24H
Interrupt 25H
Interrupt 26H
Interrupt 27H
issuing
numeric order
programming hints
Vector table
I/O Control for Devices (Function 44H)
IOCtl
IOCtl bit
IOCtl Block (Function 44H, Codes 4 and 5)
IOCtl Character (Function 44H, Codes 2 and 3)
IOCtl Data (Function 44H, Codes 0 and 1)
IOCtl Is Changeable (Function 44H, Code 08H)
IOCtl Is Redirected Block (Function 44H, Code 09H)
IOCtl Is Redirected Handle (Function 44H, Code 0AH)
IOCtl Retry (Function 44H, Code 0BH)
IOCtl Status (Function 44H, Codes 6 and 7)
io.sys file
IP. See Instruction Pointer (IP)
Iterated Data Block field, LIDATA
Iterated Data Offset field, LIDATA
J
JUMP instruction
K
Keep Process (Function 31H)
Keyboard layouts, national, NLS
L
Language
C
FORTRAN
Leaf Descriptor subfield, Eight Leaf Descriptor
format
FAR variable
NEAR variable
subfield
NEAR
VARTYP
LEDATA
field
CHKSUM
Record Length
RECTYP
purpose
LEDATA record
field
DAT, repeated
Enumerated Data Offset
Segment Index
schematic
Length fields, COMDEF, format
Length in Bits subfield, Leaf Descriptor
Length of Record Field
LHEADR record
field
CHKSUM
L-module Name
Record Length
RECTYP
schematic
LIDATA record
field
CHKSUM
Iterated Data Block, repeated
Iterated Data Offset
Record Length
RECTYP
Segment Index
purpose
schematic
subfield of Iterated Data Block
Block Count
Content
Repeat Count
Line Number Base field, LINNUM
Line number, binary
Line Number field, LINNUM
Line Number Offset field, LINNUM
Line Numbers Record (LINNUM)
LINK
Linker, Microsoft
Linker, Microsoft
Link-time semantics
LINNUM record
field
CHKSUM
Line Number Base
Line Number Offset, repeated
Line Number, repeated
Record Length
RECTYP
purpose
schematic
subfield of Line Number Base
Group Index
Segment Index
List of Names Record (LNAMES)
L-module Header Record (LHEADR)
L-module Name
LNAMES record
field
CHKSUM
Name, repeated
Record Length
RECTYP
schematic
Load and Execute Program (Function 4BH, Code 00H)
Load module
Load Overlay (Function 4BH, Code 03H)
Loadsize
lobyte, definition
Local Base field, LOCSYM
Local buffering
Local Name field, LOCSYM
Local Offset field, LOCSYM
Local symbol
Local Symbols Record (LOCSYM)
LOCAT subfield, Fixup
internal structure
schematic
Location
types
base
hibyte
lobyte
offset
pointer
Lock (Function 5CH, Code 00H)
LOCSYM record
field
CHKSUM
Local Base
Local Name, repeated
Local Offset, repeated
Record Length
RECTYP
Type Index, repeated
order with respect to COMENT
purpose
schematic
Logical Enumerated Data Record (LEDATA)
Logical Iterated Data Record (LIDATA)
Logical sector
Logical sector numbers
Logical Segment. See LSEG
LSEG
absolute
Combination attribute
Alignment attribute
absolute segment
relocatable segment
canonic Frame
Class name
Combination attribute
absolute segment
relocatable segment
combining
Complete name
definition
Overlay Name
relocatable
byte-aligned
Combination attribute
page-aligned
paragraph-aligned
word-aligned
Segment Name
M
Make Assign-List Entry (Function 5FH, Code 03H)
Mapping
logical to physical starting address
MAS. See Memory Address Space (MAS)
MATTR subfield, MOD TYP
Maxalloc
Media Check
Media descriptor byte
Media, determining
Memory address
Memory Address Space (MAS)
Memory control block
Memory image, 8086
Memory image, LSEGs in
Memory image, relocatable
Memory management function requests
Memory management, programming hints
Memory model
huge
large
medium
small
Microprocessor
80186
80286
8086
Microsoft Extensions class
Microsoft linker
Microsoft linker
Microsoft Networks
Microsoft Networks Manager's Guide
Microsoft Networks User's Guide
Minalloc
MOD TYP field, MODEND
MATTR subfield
module attributes
Mode
fixup
segment-relative
self-relative
Mode, address
MODEND record
field
CHKSUM
MOD TYP
Record Length
RECTYP
START ADDRS, conditional
purpose
schematic
subfield of START ADDRS
Frame Datum, conditional
Target Datum, conditional
Target Displacement, conditional
Module
record ordering in
Module, definition
Module End Record (MODEND)
Module header record, definition
Move File Pointer (Function 42H)
MS-DOS, 8086 object language
MS-DOS initialization
MS-DOS memory map
MS-DOS User's Reference
msdos.sys file
Multitasking
N
Name field
Name field, SAMREC
Name Indices
National keyboard layouts, NLS
National Language Support Function Requests
National Language Support (NLS)
restrictions
unsupported features
National Language Support system calls
NEAR data segment
NEAR subfield, Leaf Descriptor
NEAR variable format, Leaf Descriptor
Network-related Function Requests
Network-related function requests
Non IBM format bit
Non-destructive Read No Wait
NUL device
Number field, SAMREC
Number of Elements subfield, Leaf Descriptor
O
Object language, 8086
Object module
restrictions
Object Module Formats
Object Module Formats (OMF)
offset, definition
Offset subfield, SEG ATTR
Old system calls
OMF. See Object Module Formats (OMF)
Open File (Function 0FH)
Open Handle (Function 3DH)
Opened FCB
Operating system
MS-DOS
PC-DOS
XENIX
Overlay Name, definition
P
Parameter block
Parse File Name (Function 29H)
Path command
PC-DOS, 8086 object language
Physical Segment. See PSEG
Pointer to Next Device field
Predefined device handles
Print Character (Function 05H)
Printer Setup (Function 5EH, Code 02H
Process management function requests
Process management, programming hints
Processor. See Microprocessor
Program End Process (Interrupt 20H)
Program segment
Program Segment Prefix
Programming hints
device management
file and directory management
file locking
interrupts
memory management
miscellaneous
process management
recommendations
system calls
Programming interfaces, NLS
Prompt command
Protected-mode
application Frame Number
PSEG
definition
PUBDEF record
field
Public Base, repeated
Public Name, repeated
Public Offset, repeated
Record Length
RECTYP
Type Index, repeated
purpose
schematic
subfield of Public Base
Frame Number, conditional
subfield, Public Base
Frame Number, conditional
Group Index
Segment Index
Public Base field, PUBDEF
Public Name field, PUBDEF
Public names definition record. See PUBDEF record
Public Names Definition Record (PUBDEF)
Public Offset field, PUBDEF
Public symbol
Public variable
R
Random Block Read (Function 27H)
Random Block Write (Function 28H)
Random Read (Function 21H)
Random Write (Function 22H)
Read Handle (Function 3FH)
Read Keyboard and Echo (Function 01H)
Read Keyboard (Function 08H)
Read Only Memory
Read or Write
Record
COMDEF
COMENT
comment
Data
EXTDEF
FIXUP
FIXUPP
GRPDEF
LEDATA
LHEADR
LIDATA
LINNUM
LNAMES
LOCSYM
MODEND
PUBDEF
RECTYP(record type)
SAMREC (sample record)
SEGDEF
symbol definition
COMDEF
EXTDEF
PUBDEF
THEADR
TYPDEF
Record format
abbreviation
bitfields
conditional field
repeated field
sample (SAMREC)
SAMREC (sample record)
CHKSUM field
Name field
Number field
Record Length field
SAMREC(sample record)
RECTYP field
title
Record formats
Record Length field, SAMREC
Record order
definition
semantic rules
syntax
Record Size
RECTYP(record type)field
Reference
segment-relative
Reference self-relative
References
WIRTH
CACM, Nov. 1977)
Register
CS
DS
ES
SS
Registers, treatment of
Relocatable memory image
Relocatable segment, LSEG
Relocation information
Relocation item offset value to a word in the load
Relocation table
Remove Directory (Function 3AH)
Rename File (Function 17H)
Repeat Count subfield, Iterated Data Block
request header
Request packet
Reset Disk (Function 0DH)
Resident device drivers
ROM
Root directory
S
SAMREC (sample record)
schematic
Search for First Entry (Function 11H)
Search for Next Entry (Function 12H)
Sector count
SEG ATTR field, SEGDEF
SEGDEF record
definition
field
CHKSUM
Class Name Index
Overlay Name Index
Record Length
RECTYP
SEG ATTR
Segment Name Index
schematic
subfield of SEG ATTR
Alignment
Big
Combination
Offset, conditional
SEGDEF recrod
field
Segment Length
Segment
absolute, LSEG
attribute
Alignment
Combination
logical (LSEG)
physical (PSEG)
relocatable, LSEG
Segment addressing
Segment definition record. See SEGDEF record
Segment Definition Record (SEGDEF)
Segment Index
Segment Index field, LEDATA
Segment Index field, LIDATA
Segment Index subfield, Group Component Descriptor
Segment Index subfield, Line Number Base
Segment Index subfield, Public Base
Segment Length field, SEGDEF
Segment Name, definition
Segment Name Index field, SEGDEF
Segment-relative fixup
Segment-relative reference
Select Disk (Function 0EH)
Self-relative fixup
Self-relative reference
Semantic rules, record ordering
Semantics, link-time
Sequential Read (Function 14H)
Sequential Write (Function 15H)
Set Block (Function 4AH)
Set command
Set Country Data (Function 38H)
Set Date (Function 2BH)
Set Disk Transfer Address (Function 1AH)
Set Handle Count(Function 67H)
Set Interrupt Vector (Function 25H)
Set Relative Record (Function 24H)
Set Time (Function 2DH)
Set/Reset Verify Flag (Function 2EH)
SHORT-JUMP instruction
SS register
Stack segment, SS
Standard character I/O function requests
START ADDRS field, MODEND
Format
Start sector
Start segment value the relocation item offset
static request header
Status
Status field
Strategy entry point
Strategy routines
Subfield
Comment Type
Comment Class
Eight Leaf Descriptor
EN
Leaf Descriptor
Fixup
Frame Datum
Target Datum
Target Displacement
Frame Number, conditional
Group Component Descriptor
Segment Index
Iterated Data Block
Block Count
Content
Repeat Count
Leaf Descriptor
Element Type Index
FAR
Length in Bits
NEAR
Number of Elements
VAR SUBTYP
VARTYP
Line Number Base, LINNUM
Group Index
Segment Index
MOD TYP
MATTR
Public Base
Group INdex
SEG ATTR
Alignment
Big
Combination
Segment Index
START ADDRS
Frame Datum
Target Datum
Target Displacement
Thread
Index
TRD DAT
Subfield OFFH
Superseded system calls
Symbol
local
public
Symbol definition
Symbol definition record
COMDEF
EXTDEF
PUBDEF
Syntax, record ordering
Sysinit
System call
National Language Support:
System Calls
superseded calls
System calls
definition
programming hints
replacements for old
types of
System files
System prompt
System-management function requests
T
Target
definition
nomenclature
specification attribute
specifying
specifying, FIXUPP
Thread Number, FIXUPP
Target Datum field, FIXUPP
Target Datum subfield, Fixup
External Index
Group Index
Segment Index
Target Datum subfield, START ADDRS
Target Displacement subfield, Fixup
Target Displacment subfield, START ADDRS
Terminate But Stay Resident (Interrupt 27H)
Terminate Process Exit Address (Interrupt 22H)
Terminate Program (Function 00H)
THEADR record
field
CHKSUM
Record Length
RECTYP
T-module Name
schematic
Thread Data subfield. See TRD DAT subfield, Thread
Thread field, FIXUPP
data type
Frame
Target
definition
Thread Number, THRED
T-module, definition
T-module Header Record (THEADR)
T-Module Name
Transfer address
TRD DAT subfield, Thread
D subfield
internal structure
Method subfield
schematic
THRED subfield
TYPDEF record
communal variable
field
CHKSUM
Eight Leaf Descriptor
Record Length
RECTYP
subfield of Eight Leaf Descriptor
EN
subfield of Leaf Descriptor
Element Type Index
FAR
Length in Bits
NEAR
Number of Elements
VAR SUBTYP, optional
VARTYP
Type Index field, COMDEF
Type Index field, EXTDEF
Type Index field, LOCSYM
Type Index field, PUBDEF
Type-ahead buffer
U
Unit code field
Unlock (Function 5CH, Code 01H)
Unopened FCB
User Stack
User stack
Utility commands, NLS
V
VAR SUBTYP subfield, Leaf Descriptor
Variable
communal
FAR
HUGE"
NEAR
public
VARTYP subfield, Leaf Descriptor
ARRAY
SCALAR
STRUCT
Vector table
Volume ID
Volume label
W
Wildcard characters
Write Handle (Function 40H)
X
XENIX, 8086 object language