home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft_Programmers_Library.7z / MPL / msdos / dosencyc.txt < prev    next >
Encoding:
Text File  |  2013-11-08  |  3.3 MB  |  81,120 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1.  THE MS-DOS(R) ENCYCLOPEDIA
  2.  
  3.  
  4.  
  5.  ───────────────────────────────────────────────────────────────────────────
  6.  
  7.  
  8.  
  9.  THE MS-DOS(R) ENCYCLOPEDIA
  10.  
  11.  
  12.  
  13.  ───────────────────────────────────────────────────────────────────────────
  14.  
  15.  
  16.  Ray Duncan, General Editor
  17.  
  18.  Foreword by Bill Gates
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  Published by
  25.  Microsoft Press
  26.  A Division of Microsoft Corporation
  27.  16011 NE 36th Way, Box 97017, Redmond, Washington 98073-9717
  28.  Copyright (C) 1988 by Microsoft Press
  29.  All rights reserved. No part of the contents of this book may be reproduced
  30.  or transmitted in any form or by any means without the written permission
  31.  of the publisher.
  32.  
  33.  Library of Congress Cataloging in Publication Data
  34.  
  35.  The MS-DOS encyclopedia : versions 1.0 through 3.2 /
  36.     editor, Ray Duncan.
  37.       p.     cm.
  38.  Includes indexes.
  39.  ISBN 1-55615-049-0
  40.  1. MS-DOS (Computer operating system)  I. Duncan, Ray, 1952-
  41.  II. Microsoft Press.
  42.  QA76.76.063M74      1988    87-21452
  43.  005.4'46--dc19                   CIP
  44.  
  45.  Printed and bound in the United States of America.
  46.  
  47.  1 2 3 4 5 6 7 8 9 RMRM 8 9 0 9 8 7
  48.  
  49.  Distributed to the book trade in the United States by Harper & Row.
  50.  
  51.  Distributed to the book trade in Canada by General Publishing Company, Ltd.
  52.  
  53.  Distributed to the book trade outside the
  54.  United States and Canada by Penguin Books Ltd.
  55.  
  56.  Penguin Books Ltd., Harmondsworth, Middlesex, England
  57.  Penguin Books Australia Ltd., Ringwood, Victoria, Australia
  58.  
  59.  British Cataloging in Publication Data available
  60.  
  61.  
  62.  IBM(R), IBM AT(R), PS/2(R), and TopView(R) are registered trademarks of
  63.  International Business Machines Corporation. GW-BASIC(R), Microsoft(R),
  64.  MS(R), MS-DOS(R), SOFTCARD(R), and XENIX(R) are registered trademarks of
  65.  Microsoft Corporation.
  66.  
  67.  Microsoft Press gratefully acknowledges permission to reproduce material
  68.  listed below.
  69.  Page 4: Courtesy The Computer Museum.
  70.  Pages 5, 11, 42: Intel 4004, 8008, 8080, 8086, and 80286 microprocessor
  71.  photographs. Courtesy Intel Corporation.
  72.  Page 6: Reprinted from Popular Electronics, January 1975
  73.  Copyright (C) 1975 Ziff Communications Company.
  74.  Page 13: Reprinted with permission of Rod Brock.
  75.  Page 16: Reprinted with permission of The Seattle Times Copyright (C) 1983.
  76.  Pages 19, 34, 42: IBM PC advertisements and photographs of the PC, PC/XT,
  77.  and PC/AT reproduced with permission of International Business Machines
  78.  Corporation Copyright (C) 1981, 1982, 1984. All rights reserved.
  79.  Page 21: "Big IBM's Little Computer" Copyright (C) 1981 by The New York
  80.  Times Company. Reprinted by permission.
  81.  "IBM Announces New Microcomputer System" Reprinted with permission of
  82.  InfoWorld Copyright (C) 1981.
  83.  "IBM really gets personal" Reprinted with permission of Personal Computing
  84.  Copyright (C) 1981.
  85.  "Personal Computer from IBM" Reprinted from DATAMATION Magazine, October
  86.  1981 Copyright (C) by Cahners Publishing Company.
  87.  "IBM's New Line Likely to Shake up the Market for Personal Computers"
  88.  Reprinted by permission of The Wall Street Journal Copyright (C) Dow Jones
  89.  & Company, Inc. 1981. All Rights Reserved.
  90.  Page 36: "Irresistible DOS 3.0" and "The Ascent of DOS" Reprinted from
  91.  PC Tech Journal, December 1984 and October 1986. Copyright (C) 1984, 1986
  92.  Ziff Communications Company.
  93.  "MS-DOS 2.00: A Hands-On Tutorial" Reprinted by permission of PC World from
  94.  Volume 1, Issue 3, March 1983, published at 501 Second Street, Suite 600,
  95.  San Francisco, CA 94107.
  96.  
  97.  Special thanks to Bob O'Rear, Aaron Reynolds, and Kenichi Ikeda.
  98.  
  99.  
  100.  
  101.  Encyclopedia Staff
  102.  
  103.  
  104.  Editor-in-Chief:  Susan Lammers
  105.  
  106.  Editorial Director:  Patricia Pratt
  107.  
  108.  Senior Editor:  Dorothy L. Shattuck
  109.  
  110.  Senior Technical Editor:  David L. Rygmyr
  111.  
  112.  Special Projects Editor:  Sally A. Brunsman
  113.  
  114.  Editorial Coordinator:  Sarah Hersack
  115.  
  116.  
  117.  Associate Editors and Technical Editors: Pamela Beason, Ann
  118.  Becherer, Bob Combs, Michael Halvorson, Jeff Hinsch, Dean Holmes, Chris
  119.  Kinata, Gary Masters, Claudette Moore, Steve Ross, Roger Shanafelt, Eric
  120.  Stroo, Lee Thomas, JoAnne Woodcock
  121.  
  122.  Copy Chief:  Brianna Morgan. Proofreaders: Kathleen Atkins,
  123.  Julie Carter, Elizabeth Eisenhood, Matthew Eliot, Patrick Forgette, Alex
  124.  Hancock, Richard Isomaki, Shawn Peck, Alice Copp Smith
  125.  
  126.  Editorial Assistants:  Wallis Bolz, Charles Brod, Stephen
  127.  Brown, Pat Erickson, Debbie Kem, Susanne McRhoton, Vihn Nguyen, Cheryl
  128.  VanGeystel
  129.  
  130.  Index:  Shane-Armstrong Information Services
  131.  
  132.  Production:  Larry Anderson, Jane Bennett, Rick Bourgoin,
  133.  Darcie S. Furlan, Nick Gregoric, Peggy Herman, Lisa Iversen, Rebecca
  134.  Johnson, Ruth Pettis, Russell Steele, Jean Trenary, Joy Ulskey
  135.  
  136.  Marketing and Sales Director:  James Brown
  137.  
  138.  Director of Production:  Christopher D. Banks
  139.  
  140.  Publisher:  Min S. Yee
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  Contributors
  147.  
  148.  
  149.       Ray Duncan, General Editor   Duncan received a B.A. in Chemistry from
  150.       the University of California, Riverside, and an M.D. from the
  151.       University of California, Los Angeles, and subsequently received
  152.       specialized training in Pediatrics and Neonatology at the Cedars-Sinai
  153.       Medical Center in Los Angeles. He has written many articles for
  154.       personal computing magazines, including BYTE, PC Magazine, Dr. Dobb's
  155.       Journal, and Softalk/PC, and is the author of the Microsoft Press book
  156.       Advanced MS-DOS. He is the founder of Laboratory Microsystems
  157.       Incorporated, a software house specializing in FORTH interpreters and
  158.       compilers.
  159.  
  160.       Steve Bostwick   Bostwick holds a B.S. in Physics from the University
  161.       of California, Los Angeles, and has over 20 years' experience in
  162.       scientific and commercial data processing. He is president of Query
  163.       Computing Systems, Inc., a software firm specializing in the creation
  164.       of systems for applications that interface microcomputers with
  165.       specialized hardware. He is also an instructor for the UCLA Extension
  166.       Department of Engineering and Science and helped design their popular
  167.       Microprocessor Hardware and Software Engineering Certificate Program.
  168.  
  169.       Keith Burgoyne   Born and raised in Orange County, California,
  170.       Burgoyne began programming in 1974 on IBM 370 mainframes. In 1979, he
  171.       began developing microcomputer products for Apples, TRS-80s, Ataris,
  172.       Commodores, and IBM PCs. He is presently Senior Systems Engineer at
  173.       Local Data of Torrance, California, which is a major producer of IBM
  174.       3174/3274 and System 3X protocol conversion products. His previous
  175.       writing credits include numerous user manuals and tutorials.
  176.  
  177.       Robert A. Byers   Byers is the author of the bestselling Everyman's
  178.       Database Primer. He is presently involved with the Emerald Bay
  179.       database project with RSPI and Migent, Inc.
  180.  
  181.       Thom Hogan   During 11 years working with personal computers, Hogan
  182.       has been a software developer, a programmer, a technical writer, a
  183.       marketing manager, and a lecturer. He has written six books, numerous
  184.       magazine articles, and four manuals. Hogan is the author of the
  185.       forthcoming Microsoft Press book PC Programmer's Sourcebook.
  186.  
  187.       Jim Kyle   Kyle has 23 years' experience in computing. Since 1967, he
  188.       has been a systems programmer with strong telecommunications
  189.       orientation. His interest in microcomputers dates from 1975. He is
  190.       currently MIS Administrator for BTI Systems, Inc., the OEM Division of
  191.       BanTec Inc., manufacturers of MICR equipment for the banking
  192.       industry. He has written 14 books and numerous magazine articles
  193.       (mostly on ham radio and hobby electronics) and has been primary Forum
  194.       Administrator for Computer Language Magazine's CLMFORUM on CompuServe
  195.       since early 1985.
  196.  
  197.       Gordon Letwin   Letwin is Chief Architect, Systems Software, Microsoft
  198.       Corporation. He is the author of Inside OS/2, published by Microsoft
  199.       Press.
  200.  
  201.       Charles Petzold   Petzold holds an M.S. in Mathematics from Stevens
  202.       Institute of Technology. Before launching his writing career, he
  203.       worked 10 years in the insurance industry, programming and teaching
  204.       programming on IBM mainframes and PCs. He is the author of the
  205.       Microsoft Press book Programming Windows 2.0, a contributing editor to
  206.       PC Magazine, and a frequent contributor to the Microsoft Systems
  207.       Journal.
  208.  
  209.       Chip Rabinowitz   Rabinowitz has been a programmer for 11 years. He is
  210.       presently chief programmer for Productivity Solutions, a microcomputer
  211.       consulting firm based in Pennsylvania, and has been Forum
  212.       Administrator for the CompuServe MICROSOFT SIG since 1986.
  213.  
  214.       Jim Tomlin   Tomlin holds a B.S. and an M.S. in Mathematics. He has
  215.       programmed at Boeing, Microsoft, and Opcon and has taught at Seattle
  216.       Pacific University. He now heads his own company in Seattle, which
  217.       specializes in PC systems programming and industrial machine vision
  218.       applications.
  219.  
  220.       Richard Wilton   Wilton has programmed extensively in PL/1, FORTRAN,
  221.       FORTH, C, and several assembly languages. He is the author of
  222.       Programmer's Guide to PC & PS/2 Video Systems, published by Microsoft
  223.       Press.
  224.  
  225.       Van Wolverton   A professional writer since 1963, Wolverton has had
  226.       bylines as a newspaper reporter, editorial writer, political
  227.       columnist, and technical writer. He is the author of Running MS-DOS
  228.       and Supercharging MS-DOS, both published by Microsoft Press.
  229.  
  230.       William Wong   Wong holds engineering and computer science degrees
  231.       from Georgia Tech and Rutgers University. He is director of PC Labs
  232.       and president of Logic Fusion, Inc. His interests include operating
  233.       systems, computer languages, and artificial intelligence. He has
  234.       written numerous magazine articles and a book on MS-DOS.
  235.  
  236.       JoAnne Woodcock   Woodcock, a former senior editor at Microsoft Press,
  237.       has been a writer for Encyclopaedia Britannica and a freelance and
  238.       project editor on marine biological studies at the University of
  239.       Southern California. She is co-editor (with Michael Halvorson) of
  240.       XENIX at Work and co-author (with Peter Rinearson) of Microsoft Word
  241.       Style Sheets, both published by Microsoft Press.
  242.  
  243.  Special Technical Advisor
  244.       Mark Zbikowski
  245.  
  246.  Technical Advisors
  247.  
  248.  Paul Allen        Michael Geary     David Melin         John Pollock
  249.  Steve Ballmer     Bob Griffin       Charles Mergentime  Aaron Reynolds
  250.  Reuben Borman     Doug Hogarth      Randy Nevin         Darryl Rubin
  251.  Rob Bowman        James W. Johnson  Dan Newell          Ralph Ryan
  252.  John Butler       Kaamel Kermaani   Tani Newell         Karl Schulmeisters
  253.  Chuck Carroll     Adrian King       David Norris        Rajen Shah
  254.  Mark Chamberlain  Reed Koch         Mike O'Leary        Barry Shaw
  255.  David Chell       James Landowski   Bob O'Rear          Anthony Short
  256.  Mike Colee        Chris Larson      Mike Olsson         Ben Slivka
  257.  Mike Courtney     Thomas Lennon     Larry Osterman      Jon Smirl
  258.  Mike Dryfoos      Dan Lipkie        Ridge Ostling       Betty Stillmaker
  259.  Rachel Duncan     Marc McDonald     Sunil Pai           John Stoddard
  260.  Kurt Eckhardt     Bruce McKinney    Tim Paterson        Dennis Tillman
  261.  Eric Evans        Pascal Martin     Gary Perez          Greg Whitten
  262.  Rick Farmer       Estelle Mathers   Chris Peters        Natalie Yount
  263.  Bill Gates        Bob Matthews      Charles Petzold     Steve Zeck
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  CONTENTS
  270.  
  271.  
  272.  Foreword by Bill Gates
  273.  
  274.  Preface by Ray Duncan
  275.  
  276.  Introduction
  277.  
  278.  Section I: The Development of MS-DOS
  279.  
  280.  Section II: Programming in the MS-DOS Environment
  281.  
  282.       Part A: Structure of MS-DOS
  283.  
  284.       Article 1:  An Introduction to MS-DOS
  285.       Article 2:  The Components of MS-DOS
  286.       Article 3:  MS-DOS Storage Devices
  287.  
  288.       Part B: Programming for MS-DOS
  289.  
  290.       Article 4:  Structure of an Application Program
  291.       Article 5:  Character Device Input and Output
  292.       Article 6:  Interrupt-Driven Communications
  293.       Article 7:  File and Record Management
  294.       Article 8:  Disk Directories and Volume Labels
  295.       Article 9:  Memory Management
  296.       Article 10: The MS-DOS EXEC Function
  297.  
  298.       Part C: Customizing MS-DOS
  299.  
  300.       Article 11: Terminate-and-Stay-Resident Utilities
  301.       Article 12: Exception Handlers
  302.       Article 13: Hardware Interrupt Handlers
  303.       Article 14: Writing MS-DOS Filters
  304.       Article 15: Installable Device Drivers
  305.  
  306.       Part D: Directions of MS-DOS
  307.  
  308.       Article 16: Writing Applications for Upward Compatibility
  309.       Article 17: Windows
  310.  
  311.       Part E: Programming Tools
  312.  
  313.       Article 18: Debugging in the MS-DOS Environment
  314.       Article 19: Object Modules
  315.       Article 20: The Microsoft Object Linker
  316.  
  317.  Section III: User Commands
  318.  
  319.       Introduction
  320.  
  321.       User commands are listed in alphabetic order. This section includes
  322.       ANSI.SYS, BATCH, CONFIG.SYS, DRIVER.SYS, EDLIN, RAMDRIVE.SYS, and
  323.       VDISK.SYS.
  324.  
  325.  Section IV: Programming Utilities
  326.  
  327.       Introduction
  328.  
  329.       CREF
  330.       EXE2BIN
  331.       EXEMOD
  332.       EXEPACK
  333.       LIB
  334.       LINK
  335.       MAKE
  336.       MAPSYM
  337.       MASM
  338.  
  339.       Microsoft Debuggers:
  340.  
  341.       DEBUG
  342.       SYMDEB
  343.       CodeView
  344.  
  345.  Section V: System Calls
  346.  
  347.       Introduction
  348.  
  349.       System calls are listed in numeric order.
  350.  
  351.  Appendixes
  352.  
  353.       Appendix A: MS-DOS Version 3.3
  354.       Appendix B: Critical Error Codes
  355.       Appendix C: Extended Error Codes
  356.       Appendix D: ASCII and IBM Extended ASCII Character Sets
  357.       Appendix E: EBCDIC Character Set
  358.       Appendix F: ANSI.SYS Key and Extended Key Codes
  359.       Appendix G: File Control Block (FCB) Structure
  360.       Appendix H: Program Segment Prefix (PSP) Structure
  361.       Appendix I: 8086/8088/80286/80386 Instruction Sets
  362.       Appendix J: Common MS-DOS Filename Extensions
  363.       Appendix K: Segmented (New) .EXE File Header Format
  364.       Appendix L: Intel Hexadecimal Object File Format
  365.       Appendix M: 8086/8088 Software Compatibility Issues
  366.       Appendix N: An Object Module Dump Utility
  367.       Appendix O: IBM PC BIOS Calls
  368.  
  369.  Indexes
  370.  
  371.       Subject
  372.       Commands and System Calls
  373.  
  374.  
  375.  
  376.  
  377.  Foreword
  378.  
  379.  
  380.       Microsoft's MS-DOS is the most popular piece of software in the world.
  381.       It runs on more than 10 million personal computers worldwide and is
  382.       the foundation for at least 20,000 applications--the largest set of
  383.       applications in any computer environment. As an industry standard for
  384.       the family of 8086-based microcomputers, MS-DOS has had a central role
  385.       in the personal computer revolution and is the most significant and
  386.       enduring factor in furthering Microsoft's original vision--a computer
  387.       for every desktop and in every home. The challenge of maintaining a
  388.       single operating system over the entire range of 8086-based
  389.       microcomputers and applications is incredible, but Microsoft has been
  390.       committed to meeting this challenge since the release of MS-DOS in
  391.       1981. The true measure of our success in this effort is MS-DOS's
  392.       continued prominence in the microcomputer industry.
  393.  
  394.       Since MS-DOS's creation, more powerful and much-improved computers
  395.       have entered the marketplace, yet each new version of MS-DOS
  396.       reestablishes its position as the foundation for new applications as
  397.       well as for old. To explain this extraordinary prominence, we must
  398.       look to the origins of the personal computer industry. The three most
  399.       significant factors in the creation of MS-DOS were the compatibility
  400.       revolution, the development of Microsoft BASIC and its widespread
  401.       acceptance by the personal computer industry, and IBM's decision to
  402.       build a computer that incorporated 16-bit technology.
  403.  
  404.       The compatibility revolution began with the Intel 8080 microprocessor.
  405.       This technological breakthrough brought unprecedented opportunities in
  406.       the emerging microcomputer industry, promising continued improvements
  407.       in power, speed, and cost of desktop computing. In the minicomputer
  408.       market, every hardware manufacturer had its own special instruction
  409.       set and operating system, so software developed for a specific machine
  410.       was incompatible with the machines of other hardware vendors. This
  411.       specialization also meant tremendous duplication of effort--each
  412.       hardware vendor had to write language compilers, databases, and other
  413.       development tools to fit its particular machine. Microcomputers based
  414.       on the 8080 microprocessor promised to change all this because
  415.       different manufacturers would buy the same chip with the same
  416.       instruction set.
  417.  
  418.       From 1975 to 1981 (the 8-bit era of microcomputing), Microsoft
  419.       convinced virtually every personal computer manufacturer--Radio Shack,
  420.       Commodore, Apple, and dozens of others--to build Microsoft BASIC into
  421.       its machines. For the first time, one common language cut across all
  422.       hardware vendor lines. The success of our BASIC demonstrated the
  423.       advantages of compatibility: To their great benefit, users were
  424.       finally able to move applications from one vendor's machine to
  425.       another.
  426.  
  427.       Most machines produced during this early period did not have a built-
  428.       in disk drive. Gradually, however, floppy disks, and later fixed
  429.       disks, became less expensive and more common, and a number of disk-
  430.       based programs, including WordStar and dBASE, entered the market. A
  431.       standard disk operating system that could accommodate these
  432.       developments became extremely important, leading Lifeboat, Microsoft,
  433.       and Digital Research all to support CP/M-80, Digital Research's 8080
  434.       DOS.
  435.  
  436.       The 8-bit era proved the importance of having a multiple-manufacturer
  437.       standard that permitted the free interchange of programs. It was
  438.       important that software designed for the new 16-bit machines have this
  439.       same advantage. No personal computer manufacturer in 1980 could have
  440.       predicted with any accuracy how quickly a third-party software
  441.       industry would grow and get behind a strong standard--a standard that
  442.       would be the software industry's lifeblood. The intricacies of how
  443.       MS-DOS became the most common 16-bit operating system, in part through
  444.       the work we did for IBM, is not the key point here. The key point is
  445.       that it was inevitable for a popular operating system to emerge for
  446.       the 16-bit machine, just as Microsoft's BASIC had prevailed on the 8-
  447.       bit systems.
  448.  
  449.       It was overwhelmingly evident that the personal computer had reached
  450.       broad acceptance in the market when Time in 1982 named the personal
  451.       computer "Man of the Year." MS-DOS was integral to this acceptance and
  452.       popularity, and we have continued to adapt MS-DOS to support more
  453.       powerful computers without sacrificing the compatibility that is
  454.       essential to keeping it an industry standard. The presence of the
  455.       80386 microprocessor guarantees that continued investments in Intel-
  456.       architecture software will be worthwhile.
  457.  
  458.       Our goal with The MS-DOS Encyclopedia is to provide the most thorough
  459.       and accessible resource available anywhere for MS-DOS programmers. The
  460.       length of this book is many times greater than the source listing of
  461.       the first version of MS-DOS--evidence of the growing complexity and
  462.       sophistication of the operating system. The encyclopedia will be
  463.       especially useful to software developers faced with preserving
  464.       continuity yet enhancing the portability of their applications.
  465.  
  466.       Our thriving industry is committed to exploiting the advantages
  467.       offered by the protected mode introduced with the 80286 microprocessor
  468.       and the virtual mode introduced with the 80386 microprocessor. MS-DOS
  469.       will continue to play an integral part in this effort. Faster and more
  470.       powerful machines running Microsoft OS/2 mean an exciting future of
  471.       multitasking systems, networking, improved levels of data protection,
  472.       better hardware memory management for multiple applications, stunning
  473.       graphics systems that can display an innovative graphical user
  474.       interface, and communication subsystems. MS-DOS version 3, which runs
  475.       in real mode on 80286-based and 80386-based machines, is a vital link
  476.       in the Family API of OS/2. Users will continue to benefit from our
  477.       commitment to improved operating-system performance and usability as
  478.       the future unfolds.
  479.  
  480.                                                     Bill Gates
  481.  
  482.  
  483.  
  484.  
  485.  Preface
  486.  
  487.  
  488.       In the space of six years, MS-DOS has become the most widely used
  489.       computer operating system in the world, running on more than 10
  490.       million machines. It has grown, matured, and stabilized into a
  491.       flexible, easily extendable system that can support networking,
  492.       graphical user interfaces, nearly any peripheral device, and even CD
  493.       ROMs containing massive amounts of on-line information. MS-DOS will be
  494.       with us for many years to come as the platform for applications that
  495.       run on low-cost, 8086/8088-based machines.
  496.  
  497.       Not surprisingly, the success of MS-DOS has drawn many writers
  498.       and publishers into its orbit. The number of books on MS-DOS and its
  499.       commands, languages, and applications dwarfs the list of titles for
  500.       any other operating system. Why, then, yet another book on MS-DOS? And
  501.       what can we say about the operating system that has not been said
  502.       already?
  503.  
  504.       First, we have written and edited The MS-DOS Encyclopedia with one
  505.       audience in mind: the community of working programmers. We have
  506.       therefore been free to bypass elementary subjects such as the number
  507.       of bits in a byte and the interpretation of hexadecimal numbers.
  508.       Instead, we have emphasized detailed technical explanations, working
  509.       code examples that can be adapted and incorporated into new
  510.       applications, and a systems view of even the most common MS-DOS
  511.       commands and utilities.
  512.  
  513.       Second, because we were not subject to size restrictions, we have
  514.       explored topics in depth that other MS-DOS books mention only briefly,
  515.       such as exception and error handling, interrupt-driven communications,
  516.       debugging strategies, memory management, and installable device
  517.       drivers. We have commissioned definitive articles on the relocatable
  518.       object modules generated by Microsoft language translators, the
  519.       operation of the Microsoft Object Linker, and terminate-and-stay-
  520.       resident utilities. We have even interviewed the key developers of
  521.       MS-DOS and drawn on their files and bulletin boards to offer an
  522.       entertaining, illustrated account of the origins of Microsoft's
  523.       standard-setting operating system.
  524.  
  525.       Finally, by combining the viewpoints and experience of non-
  526.       Microsoft programmers and writers, the expertise and resources of
  527.       Microsoft software developers, and the publishing know-how of
  528.       Microsoft Press, we have assembled a unique and comprehensive
  529.       reference to MS-DOS services, commands, directives, and utilities. In
  530.       many instances, the manuscripts have been reviewed by the authors of
  531.       the Microsoft tools described.
  532.  
  533.       We have made every effort during the creation of this book to
  534.       ensure that its contents are timely and trustworthy. In a work of this
  535.       size, however, it is inevitable that errors and omissions will occur.
  536.       If you discover any such errors, please bring them to our attention so
  537.       that they can be repaired in future printings and thus aid your fellow
  538.       programmers. To this end, Microsoft Press has established a bulletin
  539.       board on MCI Mail for posting corrections and comments. Please refer
  540.       to page xvi for more information.
  541.  
  542.                                                       Ray Duncan
  543.  
  544.  
  545.  
  546.  
  547.  ───────────────────────────────────────────────────────────────────────────
  548.  
  549.                Updates to the MS-DOS Encyclopedia
  550.  
  551.  
  552.       Periodically, the staff of The MS-DOS Encyclopedia will publish
  553.       updates containing clarifications or corrections to the information
  554.       presented in this current edition. To obtain information about
  555.       receiving these updates, please check the appropriate box on the
  556.       business reply card in the back of this book, or send your name and
  557.       address to: MS-DOS Encyclopedia Update Information, c/o Microsoft
  558.       Press, 16011 NE 36th Way, Box 97017, Redmond, WA 98073-9717.
  559.  
  560.  
  561.  
  562.                     Bulletin Board Service
  563.  
  564.       Microsoft Press is sponsoring a bulletin board on MCI Mail for posting
  565.       and receiving corrections and comments for The MS-DOS Encyclopedia. To
  566.       use this service, log on to MCI Mail and, after receiving the prompt,
  567.       type
  568.  
  569.       VIEW  <Enter>
  570.  
  571.       The Bulletin Board name: prompt will be displayed. Then type
  572.  
  573.       MSPRESS  <Enter>
  574.  
  575.       to connect to the Microsoft Press bulletin board. A list of the
  576.       individual Microsoft Press bulletin boards will be displayed; simply
  577.       choose MSPress DOSENCY to enter the encyclopedia's bulletin board.
  578.  
  579.  
  580.                  Special Companion Disk Offer
  581.  
  582.       Microsoft Press has created a set of valuable, time-saving companion
  583.       disks to The MS-DOS Encyclopedia. They contain the routines and
  584.       functional programs that are listed throughout this book--thousands of
  585.       lines of executable code. Conveniently organized, these disks will
  586.       save you hours of typing time and allow you to start using the code
  587.       immediately. The companion disks are only available directly from
  588.       Microsoft Press. To order, use the special bind-in card in the back of
  589.       the book or write to: Microsoft Press, THE MS-DOS ENCYCLOPEDIA
  590.       COMPANION DISK OFFER, 16011 NE 36th Way, Box 97017, Redmond, WA 98073-
  591.       9717. Send $49.95 for each set of disks, plus $2.50 per set for
  592.       domestic postage and handling, $5.00 per set for foreign orders.
  593.       Payment must be in US funds. You may pay by check or money order
  594.       (payable to Microsoft Press), or by American Express, VISA, or
  595.       MasterCard; please include your credit card number and expiration
  596.       date. Allow 4 weeks for delivery. Please specify 5.25" disks or 3.5"
  597.       disks.
  598.  ───────────────────────────────────────────────────────────────────────────
  599.  
  600.  
  601.  
  602.  Introduction
  603.  
  604.  
  605.       The MS-DOS Encyclopedia is the most comprehensive reference work
  606.       available on Microsoft's industry-standard operating system. Written
  607.       for experienced microcomputer users and programmers, it contains
  608.       detailed, version-specific information on all the MS-DOS commands,
  609.       utilities, and system calls, plus articles by recognized experts in
  610.       specialized areas of MS-DOS programming. This wealth of material is
  611.       organized into major topic areas, each with a format suited to its
  612.       content. Special typographic conventions are also used to clarify the
  613.       material.
  614.  
  615.  
  616.  Organization of the Book
  617.  
  618.       The MS-DOS Encyclopedia is organized into five major sections, plus
  619.       appendixes. Each section has a unique internal organization;
  620.       explanatory introductions are included where appropriate.
  621.  
  622.       Section I, The Development of MS-DOS, presents the history of
  623.       Microsoft's standardsetting operating system from its immediate
  624.       predecessors through version 3.2. Numerous photographs, anecdotes, and
  625.       quotations are included.
  626.  
  627.       Section II, Programming in the MS-DOS Environment, is divided into
  628.       five parts: Structure of MS-DOS, Programming for MS-DOS, Customizing
  629.       MS-DOS, Directions of MS-DOS, and Programming Tools. Each part
  630.       contains several articles by acknowledged experts on these topics. The
  631.       articles include numerous figures, tables, and programming examples
  632.       that provide detail about the subject.
  633.  
  634.       Section III, User Commands, presents all the MS-DOS internal and
  635.       external commands in alphabetic order, including ANSI.SYS, BATCH,
  636.       CONFIG.SYS, DRIVER.SYS, EDLIN, RAMDRIVE.SYS, and VDISK.SYS. Each
  637.       command is presented in a structure that allows the experienced user
  638.       to quickly review syntax and restrictions on variables; the
  639.       less-experienced user can refer to the detailed discussion of the
  640.       command and its uses.
  641.  
  642.       Section IV, Programming Utilities, uses the same format as the User
  643.       Commands section to present the Microsoft programming aids, including
  644.       the DEBUG, SYMDEB, and CodeView debuggers. Although some of these
  645.       utilities are supplied only with Microsoft language products and are
  646.       not included on the MS-DOS system or supplemental disks, their use is
  647.       intrinsic to programming for MS-DOS, and they are therefore included
  648.       to create a comprehensive reference.
  649.  
  650.       Section V, System Calls, documents Interrupts 20H through 27H and
  651.       Interrupt 2FH. The Interrupt 21H functions are listed in individual
  652.       entries. This section, like the User Commands and Programming
  653.       Utilities sections, presents a quick review of usage for the
  654.       experienced user and also provides extensive notes for the less-
  655.       experienced programmer.
  656.  
  657.       The 15 appendixes provide quick-reference materials, including a
  658.       summary of MS-DOS version 3.3, the segmented (new) .EXE file header
  659.       format, an object file dump utility, and the Intel hexadecimal object
  660.       file format. Much of this material is organized into tables or
  661.       bulleted lists for ease of use.
  662.  
  663.       The book includes two indexes--one organized by subject and one
  664.       organized by command name or system-call number. The subject index
  665.       provides comprehensive references to the indexed topic; the command
  666.       index references only the major entry for the command or system call.
  667.  
  668.  
  669.  Program Listings
  670.  
  671.       The MS-DOS Encyclopedia contains numerous program listings in assembly
  672.       language, C, and QuickBASIC, all designed to run on the IBM PC family
  673.       and compatibles. Most of these programs are complete utilities; some
  674.       are routines that can be incorporated into functioning programs.
  675.       Vertical ellipses are often used to indicate where additional code
  676.       would be supplied by the user to create a more functional program. All
  677.       program listings are heavily commented and are essentially self-
  678.       documenting.
  679.  
  680.       The programs were tested using the Microsoft Macro Assembler (MASM)
  681.       version 4.0, the Microsoft C Compiler version 4.0, or the Microsoft
  682.       QuickBASIC Compiler version 2.0.
  683.  
  684.       The functional programs and larger routines are also available on
  685.       disk. Instructions for ordering are on the page preceding this
  686.       introduction and on the mail-in card bound into this volume.
  687.  
  688.  
  689.  Typography and Terminology
  690.  
  691.       Because The MS-DOS Encyclopedia was designed for an advanced audience,
  692.       the reader generally will be familiar with the notation and
  693.       typographic conventions used in this volume. However, for ease of use,
  694.       a few special conventions should be noted.
  695.  
  696.  Typographic conventions
  697.  
  698.       Capital letters are used for MS-DOS internal and external commands in
  699.       text and syntax lines. Capital letters are also used for filenames in
  700.       text.
  701.  
  702.       Italic font indicates user-supplied variable names, procedure names in
  703.       text, parameters whose values are to be supplied by the user, reserved
  704.       words in the C programming language, messages and return values in
  705.       text, and, occasionally, emphasis.
  706.  
  707.       A typographic distinction is made between lowercase l and the numeral
  708.       1 in both text and program listings.
  709.  
  710.       Cross-references appear in the form SECTION NAME: PART NAME,
  711.       COMMAND NAME, OR INTERRUPT NUMBER: Article Name or Function
  712.       Number.
  713.  
  714.       Color indicates user input and program examples.
  715.  
  716.  Terminology
  717.  
  718.       Although not an official IBM name, the term PC-DOS in this book means
  719.       the IBM implementation of MS-DOS. If PC-DOS is referenced and the
  720.       information differs from that for the related MS-DOS version, the
  721.       PC-DOS version number is included. To avoid confusion, the term DOS is
  722.       never used without a modifier.
  723.  
  724.       The names of special function keys are spelled as they are shown on
  725.       the IBM PC keyboard. In particular, the execute key is called Enter,
  726.       not Return. When <Enter> is included in a user-entry line, the user is
  727.       to press the Enter key at the end of the line.
  728.  
  729.       The common key combinations, such as Ctrl-C and Ctrl-Z, appear in this
  730.       form when the actual key to be pressed is being discussed but are
  731.       written as Control-C, Control-Z, and so forth when the resulting code
  732.       is the true reference. Thus, an article might reference the Control-C
  733.       handler but state that it is activated when the user presses Ctrl-C.
  734.  
  735.       Unless specifically indicated, hexadecimal numbers are used
  736.       throughout. These numbers are always followed by the designation H (h
  737.       in the code portions of program listings). Ranges of hexadecimal
  738.       values are indicated with a dash--for example, 07-0AH.
  739.  
  740.       In the printed version of the book, the notation (more) appears
  741.       in italic at the bottom of program listings and tables that
  742.       are continued on the next page. The complete caption or table title
  743.       appears on the first page of a continued element and is designated
  744.       Continued on subsequent pages.
  745.  
  746.       Book Design by The NBBJ Group, Seattle, Washington
  747.  
  748.       Cover Design by Greg Hickman
  749.  
  750.       Principal Typography by Carol L. Luke
  751.  
  752.       The manuscript for this book was prepared and submitted to Microsoft
  753.       Press in electronic form. Text files were processed and formatted
  754.       using Microsoft Word.
  755.  
  756.       Text composition by Microsoft Press in Garamond with display in
  757.       Garamond Bold using the Magna composition system and the Linotronic
  758.       300 laser imagesetter.
  759.  
  760.  
  761.  
  762.  ──────────────────────────────────────────────────────────────────────────
  763.  
  764.  Section I  The Development of MS-DOS
  765.  
  766.  
  767.  
  768.       To many people who use personal computers, MS-DOS is the key that
  769.       unlocks the power of the machine. It is their most visible connection
  770.       to the hardware hidden inside the cabinet, and it is through MS-DOS
  771.       that they can run applications and manage disks and disk files.
  772.  
  773.       In the sense that it opens the door to doing work with a personal
  774.       computer, MS-DOS is indeed a key, and the lock it fits is the Intel
  775.       8086 family of microprocessors. MS-DOS and the chips it works with
  776.       are, in fact, closely connected--so closely that the story of MS-DOS
  777.       is really part of a larger history that encompasses not only an
  778.       operating system but also a microprocessor and, in retrospect, part of
  779.       the explosive growth of personal computing itself.
  780.  
  781.       Chronologically, the history of MS-DOS can be divided into three
  782.       parts. First came the formation of Microsoft and the events preceding
  783.       Microsoft's decision to develop an operating system. Then came the
  784.       creation of the first version of MS-DOS. Finally, there is the
  785.       continuing evolution of MS-DOS since its release in 1981.
  786.  
  787.       Much of the story is based on technical developments, but dates and
  788.       facts alone do not provide an adequate look at the past. Many people
  789.       have been involved in creating MS-DOS and directing the lines along
  790.       which it continues to grow. To the extent that personal opinions and
  791.       memories are appropriate, they are included here to provide a fuller
  792.       picture of the origin and development of MS-DOS.
  793.  
  794.  
  795.  Before MS-DOS
  796.  
  797.       The role of International Business Machines Corporation in Microsoft's
  798.       decision to create MS-DOS has been well publicized. But events, like
  799.       inventions, always build on prior accomplishments, and in this respect
  800.       the roots of MS-DOS reach farther back, to four hardware and software
  801.       developments of the 1970s: Microsoft's disk-based and stand-alone
  802.       versions of BASIC, Digital Research's CP/M-80 operating system, the
  803.       emergence of the 8086 chip, and a disk operating system for the 8086
  804.       developed by Tim Paterson at a hardware company called Seattle
  805.       Computer Products.
  806.  
  807.  Microsoft and BASIC
  808.  
  809.       On the surface, BASIC and MS-DOS might seem to have little in common,
  810.       but in terms of file management, MS-DOS is a direct descendant of a
  811.       Microsoft version of BASIC called Stand-alone Disk BASIC.
  812.  
  813.       Before Microsoft even became a company, its founders, Paul Allen and
  814.       Bill Gates, developed a version of BASIC for a revolutionary small
  815.       computer named the Altair, which was introduced in January 1975 by
  816.       Micro Instrumentation Telemetry Systems (MITS) of Albuquerque, New
  817.       Mexico. Though it has long been eclipsed by other, more powerful makes
  818.       and models, the Altair was the first "personal" computer to appear in
  819.       an environment dominated by minicomputers and mainframes. It was,
  820.       simply, a metal box with a panel of switches and lights for input and
  821.       output, a power supply, a motherboard with 18 slots, and two boards.
  822.       One board was the central processing unit, with the 8-bit Intel 8080
  823.       microprocessor at its heart; the other board provided 256 bytes of
  824.       random-access memory. This miniature computer had no keyboard, no
  825.       monitor, and no device for permanent storage, but it did possess one
  826.       great advantage: a price tag of $397.
  827.  
  828.       Now, given the hindsight of a little more than a decade of
  829.       microcomputing history, it is easy to see that the Altair's
  830.       combination of small size and affordability was the thin edge of a
  831.       wedge that, in just a few years, would move everyday computing power
  832.       away from impersonal monoliths in climate-controlled rooms and onto
  833.       the desks of millions of people. In 1975, however, the computing
  834.       environment was still primarily a matter of data processing for
  835.       specialists rather than personal computing for everyone. Thus when 4
  836.       KB memory expansion boards became available for the Altair, the
  837.       software needed most by its users was not a word processor or a
  838.       spreadsheet, but a programming language--and the language first
  839.       developed for it was a version of BASIC written by Bill Gates and Paul
  840.       Allen.
  841.  
  842.       Gates and Allen had become friends in their teens, while attending
  843.       Lakeside School in Seattle. They shared an intense interest in
  844.       computers, and by the time Gates was in the tenth grade, they and
  845.       another friend named Paul Gilbert had formed a company called Traf-O-
  846.       Data to produce a machine that automated the reading of 16-channel, 4-
  847.       digit, binary-coded decimal (BCD) tapes generated by traffic-
  848.       monitoring recorders. This machine, built by Gilbert, was based on the
  849.       Intel 8008 microprocessor, the predecessor of the 8080 in the Altair.
  850.  
  851.       Although it was too limited to serve as the central processor for a
  852.       general-purpose computer, the 8008 was undeniably the ancestor of the
  853.       8080 as far as its architecture and instruction set were concerned.
  854.       Thus Traf-O-Data's work with the 8008 gave Gates and Allen a head
  855.       start when they later developed their version of BASIC for the Altair.
  856.  
  857.       Paul Allen learned of the Altair from the cover story in the January
  858.       1975 issue of Popular Electronics  magazine. Allen, then an employee
  859.       of Honeywell in Boston, convinced Gates, a student at Harvard
  860.       University, to develop a BASIC for the new computer. The two wrote
  861.       their version of BASIC for the 8080 in six weeks, and Allen flew to
  862.       New Mexico to demonstrate the language for MITS. The developers gave
  863.       themselves the company name of Microsoft and licensed their BASIC to
  864.       MITS as Microsoft's first product.
  865.  
  866.       Though not a direct forerunner of MS-DOS, Altair BASIC, like the
  867.       machine for which it was developed, was a landmark product in the
  868.       history of personal computing. On another level, Altair BASIC was also
  869.       the first link in a chain that led, somewhat circuitously, to Tim
  870.       Paterson and the disk operating system he developed for Seattle
  871.       Computer Products for the 8086 chip.
  872.  
  873.  From paper tape to disk
  874.       Gates and Allen's early BASIC for the Altair was loaded from paper
  875.       tape after the bootstrap to load the tape was entered into memory by
  876.       flipping switches on the front panel of the computer. In late 1975,
  877.       however, MITS decided to release a floppy-disk system for the Altair--
  878.       the first retail floppy-disk system on the market. As a result, in
  879.       February 1976 Allen, by then Director of Software for MITS, asked
  880.       Gates to write a disk-based version of Altair BASIC. The Altair had no
  881.       operating system and hence no method of managing files, so the disk
  882.       BASIC would have to include some file-management routines. It would,
  883.       in effect, have to function as a rudimentary operating system.
  884.  
  885.       Gates, still at Harvard University, agreed to write this version of
  886.       BASIC for MITS. He went to Albuquerque and, as has often been
  887.       recounted, checked into the Hilton Hotel with a stack of yellow legal
  888.       pads. Five days later he emerged, yellow pads filled with the code for
  889.       the new version of BASIC. Arriving at MITS with the code and a request
  890.       to be left alone, Gates began typing and debugging and, after another
  891.       five days, had Disk BASIC running on the Altair.
  892.  
  893.       This disk-based BASIC marked Microsoft's entry into the business of
  894.       languages for personal computers--not only for the MITS Altair, but
  895.       also for such companies as Data Terminals Corporation and General
  896.       Electric. Along the way, Microsoft BASIC took on added features, such
  897.       as enhanced mathematics capabilities, and, more to the point in terms
  898.       of MS-DOS, evolved into Stand-alone Disk BASIC, produced for NCR in
  899.       1977.
  900.  
  901.       Designed and coded by Marc McDonald, Stand-alone Disk BASIC included a
  902.       file-management scheme called the FAT, or file allocation table that
  903.       used a linked list for managing disk files. The FAT, born during one
  904.       of a series of discussions between McDonald and Bill Gates, enabled
  905.       disk-allocation information to be kept in one location, with "chained"
  906.       references pointing to the actual storage locations on disk. Fast and
  907.       flexible, this file-management strategy was later used in a stand-
  908.       alone version of BASIC for the 8086 chip and eventually, through an
  909.       operating system named M-DOS, became the basis for the file-handling
  910.       routines in MS-DOS.
  911.  
  912.  M-DOS
  913.  
  914.       During 1977 and 1978, Microsoft adapted both BASIC and Microsoft
  915.       FORTRAN for an increasingly popular 8-bit operating system called
  916.       CP/M. At the end of 1978, Gates and Allen moved Microsoft from
  917.       Albuquerque to Bellevue, Washington. The company continued to
  918.       concentrate on programming languages, producing versions of BASIC for
  919.       the 6502 and the TI9900.
  920.  
  921.       During this same period, Marc McDonald also worked on developing an 8-
  922.       bit operating system called M-DOS (usually pronounced "Midas" or "My
  923.       DOS"). Although it never became a real part of the Microsoft product
  924.       line, M-DOS was a true multitasking operating system modeled after the
  925.       DEC TOPS-10 operating system. M-DOS provided good performance and,
  926.       with a more flexible FAT than that built into BASIC, had a better
  927.       file-handling structure than the up-and-coming CP/M operating system.
  928.       At about 30 KB, however, M-DOS was unfortunately too big for an 8-bit
  929.       environment and so ended up being relegated to the back room. As Allen
  930.       describes it, "Trying to do a large, full-blown operating system on
  931.       the 8080 was a lot of work, and it took a lot of memory. The 8080
  932.       addresses only 64 K, so with the success of CP/M, we finally concluded
  933.       that it was best not to press on with that."
  934.  
  935.  CP/M
  936.  
  937.       In the volatile microcomputer era of 1976 through 1978, both users and
  938.       developers of personal computers quickly came to recognize the
  939.       limitations of running applications on top of Microsoft's Stand-alone
  940.       Disk BASIC or any other language. MITS, for example, scheduled a July
  941.       1976 release date for an independent operating system for its machine
  942.       that used the code from the Altair's Disk BASIC. In the same year,
  943.       Digital Research, headed by Gary Kildall, released its Control
  944.       Program/Monitor, or CP/M.
  945.  
  946.       CP/M was a typical microcomputer software product of the 1970s in that
  947.       it was written by one person, not a group, in response to a specific
  948.       need that had not yet been filled. One of the most interesting aspects
  949.       of CP/M's history is that the software was developed several years
  950.       before its release date--actually, several years before the hardware
  951.       on which it would be a standard became commercially available.
  952.  
  953.       In 1973, Kildall, a professor of computer science at the Naval
  954.       Postgraduate School in Monterey, California, was working with an 8080-
  955.       based small computer given him by Intel Corporation in return for some
  956.       programming he had done for the company. Kildall's machine, equipped
  957.       with a monitor and paper-tape reader, was certainly advanced for the
  958.       time, but Kildall became convinced that magnetic-disk storage would
  959.       make the machine even more efficient than it was.
  960.  
  961.       Trading some programming for a disk drive from Shugart, Kildall first
  962.       attempted to build a drive controller on his own. Lacking the
  963.       necessary engineering ability, he contacted a friend, John Torode, who
  964.       agreed to handle the hardware aspects of interfacing the computer and
  965.       the disk drive while Kildall worked on the software portion--the
  966.       refinement of an operating system he had written earlier that year.
  967.       The result was CP/M.
  968.  
  969.       The version of CP/M developed by Kildall in 1973 underwent several
  970.       refinements. Kildall enhanced the CP/M debugger and assembler, added a
  971.       BASIC interpreter, and did some work on an editor, eventually
  972.       developing the product that, from about 1977 until the appearance of
  973.       the IBM Personal Computer, set the standard for 8-bit microcomputer
  974.       operating systems.
  975.  
  976.       Digital Research's CP/M included a command interpreter called CCP
  977.       (Console Command Processor), which acted as the interface between the
  978.       user and the operating system itself, and an operations handler called
  979.       BDOS (Basic Disk Operating System), which was responsible for file
  980.       storage, directory maintenance, and other such housekeeping chores.
  981.       For actual input and output--disk I/O, screen display, print requests,
  982.       and so on--CP/M included a BIOS (Basic Input/Output System) tailored
  983.       to the requirements of the hardware on which the operating system ran.
  984.  
  985.       For file storage, CP/M used a system of eight-sector allocation units.
  986.       For any given file, the allocation units were listed in a directory
  987.       entry that included the filename and a table giving the disk locations
  988.       of 16 allocation units. If a long file required more than 16
  989.       allocation units, CP/M created additional directory entries as
  990.       required. Small files could be accessed rapidly under this system, but
  991.       large files with more than a single directory entry could require
  992.       numerous relatively time-consuming disk reads to find needed
  993.       information.
  994.  
  995.       At the time, however, CP/M was highly regarded and gained the support
  996.       of a broad base of hardware and software developers alike. Quite
  997.       powerful for its size (about 4KB), it was, in all respects, the
  998.       undisputed standard in the 8-bit world, and remained so until, and
  999.       even after, the appearance of the 8086.
  1000.  
  1001.  The 8086
  1002.  
  1003.       When Intel released the 8-bit 8080 chip in 1974, the Altair was still
  1004.       a year in the future. The 8080 was designed not to make computing a
  1005.       part of everyday life but to make household appliances and industrial
  1006.       machines more intelligent. By 1978, when Intel introduced the 16-bit
  1007.       8086, the microcomputer was a reality and the new chip represented a
  1008.       major step ahead in performance and memory capacity. The 8086's full
  1009.       16-bit buses made it faster than the 8080, and its ability to address
  1010.       one megabyte of random-access memory was a giant step beyond the
  1011.       8080's 64 KB limit. Although the 8086 was not compatible with the
  1012.       8080, it was architecturally similar to its predecessor and 8080
  1013.       source code could be mechanically translated to run on it. This
  1014.       translation capability, in fact, was a major influence on the design
  1015.       of Tim Paterson's operating system for the 8086 and, through
  1016.       Paterson's work, on the first released version of MS-DOS.
  1017.  
  1018.       When the 8086 arrived on the scene, Microsoft, like other developers,
  1019.       was confronted with two choices: continue working in the familiar 8-
  1020.       bit world or turn to the broader horizons offered by the new 16-bit
  1021.       technology. For a time, Microsoft did both. Acting on Paul Allen's
  1022.       suggestion, the company developed the SoftCard for the popular Apple
  1023.       II, which was based on the 8-bit 6502 microprocessor. The SoftCard
  1024.       included a Z80 microprocessor and a copy of CP/M-80 licensed from
  1025.       Digital Research. With the SoftCard, Apple II users could run any
  1026.       program or language designed to run on a CP/M machine.
  1027.  
  1028.       It was 16-bit technology, however, that held the most interest for
  1029.       Gates and Allen, who believed that this would soon become the standard
  1030.       for microcomputers. Their optimism was not universal--more than one
  1031.       voice in the trade press warned that industry investment in 8-bit
  1032.       equipment and software was too great to successfully introduce a new
  1033.       standard. Microsoft, however, disregarded these forecasts and entered
  1034.       the 16-bit arena as it had with the Altair: by developing a stand-
  1035.       alone version of BASIC for the 8086.
  1036.  
  1037.       At the same time and, coincidentally, a few miles south in Tukwila,
  1038.       Washington, a major contribution to MS-DOS was taking place. Tim
  1039.       Paterson, working at Seattle Computer Products, a company that built
  1040.       memory boards, was developing an 8086 CPU card for use in an S-100 bus
  1041.       machine.
  1042.  
  1043.  86-DOS
  1044.  
  1045.       Paterson was introduced to the 8086 chip at a seminar held by Intel in
  1046.       June 1978. He had attended the seminar at the suggestion of his
  1047.       employer, Rod Brock of Seattle Computer Products. The new chip sparked
  1048.       his interest because, as he recalls, "all its instructions worked on
  1049.       both 8 and 16 bits, and you didn't have to do everything through the
  1050.       accumulator. It was also real fast--it could do a 16-bit ADD in three
  1051.       clocks."
  1052.  
  1053.       After the seminar, Paterson--again with Brock's support--began work
  1054.       with the 8086. He finished the design of his first 8086 CPU board in
  1055.       January 1979 and by late spring had developed a working CPU, as well
  1056.       as an assembler and an 8086 monitor. In June, Paterson took his system
  1057.       to Microsoft to try it with Stand-alone BASIC, and soon after,
  1058.       Microsoft BASIC was running on Seattle Computer's new board.
  1059.  
  1060.       During this period, Paterson also received a call from Digital
  1061.       Research asking whether they could borrow the new board for developing
  1062.       CP/M-86. Though Seattle Computer did not have a board to loan,
  1063.       Paterson asked when CP/M-86 would be ready. Digital's representative
  1064.       said December 1979, which meant, according to Paterson's diary, "we'll
  1065.       have to live with Stand-alone BASIC for a few months after we start
  1066.       shipping the CPU, but then we'll be able to switch to a real operating
  1067.       system."
  1068.  
  1069.       Early in June, Microsoft and Tim Paterson attended the National
  1070.       Computer Conference in New York. Microsoft had been invited to share
  1071.       Lifeboat Associates' ten-by-ten foot booth, and Paterson had been
  1072.       invited by Paul Allen to show BASIC running on an S-100 8086 system.
  1073.       At that meeting, Paterson was introduced to Microsoft's M-DOS, which
  1074.       he found interesting because it used a system for keeping track of
  1075.       disk files--the FAT developed for Stand-alone BASIC--that was
  1076.       different from anything he had encountered.
  1077.  
  1078.       After this meeting, Paterson continued working on the 8086 board, and
  1079.       by the end of the year, Seattle Computer Products began shipping the
  1080.       CPU with a BASIC option.
  1081.  
  1082.       When CP/M-86 had still not become available by April 1980, Seattle
  1083.       Computer Products decided to develop a 16-bit operating system of its
  1084.       own. Originally, three operating systems were planned: a single-user
  1085.       system, a multiuser version, and a small interim product soon
  1086.       informally christened QDOS (for Quick and Dirty Operating System) by
  1087.       Paterson.
  1088.  
  1089.       Both Paterson (working on QDOS) and Rod Brock knew that a standard
  1090.       operating system for the 8086 was mandatory if users were to be
  1091.       assured of a wide range of application software and languages. CP/M
  1092.       had become the standard for 8-bit machines, so the ability to
  1093.       mechanically translate existing CP/M applications to run on a 16-bit
  1094.       system became one of Paterson's major goals for the new operating
  1095.       system. To achieve this compatibility, the system he developed
  1096.       mimicked CP/M-80's functions and command structure, including its use
  1097.       of file control blocks (FCBs) and its approach to executable files.
  1098.  
  1099.       At the same time, however, Paterson was dissatisfied with certain
  1100.       elements of CP/M, one of them being its file-allocation system, which
  1101.       he considered inefficient in the use of disk space and too slow in
  1102.       operation. So for fast, efficient file handling, he used a file
  1103.       allocation table, as Microsoft had done with Stand-alone Disk BASIC
  1104.       and M-DOS. He also wrote a translator to translate 8080 code to 8086
  1105.       code, and he then wrote an assembler in Z80 assembly language and used
  1106.       the translator to translate it.
  1107.  
  1108.       Four months after beginning work, Paterson had a functioning 6 KB
  1109.       operating system, officially renamed 86-DOS, and in September 1980 he
  1110.       contacted Microsoft again, this time to ask the company to write a
  1111.       version of BASIC to run on his system.
  1112.  
  1113.  IBM
  1114.  
  1115.       While Paterson was developing 86-DOS, the third major element leading
  1116.       to the creation of MS-DOS was gaining force at the opposite end of the
  1117.       country. IBM, until then seemingly oblivious to most of the
  1118.       developments in the microcomputer world, had turned its attention to
  1119.       the possibility of developing a low-end workstation for a market it
  1120.       knew well: business and business people.
  1121.  
  1122.       On August 21, 1980, a study group of IBM representatives from Boca
  1123.       Raton, Florida, visited Microsoft. This group, headed by a man named
  1124.       Jack Sams, told Microsoft of IBM's interest in developing a computer
  1125.       based on a microprocessor. IBM was, however, unsure of microcomputing
  1126.       technology and the microcomputing market. Traditionally, IBM relied on
  1127.       long development cycles--typically four or five years--and was aware
  1128.       that such lengthy design periods did not fit the rapidly evolving
  1129.       microcomputer environment.
  1130.  
  1131.       One of IBM's solutions--the one outlined by Sams's group--was to base
  1132.       the new machine on products from other manufacturers. All the
  1133.       necessary hardware was available, but the same could not be said of
  1134.       the software. Hence the visit to Microsoft with the question: Given
  1135.       the specifications for an 8-bit computer, could Microsoft write a ROM
  1136.       BASIC for it by the following April?
  1137.  
  1138.       Microsoft responded positively, but added questions of its own: Why
  1139.       introduce an 8-bit computer? Why not release a 16-bit machine based on
  1140.       Intel's 8086 chip instead? At the end of this meeting--the first of
  1141.       many--Sams and his group returned to Boca Raton with a proposal for
  1142.       the development of a low-end, 16-bit business workstation. The venture
  1143.       was named Project Chess.
  1144.  
  1145.       One month later, Sams returned to Microsoft asking whether Gates and
  1146.       Allen could, still by April 1981, provide not only BASIC but also
  1147.       FORTRAN, Pascal, and COBOL for the new computer. This time the answer
  1148.       was no because, though Microsoft's BASIC had been designed to run as a
  1149.       stand-alone product, it was unique in that respect--the other
  1150.       languages would need an operating system. Gates suggested CP/M-86,
  1151.       which was then still under development at Digital Research, and in
  1152.       fact made the initial contact for IBM. Digital Research and IBM did
  1153.       not come to any agreement, however.
  1154.  
  1155.       Microsoft, meanwhile, still wanted to write all the languages for
  1156.       IBM--approximately 400 KB of code. But to do this within the allotted
  1157.       six-month schedule, the company needed some assurances about the
  1158.       operating system IBM was going to use. Further, it needed specific
  1159.       information on the internals of the operating system, because the ROM
  1160.       BASIC would interact intimately with the BIOS.
  1161.  
  1162.  The turning point
  1163.  
  1164.       That state of indecision, then, was Microsoft's situation on Sunday,
  1165.       September 28, 1980, when Bill Gates, Paul Allen, and Kay Nishi, a
  1166.       Microsoft vice president and president of ASCII Corporation in Japan,
  1167.       sat in Gates's eighth-floor corner office in the Old National Bank
  1168.       Building in Bellevue, Washington. Gates recalls, "Kay and I were just
  1169.       sitting there at night and Paul was on the couch. Kay said, `Got to do
  1170.       it, got to do it.' It was only 20 more K of code at most--actually, it
  1171.       turned out to be 12 more K on top of the 400. It wasn't that big a
  1172.       deal, and once Kay said it, it was obvious. We'd always wanted to do a
  1173.       low-end operating system, we had specs for low-end operating systems,
  1174.       and we knew we were going to do one up on 16-bit."
  1175.  
  1176.       At that point, Gates and Allen began looking again at Microsoft's
  1177.       proposal to IBM. Their estimated 400 KB of code included four
  1178.       languages, an assembler, and a linker. To add an operating system
  1179.       would require only another 20 KB or so, and they already knew of a
  1180.       working model for the 8086: Tim Paterson's 86-DOS. The more Gates,
  1181.       Allen, and Nishi talked that night about developing an operating
  1182.       system for IBM's new computer, the more possible--even preferable--the
  1183.       idea became.
  1184.  
  1185.       Allen's first step was to contact Rod Brock at Seattle Computer
  1186.       Products to tell him that Microsoft wanted to develop and market SCP's
  1187.       operating system and that the company had an OEM customer for it.
  1188.       Seattle Computer Products, which was not in the business of marketing
  1189.       software, agreed and licensed 86-DOS to Microsoft. Eventually, SCP
  1190.       sold the operating system to Microsoft for $50,000, favorable language
  1191.       licenses, and a license back from Microsoft to use 86-DOS on its own
  1192.       machines.
  1193.  
  1194.       In October 1980, with 86-DOS in hand, Microsoft submitted another
  1195.       proposal to IBM. This time the plan included both an operating system
  1196.       and the languages for the new computer. Time was short and the
  1197.       boundaries between the languages and the operating system were
  1198.       unclear, so Microsoft explained that it needed to control the
  1199.       development of the operating system in order to guarantee delivery by
  1200.       spring of 1981. In November, IBM signed the contract.
  1201.  
  1202.  
  1203.  Creating MS-DOS
  1204.  
  1205.       At Thanksgiving, a prototype of the IBM machine arrived at Microsoft
  1206.       and Bill Gates, Paul Allen, and, primarily, Bob O'Rear began a
  1207.       schedule of long, sometimes hectic days and total immersion in the
  1208.       project. As O'Rear recalls, "If I was awake, I was thinking about the
  1209.       project."
  1210.  
  1211.       The first task handled by the team was bringing up 86-DOS on the new
  1212.       machine. This was a challenge because the work had to be done in a
  1213.       constantly changing hardware environment while changes were also being
  1214.       made to the specifications of the budding operating system itself.
  1215.  
  1216.       As part of the process, 86-DOS had to be compiled and integrated with
  1217.       the BIOS, which Microsoft was helping IBM to write, and this task was
  1218.       complicated by the media. Paterson's 86-DOS--not counting utilities
  1219.       such as EDLIN, CHKDSK, and INIT (later named FORMAT)--arrived at
  1220.       Microsoft as one large assembly-language program on an 8-inch floppy
  1221.       disk. The IBM machine, however, used 5-1/4-inch disks, so Microsoft
  1222.       needed to determine the format of the new disk and then find a way to
  1223.       get the operating system from the old format to the new.
  1224.  
  1225.       This work, handled by O'Rear, fell into a series of steps. First, he
  1226.       moved a section of code from the 8-inch disk and compiled it. Then, he
  1227.       converted the code to Intel hexadecimal format. Next, he uploaded it
  1228.       to a DEC-2020 and from there downloaded it to a large Intel fixed-disk
  1229.       development system with an In-Circuit Emulator. The DEC-2020 used for
  1230.       this task was also used in developing the BIOS, so there was
  1231.       additional work in downloading the BIOS to the Intel machine,
  1232.       converting it to hexadecimal format, moving it to an IBM development
  1233.       system, and then crossloading it to the IBM prototype.
  1234.  
  1235.       Defining and implementing the MS-DOS disk format--different from
  1236.       Paterson's 8-inch format--was an added challenge. Paterson's ultimate
  1237.       goal for 86-DOS was logical device independence, but during this first
  1238.       stage of development, the operating system simply had to be converted
  1239.       to handle logical records that were independent of the physical record
  1240.       size.
  1241.  
  1242.       Paterson, still with Seattle Computer Products, continued to work on
  1243.       86-DOS and by the end of 1980 had improved its logical device
  1244.       independence by adding functions that streamlined reading and writing
  1245.       multiple sectors and records, as well as records of variable size. In
  1246.       addition to making such refinements of his own, Paterson also worked
  1247.       on dozens of changes requested by Microsoft, from modifications to the
  1248.       operating system's startup messages to changes in EDLIN, the line
  1249.       editor he had written for his own use. Throughout this process, IBM's
  1250.       security restrictions meant that Paterson was never told the name of
  1251.       the OEM and never shown the prototype machines until he left Seattle
  1252.       Computer Products and joined Microsoft in May 1981.
  1253.  
  1254.       And of course, throughout the process the developers encountered the
  1255.       myriad loose ends, momentary puzzles, bugs, and unforeseen details
  1256.       without which no project is complete. There were, for example, the
  1257.       serial card interrupts that occurred when they should not and,
  1258.       frustratingly, a hardware constraint that the BIOS could not
  1259.       accommodate at first and that resulted in sporadic crashes during
  1260.       early MS-DOS operations.
  1261.  
  1262.       In spite of such difficulties, however, the new operating system ran
  1263.       on the prototype for the first time in February 1981. In the six
  1264.       months that followed, the system was continually refined and expanded,
  1265.       and by the time of its debut in August 1981, MS-DOS, like the IBM
  1266.       Personal Computer on which it appeared, had become a functional
  1267.       product for home and office use.
  1268.  
  1269.  
  1270.  
  1271.  Version 1
  1272.  
  1273.  
  1274.       The first release of MS-DOS, version 1.0, was not the operating system
  1275.       Microsoft envisioned as a final model for 16-bit computer systems.
  1276.       According to Bill Gates, "Basically, what we wanted to do was one that
  1277.       was more like MS-DOS 2, with the hierarchical file system and
  1278.       everything...the key thing [in developing version 1.0] was my saying,
  1279.       `Look, we can come out with a subset first and just go upward from
  1280.       that.'"
  1281.  
  1282.       This first version--Gates's subset of MS-DOS--was actually a good
  1283.       compromise between the present and the future in two important
  1284.       respects: It enabled Microsoft to meet the development schedule for
  1285.       IBM and it maintained program-translation compatibility with CP/M.
  1286.  
  1287.       Available only for the IBM Personal Computer, MS-DOS 1.0 consisted of
  1288.       4000 lines of assembly-language source code and ran in 8 KB of memory.
  1289.       In addition to utilities such as DEBUG, EDLIN, and FORMAT, it was
  1290.       organized into three major files. One file, IBMBIO.COM, interfaced
  1291.       with the ROM BIOS for the IBM PC and contained the disk and character
  1292.       input/output system. A second file, IBMDOS.COM, contained the DOS
  1293.       kernel, including the application-program interface and the disk-file
  1294.       and memory managers. The third file, COMMAND.COM, was the external
  1295.       command processor--the part of MS-DOS most visible to the user.
  1296.  
  1297.       To take advantage of the existing base of languages and such popular
  1298.       applications as WordStar and dBASE II, MS-DOS was designed to allow
  1299.       software developers to mechanically translate source code for the 8080
  1300.       to run on the 8086. And because of this link, MS-DOS looked and acted
  1301.       like CP/M-80, at that time still the standard among operating systems
  1302.       for microcomputers. Like its 8-bit relative, MS-DOS used eight-
  1303.       character filenames and three-character extensions, and it had the
  1304.       same conventions for identifying disk drives in command prompts. For
  1305.       the most part, MS-DOS also used the same command language, offered the
  1306.       same file services, and had the same general structure as CP/M. The
  1307.       resemblance was even more striking at the programming level, with an
  1308.       almost one-to-one correspondence between CP/M and MS-DOS in the system
  1309.       calls available to application programs.
  1310.  
  1311.  
  1312.  New Features
  1313.  
  1314.       MS-DOS was not, however, a CP/M twin, nor had Microsoft designed it to
  1315.       be inextricably bonded to the IBM PC. Hoping to create a product that
  1316.       would be successful over the long term, Microsoft had taken steps to
  1317.       make MS-DOS flexible enough to accommodate changes and new directions
  1318.       in the hardware technology--disks, memory boards, even
  1319.       microprocessors--on which it depended. The first steps toward this
  1320.       independence from specific hardware configurations appeared in MS-DOS
  1321.       version 1.0 in the form of device-independent input and output,
  1322.       variable record lengths, relocatable program files, and a replaceable
  1323.       command processor.
  1324.  
  1325.       MS-DOS made input and output device-independent by treating peripheral
  1326.       devices as if they were files. To do this, it assigned a reserved
  1327.       filename to each of the three devices it recognized: CON for the
  1328.       console (keyboard and display), PRN for the printer, and AUX for the
  1329.       auxiliary serial ports. Whenever one of these reserved names appeared
  1330.       in the file control block of a file named in a command, all operations
  1331.       were directed to the device, rather than to a disk file. (A file
  1332.       control block, or FCB, is a 37-byte housekeeping record located in an
  1333.       application's portion of the memory space. It includes, among other
  1334.       things, the filename, the extension, and information about the size
  1335.       and starting location of the file on disk.)
  1336.  
  1337.       Such device independence benefited both application developers and
  1338.       computer users. On the development side, it meant that applications
  1339.       could use one set of read and write calls, rather than a number of
  1340.       different calls for different devices, and it meant that an
  1341.       application did not have to be modified if new devices were added to
  1342.       the system. From the user's point of view, device independence meant
  1343.       greater flexibility. For example, even if a program had been designed
  1344.       for disk I/O only, the user could still use a file for input or direct
  1345.       output to the printer.
  1346.  
  1347.       Variable record lengths provided another step toward logical
  1348.       independence. In CP/M, logical and physical record lengths were
  1349.       identical: 128 bytes. Files could be accessed only in units of 128
  1350.       bytes and file sizes were always maintained in multiples of 128 bytes.
  1351.       With MS-DOS, however, physical sector sizes were of no concern to the
  1352.       user. The operating system maintained file lengths to the exact size
  1353.       in bytes and could be relied on to support logical records of any size
  1354.       desired.
  1355.  
  1356.       Another new feature in MS-DOS was the relocatable program file. Unlike
  1357.       CP/M, MS-DOS had the ability to load two different types of program
  1358.       files, identified by the extensions .COM and .EXE. Program files
  1359.       ending with .COM mimicked the binary files in CP/M. They were more
  1360.       compact than .EXE files and loaded somewhat faster, but the combined
  1361.       program code, stack, and data could be no larger than 64 KB. A .EXE
  1362.       program, on the other hand, could be much larger, because the file
  1363.       could contain multiple segments, each of which could be up to 64 KB.
  1364.       Once the segments were in memory, MS-DOS then used part of the file
  1365.       header, the relocation table, to automatically set the correct
  1366.       addresses for each of the different program segments.
  1367.  
  1368.       In addition to supporting .EXE files, MS-DOS made the external command
  1369.       processor, COMMAND.COM, more adaptable by making it a separate
  1370.       relocatable file just like any other program. It could therefore be
  1371.       replaced by a custom command processor, as long as the new file was
  1372.       also named COMMAND.COM.
  1373.  
  1374.  
  1375.  Performance
  1376.  
  1377.       Everyone familiar with the IBM PC knows that MS-DOS eventually became
  1378.       the dominant operating system on 8086-based microcomputers. There were
  1379.       several reasons for this, not least of which was acceptance of MS-DOS
  1380.       as the operating system for IBM's phenomenally successful line of
  1381.       personal computers. But even though MS-DOS was the only operating
  1382.       system available when the first IBM PCs were shipped, positioning
  1383.       alone would not necessarily have guaranteed its ability to outstrip
  1384.       CP/M-86, which appeared six months later. MS-DOS also offered
  1385.       significant advantages to the user in a number of areas, including the
  1386.       allocation and management of storage space on disk.
  1387.  
  1388.       Like CP/M, MS-DOS shared out disk space in allocation units. Unlike
  1389.       CP/M, however, MS-DOS mapped the use of these allocation units in a
  1390.       central file allocation table--the FAT--that was always in memory.
  1391.       Both operating systems used a directory entry for recording
  1392.       information about each file, but whereas a CP/M directory entry
  1393.       included an allocation map--a list of sixteen 1 KB allocation units
  1394.       where successive parts of the file were stored--an MS-DOS directory
  1395.       entry pointed only to the first allocation unit in the FAT and each
  1396.       entry in the table then pointed to the next unit associated with the
  1397.       file. Thus, CP/M might require several directory entries (and more
  1398.       than one disk access) to load a file larger than 16 KB, but MS-DOS
  1399.       retained a complete in-memory list of all file components and all
  1400.       available disk space without having to access the disk at all. As a
  1401.       result, MS-DOS's ability to find and load even very long files was
  1402.       extremely rapid compared with CP/M's.
  1403.  
  1404.       Two other important features--the ability to read and write multiple
  1405.       records with one operating-system call and the transient use of memory
  1406.       by the MS-DOS command processor--provided further efficiency for both
  1407.       users and developers.
  1408.  
  1409.       The independence of the logical record from the physical sector laid
  1410.       the foundation for the ability to read and write multiple sectors.
  1411.       When reading multiple records in CP/M, an application had to issue a
  1412.       read function call for each sector, one at a time. With MS-DOS, the
  1413.       application could issue one read function call, giving the operating
  1414.       system the beginning record and the number of records to read, and MS-
  1415.       DOS would then load all of the corresponding sectors automatically.
  1416.  
  1417.       Another innovative feature of MS-DOS version 1.0 was the division of
  1418.       the command processor, COMMAND.COM, into a resident portion and a
  1419.       transient portion. (There is also a third part, an initialization
  1420.       portion, which carries out the commands in an AUTOEXEC batch file at
  1421.       startup. This part of COMMAND.COM is discarded from memory when its
  1422.       work is finished.) The reason for creating resident and transient
  1423.       portions of the command processor had to do with maximizing the
  1424.       efficiency of MS-DOS for the user: On the one hand, the programmers
  1425.       wanted COMMAND.COM to include commonly requested functions, such as
  1426.       DIR and COPY, for speed and ease of use; on the other hand, adding
  1427.       these commands meant increasing the size of the command processor,
  1428.       with a resulting decrease in the memory available to application
  1429.       programs. The solution to this trade-off of speed versus utility was
  1430.       to include the extra functions in a transient portion of COMMAND.COM
  1431.       that could be overwritten by any application requiring more memory. To
  1432.       maintain the integrity of the functions for the user, the resident
  1433.       part of COMMAND.COM was given the job of checking the transient
  1434.       portion for damage when an application terminated. If necessary, this
  1435.       resident portion would then load a new copy of its transient partner
  1436.       into memory.
  1437.  
  1438.  
  1439.  Ease of Use
  1440.  
  1441.       In addition to its moves toward hardware independence and efficiency,
  1442.       MS-DOS included several services and utilities designed to make life
  1443.       easier for users and application developers. Among these services were
  1444.       improved error handling, automatic logging of disks, date and time
  1445.       stamping of files, and batch processing.
  1446.  
  1447.       MS-DOS and the IBM PC were targeted at a nontechnical group of users,
  1448.       and from the beginning IBM had stressed the importance of data
  1449.       integrity. Because data is most likely to be lost when a user responds
  1450.       incorrectly to an error message, an effort was made to include concise
  1451.       yet unambiguous messages in MS-DOS. To further reduce the risks of
  1452.       misinterpretation, Microsoft used these messages consistently across
  1453.       all MS-DOS functions and utilities and encouraged developers to use
  1454.       the same messages, where appropriate, in their applications.
  1455.  
  1456.       In a further attempt to safeguard data, MS-DOS also trapped hard
  1457.       errors--such as critical hardware errors--that had previously been
  1458.       left to the hardware-dependent logic. Now the hardware logic could
  1459.       simply report the nature of the error and the operating system would
  1460.       handle the problem in a consistent and systematic way. MS-DOS could
  1461.       also trap the Control-C break sequence so that an application could
  1462.       either protect against accidental termination by the user or provide a
  1463.       graceful exit when appropriate.
  1464.  
  1465.       To reduce errors and simplify use of the system, MS-DOS also
  1466.       automatically updated memory information about the disk when it was
  1467.       changed. In CP/M, users had to log new disks as they changed them--a
  1468.       cumbersome procedure on single-disk systems or when data was stored on
  1469.       multiple disks. In MS-DOS, new disks were automatically logged as long
  1470.       as no file was currently open.
  1471.  
  1472.       Another new feature--one visible with the DIR command--was date and
  1473.       time stamping of disk files. Even in its earliest forms, MS-DOS
  1474.       tracked the system date and displayed it at every startup, and now,
  1475.       when it turned out that only the first 16 bytes of a directory entry
  1476.       were needed for file-header information, the MS-DOS programmers
  1477.       decided to use some of the remaining 16 bytes to record the date and
  1478.       time of creation or update (and the size of the file) as well.
  1479.  
  1480.       Batch processing was originally added to MS-DOS to help IBM. IBM
  1481.       wanted to run scripts--sequences of commands or other operations--one
  1482.       after the other to test various functions of the system. To do this,
  1483.       the testers needed an automated method of calling routines
  1484.       sequentially. The result was the batch processor, which later also
  1485.       provided users with the convenience of saving and running MS-DOS
  1486.       commands as batch files.
  1487.  
  1488.       Finally, MS-DOS increased the options available to a program when it
  1489.       terminated. For example, in less sophisticated operating systems,
  1490.       applications and other programs remained in memory only as long as
  1491.       they were active; when terminated, they were removed from memory. MS-
  1492.       DOS, however, added a terminate-and-stay-resident function that
  1493.       enabled a program to be locked into memory and, in effect, become part
  1494.       of the operating-system environment until the computer system itself
  1495.       was shut down or restarted.
  1496.  
  1497.  
  1498.  The Marketplace
  1499.  
  1500.       When IBM announced the Personal Computer, it said that the new machine
  1501.       would run three operating systems: MS-DOS, CP/M-86, and SofTech
  1502.       Microsystem's p-System. Of the three, only MS-DOS was available when
  1503.       the IBM PC shipped. Nevertheless, when MS-DOS was released, nine out
  1504.       of ten programs on the InfoWorld bestseller list for 1981 ran under
  1505.       CP/M-80, and CP/M-86, which became available about six months later,
  1506.       was the operating system of choice to most writers and reviewers in
  1507.       the trade press.
  1508.  
  1509.       Understandably, MS-DOS was compared with CP/M-80 and, later, CP/M-86.
  1510.       The main concern was compatibility: To what extent was Microsoft's new
  1511.       operating system compatible with the existing standard? No one could
  1512.       have foreseen that MS-DOS would not only catch up with but supersede
  1513.       CP/M. Even Bill Gates now recalls that "our most optimistic view of
  1514.       the number of machines using MS-DOS wouldn't have matched what really
  1515.       ended up happening."
  1516.  
  1517.       To begin with, the success of the IBM PC itself surprised many
  1518.       industry watchers. Within a year, IBM was selling 30,000 PCs per
  1519.       month, thanks in large part to a business community that was already
  1520.       comfortable with IBM's name and reputation and, at least in
  1521.       retrospect, was ready for the leap to personal computing. MS-DOS, of
  1522.       course, benefited enormously from the success of the IBM PC--in large
  1523.       part because IBM supplied all its languages and applications in MS-DOS
  1524.       format.
  1525.  
  1526.       But, at first, writers in the trade press still believed in CP/M and
  1527.       questioned the viability of a new operating system in a world
  1528.       dominated by CP/M-80. Many assumed, incorrectly, that a CP/M-86
  1529.       machine could run CP/M-80 applications. Even before CP/M-86 was
  1530.       available, Future Computing  referred to the IBM PC as the "CP/M
  1531.       Record Player"--presumably in anticipation of a vast inventory of CP/M
  1532.       applications for the new computer--and led its readers to assume that
  1533.       the PC was actually a CP/M machine.
  1534.  
  1535.       Microsoft, meanwhile, held to the belief that the success of IBM's
  1536.       machine or any other 16-bit microcomputer depended ultimately on the
  1537.       emergence of an industry standard for a 16-bit operating system.
  1538.       Software developers could not afford to develop software for even two
  1539.       or three different operating systems, and users could (or would) not
  1540.       pay the prices the developers would have to charge if they did.
  1541.       Furthermore, users would almost certainly rebel against the
  1542.       inconvenience of sharing data stored under different operating-system
  1543.       formats. There had to be one operating system, and Microsoft wanted
  1544.       MS-DOS to be the one.
  1545.  
  1546.       The company had already taken the first step toward a standard by
  1547.       choosing hardware independent designs wherever possible. Machine
  1548.       independence meant portability, and portability meant that Microsoft
  1549.       could sell one version of MS-DOS to different hardware manufacturers
  1550.       who, in turn, could adapt it to their own equipment. Portability
  1551.       alone, however, was no guarantee of industry-wide acceptance. To make
  1552.       MS-DOS the standard, Microsoft needed to convince software developers
  1553.       to write programs for MS-DOS. And in 1981, these developers were a
  1554.       little confused about IBM's new operating system.
  1555.  
  1556.  An operating system by any other name...
  1557.  
  1558.       A tangle of names gave rise to one point of confusion about MS-DOS.
  1559.       Tim Paterson's "Quick and Dirty Operating System" for the 8086 was
  1560.       originally shipped by Seattle Computer Products as 86-DOS. After
  1561.       Microsoft purchased 86-DOS, the name remained for a while, but by the
  1562.       time the PC was ready for release, the new system was known as MS-DOS.
  1563.       Then, after the IBM PC reached the market, IBM began to refer to the
  1564.       operating system as the IBM Personal Computer DOS, which the trade
  1565.       press soon shortened to PC-DOS. IBM's version contained some
  1566.       utilities, such as DISKCOPY and DISKCOMP, that were not included in
  1567.       MS-DOS, the generic version available for license by other
  1568.       manufacturers. By calling attention to these differences, publications
  1569.       added to the confusion about the distinction between the Microsoft and
  1570.       IBM releases of MS-DOS.
  1571.  
  1572.       Further complications arose when Lifeboat Associates agreed to help
  1573.       promote MS-DOS but decided to call the operating system Software Bus
  1574.       86. MS-DOS thus became one of a line of trademarked Software Bus
  1575.       products, another of which was a product called SB-80, Lifeboat's
  1576.       version of CP/M-80.
  1577.  
  1578.       Finally, some of the first hardware companies to license MS-DOS also
  1579.       wanted to use their own names for the operating system. Out of this
  1580.       situation came such additional names as COMPAQ-DOS and Zenith's Z-DOS.
  1581.  
  1582.       Given this confusing host of names for a product it believed could
  1583.       become the industry standard, Microsoft finally took the lead and, as
  1584.       developer, insisted that the operating system was to be called MS-DOS.
  1585.       Eventually, everyone but IBM complied.
  1586.  
  1587.  Developers and MS-DOS
  1588.  
  1589.       Early in its career, MS-DOS represented just a small fraction of
  1590.       Microsoft's business--much larger revenues were generated by BASIC and
  1591.       other languages. In addition, in the first two years after the
  1592.       introduction of the IBM PC, the growth of CP/M-86 and other
  1593.       environments nearly paralleled that of MS-DOS. So Microsoft found
  1594.       itself in the unenviable position of giving its support to MS-DOS
  1595.       while also selling languages to run on CP/M-86, thereby contributing
  1596.       to the growth of software for MS-DOS's biggest competitor.
  1597.  
  1598.       Given the uncertain outcome of this two-horse race, some other
  1599.       software developers chose to wait and see which way the hardware
  1600.       manufacturers would jump. For their part, the hardware manufacturers
  1601.       were confronting the issue of compatibility between operating systems.
  1602.       Specifically, they needed to be convinced that MS-DOS was not a
  1603.       maverick--that it could perform as well as CP/M-86 as a base for
  1604.       applications that had been ported from the CP/M-80 environment for use
  1605.       on 16-bit computers.
  1606.  
  1607.       Microsoft approached the problem by emphasizing four related points in
  1608.       its discussions with hardware manufacturers:
  1609.  
  1610.       ■  First, one of Microsoft's goals in developing the first version of
  1611.          MS-DOS had always been translation compatibility from CP/M-80 to
  1612.          MS-DOS software.
  1613.  
  1614.       ■  Second, translation was possible only for software written in 8080
  1615.          or Z80 assembly language; thus, neither MS-DOS nor CP/M-86 could
  1616.          run programs written for other 8-bit processors, such as the 6800
  1617.          or the 6502.
  1618.  
  1619.       ■  Third, many applications were written in a high-level language,
  1620.          rather than in assembly language.
  1621.  
  1622.       ■  Fourth, most of those high-level languages were Microsoft products
  1623.          and ran on MS-DOS.
  1624.  
  1625.       Thus, even though some people had originally believed that only CP/M-
  1626.       86 would automatically make the installed base of CP/M-80 software
  1627.       available to the IBM PC and other 16-bit computers, Microsoft
  1628.       convinced the hardware manufacturers that MS-DOS was, in actuality, as
  1629.       flexible as CP/M-86 in its compatibility with existing--and
  1630.       appropriate--CP/M-80 software.
  1631.  
  1632.       MS-DOS was put at a disadvantage in one area, however, when Digital
  1633.       Research convinced several manufacturers to include both 8080 and 8086
  1634.       chips in their machines. With 8-bit and 16-bit software used on the
  1635.       same machine, the user could rely on the same disk format for both
  1636.       types of software. Because MS-DOS used a different disk format, CP/M
  1637.       had the edge in these dual-processor machines--although, in fact, it
  1638.       did not seem to have much effect on the survival of CP/M-86 after the
  1639.       first year or so.
  1640.  
  1641.       Although making MS-DOS the operating system of obvious preference was
  1642.       not as easy as simply convincing hardware manufacturers to offer it,
  1643.       Microsoft's list of MS-DOS customers grew steadily from the time the
  1644.       operating system was introduced. Many manufacturers continued to offer
  1645.       CP/M-86 along with MS-DOS, but by the end of 1983 the technical
  1646.       superiority of MS-DOS (bolstered by the introduction of such products
  1647.       as Lotus 1-2-3) carried the market. For example, when DEC, a longtime
  1648.       holdout, decided to make MS-DOS the primary operating system for its
  1649.       Rainbow computer, the company mentioned the richer set of commands and
  1650.       "dramatically" better disk performance of MS-DOS as reasons for its
  1651.       choice over CP/M-86.
  1652.  
  1653.  
  1654.  
  1655.  Version 2
  1656.  
  1657.  
  1658.       After the release of PC-specific version 1.0 of MS-DOS, Microsoft
  1659.       worked on an update that contained some bug fixes. Version 1.1 was
  1660.       provided to IBM to run on the upgraded PC released in 1982 and enabled
  1661.       MS-DOS to work with double-sided, 320 KB floppy disks. This version,
  1662.       referred to as 1.25 by all but IBM, was the first version of MS-DOS
  1663.       shipped by other OEMs, including COMPAQ and Zenith.
  1664.  
  1665.       Even before these intermediate releases were available, however,
  1666.       Microsoft began planning for future versions of MS-DOS. In developing
  1667.       the first version, the programmers had had two primary goals: running
  1668.       translated CP/M-80 software and keeping MS-DOS small. They had neither
  1669.       the time nor the room to include more sophisticated features, such as
  1670.       those typical of Microsoft's UNIX-based multiuser, multitasking
  1671.       operating system, XENIX. But when IBM informed Microsoft that the next
  1672.       major edition of the PC would be the Personal Computer XT with a 10-
  1673.       megabyte fixed disk, a larger, more powerful version of MS-DOS--one
  1674.       closer to the operating system Microsoft had envisioned from the
  1675.       start--became feasible.
  1676.  
  1677.       There were three particular areas that interested Microsoft: a new,
  1678.       hierarchical file system, installable device drivers, and some type of
  1679.       multitasking. Each of these features contributed to version 2.0, and
  1680.       together they represented a major change in MS-DOS while still
  1681.       maintaining compatibility with version 1.0.
  1682.  
  1683.  
  1684.  The File System
  1685.  
  1686.       Primary responsibility for version 2.0 fell to Paul Allen, Mark
  1687.       Zbikowski, and Aaron Reynolds, who wrote (and rewrote) most of the
  1688.       version 2.0 code. The major design issue confronting the developers,
  1689.       as well as the most visible example of its difference from versions
  1690.       1.0, 1.1, and 1.25, was the introduction of a hierarchical file system
  1691.       to handle the file-management needs of the XT's fixed disk.
  1692.  
  1693.       Version 1.0 had a single directory for all the files on a floppy disk.
  1694.       That system worked well enough on a disk of limited capacity, but on a
  1695.       10-megabyte fixed disk a single directory could easily become
  1696.       unmanageably large and cumbersome.
  1697.  
  1698.       CP/M had approached the problem of high-capacity storage media by
  1699.       using a partitioning scheme that divided the fixed disk into 10 user
  1700.       areas equivalent to 10 separate floppy-disk drives. On the other hand,
  1701.       UNIX, which had traditionally dealt with larger systems, used a
  1702.       branching, hierarchical file structure in which the user could create
  1703.       directories and subdirectories to organize files and make them readily
  1704.       accessible. This was the file-management system implemented in XENIX,
  1705.       and it was the MS-DOS team's choice for handling files on the XT's
  1706.       fixed disk.
  1707.  
  1708.       Partitioning, IBM's initial choice, had the advantages of familiarity,
  1709.       size, and ease of implementation. Many small-system users--
  1710.       particularly software developers--were already familiar with
  1711.       partitioning, if not overly fond of it, from their experience with
  1712.       CP/M. Development time was also a major concern, and the code needed
  1713.       to develop a partitioning scheme would be minimal compared with the
  1714.       code required to manage a hierarchical file system. Such a scheme
  1715.       would also take less time to implement.
  1716.  
  1717.       However, partitioning had two inherent disadvantages. First, its
  1718.       functionality would decrease as storage capacity increased, and even
  1719.       in 1982, Microsoft was anticipating substantial growth in the storage
  1720.       capacity of disk-based media. Second, partitioning depended on the
  1721.       physical device. If the size of the disk changed, either the number or
  1722.       the size of the partitions must also be changed in the code for both
  1723.       the operating system and the application programs. For Microsoft, with
  1724.       its commitment to hardware independence, partitioning would have
  1725.       represented a step in the wrong direction.
  1726.  
  1727.       A hierarchical file structure, on the other hand, could be independent
  1728.       of the physical device. A disk could be partitioned logically, rather
  1729.       than physically. And because these partitions (directories) were
  1730.       controlled by the user, they were open-ended and enabled the
  1731.       individual to determine the best way of organizing a disk.
  1732.  
  1733.       Ultimately, it was a hierarchical file system that found its way into
  1734.       MS-DOS 2.0 and eventually convinced everyone that it was, indeed, the
  1735.       better and more flexible solution to the problem of supporting a fixed
  1736.       disk. The file system was logically consistent with the XENIX file
  1737.       structure, yet physically consistent with the file access incorporated
  1738.       in versions 1.x, and was based on a root, or main, directory under
  1739.       which the user could create a system of subdirectories and sub-
  1740.       subdirectories to hold files. Each file in the system was identified
  1741.       by the directory path leading to it, and the number of subdirectories
  1742.       was limited only by the length of the pathname, which could not exceed
  1743.       64 characters.
  1744.  
  1745.       In this file structure, all the subdirectories and the filename in a
  1746.       path were separated from one another by backslash characters, which
  1747.       represented the only anomaly in the XENIX/MS-DOS system of
  1748.       hierarchical files. XENIX used a forward slash as a separator, but
  1749.       versions 1.x of MS-DOS, borrowing from the tradition of DEC operating
  1750.       systems, already used the forward slash for switches in the command
  1751.       line, so Microsoft, at IBM's request, decided to use the backslash as
  1752.       the separator instead. Although the backslash character created no
  1753.       practical problems, except on keyboards that lacked a backslash, this
  1754.       decision did introduce inconsistency between MS-DOS and existing UNIX-
  1755.       like operating systems. And although Microsoft solved the keyboard
  1756.       problem by enabling the user to change the switch character from a
  1757.       slash to a hyphen, the solution itself created compatibility problems
  1758.       for people who wished to exchange batch files.
  1759.  
  1760.       Another major change in the file-management system was related to the
  1761.       new directory structure: In order to fully exploit a hierarchical file
  1762.       system, Microsoft had to add a new way of calling file services.
  1763.  
  1764.       Versions 1.x of MS-DOS used CP/M-like structures called file control
  1765.       blocks, or FCBs, to maintain compatibility with older CP/M-80
  1766.       programs. The FCBs contained all pertinent information about the size
  1767.       and location of a file but did not allow the user to specify a file in
  1768.       a different directory. Therefore, version 2.0 of MS-DOS needed the
  1769.       added ability to access files by means of handles, or descriptors,
  1770.       that could operate across directory lines.
  1771.  
  1772.       In this added step toward logical device independence, MS-DOS returned
  1773.       a handle whenever an MS-DOS program opened a file. All further
  1774.       interaction with the file involved only this handle. MS-DOS made all
  1775.       necessary adjustments to an internal structure--different from an FCB-
  1776.       -so that the program never had to deal directly with information about
  1777.       the file's location in memory. Furthermore, even if future versions of
  1778.       MS-DOS were to change the structure of the internal control units,
  1779.       program code would not need to be rewritten--the file handle would be
  1780.       the only referent needed, and this would not change.
  1781.  
  1782.       Putting the internal control units under the supervision of MS-DOS and
  1783.       substituting handles for FCBs also made it possible for MS-DOS to
  1784.       redirect a program's input and output. A system function was provided
  1785.       that enabled MS-DOS to divert the reads or writes directed to one
  1786.       handle to the file or device assigned to another handle. This
  1787.       capability was used by COMMAND.COM to allow output from a file to be
  1788.       redirected to a device, such as a printer, or to be piped to another
  1789.       program. It also allowed system cleanup on program terminations.
  1790.  
  1791.  
  1792.  Installable Device Drivers
  1793.  
  1794.       At the time Microsoft began developing version 2.0 of MS-DOS, the
  1795.       company also realized that many third-party peripheral devices were
  1796.       not working well with one another. Each manufacturer had its own way
  1797.       of hooking its hardware into MS-DOS and if two third-party devices
  1798.       were plugged into a computer at the same time, they would often
  1799.       conflict or fail.
  1800.  
  1801.       One of the hallmarks of IBM's approach to the PC was open
  1802.       architecture, meaning that users could simply slide new cards into the
  1803.       computer whenever new input/output devices, such as fixed disks or
  1804.       printers, were added to the system. Unfortunately, version 1.0 of MS-
  1805.       DOS did not have a corresponding open architecture built into it--the
  1806.       BIOS contained all the code that permitted the operating system to run
  1807.       the hardware. If independent hardware manufacturers wanted to develop
  1808.       equipment for use with a computer manufacturer's operating system,
  1809.       they would have to either completely rewrite the device drivers or
  1810.       write a complicated utility to read the existing drivers, alter them,
  1811.       add the code to support the new device, and produce a working set of
  1812.       drivers. If the user installed more than one device, these patches
  1813.       would often conflict with one another. Furthermore, they would have to
  1814.       be revised each time the computer manufacturer updated its version of
  1815.       MS-DOS.
  1816.  
  1817.       By the time work began on version 2.0, the MS-DOS team knew that the
  1818.       ability to install any device driver at run time was vital. They
  1819.       implemented installable device drivers by making the drivers more
  1820.       modular. Like the FAT, IO.SYS (IBMBIO.COM in PC-DOS) became, in
  1821.       effect, a linked list--this time, of device drivers--that could be
  1822.       expanded through commands in the CONFIG.SYS file on the system boot
  1823.       disk. Manufacturers could now write a device driver that the user
  1824.       could install at run time by including it in the CONFIG.SYS file. MS-
  1825.       DOS could then add the device driver to the linked list.
  1826.  
  1827.       By extension, this ability to install device drivers also added the
  1828.       ability to supersede a previously installed driver--for example, the
  1829.       ANSI.SYS console driver that supports the ANSI standard escape codes
  1830.       for cursor positioning and screen control.
  1831.  
  1832.  
  1833.  Print Spooling
  1834.  
  1835.       At IBM's request, version 2.0 of MS-DOS also possessed the
  1836.       undocumented ability to perform rudimentary background processing--an
  1837.       interim solution to a growing awareness of the potentials of
  1838.       multitasking.
  1839.  
  1840.       Background print spooling was sufficient to meet the needs of most
  1841.       people in most situations, so the print spooler, PRINT.COM, was
  1842.       designed to run whenever MS-DOS had nothing else to do. When the
  1843.       parent application became active, PRINT.COM would be interrupted until
  1844.       the next lull. This type of background processing, though both limited
  1845.       and extremely complex, was exploited by a number of applications, such
  1846.       as SideKick.
  1847.  
  1848.  
  1849.  Loose Ends and a New MS-DOS
  1850.  
  1851.       Hierarchical files, installable device drivers, and print spooling
  1852.       were the major design decisions in version 2.0. But there were dozens
  1853.       of smaller changes, too.
  1854.  
  1855.       For example, with the fixed disk it was necessary to modify the code
  1856.       for automatic logging of disks. This modification meant that MS-DOS
  1857.       had to access the disk more often, and file access became much slower
  1858.       as a result. In trying to find a solution to this problem, Chris
  1859.       Peters reasoned that, if MS-DOS had just checked the disk, there was
  1860.       some minimum time a user would need to physically change disks. If
  1861.       that minimum time had not elapsed, the current disk information in
  1862.       RAM--whether for a fixed disk or a floppy--was probably still good.
  1863.  
  1864.       Peters found that the fastest anyone could physically change disks,
  1865.       even if the disks were damaged in the process, was about two seconds.
  1866.       Reasoning from this observation, he had MS-DOS check to see how much
  1867.       time had gone by since the last disk access. If less than two seconds
  1868.       had elapsed, he had MS-DOS assume that a new disk had not been
  1869.       inserted and that the disk information in RAM was still valid. With
  1870.       this little trick, the speed of file handling in MS-DOS version 2.0
  1871.       increased considerably.
  1872.  
  1873.       Version 2.0 was released in March 1983, the product of a surprisingly
  1874.       small team of six developers, including Peters, Mani Ulloa, and Nancy
  1875.       Panners in addition to Allen, Zbikowski, and Reynolds. Despite its
  1876.       complex new features, version 2.0 was only 24 KB of code. Though it
  1877.       maintained its compatibility with versions 1.x, it was in reality a
  1878.       vastly different operating system. Within six months of its release,
  1879.       version 2.0 gained widespread public acceptance. In addition, popular
  1880.       application programs such as Lotus 1-2-3 took advantage of the
  1881.       features of this new version of MS-DOS and thus helped secure its
  1882.       future as the industry standard for 8086 processors.
  1883.  
  1884.  Versions 2.1 and 2.25
  1885.  
  1886.       The world into which version 2.0 of MS-DOS emerged was considerably
  1887.       different from the one in which version 1.0 made its debut. When IBM
  1888.       released its original PC, the business market for microcomputers was
  1889.       as yet undefined--if not in scope, at least in terms of who and what
  1890.       would dominate the field. A year and a half later, when the PC/XT came
  1891.       on the scene, the market was much better known. It had, in fact, been
  1892.       heavily influenced by IBM itself. There were still many MS-DOS
  1893.       machines, such as the Tandy 2000 and the Hewlett Packard HP150, that
  1894.       were hardware incompatible with the IBM, but manufacturers of new
  1895.       computers knew that IBM was a force to consider and many chose to
  1896.       compete with the IBM PC by emulating it. Software developers, too, had
  1897.       gained an understanding of business computing and were confident they
  1898.       could position their software accurately in the enormous MS-DOS
  1899.       market.
  1900.  
  1901.       In such an environment, concerns about the existing base of CP/M
  1902.       software faded as developers focused their attention on the fast-
  1903.       growing business market and MS-DOS quickly secured its position as an
  1904.       industry standard. Now, with the obstacles to MS-DOS diminished,
  1905.       Microsoft found itself with a new concern: maintaining the standard it
  1906.       had created. Henceforth, MS-DOS had to be many things to many people.
  1907.       IBM had requirements; other OEMs had requirements. And sometimes these
  1908.       requirements conflicted.
  1909.  
  1910.  
  1911.  Hardware Developers
  1912.  
  1913.       When version 2.0 was released, IBM was already planning to introduce
  1914.       its PCjr. The PCjr would have the ability to run programs from ROM
  1915.       cartridges and, in addition to using half-height 5-1/4-inch drives,
  1916.       would employ a slightly different disk-controller architecture.
  1917.       Because of these differences from the standard PC line, IBM's
  1918.       immediate concern was for a version 2.1 of MS-DOS modified for the new
  1919.       machine.
  1920.  
  1921.       For the longer term, IBM was also planning a faster, more powerful PC
  1922.       with a 20-megabyte fixed disk. This prospect meant Microsoft needed to
  1923.       look again at its file-management system, because the larger storage
  1924.       capacity of the 20-megabyte disk stretched the size limitations for
  1925.       the file allocation table as it worked in version 2.0.
  1926.  
  1927.       However, IBM's primary interest for the next major release of MS-DOS
  1928.       was networking. Microsoft would have preferred to pursue multitasking
  1929.       as the next stage in the development of MS-DOS, but IBM was already
  1930.       developing its IBM PC Network Adapter, a plug-in card with an 80188
  1931.       chip to handle communications. So as soon as version 2.0 was released,
  1932.       the MS-DOS team, again headed by Zbikowski and Reynolds, began work on
  1933.       a networking version (3.0) of the operating system.
  1934.  
  1935.  
  1936.  Meanwhile...
  1937.  
  1938.       The international market for MS-DOS was not significant in the first
  1939.       few years after the release of the IBM PC and version 1.0 of MS-DOS.
  1940.       IBM did not, at first, ship its Personal Computer to Europe, so
  1941.       Microsoft was on its own there in promoting MS-DOS. In 1982, the
  1942.       company gained a significant advantage over CP/M-86 in Europe by
  1943.       concluding an agreement with Victor, a software company that was very
  1944.       successful in Europe and had already licensed CP/M-86. Working closely
  1945.       with Victor, Microsoft provided special development support for its
  1946.       graphics adaptors and eventually convinced the company to offer its
  1947.       products only on MS-DOS. In Japan, the most popular computers were Z80
  1948.       machines, and given the country's huge installed base of 8-bit
  1949.       machines, 16-bit computers were not taking hold. Mitsubishi, however,
  1950.       offered a 16-bit computer. Although CP/M-86 was Mitsubishi's original
  1951.       choice for an operating system, Microsoft helped get Multiplan and
  1952.       FORTRAN running on the CP/M-86 system, and eventually won the
  1953.       manufacturer's support for MS-DOS.
  1954.  
  1955.       In the software arena, by the time development was underway on the 2.x
  1956.       releases of MS-DOS, Microsoft's other customers were becoming more
  1957.       vocal about their own needs. Several wanted a networking capability,
  1958.       adding weight to IBM's request, but a more urgent need for many--a
  1959.       need not  shared by IBM at the time--was support for international
  1960.       products. Specifically, these manufacturers needed a version of MS-DOS
  1961.       that could be sold in other countries--a version of MS-DOS that could
  1962.       display messages in other languages and adapt to country-specific
  1963.       conventions, such as date and time formats.
  1964.  
  1965.       Microsoft, too, wanted to internationalize MS-DOS, so the MS-DOS team,
  1966.       while modifying the operating system to support the PCjr, also added
  1967.       functions and a COUNTRY command that allowed users to set the date and
  1968.       time formats and other country-dependent variables in the CONFIG.SYS
  1969.       file.
  1970.  
  1971.       At about the same time, another international requirement appeared.
  1972.       The Japanese market for MS-DOS was growing, and the question of
  1973.       supporting 7000 Kanji characters (ideograms) arose. The difficulty
  1974.       with Kanji is that it requires dual-byte characters. For English and
  1975.       most European character sets, one byte corresponds to one character.
  1976.       Japanese characters, however, sometimes use one byte, sometimes two.
  1977.       This variability creates problems in parsing, and as a result MS-DOS
  1978.       had to be modified to parse a string from the beginning, rather than
  1979.       back up one character at a time.
  1980.  
  1981.       This support for individual country formats and Kanji appeared in
  1982.       version 2.01 of MS-DOS. IBM did not want this version, so support for
  1983.       the PCjr, developed by Zbikowski, Reynolds, Ulloa, and Eric Evans,
  1984.       appeared separately in version 2.1, which went only to IBM and did not
  1985.       include the modifications for international MS-DOS.
  1986.  
  1987.  Different customers, different versions
  1988.  
  1989.       As early as version 1.25, Microsoft faced the problem of trying to
  1990.       satisfy those OEM customers that wanted to have the same version of
  1991.       MS-DOS as IBM. Some, such as COMPAQ, were in the business of selling
  1992.       100-percent compatibility with IBM. For them, any difference between
  1993.       their version of the operating system and IBM's introduced the
  1994.       possibility of incompatibility. Satisfying these requests was
  1995.       difficult, however, and it was not until version 3.1 that Microsoft
  1996.       was able to supply a system that other OEMs agreed was identical with
  1997.       IBM's.
  1998.  
  1999.       Before then, to satisfy the OEM customers, Microsoft combined versions
  2000.       2.1 and 2.01 to create version 2.11. Although IBM did not accept this
  2001.       because of the internationalization code, version 2.11 became the
  2002.       standard version for all non-IBM customers running any form of MS-DOS
  2003.       in the 2.x series. Version 2.11 was sold worldwide and translated into
  2004.       about 10 different languages. Two other intermediate versions provided
  2005.       support for Hangeul (the Korean character set) and Chinese Kanji.
  2006.  
  2007.  
  2008.  Software Concerns
  2009.  
  2010.       After the release of version 2.0, Microsoft also gained an
  2011.       appreciation of the importance--and difficulty--of supporting the
  2012.       people who were developing software for MS-DOS.
  2013.  
  2014.       Software developers worried about downward compatibility. They also
  2015.       worried about upward compatibility. But despite these concerns, they
  2016.       sometimes used programming practices that could guarantee neither.
  2017.       When this happened and the resulting programs were successful, it was
  2018.       up to Microsoft to ensure compatibility.
  2019.  
  2020.       For example, because the information about the internals of the BIOS
  2021.       and the ROM interface had been published, software developers could,
  2022.       and often did, work directly with the hardware in order to get more
  2023.       speed. This meant sidestepping the operating system for some
  2024.       operations. However, by choosing to work at the lower levels, these
  2025.       developers lost the protection provided by the operating system
  2026.       against hardware changes. Thus, when low-level changes were made in
  2027.       the hardware, their programs either did not work or did not run
  2028.       cooperatively with other applications.
  2029.  
  2030.       Another software problem was the continuing need for compatibility
  2031.       with CP/M. For example, in CP/M, programmers would call a fixed
  2032.       address in low memory in order to request a function; in MS-DOS, they
  2033.       would request operating-system services by executing a software
  2034.       interrupt. To support older software, the first version of MS-DOS
  2035.       allowed a program to request functions by either method. One of the
  2036.       CP/M-based programs supported in this fashion was the very popular
  2037.       WordStar. Since Microsoft could not make changes in MS-DOS that would
  2038.       make it impossible to run such a widely used program, each new version
  2039.       of MS-DOS had to continue supporting CP/M-style calls.
  2040.  
  2041.       A more pervasive CP/M-related issue was the use of FCB-style calls for
  2042.       file and record management. The version 1.x releases of MS-DOS had
  2043.       used FCB-style calls exclusively, as had CP/M. Version 2.0 introduced
  2044.       the more efficient and flexible handle calls, but Microsoft could not
  2045.       simply abolish the old FCB-style calls, because so many popular
  2046.       programs used them. In fact, some of Microsoft's own languages used
  2047.       them. So, MS-DOS had to support both types of calls in the version 2.x
  2048.       series. To encourage the use of the new handle calls, however,
  2049.       Microsoft made it easy for MS-DOS users to upgrade to version 2.0. In
  2050.       addition, the company convinced IBM to require version 2.0 for the
  2051.       PC/XT and also encouraged software developers to require 2.0 for their
  2052.       applications.
  2053.  
  2054.       At first, both software developers and OEM customers were reluctant to
  2055.       require 2.0 because they were concerned about problems with the
  2056.       installed user base of 1.0 systems--requiring version 2.0 meant
  2057.       supporting both sets of calls. Applications also needed to be able to
  2058.       detect which version of the operating system the user was running. For
  2059.       versions 1.x, the programs would have to use FCB calls; for versions
  2060.       2.x, they would use the file handles to exploit the flexibility of MS-
  2061.       DOS more fully.
  2062.  
  2063.       All told, it was an awkward period of transition, but by the time
  2064.       Microsoft began work on version 3.0 and the support for IBM's upcoming
  2065.       20-megabyte fixed disk, it had become apparent that the change had
  2066.       been in everyone's best interest.
  2067.  
  2068.  
  2069.  
  2070.  Version 3
  2071.  
  2072.  
  2073.       The types of issues that began to emerge as Microsoft worked toward
  2074.       version 3.0, MS-DOS for networks, exaggerated the problems of
  2075.       compatibility that had been encountered before.
  2076.  
  2077.       First, networking, with or without a multitasking capability, requires
  2078.       a level of cooperation and compatibility among programs that had never
  2079.       been an issue in earlier versions of MS-DOS. As described by Mark
  2080.       Zbikowski, one of the principals involved in the project, "there was a
  2081.       very long period of time between 2.1 and 3.0--almost a year and a
  2082.       half. During that time, we believed we understood all the problems
  2083.       involved in making DOS a networking product. [But] as time progressed,
  2084.       we realized that we didn't fully understand it, either from a
  2085.       compatibility standpoint or from an operating-system standpoint. We
  2086.       knew very well how it [DOS] ran in a single-tasking environment, but
  2087.       we started going to this new environment and found places where it
  2088.       came up short."
  2089.  
  2090.       In fact, the great variability in programs and programming approaches
  2091.       that MS-DOS supported eventually proved to be one of the biggest
  2092.       obstacles to the development of a sophisticated networking system and,
  2093.       in the longer term, to the addition of true multitasking.
  2094.  
  2095.       Further, by the time Microsoft began work on version 3.0, the
  2096.       programming style of the MS-DOS team had changed considerably. The
  2097.       team was still small, with a core group of just five people:
  2098.       Zbikowski, Reynolds, Peters, Evans, and Mark Bebic. But the concerns
  2099.       for maintainability that had dominated programming in larger systems
  2100.       had percolated down to the MS-DOS environment. Now, the desire to use
  2101.       tricks to optimize for speed had to be tempered by the need for
  2102.       clarity and maintainability, and the small package of tightly written
  2103.       code that was the early MS-DOS had to be sacrificed for the same
  2104.       reasons.
  2105.  
  2106.  
  2107.  Version 3.0
  2108.  
  2109.       All told, the work on version 3.0 of MS-DOS proved to be long and
  2110.       difficult. For a year and a half, Microsoft grappled with problems of
  2111.       software incompatibility, remote file management, and logical device
  2112.       independence at the network level. Even so, when IBM was ready to
  2113.       announce its new Personal Computer AT, the network software for MS-DOS
  2114.       was not quite ready, so in August 1984, Microsoft released version 3.0
  2115.       to IBM without network software.
  2116.  
  2117.       Version 3.0 supported the AT's larger fixed disk, its new CMOS clock,
  2118.       and its high-capacity 1.2-megabyte floppy disks. It also provided the
  2119.       same international support included earlier in versions 2.01 and 2.11.
  2120.       These features were made available to Microsoft's other OEM customers
  2121.       as version 3.05.
  2122.  
  2123.       But version 3.0 was not a simple extension of version 2.0. In laying
  2124.       the foundation for networking, the MS-DOS team had completely
  2125.       redesigned and rewritten the DOS kernel.
  2126.  
  2127.       Different as it was from version 1.0, version 2.0 had been built on
  2128.       top of the same structure. For example, whereas file requests in MS-
  2129.       DOS 1.0 used FCBs, requests in version 2.0 used file handles. However,
  2130.       the version 2.0 handle calls would simply parse the pathname and then
  2131.       use the underlying FCB calls in the same way as version 1.0. The
  2132.       redirected input and output in version 2.0 further complicated the
  2133.       file-system requests. When a program used one of the CP/M-compatible
  2134.       calls for character input or output, MS-DOS 2.0 first opened a handle
  2135.       and then turned it back into an FCB call at a lower level. Version 3.0
  2136.       eliminated this redundancy by eliminating the old FCB input/output
  2137.       code of versions 1 and 2, replacing it with a standard set of I/O
  2138.       calls that could be called directly by both FCB calls and handle
  2139.       calls. The look-alike calls for CP/M-compatible character I/O were
  2140.       included as part of the set of handle calls. As a result of this
  2141.       restructuring, these calls were distinctly faster in version 3.0 than
  2142.       in version 2.0.
  2143.  
  2144.       More important than the elimination of inefficiencies, however, was
  2145.       the fact that this new structure made it easier to handle network
  2146.       requests under the ISO Open System Interconnect model Microsoft was
  2147.       using for networking. The ISO model describes a number of protocol
  2148.       layers, ranging from the application-to-application interface at the
  2149.       top level down to the physical link--plugging into the network--at the
  2150.       lowest level. In the middle is the transport layer, which manages the
  2151.       actual transfer of data. The layers above the transport layer belong
  2152.       to the realm of the operating system; the layers below the transport
  2153.       layer are traditionally the domain of the network software or
  2154.       hardware.
  2155.  
  2156.       On the IBM PC network, the transport layer and the server functions
  2157.       were handled by IBM's Network Adapter card and the task of MS-DOS was
  2158.       to support this hardware. For its other OEM customers, however,
  2159.       Microsoft needed to supply both the transport and the server functions
  2160.       as software. Although version 3.0 did not provide this general-purpose
  2161.       networking software, it did provide the basic support for IBM's
  2162.       networking hardware.
  2163.  
  2164.       The support for IBM consisted of redirector and sharer software. MS-
  2165.       DOS used an approach to networking in which remote requests were
  2166.       routed by a redirector that was able to interact with the transport
  2167.       layer of the network. The transport layer was composed of the device
  2168.       drivers that could reliably transfer data from one part of the network
  2169.       to another. Just before a call was sent to the newly designed low-
  2170.       level file I/O code, the operating system determined whether the call
  2171.       was local or remote. A local call would be allowed to fall through to
  2172.       the local file I/O code; a remote call would be passed to the
  2173.       redirector which, working with the operating system, would make the
  2174.       resources on a remote machine appear as if they were local.
  2175.  
  2176.  
  2177.  Version 3.1
  2178.  
  2179.       Both the redirector and the sharer interfaces for IBM's Network
  2180.       Adapter card were in place in version 3.0 when it was delivered to
  2181.       IBM, but the redirector itself wasn't ready. Version 3.1, completed by
  2182.       Zbikowski and Reynolds and released three months later, completed this
  2183.       network support and made it available in the form of Microsoft
  2184.       Networks for use on non-IBM network cards.
  2185.  
  2186.       Microsoft Networks was built on the concept of "services" and
  2187.       "consumers." Services were provided by a file server, which was part
  2188.       of the Networks application and ran on a computer dedicated to the
  2189.       task. Consumers were programs on various network machines. Requests
  2190.       for information were passed at a high level to the file server; it was
  2191.       then the responsibility of the file server to determine where to find
  2192.       the information on the disk. The requesting programs--the consumers--
  2193.       did not need any knowledge of the remote machine, not even what type
  2194.       of file system it had.
  2195.  
  2196.       This ability to pass a high-level request to a remote server without
  2197.       having to know the details of the server's file structure allowed
  2198.       another level of generalization of the system. In MS-DOS 3.1,
  2199.       different types of file systems could be accessed on the same network.
  2200.       It was possible, for example, to access a XENIX machine across the
  2201.       network from an MS-DOS machine and to read data from XENIX files.
  2202.  
  2203.       Microsoft Networks was designed to be hardware independent. Yet the
  2204.       variability of the classes of programs that would be using its
  2205.       structures was a major problem in developing a networking system that
  2206.       would be transparent to the user. In evaluating this variability,
  2207.       Microsoft identified three types of programs:
  2208.  
  2209.       ■  First were the MS-DOS-compatible programs. These used only the
  2210.          documented software-interrupt method of requesting services from
  2211.          the operating system and would run on any MS-DOS machine without
  2212.          problems.
  2213.  
  2214.       ■  Second were the MS-DOS-based programs. These would run on IBM-
  2215.          compatible computers but not necessarily on all MS-DOS machines.
  2216.  
  2217.       ■  Third were the programs that used undocumented features of MS-DOS
  2218.          or that addressed the hardware directly. These programs tended to
  2219.          have the best performance but were also the most difficult to
  2220.          support.
  2221.  
  2222.       Of these, Microsoft officially encouraged the writing of MS-DOS
  2223.       compatible programs for use on the network.
  2224.  
  2225.  Network concerns
  2226.  
  2227.       The file-access module was changed in version 3.0 to simplify file
  2228.       management on the network, but this did not solve all the problems.
  2229.       For instance, MS-DOS still needed to handle FCB requests from programs
  2230.       that used them, but many programs would open an FCB and never close
  2231.       it. One of the functions of the server was to keep track of all open
  2232.       files on the network, and it ran into difficulties when an FCB was
  2233.       opened 50 or 100 times and never closed. To solve this problem,
  2234.       Microsoft introduced an FCB cache in version 3.1 that allowed only
  2235.       four FCBs to be open at any one time. If a fifth FCB was opened, the
  2236.       least recently used one was closed automatically and released. In
  2237.       addition, an FCBS command was added in the CONFIG.SYS file to allow
  2238.       the user or network manager to change the maximum number of FCBs that
  2239.       could be open at any one time and to protect some of the FCBs from
  2240.       automatic closure.
  2241.  
  2242.       In general, the logical device independence that had been a goal of
  2243.       MS-DOS acquired new meaning--and generated new problems--with
  2244.       networking. One problem concerned printers on the network. Commonly,
  2245.       networks are used to allow several people to share a printer. The
  2246.       network could easily accommodate a program that would open the
  2247.       printer, write to it, and close it again. Some programs, however,
  2248.       would try to use the direct IBM BIOS interface to access the printer.
  2249.       To handle this situation, Microsoft's designers had to develop a way
  2250.       for MS-DOS to intercept these BIOS requests and filter out the ones
  2251.       the server could not handle. Once this was accomplished, version 3.1
  2252.       was able to handle most types of printer output on the network in a
  2253.       transparent manner.
  2254.  
  2255.  
  2256.  
  2257.  Version 3.2
  2258.  
  2259.       In January 1986, Microsoft released another revision of MS-DOS,
  2260.       version 3.2, which supported 3-1/2-inch floppy disks. Version 3.2 also
  2261.       moved the formatting function for a device out of the FORMAT utility
  2262.       routine and into the device driver, eliminating the need for a special
  2263.       hardware-dependent program in addition to the device driver. It
  2264.       included a sample installable-block-device driver and, finally,
  2265.       benefited the users and manufacturers of IBM-compatible computers by
  2266.       including major rewrites of the MS-DOS utilities to increase
  2267.       compatibility with those of IBM.
  2268.  
  2269.  
  2270.  
  2271.  The Future
  2272.  
  2273.  
  2274.       Since its appearance in 1981, MS-DOS has taken and held an enviable
  2275.       position in the microcomputer environment. Not only has it "taught"
  2276.       millions of personal computers "how to think," it has taught equal
  2277.       millions of people how to use computers. Many highly sophisticated
  2278.       computer users can trace their first encounter with these machines to
  2279.       the original IBM PC and version 1.0 of MS-DOS. The MS-DOS command
  2280.       interface is the one with which they are comfortable and it is the MS-
  2281.       DOS file structure that, in one way or another, they wander through
  2282.       with familiarity.
  2283.  
  2284.       Microsoft has stated its commitment to ensuring that, for the
  2285.       foreseeable future, MS-DOS will continue to evolve and grow, changing
  2286.       as it has done in the past to satisfy the needs of its millions of
  2287.       users. In the long term, MS-DOS, the product of a surprisingly small
  2288.       group of gifted people, will undoubtedly remain the industry standard
  2289.       for as long as 8086-based (and to some extent, 80286-based)
  2290.       microcomputers exist in the business world. The story of MS-DOS will,
  2291.       of course, remain even longer. For this operating system has earned
  2292.       its place in microcomputing history.
  2293.  
  2294.                                                   JoAnne Woodcock
  2295.  
  2296.  
  2297.  
  2298.  ──────────────────────────────────────────────────────────────────────────
  2299.  
  2300.  Section II:  Programming in the MS-DOS Environment
  2301.  
  2302.  
  2303.  
  2304.  ──────────────────────────────────────────────────────────────────────────
  2305.  
  2306.  Part A  Structure of MS-DOS
  2307.  
  2308.  
  2309.  
  2310.  Article 1:  An Introduction to MS-DOS
  2311.  
  2312.  
  2313.       An operating system is a set of interrelated supervisory programs that
  2314.       manage and control computer processing. In general, an operating
  2315.       system provides
  2316.  
  2317.       ■  Storage management
  2318.       ■  Processing management
  2319.       ■  Security
  2320.       ■  Human interface
  2321.  
  2322.       Existing operating systems for microcomputers fall into three major
  2323.       categories: ROM monitors, traditional operating systems, and operating
  2324.       environments. The general characteristics of the three categories are
  2325.       listed in Table 1-1.
  2326.  
  2327.  
  2328.       Table 1-1. Characteristics of the Three Major Types of
  2329.                  Operating Systems.
  2330.  
  2331. ╓┌──────────────────────────┌─────────────┌─────────────┌────────────────────╖
  2332.                                           Traditional
  2333.                                           Traditional
  2334.                             ROM           Operating     Operating
  2335.                             Monitor       System        Environment
  2336.       ──────────────────────────────────────────────────────────────────
  2337.       Complexity            Low           Medium        High
  2338.       Built on              Hardware      BIOS          Operating system
  2339.       Delivered on          ROM           Disk          Disk
  2340.       Programs on           ROM           Disk          Disk
  2341.       Peripheral support    Physical      Logical       Logical
  2342.       Disk access           Sector        File system   File system
  2343.       Example               PC ROM BIOS   MS-DOS        Microsoft Windows
  2344.  
  2345.  
  2346.       A ROM monitor is the simplest type of operating system. It is designed
  2347.       for a particular hardware configuration and provides a program with
  2348.       basic--and often direct--access to peripherals attached to the
  2349.       computer. Programs coupled with a ROM monitor are often used for
  2350.       dedicated applications such as controlling a microwave oven or
  2351.       controlling the engine of a car.
  2352.  
  2353.       A traditional microcomputer operating system is built on top of a ROM
  2354.       monitor, or BIOS (basic input/output system), and provides additional
  2355.       features such as a file system and logical access to peripherals.
  2356.       (Logical access to peripherals allows applications to run in a
  2357.       hardware-independent manner.) A traditional operating system also
  2358.       stores programs in files on peripheral storage devices and, on
  2359.       request, loads them into memory for execution. MS-DOS is a traditional
  2360.       operating system.
  2361.  
  2362.       An operating environment is built on top of a traditional operating
  2363.       system. The operating environment provides additional services, such
  2364.       as common menu and forms support, that simplify program operation and
  2365.       make the user interface more consistent. Microsoft Windows is an
  2366.       operating environment.
  2367.  
  2368.  
  2369.  MS-DOS System Components
  2370.  
  2371.       The Microsoft Disk Operating System, MS-DOS, is a traditional
  2372.       microcomputer operating system that consists of five major components:
  2373.  
  2374.       ■  The operating-system loader
  2375.       ■  The MS-DOS BIOS
  2376.       ■  The MS-DOS kernel
  2377.       ■  The user interface (shell)
  2378.       ■  Support programs
  2379.  
  2380.       Each of these is introduced briefly in the following pages. See
  2381.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: The
  2382.       Components of MS-DOS.
  2383.  
  2384.  The operating-system loader
  2385.  
  2386.       The operating-system loader brings the operating system from the
  2387.       startup disk into RAM.
  2388.  
  2389.       The complete loading process, called bootstrapping, is often complex,
  2390.       and multiple loaders may be involved. (The term bootstrapping came
  2391.       about because each level pulls up the next part of the system, like
  2392.       pulling up on a pair of bootstraps.) For example, in most standard
  2393.       MS-DOS-based microcomputer implementations,  the ROM loader, which is
  2394.       the first program the microcomputer executes when it is turned on or
  2395.       restarted, reads the disk bootstrap loader from the first (boot)
  2396.       sector of the startup disk and executes it. The disk bootstrap loader,
  2397.       in turn, reads the main portions of MS-DOS--MSDOS.SYS and IO.SYS
  2398.       (IBMDOS.COM and IBMBIO.COM with PC-DOS)--from conventional disk files
  2399.       into memory. The special module SYSINIT within MSDOS.SYS then
  2400.       initializes MS-DOS's tables and buffers and discards itself. See
  2401.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: MS-DOS
  2402.       Storage Devices.
  2403.  
  2404.       (The term loader is also used to refer to the portion of the operating
  2405.       system that brings application programs into memory for execution.
  2406.       This loader is different from the ROM loader and the operating-system
  2407.       loader.)
  2408.  
  2409.  The MS-DOS BIOS
  2410.  
  2411.       The MS-DOS BIOS, loaded from the file IO.SYS during system
  2412.       initialization, is the layer of the operating system that sits between
  2413.       the operating-system kernel and the hardware. An application performs
  2414.       input and output by making requests to the operating-system kernel,
  2415.       which, in turn, calls the MS-DOS BIOS routines that access the
  2416.       hardware directly. See SYSTEM CALLS. This division of function allows
  2417.       application programs to be written in a hardware-independent manner.
  2418.  
  2419.       The MS-DOS BIOS consists of some initialization code and a collection
  2420.       of device drivers. (A device driver is a specialized program that
  2421.       provides support for a specific device such as a display or serial
  2422.       port.) The device drivers are responsible for hardware access and for
  2423.       the interrupt support that allows the associated devices to signal the
  2424.       microprocessor that they need service.
  2425.  
  2426.       The device drivers contained in the file IO.SYS, which are always
  2427.       loaded during system initialization, are sometimes referred to as the
  2428.       resident drivers. With MS-DOS versions 2.0 and later, additional
  2429.       device drivers, called installable drivers, can optionally be loaded
  2430.       during system initialization as a result of DEVICE directives in the
  2431.       system's configuration file. See PROGRAMMING IN THE MS-DOS
  2432.       ENVIRONMENT: CUSTOMIZING MS-DOS: Installable Device Drivers; USER
  2433.       COMMANDS: CONFIG.SYS:DEVICE.
  2434.  
  2435.  The MS-DOS kernel
  2436.  
  2437.       The services provided to application programs by the MS-DOS kernel
  2438.       include
  2439.  
  2440.       ■  Process control
  2441.       ■  Memory management
  2442.       ■  Peripheral support
  2443.       ■  A file system
  2444.  
  2445.       The MS-DOS kernel is loaded from the file MSDOS.SYS during system
  2446.       initialization.
  2447.  
  2448.  Process control
  2449.       Process, or task, control includes program loading, task execution,
  2450.       task termination, task scheduling, and intertask communication.
  2451.  
  2452.       Although MS-DOS is not a multitasking operating system, it can have
  2453.       multiple programs residing in memory at the same time. One program can
  2454.       invoke another, which then becomes the active (foreground) task. When
  2455.       the invoked task terminates, the invoking program again becomes the
  2456.       foreground task. Because these tasks never execute simultaneously,
  2457.       this stack-like operation is still considered to be a single-tasking
  2458.       operating system.
  2459.  
  2460.       MS-DOS does have a few "hooks" that allow certain programs to do some
  2461.       multitasking on their own. For example, terminate-and-stay-resident
  2462.       (TSR) programs such as PRINT use these hooks to perform limited
  2463.       concurrent processing by taking control of system resources while
  2464.       MS-DOS is "idle," and the Microsoft Windows operating environment adds
  2465.       support for nonpreemptive task switching.
  2466.  
  2467.       The traditional intertask communication methods include semaphores,
  2468.       queues, shared memory, and pipes. Of these, MS-DOS formally supports
  2469.       only pipes. (A pipe is a logical, unidirectional, sequential stream of
  2470.       data that is written by one program and read by another.) The data in
  2471.       a pipe resides in memory or in a disk file, depending on the
  2472.       implementation; MS-DOS uses disk files for intermediate storage of
  2473.       data in pipes because it is a single-tasking operating system.
  2474.  
  2475.  Memory management
  2476.       Because the amount of memory a program needs varies from program to
  2477.       program, the traditional operating system ordinarily provides memory-
  2478.       management functions. Memory requirements can also vary during program
  2479.       execution, and memory management is especially necessary when two or
  2480.       more programs are present in memory at the same time.
  2481.  
  2482.       MS-DOS memory management is based on a pool of variable-size memory
  2483.       blocks. The two basic memory-management actions are to allocate a
  2484.       block from the pool and to return an allocated block to the pool.
  2485.       MS-DOS allocates program space from the pool when the program is
  2486.       loaded; programs themselves can allocate additional memory from the
  2487.       pool. Many programs perform their own memory management by using a
  2488.       local memory pool, or heap--an additional memory block allocated from
  2489.       the operating system that the application program itself divides into
  2490.       blocks for use by its various routines. See PROGRAMMING IN
  2491.       THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: Memory Management.
  2492.  
  2493.  Peripheral support
  2494.       The operating system provides peripheral support to programs through a
  2495.       set of operating-system calls that are translated by the operating
  2496.       system into calls to the appropriate device driver.
  2497.  
  2498.       Peripheral support can be a direct logical-to-physical-device
  2499.       translation or the operating system can interject additional features
  2500.       or translations. Keyboards, displays, and printers usually require
  2501.       only logical-to-physical-device translations; that is, the data is
  2502.       transferred between the application program and the physical device
  2503.       with minimal alterations, if any, by the operating system. The data
  2504.       provided by clock devices, on the other hand, must be transformed to
  2505.       operating-system-dependent time and date formats. Disk devices--and
  2506.       block devices in general--have the greatest number of features added
  2507.       by the operating system. See The File System, below.
  2508.  
  2509.       As stated earlier, an application need not be concerned with the
  2510.       details of peripheral devices or with any special features the devices
  2511.       might have. Because the operating system takes care of all the
  2512.       logical-to-physical-device translations, the application program need
  2513.       only make requests of the operating system.
  2514.  
  2515.  The file system
  2516.       The file system is one of the largest portions of an operating system.
  2517.       A file system is built on the storage medium of a block device
  2518.       (usually a floppy disk or a fixed disk) by mapping a directory
  2519.       structure and files onto the physical unit of storage. A file system
  2520.       on a disk contains, at a minimum, allocation information, a directory,
  2521.       and space for files. See PROGRAMMING IN THE MS-DOS ENVIRONMENT:
  2522.       STRUCTURE OF MS-DOS: MS-DOS Storage Devices.
  2523.  
  2524.       The file allocation information can take various forms, depending on
  2525.       the operating system, but all forms basically track the space used by
  2526.       files and the space available for new data. The directory contains a
  2527.       list of the files stored on the device, their sizes, and information
  2528.       about where the data for each file is located.
  2529.  
  2530.       Several different approaches to file allocation and directory entries
  2531.       exist. MS-DOS uses a particular allocation method called a file
  2532.       allocation table (FAT) and a hierarchical directory structure. See
  2533.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: MS-DOS
  2534.       Storage Devices; PROGRAMMING FOR MS-DOS: Disk Directories and Volume
  2535.       Labels.
  2536.  
  2537.       The file granularity available through the operating system also
  2538.       varies depending on the implementation. Some systems, such as MS-DOS,
  2539.       have files that are accessible to the byte level; others are
  2540.       restricted to a fixed record size.
  2541.  
  2542.       File systems are sometimes extended to map character devices as if
  2543.       they were files. These device "files" can be opened, closed, read
  2544.       from, and written to like normal disk files, but all transactions
  2545.       occur directly with the specified character device. Device files
  2546.       provide a useful consistency to the environment for application
  2547.       programs; MS-DOS supports such files by assigning a reserved logical
  2548.       name (such as CON or PRN) to each character device.
  2549.  
  2550.  The user interface
  2551.  
  2552.       The user interface for an operating system, also called a shell or
  2553.       command processor, is generally a conventional program that allows the
  2554.       user to interact with the operating system itself. The default MS-DOS
  2555.       user interface is a replaceable shell program called COMMAND.COM.
  2556.  
  2557.       One of the fundamental tasks of a shell is to load a program into
  2558.       memory on request and pass control of the system to the program so
  2559.       that the program can execute. When the program terminates, control
  2560.       returns to the shell, which prompts the user for another command. In
  2561.       addition, the shell usually includes functions for file and directory
  2562.       maintenance and display. In theory, most of these functions could be
  2563.       provided as programs, but making them resident in the shell allows
  2564.       them to be accessed more quickly. The tradeoff is memory space versus
  2565.       speed and flexibility. Early microcomputer-based operating systems
  2566.       provided a minimal number of resident shell commands because of
  2567.       limited memory space; modern operating systems such as MS-DOS include
  2568.       a wide variety of these functions as internal commands.
  2569.  
  2570.  Support programs
  2571.  
  2572.       The MS-DOS software includes support programs that provide access to
  2573.       operating-system facilities not supplied as resident shell commands
  2574.       built into COMMAND.COM. Because these programs are stored as
  2575.       executable files on disk, they are essentially the same as application
  2576.       programs and MS-DOS loads and executes them as it would any other
  2577.       program.
  2578.  
  2579.       The support programs provided with MS-DOS, often referred to as
  2580.       external commands, include disk utilities such as FORMAT and CHKDSK
  2581.       and more general support programs such as EDLIN (a line-oriented text
  2582.       editor) and PRINT (a TSR utility that allows files to be printed while
  2583.       another program is running). See USER COMMANDS.
  2584.  
  2585.  MS-DOS releases
  2586.  
  2587.       MS-DOS and PC-DOS have been released in a number of forms, starting in
  2588.       1981. See THE DEVELOPMENT OF MS-DOS. The major MS-DOS and PC-DOS
  2589.       implementations are summarized in the following table.
  2590.  
  2591. ╓┌────────────────────────┌─────────┌────────────────────────────────────────╖
  2592.       Version             Date      Special Characteristics
  2593.       ──────────────────────────────────────────────────────────────────
  2594.       PC-DOS 1.0          1981      First operating system for the IBM
  2595.                                     PC Record-oriented files
  2596.  
  2597.       PC-DOS 1.1          1982      Double-sided-disk support
  2598.  
  2599.       MS-DOS 1.25         1982      First OEM release of MS-DOS
  2600.  
  2601.       MS-DOS/PC-DOS 2.0   1983      Operating system for the IBM
  2602.                                     PC/XT UNIX/XENIX-like file system
  2603.                                     Installable device drivers
  2604.                                     Byte-oriented files
  2605.                                     Support for fixed disks
  2606.       Version             Date      Special Characteristics
  2607.                                    Support for fixed disks
  2608.  
  2609.       PC-DOS 2.1                    Operating system for the IBM PCjr
  2610.  
  2611.       MS-DOS 2.11                   Internationalization support 2.0x bug
  2612.                                     fixes
  2613.  
  2614.       MS-DOS/PC-DOS 3.0   1984      Operating system for the IBM PC/AT
  2615.                                     Support for 1.2 MB floppy disks
  2616.                                     Support for large fixed disks
  2617.                                     Support for file and record locking
  2618.                                     Application control of print spooler
  2619.  
  2620.       MS-DOS/PC-DOS 3.1   1984      Support for MS Networks
  2621.  
  2622.       MS-DOS/PC-DOS 3.2   1986      3.5-inch floppy-disk support
  2623.                                     Disk track formatting support added
  2624.                                     to device drivers
  2625.  
  2626.       MS-DOS/PC-DOS 3.3   1987      Support for the IBM PS/2
  2627.       Version             Date      Special Characteristics
  2628.      MS-DOS/PC-DOS 3.3   1987      Support for the IBM PS/2
  2629.                                     Enhancedinternationalization support
  2630.                                     Improved file-system performance
  2631.                                     Partitioning support for disks with
  2632.                                     capacity above 32 MB
  2633.  
  2634.       PC-DOS version 1.0 was the first commercial version of MS-DOS. It was
  2635.       developed for the original IBM PC, which was typically shipped with 64
  2636.       KB of memory or less. MS-DOS and PC-DOS versions 1.x were similar in
  2637.       many ways to CP/M, the popular operating system for 8-bit
  2638.       microcomputers based on the Intel 8080 (the predecessor of the 8086).
  2639.       These versions of MS-DOS used a single-level file system with no
  2640.       subdirectory support and did not support installable device drivers or
  2641.       networks. Programs accessed files using file control blocks (FCBs)
  2642.       similar to those found in CP/M programs. File operations were record
  2643.       oriented, again like CP/M, although record sizes could be varied in
  2644.       MS-DOS.
  2645.  
  2646.       Although they retained compatibility with versions 1.x, MS-DOS and
  2647.       PC-DOS versions 2.x represented a major change. In addition to
  2648.       providing support for fixed disks, the new versions switched to a
  2649.       hierarchical file system like that found in UNIX/XENIX and to file-
  2650.       handle access instead of FCBs. (A file handle is a 16-bit number used
  2651.       to reference an internal table that MS-DOS uses to keep track of
  2652.       currently open files; an application program has no access to this
  2653.       internal table.) The UNIX/XENIX-style file functions allow files to be
  2654.       treated as a byte stream instead of as a collection of records.
  2655.       Applications can read or write 1 to 65535 bytes in a single operation,
  2656.       starting at any byte offset within the file. Filenames used for
  2657.       opening a files are passed as text strings instead of being parsed
  2658.       into an FCB. Installable device drivers were another major
  2659.       enhancement.
  2660.  
  2661.       MS-DOS and PC-DOS versions 3.x added a number of valuable features,
  2662.       including support for the added capabilities of the IBM PC/AT, for
  2663.       larger-capacity disks, and for file-locking and record-locking
  2664.       functions. Network support was added by providing hooks for a
  2665.       redirector (an additional operating-system module that has the ability
  2666.       to redirect local system service requests to a remote system by means
  2667.       of a local area network).
  2668.  
  2669.       With all these changes, MS-DOS remains a traditional single-tasking
  2670.       operating system. It provides a large number of system services in a
  2671.       transparent fashion so that, as long as they use only the MS-DOS-
  2672.       supplied services and refrain from using hardware-specific operations,
  2673.       applications developed for one MS-DOS machine can usually run on
  2674.       another.
  2675.  
  2676.  
  2677.  Basic MS-DOS Requirements
  2678.  
  2679.       Foremost among the requirements for MS-DOS is an Intel 8086-compatible
  2680.       microprocessor. See Specific Hardware Requirements below.
  2681.  
  2682.       The next requirement is the ROM bootstrap loader and enough RAM to
  2683.       contain the MS-DOS BIOS, kernel, and shell and an application program.
  2684.       The RAM must start at address 0000:0000H and, to be managed by MS-DOS,
  2685.       must be contiguous. The upper limit for RAM is the limit placed upon
  2686.       the system by the 8086 family--1 MB.
  2687.  
  2688.       The final requirement for MS-DOS is a set of devices supported by
  2689.       device drivers, including at least one block device, one character
  2690.       device, and a clock device. The block device is usually the boot disk
  2691.       device (the disk device from which MS-DOS is loaded); the character
  2692.       device is usually a keyboard/display combination for interaction with
  2693.       the user; the clock device, required for time-of-day and date support,
  2694.       is a hardware counter driven in a submultiple of one second.
  2695.  
  2696.  Specific hardware requirements
  2697.  
  2698.       MS-DOS uses several hardware components and has specific requirements
  2699.       for each. These components include
  2700.  
  2701.       ■  An 8086-family microprocessor
  2702.       ■  Memory
  2703.       ■  Peripheral devices
  2704.       ■  A ROM BIOS (PC-DOS only)
  2705.  
  2706.  The microprocessor
  2707.       MS-DOS runs on any machine that uses a microprocessor that executes
  2708.       the 8086/8088 instruction set, including the Intel 8086, 80C86, 8088,
  2709.       80186, 80188, 80286, and 80386 and the NEC V20, V30, and V40.
  2710.  
  2711.       The 80186 and 80188 are versions of the 8086 and 8088, integrated in a
  2712.       single chip with direct memory access, timer, and interrupt support
  2713.       functions. PC-DOS cannot usually run on the 80186 or 80188 because
  2714.       these chips have internal interrupt and interface register addresses
  2715.       that conflict with addresses used by the PC ROM BIOS. See PROGRAMMING
  2716.       IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Hardware Interrupt
  2717.       Handlers. MS-DOS, however, does not have address requirements that
  2718.       conflict with those interrupt and interface areas.
  2719.  
  2720.       The 80286 has an extended instruction set and two operating modes:
  2721.       real and protected. Real mode is compatible with the 8086/8088 and
  2722.       runs MS-DOS. Protected mode, used by operating systems like UNIX/XENIX
  2723.       and MS OS/2, is partially compatible with real mode in terms of
  2724.       instructions but provides access to 16 MB of memory versus only 1 MB
  2725.       in real mode (the limit of the 8086/8088).
  2726.  
  2727.       The 80386 adds further instructions and a third mode called virtual 86
  2728.       mode. The 80386 instructions operate in either a 16-bit or a 32-bit
  2729.       environment. MS-DOS can run on the 80386 in real or virtual 86 mode,
  2730.       although the latter requires additional support in the form of a
  2731.       virtual machine monitor such as Windows /386.
  2732.  
  2733.  Memory requirements
  2734.       At a minimum, MS-DOS versions 1.x require 64 KB of contiguous RAM from
  2735.       the base of memory to do useful work; versions 2.x and 3.x need at
  2736.       least 128 KB. The maximum is 1 MB, although most MS-DOS machines have
  2737.       a 640 KB limit for IBM PC compatibility. MS-DOS can use additional
  2738.       noncontiguous RAM for a RAMdisk if the proper device driver is
  2739.       included. (Other uses for noncontiguous RAM include buffers for video
  2740.       displays, fixed disks, and network adapters.)
  2741.  
  2742.       PC-DOS has the same minimum memory requirements but has an upper limit
  2743.       of 640 KB on the initial contiguous RAM, which is generally referred
  2744.       to as conventional memory. This limit was imposed by the architecture
  2745.       of the original IBM PC, with the remaining area above 640 KB reserved
  2746.       for video display buffers, fixed disk adapters, and the ROM BIOS. Some
  2747.       of the reserved areas include
  2748.  
  2749. ╓┌──────────────────────┌─────────────────────┌──────────────────────────────╖
  2750.       Base Address      Size (bytes)          Description
  2751.       ──────────────────────────────────────────────────────────────────
  2752.       A000:0000H        10000H (64 KB)        EGA video buffer
  2753.       Base Address      Size (bytes)          Description
  2754.      A000:0000H        10000H (64 KB)        EGA video buffer
  2755.       B000:0000H        1000H (4 KB)          Monochrome video buffer
  2756.       B800:0000H        4000H (16 KB)         Color/graphics video buffer
  2757.       C800:0000H        4000H (16 KB)         Fixed-disk ROM
  2758.       F000:0000H        10000H (64 KB)        PC ROM BIOS and ROM BASIC
  2759.  
  2760.       The bottom 1024 bytes of system RAM (locations 00000-003FFH) are used
  2761.       by the microprocessor for an interrupt vector table--that is, a list
  2762.       of addresses for interrupt handler routines. MS-DOS uses some of the
  2763.       entries in this table, such as the vectors for interrupts 20H through
  2764.       2FH, to store addresses of its own tables and routines and to provide
  2765.       linkage to its services for application programs. The IBM PC ROM BIOS
  2766.       and IBM PC BASIC use many additional vectors for the same purposes.
  2767.  
  2768.  Peripheral devices
  2769.       MS-DOS can support a wide variety of devices, including floppy disks,
  2770.       fixed disks, CD ROMs, RAMdisks, and digital tape drives. The required
  2771.       peripheral support for MS-DOS is provided by the MS-DOS BIOS or by
  2772.       installable device drivers.
  2773.  
  2774.       Five logical devices are provided in a basic MS-DOS system:
  2775.  
  2776. ╓┌────────────────────────────┌──────────────────────────────────────────────╖
  2777.       Device Name             Description
  2778.       ──────────────────────────────────────────────────────────────────
  2779.       CON                     Console input and output
  2780.  
  2781.       PRN                     Printer output
  2782.  
  2783.       AUX                     Auxiliary input and output
  2784.  
  2785.       CLOCK$                  Date and time support
  2786.  
  2787.       Varies (A-E)            One block device
  2788.  
  2789.       These five logical devices can be implemented with a BIOS supporting a
  2790.       minimum of three physical devices: a keyboard and display, a timer or
  2791.       clock/calendar chip that can provide a hardware interrupt at regular
  2792.       intervals, and a block storage device. In such a minimum case, the
  2793.       printer and auxiliary device are simply aliases for the console
  2794.       device. However, most MS-DOS systems support several additional
  2795.       logical and physical devices. See PROGRAMMING IN THE MS-DOS
  2796.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: Character Device Input and
  2797.       Output.
  2798.  
  2799.       The MS-DOS kernel provides one additional device: the NUL device. NUL
  2800.       is a "bit bucket"--that is, anything written to NUL is simply
  2801.       discarded. Reading from NUL always returns an end-of-file marker. One
  2802.       common use for the NUL device is as the redirected output device of a
  2803.       command or application that is being run in a batch file; this
  2804.       redirection prevents screen clutter and disruption of the batch file's
  2805.       menus and displays.
  2806.  
  2807.  The ROM BIOS
  2808.       MS-DOS requires no ROM support (except that most bootstrap loaders
  2809.       reside in ROM) and does not care whether device-driver support resides
  2810.       in ROM or is part of the MS-DOS IO.SYS file loaded at initialization.
  2811.       PC-DOS, on the other hand, uses a very specific ROM BIOS. The PC ROM
  2812.       BIOS does not provide device drivers; rather, it provides support
  2813.       routines used by the device drivers found in IBMBIO.COM (the PC-DOS
  2814.       version of IO.SYS). The support provided by a PC ROM BIOS includes
  2815.  
  2816.       ■  Power-on self test (POST)
  2817.       ■  Bootstrap loader
  2818.       ■  Keyboard
  2819.       ■  Displays (monochrome and color/graphics adapters)
  2820.       ■  Serial ports 1 and 2
  2821.       ■  Parallel printer ports 1, 2, and 3
  2822.       ■  Clock
  2823.       ■  Print screen
  2824.  
  2825.       The PC ROM BIOS loader routine searches the ROM space above the PC-DOS
  2826.       640 KB limit for additional ROMs. The IBM fixed-disk adapter and
  2827.       enhanced graphics adapter (EGA) contain such ROMs. (The fixed-disk ROM
  2828.       also includes an additional loader routine that allows the system to
  2829.       start from the fixed disk.)
  2830.  
  2831.  
  2832.  Summary
  2833.  
  2834.       MS-DOS is a widely accepted traditional operating system. Its
  2835.       consistent and well-defined interface makes it one of the easier
  2836.       operating systems to adapt and program.
  2837.  
  2838.       MS-DOS is also a growing operating system--each version has added more
  2839.       features yet made the system easier to use for both end-users and
  2840.       programmers. In addition, each version has included more support for
  2841.       different devices, from 5.25-inch floppy disks to high-density 3.5-
  2842.       inch floppy disks. As the hardware continues to evolve and user needs
  2843.       become more sophisticated, MS-DOS too will continue to evolve.
  2844.  
  2845.                                                    William Wong
  2846.  
  2847.  
  2848.  
  2849.  Article 2:  The Components of MS-DOS
  2850.  
  2851.  
  2852.       MS-DOS is a modular operating system consisting of multiple components
  2853.       with specialized functions. When MS-DOS is copied into memory during
  2854.       the loading process, many of its components are moved, adjusted, or
  2855.       discarded. However, when it is running, MS-DOS is a relatively static
  2856.       entity and its components are predictable and easy to study.
  2857.       Therefore, this article deals first with MS-DOS in its running state
  2858.       and later with its loading behavior.
  2859.  
  2860.  
  2861.  The Major Elements
  2862.  
  2863.       MS-DOS consists of three major modules:
  2864.  
  2865. ╓┌────────────────────────────┌───────────────────────┌──────────────────────╖
  2866.       Module                  MS-DOS Filename         PC-DOS Filename
  2867.       ──────────────────────────────────────────────────────────────────
  2868.       MS-DOS BIOS             IO.SYS                  IBMBIO.COM
  2869.  
  2870.       MS-DOS kernel           MSDOS.SYS               IBMDOS.COM
  2871.  
  2872.       MS-DOS shell            COMMAND.COM             COMMAND.COM
  2873.  
  2874.       During system initialization, these modules are loaded into memory, in
  2875.       the order given, just above the interrupt vector table located at the
  2876.       beginning of memory. All three modules remain in memory until the
  2877.       computer is reset or turned off. (The loader and system initialization
  2878.       modules are omitted from this list because they are discarded as soon
  2879.       as MS-DOS is running. See Loading MS-DOS, below.)
  2880.  
  2881.       The MS-DOS BIOS is supplied by the original equipment manufacturer
  2882.       (OEM) that distributes MS-DOS, usually for a particular computer. See
  2883.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: An
  2884.       Introduction to MS-DOS. The kernel is supplied by Microsoft and is the
  2885.       same across all OEMs for a particular version of MS-DOS--that is, no
  2886.       modifications are made by the OEM. The shell is a replaceable module
  2887.       that can be supplied by the OEM or replaced by the user; the default
  2888.       shell, COMMAND.COM, is supplied by Microsoft.
  2889.  
  2890.  The MS-DOS BIOS
  2891.  
  2892.       The file IO.SYS contains the MS-DOS BIOS and the MS-DOS initialization
  2893.       module, SYSINIT. The MS-DOS BIOS is customized for a particular
  2894.       machine by an OEM. SYSINIT is supplied by Microsoft and is put into
  2895.       IO.SYS by the OEM when the file is created. See Loading MS-DOS, below.
  2896.  
  2897.       The MS-DOS BIOS consists of a list of resident device drivers and an
  2898.       additional initialization module created by the OEM. The device
  2899.       drivers appear first in IO.SYS because they remain resident after
  2900.       IO.SYS is initialized; the MS-DOS BIOS initialization routine and
  2901.       SYSINIT are usually discarded after initialization.
  2902.  
  2903.       The minimum set of resident device drivers is CON, PRN, AUX, CLOCK$,
  2904.       and the driver for one block device. The resident character-device
  2905.       drivers appear in the driver list before the resident block-device
  2906.       drivers; installable character-device drivers are placed ahead of the
  2907.       resident device drivers in the list; installable block-device drivers
  2908.       are placed after the resident device drivers in the list. This
  2909.       sequence allows installable character-device drivers to supersede
  2910.       resident drivers. The NUL device driver, which must be the first
  2911.       driver in the chain, is contained in the MS-DOS kernel.
  2912.  
  2913.       Device driver code can be split between IO.SYS and ROM. For example,
  2914.       most MS-DOS systems and all PC-DOS-compatible systems have a ROM BIOS
  2915.       that contains primitive device support routines. These routines are
  2916.       generally used by resident and installable device drivers to augment
  2917.       routines contained in RAM. (Placing the entire driver in RAM makes the
  2918.       driver dependent on a particular hardware configuration; placing part
  2919.       of the driver in ROM allows the MS-DOS BIOS to be paired with a
  2920.       particular ROM interface that remains constant for many different
  2921.       hardware configurations.)
  2922.  
  2923.       The IO.SYS file is an absolute program image and does not contain
  2924.       relocation information. The routines in IO.SYS assume that the CS
  2925.       register contains the segment at which the file is loaded. Thus,
  2926.       IO.SYS has the same 64 KB restriction as a .COM file. See PROGRAMMING
  2927.       IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: Structure of an
  2928.       Application Program. Larger IO.SYS files are possible, but all device
  2929.       driver headers must lie in the first 64 KB and the code must rely on
  2930.       its own segment arithmetic to access routines outside the first 64 KB.
  2931.  
  2932.  The MS-DOS kernel
  2933.  
  2934.       The MS-DOS kernel is the heart of MS-DOS and provides the functions
  2935.       found in a traditional operating system. It is contained in a single
  2936.       proprietary file, MSDOS.SYS, supplied by Microsoft Corporation. The
  2937.       kernel provides its support functions (referred to as system
  2938.       functions) to application programs in a hardware-independent manner
  2939.       and, in turn, is isolated from hardware characteristics by relying on
  2940.       the driver routines in the MS-DOS BIOS to perform physical input and
  2941.       output operations.
  2942.  
  2943.       The MS-DOS kernel provides the following services through the use of
  2944.       device drivers:
  2945.  
  2946.       ■  File and directory management
  2947.       ■  Character device input and output
  2948.       ■  Time and date support
  2949.  
  2950.       It also provides the following non-device-related functions:
  2951.  
  2952.       ■  Memory management
  2953.       ■  Task and environment management
  2954.       ■  Country-specific configuration
  2955.  
  2956.       Programs access system functions using software interrupt (INT)
  2957.       instructions. MS-DOS reserves Interrupts 20H through 3FH for this
  2958.       purpose. The MS-DOS interrupts are
  2959.  
  2960. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  2961.       Interrupt        Name
  2962.       ──────────────────────────────────────────────────────────────────
  2963.       Interrupt        Name
  2964.       ──────────────────────────────────────────────────────────────────
  2965.       20H              Terminate Program
  2966.  
  2967.       21H              MS-DOS Function Calls
  2968.  
  2969.       22H              Terminate Routine Address
  2970.  
  2971.       23H              Control-C Handler Address
  2972.  
  2973.       24H              Critical Error Handler Address
  2974.  
  2975.       25H              Absolute Disk Read
  2976.  
  2977.       26H              Absolute Disk Write
  2978.  
  2979.       27H              Terminate and Stay Resident
  2980.  
  2981.       28H-2EH          Reserved
  2982.  
  2983.       2FH              Multiplex
  2984.       Interrupt        Name
  2985.      2FH              Multiplex
  2986.  
  2987.       30H-3FH          Reserved
  2988.  
  2989.       Interrupt 21H is the main source of MS-DOS services. The Interrupt 21H
  2990.       functions are implemented by placing a function number in the AH
  2991.       register, placing any necessary parameters in other registers, and
  2992.       issuing an INT 21H instruction. (MS-DOS also supports a call
  2993.       instruction interface for CP/M compatibility. The function and
  2994.       parameter registers differ from the interrupt interface. The CP/M
  2995.       interface was provided in MS-DOS version 1.0 solely to assist in
  2996.       movement of CP/M-based applications to MS-DOS. New applications should
  2997.       use Interrupt 21H functions exclusively.)
  2998.  
  2999.       MS-DOS version 2.0 introduced a mechanism to modify the operation of
  3000.       the MS-DOS BIOS and kernel: the CONFIG.SYS file. CONFIG.SYS is a text
  3001.       file containing command options that modify the size or configuration
  3002.       of internal MS-DOS tables and cause additional device drivers to be
  3003.       loaded. The file is read when MS-DOS is first loaded into memory. See
  3004.       USER COMMANDS: CONFIG.SYS.
  3005.  
  3006.  The MS-DOS shell
  3007.  
  3008.       The shell, or command interpreter, is the first program started by
  3009.       MS-DOS after the MS-DOS BIOS and kernel have been loaded and
  3010.       initialized. It provides the interface between the kernel and the
  3011.       user. The default MS-DOS shell, COMMAND.COM, is a command-oriented
  3012.       interface; other shells may be menu-driven or screen-oriented.
  3013.  
  3014.       COMMAND.COM is a replaceable shell. A number of commercial products
  3015.       can be used as COMMAND.COM replacements, or a programmer can develop a
  3016.       customized shell. The new shell program is installed by renaming the
  3017.       program to COMMAND.COM or by using the SHELL command in CONFIG.SYS.
  3018.       The latter method is preferred because it allows initialization
  3019.       parameters to be passed to the shell program.
  3020.  
  3021.       COMMAND.COM can execute a set of internal (built-in) commands, load
  3022.       and execute programs, or interpret batch files. Most of the internal
  3023.       commands support file and directory operations and manipulate the
  3024.       program environment segment maintained by COMMAND.COM. The programs
  3025.       executed by COMMAND.COM are .COM or .EXE files loaded from a block
  3026.       device. The batch (.BAT) files supported by COMMAND.COM provide a
  3027.       limited programming language and are therefore useful for performing
  3028.       small, frequently used series of MS-DOS commands. In particular, when
  3029.       it is first loaded by MS-DOS, COMMAND.COM searches for the batch file
  3030.       AUTOEXEC.BAT and interprets it, if found, before taking any other
  3031.       action. COMMAND.COM also provides default terminate, Control-C and
  3032.       critical error handlers whose addresses are stored in the vectors for
  3033.       Interrupts 22H, 23H, and 24H. See PROGRAMMING IN THE MS-DOS
  3034.       ENVIRONMENT: CUSTOMIZING MS-DOS: Exception Handlers.
  3035.  
  3036.  COMMAND.COM's split personality
  3037.       COMMAND.COM is a conventional .COM application with a slight twist.
  3038.       Ordinarily, a .COM program is loaded into a single memory segment.
  3039.       COMMAND.COM starts this way but then copies the nonresident portion of
  3040.       itself into high memory and keeps the resident portion in low memory.
  3041.       The memory above the resident portion is released to MS-DOS.
  3042.  
  3043.       The effect of this split is not apparent until after an executed
  3044.       program has terminated and the resident portion of COMMAND.COM regains
  3045.       control of the system. The resident portion then computes a checksum
  3046.       on the area in high memory where the nonresident portion should be, to
  3047.       determine whether it has been overwritten. If the checksum matches a
  3048.       stored value, the nonresident portion is assumed to be intact;
  3049.       otherwise, a copy of the nonresident portion is reloaded from disk and
  3050.       COMMAND.COM continues its normal operation.
  3051.  
  3052.       This "split personality" exists because MS-DOS was originally designed
  3053.       for systems with a limited amount of RAM. The nonresident portion of
  3054.       COMMAND.COM, which contains the built-in commands and batch-file-
  3055.       processing routines that are not essential to regaining control and
  3056.       reloading itself, is much larger than the resident portion, which is
  3057.       responsible for these tasks. Thus, permitting the nonresident portion
  3058.       to be overwritten frees additional RAM and allows larger application
  3059.       programs to be run.
  3060.  
  3061.  Command execution
  3062.       COMMAND.COM interprets commands by first checking to see if the
  3063.       specified command matches the name of an internal command. If so, it
  3064.       executes the command; otherwise, it searches for a .COM, .EXE, or .BAT
  3065.       file (in that order) with the specified name. If a .COM or .EXE
  3066.       program is found, COMMAND.COM uses the MS-DOS EXEC function (Interrupt
  3067.       21H Function 4BH) to load and execute it; COMMAND.COM itself
  3068.       interprets .BAT files. If no file is found, the message Bad command or
  3069.       file name is displayed.
  3070.  
  3071.       Although a command is usually simply a filename without the extension,
  3072.       MS-DOS versions 3.0 and later allow a command name to be preceded by a
  3073.       full pathname. If a path is not explicitly specified, the COMMAND.COM
  3074.       search mechanism uses the contents of the PATH environment variable,
  3075.       which can contain a list of paths to be searched for commands. The
  3076.       search starts with the current directory and proceeds through the
  3077.       directories specified by PATH until a file is found or the list is
  3078.       exhausted. For example, the PATH specification
  3079.  
  3080.       PATH C:\BIN;D:\BIN;E:\
  3081.  
  3082.       causes COMMAND.COM to search the current directory, then C:\BIN, then
  3083.       D:\BIN, and finally the root directory of drive E. COMMAND.COM
  3084.       searches each directory for a matching .COM, .EXE, or .BAT file, in
  3085.       that order, before moving to the next directory.
  3086.  
  3087.  MS-DOS environments
  3088.       Version 2.0 introduced the concept of environments to MS-DOS. An
  3089.       environment is a paragraph-aligned memory segment containing a
  3090.       concatenated set of zero-terminated (ASCIIZ) variable-length strings
  3091.       of the form
  3092.  
  3093.       variable=value
  3094.  
  3095.       that provide such information as the current search path used by
  3096.       COMMAND.COM to find executable files, the location of COMMAND.COM
  3097.       itself, and the format of the user prompt. The end of the set of
  3098.       strings is marked by a null string--that is, a single zero byte. A
  3099.       specific environment is associated with each program in memory through
  3100.       a pointer contained at offset 2CH in the 256-byte program segment
  3101.       prefix (PSP). The maximum size of an environment is 32 KB; the default
  3102.       size is 160 bytes.
  3103.  
  3104.       If a program uses the EXEC function to load and execute another
  3105.       program, the contents of the new program's environment are provided to
  3106.       MS-DOS by the initiating program--one of the parameters passed to the
  3107.       MS-DOS EXEC function is a pointer to the new program's environment.
  3108.       The default environment provided to the new program is a copy of the
  3109.       initiating program's environment.
  3110.  
  3111.       A program that uses the EXEC function to load and execute another
  3112.       program will not itself have access to the new program's environment,
  3113.       because MS-DOS provides a pointer to this environment only to the new
  3114.       program. Any changes made to the new program's environment during
  3115.       program execution are invisible to the initiating program because a
  3116.       child program's environment is always discarded when the child program
  3117.       terminates.
  3118.  
  3119.       The system's master environment is normally associated with the shell
  3120.       COMMAND.COM. COMMAND.COM creates this set of environment strings
  3121.       within itself from the contents of the CONFIG.SYS and AUTOEXEC.BAT
  3122.       files, using the SET, PATH, and PROMPT commands. See USER COMMANDS:
  3123.       AUTOEXEC.BAT; CONFIG.SYS. In MS-DOS version 3.2, the initial size of
  3124.       COMMAND.COM's environment can be controlled by loading COMMAND.COM
  3125.       with the /E parameter, using the SHELL directive in CONFIG.SYS. For
  3126.       example, placing the line
  3127.  
  3128.       SHELL=COMMAND.COM /E:2048 /P
  3129.  
  3130.       in CONFIG.SYS sets the initial size of COMMAND.COM's environment to 2
  3131.       KB. (The /P option prevents COMMAND.COM from terminating, thus causing
  3132.       it to remain in memory until the system is turned off or restarted.)
  3133.  
  3134.       The SET command is used to display or change the COMMAND.COM
  3135.       environment contents. SET with no parameters displays the list of all
  3136.       the environment strings in the environment. A typical listing might
  3137.       show the following settings:
  3138.  
  3139.       COMSPEC=A:\COMMAND.COM
  3140.       PATH=C:\;A:\;B:\
  3141.       PROMPT=$p  $d  $t$_$n$g
  3142.       TMP=C:\TEMP
  3143.  
  3144.       The following is a dump of the environment segment containing the
  3145.       previous environment example:
  3146.  
  3147.         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
  3148.  0000  43 4F 4D 53 50 45 43 3D-41 3A 5C 43 4F 4D 4D 41   COMSPEC=A:\COMMA
  3149.  0010  4E 44 2E 43 4F 4D 00 50-41 54 48 3D 43 3A 5C 3B   ND.COM.PATH=C:\;
  3150.  0020  41 3A 5C 3B 42 3A 5C 00-50 52 4F 4D 50 54 3D 24   A:\;B:\.PROMPT=$
  3151.  0030  70 20 20 24 64 20 20 24-74 24 5F 24 6E 24 67 00   p  $d  $t$_$n$g.
  3152.  0040  54 4D 50 3D 43 3A 5C 54-45 4D 50 00 00 00 00 00   TMP=C:\TEMP.....
  3153.  
  3154.       A SET command that specifies a variable but does not specify a value
  3155.       for it deletes the variable from the environment.
  3156.  
  3157.       A program can ignore the contents of its environment; however, use of
  3158.       the environment can add a great deal to the flexibility and
  3159.       configurability of batch files and application programs.
  3160.  
  3161.  Batch files
  3162.       Batch files are text files with a .BAT extension that contain MS-DOS
  3163.       user and batch commands. Each line in the file is limited to 128
  3164.       bytes. See USER COMMANDS: BATCH. Batch files can be created using most
  3165.       text editors, including EDLIN, and short batch files can even be
  3166.       created using the COPY command:
  3167.  
  3168.       C>COPY CON SAMPLE.BAT  <ENTER>
  3169.  
  3170.       The CON device is the system console; text entered from the keyboard
  3171.       is echoed on the screen as it is typed. The copy operation is
  3172.       terminated by pressing Ctrl-Z (or the F6 key on IBM-compatible
  3173.       machines), followed by the Enter key.
  3174.  
  3175.       Batch files are interpreted by COMMAND.COM one line at a time. In
  3176.       addition to the standard MS-DOS commands, COMMAND.COM's batch-file
  3177.       interpreter supports a number of special batch commands:
  3178.  
  3179. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  3180.       Command          Meaning
  3181.       ──────────────────────────────────────────────────────────────────
  3182.       ECHO1           Display a message.
  3183.  
  3184.       FOR1            Execute a command for a list of files.
  3185.  
  3186.       GOTO1           Transfer control to another point.
  3187.  
  3188.       IF1             Conditionally execute a command.
  3189.  
  3190.       PAUSE            Wait for any key to be pressed.
  3191.  
  3192.       REM              Insert comment line.
  3193.  
  3194.       Command          Meaning
  3195. 
  3196.       SHIFT1          Access more than 10 parameters.
  3197.  
  3198.       Execution of a batch file can be terminated before completion by
  3199.       pressing Ctrl-C or Ctrl-Break, causing COMMAND.COM to display the
  3200.       prompt
  3201.  
  3202.       Terminate batch job? (Y/N)
  3203.  
  3204.  I/O redirection
  3205.       I/O redirection was introduced with MS-DOS version 2.0. The
  3206.       redirection facility is implemented within COMMAND.COM using the
  3207.       Interrupt 21H system functions Duplicate File Handle (45H) and Force
  3208.       Duplicate File Handle (46H). COMMAND.COM uses these functions to
  3209.       provide both redirection at the command level and a UNIX/XENIX-like
  3210.       pipe facility.
  3211.  
  3212.       Redirection is transparent to application programs, but to take
  3213.       advantage of redirection, an application program must make use of the
  3214.       standard input and output file handles. The input and output of
  3215.       application programs that directly access the screen or keyboard or
  3216.       use ROM BIOS functions cannot be redirected.
  3217.  
  3218.       Redirection is specified in the command line by prefixing file or
  3219.       device names with the special characters >, >>, and <. Standard output
  3220.       (default = CON) is redirected using > and >> followed by the name of a
  3221.       file or character device. The former character creates a new file (or
  3222.       overwrites an existing file with the same name); the latter appends
  3223.       text to an existing file (or creates the file if it does not exist).
  3224.       Standard input (default = CON) is redirected with the < character
  3225.       followed by the name of a file or character device. See also
  3226.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Writing MS-
  3227.       DOS Filters.
  3228.  
  3229.       The redirection facility can also be used to pass information from one
  3230.       program to another through a "pipe." A pipe in MS-DOS is a special
  3231.       file created by COMMAND.COM. COMMAND.COM redirects the output of one
  3232.       program into this file and then redirects this file as the input to
  3233.       the next program. The pipe symbol, a vertical bar (), separates the
  3234.       program names. Multiple program names can be piped together in the
  3235.       same command line:
  3236.  
  3237.       C>DIR *.* | SORT | MORE
  3238.  
  3239.       This command is equivalent to
  3240.  
  3241.       C>DIR *.* > PIPE0  <ENTER>
  3242.       C>SORT < PIPE0 > PIPE1  <ENTER>
  3243.       C>MORE < PIPE1  <ENTER>
  3244.  
  3245.       The concept of pipes came from UNIX/XENIX, but UNIX/XENIX is a
  3246.       multitasking operating system that actually runs the programs
  3247.       simultaneously. UNIX/XENIX uses memory buffers to connect the
  3248.       programs, whereas MS-DOS loads one program at a time and passes
  3249.       information through a disk file.
  3250.  
  3251.  
  3252.  Loading MS-DOS
  3253.  
  3254.       Getting MS-DOS up to the standard A> prompt is a complex process with
  3255.       a number of variations. This section discusses the complete process
  3256.       normally associated with MS-DOS versions 2.0 and later. (MS-DOS
  3257.       versions 1.x use the same general steps but lack support for various
  3258.       system tables and installable device drivers.)
  3259.  
  3260.       MS-DOS is loaded as a result of either a "cold boot" or a "warm boot."
  3261.       On IBM-compatible machines, a cold boot is performed when the computer
  3262.       is first turned on or when a hardware reset occurs. A cold boot
  3263.       usually performs a power-on self test (POST) and determines the amount
  3264.       of memory available, as well as which peripheral adapters are
  3265.       installed. The POST is ordinarily reserved for a cold boot because it
  3266.       takes a noticeable amount of time. For example, an IBM-compatible ROM
  3267.       BIOS tests all conventional and extended RAM (RAM above 1 MB on an
  3268.       80286-based  or 80386-based machine), a procedure that can take tens
  3269.       of seconds. A warm boot, initiated by simultaneously pressing the
  3270.       Ctrl, Alt, and Del keys, bypasses these hardware checks and begins by
  3271.       checking for a bootable disk.
  3272.  
  3273.       A bootable disk normally contains a small loader program that loads
  3274.       MS-DOS from the same disk. See PROGRAMMING IN THE MS-DOS ENVIRONMENT:
  3275.       STRUCTURE OF MS-DOS: MS-DOS Storage Devices. The body of MS-DOS is
  3276.       contained in two files: IO.SYS and MSDOS.SYS (IBMBIO.COM and
  3277.       IBMDOS.COM with PC-DOS). IO.SYS contains the Microsoft system
  3278.       initialization module, SYSINIT, which configures MS-DOS using either
  3279.       default values or the specifications in the CONFIG.SYS file, if one
  3280.       exists, and then starts up the shell program (usually COMMAND.COM, the
  3281.       default). COMMAND.COM checks for an AUTOEXEC.BAT file and interprets
  3282.       the file if found. (Other shells might not support such batch files.)
  3283.       Finally, COMMAND.COM prompts the user for a command. (The standard
  3284.       MS-DOS prompt is A> if the system was booted from a floppy disk and C>
  3285.       if the system was booted from a fixed disk.) Each of these steps is
  3286.       discussed in detail below.
  3287.  
  3288.  The ROM BIOS, POST, and bootstrapping
  3289.  
  3290.       All 8086/8088-compatible microprocessors begin execution with the
  3291.       CS:IP set to FFFF:0000H, which typically contains a jump instruction
  3292.       to a destination in the ROM BIOS that contains the initialization code
  3293.       for the machine. (This has nothing to do with MS-DOS; it is a feature
  3294.       of the Intel microprocessors.) On IBM-compatible machines, the ROM
  3295.       BIOS occupies the address space from F000:0000H to this jump
  3296.       instruction. Figure 2-1 shows the location of the ROM BIOS within the
  3297.       1 MB address space. Supplementary ROM support can be placed before (at
  3298.       lower addresses than) the ROM BIOS.
  3299.  
  3300.       All interrupts are disabled when the microprocessor starts execution
  3301.       and it is up to the initialization routine to set up the interrupt
  3302.       vectors at the base of memory.
  3303.  
  3304.  
  3305.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3306.       │     ROM BIOS      │──FFFF:0000H
  3307.       ├───────────────────┤──F000:0000H
  3308.       │                   │
  3309.       │ Other ROM and RAM │
  3310.       │                   │
  3311.       ├───────────────────┤──Top of RAM
  3312.       │                   │   (A000:0000H for IBM PC)
  3313.       │                   │
  3314.       │                   │
  3315.       │     Free RAM      │
  3316.       │                   │
  3317.       │                   │
  3318.       │                   │
  3319.       └───────────────────┘──0000:0000H
  3320.  
  3321.       Figure 2-1. Memory layout at startup.
  3322.  
  3323.  
  3324.       The initialization routine in the ROM BIOS--the POST procedure--
  3325.       typically determines what devices are installed and operational and
  3326.       checks conventional memory (the first 1 MB) and, for 80286-based or
  3327.       80386-based machines, extended memory (above 1 MB). The devices are
  3328.       tested, where possible, and any problems are reported using a series
  3329.       of beeps and display messages on the screen.
  3330.  
  3331.       When the machine is found to be operational, the ROM BIOS sets it up
  3332.       for normal operation. First, it initializes the interrupt vector table
  3333.       at the beginning of memory and any interrupt controllers that
  3334.       reference the table. The interrupt vector table area is located from
  3335.       0000:0000H to 0000:03FFH. On IBM-compatible machines, some of the
  3336.       subsequent memory (starting at address 0000:0400H) is used for table
  3337.       storage by various ROM BIOS routines (Figure 2-2). The beginning load
  3338.       address for the MS-DOS system files is usually in the range 0000:0600H
  3339.       to 0000:0800H.
  3340.  
  3341.  
  3342.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3343.       │     ROM BIOS      │──FFFF:0000H
  3344.       ├───────────────────┤──F000:0000H
  3345.       │                   │
  3346.       │ Other ROM and RAM │
  3347.       │                   │
  3348.       ├───────────────────┤──Top of RAM
  3349.       │                   │   (A000:0000H for IBM PC)
  3350.       │                   │
  3351.       │                   │
  3352.       │     Free RAM      │
  3353.       │                   │
  3354.       │                   │
  3355.       │                   │
  3356.       ├───────────────────┤──0000:0600H
  3357.       │  ROM BIOS tables  │
  3358.       ├───────────────────┤──0000:0400H
  3359.       │ Interrupt vectors │
  3360.       │                   │
  3361.       └───────────────────┘──0000:0000H
  3362.  
  3363.       Figure 2-2. The interrupt vector table and the ROM BIOS table.
  3364.  
  3365.  
  3366.       Next, the ROM BIOS sets up any necessary hardware interfaces, such as
  3367.       direct memory access (DMA) controllers, serial ports, and the like.
  3368.       Some hardware setup may be done before the interrupt vector table area
  3369.       is set up. For example, the IBM PC DMA controller also provides
  3370.       refresh for the dynamic RAM chips and RAM cannot be used until the
  3371.       refresh DMA is running; therefore, the DMA must be set up first.
  3372.  
  3373.       Some ROM BIOS implementations also check to see if additional ROM
  3374.       BIOSs are installed by scanning the memory from A000:0000H to
  3375.       F000:0000H for a particular sequence of signature bytes. If additional
  3376.       ROM BIOSs are found, their initialization routines are called to
  3377.       initialize the associated devices. Examples of additional ROMs for the
  3378.       IBM PC family are the PC/XT's fixed-disk ROM BIOS and the EGA ROM
  3379.       BIOS.
  3380.  
  3381.       The ROM BIOS now starts the bootstrap procedure by executing the ROM
  3382.       loader routine. On the IBM PC, this routine checks the first floppy-
  3383.       disk drive to see if there is a bootable disk in it. If there
  3384.       is not, the routine then invokes the ROM associated with another
  3385.       bootable device to see if that device contains a bootable disk. This
  3386.       procedure is repeated until a bootable disk is found or until all
  3387.       bootable devices have been checked without success, in which case ROM
  3388.       BASIC is enabled.
  3389.  
  3390.       Bootable devices can be detected by a number of proprietary means. The
  3391.       IBM PC ROM BIOS reads the first sector on the disk into RAM (Figure 2-
  3392.       3) and checks for an 8086-family short or long jump at the beginning
  3393.       of the sector and for AA55H in the last word of the sector. This
  3394.       signature indicates that the sector contains the operating-system
  3395.       loader. Data disks--those disks not set up with the MS-DOS system
  3396.       files--usually cause the ROM loader routine to display a message
  3397.       indicating that the disk is not a bootable system disk. The customary
  3398.       recovery procedure is to display a message asking the user to insert
  3399.       another disk (with the operating system files on it) and press a key
  3400.       to try the load operation again. The ROM loader routine is then
  3401.       typically reexecuted from the beginning so that it can repeat its
  3402.       normal search procedure.
  3403.  
  3404.  
  3405.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3406.       │     ROM BIOS      │──FFFF:0000H
  3407.       ├───────────────────┤──F000:0000H
  3408.       │                   │
  3409.       │ Other ROM and RAM │
  3410.       │                   │
  3411.       ├───────────────────┤──Top of RAM
  3412.       │                   │   (A000:0000H for IBM PC)
  3413.       │                   │
  3414.       │                   │
  3415.       │     Free RAM      │
  3416.       │                   │
  3417.       │                   │
  3418.       │                   │
  3419.       ├───────────────────┤──0000:0600H
  3420.       │  ROM BIOS tables  │
  3421.       ├───────────────────┤──0000:0400H
  3422.       │ Interrupt vectors │
  3423.       │                   │
  3424.       └───────────────────┘──0000:0000H
  3425.  
  3426.       Figure 2-3. A loaded boot sector.
  3427.  
  3428.  
  3429.       When it finds a bootable device, the ROM loader routine loads the
  3430.       operating-system loader and transfers control to it. The operating-
  3431.       system loader then uses the ROM BIOS services through the interrupt
  3432.       table to load the next part of the operating system into low memory.
  3433.  
  3434.       Before it can proceed, the operating-system loader must know something
  3435.       about the configuration of the system boot disk (Figure 2-4). MS-DOS-
  3436.       compatible disks contain a data structure that contains this
  3437.       information. This structure, known as the BIOS parameter block (BPB),
  3438.       is located in the same sector as the operating-system loader. From the
  3439.       contents of the BPB, the operating-system loader calculates the
  3440.       location of the root directory for the boot disk so that it can verify
  3441.       that the first two entries in the root directory are IO.SYS and
  3442.       MSDOS.SYS. For versions of MS-DOS through 3.2, these files must also
  3443.       be the first two files in the file data area, and they must be
  3444.       contiguous. (The operating-system loader usually does not check the
  3445.       file allocation table [FAT] to see if IO.SYS and MSDOS.SYS are
  3446.       actually stored in contiguous sectors.) See PROGRAMMING IN
  3447.       THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: MS-DOS Storage Devices.
  3448.  
  3449.  
  3450.       ┌───────────────────┐
  3451.       │    Boot sector    │──First sector on the disk
  3452.       ├───────────────────┤
  3453.       │Reserved (optional)│
  3454.       ├───────────────────┤
  3455.       │       FAT#1       │
  3456.       ├───────────────────┤
  3457.       │       FAT#2       │
  3458.       ├───────────────────┤
  3459.       │  Root directory   │
  3460.       ├───────────────────┤
  3461.       │      IO.SYS       │
  3462.       ├───────────────────┤
  3463.       │     MSDOS.SYS     │
  3464.       ├───────────────────┤
  3465.       │                   │
  3466.       │                   │
  3467.       │  File data area   │
  3468.       │                   │
  3469.       └─────┐             │
  3470.       ┌────┐└───────┐     │
  3471.       │    └───────┐└─────┘
  3472.       │            └──────┐
  3473.       └───────────────────┘
  3474.  
  3475.       Figure 2-4. Boot-disk configuration.
  3476.  
  3477.  
  3478.       Next, the operating-system loader reads the sectors containing IO.SYS
  3479.       and MSDOS.SYS into contiguous areas of memory just above the ROM BIOS
  3480.       tables (Figure 2-5). (An alternative method is to take advantage
  3481.       of the operating-system loader's final jump to the entry point in
  3482.       IO.SYS and include routines in IO.SYS that allow it to load
  3483.       MSDOS.SYS.)
  3484.  
  3485.       Finally, assuming the file was loaded without any errors, the
  3486.       operating-system loader transfers control to IO.SYS, passing the
  3487.       identity of the boot device. The operating-system loader is no longer
  3488.       needed and its RAM is made available for other purposes.
  3489.  
  3490.  
  3491.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3492.       │     ROM BIOS      │
  3493.       ├───────────────────┤──F000:0000H
  3494.       │                   │
  3495.       │ Other ROM and RAM │
  3496.       │                   │
  3497.       ├───────────────────┤──Top of RAM
  3498.       │                   │   (A000:0000H for IBM PC)
  3499.       │ Possible free RAM │
  3500.       │                   │
  3501.       ├───────────────────┤
  3502.       │    Boot sector    │──Arbitrary location
  3503.       ├───────────────────┤
  3504.       │                   │
  3505.       │                   │
  3506.       │                   │
  3507.       │     Free RAM      │
  3508.       │                   │
  3509.       │                   │
  3510.       │                   │
  3511.       ├───────────────────┤
  3512.       │     MSDOS.SYS     │
  3513.       ├───────────────────┤
  3514.       │                   │
  3515.       │      IO.SYS       │──SYSINIT
  3516.       │                   │──MS-DOS BIOS (resident device drivers)
  3517.       ├───────────────────┤──0000:0600H
  3518.       │  ROM BIOS tables  │
  3519.       ├───────────────────┤──0000:0400H
  3520.       │ Interrupt vectors │
  3521.       │                   │
  3522.       └───────────────────┘──0000:0000H
  3523.  
  3524.       Figure 2-5. IO.SYS and MSDOS.SYS loaded.
  3525.  
  3526.  
  3527.  MS-DOS system initialization (SYSINIT)
  3528.  
  3529.       MS-DOS system initialization begins after the operating-system loader
  3530.       has loaded IO.SYS and MSDOS.SYS and transferred control to the
  3531.       beginning of IO.SYS. To this point, there has been no standard loading
  3532.       procedure imposed by MS-DOS, although the IBM PC loading procedure
  3533.       outlined here has become the de facto standard for most MS-DOS
  3534.       machines. When control is transferred to IO.SYS, however, MS-DOS
  3535.       imposes its standards.
  3536.  
  3537.       The IO.SYS file is divided into three modules:
  3538.  
  3539.       ■  The resident device drivers
  3540.       ■  The basic MS-DOS BIOS initialization module
  3541.       ■  The MS-DOS system initialization module, SYSINIT
  3542.  
  3543.       The two initialization modules are usually discarded as soon as MS-DOS
  3544.       is completely initialized and the shell program is running; the
  3545.       resident device drivers remain in memory while MS-DOS is running and
  3546.       are therefore placed in the first part of the IO.SYS file, before the
  3547.       initialization modules.
  3548.  
  3549.       The MS-DOS BIOS initialization module ordinarily displays a sign-on
  3550.       message and the copyright notice for the OEM that created IO.SYS. On
  3551.       IBM-compatible machines, it then examines entries in the interrupt
  3552.       table to determine what devices were found by the ROM BIOS at POST
  3553.       time and adjusts the list of resident device drivers accordingly. This
  3554.       adjustment usually entails removing those drivers that have no
  3555.       corresponding installed hardware. The initialization routine may also
  3556.       modify internal tables within the device drivers. The device driver
  3557.       initialization routines will be called later by SYSINIT, so the MS-DOS
  3558.       BIOS initialization routine is now essentially finished and control is
  3559.       transferred to the SYSINIT module.
  3560.  
  3561.       SYSINIT locates the top of RAM and copies itself there. It then
  3562.       transfers control to the copy and the copy proceeds with system
  3563.       initialization. The first step is to move MSDOS.SYS, which contains
  3564.       the MS-DOS kernel, to a position immediately following the end of the
  3565.       resident portion of IO.SYS, which contains the resident device
  3566.       drivers. This move overwrites the original copy of SYSINIT and usually
  3567.       all of the MS-DOS BIOS initialization routine, which are no longer
  3568.       needed. The resulting memory layout is shown in Figure 2-6.
  3569.  
  3570.  
  3571.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3572.       │     ROM BIOS      │
  3573.       ├───────────────────┤──F000:0000H
  3574.       │                   │
  3575.       │ Other ROM and RAM │
  3576.       │                   │
  3577.       ├───────────────────┤──Top of RAM
  3578.       │                   │   (A000:0000H for IBM PC)
  3579.       │      SYSINIT      │
  3580.       │                   │
  3581.       ├───────────────────┤
  3582.       │                   │
  3583.       │     Free RAM      │
  3584.       │                   │
  3585.       ├───────────────────┤
  3586.       │   MS-DOS kernel   │
  3587.       │    (MSDOS.SYS)    │
  3588.       ├───────────────────┤
  3589.       │    MS-DOS BIOS    │──Resident device drivers
  3590.       │     (IO.SYS)      │
  3591.       ├───────────────────┤──0000:0600H
  3592.       │  ROM BIOS tables  │
  3593.       ├───────────────────┤──0000:0400H
  3594.       │ Interrupt vectors │
  3595.       └───────────────────┘──0000:0000H
  3596.  
  3597.       Figure 2-6. SYSINIT and MSDOS.SYS relocated.
  3598.  
  3599.  
  3600.       SYSINIT then calls the initialization routine in the newly relocated
  3601.       MS-DOS kernel. This routine performs the internal setup for the
  3602.       kernel, including putting the appropriate values into the vectors for
  3603.       Interrupts 20H through 3FH.
  3604.  
  3605.       The MS-DOS kernel initialization routine then calls the initialization
  3606.       function of each resident device driver to set up vectors for any
  3607.       external hardware interrupts used by the device. Each block-device
  3608.       driver returns a pointer to a BPB for each drive that it supports;
  3609.       these BPBs are inspected by SYSINIT to find the largest sector size
  3610.       used by any of the drivers. See PROGRAMMING IN THE MS-DOS ENVIRONMENT:
  3611.       STRUCTURE OF MS-DOS: MS-DOS Storage Devices. The kernel initialization
  3612.       routine then allocates a sector buffer the size of the largest sector
  3613.       found and places the NUL device driver at the head of the device
  3614.       driver list.
  3615.  
  3616.       The kernel initialization routine's final operation before returning
  3617.       to SYSINIT is to display the MS-DOS copyright message. The loading of
  3618.       the system portion of MS-DOS is now complete and SYSINIT can use any
  3619.       MS-DOS function in conjunction with the resident set of device
  3620.       drivers.
  3621.  
  3622.       SYSINIT next attempts to open the CONFIG.SYS file in the root
  3623.       directory of the boot drive. If the file does not exist, SYSINIT uses
  3624.       the default system parameters; if the file is opened, SYSINIT reads
  3625.       the entire file into high memory and converts all characters to
  3626.       uppercase. The file contents are then processed to determine such
  3627.       settings as the number of disk buffers, the number of entries in the
  3628.       file tables, and the number of entries in the drive translation table
  3629.       (depending on the specific commands in the file), and these structures
  3630.       are allocated following the MS-DOS kernel (Figure 2-7).
  3631.  
  3632.       Then SYSINIT processes the CONFIG.SYS text sequentially to determine
  3633.       what installable device drivers are to be implemented and loads the
  3634.       installable device driver files into memory after the system disk
  3635.       buffers and the file and drive tables. Installable device driver files
  3636.       can be located in any directory on any drive whose driver has already
  3637.       been loaded. Each installable device driver initialization function is
  3638.       called after the device driver file is loaded into memory. The
  3639.       initialization procedure is the same as for resident device drivers,
  3640.       except that SYSINIT uses an address returned by the device driver
  3641.       itself to determine where the next device driver is to be placed. See
  3642.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Installable
  3643.       Device Drivers.
  3644.  
  3645.  
  3646.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3647.       │     ROM BIOS      │
  3648.       ├───────────────────┤──F000:0000H
  3649.       │                   │
  3650.       │ Other ROM and RAM │
  3651.       │                   │
  3652.       ├───────────────────┤──Top of RAM
  3653.       │                   │   (A000:0000H for IBM PC)
  3654.       │      SYSINIT      │
  3655.       │                   │
  3656.       ├───────────────────┤
  3657.       │                   │
  3658.       │                   │
  3659.       │     Free RAM      │
  3660.       │                   │
  3661.       │                   │
  3662.       ├───────────────────┤
  3663.       │    Installable    │
  3664.       │  device drivers   │
  3665.       ├───────────────────┤
  3666.       │File control blocks│
  3667.       ├───────────────────┤
  3668.       │   Disk buffers    │
  3669.       ├───────────────────┤
  3670.       │   MS-DOS tables   │
  3671.       ├───────────────────┤
  3672.       │   MS-DOS kernel   │
  3673.       │    (MSDOS.SYS)    │
  3674.       ├───────────────────┤
  3675.       │    MS-DOS BIOS    │──Resident device drivers
  3676.       │     (IO.SYS)      │
  3677.       ├───────────────────┤──0000:0600H
  3678.       │  ROM BIOS tables  │
  3679.       ├───────────────────┤──0000:0400H
  3680.       │ Interrupt vectors │
  3681.       │                   │
  3682.       └───────────────────┘──0000:0000H
  3683.  
  3684.       Figure 2-7. Tables allocated and installable device drivers loaded.
  3685.  
  3686.  
  3687.       Like resident device drivers, installable device drivers can be
  3688.       discarded by SYSINIT if the device driver initialization routine
  3689.       determines that a device is inoperative or nonexistent. A discarded
  3690.       device driver is not included in the list of device drivers.
  3691.       Installable character-device drivers supersede resident character-
  3692.       device drivers with the same name; installable block-device drivers
  3693.       cannot supersede resident block-drivers and are assigned drive letters
  3694.       following those of the resident block-device drivers.
  3695.  
  3696.       SYSINIT now closes all open files and then opens the three character
  3697.       devices CON, PRN, and AUX. The console (CON) is used as standard
  3698.       input, standard output, and standard error; the standard printer port
  3699.       is PRN (which defaults to LPT1); the standard auxiliary port is AUX
  3700.       (which defaults to COM1). Installable device drivers with these names
  3701.       will replace any resident versions.
  3702.  
  3703.  Starting the shell
  3704.  
  3705.       SYSINIT's last function is to load and execute the shell program by
  3706.       using the MS-DOS EXEC function. See PROGRAMMING IN THE MS-DOS
  3707.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: The MS-DOS EXEC Function. The
  3708.       SHELL statement in CONFIG.SYS specifies both the name of the shell
  3709.       program and its initial parameters; the default MS-DOS shell is
  3710.       COMMAND.COM. The shell program is loaded at the start of free memory
  3711.       after the installable device drivers or after the last internal MS-DOS
  3712.       file control block if there are no installable device drivers (Figure
  3713.       2-8).
  3714.  
  3715.  COMMAND.COM
  3716.       COMMAND.COM consists of three parts:
  3717.  
  3718.       ■  A resident portion
  3719.       ■  An initialization module
  3720.       ■  A transient portion
  3721.  
  3722.       The resident portion contains support for termination of programs
  3723.       started by COMMAND.COM and presents critical-error messages. It is
  3724.       also responsible for reloading the transient portion when necessary.
  3725.  
  3726.       The initialization module is called once by the resident portion.
  3727.       First, it moves the transient portion to high memory. (Compare Figures
  3728.       2-8 and 2-9.) Then it processes the parameters specified in the SHELL
  3729.       command in the CONFIG.SYS file, if any. See USER COMMANDS: COMMAND.
  3730.       Next, it processes the AUTOEXEC.BAT file, if one exists, and finally,
  3731.       it transfers control back to the resident portion, which frees the
  3732.       space used by the initialization module and transient portion. The
  3733.       relocated transient portion then displays the MS-DOS user prompt and
  3734.       is ready to accept commands.
  3735.  
  3736.       The transient portion gets a command from either the console or a
  3737.       batch file and executes it. Commands are divided into three
  3738.       categories:
  3739.  
  3740.       ■  Internal commands
  3741.       ■  Batch files
  3742.       ■  External commands
  3743.  
  3744.       Internal commands are routines contained within COMMAND.COM and
  3745.       include operations like COPY or ERASE. Execution of an internal
  3746.       command does not overwrite the transient portion. Internal commands
  3747.       consist of a keyword, sometimes followed by a list of command-specific
  3748.       parameters.
  3749.  
  3750.  
  3751.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3752.       │     ROM BIOS      │
  3753.       ├───────────────────┤──F000:0000H
  3754.       │                   │
  3755.       │ Other ROM and RAM │
  3756.       │                   │
  3757.       ├───────────────────┤──Top of RAM
  3758.       │                   │   (A000:0000H for IBM PC)
  3759.       │      SYSINIT      │
  3760.       │                   │
  3761.       ├───────────────────┤
  3762.       │                   │
  3763.       │                   │
  3764.       │     Free RAM      │
  3765.       │                   │
  3766.       │                   │
  3767.       ├───────────────────┤
  3768.       │    COMMAND.COM    │
  3769.       │    (transient)    │
  3770.       ├───────────────────┤
  3771.       │    COMMAND.COM    │
  3772.       │ (initialization)  │
  3773.       ├───────────────────┤
  3774.       │    COMMAND.COM    │
  3775.       │    (resident)     │
  3776.       ├───────────────────┤
  3777.       │    Installable    │
  3778.       │  device drivers   │
  3779.       ├───────────────────┤
  3780.       │File control blocks│
  3781.       ├───────────────────┤
  3782.       │   Disk buffers    │
  3783.       ├───────────────────┤
  3784.       │   MS-DOS tables   │
  3785.       ├───────────────────┤
  3786.       │   MS-DOS kernel   │
  3787.       │    (MSDOS.SYS)    │
  3788.       ├───────────────────┤
  3789.       │    MS-DOS BIOS    │──Resident device drivers
  3790.       │     (IO.SYS)      │
  3791.       ├───────────────────┤──0000:0600H
  3792.       │  ROM BIOS tables  │
  3793.       ├───────────────────┤──0000:0400H
  3794.       │ Interrupt vectors │
  3795.       └───────────────────┘──0000:0000H
  3796.  
  3797.       Figure 2-8. COMMAND.COM loaded.
  3798.  
  3799.  
  3800.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3801.       │     ROM BIOS      │
  3802.       ├───────────────────┤──F000:0000H
  3803.       │                   │
  3804.       │ Other ROM and RAM │
  3805.       │                   │
  3806.       ├───────────────────┤──Top of RAM
  3807.       │    COMMAND.COM    │   (A000:0000H for IBM PC)
  3808.       │    (transient)    │
  3809.       ├───────────────────┤
  3810.       │                   │
  3811.       │                   │
  3812.       │     Free RAM      │
  3813.       │                   │
  3814.       │                   │
  3815.       ├───────────────────┤
  3816.       │    COMMAND.COM    │
  3817.       │    (resident)     │
  3818.       ├───────────────────┤
  3819.       │    Installable    │
  3820.       │  device drivers   │
  3821.       ├───────────────────┤
  3822.       │File control blocks│
  3823.       ├───────────────────┤
  3824.       │   Disk buffers    │
  3825.       ├───────────────────┤
  3826.       │   MS-DOS tables   │
  3827.       ├───────────────────┤
  3828.       │   MS-DOS kernel   │
  3829.       │    (MSDOS.SYS)    │
  3830.       ├───────────────────┤
  3831.       │    MS-DOS BIOS    │──Resident device drivers
  3832.       │     (IO.SYS)      │
  3833.       ├───────────────────┤──0000:0600H
  3834.       │  ROM BIOS tables  │
  3835.       ├───────────────────┤──0000:0400H
  3836.       │ Interrupt vectors │
  3837.       │                   │
  3838.       └───────────────────┘──0000:0000H
  3839.  
  3840.       Figure 2-9. COMMAND.COM after relocation.
  3841.  
  3842.  
  3843.       Batch files are text files that contain internal commands, external
  3844.       commands, batch-file directives, and nonexecutable comments. See USER
  3845.       COMMANDS: BATCH.
  3846.  
  3847.       External commands, which are actually executable programs, are stored
  3848.       in separate files with .COM and .EXE extensions and are included on
  3849.       the MS-DOS distribution disks. See PROGRAMMING IN THE MS-DOS
  3850.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: Structure of an Application
  3851.       Program. These programs are invoked with the name of the file without
  3852.       the extension. (MS-DOS versions 3.x allow the complete pathname of the
  3853.       external command to be specified.)
  3854.  
  3855.       External commands are loaded by COMMAND.COM by means of the MS-DOS
  3856.       EXEC function. The EXEC function loads a program into the free memory
  3857.       area, also called the transient program area (TPA), and then passes it
  3858.       control. Control returns to COMMAND.COM when the new program
  3859.       terminates. Memory used by the program is released unless it is a
  3860.       terminate-and-stay-resident (TSR) program, in which case some of the
  3861.       memory is retained for the resident portion of the program. See
  3862.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Terminate-
  3863.       and-Stay-Resident Utilities.
  3864.  
  3865.       After a program terminates, the resident portion of COMMAND.COM checks
  3866.       to see if the transient portion is still valid, because if the program
  3867.       was large, it may have overwritten the transient portion's memory
  3868.       space. The validity check is done by computing a checksum on the
  3869.       transient portion and comparing it with a stored value. If the
  3870.       checksums do not match, the resident portion loads a new copy of the
  3871.       transient portion from the COMMAND.COM file.
  3872.  
  3873.       Just as COMMAND.COM uses the EXEC function to load and execute a
  3874.       program, programs can load and execute other programs until the system
  3875.       runs out of memory. Figure 2-10 shows a typical memory configuration
  3876.       for multiple applications loaded at the same time. The active task--
  3877.       the last one executed--ordinarily has complete control over the
  3878.       system, with the exception of the hardware interrupt handlers, which
  3879.       gain control whenever a hardware interrupt needs to be serviced.
  3880.  
  3881.       MS-DOS is not a multitasking operating system, so although several
  3882.       programs can be resident in memory, only one program can be active at
  3883.       a time. The stack-like nature of the system is apparent in Figure
  3884.       2-10. The top program is the active one; the next program down will
  3885.       continue to run when the top program exits, and so on until control
  3886.       returns to COMMAND.COM. RAM-resident programs that remain in memory
  3887.       after they have terminated are the exception. In this case, a program
  3888.       lower in memory than another program can become the active program,
  3889.       although the one-active-process limit is still in effect.
  3890.  
  3891.  
  3892.       ┌───────────────────┐──FFFF:000FH (1 MB)
  3893.       │     ROM BIOS      │
  3894.       ├───────────────────┤──F000:0000H
  3895.       │                   │
  3896.       │ Other ROM and RAM │
  3897.       │                   │
  3898.       ├───────────────────┤──Top of RAM
  3899.       │    COMMAND.COM    │   (A000:0000H for IBM PC)
  3900.       │    (transient)    │
  3901.       ├───────────────────┤
  3902.       │                   │
  3903.       │     Free RAM      │
  3904.       │                   │
  3905.       ├───────────────────┤
  3906.       │    Program #3     │
  3907.       │     (active)      │
  3908.       ├───────────────────┤
  3909.       │    Program #2     │
  3910.       ├───────────────────┤
  3911.       │    Program #1     │
  3912.       ├───────────────────┤
  3913.       │    COMMAND.COM    │
  3914.       │    (resident)     │
  3915.       ├───────────────────┤
  3916.       │    Installable    │
  3917.       │  device drivers   │
  3918.       ├───────────────────┤
  3919.       │File control blocks│
  3920.       ├───────────────────┤
  3921.       │   Disk buffers    │
  3922.       ├───────────────────┤
  3923.       │   MS-DOS tables   │
  3924.       ├───────────────────┤
  3925.       │   MS-DOS kernel   │
  3926.       │    (MSDOS.SYS)    │
  3927.       ├───────────────────┤
  3928.       │    MS-DOS BIOS    │──Resident device drivers
  3929.       │     (IO.SYS)      │
  3930.       ├───────────────────┤──0000:0600H
  3931.       │  ROM BIOS tables  │
  3932.       ├───────────────────┤──0000:0400H
  3933.       │ Interrupt vectors │
  3934.       │                   │
  3935.       └───────────────────┘──0000:0000H
  3936.  
  3937.       Figure 2-10. Multiple programs loaded.
  3938.  
  3939.  
  3940.  A custom shell program
  3941.       The SHELL directive in the CONFIG.SYS file can be used to replace the
  3942.       system's default shell, COMMAND.COM, with a custom shell. Nearly any
  3943.       program can be used as a system shell as long as it supplies default
  3944.       handlers for the Control-C and critical error exceptions. For example,
  3945.       the program in Figure 2-11 can be used to make any application program
  3946.       appear to be a shell program--if the application program terminates,
  3947.       SHELL.COM restarts it, giving the appearance that the application
  3948.       program is the shell program.
  3949.  
  3950.       SHELL.COM sets up the segment registers for operation as a .COM file
  3951.       and reduces the program segment size to less than 1 KB. It then
  3952.       initializes the segment values in the parameter table for the EXEC
  3953.       function, because .COM files cannot set up segment values within a
  3954.       program. The Control-C and critical error interrupt handler vectors
  3955.       are set to the address of the main program loop, which tries to load
  3956.       the new shell program. SHELL.COM prints a message if the EXEC
  3957.       operation fails. The loop continues forever and SHELL.COM will never
  3958.       return to the now-discarded SYSINIT that started it.
  3959.  
  3960.       ──────────────────────────────────────────────────────────────────────
  3961.  
  3962.       Figure 2-11. A simple program to run an application as an MS-DOS
  3963.       shell.
  3964.  
  3965.       ──────────────────────────────────────────────────────────────────────
  3966.  
  3967.       SHELL.COM is very short and not too smart. It needs to be changed and
  3968.       rebuilt if the name of the application program changes. A simple
  3969.       extension to SHELL--call it XSHELL-would be to place the name of the
  3970.       application program and any parameters in the command line. XSHELL
  3971.       would then have to parse the program name and the contents of the two
  3972.       FCBs needed for the EXEC function. The CONFIG.SYS line for starting
  3973.       this shell would be
  3974.  
  3975.       SHELL=XSHELL \SHELL\DEMO.EXE PARAM1 PARAM2 PARAM3
  3976.  
  3977.       SHELL.COM does not set up a new environment but simply uses the one
  3978.       passed to it.
  3979.  
  3980.                                                    William Wong
  3981.  
  3982.  
  3983.  
  3984.  Article 3:  MS-DOS Storage Devices
  3985.  
  3986.  
  3987.       Application programs access data on MS-DOS storage devices through the
  3988.       MS-DOS file-system support that is part of the MS-DOS kernel. The
  3989.       MS-DOS kernel accesses these storage devices, also called block
  3990.       devices, through two types of device drivers: resident block-device
  3991.       drivers contained in IO.SYS and installable block-device drivers
  3992.       loaded from individual files when MS-DOS is loaded. See
  3993.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: The
  3994.       Components of MS-DOS; CUSTOMIZING MS-DOS: Installable
  3995.       Device Drivers.
  3996.  
  3997.       MS-DOS can handle almost any medium, recording method, or other
  3998.       variation for a storage device as long as there is a device driver for
  3999.       it. MS-DOS needs to know only the sector size and the maximum number
  4000.       of sectors for the device; the appropriate translation between logical
  4001.       sector number and physical location is made by the device driver.
  4002.       Information about the number of heads, tracks, and so on is required
  4003.       only for those partitioning programs that allocate logical devices
  4004.       along these boundaries. See Layout of a Partition, below.
  4005.  
  4006.       The floppy-disk drive is perhaps the best-known block device, followed
  4007.       by its faster cousin, the fixed-disk drive. Other MS-DOS media include
  4008.       RAMdisks, nonvolatile RAMdisks, removable hard disks, tape drives, and
  4009.       CD ROM drives. With the proper device driver, MS-DOS can place a file
  4010.       system on any of these devices (except read-only media such as CD
  4011.       ROM).
  4012.  
  4013.       This article discusses the structure of the file system on floppy and
  4014.       fixed disks, starting with the physical layout of a disk and then
  4015.       moving on to the logical layout of the file system. The scheme
  4016.       examined is for the IBM PC fixed disk.
  4017.  
  4018.  
  4019.  Structure of an MS-DOS Disk
  4020.  
  4021.       The structure of an MS-DOS disk can be viewed in a number of ways:
  4022.  
  4023.       ■  Physical device layout
  4024.       ■  Logical device layout
  4025.       ■  Logical block layout
  4026.       ■  MS-DOS file system
  4027.  
  4028.       The physical layout of a disk is expressed in terms of sectors,
  4029.       tracks, and heads. The logical device layout, also expressed in terms
  4030.       of sectors, tracks, and heads, indicates how a logical device maps
  4031.       onto a physical device. A partitioned physical device contains
  4032.       multiple logical devices; a physical device that cannot be partitioned
  4033.       contains only one. Each logical device has a logical block layout used
  4034.       by MS-DOS to implement a file system. These various views of an MS-DOS
  4035.       disk are discussed below. See also PROGRAMMING IN THE MS-DOS
  4036.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: File and Record Management; Disk
  4037.       Directories and Volume Labels.
  4038.  
  4039.  Layout of a physical block device
  4040.  
  4041.       The two major block-device implementations are solid-state RAMdisks
  4042.       and rotating magnetic media such as floppy or fixed disks. Both
  4043.       implementations provide a fixed amount of storage in a fixed number of
  4044.       randomly accessible same-size sectors.
  4045.  
  4046.  RAMdisks
  4047.       A RAMdisk is a block device that has sectors mapped sequentially into
  4048.       RAM. Thus, the RAMdisk is viewed as a large set of sequentially
  4049.       numbered sectors whose addresses are computed by simply multiplying
  4050.       the sector number by the sector size and adding the base address of
  4051.       the RAMdisk sector buffer. Access is fast and efficient and the access
  4052.       time to any sector is fixed, making the RAMdisk the fastest block
  4053.       device available. However, there are significant drawbacks to
  4054.       RAMdisks. First, they are volatile; their contents are irretrievably
  4055.       lost when the computer's power is turned off (although a special
  4056.       implementation of the RAMdisk known as a nonvolatile RAMdisk includes
  4057.       a battery backup system that ensures that its contents are not lost
  4058.       when the computer's power is turned off). Second, they are usually not
  4059.       portable.
  4060.  
  4061.  Physical disks
  4062.       Floppy-disk and fixed-disk systems, on the other hand, store
  4063.       information on revolving platters coated with a special magnetic
  4064.       material. The disk is rotated in the drive at high speeds--
  4065.       approximately 300 revolutions per minute (rpm) for floppy disks and
  4066.       3600 rpm for fixed disks. (The term "fixed" refers to the fact that
  4067.       the medium is built permanently into the drive, not to the motion of
  4068.       the medium.) Fixed disks are also referred to as "hard" disks, because
  4069.       the disk itself is usually made from a rigid material such as metal or
  4070.       glass; floppy disks are usually made from a flexible material such as
  4071.       plastic.
  4072.  
  4073.       A transducer element called the read/write head is used to read and
  4074.       write tiny magnetic regions on the rotating magnetic medium. The
  4075.       regions act like small bar magnets with north and south poles. The
  4076.       magnetic regions of the medium can be logically oriented toward one or
  4077.       the other of these poles--orientation toward one pole is interpreted
  4078.       as a specific binary state (1 or 0) and orientation toward the other
  4079.       pole is interpreted as the opposite binary state. A change in the
  4080.       direction of orientation (and hence a change in the binary value)
  4081.       between two adjacent regions is called a flux reversal, and the
  4082.       density of a particular disk implementation can be measured by the
  4083.       number of regions per inch reliably capable of flux reversal. Higher
  4084.       densities of these regions yield higher-capacity disks. The flux
  4085.       density of a particular system depends on the drive mechanics, the
  4086.       characteristics of the read/write head, and the magnetic properties of
  4087.       the medium.
  4088.  
  4089.       The read/write head can encode digital information on a disk using a
  4090.       number of recording techniques, including frequency modulation (FM),
  4091.       modified frequency modulation (MFM), run length limited (RLL)
  4092.       encoding, and advanced run length limited (ARLL) encoding. Each
  4093.       technique offers double the data encoding density of the previous one.
  4094.       The associated control logic is more complex for the denser
  4095.       techniques.
  4096.  
  4097.       Tracks
  4098.       A read/write head reads data from or writes data to a thin section of
  4099.       the disk called a track, which is laid out in a circular fashion
  4100.       around the disk (Figure 3-1). Standard 5.25-inch floppy disks contain
  4101.       either 40 (0-39) or 80 (0-79) tracks per side. Like-numbered tracks on
  4102.       either side of a double-sided disk are distinguished by the number of
  4103.       the read/write head used to access the track. For example, track 1 on
  4104.       the top of the disk is identified as head 0, track 1; track 1 on the
  4105.       bottom of the disk is identified as head 1, track 1.
  4106.  
  4107.       Tracks can be either spirals, as on a phonograph record, or concentric
  4108.       rings. Computer media usually use one of two types of concentric
  4109.       rings. The first type keeps the same number of sectors on each track
  4110.       (see Sectors, below) and is rotated at a constant angular velocity
  4111.       (CAV). The second type maintains the same recording density across the
  4112.       entire surface of the disk, so a track near the center of a disk
  4113.       contains fewer sectors than a track near the perimeter. This latter
  4114.       type of disk is rotated at different speeds to keep the medium under
  4115.       the magnetic head moving at a constant linear velocity (CLV).
  4116.  
  4117.  
  4118.               ╔══════════════════════════════════════════╗
  4119.               ║                                          ║
  4120.               ║    Figure 3-1 is found on page 87        ║
  4121.               ║    in the printed version of the book.   ║
  4122.               ║                                          ║
  4123.               ╚══════════════════════════════════════════╝
  4124.  
  4125.       Figure 3-1. The physical layout of a CAV 9-sector, 5.25-inch floppy
  4126.       disk.
  4127.  
  4128.  
  4129.       Most MS-DOS computers use CAV disks, although a CLV disk can store
  4130.       more sectors using the same type of medium. This difference in storage
  4131.       capacity occurs because the limiting factor is the flux density of the
  4132.       medium and a CAV disk must maintain the same number of magnetic flux
  4133.       regions per sector on the interior of the disk as at the perimeter.
  4134.       Thus, the sectors on or near the perimeter do not use the full
  4135.       capability of the medium and the heads, because the space reserved for
  4136.       each magnetic flux region on the perimeter is larger than that
  4137.       available near the center of the disk. In spite of their greater
  4138.       storage capacity, however, CLV disks (such as CD ROMs) usually have
  4139.       slower access times than CAV disks because of the constant need to
  4140.       fine-tune the motor speed as the head moves from track to track. Thus,
  4141.       CAV disks are preferred for MS-DOS systems.
  4142.  
  4143.       Heads
  4144.       Simple disk systems use a single disk, or platter, and use one or two
  4145.       sides of the platter; more complex systems, such as fixed disks, use
  4146.       multiple platters. Disk systems that use both sides of a disk have one
  4147.       read/write head per side; the heads are positioned over the track to
  4148.       be read from or written to by means of a positioning mechanism such as
  4149.       a solenoid or servomotor. The heads are ordinarily moved in unison,
  4150.       using a single head-movement mechanism; thus, heads on opposite sides
  4151.       of a platter in a double-sided disk system typically access the same
  4152.       logical track on their associated sides of the platter. (Performance
  4153.       can be increased by increasing the number of heads to as many as one
  4154.       head per track, eliminating the positioning mechanism. However,
  4155.       because they are quite expensive, such multiple-head systems are
  4156.       generally found only on high-performance minicomputers and
  4157.       mainframes.)
  4158.  
  4159.       The set of like-numbered tracks on the two sides of a platter (or on
  4160.       all sides of all platters in a multiplatter system) is called a
  4161.       cylinder. Disks are usually partitioned along cylinders. Tracks and
  4162.       cylinders may appear to have the same meaning; however, the term track
  4163.       is used to define a concentric ring containing a specific number of
  4164.       sectors on a single side of a single platter, whereas the term
  4165.       cylinder refers to the number of like-numbered tracks on a device
  4166.       (Figure 3-2).
  4167.  
  4168.  
  4169.               ╔══════════════════════════════════════════╗
  4170.               ║                                          ║
  4171.               ║    Figure 3-2 is found on page 88        ║
  4172.               ║    in the printed version of the book.   ║
  4173.               ║                                          ║
  4174.               ╚══════════════════════════════════════════╝
  4175.  
  4176.       Figure 3-2. Tracks and cylinders on a fixed-disk system.
  4177.  
  4178.  
  4179.       Sectors
  4180.       Each track is divided into equal-size portions called sectors. The
  4181.       size of a sector is a power of 2 and is usually greater than 128
  4182.       bytes--typically, 512 bytes.
  4183.  
  4184.       Floppy disks are either hard-sectored or soft-sectored, depending on
  4185.       the disk drive and the medium. Hard-sectored disks are implemented
  4186.       using a series of small holes near the center of the disk that
  4187.       indicate the beginning of each sector; these holes are read by a
  4188.       photosensor/LED pair built into the disk drive. Soft-sectored disks
  4189.       are implemented by magnetically marking the beginning of each sector
  4190.       when the disk is formatted. A soft-sectored disk has a single hole
  4191.       near the center of the disk (see Figure 3-1) that marks the location
  4192.       of sector 0 for reference when the disk is formatted or when error
  4193.       detection is performed; this hole is also read by a photosensor/LED
  4194.       pair. Fixed disks use a special implementation of soft sectors (see
  4195.       below). A hard-sectored floppy disk cannot be used in a disk drive
  4196.       built for use with soft-sectored floppy disks (and vice versa).
  4197.  
  4198.       In addition to a fixed number of data bytes, both sector types include
  4199.       a certain amount of overhead information, such as error correction and
  4200.       sector identification, in each sector. The structure of each sector is
  4201.       implemented during the formatting process.
  4202.  
  4203.       Standard fixed disks and 5.25-inch floppy disks generally have from 8
  4204.       to 17 physical sectors per track. Sectors are numbered beginning at 1.
  4205.       Each sector is uniquely identified by a complete specification of the
  4206.       read/write head, cylinder number, and sector number. To access a
  4207.       particular sector, the disk drive controller hardware moves all heads
  4208.       to the specified cylinder and then activates the appropriate head for
  4209.       the read or write operation.
  4210.  
  4211.       The read/write heads are mechanically positioned using one of two
  4212.       hardware implementations. The first method, used with floppy disks,
  4213.       employs an "open-loop" servomechanism in which the software computes
  4214.       where the heads should be and the hardware moves them there. (A
  4215.       servomechanism is a device that can move a solenoid or hold it in a
  4216.       fixed position.) An open-loop system employs no feedback mechanism to
  4217.       determine whether the heads were positioned correctly--the hardware
  4218.       simply moves the heads to the requested position and returns an error
  4219.       if the information read there is not what was expected. The
  4220.       positioning mechanism in floppy-disk drives is made with close
  4221.       tolerances because if the positioning of the heads on two drives
  4222.       differs, disks written on one might not be usable on the other.
  4223.  
  4224.       Most fixed disk systems use the second method--a "closed-loop"
  4225.       servomechanism that reserves one side of one platter for positioning
  4226.       information. This information, which indicates where the tracks and
  4227.       sectors are located, is written on the disk at the factory when the
  4228.       drive is assembled. Positioning the read/write heads in a closed-loop
  4229.       system is actually a two-step process: First, the head assembly is
  4230.       moved to the approximate location of the read or write operation; then
  4231.       the disk controller reads the closed-loop servo information, compares
  4232.       it to the desired location, and fine-tunes the head position
  4233.       accordingly. This fine-tuning approach yields faster access times and
  4234.       also allows for higher-capacity disks because the positioning can be
  4235.       more accurate and the distances between tracks can therefore be
  4236.       smaller. Because the "servo platter" usually has positioning
  4237.       information on one side and data on the other, many systems have an
  4238.       odd number of read/write heads for data.
  4239.  
  4240.       Interleaving
  4241.       CAV MS-DOS disks are described in terms of bytes per sector, sectors
  4242.       per track, number of cylinders, and number of read/write heads.
  4243.       Overall access time is based on how fast the disk rotates (rotational
  4244.       latency) and how fast the heads can move from track to track (track-
  4245.       to-track latency).
  4246.  
  4247.       On most fixed disks, the sectors on the disk are logically or
  4248.       physically numbered so that logically sequential sectors are not
  4249.       physically adjacent (Figure 3-3). The underlying principle is that,
  4250.       because the controller cannot finish processing one sector before the
  4251.       next sequential sector arrives under the read/write head, the
  4252.       logically numbered sectors must be staggered around the track. This
  4253.       staggering of sectors is called skewing or, more commonly,
  4254.       interleaving. A 2-to-1 (2:1) interleave places sequentially accessed
  4255.       sectors so that there is one additional sector between them; a 3:1
  4256.       interleave places two additional sectors between them. A slower disk
  4257.       controller needs a larger interleave factor. A 3:1 interleave means
  4258.       that three revolutions are required to read all sectors on a track in
  4259.       numeric order.
  4260.  
  4261.  
  4262.               ╔══════════════════════════════════════════╗
  4263.               ║                                          ║
  4264.               ║    Figure 3-3 is found on page 90        ║
  4265.               ║    in the printed version of the book.   ║
  4266.               ║                                          ║
  4267.               ╚══════════════════════════════════════════╝
  4268.  
  4269.       Figure 3-3. A 3:1 interleave.
  4270.  
  4271.  
  4272.       One approach to improving fixed-disk performance is to decrease the
  4273.       interleave ratio. This generally requires a specialized utility
  4274.       program and also requires that the disk be reformatted to adjust to
  4275.       the new layout. Obviously, a 1:1 interleave is the most efficient,
  4276.       provided the disk controller can process at that speed. The normal
  4277.       interleave for an IBM PC/AT and its standard fixed disk and disk
  4278.       controller is 3:1, but disk controllers are available for the PC/AT
  4279.       that are capable of handling a 1:1 interleave. Floppy disks on MS-DOS-
  4280.       based computers all have a 1:1 interleave ratio.
  4281.  
  4282.  Layout of a partition
  4283.  
  4284.       For several reasons, large physical block devices such as fixed disks
  4285.       are often logically partitioned into smaller logical block devices
  4286.       (Figure 3-4). For instance, such partitions allow a device to be
  4287.       shared among different operating systems. Partitions can also be used
  4288.       to keep the size of each logical device within the PC-DOS 32 MB
  4289.       restriction (important for large fixed disks). MS-DOS permits a
  4290.       maximum of four partitions.
  4291.  
  4292.  
  4293.               ╔══════════════════════════════════════════╗
  4294.               ║                                          ║
  4295.               ║    Figure 3-4 is found on page 91        ║
  4296.               ║    in the printed version of the book.   ║
  4297.               ║                                          ║
  4298.               ╚══════════════════════════════════════════╝
  4299.  
  4300.       Figure 3-4. A partitioned disk.
  4301.  
  4302.  
  4303.       A partitioned block device has a partition table located in one sector
  4304.       at the beginning of the disk. This table indicates where the logical
  4305.       block devices are physically located. (Even a partitioned device with
  4306.       only one partition usually has such a table.)
  4307.  
  4308.       Under the MS-DOS partitioning standard, the first physical sector on
  4309.       the fixed disk contains the partition table and a bootstrap program
  4310.       capable of checking the partition table for a bootable partition,
  4311.       loading the bootable partition's boot sector, and transferring control
  4312.       to it. The partition table, located at the end of the first physical
  4313.       sector of the disk, can contain a maximum of four entries:
  4314.  
  4315. ╓┌────────────────────────┌───────────────────┌──────────────────────────────╖
  4316.       Offset From
  4317.       Start of Sector     Size (bytes)        Description
  4318.       ──────────────────────────────────────────────────────────────────
  4319.       01BEH               16                  Partition #4
  4320.       01CEH               16                  Partition #3
  4321.       01DEH               16                  Partition #2
  4322.       01EEH               16                  Partition #1
  4323.       01FEH                2                  Signature: AA55H
  4324.  
  4325.       The partitions are allocated in reverse order. Each 16-byte entry
  4326.       contains the following information:
  4327.  
  4328. ╓┌─────────────────────┌─────────────┌───────────────────────────────────────╖
  4329.       Offset From
  4330.       Start of Entry   Size (bytes)  Description
  4331.       ──────────────────────────────────────────────────────────────────
  4332.       00H              1             Boot indicator
  4333.       01H              1             Beginning head
  4334.       02H              1             Beginning sector
  4335.       03H              1             Beginning cylinder
  4336.       04H              1             System indicator
  4337.       05H              1             Ending head
  4338.       06H              1             Ending sector
  4339.       07H              1             Ending cylinder
  4340.       08H              4             Starting sector (relative to
  4341.                                      beginning of disk)
  4342.       0CH              4             Number of sectors in partition
  4343.  
  4344.       The boot indicator is zero for a nonbootable partition and 80H for a
  4345.       bootable (active) partition. A fixed disk can have only one bootable
  4346.       partition. (When setting a bootable partition, partition programs such
  4347.       as FDISK reset the boot indicators for all other partitions to zero.)
  4348.       See USER COMMANDS: FDISK.
  4349.  
  4350.       The system indicators are
  4351.  
  4352. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  4353.       Code        Meaning
  4354.       ──────────────────────────────────────────────────────────────────
  4355.       00H         Unknown
  4356.       01H         MS-DOS, 12-bit FAT
  4357.       04H         MS-DOS, 16-bit FAT
  4358.  
  4359.       Each partition's boot sector is located at the start of the partition,
  4360.       which is specified in terms of beginning head, beginning sector, and
  4361.       beginning cylinder numbers. This information, stored in the partition
  4362.       table in this order, is loaded into the DX and CX registers by the PC
  4363.       ROM BIOS loader routine when the machine is turned on or restarted.
  4364.       The starting sector of the partition relative to the beginning of the
  4365.       disk is also indicated. The ending head, sector, and cylinder numbers,
  4366.       also included in the partition table, specify the last accessible
  4367.       sector for the partition. The total number of sectors in a partition
  4368.       is the difference between the starting and ending head and cylinder
  4369.       numbers times the number of sectors per cylinder.
  4370.  
  4371.       MS-DOS versions 2.0 through 3.2 allow only one MS-DOS partition per
  4372.       partitioned device. Various device drivers have been implemented that
  4373.       use a different partition table that allows more than one MS-DOS
  4374.       partition to be installed, but the secondary MS-DOS partitions are
  4375.       usually accessible only by means of an installable device driver that
  4376.       knows about this change. (Even with additional MS-DOS partitions, a
  4377.       fixed disk can have only one bootable partition.)
  4378.  
  4379.  Layout of a file system
  4380.  
  4381.       Block devices are accessed on a sector basis. The MS-DOS kernel,
  4382.       through the device driver, sees a block device as a logical fixed-size
  4383.       array of sectors and assumes that the array contains a valid MS-DOS
  4384.       file system. The device driver, in turn, translates the logical sector
  4385.       requests from MS-DOS into physical locations on the block device.
  4386.  
  4387.       The initial MS-DOS file system is written to the storage medium by the
  4388.       MS-DOS FORMAT program. See USER COMMANDS: FORMAT. The general layout
  4389.       for the file system is shown in Figure 3-5.
  4390.  
  4391.  
  4392.       ┌────────────────────────────────────────────────────────┐
  4393.       │OEM identification, BIOS parameter block, Loader routine│
  4394.       │                     Reserved area                      │
  4395.       ├────────────────────────────────────────────────────────┤
  4396.       │             File allocation table (FAT) #1             │
  4397.       ├────────────────────────────────────────────────────────┤
  4398.       │           Possible additional copies of FAT            │
  4399.       ├────────────────────────────────────────────────────────┤
  4400.       │                                                        │
  4401.       │                  Root disk directory                   │
  4402.       │                                                        │
  4403.       ├────────────────────────────────────────────────────────┤
  4404.       │                                                        │
  4405.       │                                                        │
  4406.       │                                                        │
  4407.       │                       Files area                       │
  4408.       │                                                        │
  4409.       └───────────────────┐                                    │
  4410.       ┌──────────────────┐└──────────────────┐                 │
  4411.       │                  └──────────────────┐└─────────────────┘
  4412.       │                                     └──────────────────┐
  4413.       │                                                        │
  4414.       └────────────────────────────────────────────────────────┘
  4415.  
  4416.       Figure 3-5. The MS-DOS file system.
  4417.  
  4418.  
  4419.       The boot sector is always at the beginning of a partition. It contains
  4420.       the OEM identification, a loader routine, and a BIOS parameter block
  4421.       (BPB) with information about the device, and it is followed by an
  4422.       optional area of reserved sectors. See The Boot Sector, below. The
  4423.       reserved area has no specific use, but an OEM might require a more
  4424.       complex loader routine and place it in this area. The file allocation
  4425.       tables (FATs) indicate how the file data area is allocated; the root
  4426.       directory contains a fixed number of directory entries; and the file
  4427.       data area contains data files, subdirectory files, and free data
  4428.       sectors.
  4429.  
  4430.       All the areas just described--the boot sector, the FAT, the root
  4431.       directory, and the file data area--are of fixed size; that is, they do
  4432.       not change after FORMAT sets up the medium. The size of each of these
  4433.       areas depends on various factors. For instance, the size of the FAT is
  4434.       proportional to the file data area. The root directory size ordinarily
  4435.       depends on the type of device; a single-sided floppy disk can hold 64
  4436.       entries, a double-sided floppy disk can hold 112, and a fixed disk can
  4437.       hold 256. (RAMdisk drivers such as RAMDRIVE.SYS and some
  4438.       implementations of FORMAT allow the number of directory entries to be
  4439.       specified.)
  4440.  
  4441.       The file data area is allocated in terms of clusters. A cluster is a
  4442.       fixed number of contiguous sectors. Sector size and cluster size must
  4443.       be a power of 2. The sector size is usually 512 bytes and the cluster
  4444.       size is usually 1, 2, or 4 KB, but larger sector and cluster sizes are
  4445.       possible. Commonly used MS-DOS cluster sizes are
  4446.  
  4447. ╓┌────────────────────────────────┌───────────────────┌──────────────────────╖
  4448.       Disk Type                   Sectors/Cluster     Bytes/Cluster1
  4449.       ──────────────────────────────────────────────────────────────────
  4450.       Single-sided floppy disk     1                    512
  4451.       Double-sided floppy disk     2                   1024
  4452.       PC/AT fixed disk             4                   2048
  4453.       PC/XT fixed disk             8                   4096
  4454.       Disk Type                   Sectors/Cluster     Bytes/Cluster1
  4455.      PC/XT fixed disk             8                   4096
  4456.       Other fixed disks           16                   8192
  4457.       Other fixed disks           32                  16384
  4458.  
  4459.       In general, larger cluster sizes are used to support larger fixed
  4460.       disks. Although smaller cluster sizes make allocation more space
  4461.       -efficient, larger clusters are usually more efficient for random and
  4462.       sequential access, especially if the clusters for a single file are
  4463.       not sequentially allocated.
  4464.  
  4465.       The file allocation table contains one entry per cluster in the file
  4466.       data area. Doubling the sectors per cluster will also halve the number
  4467.       of FAT entries for a given partition. See The File Allocation Table,
  4468.       below.
  4469.  
  4470.  The boot sector
  4471.       The boot sector (Figure 3-6) contains a BIOS parameter block, a loader
  4472.       routine, and some other fields useful to device drivers. The BPB
  4473.       describes a number of physical parameters of the device, as well as
  4474.       the location and size of the other areas on the device. The device
  4475.       driver returns the BPB information to MS-DOS when requested, so that
  4476.       MS-DOS can determine how the disk is configured.
  4477.  
  4478.  
  4479.       00H ┌───────────────────────────────────────────┐
  4480.           │           E9 XX XX or EB XX 90            │
  4481.       03H ├───────────────────────────────────────────┤
  4482.           │                                           │
  4483.           │      OEM name and version (8 bytes)       │
  4484.           │                                           │
  4485.       0BH ├───────────────────────────────────────────┤
  4486.           │        Bytes per sector (2 bytes)         │▒
  4487.       0DH ├───────────────────────────────────────────┤▒
  4488.           │   Sectors per allocation unit (1 byte)    │▒
  4489.       0EH ├───────────────────────────────────────────┤▒
  4490.           │ Reserved sectors, starting at 0 (2 bytes) │▒
  4491.       10H ├───────────────────────────────────────────┤▒
  4492.           │          Number of FATs (1 byte)          │▒
  4493.       11H ├───────────────────────────────────────────┤▒ BPB
  4494.           │Number of root-directory entries (2 bytes) │▒
  4495.       13H ├───────────────────────────────────────────┤▒
  4496.           │ Total sectors in logical volume (2 bytes) │▒
  4497.       15H ├───────────────────────────────────────────┤▒
  4498.           │           Media descriptor byte           │▒
  4499.       16H ├───────────────────────────────────────────┤▒
  4500.           │    Number of sectors per FAT (2 bytes)    │▒
  4501.       18H ├───────────────────────────────────────────┤
  4502.           │        Sectors per track (2 bytes)        │
  4503.       1AH ├───────────────────────────────────────────┤
  4504.           │         Number of heads (2 bytes)         │
  4505.       1CH ├───────────────────────────────────────────┤
  4506.           │    Number of hidden sectors (2 bytes)     │
  4507.       1EH ├───────────────────────────────────────────┤
  4508.           │                                           │
  4509.           │                                           │
  4510.           │                                           │
  4511.           │              Loader routine               │
  4512.           │                                           │
  4513.           │                                           │
  4514.           │                                           │
  4515.           │                                           │
  4516.           │                                           │
  4517.           └───────────────────────────────────────────┘
  4518.  
  4519.       Figure 3-6. Map of the boot sector of an MS-DOS disk. Bytes 0BH
  4520.       through 17H are the BIOS parameter block (BPB).
  4521.  
  4522.  
  4523.       Figure 3-7 is a hexadecimal dump of an actual boot sector. The first 3
  4524.       bytes of the boot sector shown in Figure 3-7 would be E9H 2CH 00H if a
  4525.       long jump were used instead of a short one (as in early versions of
  4526.       MS-DOS). The last 2 bytes in the sector, 55H and AAH, are a fixed
  4527.       signature used by the loader routine to verify that the sector is a
  4528.       valid boot sector.
  4529.  
  4530.  
  4531.         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
  4532.  0000  EB 2D 90 20 20 20 20 20-20 20 20 00 02 02 01 00   k-.        .....
  4533.  0010  02 70 00 A0 05 F9 03 00-09 00 02 00 00 00 00 00   .p. .y..........
  4534.  0020  00 0A 00 00 DF 02 25 02-09 2A FF 50 F6 0A 02 FA   ...._.%..*.Pv..z
  4535.  0030  B8 C0 07 8E D8 BC 00 7C-33 C0 8E D0 8E C0 FB FC   8@..X<.|3@.P.@{|
  4536.    .
  4537.    .
  4538.    .
  4539.  0180  0A 44 69 73 6B 20 42 6F-6F 74 20 46 61 69 6C 75   .Disk Boot Failu
  4540.  0190  72 65 0D 0A 0D 0A 4E 6F-6E 2D 53 79 73 74 65 6D   re....Non-System
  4541.  01A0  20 64 69 73 6B 20 6F 72-20 64 69 73 6B 20 65 72    disk or disk er
  4542.  01B0  72 6F 72 0D 0A 52 65 70-6C 61 63 65 20 61 6E 64   ror..Replace and
  4543.  01C0  20 70 72 65 73 73 20 61-6E 79 20 6B 65 79 20 77    press any key w
  4544.  01D0  68 65 6E 20 72 65 61 64-79 0D 0A 00 00 00 00 00   hen ready.......
  4545.  01E0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
  4546.  01F0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 55 AA   ...............*
  4547.  
  4548.       Figure 3-7. Hexadecimal dump of an MS-DOS boot sector. The BPB is
  4549.       highlighted.
  4550.  
  4551.  
  4552.       The BPB information contained in bytes 0BH through 17H indicates that
  4553.       there are
  4554.  
  4555.        512 bytes per sector
  4556.          2 sectors per cluster
  4557.          1 reserved sector (for the boot sector)
  4558.          2 FATs
  4559.        112 root directory entries
  4560.       1440 sectors on the disk
  4561.        F9H media descriptor
  4562.          3 sectors per FAT
  4563.  
  4564.       Additional information immediately after the BPB indicates that there
  4565.       are 9 sectors per track, 2 read/write heads, and 0 hidden sectors.
  4566.  
  4567.       The media descriptor, which appears in the BPB and in the first byte
  4568.       of each FAT, is used to indicate the type of medium currently in a
  4569.       drive. IBM-compatible media have the following descriptors:
  4570.  
  4571. ╓┌───────────────────┌────────────────────────────────┌──────────────────────╖
  4572.       Descriptor     Media Type                       MS-DOS Versions
  4573.       ──────────────────────────────────────────────────────────────────
  4574.       0F8H           Fixed disk                       2, 3
  4575.       0F0H           3.5-inch, 2-sided, 18 sector     3.2
  4576.       0F9H           3.5-inch, 2-sided, 9 sector      3.2
  4577.       0F9H           5.25-inch, 2-sided, 15 sector    3.x
  4578.       0FCH           5.25-inch, 1-sided, 9 sector     2.x, 3.x
  4579.       0FDH           5.25-inch, 2-sided, 9 sector     2.x, 3.x
  4580.       Descriptor     Media Type                       MS-DOS Versions
  4581.      0FDH           5.25-inch, 2-sided, 9 sector     2.x, 3.x
  4582.       0FEH           5.25-inch, 1-sided, 8 sector     1.x, 2.x, 3.x
  4583.       0FFH           5.25-inch, 2-sided, 8 sector     1.x (except 1.0), 2, 3
  4584.       0FEH           8-inch, 1-sided, single-density
  4585.       0FDH           8-inch, 2-sided, single-density
  4586.       0FEH           8-inch, 1-sided, double-density
  4587.       0FDH           8-inch, 2-sided, double-density
  4588.  
  4589.  
  4590.  The file allocation table
  4591.       The file allocation table provides a map to the storage locations of
  4592.       files on a disk by indicating which clusters are allocated to each
  4593.       file and in what order. To enable MS-DOS to locate a file, the file's
  4594.       directory entry contains its beginning FAT entry number. This FAT
  4595.       entry, in turn, contains the entry number of the next cluster if the
  4596.       file is larger than one cluster or a last-cluster number if there is
  4597.       only one cluster associated with the file. A file whose size implies
  4598.       that it occupies 10 clusters will have 10 FAT entries and 9 FAT links.
  4599.       (The set of links for a particular file is called a chain.)
  4600.  
  4601.       Additional copies of the FAT are used to provide backup in case of
  4602.       damage to the first, or primary, FAT; the typical floppy disk or fixed
  4603.       disk contains two FATs. The FATs are arranged sequentially after the
  4604.       boot sector, with some possible intervening reserved area. MS-DOS
  4605.       ordinarily uses the primary FAT but updates all FATs when a change
  4606.       occurs. It also compares all FATs when a disk is first accessed, to
  4607.       make sure they match.
  4608.  
  4609.       MS-DOS supports two types of FAT: One uses 12-bit links; the other,
  4610.       introduced with version 3.0 to accommodate large fixed disks with more
  4611.       than 4087 clusters, uses 16-bit links.
  4612.  
  4613.       The first two entries of a FAT are always reserved and are filled with
  4614.       a copy of the media descriptor byte and two (for a 12-bit FAT) or
  4615.       three (for a 16-bit FAT) 0FFH bytes, as shown in the following dumps
  4616.       of the first 16 bytes of the FAT:
  4617.  
  4618.       12-bit FAT:
  4619.  
  4620.       F9 FF FF 03 40 00 FF 6F-00 07 F0 FF 00 00 00 00
  4621.  
  4622.       16-bit FAT:
  4623.  
  4624.       F8 FF FF FF 03 00 04 00-FF FF 06 00 07 00 FF FF
  4625.  
  4626.       The remaining FAT entries have a one-to-one relationship with the
  4627.       clusters in the file data area. Each cluster's use status is indicated
  4628.       by its corresponding FAT value. (FORMAT initially marks the FAT entry
  4629.       for each cluster as free.) The use status is one of the following:
  4630.  
  4631. ╓┌──────────────────────────┌──────────────────┌─────────────────────────────╖
  4632.       12-bit                16-bit             Meaning
  4633.       ──────────────────────────────────────────────────────────────────
  4634.       000H                  0000H              Free cluster
  4635.       001H                  0001H              Unused code
  4636.       FF0-FF6H              FFF0-FFF6H         Reserved
  4637.       FF7H                  FFF7H              Bad cluster; cannot be used
  4638.       FF8-FFFH              FFF8-FFFFH         Last cluster of file
  4639.       All other values      All other values   Link to next cluster in file
  4640.  
  4641.       If a FAT entry is nonzero, the corresponding cluster has been
  4642.       allocated. A free cluster is found by scanning the FAT from the
  4643.       beginning to find the first zero value. Bad clusters are ordinarily
  4644.       identified during formatting. Figure 3-8 shows a typical FAT chain.
  4645.  
  4646.  
  4647.  FAT:  0      1      2      3      4      5      6      7      8      9
  4648.  entry
  4649.                       ┌─────┐ ┌───────────┐ ┌─────┐
  4650.     ┌──────┬──────┬───┴──┬───┴─┬──────┬───┴─┬─────┬──────┬──────┬──────┬─
  4651.     │ FFDH │ FFFH │ 003H │ 005H │ FF7H │ 006H │ FFFH │ 000H │ 000H │ 000H │
  4652.     │(4093)│(4095)│ (3)  │ (5)  │(4087)│ (6)  │(4095)│ (0)  │ (0)  │ (0)  │
  4653.     └──┬───┴──┬───┴──────┴──────┴──┬───┴──────┴──────┴──┬───┴──────┴──────┴─
  4654.        │      │                    │                    │       continues...
  4655.        │      │                    │                    │
  4656.        │      │                    │                    │
  4657.        │      │                    │                    └─Unused;
  4658.        │      │                    │                      available cluster
  4659.        │      │                    │
  4660.        │      │                    └─Unusable
  4661.        │      │
  4662.        │      └─Unused; not available
  4663.        │
  4664.        └─Disk is double-sided, double-density
  4665.  
  4666.       Figure 3-8. Space allocation in the FAT for a typical MS-DOS disk.
  4667.  
  4668.  
  4669.       Free FAT entries contain a link value of zero; a link value of 1 is
  4670.       never used. Thus, the first allocatable link number, associated with
  4671.       the first available cluster in the file data area, is 2, which is the
  4672.       number assigned to the first physical cluster in the file data area.
  4673.       Figure 3-9 shows the relationship of files, FAT entries, and clusters
  4674.       in the file data area.
  4675.  
  4676.  
  4677.     12-bit FAT:
  4678.  
  4679.       Reserved    003H        FFFH        007H        000H
  4680.          │       ┌────┐      ┌────┐      ┌────┐      ┌────┐
  4681.     ┌────┴─────┐┌┴─┐  │     ┌┴─┐  │     ┌┴─┐  │     ┌┴─┐  │
  4682.     │F9  FF  FF││03│ 40 │00││FF│ 6F │00││07│ F0 │FF││00│ 00
  4683.                      │  └─┬┘     │  └─┬┘     │  └─┬┘
  4684.                      └────┘      └────┘      └────┘
  4685.                       004H        006H        FFFH
  4686.  
  4687.  
  4688.     16-bit FAT:
  4689.  
  4690.         Reserved
  4691.            │         0003H   0004H   FFFFH   0006H   0007H   FFFFH   0000H
  4692.     ┌──────┴───────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐┌──────┐
  4693.     │F8  FF  FF  FF││03  00││04  00││FF  FF││06  00││07  00││FF  FF││00  00│
  4694.  
  4695.       FAT entry:     0     1     2     3     4     5     6     7     8
  4696.                   ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─
  4697.       12-bit FAT: │     │     │ 003H│ 004H│ FFFH│ 006H│ 007H│ FFFH│ 000H│
  4698.                   │ Reserved  │     │     │     │     │     │     │     │
  4699.       16-bit FAT: │     │     │0003H│0004H│FFFFH│0006H│0007H│FFFFH│0000H│
  4700.                   └─────┴─────┴──┬─┴──┬─┴────┴──┬─┴──┬─┴────┴─────┴─
  4701.                                 │ └───┘ └───┘     │ └───┘ └───┘continues...
  4702.            Directory entry      │                 │
  4703.       ┌───────────────────────┐ │                 │
  4704.       │        FILE1.TXT      ├─┘                 │
  4705.       │(points to FAT entry 2)│                   │
  4706.       └───────────────────────┘                   │
  4707.                                                   │
  4708.       ┌───────────────────────┐                   │
  4709.       │        FILE2.TXT      ├───────────────────┘
  4710.       │(points to FAT entry 5)│
  4711.       └───────────────────────┘
  4712.                        File data area       Corresponding FAT entry
  4713.                   ┌───────────────────────┐
  4714.                   │       FILE1.TXT       │            2
  4715.                   ├───────────────────────┤
  4716.                   │       FILE1.TXT       │            3
  4717.                   ├───────────────────────┤
  4718.                   │       FILE1.TXT       │            4
  4719.                   ├───────────────────────┤
  4720.                   │       FILE2.TXT       │            5
  4721.                   ├───────────────────────┤
  4722.                   │       FILE2.TXT       │            6
  4723.                   ├───────────────────────┤
  4724.                   │       FILE2.TXT       │            7
  4725.                   ├───────────────────────┤
  4726.                   │  Unused (available)   │            8
  4727.                   ├───────────────────────┤
  4728.  
  4729.       Figure 3-9. Correspondence between the FAT and the file data area.
  4730.  
  4731.  
  4732.       There is no logical difference between the operation of the 12-bit and
  4733.       16-bit FAT entries; the difference is simply in the storage and access
  4734.       methods. Because the 8086 is specifically designed to manipulate 8- or
  4735.       16-bit values efficiently, the access procedure for the 12-bit FAT is
  4736.       more complex than that for the 16-bit FAT (see Figures 3-10
  4737.       and 3-11).
  4738.  
  4739.       Special considerations
  4740.       The FAT is a highly efficient bookkeeping system, but various
  4741.       tradeoffs and problems can occur. One tradeoff is having a partially
  4742.       filled cluster at the end of a file. This situation leads to an
  4743.       efficiency problem when a large cluster size is used, because an
  4744.       entire cluster is allocated, regardless of the number of bytes it
  4745.       contains. For example, ten 100-byte files on a disk with 16 KB
  4746.       clusters use 160 KB of disk space; the same files on a disk with 1 KB
  4747.       clusters use only 10 KB--a difference of 150 KB, or 15 times less
  4748.       storage used by the smaller cluster size. On the other hand, the 12-
  4749.       bit FAT routine in Figure 3-10 shows the difficulty (and therefore
  4750.       slowness) of moving through a large file that has a long linked list
  4751.       of many small clusters. Therefore, the nature of the data must be
  4752.       considered: Large database applications work best with a larger
  4753.       cluster size; a smaller cluster size allows many small text files to
  4754.       fit on a disk. (The programmer writing the device driver for a disk
  4755.       device ordinarily sets the cluster size.)
  4756.  
  4757.       ──────────────────────────────────────────────────────────────────────
  4758.  
  4759.       Figure 3-10. Assembly-language routine to access a 12-bit FAT.
  4760.  
  4761.       ──────────────────────────────────────────────────────────────────────
  4762.  
  4763.       Figure 3-11. Assembly-language routine to access a 16-bit FAT.
  4764.  
  4765.       ──────────────────────────────────────────────────────────────────────
  4766.  
  4767.       Problems with corrupted directories or FATs, induced by such events as
  4768.       power failures and programs running wild, can lead to greater problems
  4769.       if not corrected. The MS-DOS CHKDSK program can detect and fix some of
  4770.       these problems. See USER COMMANDS: CHKDISK. For example, one common
  4771.       problem is dangling allocation lists caused by the absence of a
  4772.       directory entry pointing to the start of the list. This situation
  4773.       often results when the directory entry was not updated because a file
  4774.       was not closed before the computer was turned off or restarted. The
  4775.       effect is relatively benign: The data is inaccessible, but this
  4776.       limitation does not affect other file allocation operations. CHKDSK
  4777.       can fix this problem by making a new directory entry and linking it to
  4778.       the list.
  4779.  
  4780.       Another difficulty occurs when the file size in a directory entry does
  4781.       not match the file length as computed by traversing the linked list in
  4782.       the FAT. This problem can result in improper operation of a program
  4783.       and in error responses from MS-DOS.
  4784.  
  4785.       A more complex (and rarer) problem occurs when the directory entry is
  4786.       properly set up but all or some portion of the linked list is also
  4787.       referenced by another directory entry. The problem is grave, because
  4788.       writing or appending to one file changes the contents of the other
  4789.       file. This error usually causes severe data and/or directory
  4790.       corruption or causes the system to crash.
  4791.  
  4792.       A similar difficulty occurs when a linked list terminates with a free
  4793.       cluster instead of a last-cluster number. If the free cluster is
  4794.       allocated before the error is corrected, the problem eventually
  4795.       reverts to the preceding problem. An associated difficulty occurs if a
  4796.       link value of 1 or a link value that exceeds the size of the FAT is
  4797.       encountered.
  4798.  
  4799.       In addition to CHKDSK, a number of commercially available utility
  4800.       programs can be used to assist in FAT maintenance. For instance, disk
  4801.       reorganizers can be used to essentially rearrange the FAT and adjust
  4802.       the directory so that all files on a disk are laid out sequentially in
  4803.       the file data area and, of course, in the FAT.
  4804.  
  4805.  The root directory
  4806.       Directory entries, which are 32 bytes long, are found in both the root
  4807.       directory and the subdirectories. Each entry includes a filename and
  4808.       extension, the file's size, the starting FAT entry, the time and date
  4809.       the file was created or last revised, and the file's attributes. This
  4810.       structure resembles the format of the CP/M-style file control blocks
  4811.       (FCBs) used by the MS-DOS version 1.x file functions. See PROGRAMMING
  4812.       IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: Disk Directories
  4813.       and Volume Labels.
  4814.  
  4815.       The MS-DOS file-naming convention is also derived from CP/M: an eight-
  4816.       character filename followed by a three-character file type, each left
  4817.       aligned and padded with spaces if necessary. Within the limitations of
  4818.       the character set, the name and type are completely arbitrary. The
  4819.       time and date stamps are in the same format used by other MS-DOS
  4820.       functions and reflect the time the file was last written to.
  4821.  
  4822.       Figure 3-12 shows a dump of a 512-byte directory sector containing 16
  4823.       directory entries. (Each entry occupies two lines in this example.)
  4824.       The byte at offset 0ABH, containing a 10H, signifies that the entry
  4825.       starting at 0A0H is for a subdirectory. The byte at offset 160H,
  4826.       containing 0E5H, means that the file has been deleted. The byte at
  4827.       offset 8BH, containing the value 08H, indicates that the directory
  4828.       entry beginning at offset 80H is a volume label. Finally the zero byte
  4829.       at offset 1E0H marks the end of the directory, indicating that the
  4830.       subsequent entries in the directory have never been used and therefore
  4831.       need not be searched (versions 2.0 and later).
  4832.  
  4833.  
  4834.         0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
  4835.  0000  49 4F 20 20 20 20 20 20-53 59 53 27 00 00 00 00   IO      SYS'....
  4836.  0010  00 00 00 00 00 00 59 53-89 0B 02 00 D1 12 00 00   ......YS....Q...
  4837.  0020  4F 53 44 4F 53 20 20 20-53 59 53 27 00 00 00 00   MSDOS   SYS'....
  4838.  0030  00 00 00 00 00 00 41 49-52 0A 07 00 C9 43 00 00   ......AIR...IC..
  4839.  0040  41 4E 53 49 20 20 20 20-53 59 53 20 00 00 00 00   ANSI    SYS ....
  4840.  0050  00 00 00 00 00 00 41 49-52 0A 18 00 76 07 00 00   ......AIR...v...
  4841.  0060  58 54 41 4C 4B 20 20 20-45 58 45 20 00 00 00 00   XTALK   EXE ....
  4842.  0070  00 00 00 00 00 00 F7 7D-38 09 23 02 84 0B 01 00   ......w}8.#.....
  4843.  0080  4C 41 42 45 4C 20 20 20-20 20 20 08 00 00 00 00   LABEL       ....
  4844.  0090  00 00 00 00 00 00 8C 20-2A 09 00 00 00 00 00 00   ....... *.D..R..
  4845.  00A0  4C 4F 54 55 53 20 20 20-20 20 20 10 00 00 00 00   LOTUS       ....
  4846.  00B0  00 00 00 00 00 00 E0 0A-E1 06 A6 01 00 00 00 00   ......'.a.&.a...
  4847.  00C0  4C 54 53 4C 4F 41 44 20-43 4F 4D 20 00 00 00 00   LTSLOAD COM ....
  4848.  00D0  00 00 00 00 00 00 E0 0A-E1 06 A7 01 A0 27 00 00   ......'.a.'. '..
  4849.  00E0  4D 43 49 2D 53 46 20 20-58 54 4B 20 00 00 00 00   MCI-SF  XTK ....
  4850.  00F0  00 00 00 00 00 00 46 19-32 0D B1 01 79 04 00 00   ......F.2.1.y...
  4851.  0100  58 54 41 4C 4B 20 20 20-48 4C 50 20 00 00 00 00   XTALK   HLP ....
  4852.  0110  00 00 00 00 00 00 C5 6D-73 07 A3 02 AF 88 00 00   ......Ems.#./...
  4853.  0120  54 58 20 20 20 20 20 20-43 4F 4D 20 00 00 00 00   TX      COM ....
  4854.  0130  00 00 00 00 00 00 05 61-65 0C 39 01 E8 20 00 00   .......ae.9.h ..
  4855.  0140  43 4F 4D 4D 41 4E 44 20-43 4F 4D 20 00 00 00 00   COMMAND COM ....
  4856.  0150  00 00 00 00 00 00 41 49-52 0A 27 00 55 3F 00 00   ......AIR.'.U?..
  4857.  0160  E5 32 33 20 20 20 20 20-45 58 45 20 00 00 00 00   e23     EXE ....
  4858.  0170  00 00 00 00 00 00 9C B2-85 0B 42 01 80 5F 01 00   .......2..B.._..
  4859.  0180  47 44 20 20 20 20 20 20-44 52 56 20 00 00 00 00   GD      DRV ....
  4860.  0190  00 00 00 00 00 00 E0 0A-E1 06 9A 01 5B 08 00 00   ......'.a...[...
  4861.  01A0  4B 42 20 20 20 20 20 20-44 52 56 20 00 00 00 00   KB      DRV ....
  4862.  01B0  00 00 00 00 00 00 E0 0A-E1 06 9D 01 60 01 00 00   ......'.a...'...
  4863.  01C0  50 52 20 20 20 20 20 20-44 52 56 20 00 00 00 00   PR      DRV ....
  4864.  01D0  00 00 00 00 00 00 E0 0A-E1 06 9E 01 49 01 00 00   ......'.a...I...
  4865.  01E0  00 F6 F6 F6 F6 F6 F6 F6-F6 F6 F6 F6 F6 F6 F6 F6   ................
  4866.  01F0  F6 F6 F6 F6 F6 F6 F6 F6-F6 F6 F6 F6 F6 F6 F6 F6   ................
  4867.  
  4868.       Figure 3-12. Hexadecimal dump of a 512-byte directory sector.
  4869.  
  4870.  
  4871.       The sector shown in Figure 3-12 is actually an example of the first
  4872.       directory sector in the root directory of a bootable disk. Notice that
  4873.       IO.SYS and MSDOS.SYS are the first two files in the directory and that
  4874.       the file attribute byte (offset 0BH in a directory entry) has a binary
  4875.       value of 00100111, indicating that both files have hidden (bit 1 = 1),
  4876.       system (bit 0 = 1), and read-only (bit 2 = 1) attributes. The archive
  4877.       bit (bit 5) is also set, marking the files for possible backup.
  4878.  
  4879.       The root directory can optionally have a special type of entry called
  4880.       a volume label, identified by an attribute type of 08H, that is used
  4881.       to identify disks by name. A root directory can contain only one
  4882.       volume label. The root directory can also contain entries that point
  4883.       to subdirectories; such entries are identified by an attribute type of
  4884.       10H and a file size of zero. Programs that manipulate subdirectories
  4885.       must do so by tracing through their chains of clusters in the FAT.
  4886.  
  4887.       Two other special types of directory entries are found only within
  4888.       subdirectories. These entries have the filenames . and .. and
  4889.       correspond to the current directory and the parent directory of the
  4890.       current directory. These special entries, sometimes called directory
  4891.       aliases, can be used to move quickly through the directory structure.
  4892.  
  4893.       The maximum pathname length supported by MS-DOS, excluding a drive
  4894.       specifier but including any filename and extension and subdirectory
  4895.       name separators, is 64 characters. The size of the directory structure
  4896.       itself is limited only by the number of root directory entries and the
  4897.       available disk space.
  4898.  
  4899.  The file area
  4900.       The file area contains subdirectories, file data, and unallocated
  4901.       clusters. The area is divided into fixed-size clusters and the use for
  4902.       a particular cluster is specified by the corresponding FAT entry.
  4903.  
  4904.  
  4905.  Other MS-DOS Storage Devices
  4906.  
  4907.       As mentioned earlier, MS-DOS supports other types of storage devices,
  4908.       such as magnetic-tape drives and CD ROM drives. Tape drives are most
  4909.       often used for archiving and for sequential transaction processing and
  4910.       therefore are not discussed here.
  4911.  
  4912.       CD ROMs are compact laser discs that hold a massive amount of
  4913.       information--a single side of a CD ROM can hold almost 500 MB of data.
  4914.       However, there are some drawbacks to current CD ROM technology. For
  4915.       instance, data cannot be written to them--the information is placed on
  4916.       the compact disk at the factory when the disk is made and is available
  4917.       on a read-only basis. In addition, the access time for a CD ROM is
  4918.       much slower than for most magnetic-disk systems. Even with these
  4919.       limitations, however, the ability to hold so much information makes
  4920.       CD ROM a good method for storing large amounts of static information.
  4921.  
  4922.                                                    William Wong
  4923.  
  4924.  
  4925.  
  4926.  ───────────────────────────────────────────────────────────────────────────
  4927.  
  4928.  Part B  Programming for MS-DOS
  4929.  
  4930.  
  4931.  
  4932.  Article 4:  Structure of an Application Program
  4933.  
  4934.  
  4935.       Planning an MS-DOS application program requires serious analysis of
  4936.       the program's size. This analysis can help the programmer determine
  4937.       which of the two program styles supported by MS-DOS best suits the
  4938.       application. The .EXE program structure provides a large program with
  4939.       benefits resulting from the extra 512 bytes (or more) of header that
  4940.       preface all .EXE files. On the other hand, at the cost of losing the
  4941.       extra benefits, the .COM program structure does not burden a small
  4942.       program with the overhead of these extra header bytes.
  4943.  
  4944.       Because .COM programs start their lives as .EXE programs (before being
  4945.       converted by EXE2BIN) and because several aspects of application
  4946.       programming under MS-DOS remain similar regardless of the program
  4947.       structure used, a solid understanding of .EXE structures is beneficial
  4948.       even to the programmer who plans on writing only .COM programs.
  4949.       Therefore, we'll begin our discussion with the structure and behavior
  4950.       of .EXE programs and then look at differences between .COM programs
  4951.       and .EXE programs, including restrictions on the structure and content
  4952.       of .COM programs.
  4953.  
  4954.  
  4955.  The .EXE Program
  4956.  
  4957.       The .EXE program has several advantages over the .COM program for
  4958.       application design. Considerations that could lead to the choice of
  4959.       the .EXE format include
  4960.  
  4961.       ■  Extremely large programs
  4962.       ■  Multiple segments
  4963.       ■  Overlays
  4964.       ■  Segment and far address constants
  4965.       ■  Long calls
  4966.       ■  Possibility of upgrading programs to MS OS/2 protected mode
  4967.  
  4968.       The principal advantages of the .EXE format are provided by the file
  4969.       header. Most important, the header contains information that permits a
  4970.       program to make direct segment address references--a requirement if
  4971.       the program is to grow beyond 64 KB.
  4972.  
  4973.       The file header also tells MS-DOS how much memory the program
  4974.       requires. This information keeps memory not required by the program
  4975.       from being allocated to the program-an important consideration if the
  4976.       program is to be upgraded in the future to run efficiently under MS
  4977.       OS/2 protected mode.
  4978.  
  4979.       Before discussing the .EXE program structure in detail, we'll look at
  4980.       how .EXE programs behave.
  4981.  
  4982.  Giving control to the .EXE program
  4983.  
  4984.       Figure 4-1 gives an example of how a .EXE program might appear in
  4985.       memory when MS-DOS first gives the program control. The diagram shows
  4986.       Microsoft's preferred program segment arrangement.
  4987.  
  4988.  
  4989.                     ┌─────────────────────┬───────────────────────┐ SP
  4990.                     │                    ▒│Any segments with class│
  4991.                     │                    ▒│        STACK          │
  4992.                     │                    ▒├───────────────────────┤ SS
  4993.                     │    All segments    ▒│Any segments with class│
  4994.                     │     declared as    ▒│         BSS           │
  4995.                     │    part of group  ▒├───────────────────────┤
  4996.                     │        DGROUP      ▒│  Any DGROUP segments  │
  4997.                     │                    ▒│  not shown elsewhere  │
  4998.                     │                    ▒├───────────────────────┤
  4999.                     │                    ▒│Any segments with class│
  5000.                     │                    ▒│        BEGDATA        │
  5001.                     ├─────────────────────┴───────────────────────┤
  5002.                     │        Any segments with class names        │ IP
  5003.       Start segment │              ending with CODE               │
  5004.       and start of ├─────────────────────────────────────────────┤ CS
  5005.       program image          Program segment prefix (PSP)
  5006.       (load module) └─  ──  ──  ──  ──  ──  ──  ──  ──  ──  ──  ──┘ DS,ES
  5007.  
  5008.       Figure 4-1. The .EXE program: memory map diagram with register
  5009.       pointers.
  5010.  
  5011.  
  5012.       Before transferring control to the .EXE program, MS-DOS initializes
  5013.       various areas of memory and several of the microprocessor's registers.
  5014.       The following discussion explains what to expect from MS-DOS before it
  5015.       gives the .EXE program control.
  5016.  
  5017.  The program segment prefix
  5018.       The program segment prefix (PSP) is not a direct result of any program
  5019.       code. Rather, this special 256-byte (16-paragraph) page of memory is
  5020.       built by MS-DOS in front of all .EXE and .COM programs when they are
  5021.       loaded into memory. Although the PSP does contain several fields of
  5022.       use to newer programs, it exists primarily as a remnant of CP/M--
  5023.       Microsoft adopted the PSP for ease in porting the vast number of
  5024.       programs available under CP/M to the MS-DOS environment. Figure 4-2
  5025.       shows the fields that make up the PSP.
  5026.  
  5027.  
  5028.  
  5029.             x0H    x1H    x2H    x3H    x4H    x5H    x6H    x7H     x8H    x9
  5030.           ┌─────────────┬─────────────┬──────┬────────────────────────────────
  5031.           │             │             │      │
  5032.           │  INT 20H    │  End alloc  │ Resv.│  Far call to MS-DOS fn handler.
  5033.       OxH │             │             │      │
  5034.           │ OCDH │ 20H  │seg lo│seg hi│      │ 9AH  │ofs lo│ofs hi│ seg lo│seg
  5035.           └──────┴──────┼──────┴──────┴──────┴──────┼──────┴──────┴───────┴───
  5036.                         │                           │
  5037.           │ ...address  │Prev critical error address│                      ...
  5038.       1xH │             │                           │
  5039.           │seg lo│seg hi│ofs lo│ofs hi│seg lo│seg hi│      │      │       │
  5040.           └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴───────┴───
  5041.  
  5042.           │                                  ...Reserved...
  5043.       2xH │
  5044.           │      │      │      │      │      │      │      │      │       │
  5045.           └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴───────┴───
  5046.  
  5047.           │                                                 ...Reserved...
  5048.       3xH │
  5049.           │      │      │      │      │      │      │      │      │       │
  5050.           └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴───────┴───
  5051.  
  5052.           │
  5053.           │                                                   ...Reserved...
  5054.       4xH │
  5055.           │      │      │      │      │      │      │      │      │       │
  5056.           ├──────┴──────┴──────┼──────┴──────┴──────┴──────┴──────┴───────┴───
  5057.           │                    │
  5058.           │  INT 21H and RETF  │                                 Reserved
  5059.       5xH │                    │
  5060.           │ OCDH │ 21H  │ OCBH │      │      │      │      │      │       │
  5061.           └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴───────┴───
  5062.  
  5063.           │                   ...Primary file control block (FCB)...
  5064.       6xH │
  5065.           │  e   │  n   │  a   │  m   │  e   │  E   │  x   │  t   │  00H  │ 00
  5066.           └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴───────┴───
  5067.  
  5068.           │                 ...Secondary file control block (FCB)...
  5069.       7xH │
  5070.           │  e   │  n   │  a   │  m   │  e   │  E   │  x   │  t   │  00H  │ 00
  5071.           └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴───────┴───
  5072.  
  5073.           │
  5074.           │                            Command trail and default disk transfer
  5075.       8xH │                                          (continues through OFFH).
  5076.           │ Len  │      │      │      │      │      │      │      │       │
  5077.           └──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴───────┴───
  5078.  
  5079.       Figure 4-2. The program segment prefix (PSP).
  5080.  
  5081.  
  5082.       PSP:0000H (Terminate [old Warm Boot] Vector) The PSP begins with an
  5083.       8086-family INT 20H instruction, which the program can use to transfer
  5084.       control back to MS-DOS. The PSP includes this instruction at offset
  5085.       00H because this address was the WBOOT (Warm Boot/Terminate) vector
  5086.       under CP/M and CP/M programs usually terminated by jumping to this
  5087.       vector. This method of termination should not be used in newer
  5088.       programs. See Terminating the .EXE Program, below.
  5089.  
  5090.       PSP:0002H (Address of Last Segment Allocated to Program) MS-DOS
  5091.       introduced the word at offset 02H into the PSP. It contains the
  5092.       segment address of the paragraph following the block of memory
  5093.       allocated to the program. This address should be used only to
  5094.       determine the size or the end of the memory block allocated to the
  5095.       program; it must not be considered a pointer to free memory that the
  5096.       program can appropriate. In most cases this address will not point to
  5097.       free memory, because any free memory will already have been
  5098.       allocated to the program unless the program was linked using the
  5099.       /CPARMAXALLOC switch. Even when /CPARMAXALLOC is used, MS-DOS may fit
  5100.       the program into a block of memory only as big as the program
  5101.       requires. Well-behaved programs should acquire additional memory only
  5102.       through the MS-DOS function calls provided for that purpose.
  5103.  
  5104.       PSP:0005H (MS-DOS Function Call [old BDOS] Vector) Offset 05H is also
  5105.       a hand-me-down from CP/M. This location contains an 8086-family far
  5106.       (intersegment) call instruction to MS-DOS's function request handler.
  5107.       (Under CP/M, this address was the Basic Disk Operating System [BDOS]
  5108.       vector, which served a similar purpose.) This vector should not be
  5109.       used to call MS-DOS in newer programs. The System Calls section of
  5110.       this book explains the newer, approved method for calling MS-DOS.
  5111.       MS-DOS provides this vector only to support CP/M-style programs and
  5112.       therefore honors only the CP/M-style functions (00-24H) through it.
  5113.  
  5114.       PSP:000AH-0015H (Parent's 22H, 23H, and 24H Interrupt Vector Save)
  5115.       MS-DOS uses offsets 0AH through 15H to save the contents of three
  5116.       program-specific interrupt vectors. MS-DOS must save these vectors
  5117.       because it permits any program to execute another program (called a
  5118.       child process) through an MS-DOS function call that returns control to
  5119.       the original program when the called program terminates. Because the
  5120.       original program resumes executing when the child program terminates,
  5121.       MS-DOS must restore these three interrupt vectors for the original
  5122.       program in case the called program changed them. The three vectors
  5123.       involved include the program termination handler vector (Interrupt
  5124.       22H), the Control-C/Control-Break handler vector (Interrupt 23H), and
  5125.       the critical error handler vector (Interrupt 24H). MS-DOS saves the
  5126.       original preexecution contents of these vectors in the child program's
  5127.       PSP as doubleword fields beginning at offsets 0AH for the program
  5128.       termination handler vector, 0EH for the Control-C/Control-Break
  5129.       handler vector, and 12H for the critical error handler vector.
  5130.  
  5131.       PSP:002CH (Segment Address of Environment) Under MS-DOS versions 2.0
  5132.       and later, the word at offset 2CH contains one of the most useful
  5133.       pieces of information a program can find in the PSP--the segment
  5134.       address of the first paragraph of the MS-DOS environment. This pointer
  5135.       enables the program to search through the environment for any
  5136.       configuration or directory search path strings placed there by users
  5137.       with the SET command.
  5138.  
  5139.       PSP:0050H (New MS-DOS Call Vector) Many programmers disregard the
  5140.       contents of offset 50H. The location consists simply of an INT 21H
  5141.       instruction followed by a RETF. A .EXE program can call this location
  5142.       using a far call as a means of accessing the MS-DOS function handler.
  5143.       Of course, the program can also simply do an INT 21H directly, which
  5144.       is smaller and faster than calling 50H. Unlike calls to offset 05H,
  5145.       calls to offset 50H can request the full range of MS-DOS functions.
  5146.  
  5147.       PSP:005CH (Default File Control Block 1) and PSP:006CH (Default File
  5148.       Control Block 2) MS-DOS parses the first two parameters the user
  5149.       enters in the command line following the program's name. If the first
  5150.       parameter qualifies as a valid (limited) MS-DOS filename (the name can
  5151.       be preceded by a drive letter but not a directory path), MS-DOS
  5152.       initializes offsets 5CH through 6BH with the first 16 bytes of an
  5153.       unopened file control block (FCB) for the specified file. If the
  5154.       second parameter also qualifies as a valid MS-DOS filename, MS-DOS
  5155.       initializes offsets 6CH through 7BH with the first 16 bytes of an
  5156.       unopened FCB for the second specified file. If the user specifies a
  5157.       directory path as part of either filename, MS-DOS initializes only the
  5158.       drive code in the associated FCB. Many programmers no longer use this
  5159.       feature, because file access using FCBs does not support directory
  5160.       paths and other newer MS-DOS features.
  5161.  
  5162.       Because FCBs expand to 37 bytes when the file is opened, opening the
  5163.       first FCB at offset 5CH causes it to grow from 16 bytes to 37 bytes
  5164.       and to overwrite the second FCB. Similarly, opening the second FCB at
  5165.       offset 6CH causes it to expand and to overwrite the first part of the
  5166.       command tail and default disk transfer area (DTA). (The command tail
  5167.       and default DTA are described below.) To use the contents of both
  5168.       default FCBs, the program should copy the FCBs to a pair of 37-byte
  5169.       fields located in the program's data area. The program can use the
  5170.       first FCB without moving it only after relocating the second FCB (if
  5171.       necessary) and only by performing sequential reads or writes when
  5172.       using the first FCB. To perform random reads and writes using the
  5173.       first FCB, the programmer must either move the first FCB or change the
  5174.       default DTA address. Otherwise, the first FCB's random record field
  5175.       will overlap the start of the default DTA. See PROGRAMMING IN THE MS-
  5176.       DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: File and Record Management.
  5177.  
  5178.       PSP:0080H (Command Tail and Default DTA) The default DTA resides in
  5179.       the entire second half (128 bytes) of the PSP. MS-DOS uses this area
  5180.       of memory as the default record buffer if the program uses the FCB-
  5181.       style file access functions. Again, MS-DOS inherited this location
  5182.       from CP/M. (MS-DOS provides a function the program can call to change
  5183.       the address MS-DOS will use as the current DTA. See SYSTEM CALLS:
  5184.       INTERRUPT 21H: Function 1AH.) Because the default DTA serves no
  5185.       purpose until the program performs some file activity that requires
  5186.       it, MS-DOS places the command tail in this area for the program to
  5187.       examine. The command tail consists of any text the user types
  5188.       following the program name when executing the program. Normally, an
  5189.       ASCII space (20H) is the first character in the command tail, but any
  5190.       character MS-DOS recognizes as a separator can occupy this position.
  5191.       MS-DOS stores the command-tail text starting at offset 81H and always
  5192.       places an ASCII carriage return (0DH) at the end of the text. As an
  5193.       additional aid, it places the length of the command tail at offset
  5194.       80H. This length includes all characters except the final 0DH. For
  5195.       example, the command line
  5196.  
  5197.       C>DOIT WITH CLASS  <ENTER>
  5198.  
  5199.       will result in the program DOIT being executed with PSP:0080H
  5200.       containing
  5201.  
  5202.       0B  20 57 49 54 48 20 43 4C 41 53 53 0D
  5203.       len sp W  I  T  H  sp C  L  A  S  S  cr
  5204.  
  5205.  The stack
  5206.       Because .EXE-style programs did not exist under CP/M, MS-DOS expects
  5207.       .EXE programs to operate in strictly MS-DOS fashion. For example,
  5208.       MS-DOS expects the .EXE program to supply its own stack. (Figure 4-1
  5209.       shows the program's stack as the top box in the diagram.)
  5210.  
  5211.       Microsoft's high-level-language compilers create a stack themselves,
  5212.       but when writing in assembly language the programmer must specifically
  5213.       declare one or more segments with the STACK combine type. If the
  5214.       programmer declares multiple stack segments, possibly in different
  5215.       source modules, the linker combines them into one large segment. See
  5216.       Controlling the .EXE Program's Structure, below.
  5217.  
  5218.       Many programmers declare their stack segments as preinitialized with
  5219.       some recognizable repeating string such as *STACK. This makes it
  5220.       possible to examine the program's stack in memory (using a debugger
  5221.       such as DEBUG) to determine how much stack space the program actually
  5222.       used. On the other hand, if the stack is left as uninitialized memory
  5223.       and linked at the end of the .EXE program, it will not require space
  5224.       within the .EXE file. (The reason for this will become more apparent
  5225.       when we examine the structure of a .EXE file.)
  5226.  
  5227.       Note: When multiple stack segments have been declared in different
  5228.       .ASM files, the Microsoft Object Linker (LINK) correctly allocates the
  5229.       total amount of stack space specified in all the source modules, but
  5230.       the initialization data from all modules is overlapped module by
  5231.       module at the high end of the combined segment.
  5232.  
  5233.       An important difference between .COM and .EXE programs is that MS-DOS
  5234.       preinitializes a .COM program's stack with a termination address
  5235.       before transferring control to the program. MS-DOS does not do this
  5236.       for .EXE programs, so a .EXE program cannot simply execute an 8086-
  5237.       family RET instruction as a means of terminating.
  5238.  
  5239.       Note: In the assembly-language files generated for a Microsoft C
  5240.       program or for programs in most other high-level-languages, the
  5241.       compiler's placement of a RET instruction at the end of the main
  5242.       function/subroutine/procedure might seem confusing. After all, MS-DOS
  5243.       does not place any return address on the stack. The compiler places
  5244.       the RET at the end of main because main does not receive control
  5245.       directly from MS-DOS. A library initialization routine receives
  5246.       control from MS-DOS; this routine then calls main. When main performs
  5247.       the RET, it returns control to a library termination routine, which
  5248.       then terminates back to MS-DOS in an approved manner.
  5249.  
  5250.  Preallocated memory
  5251.       While loading a .EXE program, MS-DOS performs several steps to
  5252.       determine the initial amount of memory to be allocated to the program.
  5253.       First, MS-DOS reads the two values the linker places near the start of
  5254.       the .EXE header: The first value, MINALLOC, indicates the minimum
  5255.       amount of extra memory the program requires to start executing; the
  5256.       second value, MAXALLOC, indicates the maximum amount of extra memory
  5257.       the program would like allocated before it starts executing. Next,
  5258.       MS-DOS locates the largest free block of memory available. If the size
  5259.       of the program's image within the .EXE file combined with the value
  5260.       specified for MINALLOC exceeds the memory block it found, MS-DOS
  5261.       returns an error to the process trying to load the program. If that
  5262.       process is COMMAND.COM, COMMAND.COM then displays a Program too big to
  5263.       fit in memory error message and terminates the user's execution
  5264.       request. If the block exceeds the program's MINALLOC requirement,
  5265.       MS-DOS then compares the memory block against the program's image
  5266.       combined with the MAXALLOC request. If the free block exceeds the
  5267.       maximum memory requested by the program, MS-DOS allocates only the
  5268.       maximum request; otherwise, it allocates the entire block. MS-DOS then
  5269.       builds a PSP at the start of this block and loads the program's image
  5270.       from the .EXE file into memory following the PSP.
  5271.  
  5272.       This process ensures that the extra memory allocated to the program
  5273.       will immediately follow the program's image. The same will not
  5274.       necessarily be true for any memory MS-DOS allocates to the program as
  5275.       a result of MS-DOS function calls the program performs during its
  5276.       execution. Only function calls requesting MS-DOS to increase the
  5277.       initial allocation can guarantee additional contiguous memory. (Of
  5278.       course, the granting of such increase requests depends on the
  5279.       availability of free memory following the initial allocation.)
  5280.  
  5281.       Programmers writing .EXE programs sometimes find the lack of keywords
  5282.       or compiler/ assembler switches that deal with MINALLOC (and possibly
  5283.       MAXALLOC) confusing. The programmer never explicitly specifies a
  5284.       MINALLOC value because LINK sets MINALLOC to the total size of all
  5285.       uninitialized data and/or stack segments linked at the very end of the
  5286.       program. The MINALLOC field allows the compiler to indicate the size
  5287.       of the initialized data fields in the load module without actually
  5288.       including the fields themselves, resulting in a smaller .EXE program
  5289.       file. For LINK to minimize the size of the .EXE file, the program must
  5290.       be coded and linked in such a way as to place all uninitialized data
  5291.       fields at the end of the program. Microsoft high-level-language
  5292.       compilers handle this automatically; assembly-language programmers
  5293.       must give LINK a little help.
  5294.  
  5295.       Note: Beginning and even advanced assembly-language programmers can
  5296.       easily fall into an argument with the assembler over field addressing
  5297.       when attempting to place data fields after the code in the source
  5298.       file. This argument can be avoided if programmers use the SEGMENT and
  5299.       GROUP assembler directives. See Controlling the .EXE Program's
  5300.       Structure, below.
  5301.  
  5302.       No reliable method exists for the linker to determine the correct
  5303.       MAXALLOC value required by the .EXE program. Therefore, LINK uses a
  5304.       "safe" value of FFFFH, which causes MS-DOS to allocate all of the
  5305.       largest block of free memory--which is usually all free memory--to the
  5306.       program. Unless a program specifically releases the memory for which
  5307.       it has no use, it denies multitasking supervisor programs, such as
  5308.       IBM's TopView, any memory in which to execute additional programs--
  5309.       hence the rule that a well-behaved program releases unneeded memory
  5310.       during its initialization. Unfortunately, this memory conservation
  5311.       approach provides no help if a multitasking supervisor supports the
  5312.       ability to load several programs into memory without executing them.
  5313.       Therefore, programs that have correctly established MAXALLOC values
  5314.       actually are well-behaved programs.
  5315.  
  5316.       To this end, newer versions of Microsoft LINK include the
  5317.       /CPARMAXALLOC switch to permit specification of the maximum amount of
  5318.       memory required by the program. The /CPARMAXALLOC switch can also be
  5319.       used to set MAXALLOC to a value that is known to be less than
  5320.       MINALLOC. For example, specifying a MAXALLOC value of 1 (/CP:1) forces
  5321.       MS-DOS to allocate only MINALLOC extra paragraphs to the program. In
  5322.       addition, Microsoft supplies a program called EXEMOD with most of its
  5323.       languages. This program permits modification of the MAXALLOC field in
  5324.       the headers of existing .EXE programs. See Modifying the .EXE File
  5325.       Header, below.
  5326.  
  5327.  The registers
  5328.       Figure 4-1 gives a general indication of how MS-DOS sets the 8086-
  5329.       family registers before transferring control to a .EXE program. MS-DOS
  5330.       determines most of the original register values from information the
  5331.       linker places in the .EXE file header at the start of the .EXE file.
  5332.  
  5333.       MS-DOS sets the SS register to the segment (paragraph) address of the
  5334.       start of any segments declared with the STACK combine type and sets
  5335.       the SP register to the offset from SS of the byte immediately after
  5336.       the combined stack segments. (If no stack segment is declared, MS-DOS
  5337.       sets SS:SP to CS:0000.) Because in the 8086-family architecture a
  5338.       stack grows from high to low memory addresses, this effectively sets
  5339.       SS:SP to point to the base of the stack. Therefore, if the programmer
  5340.       declares stack segments when writing an assembly-language program, the
  5341.       program will not need to initialize the SS and SP registers.
  5342.       Microsoft's high-level-language compilers handle the creation of stack
  5343.       segments automatically. In both cases, the linker determines the
  5344.       initial SS and SP values and places them in the header at the start of
  5345.       the .EXE program file.
  5346.  
  5347.       Unlike its handling of the SS and SP registers, MS-DOS does not
  5348.       initialize the DS and ES registers to any data areas of the .EXE
  5349.       program. Instead, it points DS and ES to the start of the PSP. It does
  5350.       this for two primary reasons: First, MS-DOS uses the DS and ES
  5351.       registers to tell the program the address of the PSP; second, most
  5352.       programs start by examining the command tail within the PSP. Because
  5353.       the program starts without DS pointing to the data segments, the
  5354.       program must initialize DS and (optionally) ES to point to the data
  5355.       segments before it starts trying to access any fields in those
  5356.       segments. Unlike .COM programs, .EXE programs can do this easily
  5357.       because they can make direct references to segments, as follows:
  5358.  
  5359.               MOV     AX,SEG DATA_SEGMENT_OR_GROUP_NAME
  5360.               MOV     DS,AX
  5361.               MOV     ES,AX
  5362.  
  5363.       High-level-language programs need not initialize and maintain DS and
  5364.       ES; the compiler and library support routines do this.
  5365.  
  5366.       In addition to pointing DS and ES to the PSP, MS-DOS also sets AH and
  5367.       AL to reflect the validity of the drive identifiers it placed in the
  5368.       two FCBs contained in the PSP. MS-DOS sets AL to 0FFH if the first FCB
  5369.       at PSP:005CH was initialized with a nonexistent drive identifier;
  5370.       otherwise, it sets AL to zero. Similarly, MS-DOS sets AH to reflect
  5371.       the drive identifier placed in the second FCB at PSP:006CH.
  5372.  
  5373.       When MS-DOS analyzes the first two command-line parameters following
  5374.       the program name in order to build the first and second FCBs, it
  5375.       treats any character followed by a colon as a drive prefix. If the
  5376.       drive prefix consists of a lowercase letter (ASCII a through z), MS-
  5377.       DOS starts by converting the character to uppercase (ASCII A through
  5378.       Z). Then it subtracts 40H from the character, regardless of its
  5379.       original value. This converts the drive prefix letters A through Z to
  5380.       the drive codes 01H through 1AH, as required by the two FCBs. Finally,
  5381.       MS-DOS places the drive code in the appropriate FCB.
  5382.  
  5383.       This process does not actually preclude invalid drive specifications
  5384.       from being placed in the FCBs. For instance, MS-DOS will accept the
  5385.       drive prefix !: and place a drive code of 0E1H in the FCB (! = 21H;
  5386.       21H-40H = 0E1H). However, MS-DOS will then check the drive code to see
  5387.       if it represents an existing drive attached to the computer and will
  5388.       pass a value of 0FFH to the program in the appropriate register (AL or
  5389.       AH) if it does not.
  5390.  
  5391.       As a side effect of this process, MS-DOS accepts @: as a valid drive
  5392.       prefix because the subtraction of 40H converts the @ character (40H)
  5393.       to 00H. MS-DOS accepts the 00H value as valid because a 00H drive code
  5394.       represents the current default drive. MS-DOS will leave the FCB's
  5395.       drive code set to 00H rather than translating it to the code for the
  5396.       default drive because the MS-DOS function calls that use FCBs accept
  5397.       the 00H code.
  5398.  
  5399.       Finally, MS-DOS initializes the CS and IP registers, transferring
  5400.       control to the program's entry point. Programs developed using high-
  5401.       level-language compilers usually receive control at a library
  5402.       initialization routine. A programmer writing an assembly-language
  5403.       program using the Microsoft Macro Assembler (MASM) can declare any
  5404.       label within the program as the entry point by placing the label
  5405.       after the END statement as the last line of the program:
  5406.  
  5407.               END     ENTRY_POINT_LABEL
  5408.  
  5409.       With multiple source files, only one of the files should have a label
  5410.       following the END statement. If more than one source file has such a
  5411.       label, LINK uses the first one it encounters as the entry point.
  5412.  
  5413.       The other processor registers (BX, CX, DX, BP, SI, and DI) contain
  5414.       unknown values when the program receives control from MS-DOS. Once
  5415.       again, high-level-language programmers can ignore this fact--the
  5416.       compiler and library support routines deal with the situation. How-
  5417.       ever, assembly-language programmers should keep this fact in mind.
  5418.       It may give needed insight sometime in the future when a program
  5419.       functions at certain times and not at others.
  5420.  
  5421.       In many cases, debuggers such as DEBUG and SYMDEB initialize
  5422.       uninitialized registers to some predictable but undocumented state.
  5423.       For instance, some debuggers may predictably set BP to zero before
  5424.       starting program execution. However, a program must not rely on such
  5425.       debugger actions, because MS-DOS makes no such promises. Situations
  5426.       like this could account for a program that fails when executed
  5427.       directly under MS-DOS but works fine when executed using a debugger.
  5428.  
  5429.  Terminating the .EXE program
  5430.  
  5431.       After MS-DOS has given the .EXE program control and it has completed
  5432.       whatever task it set out to perform, the program needs to give control
  5433.       back to MS-DOS. Because of MS-DOS's evolution, five methods of program
  5434.       termination have accumulated--not including the several ways MS-DOS
  5435.       allows programs to terminate but remain resident in memory.
  5436.  
  5437.       Before using any of the termination methods supported by MS-DOS, the
  5438.       program should always close any files it had open, especially those
  5439.       to which data has been written or whose lengths were changed. Under
  5440.       versions 2.0 and later, MS-DOS closes any files opened using handles.
  5441.       However, good programming practice dictates that the program not rely
  5442.       on the operating system to close the program's files. In addition,
  5443.       programs written to use shared files under MS-DOS versions 3.0 and
  5444.       later should release any file locks before closing the files and
  5445.       terminating.
  5446.  
  5447.  The Terminate Process with Return Code function
  5448.       Of the five ways a program can terminate, only the Interrupt 21H
  5449.       Terminate Process with Return Code function (4CH) is recommended for
  5450.       programs running under MS-DOS version 2.0 or later. This method is one
  5451.       of the easiest approaches to terminating any program, regardless of
  5452.       its structure or segment register settings. The Terminate Process with
  5453.       Return Code function call simply consists of the following:
  5454.  
  5455.               MOV     AH,4CH               ;load the MS-DOS function code
  5456.               MOV     AL,RETURN_CODE       ;load the termination code
  5457.               INT     21H                  ;call MS-DOS to terminate program
  5458.  
  5459.       The example loads the AH register with the Terminate Process with
  5460.       Return Code function code. Then it loads the AL register with a return
  5461.       code. Normally, the return code represents the reason the program
  5462.       terminated or the result of any operation the program performed.
  5463.  
  5464.       A program that executes another program as a child process can recover
  5465.       and analyze the child program's return code if the child process used
  5466.       this termination method. Likewise, the child process can recover the
  5467.       RETURN_CODE returned by any program it executes as a child process.
  5468.       When a program is terminated using this method and control returns to
  5469.       MS-DOS, a batch (.BAT) file can be used to test the terminated
  5470.       program's return code using the IF ERRORLEVEL statement.
  5471.  
  5472.       Only two general conventions have been adopted for the value of
  5473.       RETURN_CODE: First, a RETURN_CODE value of 00H indicates a normal
  5474.       no-error termination of the program; second, increasing RETURN_CODE
  5475.       values indicate increasing severity of conditions under which the
  5476.       program terminated. For instance, a compiler could use the RETURN_CODE
  5477.       00H if it found no errors in the source file, 01H if it found only
  5478.       warning errors, or 02H if it found severe errors.
  5479.  
  5480.       If a program has no need to return any special RETURN_CODE values,
  5481.       then the following instructions will suffice to terminate the program
  5482.       with a RETURN_CODE of 00H:
  5483.  
  5484.               MOV     AX,4C00H
  5485.               INT     21H
  5486.  
  5487.       Apart from being the approved termination method, Terminate Process
  5488.       with Return Code is easier to use with .EXE programs than any other
  5489.       termination method because all other methods require that the CS
  5490.       register point to the start of the PSP when the program terminates.
  5491.       This restriction causes problems for .EXE programs because they have
  5492.       code segments with segment addresses different from that of the PSP.
  5493.  
  5494.       The only problem with Terminate Process with Return Code is that it is
  5495.       not available under MS-DOS versions earlier than 2.0, so it cannot be
  5496.       used if a program must be compatible with early MS-DOS versions.
  5497.       However, Figure 4-3 shows how a program can use the approved
  5498.       termination method when available but still remain pre-2.0 compatible.
  5499.       See The Warm Boot/Terminate Vector, below.
  5500.  
  5501.       ──────────────────────────────────────────────────────────────────────
  5502.  
  5503.       Figure 4-3. Terminating properly under any MS-DOS version.
  5504.  
  5505.       ──────────────────────────────────────────────────────────────────────
  5506.  
  5507.  The Terminate Program interrupt
  5508.       Before MS-DOS version 2.0, terminating with an approved method meant
  5509.       executing an INT 20H instruction, the Terminate Program interrupt. The
  5510.       INT 20H instruction was replaced as the approved termination method
  5511.       for two primary reasons: First, it did not provide a means whereby
  5512.       programs could return a termination code; second, CS had to point to
  5513.       the PSP before the INT 20H instruction was executed.
  5514.  
  5515.       The restriction placed on the value of CS at termination did not pose
  5516.       a problem for .COM programs because they execute with CS pointing to
  5517.       the beginning of the PSP. A .EXE program, on the other hand, executes
  5518.       with CS pointing to various code segments of the program, and the
  5519.       value of CS cannot be changed arbitrarily when the program is ready to
  5520.       terminate. Because of this, few .EXE programs attempt simply to
  5521.       execute a Terminate Program interrupt from directly within their own
  5522.       code segments. Instead, they usually use the termination method
  5523.       discussed next.
  5524.  
  5525.  The Warm Boot/Terminate vector
  5526.       The earlier discussion of the structure of the PSP briefly covered one
  5527.       older method a .EXE program can use to terminate: Offset 00H within
  5528.       the PSP contains an INT 20H instruction to which the program can jump
  5529.       in order to terminate. MS-DOS adopted this technique to support the
  5530.       many CP/M programs ported to MS-DOS. Under CP/M, this PSP location was
  5531.       referred to as the Warm Boot vector because the CP/M operating system
  5532.       was always reloaded from disk (rebooted) whenever a program
  5533.       terminated.
  5534.  
  5535.       Because offset 00H in the PSP contains an INT 20H instruction, jumping
  5536.       to that location terminates a program in the same manner as an INT 20H
  5537.       included directly within the program, but with one important
  5538.       difference: By jumping to PSP:0000H, the program sets the CS register
  5539.       to point to the beginning of the PSP, thereby satisfying the only
  5540.       restriction imposed on executing the Terminate Program interrupt. The
  5541.       discussion of MS-DOS Function 4CH gave an example of how a .EXE
  5542.       program can terminate via PSP:0000H. The example first asks MS-DOS for
  5543.       its version number and then terminates via PSP:0000H only under
  5544.       versions of MS-DOS earlier than 2.0. Programs can also use PSP:0000H
  5545.       under MS-DOS versions 2.0 and later; the example uses Function 4CH
  5546.       simply because it is preferred under the later MS-DOS versions.
  5547.  
  5548.  The RET instruction
  5549.       The other popular method used by CP/M programs to terminate involved
  5550.       simply executing a RET instruction. This worked because CP/M pushed
  5551.       the address of the Warm Boot vector onto the stack before giving the
  5552.       program control. MS-DOS provides this support only for .COM-style
  5553.       programs; it does not push a termination address onto the stack before
  5554.       giving .EXE programs control.
  5555.  
  5556.       The programmer who wants to use the RET instruction to return to
  5557.       MS-DOS can use the variation of the Figure 4-3 listing shown in
  5558.       Figure 4-4.
  5559.  
  5560.       ──────────────────────────────────────────────────────────────────────
  5561.  
  5562.       Figure 4-4. Using RET to return control to MS-DOS.
  5563.  
  5564.       ──────────────────────────────────────────────────────────────────────
  5565.  
  5566.  The Terminate Process function
  5567.       The final method for terminating a .EXE program is Interrupt 21H
  5568.       Function 00H (Terminate Process). This method maintains the same
  5569.       restriction as all other older termination methods: CS must point to
  5570.       the PSP. Because of this restriction, .EXE programs typically avoid
  5571.       this method in favor of terminating via PSP:0000H, as discussed above
  5572.       for programs executing under versions of MS-DOS earlier than 2.0.
  5573.  
  5574.  Terminating and staying resident
  5575.       A .EXE program can use any of several additional termination methods
  5576.       to return control to MS-DOS but still remain resident within memory to
  5577.       service a special event. See PROGRAMMING IN THE MS-DOS ENVIRONMENT:
  5578.       CUSTOMIZING MS-DOS: Terminate-and-Stay-Resident Utilities.
  5579.  
  5580.  Structure of the .EXE files
  5581.  
  5582.       So far we've examined how the .EXE program looks in memory, how MS-DOS
  5583.       gives the program control of the computer, and how the program should
  5584.       return control to MS-DOS. Next we'll investigate what the program
  5585.       looks like as a disk file, before MS-DOS loads it into memory. Figure
  5586.       4-5 shows the general structure of a .EXE file.
  5587.  
  5588.  
  5589.  
  5590.                    x0H    x1H    x2H    x3H    x4H    x5H    x6H    x7H    x8H
  5591.                  ┌─────────────┬─────────────┬─────────────┬─────────────┬────
  5592.                  │             │             │             │             │
  5593.                  │  Signature  │  Last page  │ File Pages  │ Reloc Items │Head
  5594.            OxH  │             │    Size     │             │             │
  5595.                  │  4DH │ 5AH  │lo byt│hi byt│lo byt│hi byt│lo byt│hi byt│lo b
  5596.                  ├──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼────
  5597.                  │             │             │             │             │
  5598.                  │ Initial SP  │ Neg Chksum  │ Initial IP  │Pre Reloc CS │Relo
  5599.            1xH  │             │             │             │             │
  5600.                  │ofs lo│ofs hi│lo byt│hi byt│ofs lo│ofs hi│seg lo│seg hi│lo b
  5601.                  ├──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴────
  5602.                  └────────────────────┐
  5603.                  ┌───────────────────┐└────────────────────┐
  5604.                  │                   └────────────────────┐└──────────────────
  5605.      Use Reloc   │                                        └───────────────────
  5606.     Tbl Ofs at   │
  5607.    18H (offset   ├───────────────────────────┬───────────────────────────┬────
  5608.        is from   │   Seg relocation Ptr #1   │   Seg relocation Ptr #2   │   S
  5609.       start of  │                           │                           │
  5610.          file)   │                           │                           │
  5611.                  │ofs lo│ofs hi│seg lo│seg hi│ofs lo│ofs hi│seg lo│seg hi│ofs
  5612.                  ├──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴────
  5613.                  └────────────────────┐
  5614.                  ┌───────────────────┐└────────────────────┐
  5615.                  │                   └────────────────────┐└──────────────────
  5616.                  │                                        └───────────────────
  5617.                  │
  5618.                  ├───────────────────────────┬───────────────────────────┬────
  5619.                  │   Seg relocation Ptr #n-3 │   Seg relocation Ptr #n-2 │  Se
  5620.                  │                           │                           │
  5621.                  │                           │                           │
  5622.                  │ofs lo│ofs hi│seg lo│seg hi│ofs lo│ofs hi│seg lo│seg hi│ofs
  5623.                  ├──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴────
  5624.                  └────────────────────┐
  5625.     Use Header   ┌───────────────────┐└────────────────────┐
  5626.   Paras at O8H   │                   └────────────────────┐└──────────────────
  5627.   (load module   │                                        └───────────────────
  5628.  always starts   │
  5629.   on paragraph  ├────────────────────────────────────────────────────────────
  5630.      boundary)   │            
  5631.                  │      Program image
  5632.                  │  - - - - - - - - - - - - - - - - - - - - - -- - - - - - -
  5633.                  │      (load module)            Use last page size at 02H
  5634.                  │            
  5635.    End of file  ├────────────────────────────────────────────────────────────
  5636.                  |
  5637.                  |
  5638.                   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5639.  
  5640.       Figure 4-5. Structure of a .EXE file.
  5641.  
  5642.  
  5643.  The file header
  5644.       Unlike .COM program files, .EXE program files contain information that
  5645.       permits the .EXE program and MS-DOS to use the full capabilities of
  5646.       the 8086 family of microprocessors. The linker places all this extra
  5647.       information in a header at the start of the .EXE file. Although the
  5648.       .EXE file structure could easily accommodate a header as small as 32
  5649.       bytes, the linker never creates a header smaller than 512 bytes. (This
  5650.       minimum header size corresponds to the standard record size preferred
  5651.       by MS-DOS.) The .EXE file header contains the following information,
  5652.       which MS-DOS reads into a temporary work area in memory for use while
  5653.       loading the .EXE program:
  5654.  
  5655.       00-01H (.EXE Signature) MS-DOS does not rely on the extension (.EXE or
  5656.       .COM) to determine whether a file contains a .COM or a .EXE program.
  5657.       Instead, MS-DOS recognizes the file as a .EXE program if the first 2
  5658.       bytes in the header contain the signature 4DH 5AH (ASCII characters M
  5659.       and Z). If either or both of the signature bytes contain other values,
  5660.       MS-DOS assumes the file contains a .COM program, regardless of the
  5661.       extension. The reverse is not necessarily true--that is, MS-DOS does
  5662.       not accept the file as a .EXE program simply because the file begins
  5663.       with a .EXE signature. The file must also pass several other tests.
  5664.  
  5665.       02-03H (Last Page Size) The word at this location indicates the actual
  5666.       number of bytes in the final 512-byte page of the file. This word
  5667.       combines with the following word to determine the actual size of the
  5668.       file.
  5669.  
  5670.       04-05H (File Pages) This word contains a count of the total number of
  5671.       512-byte pages required to hold the file. If the file contains 1024
  5672.       bytes, this word contains the value 0002H; if the file contains 1025
  5673.       bytes, this word contains the value 0003H. The previous word (Last
  5674.       Page Size, 02-03H) is used to determine the number of valid bytes in
  5675.       the final 512-byte page. Thus, if the file contains 1024 bytes, the
  5676.       Last Page Size word contains 0000H because no bytes overflow into a
  5677.       final partly used page; if the file contains 1025 bytes, the Last Page
  5678.       Size word contains 0001H because the final page contains only a single
  5679.       valid byte (the 1025th byte).
  5680.  
  5681.       06-07H (Relocation Items) This word gives the number of entries that
  5682.       exist in the relocation pointer table. See Relocation Pointer Table,
  5683.       below.
  5684.  
  5685.       08-09H (Header Paragraphs) This word gives the size of the .EXE file
  5686.       header in 16-byte paragraphs. It indicates the offset of the program's
  5687.       compiled/assembled and linked image (the load module) within the .EXE
  5688.       file. Subtracting this word from the two file-size words starting at
  5689.       02H and 04H reveals the size of the program's image. The header always
  5690.       spans an even multiple of 16-byte paragraphs. For example, if the file
  5691.       consists of a 512-byte header and a 513-byte program image, then the
  5692.       file's total size is 1025 bytes. As discussed before, the Last Page
  5693.       Size word (02-03H) will contain 0001H and the File Pages word (04-05H)
  5694.       will contain 0003H. Because the header is 512 bytes, the Header
  5695.       Paragraphs word (08-09H) will contain 32 (0020H). (That is, 32
  5696.       paragraphs times 16 bytes per paragraph totals 512 bytes.) By
  5697.       subtracting the 512 bytes of the header from the 1025-byte total file
  5698.       size, the size of the program's image can be determined--in this case,
  5699.       513 bytes.
  5700.  
  5701.       0A-0BH (MINALLOC) This word indicates the minimum number of 16-byte
  5702.       paragraphs the program requires to begin execution in addition to the
  5703.       memory required to hold the program's image. MINALLOC normally
  5704.       represents the total size of any uninitialized data and/or stack
  5705.       segments linked at the end of the program. LINK excludes the space
  5706.       reserved by these fields from the end of the .EXE file to avoid
  5707.       wasting disk space. If not enough memory remains to satisfy MINALLOC
  5708.       when loading the program, MSDOS returns an error to the process trying
  5709.       to load the program. If the process is COMMAND.COM, COMMAND.COM then
  5710.       displays a Program too big to fit in memory error message. The EXEMOD
  5711.       utility can alter this field if desired. See Modifying the .EXE File
  5712.       Header, below.
  5713.  
  5714.       0C-0DH (MAXALLOC) This word indicates the maximum number of 16-byte
  5715.       paragraphs the program would like allocated to it before it begins
  5716.       execution. MAXALLOC indicates additional memory desired beyond that
  5717.       required to hold the program's image. MS-DOS uses this value to
  5718.       allocate MAXALLOC extra paragraphs, if available. If MAXALLOC
  5719.       paragraphs are not available, the program receives the largest memory
  5720.       block available--at least MINALLOC additional paragraphs. The
  5721.       programmer could use the MAXALLOC field to request that MS-DOS
  5722.       allocate space for use as a print buffer or as a program-maintained
  5723.       heap, for example.
  5724.  
  5725.       Unless otherwise specified with the /CPARMAXALLOC switch at link time,
  5726.       the linker sets MAXALLOC to FFFFH. This causes MS-DOS to allocate all
  5727.       of the largest block of memory it has available to the program. To
  5728.       make the program compatible with multitasking supervisor programs, the
  5729.       programmer should use /CPARMAXALLOC to set the true maximum number of
  5730.       extra paragraphs the program desires. The EXEMOD utility can also be
  5731.       used to alter this field.
  5732.  
  5733.       Note: If both MINALLOC and MAXALLOC have been set to 0000H, MS-DOS
  5734.       loads the program as high in memory as possible. LINK sets these
  5735.       fields to 0000H if the /HIGH switch was used; the EXEMOD utility can
  5736.       also be used to modify these fields.
  5737.  
  5738.       0E-0FH (Initial SS Value) This word contains the paragraph address of
  5739.       the stack segment relative to the start of the load module. At load
  5740.       time, MS-DOS relocates this value by adding the program's start
  5741.       segment address to it, and the resulting value is placed in the SS
  5742.       register before giving the program control. (The start segment
  5743.       corresponds to the first segment boundary in memory following the
  5744.       PSP.)
  5745.  
  5746.       10-11H (Initial SP Value) This word contains the absolute value that
  5747.       MS-DOS loads into the SP register before giving the program control.
  5748.       Because MS-DOS always loads programs starting on a segment address
  5749.       boundary, and because the linker knows the size of the stack segment,
  5750.       the linker is able to determine the correct SP offset at link time;
  5751.       therefore, MS-DOS does not need to adjust this value at load time. The
  5752.       EXEMOD utility can be used to alter this field.
  5753.  
  5754.       12-13H (Complemented Checksum) This word contains the one's complement
  5755.       of the summation of all words in the .EXE file. Current versions of
  5756.       MS-DOS basically ignore this word when they load a .EXE program;
  5757.       however, future versions might not. When LINK generates a .EXE file,
  5758.       it adds together all the contents of the .EXE file (including the .EXE
  5759.       header) by treating the entire file as a long sequence of 16-bit
  5760.       words. During this addition, LINK gives the Complemented Checksum word
  5761.       (12-13H) a temporary value of 0000H. If the file consists of an odd
  5762.       number of bytes, then the final byte is treated as a word with a high
  5763.       byte of 00H. Once LINK has totaled all words in the .EXE file, it
  5764.       performs a one's complement operation on the total and records the
  5765.       answer in the .EXE file header at offsets 12-13H. The validity of a
  5766.       .EXE file can then be checked by performing the same word-totaling
  5767.       process as LINK performed. The total should be FFFFH, because the
  5768.       total will include LINK's calculated complemented checksum, which is
  5769.       designed to give the file the FFFFH total.
  5770.  
  5771.       An example 7-byte .EXE file illustrates how .EXE file checksums are
  5772.       calculated. (This is a totally fictitious file, because .EXE headers
  5773.       are never smaller than 512 bytes.) If this fictitious file contained
  5774.       the bytes 8CH C8H 8EH D8H BAH 10H B4H, then the file's total would be
  5775.       calculated using C88CH+D88EH+10BAH+00B4H=1B288H. (Overflow past 16
  5776.       bits is ignored, so the value is interpreted as B288H.) If this were a
  5777.       valid .EXE file, then the B288H total would have been FFFFH instead.
  5778.  
  5779.       14-15H (Initial IP Value) This word contains the absolute value that
  5780.       MS-DOS loads into the IP register in order to transfer control to the
  5781.       program. Because MS-DOS always loads programs starting on a segment
  5782.       address boundary, the linker can calculate the correct IP offset from
  5783.       the initial CS register value at link time; therefore, MS-DOS does not
  5784.       need to adjust this value at load time.
  5785.  
  5786.       16-17H (Pre-Relocated Initial CS Value) This word contains the initial
  5787.       value, relative to the start of the load module, that MS-DOS places in
  5788.       the CS register to give the .EXE program control. MS-DOS adjusts this
  5789.       value in the same manner as the initial SS value before loading it
  5790.       into the CS register.
  5791.  
  5792.       18-19H (Relocation Table Offset) This word gives the offset from the
  5793.       start of the file to the relocation pointer table. This word must be
  5794.       used to locate the relocation pointer table, because variable-length
  5795.       information pertaining to program overlays can occur before the table,
  5796.       thus causing the position of the table to vary.
  5797.  
  5798.       1A-1BH (Overlay Number) This word is normally set to 0000H, indicating
  5799.       that the .EXE file consists of the resident, or primary, part of the
  5800.       program. This number changes only in files containing programs that
  5801.       use overlays, which are sections of a program that remain on disk
  5802.       until the program actually requires them. These program sections are
  5803.       loaded into memory by special overlay managing routines included in
  5804.       the run-time libraries supplied with some Microsoft high-level-
  5805.       language compilers.
  5806.  
  5807.       The preceding section of the header (00-1BH) is known as the formatted
  5808.       area. Optional information used by high-level-language overlay
  5809.       managers can follow this formatted area. Unless the program in the
  5810.       .EXE file incorporates such information, the relocation pointer table
  5811.       immediately follows the formatted header area.
  5812.  
  5813.       Relocation Pointer Table The relocation pointer table consists of a
  5814.       list of pointers to words within the .EXE program image that MS-DOS
  5815.       must adjust before giving the program control. These words consist of
  5816.       references made by the program to the segments that make up the
  5817.       program. MS-DOS must adjust these segment address references when it
  5818.       loads the program, because it can load the program into memory
  5819.       starting at any segment address boundary.
  5820.  
  5821.       Each pointer in the table consists of a doubleword. The first word
  5822.       contains an offset from the segment address given in the second word,
  5823.       which in turn indicates a segment address relative to the start of the
  5824.       load module. Together, these two words point to a third word within
  5825.       the load module that must have the start segment address added to it.
  5826.       (The start segment corresponds to the segment address at which MS-DOS
  5827.       started loading the program's image, immediately following the PSP.)
  5828.       Figure 4-6 shows the entire procedure MS-DOS performs for each
  5829.       relocation table entry.
  5830.  
  5831.  
  5832.          .EXE File
  5833.  ┌────────────────────┐ End of file
  5834.  │                    │
  5835.  │                    │
  5836.  │                    │
  5837.  │┌──────────────────┐│
  5838.  ││Rel Seg Ref=003CH ││
  5839.  ││Abs Seg Ref=25D1H ││
  5840.  │└──────────────────┘│
  5841.  │    Load module     │
  5842.  ├────────────────────┤
  5843.  └────────┐           │                                      Memory
  5844.  ┌───────┐└────────┐  │                             ┌──────────────────────┐
  5845.  │       └────────┐└──┘                             │                      │
  5846.  │                └───┐                    003CH──┐│                      │
  5847.  │┌──────────────────┐│                ┌─+2595H   ││ ┌─────────────────┐  │
  5848.  ││Relocation pointer││                │   ─────   └┼─┤Rel Seg Ref=003CH│  │
  5849.  ││   0002H:0005H ───┼┼─┐              │   25D1H────┼─Abs Seg Ref=25D1H│  │
  5850.  │└──────────────────┘│ │              │┌───────────┼│                 │  │
  5851.  │ Relocation pointer │ │              ││           │ └─────────────────┘  │
  5852.  │      table         │ └─ 0002H:0005H││           │                      │
  5853.  ├────────────────────┤    +2595H ────┴┼"Start seg"│    Load module       │
  5854.  │  Formatted header  │     ─────────── │   2595H  ├──────────────────────┤
  5855.  │       area         │     2597H:0005H─┘           │Program segment prefix│
  5856.  └────────────────────┘Start of file                └──────────────────────┘
  5857.  
  5858.       Figure 4-6. The .EXE file relocation procedure.
  5859.  
  5860.  
  5861.  The load module
  5862.       The load module starts where the .EXE header ends and consists of the
  5863.       fully linked image of the program. The load module appears within the
  5864.       .EXE file exactly as it would appear in memory if MS-DOS were to load
  5865.       it at segment address 0000H. The only changes MS-DOS makes to the load
  5866.       module involve relocating any direct segment references.
  5867.  
  5868.       Although the .EXE file contains distinct segment images within the
  5869.       load module, it provides no information for separating those
  5870.       individual segments from one another. Existing versions of MS-DOS
  5871.       ignore how the program is segmented; they simply copy the load module
  5872.       into memory, relocate any direct segment references, and give the
  5873.       program control.
  5874.  
  5875.  Loading the .EXE program
  5876.  
  5877.       So far we've covered all the characteristics of the .EXE program as
  5878.       it resides in memory and on disk. We've also touched on all the steps
  5879.       MS-DOS performs while loading the .EXE program from disk and executing
  5880.       it. The following list recaps the .EXE program loading process in the
  5881.       order in which MS-DOS performs it:
  5882.  
  5883.        1. MS-DOS reads the formatted area of the header (the first
  5884.           1BH bytes) from the .EXE file into a work area.
  5885.  
  5886.        2. MS-DOS determines the size of the largest available block of
  5887.           memory.
  5888.  
  5889.        3. MS-DOS determines the size of the load module using the Last Page
  5890.           Size (offset 02H), File Pages (offset 04H), and Header Paragraphs
  5891.           (offset 08H) fields from the header. An example of this process
  5892.           is in the discussion of the Header Paragraphs field.
  5893.  
  5894.        4. MS-DOS adds the MINALLOC field (offset 0AH) in the header to the
  5895.           calculated load-module size and the size of the PSP (100H bytes).
  5896.           If this total exceeds the size of the largest available block,
  5897.           MS-DOS terminates the load process and returns an error to the
  5898.           calling process. If the calling process was COMMAND.COM,
  5899.           COMMAND.COM then displays a Program too big to fit in memory
  5900.           error message.
  5901.  
  5902.        5. MS-DOS adds the MAXALLOC field (offset 0CH) in the header to the
  5903.           calculated load-module size and the size of the PSP. If the memory
  5904.           block found earlier exceeds this calculated total, MS-DOS allo-
  5905.           cates the calculated memory size to the program from the memory
  5906.           block; if the calculated total exceeds the block's size, MS-DOS
  5907.           allocates the entire block.
  5908.  
  5909.        6. If the MINALLOC and MAXALLOC fields both contain 0000H, MS-DOS
  5910.           uses the calculated load-module size to determine a start segment.
  5911.           MS-DOS calculates the start segment so that the load module will
  5912.           load into the high end of the allocated block. If either MINALLOC
  5913.           or MAXALLOC contains nonzero values (the normal case), MS-DOS
  5914.           establishes the start segment as the segment following the PSP.
  5915.  
  5916.        7. MS-DOS loads the load module into memory starting at the start
  5917.           segment.
  5918.  
  5919.        8. MS-DOS reads the relocation pointers into a work area and re-
  5920.           locates the load module's direct segment references, as shown in
  5921.           Figure 4-6.
  5922.  
  5923.        9. MS-DOS builds a PSP in the first 100H bytes of the allocated
  5924.           memory block. While building the two FCBs within the PSP, MS-DOS
  5925.           determines the initial values for the AL and AH registers.
  5926.  
  5927.       10. MS-DOS sets the SS and SP registers to the values in the header
  5928.           after the start segment is added to the SS value.
  5929.  
  5930.       11. MS-DOS sets the DS and ES registers to point to the beginning of
  5931.           the PSP.
  5932.  
  5933.       12. MS-DOS transfers control to the .EXE program by setting CS and IP
  5934.           to the values in the header after adding the start segment to the
  5935.           CS value.
  5936.  
  5937.  Controlling the .EXE program's structure
  5938.  
  5939.       We've now covered almost every aspect of a completed .EXE program.
  5940.       Next, we'll discuss how to control the structure of the final .EXE
  5941.       program from the source level. We'll start by covering the statements
  5942.       provided by MASM that permit the programmer to define the structure of
  5943.       the program when programming in assembly language. Then we'll cover
  5944.       the five standard memory models provided by Microsoft's C and FORTRAN
  5945.       compilers (both version 4.0), which provide predefined structuring
  5946.       over which the programmer has limited control.
  5947.  
  5948.  The MASM SEGMENT directive
  5949.       MASM's SEGMENT directive and its associated ENDS directive mark the
  5950.       beginning and end of a program segment. Program segments contain
  5951.       collections of code or data that have offset addresses relative to the
  5952.       same common segment address.
  5953.  
  5954.       In addition to the required segment name, the SEGMENT directive has
  5955.       three optional parameters:
  5956.  
  5957.       segname SEGMENT [align] [combine] ['class']
  5958.  
  5959.       With MASM, the contents of a segment can be defined at one point in
  5960.       the source file and the definition can be resumed as many times as
  5961.       necessary throughout the remainder of the file. When MASM encounters a
  5962.       SEGMENT directive with a segname it has previously encountered, it
  5963.       simply resumes the segment definition where it left off. This occurs
  5964.       regardless of the combine type specified in the SEGMENT directive--the
  5965.       combine type influences only the actions of the linker. See The
  5966.       combine Type Parameter, below.
  5967.  
  5968.       The align type parameter
  5969.       The optional align parameter lets the programmer send the linker an
  5970.       instruction on how to align a segment within memory. In reality, the
  5971.       linker can align the segment only in relation to the start of the
  5972.       program's load module, but the result remains the same because MS-DOS
  5973.       always loads the module aligned on a paragraph (16-byte) boundary.
  5974.       (The PAGE align type creates a special exception, as discussed below.)
  5975.  
  5976.       The following alignment types are permitted:
  5977.  
  5978.       BYTE This align type instructs the linker to start the segment on the
  5979.       byte immediately following the previous segment. BYTE alignment
  5980.       prevents any wasted memory between the previous segment and the BYTE-
  5981.       aligned segment.
  5982.  
  5983.       A minor disadvantage to BYTE alignment is that the 8086-family segment
  5984.       registers might not be able to directly address the start of the
  5985.       segment in all cases. Because they can address only on paragraph
  5986.       boundaries, the segment registers may have to point as many as 15
  5987.       bytes behind the start of the segment. This means that the segment
  5988.       size should not be more than 15 bytes short of 64 KB. The linker
  5989.       adjusts offset and segment address references to compensate for
  5990.       differences between the physical segment start and the paragraph
  5991.       addressing boundary.
  5992.  
  5993.       Another possible concern is execution speed on true 16-bit 8086-family
  5994.       microprocessors. When using non-8088 microprocessors, a program can
  5995.       actually run faster if the instructions and word data fields within
  5996.       segments are aligned on word boundaries. This permits the 16-bit
  5997.       processors to fetch full words in a single memory read, rather than
  5998.       having to perform two single-byte reads. The EVEN directive tells MASM
  5999.       to align instructions and data fields on word boundaries; however,
  6000.       MASM can establish this alignment only in relation to the start of the
  6001.       segment, so the entire segment must start aligned on a word or larger
  6002.       boundary to guarantee alignment of the items within the segment.
  6003.  
  6004.       WORD This align type instructs the linker to start the segment on the
  6005.       next word boundary. Word boundaries occur every 2 bytes and consist of
  6006.       all even addresses (addresses in which the least significant bit
  6007.       contains a zero). WORD alignment permits alignment of data fields and
  6008.       instructions within the segment on word boundaries, as discussed for
  6009.       the BYTE alignment type. However, the linker may have to waste 1 byte
  6010.       of memory between the previous segment and the word-aligned segment in
  6011.       order to position the new segment on a word boundary.
  6012.  
  6013.       Another minor disadvantage to WORD alignment is that the 8086-family
  6014.       segment registers might not be able to directly address the start of
  6015.       the segment in all cases. Because they can address only on paragraph
  6016.       boundaries, the segment registers may have to point as many as 14
  6017.       bytes behind the start of the segment. This means that the segment
  6018.       size should not be more than 14 bytes short of 64 KB. The linker
  6019.       adjusts offset and segment address references to compensate for
  6020.       differences between the physical segment start and the paragraph
  6021.       addressing boundary.
  6022.  
  6023.       PARA This align type instructs the linker to start the segment on the
  6024.       next paragraph boundary. The segments default to PARA if no alignment
  6025.       type is specified. Paragraph boundaries occur every 16 bytes and
  6026.       consist of all addresses with hexadecimal values ending in zero
  6027.       (0000H, 0010H, 0020H, and so forth). Paragraph alignment ensures that
  6028.       the segment begins on a segment register addressing boundary, thus
  6029.       making it possible to address a full 64 KB segment. Also, because
  6030.       paragraph addresses are even addresses, PARA alignment has the same
  6031.       advantages as WORD alignment. The only real disadvantage to PARA
  6032.       alignment is that the linker may have to waste as many as 15 bytes of
  6033.       memory between the previous segment and the paragraph-aligned segment.
  6034.  
  6035.       PAGE This align type instructs the linker to start the segment on the
  6036.       next page boundary. Page boundaries occur every 256 bytes and consist
  6037.       of all addresses in which the low address byte equals zero (0000H,
  6038.       0100H, 0200H, and so forth). PAGE alignment ensures only that the
  6039.       linker positions the segment on a page boundary relative to the start
  6040.       of the load module. Unfortunately, this does not also ensure alignment
  6041.       of the segment on an absolute page within memory, because MS-DOS only
  6042.       guarantees alignment of the entire load module on a paragraph
  6043.       boundary.
  6044.  
  6045.       When a programmer declares pieces of a segment with the same name in
  6046.       different source modules, the align type specified for each segment
  6047.       piece influences the alignment of that specific piece of the segment.
  6048.       For example, assume the following two segment declarations appear in
  6049.       different source modules:
  6050.  
  6051.       _DATA   SEGMENT PARA PUBLIC 'DATA'
  6052.               DB      '123'
  6053.       _DATA   ENDS
  6054.  
  6055.       _DATA   SEGMENT PARA PUBLIC 'DATA'
  6056.               DB      '456'
  6057.       _DATA   ENDS
  6058.  
  6059.       The linker starts by aligning the first segment piece located in the
  6060.       first object module on a paragraph boundary, as requested. When the
  6061.       linker encounters the second segment piece in the second object
  6062.       module, it aligns that piece on the first paragraph boundary following
  6063.       the first segment piece. This results in a 13-byte gap between the
  6064.       first segment piece and the second. The segment pieces must exist in
  6065.       separate source modules for this to occur. If the segment pieces exist
  6066.       in the same source module, MASM assumes that the second segment
  6067.       declaration is simply a resumption of the first and creates an object
  6068.       module with segment declarations equivalent to the following:
  6069.  
  6070.       _DATA   SEGMENT PARA PUBLIC 'DATA'
  6071.               DB      '123'
  6072.               DB      '456'
  6073.       _DATA   ENDS
  6074.  
  6075.       The combine type parameter
  6076.       The optional combine parameter allows the programmer to send
  6077.       directions to the linker on how to combine segments with the same
  6078.       segname occurring in different object modules. If no combine type is
  6079.       specified, the linker treats such segments as if each had a different
  6080.       segname. The combine type has no effect on the relationship of
  6081.       segments with different segnames. MASM and LINK both support the
  6082.       following combine types:
  6083.  
  6084.       PUBLIC This combine type instructs the linker to concatenate multiple
  6085.       segments having the same segname into a single contiguous segment. The
  6086.       linker adjusts any address references to labels within the
  6087.       concatenated segments to reflect the new position of those labels
  6088.       relative to the start of the combined segment. This combine type is
  6089.       useful for accessing code or data in different source modules using a
  6090.       common segment register value.
  6091.  
  6092.       STACK This combine type operates similarly to the PUBLIC combine type,
  6093.       except for two additional effects: The STACK type tells the linker
  6094.       that this segment comprises part of the program's stack and
  6095.       initialization data contained within STACK segments is handled
  6096.       differently than in PUBLIC segments. Declaring segments with the STACK
  6097.       combine type permits the linker to determine the initial SS and SP
  6098.       register values it places in the .EXE file header. Normally, a
  6099.       programmer would declare only one STACK segment in one of the source
  6100.       modules. If pieces of the stack are declared in different source
  6101.       modules, the linker will concatenate them in the same fashion as
  6102.       PUBLIC segments. However, initialization data declared within any
  6103.       STACK segment is placed at the high end of the combined STACK segments
  6104.       on a module-by-module basis. Thus, each successive module's
  6105.       initialization data overlays the previous module's data. At least one
  6106.       segment must be declared with the STACK combine type; otherwise, the
  6107.       linker will issue a warning message because it cannot determine the
  6108.       program's initial SS and SP values. (The warning can be ignored if the
  6109.       program itself initializes SS and SP.)
  6110.  
  6111.       COMMON This combine type instructs the linker to overlap multiple
  6112.       segments having the same segname. The length of the resulting segment
  6113.       reflects the length of the longest segment declared. If any code or
  6114.       data is declared in the overlapping segments, the data contained in
  6115.       the final segments linked replaces any data in previously loaded
  6116.       segments. This combine type is useful when a data area is to be shared
  6117.       by code in different source modules.
  6118.  
  6119.       MEMORY Microsoft's LINK treats this combine type the same as it treats
  6120.       the PUBLIC type. MASM, however, supports the MEMORY type for
  6121.       compatibility with other linkers that use Intel's definition of a
  6122.       MEMORY combine type.
  6123.  
  6124.       AT address This combine type instructs LINK to pretend that the
  6125.       segment will reside at the absolute segment address. LINK then adjusts
  6126.       all address references to the segment in accordance with the
  6127.       masquerade. LINK will not create an image of the segment in the load
  6128.       module, and it will ignore any data defined within the segment. This
  6129.       behavior is consistent with the fact that MS-DOS does not support the
  6130.       loading of program segments into absolute memory segments. All pro-
  6131.       grams must be able to execute from any segment address at which MS-DOS
  6132.       can find available memory. The SEGMENT AT address combine type is
  6133.       useful for creating templates of various areas in memory outside the
  6134.       program. For instance, SEGMENT AT 0000H could be used to create a
  6135.       template of the 8086-family interrupt vectors. Because data contained
  6136.       within SEGMENT AT address segments is suppressed by LINK and not by
  6137.       MASM (which places the data in the object module), it is possible to
  6138.       use .OBJ files generated by MASM with another linker that supports ROM
  6139.       or other absolute code generation should the programmer require this
  6140.       specialized capability.
  6141.  
  6142.       The class type parameter
  6143.       The class parameter provides the means to organize different segments
  6144.       into classifications. For instance, here are three source modules,
  6145.       each with its own separate code and data segments:
  6146.  
  6147.       ;Module "A"
  6148.       A_DATA  SEGMENT PARA PUBLIC 'DATA'
  6149.       ;Module "A" data fields
  6150.       A_DATA  ENDS
  6151.       A_CODE  SEGMENT PARA PUBLIC 'CODE'
  6152.       ;Module "A" code
  6153.       A_CODE  ENDS
  6154.               END
  6155.  
  6156.       ;Module "B"
  6157.       B_DATA  SEGMENT PARA PUBLIC 'DATA'
  6158.       ;Module "B" data fields
  6159.       B_DATA  ENDS
  6160.       B_CODE  SEGMENT PARA PUBLIC 'CODE'
  6161.       ;Module "B" code
  6162.       B_CODE  ENDS
  6163.               END
  6164.  
  6165.       ;Module "C"
  6166.       C_DATA  SEGMENT PARA PUBLIC 'DATA'
  6167.       ;Module "C" data fields
  6168.       C_DATA  ENDS
  6169.       C_CODE  SEGMENT PARA PUBLIC 'CODE'
  6170.       ;Module "C" code
  6171.       C_CODE  ENDS
  6172.               END
  6173.  
  6174.       If the 'CODE' and 'DATA' class types are removed from the SEGMENT
  6175.       directives shown above, the linker organizes the segments as it en-
  6176.       counters them. If the programmer specifies the modules to the linker
  6177.       in alphabetic order, the linker produces the following segment
  6178.       ordering:
  6179.  
  6180.               A_DATA
  6181.               A_CODE
  6182.               B_DATA
  6183.               B_CODE
  6184.               C_DATA
  6185.               C_CODE
  6186.  
  6187.       However, if the programmer specifies the class types shown in the
  6188.       sample source modules, the linker organizes the segments by
  6189.       classification as follows:
  6190.  
  6191.               'DATA' class:    A_DATA
  6192.                                B_DATA
  6193.                                C_DATA
  6194.  
  6195.               'CODE' class:    A_CODE
  6196.                                B_CODE
  6197.                                C_CODE
  6198.  
  6199.       Notice that the linker still organizes the classifications in the
  6200.       order in which it encounters the segments belonging to the various
  6201.       classifications. To completely control the order in which the linker
  6202.       organizes the segments, the programmer must use one of three basic
  6203.       approaches. The preferred method involves using the /DOSSEG switch
  6204.       with the linker. This produces the segment ordering shown in Figure
  6205.       4-1. The second method involves creating a special source module that
  6206.       contains empty SEGMENT-ENDS blocks for all the segments declared in
  6207.       the various other source modules. The programmer creates the list in
  6208.       the order the segments are to be arranged in memory and then specifies
  6209.       the .OBJ file for this module as the first file for the linker to
  6210.       process. This procedure establishes the order of all the segments
  6211.       before LINK begins processing the other program modules, so the
  6212.       programmer can declare segments in these other modules in any con-
  6213.       venient order. For instance, the following source module rearranges
  6214.       the result of the previous example so that the linker places the
  6215.       'CODE' class before the 'DATA' class:
  6216.  
  6217.       A_CODE  SEGMENT PARA PUBLIC 'CODE'
  6218.       A_CODE  ENDS
  6219.       B_CODE  SEGMENT PARA PUBLIC 'CODE'
  6220.       B_CODE  ENDS
  6221.       C_CODE  SEGMENT PARA PUBLIC 'CODE'
  6222.       C_CODE  ENDS
  6223.  
  6224.       A_DATA  SEGMENT PARA PUBLIC 'DATA'
  6225.       A_DATA  ENDS
  6226.       B_DATA  SEGMENT PARA PUBLIC 'DATA'
  6227.       B_DATA  ENDS
  6228.       C_DATA  SEGMENT PARA PUBLIC 'DATA'
  6229.       C_DATA  ENDS
  6230.  
  6231.               END
  6232.  
  6233.       Rather than creating a new module, the third method places the same
  6234.       segment ordering list shown above at the start of the first module
  6235.       containing actual code or data that the programmer will be specifying
  6236.       for the linker. This duplicates the approach used by Microsoft's newer
  6237.       compilers, such as C version 4.0.
  6238.  
  6239.       The ordering of segments within the load module has no direct effect
  6240.       on the linker's adjustment of address references to locations within
  6241.       the various segments. Only the GROUP directive and the SEGMENT
  6242.       directive's combine parameter affect address adjustments performed by
  6243.       the linker. See The MASM GROUP Directive, below.
  6244.  
  6245.       Note: Certain older versions of the IBM Macro Assembler wrote segments
  6246.       to the object file in alphabetic order regardless of their order in
  6247.       the source file. These older versions can limit efforts to control
  6248.       segment ordering. Upgrading to a new version of the assembler is the
  6249.       best solution to this problem.
  6250.  
  6251.       Ordering segments to shrink the .EXE file
  6252.       Correct segment ordering can significantly decrease the size of a .EXE
  6253.       program as it resides on disk. This size-reduction ordering is
  6254.       achieved by placing all uninitialized data fields in their own
  6255.       segments and then controlling the linker's ordering of the program's
  6256.       segments so that the uninitialized data field segments all reside at
  6257.       the end of the program. When the program modules are assembled, MASM
  6258.       places information in the object modules to tell the linker about
  6259.       initialized and uninitialized areas of all segments. The linker then
  6260.       uses this information to prevent the writing of uninitialized data
  6261.       areas that occur at the end of the program image as part of the
  6262.       resulting .EXE file. To account for the memory space required by these
  6263.       fields, the linker also sets the MINALLOC field in the .EXE file
  6264.       header to represent the data area not written to the file. MS-DOS then
  6265.       uses the MINALLOC field to reallocate this missing space when loading
  6266.       the program.
  6267.  
  6268.  The MASM GROUP directive
  6269.       The MASM GROUP directive can also have a strong impact on a .EXE
  6270.       program. However, the GROUP directive has no effect on the arrangement
  6271.       of program segments within memory. Rather, GROUP associates program
  6272.       segments for addressing purposes.
  6273.  
  6274.       The GROUP directive has the following syntax:
  6275.  
  6276.       grpname GROUP segname,segname,segname,...
  6277.  
  6278.       This directive causes the linker to adjust all address references to
  6279.       labels within any specified segname to be relative to the start of the
  6280.       declared group. The start of the group is determined at link time. The
  6281.       group starts with whichever of the segments in the GROUP list the
  6282.       linker places lowest in memory.
  6283.  
  6284.       That the GROUP directive neither causes nor requires contiguous
  6285.       arrangement of the grouped segments creates some interesting, although
  6286.       not necessarily desirable, possibilities. For instance, it permits the
  6287.       programmer to locate segments not belonging to the declared group
  6288.       between segments that do belong to the group. The only restriction
  6289.       imposed on the declared group is that the last byte of the last
  6290.       segment in the group must occur within 64 KB of the start of the
  6291.       group. Figure 4-7 illustrates this type of segment arrangement:
  6292.  
  6293.  
  6294.       ────────────────────────────────── ┌─────────────────────────────────┐
  6295.                                         │                                 │
  6296.       │                                  │            SEGMENT_C            │
  6297.       │                                  │  (listed with GROUP directive)  │
  6298.       │          ───────────────LABEL_C │                                 │
  6299.       │                                 ├─────────────────────────────────┤
  6300.       │          │         ─────LABEL_B │                                 │
  6301.     64 KB        │                      │            SEGMENT_B            │
  6302.    maximum       │       Offset to       │(not listed with GROUP directive)│
  6303.       │       Offset to     LABEL_B     │                                 │
  6304.       │       LABEL_C      ───────────── ├─────────────────────────────────┤
  6305.       │          │         ─────LABEL_A │                                 │
  6306.       │          │                      │            SEGMENT_A            │
  6307.       │          │       Offset to       │  (listed with GROUP directive)  │
  6308.                           LABEL_A     │                                 │
  6309.       ────────────────────────────────── └─────────────────────────────────┘
  6310.  
  6311.       Figure 4-7. Noncontiguous segments in the same GROUP.
  6312.  
  6313.  
  6314.       Warning: One of the most confusing aspects of the GROUP directive
  6315.       relates to MASM's OFFSET operator. The GROUP directive affects only
  6316.       the offset addresses generated by such direct addressing instructions
  6317.       as
  6318.  
  6319.               MOV     AX,FIELD_LABEL
  6320.  
  6321.       but it has no effect on immediate address values generated by such
  6322.       instructions as
  6323.  
  6324.               MOV     AX,OFFSET FIELD_LABEL
  6325.  
  6326.       Using the OFFSET operator on labels contained within grouped segments
  6327.       requires the following approach:
  6328.  
  6329.               MOV     AX,OFFSET GROUP_NAME:FIELD_LABEL
  6330.  
  6331.       The programmer must explicitly request the offset from the group base,
  6332.       because MASM defines the result of the OFFSET operator to be the
  6333.       offset of the label from the start of its segment, not its group.
  6334.  
  6335.  Structuring a small program with SEGMENT and GROUP
  6336.       Now that we have analyzed the functions performed by the SEGMENT and
  6337.       GROUP directives, we'll put both directives to work structuring a
  6338.       skeleton program. The program, shown in Figures 4-8, 4-9, and 4-10,
  6339.       consists of three source modules (MODULE_A, MODULE_B, and MODULE_C),
  6340.       each using the following four program segments:
  6341.  
  6342. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  6343.       Segment          Definition
  6344.       Segment          Definition
  6345.       ──────────────────────────────────────────────────────────────────
  6346.       _TEXT            The code or program text segment
  6347.  
  6348.       _DATA            The standard data segment containing preinitialized
  6349.                        data fields the program might change
  6350.  
  6351.       CONST            The constant data segment containing constant data
  6352.                        fields the program will not change
  6353.  
  6354.       _BSS             The "block storage segment/space" segment containing
  6355.                        uninitialized data fields1
  6356.  
  6357.       ──────────────────────────────────────────────────────────────────────
  6358.  
  6359.       Figure 4-8. Structuring a .EXE program: MODULE_A.
  6360.  
  6361.       ──────────────────────────────────────────────────────────────────────
  6362.  
  6363.       Figure 4-9. Structuring a .EXE program: MODULE_B.
  6364.  
  6365.       ──────────────────────────────────────────────────────────────────────
  6366.  
  6367.       Figure 4-10. Structuring a .EXE program: MODULE_C.
  6368.  
  6369.       ──────────────────────────────────────────────────────────────────────
  6370.  
  6371.  
  6372.       This example creates a small memory model program image, so the linked
  6373.       program can have only a single code segment and a single data
  6374.       segment--the simplest standard form of a .EXE program. See Using
  6375.       Microsoft's Contemporary Memory Models, below.
  6376.  
  6377.       In addition to declaring the four segments already discussed, MODULE_A
  6378.       declares a STACK segment in which to define a block of memory for use
  6379.       as the program's stack and also defines the linking order of the five
  6380.       segments. Defining the linking order leaves the programmer free to
  6381.       declare the segments in any order when defining the segment contents--
  6382.       a necessity because the assembler has difficulty assembling programs
  6383.       that use forward references.
  6384.  
  6385.       With Microsoft's MASM and LINK on the same disk with the .ASM files,
  6386.       the following commands can be made into a batch file:
  6387.  
  6388.       MASM STRUCA;
  6389.       MASM STRUCB;
  6390.       MASM STRUCC;
  6391.       LINK STRUCA+STRUCB+STRUCC/M;
  6392.  
  6393.       These commands will assemble and link all the .ASM files listed,
  6394.       producing the memory map report file STRUCA.MAP shown in Figure 4-11.
  6395.  
  6396.        Start  Stop   Length Name                   Class
  6397.        00000H 0000CH 0000DH _TEXT                  CODE
  6398.        0000EH 0001FH 00012H _DATA                  DATA
  6399.        00020H 0003DH 0001EH CONST                  CONST
  6400.        0003EH 0004EH 00011H _BSS                   BSS
  6401.        00050H 0014FH 00100H STACK                  STACK
  6402.  
  6403.        Origin   Group
  6404.        0000:0   DGROUP
  6405.  
  6406.         Address         Publics by Name
  6407.  
  6408.        0000:000B       PROC_B
  6409.        0000:000C       PROC_C
  6410.  
  6411.         Address         Publics by Value
  6412.  
  6413.        0000:000B       PROC_B
  6414.        0000:000C       PROC_C
  6415.       Program entry point at 0000:0000
  6416.  
  6417.       Figure 4-11. Structuring a .EXE program: memory map report.
  6418.  
  6419.  
  6420.       The above memory map report represents the memory diagram shown in
  6421.       Figure 4-12.
  6422.  
  6423.  
  6424.      Absolute address                                      Size in bytes
  6425.                00150H ┌────────┬──────────┬──────────┬──────      ─────
  6426.                        │        │  STACK   │  STACK   │  256         
  6427.                        │        │  Class   │   (A)    │              │
  6428.                00050H ├ ─ ─ ─ ─┼──────────┴──────────┼──────        │
  6429.                        │        │ PARA align gap      │   1          │
  6430.                0004FH ├ ─ ─ ─ ─┼──────────┬──────────┼───────────   │
  6431.                        │        │          │BSS (C)   │   5         │
  6432.                0004AH ├ ─ ─ ─ ─┼ ─ ─ ─ ─ ─┼──────────┼──────  │     │
  6433.                        │        │          │WORD      │        │     │
  6434.                        │        │          │align gap │        │     │
  6435.                00049H ├ ─ ─ ─ ─├  BSS  ─ ─┼──────────┤        │     │
  6436.                        │        │          │BSS (B)   │   5    15    │
  6437.                00044H ├ ─ ─ ─ ─├ Class ─ ─┼──────────┼──────  │     │
  6438.                        │        │          │WORD      │        │     │
  6439.                        │        │          │align gap │        │     │
  6440.                00043H ├ DGROUP─│ ─ ─ ─ ─ ─┼──────────┤        │    321
  6441.                        │        │          │BSS (A)   │   5         │
  6442.                0003EH ├ Group ─┼──────────┼──────────┼───────────   │
  6443.                        │        │          │CONST(C)  │  10         │
  6444.                00034H ├ ─ ─ ─ ─┼ CONST ─ ─┼──────────┼──────  │     │
  6445.                        │        │          │CONST(B)  │  10    30    │
  6446.                0002AH ├ ─ ─ ─ ─┼ Class ─ ─┼──────────┼──────  │     │
  6447.                        │        │          │CONST(A)  │  10         │
  6448.                00020H ├ ─ ─ ─ ─┼──────────┬──────────┬───────────   │
  6449.                        │        │          │DATA (C)  │    6        │
  6450.                0001AH ├ ─ ─ ─ ─┼─ DATA─ ─ ├──────────┼──────  │     │
  6451.                        │        │          │DATA (B)  │    6   18    │
  6452.                00014H ├ ─ ─ ─ ─┼─ Class ─ ├──────────┼──────  │     │
  6453.                        │        │          │DATA (A)  │    6        │
  6454.                0000EH ├ ─ ─ ─ ─┼──────────┴──────────┼───────────   │
  6455.                        │        │   WORD align gap    │    1         
  6456.                0000DH ├────────┼──────────┬──────────┼──────────── ─────
  6457.                        │        │          │TEXT (C)  │    1   
  6458.                0000CH │ ─ ─ ─CODE ─ ─ ─ ─ ├──────────┼──────  │
  6459.                        │                   │TEXT (B)  │    1   13
  6460.                0000BH │ ─ ─ ─Class─ ─ ─ ─ ├──────────┼──────  │
  6461.       DGROUP           │        │          │TEXT (A)  │   11   
  6462.   addressing  00000H └────────┴──────────┴──────────┴───────────
  6463.         base
  6464.  
  6465.       Figure 4-12. Structure of the sample .EXE program.
  6466.  
  6467.  
  6468.  Using Microsoft's contemporary memory models
  6469.  
  6470.       Now that we've analyzed the various aspects of designing assembly-
  6471.       language .EXE programs, we can look at how Microsoft's high-level-
  6472.       language compilers create .EXE programs from high-level-language
  6473.       source files. Even assembly-language programmers will find this
  6474.       discussion of interest and should seriously consider using the five
  6475.       standard memory models outlined here.
  6476.  
  6477.       This discussion is based on the Microsoft C Compiler version 4.0,
  6478.       which, along with the Microsoft FORTRAN Compiler version 4.0,
  6479.       incorporates the most contemporary code generator currently available.
  6480.       These newer compilers generate code based on three to five
  6481.       of the following standard programmer-selectable program structures,
  6482.       referred to as memory models. The discussion of each of these memory
  6483.       models will center on the model's use with the Microsoft C Compiler
  6484.       and will close with comments regarding any differences for the
  6485.       Microsoft FORTRAN Compiler.
  6486.  
  6487.       Small (C compiler switch /AS) This model, the default, includes only a
  6488.       single code segment and a single data segment. All code must fit
  6489.       within 64 KB, and all data must fit within an additional 64 KB. Most C
  6490.       program designs fall into this category. Data can exceed the 64 KB
  6491.       limit only if the far and huge attributes are used, forcing the
  6492.       compiler to use far addressing, and the linker to place far and huge
  6493.       data items into separate segments. The data-size-threshold switch
  6494.       described for the compact model is ignored by the Microsoft C Compiler
  6495.       when used with a small model. The C compiler uses the default segment
  6496.       name _TEXT for all code and the default segment name _DATA for all
  6497.       non-far/huge data. Microsoft FORTRAN programs can generate a semblance
  6498.       of this model only by using the /NM (name module) and /AM (medium
  6499.       model) compiler switches in combination with the near attribute on all
  6500.       subprogram declarations.
  6501.  
  6502.       Medium (C and FORTRAN compiler switch /AM) This model includes only a
  6503.       single data segment but breaks the code into multiple code segments.
  6504.       All data must fit within 64 KB, but the 64 KB restriction on code size
  6505.       applies only on a module-by-module basis. Data can exceed the 64 KB
  6506.       limit only if the far and huge attributes are used, forcing the
  6507.       compiler to use far addressing, and the linker to place far and huge
  6508.       data items into separate segments. The data-size-threshold switch
  6509.       described for the compact model is ignored by the Microsoft C Compiler
  6510.       when used with a medium model. The compiler uses the default segment
  6511.       name _DATA for all non-far/huge data and the template module_TEXT to
  6512.       create names for all code segments. The module element of module_TEXT
  6513.       indicates where the compiler is to substitute the name of the source
  6514.       module. For example, if the source module HELPFUNC.C is compiled using
  6515.       the medium model, the compiler creates the code segment HELPFUNC_TEXT.
  6516.       The Microsoft FORTRAN Compiler version 4.0 directly supports the
  6517.       medium model.
  6518.  
  6519.       Compact (C compiler switch /AC) This model includes only a single code
  6520.       segment but breaks the data into multiple data segments. All code must
  6521.       fit within 64 KB, but the data is allowed to consume all the remaining
  6522.       available memory. The Microsoft C Compiler's optional data-size-
  6523.       threshold switch (/Gt) controls the placement of the larger data items
  6524.       into additional data segments, leaving the smaller items in the
  6525.       default segment for faster access. Individual data items within the
  6526.       program cannot exceed 64 KB under the compact model without being
  6527.       explicitly declared huge. The compiler uses the default segment name
  6528.       _TEXT for all code segments and the template module#_DATA to create
  6529.       names for all data segments. The module element indicates where the
  6530.       compiler is to substitute the source module's name; the # element
  6531.       represents a digit that the compiler changes for each additional data
  6532.       segment required to hold the module's data. The compiler starts with
  6533.       the digit 5 and counts up. For example, if the name of the source
  6534.       module is HELPFUNC.C, the compiler names the first data segment
  6535.       HELPFUNC5_DATA. FORTRAN programs can generate a semblance of this
  6536.       model only by using the /NM (name module) and /AL (large model)
  6537.       compiler switches in combination with the near attribute on all
  6538.       subprogram declarations.
  6539.  
  6540.       Large (C and FORTRAN compiler switch /AL) This model creates multiple
  6541.       code and data segments. The compiler treats data in the same manner as
  6542.       it does for the compact model and treats code in the same manner as it
  6543.       does for the medium model. The Microsoft FORTRAN Compiler version 4.0
  6544.       directly supports the large model.
  6545.  
  6546.       Huge (C and FORTRAN compiler switch /AH) Allocation of segments under
  6547.       the huge model follows the same rules as for the large model. The
  6548.       difference is that individual data items can exceed 64 KB. Under the
  6549.       huge model, the compiler generates the necessary code to index arrays
  6550.       or adjust pointers across segment boundaries, effectively transforming
  6551.       the microprocessor's segment-addressed memory into linear-addressed
  6552.       memory. This makes the huge model especially useful for porting a
  6553.       program originally written for a processor that used linear
  6554.       addressing. The speed penalties the program pays in exchange for this
  6555.       addressing freedom require serious consideration. If the program
  6556.       actually contains any data structures exceeding 64 KB, it probably
  6557.       contains only a few. In that case, it is best to avoid using the huge
  6558.       model by explicitly declaring those few data items as huge using the
  6559.       huge keyword within the source module. This prevents penalizing all
  6560.       the non-huge items with extra addressing math. The Microsoft FORTRAN
  6561.       Compiler version 4.0 directly supports the huge model.
  6562.  
  6563.       Figure 4-13 shows an example of the segment arrangement created by a
  6564.       large/huge model program. The example assumes two source modules:
  6565.       MSCA.C and MSCB.C. Each source module specifies enough data to cause
  6566.       the compiler to create two extra data segments for that module. The
  6567.       diagram does not show all the various segments that occur as a result
  6568.       of linking with the run-time library or as a result of compiling with
  6569.       the intention of using the CodeView debugger.
  6570.  
  6571.  
  6572.     Groups     Classes     Segments
  6573.  ┌───────────┬───────────┬───────────┐
  6574.  │           │           │           │ SMCLH: Program stack
  6575.  │           │   STACK   │  STACK    │
  6576.  │           ├───────────┼───────────┤
  6577.  │           │           │           │ SM: All unitialized global
  6578.  │           │           │ c_common  │  items, CLH: Empty
  6579.  │  DGROUP   │    BSS    ├───────────┤
  6580.  │           │           │           │ SMCLH: All uninitialized non-
  6581.  │           │           │  _BSS     │  far/huge items
  6582.  │           ├───────────┼───────────┤
  6583.  │           │           │           │ SMCLH: Constants (floating point
  6584.  │           │   CONST   │  CONST    │  constraints, segment addresses, etc)
  6585.  │           ├───────────┼───────────┤
  6586.  │           │           │           │ SMCLH: All items that don't end up
  6587.  │           │    DATA   │  _DATA    │  anywhere else
  6588.  ├───────────┼───────────┼───────────┤
  6589.  │           │           │           │ SM: Nonexistent, CLH: All unini-
  6590.  │           │  FAR_BSS  │  FAR_BSS  │  tialized global items
  6591.  │           ├───────────┼───────────┤
  6592.  │           │           │           │ From MSCB only: SM Far/huge items,
  6593.  │           │           │MSCB6_DATA │  CLH: Items larger than threshold
  6594.  │           │           ├───────────┤
  6595.  │           │           │           │ From MSCB only: SM Far/huge items,
  6596.  │           │           │MSCB5_DATA │  CLH: Items larger than threshold
  6597.  │           │ FAR_DATA  ├───────────┤
  6598.  │           │           │           │ From MSCB only: SM Far/huge items,
  6599.  │           │           │MSCA6_DATA │  CLH: Items larger than threshold
  6600.  │           │           ├───────────┤
  6601.  │           │           │           │ From MSCB only: SM Far/huge items,
  6602.  │           │           │MSCA5_DATA │  CLH: Items larger than threshold
  6603.  │           ├───────────┼───────────┤
  6604.  │           │           │           │ SC: All code, MLH: Run-time
  6605.  │           │           │   TEXT    │  library code only
  6606.  │           │           ├───────────┤
  6607.  │           │   CODE    │           │ SC: Nonexistent, MLH: MSCB.C Code
  6608.  │           │           │ MSCB_TEXT │
  6609.  │           │           ├───────────┤
  6610.  │           │           │           │ SC: Nonexistent, MLH: MSCA.C Code
  6611.  │           │           │ MSCA_TEXT │
  6612.  └───────────┴───────────┴───────────┘        ───────────────────────
  6613.                                         S = Small model    L = Large model
  6614.                                         M = Medium model   H = Huge model
  6615.                                         C = Compact model
  6616.  
  6617.       Figure 4-13. General structure of a Microsoft C program.
  6618.  
  6619.  
  6620.       Note that if the program declares an extremely large number of small
  6621.       data items, it can exceed the 64 KB size limit on the default data
  6622.       segment (_DATA) regardless of the memory model specified. This occurs
  6623.       because the data items all fall below the data-size-threshold limit
  6624.       (compiler /Gt switch), causing the compiler to place them in the _DATA
  6625.       segment. Lowering the data size threshold or explicitly using the far
  6626.       attribute within the source modules eliminates this problem.
  6627.  
  6628.  Modifying the .EXE file header
  6629.  
  6630.       With most of its language compilers, Microsoft supplies a utility
  6631.       program called EXEMOD. See PROGRAMMING UTILITIES: EXEMOD. This utility
  6632.       allows the programmer to display and modify certain fields contained
  6633.       within the .EXE file header. Following are the header fields EXEMOD
  6634.       can modify (based on EXEMOD version 4.0):
  6635.  
  6636.       MAXALLOC This field can be modified by using EXEMOD's /MAX switch.
  6637.       Because EXEMOD operates on .EXE files that have already been linked,
  6638.       the /MAX switch can be used to modify the MAXALLOC field in existing
  6639.       .EXE programs that contain the default MAXALLOC value of FFFFH,
  6640.       provided the programs do not rely on MS-DOS's allocating all free
  6641.       memory to them. EXEMOD's /MAX switch functions in an identical manner
  6642.       to LINK's /CPARMAXALLOC switch.
  6643.  
  6644.       MINALLOC This field can be modified by using EXEMOD's /MIN switch.
  6645.       Unlike the case with the MAXALLOC field, most programs do not have an
  6646.       arbitrary value for MINALLOC. MINALLOC normally represents
  6647.       uninitialized memory and stack space the linker has compressed out of
  6648.       the .EXE file, so a programmer should never reduce the MINALLOC value
  6649.       within a .EXE program written by someone else. If a program requires
  6650.       some minimum amount of extra dynamic memory in addition to any static
  6651.       fields, MINALLOC can be increased to ensure that the program will have
  6652.       this extra memory before receiving control. If this is done, the
  6653.       program will not have to verify that MS-DOS allocated enough memory to
  6654.       meet program needs. Of course, the same result can be achieved without
  6655.       EXEMOD by declaring this minimum extra memory as an uninitialized
  6656.       field at the end of the program.
  6657.  
  6658.       Initial SP Value This field can be modified by using the /STACK switch
  6659.       to increase or decrease the size of a program's stack. However,
  6660.       modifying the initial SP value for programs developed using Microsoft
  6661.       language compiler versions earlier than the following may cause the
  6662.       programs to fail: C version 3.0, Pascal version 3.3, and FORTRAN
  6663.       version 3.3. Other language compilers may have the same restriction.
  6664.       The /STACK switch can also be used with programs developed using MASM,
  6665.       provided the stack space is linked at the end of the program, but it
  6666.       would probably be wise to change the size of the STACK segment
  6667.       declaration within the program instead. The linker also provides a
  6668.       /STACK switch that performs the same purpose.
  6669.  
  6670.       Note: With the /H switch set, EXEMOD displays the current values of
  6671.       the fields within the .EXE header. This switch should not be used with
  6672.       the other switches. EXEMOD also displays field values if no switches
  6673.       are used.
  6674.  
  6675.       Warning: EXEMOD also functions correctly when used with packed .EXE
  6676.       files created using EXEPACK or the /EXEPACK linker switch. However, it
  6677.       is important to use the EXEMOD version shipped with the linker or
  6678.       EXEPACK utility. Possible future changes in the packing method may
  6679.       result in incompatibilities between EXEMOD and nonassociated
  6680.       linker/EXEPACK versions.
  6681.  
  6682.  Patching the .EXE program using DEBUG
  6683.  
  6684.       Every experienced programmer knows that programs always seem to have
  6685.       at least one unspotted error. If a program has been distributed to
  6686.       other users, the programmer will probably need to provide those users
  6687.       with corrections when such bugs come to light. One inexpensive
  6688.       updating approach used by many large companies consists of mailing out
  6689.       single-page instructions explaining how the user can patch the program
  6690.       to correct the problem.
  6691.  
  6692.       Program patching usually involves loading the program file into the
  6693.       DEBUG utility supplied with MS-DOS, storing new bytes into the program
  6694.       image, and then saving the program file back to disk. Unfortunately,
  6695.       DEBUG cannot load a .EXE program into memory and then save it back to
  6696.       disk in .EXE format. The programmer must trick DEBUG into patching
  6697.       .EXE program files, using the procedure outlined below. See
  6698.       PROGRAMMING UTILITIES: DEBUG.
  6699.  
  6700.       Note: Users should be reminded to make backup copies of their program
  6701.       before attempting the patching procedure.
  6702.  
  6703.       1. Rename the .EXE file using a filename extension that does not have
  6704.          special meaning for DEBUG. (Avoid .EXE, .COM, and .HEX.) For
  6705.          instance, MYPROG.BIN serves well as a temporary new name for
  6706.          MYPROG.EXE because DEBUG does not recognize a file with a .BIN
  6707.          extension as anything special. DEBUG will load the entire image of
  6708.          MYPROG.BIN, including the .EXE header and relocation table, into
  6709.          memory starting at offset 100H within a .COM-style program segment
  6710.          (as discussed previously).
  6711.  
  6712.       2. Locate the area within the load module section of the .EXE file
  6713.          image that requires patching. The previous discussion of the .EXE
  6714.          file image, together with compiler/ assembler listings and linker
  6715.          memory map reports, provides the information necessary to locate
  6716.          the error within the .EXE file image. DEBUG loads the file image
  6717.          starting at offset 100H within a .COM-style program segment, so the
  6718.          programmer must compensate for this offset when calculating
  6719.          addresses within the file image. Also, the compiler listings and
  6720.          linker memory map reports provide addresses relative to the start
  6721.          of the program image within the .EXE file, not relative to the
  6722.          start of the file itself. Therefore, the programmer must first
  6723.          check the information contained in the .EXE file header to
  6724.          determine where the load module (the program's image) starts within
  6725.          the file.
  6726.  
  6727.       3. Use DEBUG's E (Enter Data) or A (Assemble Machine Instructions
  6728.          command to insert the corrections. (Normally, patch instructions to
  6729.          users would simply give an address at which the user should apply
  6730.          the patch. The user need not know how to determine the address.)
  6731.  
  6732.       4. After the patch has been applied, simply issue the DEBUG W (Write
  6733.          File or Sectors) command to write the corrected image back to disk
  6734.          under the same filename, provided the patch has not increased the
  6735.          size of the program. If program size has increased, first
  6736.          change the appropriate size fields in then .EXE header at the start
  6737.          of the file and use the DEBUG R (Display or Modify Registers)
  6738.          command to modify the BX and CX registers so that they contain the
  6739.          file image's new size. Then use the W command to write the image
  6740.          back to disk under the same name.
  6741.  
  6742.       5. Use the DEBUG Q (Quit) command to return to MS-DOS command level,
  6743.          and then rename the file to the original .EXE filename extension.
  6744.  
  6745.  .EXE summary
  6746.  
  6747.       To summarize, the .EXE program and file structures provide
  6748.       considerable flexibility in the design of programs, providing the
  6749.       programmer with the necessary freedom to produce large-scale
  6750.       applications. Programs written using Microsoft's high-level-language
  6751.       compilers have access to five standardized program structure models
  6752.       (small, medium, compact, large, and huge). These standardized models
  6753.       are excellent examples of ways to structure assembly-language
  6754.       programs.
  6755.  
  6756.  
  6757.  The .COM Program
  6758.  
  6759.       The majority of differences between .COM and .EXE programs exist
  6760.       because .COM program files are not prefaced by header information.
  6761.       Therefore, .COM programs do not benefit from the features the .EXE
  6762.       header provides.
  6763.  
  6764.       The absence of a header leaves MS-DOS with no way of knowing how much
  6765.       memory the .COM program requires in addition to the size of the
  6766.       program's image. Therefore, MS-DOS must always allocate the largest
  6767.       free block of memory to the .COM program, regardless of the program's
  6768.       true memory requirements. As was discussed for .EXE programs, this
  6769.       allocation of the largest block of free memory usually results in
  6770.       MS-DOS's allocating all remaining free memory--an action that can
  6771.       cause problems for multitasking supervisor programs.
  6772.  
  6773.       The .EXE program header also includes the direct segment address
  6774.       relocation pointer table. Because they lack this table, .COM programs
  6775.       cannot make address references to the labels specified in SEGMENT
  6776.       directives, with the exception of SEGMENT AT address directives. If a
  6777.       .COM program did make these references, MS-DOS would have no way of
  6778.       adjusting the addresses to correspond to the actual segment address
  6779.       into which MS-DOS loaded the program. See Creating the .COM Program,
  6780.       below.
  6781.  
  6782.       The .COM program structure exists primarily to support the vast number
  6783.       of CP/M programs ported to MS-DOS. Currently, .COM programs are most
  6784.       often used to avoid adding the 512 bytes or more of .EXE header
  6785.       information onto small, simple programs that often do not exceed 512
  6786.       bytes by themselves.
  6787.  
  6788.       The .COM program structure has another advantage: Its memory
  6789.       organization places the PSP within the same address segment as the
  6790.       rest of the program. Thus, it is easier to access fields within the
  6791.       PSP in .COM programs.
  6792.  
  6793.  Giving control to the .COM program
  6794.  
  6795.       After allocating the largest block of free memory to the .COM program,
  6796.       MS-DOS builds a PSP in the lowest 100H bytes of the block. No
  6797.       difference exists between the PSP MS-DOS builds for .COM programs and
  6798.       the PSP it builds for .EXE programs. Also with .EXE programs, MS-DOS
  6799.       determines the initial values for the AL and AH registers at this time
  6800.       and then loads the entire .COM-file image into memory immediately
  6801.       following the PSP. Because .COM files have no file-size header fields,
  6802.       MS-DOS relies on the size recorded in the disk directory to determine
  6803.       the size of the program image. It loads the program exactly as it
  6804.       appears in the file, without checking the file's contents.
  6805.  
  6806.       MS-DOS then sets the DS, ES, and SS segment registers to point to the
  6807.       start of the PSP. If able to allocate at least 64 KB to the program,
  6808.       MS-DOS sets the SP register to offset FFFFH + 1 (0000H) to establish
  6809.       an initial stack; if less than 64 KB are available for allocation to
  6810.       the program, MS-DOS sets the SP to 1 byte past the highest offset
  6811.       owned by the program. In either case, MS-DOS then pushes a single word
  6812.       of 0000H onto the program's stack for use in terminating the program.
  6813.  
  6814.       Finally, MS-DOS transfers control to the program by setting the CS
  6815.       register to the PSP's segment address and the IP register to 0100H.
  6816.       This means that the program's entry point must exist at the very start
  6817.       of the program's image, as shown in later examples.
  6818.  
  6819.       Figure 4-14 shows the overall structure of a .COM program as it
  6820.       receives control from MS-DOS.
  6821.  
  6822.  
  6823.                                   .COM program memory image
  6824.                             ┌───────────┐
  6825.                             │     ┌───┬──┬───────────────┐              ─
  6826.                SP=FFEH1────┘     │00H│00H│               │              
  6827.                                   │ Remaining free memory │              │
  6828.                                   │   within first 64 KB  │              │
  6829.                                   │ allocated to .COM pro-│              │
  6830.                                   │ gram (provided a full │              │
  6831.                                   │  64 KB was available) │              │
  6832.                                   │                       │          64 KB1
  6833.                                   ├───────────────────────┤              │
  6834.                                ┌─│  .COM program image   │              │
  6835.                                │  │       from file       │              │
  6836.       ┌───────────────────────┐│  │                       │              │
  6837.       │                       ││  ├───────────────────────┤ IP=0100H    │
  6838.       │  .COM program image   ├┘  │Program segment prefix │              
  6839.       └───────────────────────┘   └───────────────────────┘ CS,DS,ES,SS ─
  6840.  
  6841.       Figure 4-14. The .COM program: memory map diagram with register
  6842.       pointers.
  6843.  
  6844.  
  6845.  Terminating the .COM program
  6846.  
  6847.       A .COM program can use all the termination methods described for .EXE
  6848.       programs but should still use the MS-DOS Interrupt 21H Terminate
  6849.       Process with Return Code function (4CH) as the preferred method. If
  6850.       the .COM program must remain compatible with versions of MS-DOS
  6851.       earlier than 2.0, it can easily use any of the older termination
  6852.       methods, including those described as difficult to use from .EXE
  6853.       programs, because .COM programs execute with the CS register pointing
  6854.       to the PSP as required by these methods.
  6855.  
  6856.  Creating the .COM program
  6857.  
  6858.       A .COM program is created in the same manner as a .EXE program and
  6859.       then converted using the MS-DOS EXE2BIN utility. See PROGRAMMING
  6860.       UTILITIES: EXE2BIN.
  6861.  
  6862.       Certain restrictions do apply to .COM programs, however. First, .COM
  6863.       programs cannot exceed 64 KB minus 100H bytes for the PSP minus
  6864.       2 bytes for the zero word initially pushed on the stack.
  6865.  
  6866.       Next, only a single segment--or at least a single addressing group--
  6867.       should exist within the program. The following two examples show ways
  6868.       to structure a .COM program to satisfy both this restriction and
  6869.       MASM's need to have data fields precede program code in the source
  6870.       file.
  6871.  
  6872.       COMPROG1.ASM (Figure 4-15) declares only a single segment (COMSEG), so
  6873.       no special considerations apply when using the MASM OFFSET operator.
  6874.       See The MASM GROUP Directive above. COMPROG2.ASM (Figure 4-16)
  6875.       declares separate code (CSEG) and data (DSEG) segments, which the
  6876.       GROUP directive ties into a common addressing block. Thus, the
  6877.       programmer can declare data fields at the start of the source file and
  6878.       have the linker place the data fields segment (DSEG) after the code
  6879.       segment (CSEG) when it links the program, as discussed for the .EXE
  6880.       program structure. This second example simulates the program
  6881.       structuring provided under CP/M by Microsoft's old Macro-80 (M80)
  6882.       macro assembler and Link-80 (L80) linker. The design also expands
  6883.       easily to accommodate COMMON or other additional segments.
  6884.  
  6885.       ──────────────────────────────────────────────────────────────────────
  6886.  
  6887.       Figure 4-15. .COM program with data at start.
  6888.  
  6889.       ──────────────────────────────────────────────────────────────────────
  6890.  
  6891.       Figure 4-16. .COM program with data at end.
  6892.  
  6893.       ──────────────────────────────────────────────────────────────────────
  6894.  
  6895.       These examples demonstrate other significant requirements for
  6896.       producing a functioning .COM program. For instance, the ORG 0100H
  6897.       statement in both examples tells MASM to start assembling the code at
  6898.       offset 100H within the encompassing segment. This corresponds to
  6899.       MS-DOS's transferring control to the program at IP = 0100H. In
  6900.       addition, the entry-point label (BEGIN) immediately follows the ORG
  6901.       statement and appears again as a parameter to the END statement.
  6902.       Together, these factors satisfy the requirement that .COM programs
  6903.       declare their entry point at offset 100H. If any factor is missing,
  6904.       the MS-DOS EXE2BIN utility will not properly convert the .EXE file
  6905.       produced by the linker into a .COM file. Specifically, if a .COM
  6906.       program declares an entry point (as a parameter to the END statement)
  6907.       that is at neither offset 0100H nor offset 0000H, EXE2BIN rejects the
  6908.       .EXE file when the programmer attempts to convert it. If the program
  6909.       fails to declare an entry point or declares an entry point at offset
  6910.       0000H, EXE2BIN assumes that the .EXE file is to be converted to a
  6911.       binary image rather than to a .COM image. When EXE2BIN converts a .EXE
  6912.       file to a non-.COM binary file, it does not strip the extra 100H bytes
  6913.       the linker places in front of the code as a result of the ORG
  6914.       0100H instruction. Thus, the program actually begins at offset
  6915.       200H when MS-DOS loads it into memory, but all the program's address
  6916.       references will have been assembled and linked based on the 100H
  6917.       offset. As a result, the program--and probably the rest of the system
  6918.       as well--is likely to crash.
  6919.  
  6920.       A .COM program also must not contain direct segment address references
  6921.       to any segments that make up the program. Thus, the .COM program
  6922.       cannot reference any segment labels or reference any labels as long
  6923.       (FAR) pointers. (This rule does not prevent the program from
  6924.       referencing segment labels declared using the SEGMENT AT address
  6925.       directive.) Following are various examples of direct segment address
  6926.       references that are not permitted as part of .COM programs:
  6927.  
  6928.       PROC_A  PROC    FAR
  6929.       PROC_A  ENDP
  6930.               CALL    PROC_A          ;intersegment call
  6931.               JMP     PROC_A          ;intersegment jump
  6932.  
  6933.       or
  6934.  
  6935.               EXTRN   PROC_A:FAR
  6936.               CALL    PROC_A          ;intersegment call
  6937.               JMP     PROC_A          ;intersegment jump
  6938.  
  6939.       or
  6940.  
  6941.               MOV     AX,SEG SEG_A    ;segment address
  6942.               DD      LABEL_A         ;segment:offset pointer
  6943.  
  6944.       Finally, .COM programs must not declare any segments with the STACK
  6945.       combine type. If a program declares a segment with the STACK combine
  6946.       type, the linker will insert initial SS and SP values into the .EXE
  6947.       file header, causing EXE2BIN to reject the .EXE file. A .COM program
  6948.       does not have explicitly declared stacks, although it can reserve
  6949.       space in a non-STACK combine type segment to which it can initialize
  6950.       the SP register after it receives control. The absence of a stack
  6951.       segment will cause the linker to issue a harmless warning message.
  6952.  
  6953.       When the program is assembled and linked into a .EXE file, it must be
  6954.       converted into a binary file with a .COM extension by using the
  6955.       EXE2BIN utility as shown in the following example for the file
  6956.       YOURPROG.EXE:
  6957.  
  6958.       C>EXE2BIN YOURPROG YOURPROG.COM  <ENTER>
  6959.  
  6960.       It is not necessary to delete or rename a .EXE file with the same
  6961.       filename as the .COM file before trying to execute the .COM file as
  6962.       long as both remain in the same directory, because MS-DOS's order of
  6963.       execution is .COM files first, then .EXE files, and finally .BAT
  6964.       files. However, the safest practice is to delete a .EXE file
  6965.       immediately after converting it to a .COM file in case the .COM file
  6966.       is later renamed or moved to a different directory. If a .EXE file
  6967.       designed for conversion to a .COM file is executed by accident, it is
  6968.       likely to crash the system.
  6969.  
  6970.  Patching the .COM program using DEBUG
  6971.  
  6972.       As discussed for .EXE files, a programmer who distributes software to
  6973.       users will probably want to send instructions on how to patch in error
  6974.       corrections. This approach to software updates lends itself even
  6975.       better to .COM files than it does to .EXE files.
  6976.  
  6977.       For example, because .COM files contain only the code image, they need
  6978.       not be renamed in order to read and write them using DEBUG. The user
  6979.       need only be instructed on how to load the .COM file into DEBUG, how
  6980.       to patch the program, and how to write the patched image back to disk.
  6981.       Calculating the addresses and patch values is even easier, because no
  6982.       header exists in the .COM file image to cause complications. With the
  6983.       preceding exceptions, the details for patching .COM programs remain
  6984.       the same as previously outlined for .EXE programs.
  6985.  
  6986.  .COM summary
  6987.  
  6988.       To summarize, the .COM program and file structures are a simpler but
  6989.       more restricted approach to writing programs than the .EXE structure
  6990.       because the programmer has only a single memory model from which to
  6991.       choose (the .COM program segment model). Also, .COM program files do
  6992.       not contain the 512-byte (or more) header inherent to .EXE files, so
  6993.       the .COM program structure is well suited to small programs for which
  6994.       adding 512 bytes of header would probably at least double the file's
  6995.       size.
  6996.  
  6997.  
  6998.  Summary of Differences
  6999.  
  7000.       The following table summarizes the differences between .COM and .EXE
  7001.       programs.
  7002.  
  7003. ╓┌─────────────────────┌────────────────────────────┌────────────────────────╖
  7004.                        .COM program                 .EXE program
  7005.       ─────────────────────────────────────────────────────────────────────
  7006.       Maximum size     65536 bytes minus 256 bytes  No limit
  7007.                        for PSP and 2 bytes for
  7008.                        stack
  7009.  
  7010.       Entry point      PSP:0100H                    Defined by END statement
  7011.  
  7012.       CS at entry      PSP                          Segment containing
  7013.                                                     program's entry point
  7014.  
  7015.       IP at entry      0100H                        Offset of entry point
  7016.                        .COM program                 .EXE program
  7017.      IP at entry      0100H                        Offset of entry point
  7018.                                                     within its segment
  7019.  
  7020.       DS at entry      PSP                          PSP
  7021.  
  7022.       ES at entry      PSP                          PSP
  7023.  
  7024.       SS at entry      PSP                          Segment with STACK
  7025.                                                     attribute
  7026.  
  7027.       SP at entry      FFFEH or top word in         End of segment
  7028.                        available memory,            defined with
  7029.                        whichever is lower           STACK attribute
  7030.  
  7031.       Stack at entry   Zero word                    Initialized or
  7032.                                                     uninitialized,
  7033.                                                     depending on source
  7034.  
  7035.       Stack size       65536 bytes minus 256 bytes  Defined in
  7036.                        for PSP and size of          segment with
  7037.                        .COM program                 .EXE program
  7038.                       for PSP and size of          segment with
  7039.                        executable code and data     STACK attribute
  7040.  
  7041.       Subroutine calls NEAR                         NEAR or FAR
  7042.  
  7043.       Exit method      Interrupt 21H Function 4CH   Interrupt 21H Function
  7044.                        preferred; NEAR RET if       4CHpreferred;
  7045.                        MS-DOS versions 1.x          indirect jump to
  7046.                                                     PSP:0000H if MS-DOS
  7047.                                                     versions 1.x
  7048.  
  7049.       Size of file     Exact size of program        Size of program plus
  7050.                                                     header (at least 512
  7051.                                                     extra bytes)
  7052.  
  7053.       Which format the programmer uses for an application usually depends on
  7054.       the program's intended size, but the decision can also be influenced
  7055.       by a program's need to address multiple memory segments. Normally,
  7056.       small utility programs (such as CHKDSK and FORMAT) are designed as
  7057.       .COM programs; large programs (such as the Microsoft C Compiler) are
  7058.       designed as .EXE programs. The ultimate decision is, of course, the
  7059.       programmer's.
  7060.  
  7061.                                                               Keith Burgoyne
  7062.  
  7063.  
  7064.  
  7065.  Article 5:  Character Device Input and Output
  7066.  
  7067.  
  7068.       All functional computer systems are composed of a central processing
  7069.       unit (CPU), some memory, and peripheral devices that the CPU can use
  7070.       to store data or communicate with the outside world. In MS-DOS
  7071.       systems, the essential peripheral devices are the keyboard (for
  7072.       input), the display (for output), and one or more disk drives (for
  7073.       nonvolatile storage). Additional devices such as printers, modems, and
  7074.       pointing devices extend the functionality of the computer or offer
  7075.       alternative methods of using the system.
  7076.  
  7077.       MS-DOS recognizes two types of devices: block devices, which are
  7078.       usually floppy-disk or fixed-disk drives; and character devices, such
  7079.       as the keyboard, display, printer, and communications ports.
  7080.  
  7081.       The distinction between block and character devices is not always
  7082.       readily apparent, but in general, block devices transfer information
  7083.       in chunks, or blocks, and character devices move data one character
  7084.       (usually 1 byte) at a time. MS-DOS identifies each block device by a
  7085.       drive letter assigned when the device's controlling software, the
  7086.       device driver, is loaded. A character device, on the other hand, is
  7087.       identified by a logical name (similar to a filename and subject to
  7088.       many of the same restrictions) built into its device driver. See
  7089.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Installable
  7090.       Device Drivers.
  7091.  
  7092.  
  7093.  Background Information
  7094.  
  7095.       Versions 1.x of MS-DOS, first released for the IBM PC in 1981,
  7096.       supported peripheral devices with a fixed set of device drivers
  7097.       loaded during system initialization from the hidden file IO.SYS (or
  7098.       IBMBIO.COM with PC-DOS). These versions of MS-DOS offered application
  7099.       programs a high degree of input/output device independence by allowing
  7100.       character devices to be treated like files, but they did not provide
  7101.       an easy way to augment the built-in set of drivers if the user wished
  7102.       to add a third-party peripheral device to the system.
  7103.  
  7104.       With the release of MS-DOS version 2.0, the hardware flexibility of
  7105.       the system was tremendously enhanced. Versions 2.0 and later support
  7106.       installable device drivers that can reside in separate files on the
  7107.       disk and can be linked into the operating system simply by adding a
  7108.       DEVICE directive to the CONFIG.SYS file on the startup disk. See USER
  7109.       COMMANDS: CONFIG.SYS: DEVICE. A well-defined interface between
  7110.       installable drivers and the MS-DOS kernel allows such drivers to be
  7111.       written for most types of peripheral devices without the need for
  7112.       modification to the operating system itself.
  7113.  
  7114.       The CONFIG.SYS file can contain a number of different DEVICE commands
  7115.       to load separate drivers for pointing devices, magnetic-tape drives,
  7116.       network interfaces, and so on. Each driver, in turn, is specialized
  7117.       for the hardware characteristics of the device it supports. When the
  7118.       system is turned on or restarted, the installable device drivers are
  7119.       added to the chain, or linked list, of default device drivers loaded
  7120.       from IO.SYS during MS-DOS initialization. Thus, the need for the
  7121.       system's default set of device drivers to support a wide range of
  7122.       optional device types and features at an excessive cost of system
  7123.       memory is avoided.
  7124.  
  7125.       One important distinction between block and character devices is that
  7126.       MS-DOS always adds new block-device drivers to the tail of the driver
  7127.       chain but adds new character-device drivers to the head of the chain.
  7128.       Thus, because MS-DOS searches the chain sequentially and uses the
  7129.       first driver it finds that satisfies its search conditions, any
  7130.       existing character-device driver can be superseded by simply
  7131.       installing another driver with an identical logical device name.
  7132.  
  7133.       This article covers some of the details of working with MS-DOS
  7134.       character devices: displaying text, keyboard input, and other basic
  7135.       character I/O functions; the definition and use of standard input and
  7136.       output; redirection of the default character devices; and the use of
  7137.       the IOCTL function (Interrupt 21H Function 44H) to communicate
  7138.       directly with a character-device driver. Much of the information
  7139.       presented in this article is applicable only to MS-DOS versions 2.0
  7140.       and later.
  7141.  
  7142.  
  7143.  Accessing Character Devices
  7144.  
  7145.       Application programs can use either of two basic techniques to access
  7146.       character devices in a portable manner under MS-DOS. First, a program
  7147.       can use the handle-type function calls that were added to MS-DOS in
  7148.       version 2.0. Alternatively, a program can use the so-called
  7149.       "traditional" character-device functions that were present in versions
  7150.       1.x and have been retained in the operating system for compatibility.
  7151.       Because the handle functions are more powerful and flexible, they are
  7152.       discussed first.
  7153.  
  7154.       A handle is a 16-bit number returned by the operating system whenever
  7155.       a file or device is opened or created by passing a name to MS-DOS
  7156.       Interrupt 21H Function 3CH (Create File with Handle), 3DH (Open File
  7157.       with Handle), 5AH (Create Temporary File), or 5BH (Create New File).
  7158.       After a handle is obtained, it can be used with Interrupt 21H Function
  7159.       3FH (Read File or Device) or Function 40H (Write File or Device) to
  7160.       transfer data between the computer's memory and the file or device.
  7161.  
  7162.       During an open or create function call, MS-DOS searches the device-
  7163.       driver chain sequentially for a character device with the specified
  7164.       name (the extension is ignored) before searching the disk directory.
  7165.       Thus, a file with the same name as any character device in the driver
  7166.       chain--for example, the file NUL.TXT--cannot be created, nor can an
  7167.       existing file be accessed if a device in the chain has the same name.
  7168.  
  7169.       The second method for accessing character devices is through the
  7170.       traditional MS-DOS character input and output functions, Interrupt 21H
  7171.       Functions 01H through 0CH. These functions are designed to communicate
  7172.       directly with the keyboard, display, printer, and serial port. Each of
  7173.       these devices has its own function or group of functions, so neither
  7174.       names nor handles need be used. However, in MS-DOS versions 2.0 and
  7175.       later, these function calls are translated within MS-DOS to make use
  7176.       of the same routines that are used by the handle functions, so the
  7177.       traditional keyboard and display functions are affected by I/O
  7178.       redirection and piping.
  7179.  
  7180.       Use of either the traditional or the handle-based method for character
  7181.       device I/O results in highly portable programs that can be used on any
  7182.       computer that runs MS-DOS. A third, less portable access method is to
  7183.       use the hardware-specific routines resident in the read-only memory
  7184.       (ROM) of a specific computer (such as the IBM PC ROM BIOS driver
  7185.       functions), and a fourth, definitely nonportable approach is to
  7186.       manipulate the peripheral device's adapter directly, bypassing the
  7187.       system software altogether. Although these latter hardware-dependent
  7188.       methods cannot be recommended, they are admittedly sometimes necessary
  7189.       for performance reasons.
  7190.  
  7191.  
  7192.  The Basic MS-DOS Character Devices
  7193.  
  7194.       Every MS-DOS system supports at least the following set of logical
  7195.       character devices without the need for any additional installable
  7196.       drivers:
  7197.  
  7198. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  7199.       Device      Meaning
  7200.       ──────────────────────────────────────────────────────────────────
  7201.       CON         Keyboard and display
  7202.       PRN         System list device, usually a parallel port
  7203.       AUX         Auxiliary device, usually a serial port
  7204.       CLOCK$      System real-time clock
  7205.       Device      Meaning
  7206.      CLOCK$      System real-time clock
  7207.       NUL         "Bit-bucket" device
  7208.  
  7209.       These devices can be opened by name or they can be addressed through
  7210.       the "traditional" function calls; strings can be read from or written
  7211.       to the devices according to their capabilities on any MS-DOS system.
  7212.       Data written to the NUL device is discarded; reads from the NUL device
  7213.       always return an end-of-file condition.
  7214.  
  7215.       PC-DOS and compatible implementations of MS-DOS typically also support
  7216.       the following logical character-device names:
  7217.  
  7218. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  7219.       Device      Meaning
  7220.       ──────────────────────────────────────────────────────────────────
  7221.       COM1        First serial communications port
  7222.       COM2        Second serial communications port
  7223.       LPT1        First parallel printer port
  7224.       LPT2        Second parallel printer port
  7225.       LPT3        Third parallel printer port
  7226.       Device      Meaning
  7227.      LPT3        Third parallel printer port
  7228.  
  7229.       In such systems, PRN is an alias for LPT1 and AUX is an alias for
  7230.       COM1. The MODE command can be used to redirect an LPT device to
  7231.       another device. See USER COMMANDS: MODE.
  7232.  
  7233.       As previously mentioned, any of these default character-device drivers
  7234.       can be superseded by a user-installed device driver--for example, one
  7235.       that offers enhanced functionality or changes the device's apparent
  7236.       characteristics. One frequently used alternative character-device
  7237.       driver is ANSI.SYS, which replaces the standard MS-DOS CON device
  7238.       driver and allows ANSI escape sequences to be used to perform tasks
  7239.       such as clearing the screen, controlling the cursor position, and
  7240.       selecting character attributes. See USER COMMANDS: ANSI.SYS.
  7241.  
  7242.  The standard devices
  7243.  
  7244.       Under MS-DOS versions 2.0 and later, each program owns five previously
  7245.       opened handles for character devices (referred to as the standard
  7246.       devices) when it begins executing. These handles can be used for input
  7247.       and output operations without further preliminaries. The five standard
  7248.       devices and their associated handles are
  7249.  
  7250. ╓┌───────────────────────────────────────┌────────────┌──────────────────────╖
  7251.       Standard Device Name               Handle       Default Assignment
  7252.       ──────────────────────────────────────────────────────────────────
  7253.       Standard input (stdin)             0            CON
  7254.       Standard output (stdout)           1            CON
  7255.       Standard error (stderr)            2            CON
  7256.       Standard auxiliary (stdaux)        3            AUX
  7257.       Standard printer (stdprn)          4            PRN
  7258.  
  7259.       The standard input and standard output handles are especially
  7260.       important because they are subject to I/O redirection. Although these
  7261.       handles are associated by default with the CON device so that read and
  7262.       write operations are implemented using the keyboard and video display,
  7263.       the user can associate the handles with other character devices or
  7264.       with files by using redirection parameters in a program's command
  7265.       line:
  7266.  
  7267. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  7268.       Redirection      Result
  7269.       ──────────────────────────────────────────────────────────────────────
  7270.       < file           Causes read operations from standard input to obtain
  7271.                        data from file.
  7272.       > file           Causes data written to standard output to be placed
  7273.                        in file.
  7274.       >> file          Causes data written to standard output to be appended
  7275.                        to file.
  7276.       p1 | p2          Causes data written to standard output by program p1
  7277.                        to appear as the standard input of program p2.
  7278.  
  7279.       This ability to redirect I/O adds great flexibility and power to the
  7280.       system. For example, programs ordinarily controlled by keyboard
  7281.       entries can be run with "scripts" from files, the output of a program
  7282.       can be captured in a file or on a printer for later inspection, and
  7283.       general-purpose programs (filters) can be written that process text
  7284.       streams without regard to the text's origin or destination. See
  7285.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Writing
  7286.       MS-DOS Filters.
  7287.  
  7288.       Ordinarily, an application program is not aware that its input or
  7289.       output has been redirected, although a write operation to standard
  7290.       output will fail unexpectedly if standard output was redirected to a
  7291.       disk file and the disk is full. An application can check for the
  7292.       existence of I/O redirection with an IOCTL (Interrupt 21H Function
  7293.       44H) call, but it cannot obtain any information about the destination
  7294.       of the redirected handle except whether it is associated with a
  7295.       character device or with a file.
  7296.  
  7297.  Raw versus cooked mode
  7298.  
  7299.       MS-DOS associates each handle for a character device with a mode that
  7300.       determines how I/O requests directed to that handle are treated. When
  7301.       a handle is in raw mode, characters are passed between the application
  7302.       program and the device driver without any filtering or buffering by
  7303.       MS-DOS. When a handle is in cooked mode, MS-DOS buffers any data that
  7304.       is read from or written to the device and takes special actions when
  7305.       certain characters are detected.
  7306.  
  7307.       During cooked mode input, MS-DOS obtains characters from the device
  7308.       driver one at a time, checking each character for a Control-C. The
  7309.       characters are assembled into a string within an internal MS-DOS
  7310.       buffer. The input operation is terminated when a carriage return (0DH)
  7311.       or an end-of-file mark (1AH) is received or when the number of
  7312.       characters requested by the application have been accumulated. If the
  7313.       source is standard input, lone linefeed characters are translated to
  7314.       carriage-return/linefeed pairs. The string is then copied from the
  7315.       internal MS-DOS buffer to the application program's buffer, and
  7316.       control returns to the application program.
  7317.  
  7318.       During cooked mode output, MS-DOS transfers the characters in the
  7319.       application program's output buffer to the device driver one at a
  7320.       time, checking after each character for a Control-C pending at the
  7321.       keyboard. If the destination is standard output and standard output
  7322.       has not been redirected, tabs are expanded to spaces using eight-
  7323.       column tab stops. Output is terminated when the requested number of
  7324.       characters have been written or when an end-of-file mark (1AH) is
  7325.       encountered in the output string.
  7326.  
  7327.       In contrast, during raw mode input or output, data is transferred
  7328.       directly between the application program's buffer and the device
  7329.       driver. Special characters such as carriage return and the end-of-file
  7330.       mark are ignored, and the exact number of characters in the
  7331.       application program's request are always read or written. MS-DOS does
  7332.       not break the strings into single-character calls to the device driver
  7333.       and does not check the keyboard buffer for Control-C entries during
  7334.       the I/O operation. Finally, characters read from standard input in raw
  7335.       mode are not echoed to standard output.
  7336.  
  7337.       As might be expected from the preceding description, raw mode input or
  7338.       output is usually much faster than cooked mode input or output,
  7339.       because each character is not being individually processed by the
  7340.       MS-DOS kernel. Raw mode also allows programs to read characters from
  7341.       the keyboard buffer that would otherwise be trapped by MS-DOS (for
  7342.       example, Control-C, Control-P, and Control-S). (If BREAK is on, MS-DOS
  7343.       will still check for Control-C entries during other function calls,
  7344.       such as disk operations, and transfer control to the Control-C
  7345.       exception handler if a Control-C is detected.) A program can use the
  7346.       MS-DOS IOCTL Get and Set Device Data services (Interrupt 21H Function
  7347.       44H Subfunctions 00H and 01H) to set the mode for a character-device
  7348.       handle. See IOCTL, below.
  7349.  
  7350.       Ordinarily, raw or cooked mode is strictly an attribute of a specific
  7351.       handle that was obtained from a previous open operation and affects
  7352.       only the I/O operations requested by the program that owns the handle.
  7353.       However, when a program uses IOCTL to select raw or cooked mode for
  7354.       one of the standard device handles, the selection has a global effect
  7355.       on the behavior of the system because those handles are never closed.
  7356.       Thus, some of the "traditional" keyboard input functions might behave
  7357.       in unexpected ways. Consequently, programs that change the mode on a
  7358.       standard device handle should save the handle's mode at entry and
  7359.       restore it before performing a final exit to MS-DOS, so that the
  7360.       operation of COMMAND.COM and other applications will not be disturbed.
  7361.       Such programs should also incorporate custom critical error and
  7362.       Control-C exception handlers so that the programs cannot be terminated
  7363.       unexpectedly. See PROGRAMMING IN THE MS-DOS ENVIRONMENT: CUSTOMIZING
  7364.       MS-DOS: Exception Handlers.
  7365.  
  7366.  The keyboard
  7367.  
  7368.       Among the MS-DOS Interrupt 21H functions are two methods of checking
  7369.       for and receiving input from the keyboard: the traditional method,
  7370.       which uses MS-DOS character input Functions 01H, 06H, 07H, 08H, 0AH,
  7371.       0BH, and 0CH (Table 5-1); and the handle method, which uses Function
  7372.       3FH. Each of these methods has its own advantages and disadvantages.
  7373.       See SYSTEM CALLS.
  7374.  
  7375.  
  7376.       Table 5-1. Traditional MS-DOS Character Input Functions.
  7377.  
  7378. ╓┌───────────────┌─────────────────────────────┌──────────────┌──────┌───────╖
  7379.                                                Read Multiple         Ctrl-C
  7380.       Function   Name                          Characters     Echo   Check
  7381.       ──────────────────────────────────────────────────────────────────────
  7382.       01H        Character Input with Echo     No             Yes    Yes
  7383.       06H        Direct Console I/O            No             No     No
  7384.       07H        Unfiltered Character Input
  7385.                  Without Echo                  No             No     No
  7386.       08H        Character Input Without Echo  No             No     Yes
  7387.       0AH        Buffered Keyboard Input       Yes            Yes    Yes
  7388.       0BH        Check Keyboard Status         No             No     Yes
  7389.       0CH        Flush Buffer, Read Keyboard   1             1     1
  7390.  
  7391.  
  7392.       The first four traditional keyboard input calls are really very
  7393.       similar. They all return a character in the AL register; they differ
  7394.       mainly in whether they echo that character to the display and whether
  7395.       they are sensitive to interruption by the user's entry of a Control-C.
  7396.       Both Functions 06H and 0BH can be used to test keyboard status (that
  7397.       is, whether a key has been pressed and is waiting to be read by the
  7398.       program); Function 0BH is simpler to use, but Function 06H is immune
  7399.       to Control-C entries.
  7400.  
  7401.       Function 0AH is used to read a "buffered line" from the user, meaning
  7402.       that an entire line is accepted by MS-DOS before control returns to
  7403.       the program. The line is terminated when the user presses the Enter
  7404.       key or when the maximum number of characters (to 255) specified by the
  7405.       program have been received. While entry of the line is in progress,
  7406.       the usual editing keys (such as the left and right arrow keys and the
  7407.       function keys on IBM PCs and compatibles) are active; only the final,
  7408.       edited line is delivered to the requesting program.
  7409.  
  7410.       Function 0CH allows a program to flush the type-ahead buffer before
  7411.       accepting input. This capability is important for occasions when a
  7412.       prompt must be displayed unexpectedly (such as when a critical error
  7413.       occurs) and the user could not have typed ahead a valid response. This
  7414.       function should also be used when the user is being prompted for a
  7415.       critical decision (such as whether to erase a file), to prevent a
  7416.       character that was previously pressed by accident from triggering an
  7417.       irrecoverable operation. Function 0CH is unusual in that it is called
  7418.       with the number of one of the other keyboard input functions in
  7419.       register AL. After any pending input has been discarded, Function 0CH
  7420.       simply transfers to the other specified input function; thus, its
  7421.       other parameters (if any) depend on the function that ultimately will
  7422.       be executed.
  7423.  
  7424.       The primary disadvantage of the traditional function calls is that
  7425.       they handle redirected input poorly. If standard input has been
  7426.       redirected to a file, no way exists for a program calling the
  7427.       traditional input functions to detect that the end of the file has
  7428.       been reached-the input function will simply wait forever, and the
  7429.       system will appear to hang.
  7430.  
  7431.       A program that wishes to use handle-based I/O to get input from the
  7432.       keyboard must use the MS-DOS Read File or Device service, Interrupt
  7433.       21H Function 3FH. Ordinarily, the program can employ the predefined
  7434.       handle for standard input (0), which does not need to be opened and
  7435.       which allows the program's input to be redirected by the user to
  7436.       another file or device. If the program needs to circumvent redirection
  7437.       and ensure that its input is from the keyboard, it can open the CON
  7438.       device with Interrupt 21H Function 3DH and use the handle obtained
  7439.       from that open operation instead of the standard input handle.
  7440.  
  7441.       A program using the handle functions to read the keyboard can control
  7442.       the echoing of characters and sensitivity to Control-C entries by
  7443.       selecting raw or cooked mode with the IOCTL Get and Set Device Data
  7444.       services (default = cooked mode). To test the keyboard status, the
  7445.       program can either issue an IOCTL Check Input Status call (Interrupt
  7446.       21H Function 44H Subfunction 06H) or use the traditional Check
  7447.       Keyboard Status call (Interrupt 21H Function 0BH).
  7448.  
  7449.       The primary advantages of the handle method for keyboard input are its
  7450.       symmetry with file operations and its graceful handling of redirected
  7451.       input. The handle function also allows strings as long as 65535 bytes
  7452.       to be requested; the traditional Buffered Keyboard Input function
  7453.       allows a maximum of 255 characters to be read at a time. This
  7454.       consideration is important for programs that are frequently used with
  7455.       redirected input and output (such as filters), because reading and
  7456.       writing larger blocks of data from files results in more efficient
  7457.       operation. The only real disadvantage to the handle method is that it
  7458.       is limited to MS-DOS versions 2.0 and later (although this is no
  7459.       longer a significant restriction).
  7460.  
  7461.  Role of the ROM BIOS
  7462.       When a key is pressed on the keyboard of an IBM PC or compatible, it
  7463.       generates a hardware interrupt (09H) that is serviced by a routine in
  7464.       the ROM BIOS. The ROM BIOS interrupt handler reads I/O ports assigned
  7465.       to the keyboard controller and translates the key's scan code into an
  7466.       ASCII character code. The result of this translation depends on the
  7467.       current state of the NumLock and CapsLock toggles, as well as on
  7468.       whether the Shift, Control, or Alt key is being held down. (The ROM
  7469.       BIOS maintains a keyboard flags byte at address 0000:0417H that gives
  7470.       the current status of each of these modifier keys.)
  7471.  
  7472.       After translation, both the scan code and the ASCII code are placed in
  7473.       the ROM BIOS's 32-byte (16-character) keyboard input buffer. In the
  7474.       case of "extended" keys such as the function keys or arrow keys, the
  7475.       ASCII code is a zero byte and the scan code carries all the
  7476.       information. The keyboard buffer is arranged as a circular, or ring,
  7477.       buffer and is managed as a first-in/first-out queue. Because of the
  7478.       method used to determine when the buffer is empty, one position in the
  7479.       buffer is always wasted; the maximum number of characters that can be
  7480.       held in the buffer is therefore 15. Keys pressed when the buffer is
  7481.       full are discarded and a warning beep is sounded.
  7482.  
  7483.       The ROM BIOS provides an additional module, invoked by software
  7484.       Interrupt 16H, that allows programs to test keyboard status, determine
  7485.       whether characters are waiting in the type-ahead buffer, and remove
  7486.       characters from the buffer. See Appendix O: IBM PC BIOS Calls. Its use
  7487.       by application programs should ordinarily be avoided, however, to
  7488.       prevent introducing unnecessary hardware dependence.
  7489.  
  7490.       On IBM PCs and compatibles, the keyboard input portion of the CON
  7491.       driver in the BIOS is a simple sequence of code that calls ROM BIOS
  7492.       Interrupt 16H to do the hardware-dependent work. Thus, calls to MS-DOS
  7493.       for keyboard input by an application program are subject to two layers
  7494.       of translation: The Interrupt 21H function call is converted by the
  7495.       MS-DOS kernel to calls to the CON driver, which in turn remaps the
  7496.       request onto a ROM BIOS call that obtains the character.
  7497.  
  7498.  Keyboard programming examples
  7499.       Example: Use the ROM BIOS keyboard driver to read a character from the
  7500.       keyboard. The character is not echoed to the display.
  7501.  
  7502.          mov     ah,00h          ; subfunction 00H = read character
  7503.          int     16h             ; transfer to ROM BIOS
  7504.                                  ; now AH = scan code, AL = character
  7505.  
  7506.       Example: Use the MS-DOS traditional keyboard input function to read a
  7507.       character from the keyboard. The character is not echoed to the
  7508.       display. The input can be interrupted with a Ctrl-C keystroke.
  7509.  
  7510.          mov     ah,08h          ; function 08H = character input
  7511.                                  ;   without echo
  7512.          int     21h             ; transfer to MS-DOS
  7513.                                  ; now AL = character
  7514.  
  7515.       Example: Use the MS-DOS traditional Buffered Keyboard Input function
  7516.       to read an entire line from the keyboard, specifying a maximum line
  7517.       length of 80 characters. All editing keys are active during entry, and
  7518.       the input is echoed to the display.
  7519.  
  7520.       kbuf    db      80              ; maximum length of read
  7521.               db      0               ; actual length of read
  7522.               db      80 dup (0)      ; keyboard input goes here
  7523.               .
  7524.               .
  7525.               .
  7526.               mov     dx,seg kbuf     ; set DS:DX = address of
  7527.               mov     ds,dx           ; keyboard input buffer
  7528.               mov     dx,offset kbuf
  7529.               mov     ah,0ah          ; function 0AH = read buffered line
  7530.               int     21h             ; transfer to MS-DOS
  7531.                                       ; terminated by a carriage return,
  7532.                                       ; and kbuf+1 = length of input,
  7533.                                       ; not including the carriage return
  7534.  
  7535.       Example: Use the MS-DOS handle-based Read File or Device function and
  7536.       the standard input handle to read an entire line from the keyboard,
  7537.       specifying a maximum line length of 80 characters. All editing keys
  7538.       are active during entry, and the input is echoed to the display. (The
  7539.       input will not terminate on a carriage return as expected if standard
  7540.       input is in raw mode.)
  7541.  
  7542.       kbuf    db      80 dup (0)      ; buffer for keyboard input
  7543.               .
  7544.               .
  7545.               .
  7546.               mov     dx,seg kbuf     ; set DS:DX = address of
  7547.               mov     ds,dx           ; keyboard input buffer
  7548.               mov     dx,offset kbuf
  7549.               mov     cx,80           ; CX = maximum length of input
  7550.               mov     bx,0            ; standard input handle = 0
  7551.               mov     ah,3fh          ; function 3FH = read file/device
  7552.               int     21h             ; transfer to MS-DOS
  7553.               jc      error           ; jump if function failed
  7554.                                       ; otherwise AX = actual
  7555.                                       ; length of keyboard input,
  7556.                                       ; including carriage-return and
  7557.                                       ; linefeed, and the data is
  7558.                                       ; in the buffer 'kbuf'
  7559.  
  7560.  The display
  7561.  
  7562.       The output half of the MS-DOS logical character device CON is the
  7563.       video display. On IBM PCs and compatibles, the video display is an
  7564.       "option" of sorts that comes in several forms. IBM has introduced five
  7565.       video subsystems that support different types of displays: the
  7566.       Monochrome Display Adapter (MDA), the Color/Graphics Adapter (CGA),
  7567.       the Enhanced Graphics Adapter (EGA), the Video Graphics Array (VGA),
  7568.       and the Multi-Color Graphics Array (MCGA). Other, non-IBM-compatible
  7569.       video subsystems in common use include the Hercules Graphics Card and
  7570.       its variants that support downloadable fonts.
  7571.  
  7572.       Two portable techniques exist for writing text to the video display
  7573.       with MS-DOS function calls. The traditional method is supported by
  7574.       Interrupt 21H Functions 02H (Character Output), 06H (Direct Console
  7575.       I/O), and 09H (Display String). The handle method is supported by
  7576.       Function 40H (Write File or Device) and is available only in MS-DOS
  7577.       versions 2.0 and later. See SYSTEM CALLS: INTERRUPT 21H: Functions
  7578.       02H, 06H, 09H, 40H. All these calls treat the display essentially
  7579.       as a "glass teletype" and do not support bit-mapped graphics.
  7580.  
  7581.       Traditional Functions 02H and 06H are similar. Both are called with
  7582.       the character to be displayed in the DL register; they differ in that
  7583.       Function 02H is sensitive to interruption by the user's entry of a
  7584.       Control-C, whereas Function 06H is immune to Control-C but cannot be
  7585.       used to output the character 0FFH (ASCII rubout). Both calls check
  7586.       specifically for carriage return (0DH), linefeed (0AH), and backspace
  7587.       (08H) characters and take the appropriate action if these characters
  7588.       are detected.
  7589.  
  7590.       Because making individual calls to MS-DOS for each character to be
  7591.       displayed is inefficient and slow, the traditional Display String
  7592.       function (09H) is generally used in preference to Functions 02H and
  7593.       06H. Function 09H is called with the address of a string that is
  7594.       terminated with a dollar-sign character ($); it displays the entire
  7595.       string in one operation, regardless of its length. The string can
  7596.       contain embedded control characters such as carriage return and
  7597.       linefeed.
  7598.  
  7599.       To use the handle method for screen display, programs must call the
  7600.       MS-DOS Write File or Device service, Interrupt 21H Function 40H.
  7601.       Ordinarily, a program should use the predefined handle for standard
  7602.       output (1) to send text to the screen, so that any redirection
  7603.       requested by the user on the program's command line will be honored.
  7604.       If the program needs to circumvent redirection and ensure that its
  7605.       output goes to the screen, it can either use the predefined handle for
  7606.       standard error (2) or explicitly open the CON device with Interrupt
  7607.       21H Function 3DH and use the resulting handle for its write
  7608.       operations.
  7609.  
  7610.       The handle technique for displaying text has several advantages over
  7611.       the traditional calls. First, the length of the string to be displayed
  7612.       is passed as an explicit parameter, so the string need not contain a
  7613.       special terminating character and the $ character can be displayed as
  7614.       part of the string. Second, the traditional calls are translated to
  7615.       handle calls inside MS-DOS, so the handle calls have less internal
  7616.       overhead and are generally faster. Finally, use of the handle Write
  7617.       File or Device function to display text is symmetric with the methods
  7618.       the program must use to access its files. In short, the traditional
  7619.       functions should be avoided unless the program must be capable of
  7620.       running under MS-DOS versions 1.x.
  7621.  
  7622.  Controlling the screen
  7623.       One of the deficiencies of the standard MS-DOS CON device driver is
  7624.       the lack of screen-control capabilities. The default CON driver has no
  7625.       built-in routines to support cursor placement, screen clearing,
  7626.       display mode selection, and so on.
  7627.  
  7628.       In MS-DOS versions 2.0 and later, an optional replacement CON driver
  7629.       is supplied in the file ANSI.SYS. This driver contains most of the
  7630.       screen-control capabilities needed by text-oriented application
  7631.       programs. The driver is installed by adding a DEVICE directive to the
  7632.       CONFIG.SYS file and restarting the system. When ANSI.SYS is active, a
  7633.       program can position the cursor, inquire about the current cursor
  7634.       position, select foreground and background colors, and clear the
  7635.       current line or the entire screen by sending an escape sequence
  7636.       consisting of the ASCII Esc character (1BH) followed by various
  7637.       function-specific parameters to the standard output device. See USER
  7638.       COMMANDS: ANSI.SYS.
  7639.  
  7640.       Programs that use the ANSI.SYS capabilities for screen control are
  7641.       portable to any MS-DOS implementation that contains the ANSI.SYS
  7642.       driver. Programs that seek improved performance by calling the ROM
  7643.       BIOS video driver or by assuming direct control of the hardware are
  7644.       necessarily less portable and usually require modification when new PC
  7645.       models or video subsystems are released.
  7646.  
  7647.  Role of the ROM BIOS
  7648.       The video subsystems in IBM PCs and compatibles use a hybrid of
  7649.       memory-mapped and port-addressed I/O. A range of the machine's memory
  7650.       addresses is typically reserved for a video refresh buffer that holds
  7651.       the character codes and attributes to be displayed on the screen; the
  7652.       cursor position, display mode, palettes, and similar global display
  7653.       characteristics are governed by writing control values to specific I/O
  7654.       ports.
  7655.  
  7656.       The ROM BIOS of IBM PCs and compatibles contains a primitive driver
  7657.       for the MDA, CGA, EGA, VGA, and MCGA video subsystems. This driver
  7658.       supports the following functions:
  7659.  
  7660.       ■  Read or write characters with attributes at any screen position.
  7661.       ■  Query or set the cursor position.
  7662.       ■  Clear or scroll an arbitrary portion of the screen.
  7663.       ■  Select palette, background, foreground, and border colors.
  7664.       ■  Query or set the display mode (40-column text, 80-column text, all-
  7665.          points-addressable graphics, and so on).
  7666.       ■  Read or write a pixel at any screen coordinate.
  7667.  
  7668.       These functions are invoked by a program through software Interrupt
  7669.       10H. See Appendix O: IBM PC BIOS Calls. In PC-DOS-compatible
  7670.       implementations of MS-DOS, the display portions of the MS-DOS CON and
  7671.       ANSI.SYS drivers use these ROM BIOS routines. Video subsystems that
  7672.       are not IBM compatible either must contain their own ROM BIOS or must
  7673.       be used with an installable device driver that captures Interrupt 10H
  7674.       and provides appropriate support functions.
  7675.  
  7676.       Text-only application programs should avoid use of the ROM BIOS
  7677.       functions or direct access to the hardware whenever possible, to
  7678.       ensure maximum portability between MS-DOS systems. However, because
  7679.       the MS-DOS CON driver contains no support for bit-mapped graphics,
  7680.       graphically oriented applications usually must resort to direct
  7681.       control of the video adapter and its refresh buffer for speed and
  7682.       precision.
  7683.  
  7684.  Display programming examples
  7685.       Example: Use the ROM BIOS Interrupt 10H function to write an asterisk
  7686.       character to the display in text mode. (In graphics mode, BL must also
  7687.       be set to the desired foreground color.)
  7688.  
  7689.               mov     ah,0eh          ; subfunction 0EH = write character
  7690.                                       ; in teletype mode
  7691.               mov     al,'*'          ; AL = character to display
  7692.               mov     bh,0            ; select display page 0
  7693.               int     10h             ; transfer to ROM BIOS video driver
  7694.  
  7695.       Example: Use the MS-DOS traditional function to write an asterisk
  7696.       character to the display. If the user's entry of a Control-C is
  7697.       detected during the output and standard output is in cooked mode,
  7698.       MS-DOS calls the Control-C exception handler whose address is found in
  7699.       the vector for Interrupt 23H.
  7700.  
  7701.               mov     ah,02h          ; function 02H = display character
  7702.               mov     dl,'*'          ; DL = character to display
  7703.               int     21h             ; transfer to MS-DOS
  7704.  
  7705.       Example: Use the MS-DOS traditional function to write a string to the
  7706.       display. The output is terminated by the $ character and can be
  7707.       interrupted when the user enters a Control-C if standard output is in
  7708.       cooked mode.
  7709.  
  7710.       msg     db      'This is a test message','$'
  7711.               .
  7712.               .
  7713.               .
  7714.               mov     dx,seg msg      ; DS:DX = address of text
  7715.               mov     ds,dx           ; to display
  7716.               mov     dx,offset msg
  7717.               mov     ah,09h          ; function 09H = display string
  7718.               int     21h             ; transfer to MS-DOS
  7719.  
  7720.       Example: Use the MS-DOS handle-based Write File or Device function and
  7721.       the predefined handle for standard output to write a string to the
  7722.       display. Output can be interrupted by the user's entry of a Control-C
  7723.       if standard output is in cooked mode.
  7724.  
  7725.       msg     db      'This is a test message'
  7726.       msg_len equ     $-msg
  7727.               .
  7728.               .
  7729.               .
  7730.               mov     dx,seg msg      ; DS:DX = address of text
  7731.               mov     ds,dx           ; to display
  7732.               mov     dx,offset msg
  7733.               mov     cx,msg_len      ; CX = length of text
  7734.               mov     bx,1            ; BX = handle for standard output
  7735.               mov     ah,40h          ; function 40H = write file/device
  7736.               int     21h             ; transfer to MS-DOS
  7737.  
  7738.  The serial communications ports
  7739.  
  7740.       Through version 3.2, MS-DOS has built-in support for two serial
  7741.       communications ports, identified as COM1 and COM2, by means of three
  7742.       drivers named AUX, COM1, and COM2. (AUX is ordinarily an alias for
  7743.       COM1.)
  7744.  
  7745.       The traditional MS-DOS method of reading from and writing to the
  7746.       serial ports is through Interrupt 21H Function 03H for AUX input and
  7747.       Function 04H for AUX output. In MS-DOS versions 2.0 and later, the
  7748.       handle-based Read File or Device and Write File or Device functions
  7749.       (Interrupt 21H Functions 3FH and 40H) can be used to read from or
  7750.       write to the auxiliary device. A program can use the predefined handle
  7751.       for the standard auxiliary device (3) with Functions 3FH and 40H, or
  7752.       it can explicitly open the COM1 or COM2 devices with Interrupt 21H
  7753.       Function 3DH and use the handle obtained from that open operation to
  7754.       perform read and write operations.
  7755.  
  7756.       MS-DOS support for the serial communications port is inadequate in
  7757.       several respects for high-performance serial I/O applications. First,
  7758.       MS-DOS provides no portable way to test for the existence or the
  7759.       status of a particular serial port in a system; if a program "opens"
  7760.       COM2 and writes data to it and the physical COM2 adapter is not
  7761.       present in the system, the program may simply hang. Similarly, if the
  7762.       serial port exists but no character has been received and the program
  7763.       attempts to read a character, the program will hang until one is
  7764.       available; there is no traditional function call to check if a
  7765.       character is waiting as there is for the keyboard.
  7766.  
  7767.       MS-DOS also provides no portable method to initialize the
  7768.       communications adapter to a particular baud rate, word length, and
  7769.       parity. An application must resort to ROM BIOS calls, manipulate the
  7770.       hardware directly, or rely on the user to configure the port properly
  7771.       with the MODE command before running the application that uses it. The
  7772.       default settings for the serial port on PC-DOS-compatible systems are
  7773.       2400 baud, no parity, 1 stop bit, and 8 databits. See USER COMMANDS:
  7774.       MODE.
  7775.  
  7776.       A more serious problem with the default MS-DOS auxiliary device driver
  7777.       in IBM PCs and compatibles, however, is that it is not interrupt
  7778.       driven. Accordingly, when baud rates above 1200 are selected,
  7779.       characters can be lost during time-consuming operations performed by
  7780.       the drivers for other devices, such as clearing the screen or reading
  7781.       or writing a floppy-disk sector. Because the MS-DOS AUX device driver
  7782.       typically relies on the ROM BIOS serial port driver (accessed through
  7783.       software Interrupt 14H) and because the ROM BIOS driver is not
  7784.       interrupt driven either, bypassing MS-DOS and calling the ROM BIOS
  7785.       functions does not usually improve matters.
  7786.  
  7787.       Because of all the problems just described, telecommunications
  7788.       application programs commonly take over complete control of the serial
  7789.       port and supply their own interrupt handler and internal buffering for
  7790.       character read and write operations. See PROGRAMMING IN THE MS-DOS
  7791.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: Interrupt-Driven Communications.
  7792.  
  7793.  Serial port programming examples
  7794.       Example: Use the ROM BIOS serial port driver to write a string to
  7795.       COM1.
  7796.  
  7797.       msg     db      'This is a test message'
  7798.       msg_len equ     $-msg
  7799.               .
  7800.               .
  7801.               .
  7802.               mov     bx,seg msg      ; DS:BX = address of message
  7803.               mov     ds,bx
  7804.               mov     bx,offset msg
  7805.               mov     cx,msg_len      ; CX = length of message
  7806.               mov     dx,0            ; DX = 0 for COM1
  7807.       L1:     mov     al,[bx]         ; get next character into AL
  7808.               mov     ah,01h          ; subfunction 01H = output
  7809.               int     14h             ; transfer to ROM BIOS
  7810.               inc     bx              ; bump pointer to output string
  7811.               loop    L1              ; and loop until all chars. sent
  7812.  
  7813.       Example: Use the MS-DOS traditional function for auxiliary device
  7814.       output to write a string to COM1.
  7815.  
  7816.       msg     db      'This is a test message'
  7817.       msg_len equ     $-msg
  7818.               .
  7819.               .
  7820.               .
  7821.               mov     bx,seg msg      ; set DS:BX = address of message
  7822.               mov     ds,bx
  7823.               mov     bx,offset msg
  7824.               mov     cx,msg_len      ; set CX = length of message
  7825.       L1:     mov     dl,[bx]         ; get next character into DL
  7826.               mov     ah,04h          ; function 04H = auxiliary output
  7827.               int     21h             ; transfer to MS-DOS
  7828.               inc     bx              ; bump pointer to output string
  7829.               loop    L1              ; and loop until all chars. sent
  7830.  
  7831.       Example: Use the MS-DOS handle-based Write File or Device function and
  7832.       the predefined handle for the standard auxiliary device to write a
  7833.       string to COM1.
  7834.  
  7835.       msg     db      'This is a test message'
  7836.       msg_len equ     $-msg
  7837.               .
  7838.               .
  7839.               .
  7840.               mov     dx,seg msg      ; DS:DX = address of message
  7841.               mov     ds,dx
  7842.               mov     dx,offset msg
  7843.               mov     cx,msg_len      ; CX = length of message
  7844.               mov     bx,3            ; BX = handle for standard aux.
  7845.               mov     ah,40h          ; function 40H = write file/device
  7846.               int     21h             ; transfer to MS-DOS
  7847.               jc      error           ; jump if write operation failed
  7848.  
  7849.  The parallel port and printer
  7850.  
  7851.       Most MS-DOS implementations contain device drivers for four printer
  7852.       devices: LPT1, LPT2, LPT3, and PRN. PRN is ordinarily an alias for
  7853.       LPT1 and refers to the first parallel output port in the system. To
  7854.       provide for list devices that do not have a parallel interface, the
  7855.       LPT devices can be individually redirected with the MODE command to
  7856.       one of the serial communications ports. See USER COMMANDS: MODE.
  7857.  
  7858.       As with the keyboard, the display, and the serial port, MS-DOS allows
  7859.       the printer to be accessed with either traditional or handle-based
  7860.       function calls. The traditional function call is Interrupt 21H
  7861.       Function 05H, which accepts a character in DL and sends it to the
  7862.       physical device currently assigned to logical device name LPT1.
  7863.  
  7864.       A program can perform handle-based output to the printer with
  7865.       Interrupt 21H Function 40H (Write File or Device). The predefined
  7866.       handle for the standard printer (4) can be used to send strings to
  7867.       logical device LPT1. Alternatively, the program can issue an open
  7868.       operation for a specific printer device with Interrupt 21H Function
  7869.       3DH and use the handle obtained from that open operation with Function
  7870.       40H. This latter method also allows more than one printer to be used
  7871.       at a time from the same program.
  7872.  
  7873.       Because the parallel ports are assumed to be output only, no
  7874.       traditional call exists for input from the parallel port. In addition,
  7875.       no portable method exists to test printer port status under MS-DOS;
  7876.       programs that wish to avoid sending a character to the printer adapter
  7877.       when it is not ready or not physically present in the system must test
  7878.       the adapter's status by making a call to the ROM BIOS printer driver
  7879.       (by means of software Interrupt 17H; see Appendix O: IBM PC BIOS
  7880.       Calls) or by accessing the hardware directly.
  7881.  
  7882.  Parallel port programming examples
  7883.  
  7884.       Example: Use the ROM BIOS printer driver to send a string to the first
  7885.       parallel printer port.
  7886.  
  7887.       msg     db      'This is a test message'
  7888.       msg_len equ     $-msg
  7889.               .
  7890.               .
  7891.               .
  7892.               mov     bx,seg msg      ; DS:BX = address of message
  7893.               mov     ds,bx
  7894.               mov     bx,offset msg
  7895.               mov     cx,msg_len      ; CX = length of message
  7896.               mov     dx,0            ; DX = 0 for LPT1
  7897.       L1:     mov     al,[bx]         ; get next character into AL
  7898.               mov     ah,00h          ; subfunction 00H = output
  7899.               int     17h             ; transfer to ROM BIOS
  7900.               inc     bx              ; bump pointer to output string
  7901.               loop    L1              ; and loop until all chars. sent
  7902.  
  7903.       Example: Use the traditional MS-DOS function call to send a string to
  7904.       the first parallel printer port.
  7905.  
  7906.       msg     db      'This is a test message'
  7907.       msg_len equ     $-msg
  7908.               .
  7909.               .
  7910.               .
  7911.               mov     bx,seg msg      ; DS:BX = address of message
  7912.               mov     ds,bx
  7913.               mov     bx,offset msg
  7914.               mov     cx,msg_len      ; CX = length of message
  7915.       L1:     mov     dl,[bx]         ; get next character into DL
  7916.               mov     ah,05h          ; function 05H = printer output
  7917.               int     21h             ; transfer to MS-DOS
  7918.               inc     bx              ; bump pointer to output string
  7919.               loop    L1              ; and loop until all chars. sent
  7920.  
  7921.       Example: Use the handle-based MS-DOS Write File or Device call and the
  7922.       predefined handle for the standard printer to send a string to the
  7923.       system list device.
  7924.  
  7925.       msg     db      'This is a test message'
  7926.       msg_len equ     $-msg
  7927.               .
  7928.               .
  7929.               .
  7930.               mov     dx,seg msg      ; DS:DX = address of message
  7931.               mov     ds,dx
  7932.               mov     dx,offset msg
  7933.               mov     cx,msg_len      ; CX = length of message
  7934.               mov     bx,4            ; BX = handle for standard printer
  7935.               mov     ah,40h          ; function 40H = write file/device
  7936.               int     21h             ; transfer to MS-DOS
  7937.               jc      error           ; jump if write operation failed
  7938.  
  7939.  
  7940.  IOCTL
  7941.  
  7942.       In versions 2.0 and later, MS-DOS has provided applications with the
  7943.       ability to communicate directly with device drivers through a set of
  7944.       subfunctions grouped under Interrupt 21H Function 44H (IOCTL). See
  7945.       SYSTEM CALLS: INTERRUPT 21H: Function 44H. The IOCTL subfunctions that
  7946.       are particularly applicable to the character I/O needs of application
  7947.       programs are
  7948.  
  7949. ╓┌────────────────────────────┌──────────────────────────────────────────────╖
  7950.       Subfunction             Name
  7951.       ──────────────────────────────────────────────────────────────────
  7952.       00H                     Get Device Data
  7953.       01H                     Set Device Data
  7954.       02H                     Receive Control Data from Character Device
  7955.       03H                     Send Control Data to Character Device
  7956.       06H                     Check Input Status
  7957.       07H                     Check Output Status
  7958.       0AH                     Check if Handle is Remote (version 3.1 or
  7959.                               later)
  7960.       0CH                     Generic I/O Control for Handles: Get/Set
  7961.       Subfunction             Name
  7962.      0CH                     Generic I/O Control for Handles: Get/Set
  7963.                               Output Iteration Count
  7964.  
  7965.       Various bits in the device information word returned by Subfunction
  7966.       00H can be tested by an application to determine whether a specific
  7967.       handle is associated with a character device or a file and whether the
  7968.       driver for the device can process control strings passed by
  7969.       Subfunctions 02H and 03H. The device information word also allows the
  7970.       program to test whether a character device is the CLOCK$, standard
  7971.       input, standard output, or NUL device and whether the device is in raw
  7972.       or cooked mode. The program can then use Subfunction 01H to select raw
  7973.       mode or cooked mode for subsequent I/O performed with the handle.
  7974.  
  7975.       Subfunctions 02H and 03H allow control strings to be passed between
  7976.       the device driver and an application; they do not usually result in
  7977.       any physical I/O to the device. For example, a custom device driver
  7978.       might allow an application program to configure the serial port by
  7979.       writing a specific set of control parameters to the driver with
  7980.       Subfunction 03H. Similarly, the custom driver might respond to
  7981.       Subfunction 02H by passing the application a series of bytes that
  7982.       defines the current configuration and status of the serial port.
  7983.  
  7984.       Subfunctions 06H and 07H can be used by application programs to test
  7985.       whether a device is ready to accept an output character or has a
  7986.       character ready for input. These subfunctions are particularly
  7987.       applicable to the serial communications ports and parallel printer
  7988.       ports because MS-DOS does not supply traditional function calls to
  7989.       test their status.
  7990.  
  7991.       Subfunction 0AH can be used to determine whether the character device
  7992.       associated with a handle is local or remote--that is, attached to the
  7993.       computer the program is running on or attached to another computer on
  7994.       a local area network. A program should not ordinarily attempt to
  7995.       distinguish between local and remote devices during normal input and
  7996.       output, but the information can be useful in attempts to recover from
  7997.       error conditions. This subfunction is available only if Microsoft
  7998.       Networks is running.
  7999.  
  8000.       Finally, Subfunction 0CH allows a program to query or set the number
  8001.       of times a device driver tries to send output to the printer before
  8002.       assuming the device is not available.
  8003.  
  8004.  IOCTL programming examples
  8005.  
  8006.       Example: Use IOCTL Subfunction 00H to obtain the device information
  8007.       word for the standard input handle and save it, and then use
  8008.       Subfunction 01H to place standard input into raw mode.
  8009.  
  8010.       info    dw      ?               ; save device information word here
  8011.               .
  8012.               .
  8013.               .
  8014.               mov     ax,4400h        ; AH = function 44H, IOCTL
  8015.                                       ; AL = subfunction 00H, get device
  8016.                                       ; information word
  8017.               mov     bx,0            ; BX = handle for standard input
  8018.               int     21h             ; transfer to MS-DOS
  8019.               mov     info,dx         ; save device information word
  8020.                                       ; (assumes DS = data segment)
  8021.               or      dl,20h          ; set raw mode bit
  8022.               mov     dh,0            ; and clear DH as MS-DOS requires
  8023.               mov     ax,4401h        ; AL = subfunction 01H, set device
  8024.                                       ; information word
  8025.                                       ; (BX still contains handle)
  8026.               int     21h             ; transfer to MS-DOS
  8027.  
  8028.       Example: Use IOCTL Subfunction 06H to test whether a character is
  8029.       ready for input on the first serial port. The function returns AL =
  8030.       0FFH if a character is ready and AL = 00H if not.
  8031.  
  8032.               mov     ax,4406H        ; AH = function 44H, IOCTL
  8033.                                       ; AL = subfunction 06H, get
  8034.                                       ; input status
  8035.               mov     bx,3            ; BX = handle for standard aux
  8036.               int     21h             ; transfer to MS-DOS
  8037.               or      al,al           ; test status of AUX driver
  8038.               jnz     ready           ; jump if input character ready
  8039.                                       ; else no character is waiting
  8040.  
  8041.                                                    Jim Kyle
  8042.                                                    Chip Rabinowitz
  8043.  
  8044.  
  8045.  
  8046.  Article 6:  Interrupt-Driven Communications
  8047.  
  8048.  
  8049.       In the earliest days of personal-computer communications, when speeds
  8050.       were no faster than 300 bits per second, primitive programs that moved
  8051.       characters to and from the remote system were adequate. The PC had
  8052.       time between characters to determine what it ought to do next and
  8053.       could spend that time keeping track of the status of the remote
  8054.       system.
  8055.  
  8056.       Modern data-transfer rates, however, are four to eight times faster
  8057.       and leave little or no time to spare between characters. At 1200 bits
  8058.       per second, as many as three characters can be lost in the time
  8059.       required to scroll the display up one line. At such speeds, a
  8060.       technique to permit characters to be received and simultaneously
  8061.       displayed becomes necessary.
  8062.  
  8063.       Mainframe systems have long made use of hardware interrupts to
  8064.       coordinate such activities. The processor goes about its normal
  8065.       activity; when a peripheral device needs attention, it sends an
  8066.       interrupt request to the processor. The processor interrupts its
  8067.       activity, services the request, and then goes back to what it was
  8068.       doing. Because the response is driven by the request, this type of
  8069.       processing is known as interrupt-driven. It gives the effect of doing
  8070.       two things at the same time without requiring two separate processors.
  8071.  
  8072.       Successful telecommunication with PCs at modern data rates demands an
  8073.       interrupt-driven routine for data reception. This article discusses in
  8074.       detail the techniques for interrupt-driven communications and
  8075.       culminates in two sample program packages.
  8076.  
  8077.       The article begins by establishing the purpose of communications
  8078.       programs and then discusses the capability of the simple functions
  8079.       provided by MS-DOS to achieve this goal. To see what must be done to
  8080.       supplement MS-DOS functions, the hardware (both the modem and the
  8081.       serial port) is examined. This leads to a discussion of the method
  8082.       MS-DOS has provided since version 2.0 for solving the problems of
  8083.       special hardware interfacing: the installable device driver.
  8084.  
  8085.       With the background established, alternate paths to interrupt-driven
  8086.       communications are discussed--one following recommended MS-DOS
  8087.       techniques, the other following standard industry practice--and
  8088.       programs are developed for each.
  8089.  
  8090.       Throughout this article, the discussion is restricted to the
  8091.       architecture and BIOS of the IBM PC family. MS-DOS systems not totally
  8092.       compatible with this architecture may require substantially different
  8093.       approaches at the detailed level, but the same general principles
  8094.       apply.
  8095.  
  8096.  
  8097.  Purpose of Communications Programs
  8098.  
  8099.       The primary purpose of any communications program is communicating--
  8100.       that is, transmitting information entered as keystrokes (or bytes read
  8101.       from a file) in a form suitable for transmission to a remote computer
  8102.       via phone lines and, conversely, converting information received from
  8103.       the remote computer into a display on the video screen (or data in a
  8104.       file).
  8105.  
  8106.       Some years ago, the most abstract form of all communications programs
  8107.       was dubbed a modem engine, by analogy to Babbage's analytical engine
  8108.       or the inference-engine model used in artificial-intelligence
  8109.       development. The functions of the modem engine are common to all kinds
  8110.       of communications programs, from the simplest to the most complex, and
  8111.       can be described in a type of pseudo-C as follows:
  8112.  
  8113.       The Modem Engine Pseudocode
  8114.  
  8115.            DO {  IF (input character is available)
  8116.                     send_it_to_remote;
  8117.                  IF (remote character is available)
  8118.                     use_it_locally;
  8119.               } UNTIL (told_to_stop);
  8120.  
  8121.       The essence of this modem-engine code is that the absence of an input
  8122.       character, or of a character from the remote computer, does not hang
  8123.       the loop in a wait state. Rather, the engine continues to cycle: If it
  8124.       finds work to do, it does it; if not, the engine keeps looking.
  8125.  
  8126.       Of course, at times it is desirable to halt the continuous action of
  8127.       the modem engine. For example, when receiving a long message, it is
  8128.       nice to be able to pause and read the message before the lines scroll
  8129.       into oblivion. On the other hand, taking too long to study the screen
  8130.       means that incoming characters are lost. The answer is a technique
  8131.       called flow control, in which a special control character is sent to
  8132.       shut down transmission and some other character is later sent to start
  8133.       it up again.
  8134.  
  8135.       Several conventions for flow control exist. One of the most widespread
  8136.       is known as XON/XOFF, from the old Teletype-33 keycap legends for the
  8137.       two control codes involved. In the original use, XOFF halted the paper
  8138.       tape reader and XON started it going again. In mid-1967, the General
  8139.       Electric Company began using these signals in its time-sharing
  8140.       computer services to control the flow of data, and the practice
  8141.       rapidly spread throughout the industry.
  8142.  
  8143.       The sample program named ENGINE, shown later in this article, is an
  8144.       almost literal implementation of the modem-engine approach. This
  8145.       sample represents one extreme of simplicity in communications
  8146.       programs. The other sample program, CTERM.C, is much more complex, but
  8147.       the modem engine is still at its heart.
  8148.  
  8149.  
  8150.  Using Simple MS-DOS Functions
  8151.  
  8152.       Because MS-DOS provides, among its standard service functions, the
  8153.       capability of sending output to or reading input from the device named
  8154.       AUX (which defaults to COM1, the first serial port on most machines),
  8155.       a first attempt at implementing the modem engine using MS-DOS
  8156.       functions might look something like the following incomplete fragment
  8157.       of Microsoft Macro Assembler (MASM) code:
  8158.  
  8159.       ;Incomplete (and Unworkable) Implementation
  8160.  
  8161.       LOOP:   MOV     AH,08h          ; read keyboard, no echo
  8162.               INT     21h
  8163.               MOV     DL,AL           ; set up to send
  8164.               MOV     AH,04h          ; send to AUX device
  8165.               INT     21h
  8166.               MOV     AH,03h          ; read from AUX device
  8167.               INT     21h
  8168.               MOV     DL,AL           ; set up to send
  8169.               MOV     AH,02h          ; send to screen
  8170.               INT     21h
  8171.               JMP     LOOP            ; keep doing it
  8172.  
  8173.       The problem with this code is that it violates the keep-looking
  8174.       principle both at the keyboard and at the AUX port: Interrupt 21H
  8175.       Function 08H does not return until a keyboard character is available,
  8176.       so no data from the AUX port can be read until a key is pressed
  8177.       locally. Similarly, Function 03H waits for a character to become
  8178.       available from AUX, so no more keys can be recognized locally until
  8179.       the remote system sends a character. If nothing is received, the loop
  8180.       waits forever.
  8181.  
  8182.       To overcome the problem at the keyboard end, Function 0BH can be used
  8183.       to determine if a key has been pressed before an attempt is made to
  8184.       read one, as shown in the following modification of the fragment:
  8185.  
  8186.       ;Improved, (but Still Unworkable) Implementation
  8187.  
  8188.       LOOP:   MOV     AH,0Bh          ; test keyboard for char
  8189.               INT     21h
  8190.               OR      AL,AL           ; test for zero
  8191.               JZ      RMT             ; no char avail, skip
  8192.               MOV     AH,08h          ; have char, read it in
  8193.               INT     21h
  8194.               MOV     DL,AL           ; set up to send
  8195.               MOV     AH,04h          ; send to AUX device
  8196.               INT     21h
  8197.       RMT:
  8198.               MOV     AH,03h          ; read from AUX device
  8199.               INT     21h
  8200.               MOV     DL,AL           ; set up to send
  8201.               MOV     AH,02h          ; send to screen
  8202.               INT     21h
  8203.               JMP     LOOP            ; keep doing it
  8204.  
  8205.       This code permits any input from AUX to be received without waiting
  8206.       for a local key to be pressed, but if AUX is slow about providing
  8207.       input, the program waits indefinitely before checking the keyboard
  8208.       again. Thus, the problem is only partially solved.
  8209.  
  8210.       MS-DOS, however, simply does not provide any direct method of making
  8211.       the required tests for AUX or, for that matter, any of the serial port
  8212.       devices. That is why communications programs must be treated
  8213.       differently from most other types of programs under MS-DOS and why
  8214.       such programs must be intimately involved with machine details despite
  8215.       all accepted principles of portable program design.
  8216.  
  8217.  
  8218.  The Hardware Involved
  8219.  
  8220.       Personal-computer communications require at least two distinct pieces
  8221.       of hardware (separate devices, even though they are often combined on
  8222.       a single board). These hardware items are the serial port, which
  8223.       converts data from the computer's internal bus into a bit stream for
  8224.       transmission over a single external line, and the modem, which
  8225.       converts the bit stream into a form suitable for telephone-line (or,
  8226.       sometimes, radio) transmission.
  8227.  
  8228.  The modem
  8229.  
  8230.       The modem (a word coined from MOdulator-DEModulator) is a device that
  8231.       converts a stream of bits, represented as sequential changes of
  8232.       voltage level, into audio frequency signals suitable for transmission
  8233.       over voice-grade telephone circuits (modulation) and converts these
  8234.       signals back into a stream of bits that duplicates the original input
  8235.       (demodulation).
  8236.  
  8237.       Specific characteristics of the audio signals involved were
  8238.       established by AT&T when that company monopolized the modem industry,
  8239.       and those characteristics then evolved into de facto standards when
  8240.       the monopoly vanished. They take several forms, depending on the data
  8241.       rate in use; these forms are normally identified by the original Bell
  8242.       specification number, such as 103 (for 600 bps and below) or 212A (for
  8243.       the 1200 bps standard).
  8244.  
  8245.       The data rate is measured in bits per second (bps), often mistermed
  8246.       baud or even "baud per second." A baud measures the number of signals
  8247.       per second; as with knot (nautical miles per hour), the time reference
  8248.       is built in. If one signal change marks one bit, as is true for the
  8249.       Bell 103 standard, then baud and bps have equal values. However, they
  8250.       are not equivalent for more complex signals. For example, the Bell
  8251.       212A diphase standard for 1200 bps uses two tone streams, each
  8252.       operating at 600 baud, to transmit data at 1200 bits per second.
  8253.  
  8254.       For accuracy, this article uses bps, rather than baud, except where
  8255.       widespread industry misuse of baud has become standardized (as in
  8256.       "baud rate generator").
  8257.  
  8258.       Originally, the modem itself was a box connected to the computer's
  8259.       serial port via a cable. Characteristics of this cable, its
  8260.       connectors, and its signals were standardized in the 1960s by the
  8261.       Electronic Industries Association (EIA), in Standard RS232C. Like the
  8262.       Bell standards for modems, RS232C has survived almost unchanged. Its
  8263.       characteristics are listed in Table 6-1.
  8264.  
  8265.  
  8266.       Table 6-1. RS232C Signals.
  8267.  
  8268. ╓┌─────────────────────┌──────────┌───────────┌──────────────────────────────╖
  8269.       DB25 Pin         232        Name        Description
  8270.       ──────────────────────────────────────────────────────────────────
  8271.        1                                      Safety Ground
  8272.        2               BA         TXD         Transmit Data
  8273.        3               BB         RXD         Receive Data
  8274.        4               CA         RTS         Request To Send
  8275.        5               CB         CTS         Clear To Send
  8276.       DB25 Pin         232        Name        Description
  8277.       5               CB         CTS         Clear To Send
  8278.        6               CC         DSR         Data Set Ready
  8279.        7               AB         GND         Signal Ground
  8280.        8               CF         DCD         Data Carrier Detected
  8281.       20               CD         DTR         Data Terminal Ready
  8282.       22               CE         RI          Ring Indicator
  8283.  
  8284.  
  8285.       With the increasing popularity of personal computers, internal modems
  8286.       that plug into the PC's motherboard and combine the modem and a serial
  8287.       port became available.
  8288.  
  8289.       The first such units were manufactured by Hayes Corporation, and like
  8290.       Bell and the EIA, they created a standard. Functionally, the internal
  8291.       modem is identical to the combination of a serial port, a connecting
  8292.       cable, and an external modem.
  8293.  
  8294.  The serial port
  8295.  
  8296.       Each serial port of a standard IBM PC connects the rest of the system
  8297.       to a type INS8250 Universal Asynchronous Receiver Transmitter (UART)
  8298.       integrated circuit (IC) chip developed by National Semiconductor
  8299.       Corporation. This chip, along with associated circuits in the port,
  8300.  
  8301.       1. Converts data supplied via the system data bus into a sequence of
  8302.          voltage levels on the single TXD output line that represent binary
  8303.          digits.
  8304.  
  8305.       2. Converts data received as a sequence of binary levels on the single
  8306.          RXD input line into bytes for the data bus.
  8307.  
  8308.       3. Controls the modem's actions through the DTR and RTS output lines.
  8309.  
  8310.       4. Provides status information to the processor; this information
  8311.          comes from the modem, via the DSR, DCD, CTS, and RI input lines,
  8312.          and from within the UART itself, which signals data available, data
  8313.          needed, or error detected.
  8314.  
  8315.       The word asynchronous in the name of the IC comes from the Bell
  8316.       specifications. When computer data is transmitted, each bit's
  8317.       relationship to its neighbors must be preserved; this can be done in
  8318.       either of two ways. The most obvious method is to keep the bit stream
  8319.       strictly synchronized with a clock signal of known frequency and count
  8320.       the cycles to identify the bits. Such a transmission is known as
  8321.       synchronous, often abbreviated to synch or sometimes bisync for binary
  8322.       synchronous. The second method, first used with mechanical
  8323.       teleprinters, marks the start of each bit group with a defined start
  8324.       bit and the end with one or more defined stop bits, and it defines a
  8325.       duration for each bit time. Detection of a start bit marks the
  8326.       beginning of a received group; the signal is then sampled at each bit
  8327.       time until the stop bit is encountered. This method is known as
  8328.       asynchronous (or just asynch) and is the one used by the standard
  8329.       IBM PC.
  8330.  
  8331.       The start bit is, by definition, exactly the same as that used to
  8332.       indicate binary zero, and the stop bit is the same as that indicating
  8333.       binary one. A zero signal is often called SPACE, and a one signal is
  8334.       called MARK, from terms used in the teleprinter industry.
  8335.  
  8336.       During transmission, the least significant bit of the data is sent
  8337.       first, after the start bit. A parity bit, if used, appears as the most
  8338.       significant bit in the data group, before the stop bit or bits; it
  8339.       cannot be distinguished from a databit except by its position. Once
  8340.       the first stop bit is sent, the line remains in MARK (sometimes called
  8341.       idling) condition until a new start bit indicates the beginning of
  8342.       another group.
  8343.  
  8344.       In most PC uses, the serial port transfers one 8-bit byte at a time,
  8345.       and the term word specifies a 16-bit quantity. In the UART world,
  8346.       however, a word is the unit of information sent by the chip in each
  8347.       chunk. The word length is part of the control information set into the
  8348.       chip during setup operations and can be 5, 6, 7, or 8 bits. This
  8349.       discussion follows UART conventions and refers to words, rather than
  8350.       to bytes.
  8351.  
  8352.       One special type of signal, not often used in PC-to-PC communications
  8353.       but sometimes necessary in communicating with mainframe systems, is a
  8354.       BREAK. The BREAK is an all-SPACE condition that extends for more than
  8355.       one word time, including the stop-bit time. (Many systems require the
  8356.       BREAK to last at least 150 milliseconds regardless of data rate.)
  8357.       Because it cannot be generated by any normal data character
  8358.       transmission, the BREAK is used to interrupt, or break into, normal
  8359.       operation. The IBM PC's 8250 UART can generate the BREAK  signal, but
  8360.       its duration must be determined by a program, rather than by the chip.
  8361.  
  8362.  The 8250 UART architecture
  8363.  
  8364.       The 8250 UART contains four major functional areas: receiver,
  8365.       transmitter, control circuits, and status circuits. Because these
  8366.       areas are closely related, some terms used in the following
  8367.       descriptions are, of necessity, forward references to subsequent
  8368.       paragraphs.
  8369.  
  8370.       The major parts of the receiver are a shift register and a data
  8371.       register called the Received Data Register. The shift register
  8372.       assembles sequentially received data into word-parallel form by
  8373.       shifting the level of the RXD line into its front end at each bit time
  8374.       and, at the same time, shifting previous bits over. When the shift
  8375.       register is full, all bits in it are moved over to the data register,
  8376.       the shift register is cleared to all zeros, and the bit in the status
  8377.       circuits that indicates data ready is set. If an error is detected
  8378.       during receipt of that word, other bits in the status circuits are
  8379.       also set.
  8380.  
  8381.       Similarly, the major parts of the transmitter are a holding register
  8382.       called the Transmit Holding Register and a shift register. Each word
  8383.       to be transmitted is transferred from the data bus to the holding
  8384.       register. If the holding register is not empty when this is done, the
  8385.       previous contents are lost. The transmitter's shift register converts
  8386.       word-parallel data into bit-serial form for transmission by shifting
  8387.       the most significant bit out to the TXD line once each bit time, at
  8388.       the same time shifting lower bits over and shifting in an idling bit
  8389.       at the low end of the register. When the last databit has been shifted
  8390.       out, any data in the holding register is moved to the shift register,
  8391.       the holding register is filled with idling bits in case no more data
  8392.       is forthcoming, and the bit in the status circuits that indicates the
  8393.       Transmit Holding Register is empty is set to indicate that another
  8394.       word can be transferred. The parity bit, if any, and stop bits are
  8395.       added to the transmitted stream after the last databit of each word is
  8396.       shifted out.
  8397.  
  8398.       The control circuits establish three communications features: first,
  8399.       line control values, such as word length, whether or not (and how)
  8400.       parity is checked, and the number of stop bits; second, modem control
  8401.       values, such as the state of the DTR and RTS output lines; and third,
  8402.       the rate at which data is sent and received. These control values are
  8403.       established by two 8-bit registers and one 16-bit register, which are
  8404.       addressed as four 8-bit registers. They are the Line Control Register
  8405.       (LCR), the Modem Control Register (MCR), and the 16-bit BRG Divisor
  8406.       Latch, addressed as Baud0 and Baud1.
  8407.  
  8408.       The BRG Divisor Latch sets the data rate by defining the bit time
  8409.       produced by the Programmable Baud Rate Generator (PBRG), a major part
  8410.       of the control circuits. The PBRG can provide any data speed from a
  8411.       few bits per second to 38400 bps; in the BIOS of the IBM PC, PC/XT,
  8412.       and PC/AT, though, only the range 110 through 9600 bps is supported.
  8413.       How the LCR and the MCR establish their control values, how the PBRG
  8414.       is programmed, and how interrupts are enabled are discussed later.
  8415.  
  8416.       The fourth major area in the 8250 UART, the status circuits, records
  8417.       (in a pair of status registers) the conditions in the receive and
  8418.       transmit circuits, any errors that are detected, and any change in
  8419.       state of the RS232C input lines from the modem. When any status
  8420.       register's content changes, an interrupt request, if enabled, is
  8421.       generated to notify the rest of the PC system. This approach lets the
  8422.       PC attend to other matters without having to continually monitor the
  8423.       status of the serial port, yet it assures immediate action when
  8424.       something does occur.
  8425.  
  8426.  The 8250 programming interface
  8427.       Not all the registers mentioned in the preceding section are
  8428.       accessible to programmers. The shift registers, for example, can be
  8429.       read from or written to only by the 8250's internal circuits. There
  8430.       are 10 registers available to the programmer, and they are accessed by
  8431.       only seven distinct addresses (shown in Table 6-2). The Received Data
  8432.       Register and the Transmit Holding Register share a single address (a
  8433.       read gets the received data; a write goes to the holding register). In
  8434.       addition, both this address and that of the Interrupt Enable Register
  8435.       (IER) are shared with the PBRG Divisor Latch. A bit in the Line
  8436.       Control Register called the Divisor Latch Access Bit (DLAB) determines
  8437.       which register is addressed at any specific time.
  8438.  
  8439.       In the IBM PC, the seven addresses used by the 8250 are selected by
  8440.       the low 3 bits of the port number (the higher bits select the specific
  8441.       port). Thus, each serial port occupies eight positions in the address
  8442.       space. However, only the lowest address used--the one in which the low
  8443.       3 bits are all 0--need be remembered in order to access all eight
  8444.       addresses.
  8445.  
  8446.       Because of this, any serial port in the PC is referred to by an
  8447.       address that, in hexadecimal notation, ends with either 0 or 8: The
  8448.       COM1 port normally uses address 03F8H, and COM2 uses 02F8H. This
  8449.       lowest port address is usually called the base port address, and each
  8450.       addressable register is then referenced as an offset from this base
  8451.       value, as shown in Table 6-2.
  8452.  
  8453.  
  8454.       Table 6-2. 8250 Port Offsets from Base Address.
  8455.  
  8456. ╓┌────────────────┌──────────────────────┌───────────────────────────────────╖
  8457.       Offset      Name                   Description
  8458.       ──────────────────────────────────────────────────────────────────
  8459.       If DLAB bit in LCR = 0:
  8460.       00H         DATA                   Received Data Register if
  8461.                                          read from, Transmit Holding
  8462.                                          Register if written to
  8463.       01H         IER                    Interrupt Enable Register
  8464.  
  8465.       Offset      Name                   Description
  8466. 
  8467.       If DLAB bit in LCR = 1:
  8468.       00H         Baud0                  BRG Divisor Latch, low byte
  8469.       01H         Baud1                  BRG Divisor Latch, high byte
  8470.  
  8471.       Not affected by DLAB bit:
  8472.       02H         IID                    Interrupt Identifier Register
  8473.       03H         LCR                    Line Control Register
  8474.       04H         MCR                    Modem Control Register
  8475.       05H         LSR                    Line Status Register
  8476.       06H         MSR                    Modem Status Register
  8477.  
  8478.  
  8479.  The control circuits
  8480.       The control circuits of the 8250 include the Programmable Baud Rate
  8481.       Generator (PBRG), the Line Control Register (LCR), the Modem Control
  8482.       Register (MCR), and the Interrupt Enable Register (IER).
  8483.  
  8484.       The PBRG establishes the bit time used for both transmitting and
  8485.       receiving data by dividing an external clock signal. To select a
  8486.       desired bit rate, the appropriate divisor is loaded into the PBRG's
  8487.       16-bit Divisor Latch by setting the Divisor Latch Access Bit (DLAB) in
  8488.       the Line Control Register to 1 (which changes the functions of
  8489.       addresses 0 and 1) and then writing the divisor into Baud0 and Baud1.
  8490.       After the bit rate is selected, DLAB is changed back to 0, to permit
  8491.       normal operation of the DATA registers and the IER.
  8492.  
  8493.       With the 1.8432 MHz external UART clock frequency used in standard IBM
  8494.       systems, divisor values (in decimal notation) for bit rates between
  8495.       45.5 and 38400 bps are listed in Table 6-3. These speeds are
  8496.       established by a crystal contained in the serial port (or internal
  8497.       modem) and are totally unrelated to the speed of the processor's
  8498.       clock.
  8499.  
  8500.  
  8501.       Table 6-3. Bit Rate Divisor Table for 8250/IBM.
  8502.  
  8503. ╓┌─────────────────┌─────────────────────────────────────────────────────────╖
  8504.       BPS          Divisor
  8505.       ──────────────────────────────────────────────────────────────────
  8506.          45.5      2532
  8507.       BPS          Divisor
  8508.         45.5      2532
  8509.          50        2304
  8510.          75        1536
  8511.         110        1047
  8512.         134.5       857
  8513.         150         768
  8514.         300         384
  8515.         600         192
  8516.        1200          96
  8517.        1800          64
  8518.        2000          58
  8519.        2400          48
  8520.        4800          24
  8521.        9600          12
  8522.       19200           6
  8523.       38400           3
  8524.  
  8525.  
  8526.       The remaining control circuits are the Line Control Register, the
  8527.       Modem Control Register, and the Interrupt Enable Register. Bits in the
  8528.       LCR control the assignment of offsets 0 and 1, transmission of the
  8529.       BREAK signal, parity generation, the number of stop bits, and the word
  8530.       length sent and received, as shown in Table 6-4.
  8531.  
  8532.  
  8533.       Table 6-4. 8250 Line Control Register Bit Values.
  8534.  
  8535. ╓┌─────────────────┌─────────┌─────────────┌─────────────────────────────────╖
  8536.       Bit             Name      Binary     Meaning
  8537.       ──────────────────────────────────────────────────────────────────
  8538.       Address Control:
  8539.       7               DLAB      0xxxxxxx   Offset 0 refers to DATA;
  8540.                                            offset 1 refers to IER
  8541.                                 1xxxxxxx   Offsets 0 and 1 refer to BRG
  8542.                                            Divisor Latch
  8543.  
  8544.       BREAK Control:
  8545.       6               SETBRK    x0xxxxxx   Normal UART operation
  8546.                                 x1xxxxxx   Send BREAK signal
  8547.  
  8548.       Parity Checking:
  8549.       Bit             Name      Binary     Meaning
  8550.      Parity Checking:
  8551.       5,4,3           GENPAR    xxxx0xxx   No parity bit
  8552.                                 xx001xxx   Parity bit is ODD
  8553.                                 xx011xxx   Parity bit is EVEN
  8554.                                 xx101xxx   Parity bit is 1
  8555.                                 xx111xxx   Parity bit is 0
  8556.  
  8557.       Stop Bits:
  8558.       2               XSTOP     xxxxx0xx   Only 1 stop bit
  8559.                                 xxxxx1xx   2 stop bits(1.5 if WL = 5)
  8560.  
  8561.       Word Length:
  8562.       1,0             WD5       xxxxxx00   Word length = 5
  8563.                       WD6       xxxxxx01   Word length = 6
  8564.                       WD7       xxxxxx10   Word length = 7
  8565.                       WD8       xxxxxx11   Word length = 8
  8566.  
  8567.  
  8568.       Two bits in the MCR (Table 6-5) control output lines DTR and RTS; two
  8569.       other MCR bits (OUT1 and OUT2) are left free by the UART to be
  8570.       assigned by the user; a fifth bit (TEST) puts the UART into a self-
  8571.       test mode of operation. The upper 3 bits have no effect on the UART.
  8572.       The MCR can be both read from and written to.
  8573.  
  8574.       Both of the user-assignable bits are defined in the IBM PC. OUT1 is
  8575.       used by Hayes internal modems to cause a power-on reset of their
  8576.       circuits; OUT2 controls the passage of UART-generated interrupt
  8577.       request signals to the rest of the PC. Unless OUT2 is set to 1,
  8578.       interrupt signals from the UART cannot reach the rest of the PC, even
  8579.       though all other controls are properly set. This feature is
  8580.       documented, but obscurely, in the IBM Technical Reference manuals and
  8581.       the asynchronous-adapter schematic; it is easy to overlook when
  8582.       writing an interrupt-driven program for these machines.
  8583.  
  8584.  
  8585.       Table 6-5. 8250 Modem Control Register Bit Values.
  8586.  
  8587. ╓┌────────────┌───────────┌──────────────────────────────────────────────────╖
  8588.       Name    Binary      Description
  8589.       ──────────────────────────────────────────────────────────────────
  8590.       TEST    xxx1xxxx    Turns on UART self-test configuration.
  8591.       Name    Binary      Description
  8592.      TEST    xxx1xxxx    Turns on UART self-test configuration.
  8593.       OUT2    xxxx1xxx    Controls 8250 interrupt signals (User2 Output).
  8594.       OUT1    xxxxx1xx    Resets Hayes 1200b internal modem (User1 Output).
  8595.       RTS     xxxxxx1x    Sets RTS output to RS232C connector.
  8596.       DTR     xxxxxxx1    Sets DTR output to RS232C connector.
  8597.  
  8598.  
  8599.       The 8250 can generate any or all of four classes of interrupts, each
  8600.       individually enabled or disabled by setting the appropriate control
  8601.       bit in the Interrupt Enable Register (Table 6-6). Thus, setting the
  8602.       IER to 00H disables all the UART interrupts within the 8250 without
  8603.       regard to any other settings, such as OUT2, system interrupt masking,
  8604.       or the CLI/STI commands. The IER can be both read from and written to.
  8605.       Only the low 4 bits have any effect on the UART.
  8606.  
  8607.  
  8608.       Table 6-6. 8250 Interrupt Enable Register Constants.
  8609.  
  8610. ╓┌─────────────────┌─────────────────────────────────────────────────────────╖
  8611.       Binary       Action
  8612.       Binary       Action
  8613.       ──────────────────────────────────────────────────────────────────
  8614.       xxxx1xxx     Enable Modem Status Interrupt.
  8615.       xxxxx1xx     Enable Line Status Interrupt.
  8616.       xxxxxx1x     Enable Transmit Register Interrupt.
  8617.       xxxxxxx1     Enable Received Data Ready Interrupt.
  8618.  
  8619.  
  8620.  The status circuits
  8621.       The status circuits of the 8250 include the Line Status Register
  8622.       (LSR), the Modem Status Register (MSR), the Interrupt Identifier (IID)
  8623.       Register, and the interrupt-request generation system.
  8624.  
  8625.       The 8250 includes circuitry that detects a received BREAK signal and
  8626.       also detects three classes of data-reception errors. Separate bits in
  8627.       the LSR (Table 6-7) are set to indicate that a BREAK has been received
  8628.       and to indicate any of the following: a parity error (if lateral
  8629.       parity is in use), a framing error (incoming bit = 0 at stop-bit
  8630.       time), or an overrun error (word not yet read from receive buffer by
  8631.       the time the next word must be moved into it).
  8632.  
  8633.       The remaining bits of the LSR indicate the status of the Transmit
  8634.       Shift Register, the Transmit Holding Register, and the Received Data
  8635.       Register; the most significant bit of the LSR is not used and is
  8636.       always 0. The LSR is a read-only register; writing to it has no
  8637.       effect.
  8638.  
  8639.  
  8640.       Table 6-7. 8250 Line Status Register Bit Values.
  8641.  
  8642. ╓┌──────────────┌────────────────┌───────────────────────────────────────────╖
  8643.       Bit       Binary           Meaning
  8644.       ──────────────────────────────────────────────────────────────────
  8645.       7         0xxxxxxx         Always zero
  8646.       6         x1xxxxxx         Transmit Shift Register empty
  8647.       5         xx1xxxxx         Transmit Holding Register empty
  8648.       4         xxx1xxxx         BREAK received
  8649.       3         xxxx1xxx         Framing error
  8650.       2         xxxxx1xx         Parity error
  8651.       1         xxxxxx1x         Overrun error
  8652.       0         xxxxxxx1         Received data ready
  8653.  
  8654.  
  8655.       The MSR (Table 6-8) monitors the four RS232C lines that report modem
  8656.       status. The upper 4 bits of this register indicate the voltage level
  8657.       of the associated RS232C line; the lower 4 bits indicate that the
  8658.       voltage level has changed since the register was last read.
  8659.  
  8660.  
  8661.       Table 6-8. 8250 Modem Status Register Bit Values.
  8662.  
  8663. ╓┌──────────────┌──────────────────┌─────────────────────────────────────────╖
  8664.       Bit       Binary             Meaning
  8665.       ──────────────────────────────────────────────────────────────────
  8666.       7         1xxxxxxx           Data Carrier Detected (DCD) level
  8667.       6         x1xxxxxx           Ring Indicator (RI) level
  8668.       5         xx1xxxxx           Data Set Ready (DSR) level
  8669.       4         xxx1xxxx           Clear To Send (CTS) level
  8670.       3         xxxx1xxx           DCD change
  8671.       2         xxxxx1xx           RI change
  8672.       1         xxxxxx1x           DSR change
  8673.       0         xxxxxxx1           CTS change
  8674.  
  8675.  
  8676.       As mentioned previously, four types of interrupts are generated. The
  8677.       four types are identified by flag values in the IID Register (Table
  8678.       6-9). These flags are set as follows:
  8679.  
  8680.       ■  Change of any bit value in the MSR sets the modem status flag.
  8681.  
  8682.       ■  Setting of the BREAK Received bit or any of the three error bits in
  8683.          the LSR sets the line status flag.
  8684.  
  8685.       ■  Setting of the Transmit Holding Register Empty bit in the LSR sets
  8686.          the transmit flag.
  8687.  
  8688.       ■  Setting of the Received Data Ready bit in the LSR sets the receive
  8689.          flag.
  8690.  
  8691.       The IID register indicates the interrupt type, even though the IER may
  8692.       be disabling that type of interrupt from generating any request. The
  8693.       IID is a read-only register; attempts to write to it have no effect.
  8694.  
  8695.  
  8696.       Table 6-9. 8250 Interrupt Identification and Causes.
  8697.  
  8698. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  8699.       IID content      Meaning
  8700.       ──────────────────────────────────────────────────────────────────
  8701.       xxxxxxx1B        No interrupt active
  8702.  
  8703.       xxxxx000B        Modem Status Interrupt; bit changed in MSR
  8704.  
  8705.       xxxxx010B        Transmit Register Interrupt; Transmit Holding
  8706.                        Register empty, bitset in LSR
  8707.  
  8708.       xxxxx100B        Received Data Ready Interrupt; Data Register full,
  8709.                        bit set in LSR
  8710.  
  8711.       xxxxx110B        Line Status Interrupt; BREAK or error bit set in LSR
  8712.  
  8713.  
  8714.       As shown in Table 6-9, an all-zero value (which in most of the other
  8715.       registers is a totally disabling condition) means that a Modem Status
  8716.       Interrupt condition has not yet been serviced. A modem need not be
  8717.       connected, however, for a Modem Status Interrupt condition to occur;
  8718.       all that is required is for one of the RS232C non-data input lines to
  8719.       change state, thus changing the MSR.
  8720.  
  8721.       Whenever a flag is set in the IID, the UART interrupt-request
  8722.       generator will, if enabled by the UART programming, generate an
  8723.       interrupt request to the processor. Two or more interrupts can be
  8724.       active at the same time; if so, more than one flag in the IID register
  8725.       is set.
  8726.  
  8727.       The IID flag for each interrupt type (and the LSR or MSR bits
  8728.       associated with it) clears when the corresponding register is read
  8729.       (or, in one case, written to). For example, reading the content of the
  8730.       MSR clears the modem status flag; writing a byte to the DATA register
  8731.       clears the transmit flag; reading the DATA register clears the receive
  8732.       flag; reading the LSR clears the line status flag. The LSR or MSR bit
  8733.       does not clear until it has been read; the IID flag clears with the
  8734.       LSR or MSR bit.
  8735.  
  8736.  Programming the UART
  8737.       Each time power is applied, any serial-interface device must be
  8738.       programmed before it is used. This programming can be done by the
  8739.       computer's bootstrap sequence or as a part of the port initialization
  8740.       routines performed when a port driver is installed. Often, both
  8741.       techniques are used: The bootstrap provides default conditions, and
  8742.       these can be modified during initialization to meet the needs of each
  8743.       port driver used in a session.
  8744.  
  8745.       When the 8250 chip is programmed, the BRG Divisor Latch should be set
  8746.       for the proper baud rate, the LCR and MCR should be loaded, the IER
  8747.       should be set, and all internal interrupt requests and the receive
  8748.       buffer should be cleared. The sequence in which these are done is not
  8749.       especially critical, but any pending interrupt requests should be
  8750.       cleared before they are permitted to pass on to the rest of the PC.
  8751.  
  8752.       The following sample code performs these startup actions, setting up
  8753.       the chip in device COM1 (at port 03F8H) to operate at 1200 bps with a
  8754.       word length of 8 bits, no parity checking, and all UART interrupts
  8755.       enabled. (In practical code, all values for addresses and operating
  8756.       conditions would not be built in; these values are included in the
  8757.       example to clarify what is being done at each step.)
  8758.  
  8759.               MOV     DX,03FBh        ; base port COM1 (03F8) + LCR (3)
  8760.               MOV     AL,080h         ; enable Divisor Latch
  8761.               OUT     DX,AL
  8762.               MOV     DX,03F8h        ; set for Baud0
  8763.               MOV     AX,96           ; set divisor to 1200 bps
  8764.               OUT     DX,AL
  8765.               INC     DX              ; to offset 1 for Baud1
  8766.               MOV     AL,AH           ; high byte of divisor
  8767.               OUT     DX,AL
  8768.               MOV     DX,03FBh        ; back to the LCR offset
  8769.               MOV     AL,03           ; DLAB = 0, Parity = N, WL = 8
  8770.               OUT     DX,AL
  8771.               MOV     DX,03F9h        ; offset 1 for IER
  8772.               MOV     AL,0Fh          ; enable all ints in 8250
  8773.               OUT     DX,AL
  8774.               MOV     DX,03FCh        ; COM1 + MCR (4)
  8775.               MOV     AL,0Bh          ; OUT2 + RTS + DTR bits
  8776.               OUT     DX,AL
  8777.       CLRGS:
  8778.               MOV     DX,03FDh        ; clear LSR
  8779.               IN      AL,DX
  8780.               MOV     DX,03F8h        ; clear RX reg
  8781.               IN      AL,DX
  8782.               MOV     DX,03FEh        ; clear MSR
  8783.               IN      AL,DX
  8784.               MOV     DX,03FAh        ; IID reg
  8785.               IN      AL,DX
  8786.               IN      AL,DX           ; repeat to be sure
  8787.               TEST    AL,1            ; int pending?
  8788.               JZ      CLRGS           ; yes, repeat
  8789.  
  8790.       Note: This code does not completely set up the IBM serial port.
  8791.       Although it fully programs the 8250 itself, additional work remains to
  8792.       be done. The system interrupt vectors must be changed to provide
  8793.       linkage to the interrupt service routine (ISR) code, and the 8259
  8794.       Priority Interrupt Controller (PIC) chip must also be programmed to
  8795.       respond to interrupt requests from the UART channels. See PROGRAMMING
  8796.       IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Hardware Interrupt
  8797.       Handlers.
  8798.  
  8799.  
  8800.  Device Drivers
  8801.  
  8802.       All versions of MS-DOS since 2.0 have permitted the installation of
  8803.       user-provided device drivers. From the standpoint of operating-system
  8804.       theory, using such drivers is the proper way to handle generic
  8805.       communications interfacing. The following paragraphs are intended as a
  8806.       refresher and to explain this article's departure from standard
  8807.       device-driver terminology. See PROGRAMMING IN THE MS-DOS ENVIRONMENT:
  8808.       CUSTOMIZING MS-DOS: Installable Device Drivers.
  8809.  
  8810.       An installable device driver consists of (1) a driver header that
  8811.       links the driver to others in the chain maintained by MS-DOS, tells
  8812.       the system the characteristics of this specific driver, provides
  8813.       pointers to the two major routines contained in the driver, and (for a
  8814.       character-device driver) identifies the driver by name; (2) any data
  8815.       and storage space the driver may require; and (3) the two major code
  8816.       routines.
  8817.  
  8818.       The code routines are called the Strategy routine and the Interrupt
  8819.       routine in normal device-driver descriptions. Neither has any
  8820.       connection with the hardware interrupts dealt with by the drivers
  8821.       presented in this article. Because of this, the term Request routine
  8822.       is used instead of Interrupt routine, so that hardware interrupt code
  8823.       can be called an interrupt service routine (ISR) with minimal chances
  8824.       for confusion.
  8825.  
  8826.       MS-DOS communicates with a device driver by reserving space for a
  8827.       command packet of as many as 22 bytes and by passing this packet's
  8828.       address to the driver with a call to the Strategy routine. All data
  8829.       transfer between MS-DOS and the driver, in both directions, occurs via
  8830.       this command packet and the Request routine. The operating system
  8831.       places a command code and, optionally, a byte count and a buffer
  8832.       address into the packet at the specified locations, then calls the
  8833.       Request routine. The driver performs the command and returns the
  8834.       status (and sometimes a byte count) in the packet.
  8835.  
  8836.  
  8837.  Two Alternative Approaches
  8838.  
  8839.       Now that the factors involved in creating interrupt-driven
  8840.       communications programs have been discussed, they can be put together
  8841.       into practical program packages. Doing so brings out not only general
  8842.       principles but also minor details that make the difference between
  8843.       success and failure of program design in this hardware-dependent and
  8844.       time-critical area.
  8845.  
  8846.  The traditional way: Going it alone
  8847.  
  8848.       Because MS-DOS provides no generic functions suitable for
  8849.       communications use, virtually all popular communications programs
  8850.       provide and install their own port driver code, and then remove it
  8851.       before returning to MS-DOS. This approach entails the creation of a
  8852.       communications handler for each program and requires the
  8853.       "uninstallation" of the handler on exit from the program that uses it.
  8854.       Despite the extra requirements, most communications programs use this
  8855.       method.
  8856.  
  8857.  The alternative: Creating a communications device driver
  8858.  
  8859.       Instead of providing temporary interface code that must be removed
  8860.       from the system before returning to the command level, an installable
  8861.       device driver can be built as a replacement for COMx so that every
  8862.       program can have all features. However, this approach is not
  8863.       compatible with existing terminal programs because it has never been a
  8864.       part of MS-DOS.
  8865.  
  8866.  Comparison of the two methods
  8867.  
  8868.       The traditional approach has several advantages, the most obvious
  8869.       being that the driver code can be fully tailored to the needs of the
  8870.       program. Because only one program will ever use the driver, no general
  8871.       cases need be considered.
  8872.  
  8873.       However, if a user wants to keep communications capability available
  8874.       in a terminate-and-stay-resident (TSR) module for background use and
  8875.       also wants a different type of communications program running in the
  8876.       foreground (not, of course, while the background task is using the
  8877.       port), the background program and the foreground job must each have
  8878.       its own  separate driver code. And, because such code usually includes
  8879.       buffer areas, the duplicated drivers represent wasted resources.
  8880.  
  8881.       A single communications device driver that is installed when the
  8882.       system powers up and that remains active until shutdown avoids wasting
  8883.       resources by allowing both the background and foreground tasks to
  8884.       share the driver code. Until such drivers are common, however, it is
  8885.       unlikely that commercial software will be able to make use of them. In
  8886.       addition, such a driver must either provide totally general
  8887.       capabilities or it must include control interfaces so each user
  8888.       program can dynamically alter the driver to suit its needs.
  8889.  
  8890.       At this time, the use of a single driver is an interesting exercise
  8891.       rather than a practical application, although a possible exception is
  8892.       a dedicated system in which all software is either custom designed or
  8893.       specially modified. In such a system, the generalized driver can
  8894.       provide significant improvement in the efficiency of resource
  8895.       allocation.
  8896.  
  8897.  
  8898.  A Device-Driver Program Package
  8899.  
  8900.       Despite the limitations mentioned in the preceding section, the first
  8901.       of the two complete packages in this article uses the concept of a
  8902.       separate device driver. The driver handles all hardware-dependent
  8903.       interfacing and thus permits extreme simplicity in all other modules
  8904.       of the package. This approach is presented first because it is
  8905.       especially well suited for introducing the concepts of communications
  8906.       programs. However, the package is not merely a tutorial device: It
  8907.       includes some features that are not available in most commercial
  8908.       programs.
  8909.  
  8910.       The package itself consists of three separate programs. First is the
  8911.       device driver, which becomes a part of MS-DOS via the CONFIG.SYS file.
  8912.       Second is the modem engine, which is the actual terminal program. (A
  8913.       functionally similar component forms the heart of every communications
  8914.       program, whether it is written in assembly language or a high-level
  8915.       language and regardless of the machine or operating system in use.)
  8916.       Third is a separately executed support program that permits changing
  8917.       such driver characteristics as word length, parity, and baud rate.
  8918.  
  8919.       In most programs that use the traditional approach, the driver and the
  8920.       support program are combined with the modem engine in a single unit
  8921.       and the resulting mass of detail obscures the essential simplicity of
  8922.       each part. Here, the parts are presented as separate modules to
  8923.       emphasize that simplicity.
  8924.  
  8925.  The device driver: COMDVR.ASM
  8926.  
  8927.       The device driver is written to augment the default COM1 and COM2
  8928.       devices with other devices named ASY1 and ASY2 that use the same
  8929.       physical hardware but are logically separate. The driver (COMDVR.ASM)
  8930.       is implemented in MASM and is shown in the listing in Figure 6-1.
  8931.       Although the driver is written basically as a skeleton, it is designed
  8932.       to permit extensive expansion and can be used as a general-purpose
  8933.       sample of device-driver source code.
  8934.  
  8935.  The code
  8936.  
  8937.       ──────────────────────────────────────────────────────────────────────
  8938.  
  8939.       Figure 6-1. COMDVR.ASM.
  8940.  
  8941.       ──────────────────────────────────────────────────────────────────────
  8942.  
  8943.  
  8944.       The first part of the driver source code (after the necessary MASM
  8945.       housekeeping details in lines 1 through 8) is a commented-out macro
  8946.       definition (lines 10 through 32). This macro is used only during
  8947.       debugging and is part of a debugging technique that requires no
  8948.       sophisticated hardware and no more complex debugging program than the
  8949.       venerable DEBUG.COM. (Debugging techniques are discussed after the
  8950.       presentation of the driver program itself.)
  8951.  
  8952.       Definitions
  8953.       The actual driver source program consists of three sets of EQU
  8954.       definitions (lines 34 through 194), followed by the modular code and
  8955.       data areas (lines 197 through 900). The first set of definitions
  8956.       (lines 34 through 82) gives symbolic names to the permissible values
  8957.       for MS-DOS device-driver control bits and the device-driver
  8958.       structures.
  8959.  
  8960.       The second set of definitions (lines 84 through 145) assigns names to
  8961.       the ports and bit values that are associated with the IBM hardware--
  8962.       both the 8259 PIC and the 8250 UART. The third set of definitions
  8963.       (lines 147 through 194) assigns names to the control values and
  8964.       structures associated with this driver.
  8965.  
  8966.       The definition method used here is recommended for all drivers. To
  8967.       move this driver from the IBM architecture to some other hardware, the
  8968.       major change required to the program would be reassignment of the port
  8969.       addresses and bit values in lines 84 through 145.
  8970.  
  8971.       The control values and structures for this specific driver (defined in
  8972.       the third EQU set) provide the means by which the separate support
  8973.       program can modify the actions of each of the two logical drivers.
  8974.       They also permit the driver to return status information to both the
  8975.       support program and the using program as necessary. Only a few
  8976.       features are implemented, but adequate space for expansion is
  8977.       provided. The addition of a few more definitions in this area and one
  8978.       or two extra procedures in the code section would do all that is
  8979.       necessary to extend the driver's capabilities to such features as
  8980.       automatic expansion of tab characters, case conversion, and so forth,
  8981.       should they be desired.
  8982.  
  8983.       Headers and structure tables
  8984.       The driver code itself starts with a linked pair of device-driver
  8985.       header blocks, one for ASY1 (lines 201 through 207) and the other for
  8986.       ASY2 (lines 208 through 213). Following the headers, in lines 215
  8987.       through 236, are a commented-out space reservation used by the
  8988.       debugging procedure (line 215), the pointer to the command packet
  8989.       (line 219), and the baud-rate conversion table (lines 221 through
  8990.       236).
  8991.  
  8992.       The conversion table is followed by structure tables containing all
  8993.       data unique to ASY1 (lines 239 through 242) and ASY2 (lines 244
  8994.       through 247). After the structure tables, buffer areas are reserved in
  8995.       lines 249 through 254. One input buffer and one output buffer are
  8996.       reserved for each port. All buffers are the same size; for simplicity,
  8997.       buffer size is given a name (at line 249) so that it can be changed by
  8998.       editing a single line of the program.
  8999.  
  9000.       The size is arbitrary in this case, but if file transfers are
  9001.       anticipated, the buffer should be able to hold at least 2 seconds'
  9002.       worth of data (240 bytes at 1200 bps) to avoid data loss during writes
  9003.       to disk. Whatever size is chosen should be a power of 2 for simple
  9004.       pointer arithmetic and, if video display is intended, should not be
  9005.       less than 8 bytes, to prevent losing characters when the screen
  9006.       scrolls.
  9007.  
  9008.       If additional ports are desired, more headers can be added after line
  9009.       213; corresponding structure tables for each driver, plus matching
  9010.       pairs of buffers, would also be necessary. The final part of this area
  9011.       is the dispatch table (lines 256 through 284), which lists offsets of
  9012.       all request routines in the driver; its use is discussed below.
  9013.  
  9014.       Strategy and Request routines
  9015.       With all data taken care of, the program code begins at the Strategy
  9016.       routine (lines 289 through 296), which is used by both ports. This
  9017.       code saves the command packet address passed to it by MS-DOS for use
  9018.       by the Request routine and returns to MS-DOS.
  9019.  
  9020.       The Request routines (lines 298 through 567) are also shared by both
  9021.       ports, but the two drivers are distinguished by the address placed
  9022.       into the SI register. This address points to the structure table that
  9023.       is unique to each port and contains such data as the port's base
  9024.       address, the associated hardware interrupt vector, the interrupt
  9025.       service routine offset within the driver's segment, the base offsets
  9026.       of the input and output buffers for that port, two pointers for each
  9027.       of the buffers, and the input and output status conditions (including
  9028.       baud rate) for the port. The only difference between one port's driver
  9029.       and the other's is the data pointed to by SI; all Request routine code
  9030.       is shared by both ports.
  9031.  
  9032.       Each driver's Request routine has a unique entry point (at line 298
  9033.       for ASY1 and at line 303 for ASY2) that saves the original content of
  9034.       the SI register and then loads it with the address of the structure
  9035.       table for that driver. The routines then join as a common stream at
  9036.       line 307 (Gen_request).
  9037.  
  9038.       This common code preserves all other registers used (lines 309 through
  9039.       318), sets DS equal to CS (lines 319 and 320), retrieves the command-
  9040.       packet pointer saved by the Strategy routine (line 321), uses the
  9041.       pointer to get the command code (line 323), uses the code to calculate
  9042.       an offset into a table of addresses (lines 324 through 326), and
  9043.       performs an indexed jump (lines 322 and 327) by way of the dispatch
  9044.       table (lines 256 through 284) to the routine that executes the
  9045.       requested command (at line 336, 360, 389, 404, 414, 421, 441, 453,
  9046.       500, or 829).
  9047.  
  9048.       Although the device-driver specifications for MS-DOS version 3.2 list
  9049.       command request codes ranging from 0 to 24, not all are used. Earlier
  9050.       versions of MS-DOS permitted only 0 to 12 (versions 2.x) or 0 to 16
  9051.       (versions 3.0 and 3.1) codes. In this driver, all 24 codes are
  9052.       accounted for; those not implemented in this driver return a DONE and
  9053.       NO ERROR status to the caller. Because the Request routine is called
  9054.       only by MS-DOS itself, there is no check for invalid codes. Actually,
  9055.       because the header attribute bits are not set to specify that codes 13
  9056.       through 24 are valid, the 24 bytes occupied by their table entries
  9057.       (lines 273 through 284) could be saved by omitting the entries. They
  9058.       are included only to show how nonexistent commands can be
  9059.       accommodated.
  9060.  
  9061.       Immediately following the dispatch indexed jump, at lines 329 through
  9062.       353 within the same PROC declaration, is the common code used by all
  9063.       Request routines to store status information in the command packet,
  9064.       restore the registers, and return to the caller. The alternative entry
  9065.       points for BUSY status (line 332), NO ERROR status (line 338), or an
  9066.       error code (in the AX register at entry to Exit, line 339) not only
  9067.       save several bytes of redundant code but also improve readability of
  9068.       the code by providing unique single labels for BUSY, NO ERROR, and
  9069.       ERROR return conditions.
  9070.  
  9071.       All of the Request routines, except for the Init code at line 829,
  9072.       immediately follow the dispatching shell in lines 358 through 568.
  9073.       Each is simplified to perform just one task, such as read data in or
  9074.       write data out. The Read routine (lines 360 through 385) is typical:
  9075.       First, the requested byte count and user's buffer address are obtained
  9076.       from the command packet. Next, the pointer to the command packet is
  9077.       saved with a PUSH instruction, so that the ES and BX registers can be
  9078.       used for a pointer to the port's input buffer.
  9079.  
  9080.       Before the Get_in routine that actually accesses the input buffer is
  9081.       called, the input status byte is checked (line 368). If an error
  9082.       condition is flagged, lines 370 through 373 clear the status flag,
  9083.       flush the saved pointers from the stack, and jump to the error-return
  9084.       exit from the driver. If no error exists, line 375 calls Get_in to
  9085.       access the input buffer and lines 376 and 377 determine whether a byte
  9086.       was obtained. If a byte is found, it is stored in the user's buffer by
  9087.       line 378, and line 379 loops back to get another byte until the
  9088.       requested count has been obtained or until no more bytes are
  9089.       available. In practice, the count is an upper limit and the loop is
  9090.       normally broken when data runs out.
  9091.  
  9092.       No matter how it happens, control eventually reaches the Got_all
  9093.       routine and lines 381 and 382, where the saved pointers to the command
  9094.       packet are restored from the stack. Lines 383 and 384 adjust the count
  9095.       value in the packet to reflect the actual number of bytes obtained.
  9096.       Finally, line 385 jumps to the normal, no-error exit from the driver.
  9097.  
  9098.       Buffering
  9099.       Both buffers for each driver are of the type known as circular, or
  9100.       ring, buffers. Effectively, such a buffer is endless; it is accessed
  9101.       via pointers, and when a pointer increments past the end of the
  9102.       buffer, the pointer returns to the buffer's beginning. Two pointers
  9103.       are used here for each buffer, one to put data into it and one to get
  9104.       data out. The get pointer always points to the next byte to be read;
  9105.       the put pointer points to where the next byte will be written, just
  9106.       past the last byte written to the buffer.
  9107.  
  9108.       If both pointers point to the same byte, the buffer is empty; the next
  9109.       byte to be read has not yet been written. The full-buffer condition is
  9110.       more difficult to test for: The put pointer is incremented and
  9111.       compared with the get pointer; if they are equal, doing a write would
  9112.       force a false buffer-empty condition, so the buffer must be full.
  9113.  
  9114.       All buffer manipulation is done via four procedures (lines 569 through
  9115.       674). Put_out (lines 572 through 596) writes a byte to the driver's
  9116.       output buffer or returns a buffer-full indication by setting AH to
  9117.       0FFH. Get_out (lines 598 through 622) gets a byte from the output
  9118.       buffer or returns 0FFH in AH to indicate that no byte is available.
  9119.       Put_in (lines 624 through 648) and Get_in (lines 650 through 674) do
  9120.       exactly the same as Put_out and Get_out, but for the input buffer.
  9121.       These procedures are used both by the Request routines and by the
  9122.       hardware interrupt service routine (ISR).
  9123.  
  9124.       Interrupt service routines
  9125.       The most complex part of this driver is the ISR (lines 676 through
  9126.       806), which decides which of the four possible services for a port is
  9127.       to be performed and where. Like the Request routines, the ISR provides
  9128.       unique entry points for each port (line 679 for ASY1 and line 685 for
  9129.       ASY2); these entry points first preserve the SI register and then load
  9130.       it with the address of the port's structure table. With SI indicating
  9131.       where the actions are to be performed, the two entries then merge at
  9132.       line 690 into common code that first preserves all registers to be
  9133.       used by the ISR (lines 690 through 698) and then tests for each of the
  9134.       four possible types of service and performs each requested action.
  9135.  
  9136.       Much of the complexity of the ISR is in the decoding of modem-status
  9137.       conditions. Because the resulting information is not used by this
  9138.       driver (although it could be used to prevent attempts to transmit
  9139.       while off line), these ISR options can be removed so that only the
  9140.       Transmit and Receive interrupts are serviced. To do this, AllInt (at
  9141.       line 145) should be changed from the OR of all four bits to include
  9142.       only the transmit and receive bits (03H, or 00000011B).
  9143.  
  9144.       The transmit and receive portions of the ISR incorporate XON/XOFF flow
  9145.       control (for transmitted data only) by default. This control is done
  9146.       at the ISR level, rather than in the using program, to minimize the
  9147.       time required to respond to an incoming XOFF signal. Presence of the
  9148.       flow-control decisions adds complexity to what would otherwise be
  9149.       extremely simple actions.
  9150.  
  9151.       Flow control is enabled or disabled by setting the OutSpec word in the
  9152.       structure table with the Driver Status utility (presented later) via
  9153.       the IOCTL function (Interrupt 21H Function 44H). When flow control is
  9154.       enabled, any XOFF character (11H) that is received halts all outgoing
  9155.       data until XON (13H) is received. No XOFF or XON is retained in the
  9156.       input buffer to be sent on to any program, although all patterns other
  9157.       than XOFF and XON are passed through by the driver. When flow
  9158.       control is disabled, the driver passes all patterns in both
  9159.       directions. For binary file transfer, flow control must be disabled.
  9160.  
  9161.       The transmit action is simple: The code merely calls the Start_output
  9162.       procedure at line 750. Start_output is described in detail below.
  9163.  
  9164.       The receive action is almost as simple as transmit, except for the
  9165.       flow-control testing. First, the ISR takes the received byte from the
  9166.       UART (lines 758 and 759) to avoid any chance of an overrun error. The
  9167.       ISR then tests the input specifier (at line 760) to determine whether
  9168.       flow control is in effect. If it is not, processing jumps directly to
  9169.       line 784 to store the received byte in the input buffer with Put_in
  9170.       (line 785).
  9171.  
  9172.       If flow control is active, however, the received byte is compared with
  9173.       the XOFF character (lines 762 through 765). If the byte matches,
  9174.       output is disabled and the byte is ignored. If the byte is not XOFF,
  9175.       it is compared with XON (lines 766 through 768). If it is not XON
  9176.       either, control jumps to line 784. If the byte is XON, output is re-
  9177.       enabled if it was disabled. Regardless, the XON byte itself is
  9178.       ignored.
  9179.  
  9180.       When control reaches Stuff_in at line 784, Put_in is called to store
  9181.       the received byte in the input buffer. If there is no room for it, a
  9182.       lost-databit is set in the input status flags (line 788); otherwise,
  9183.       the receive routine is finished.
  9184.  
  9185.       If the interrupt was a line-status action, the LSR is read (lines 776
  9186.       through 779). If the input specifier so directs, the content is
  9187.       converted to an IBM PC extended graphics character by setting bit 7 to
  9188.       1 and the character is stored in the input buffer as if it were a
  9189.       received byte. Otherwise, the Line Status interrupt merely sets the
  9190.       generic BadInp error bit in the input status flags, which can be read
  9191.       with the IOCTL Read function of the driver.
  9192.  
  9193.       When all ISR action is complete, lines 794 through 806 restore machine
  9194.       conditions to those existing at the time of the interrupt and return
  9195.       to the interrupted procedure.
  9196.  
  9197.       The Start_output routine
  9198.       Start_output (lines 808 through 824) is a routine that, like the four
  9199.       buffer procedures, is used by both the Request routines and the ISR.
  9200.       Its purpose is to initiate transmission of a byte, provided that
  9201.       output is not blocked by flow control, the UART Transmit Holding
  9202.       Register is empty, and a byte to be transmitted exists in the output
  9203.       ring buffer. This routine uses the Get_out buffer routine to access
  9204.       the buffer and determine whether a byte is available. If all
  9205.       conditions are met, the byte is sent to the UART holding register by
  9206.       lines 819 and 820.
  9207.  
  9208.       The Initialization Request routine
  9209.       The Initialization Request routine (lines 829 through 897) is critical
  9210.       to successful operation of the driver. This routine is placed last in
  9211.       the package so that it can be discarded as soon as it has served its
  9212.       purpose by installing the driver. It is essential to clear each
  9213.       register of the 8250 by reading its contents before enabling the
  9214.       interrupts and to loop through this action until the 8250 finally
  9215.       shows no requests pending. The strange Clc jnc $+2 sequence that
  9216.       appears repeatedly in this routine is a time delay required by high-
  9217.       speed machines (6 MHz and up) so that the 8250 has time to settle
  9218.       before another access is attempted; the delay does no harm on slower
  9219.       machines.
  9220.  
  9221.       Using COMDVR
  9222.       The first step in using this device driver is assembling it with the
  9223.       Microsoft Macro Assembler (MASM). Next, use the Microsoft Object
  9224.       Linker (LINK) to create a .EXE file. Convert the .EXE file into a
  9225.       binary image file with the EXE2BIN utility. Finally, include the line
  9226.       DEVICE=COMDVR.SYS in the CONFIG.SYS file so that COMDVR will be
  9227.       installed when the system is restarted.
  9228.  
  9229.       Note: The number and colon at the beginning of each line in the
  9230.       program listings in this article are for reference only and should not
  9231.       be included in the source file.
  9232.  
  9233.       Figure 6-2 shows the sequence of actions required, assuming that EDLIN
  9234.       is used for modifying (or creating) the CONFIG.SYS file and that all
  9235.       commands are issued from the root directory of the boot drive.
  9236.  
  9237.       C>Creating the driver:
  9238.  
  9239.       C>MASM COMDVR;  <Enter>
  9240.       C>LINK COMDVR;  <Enter>
  9241.       C>EXE2BIN COMDVR.EXE COMDVR.SYS  <Enter>
  9242.  
  9243.       Modifying CONFIG.SYS (^Z = press Ctrl-Z):
  9244.  
  9245.       C>EDLIN CONFIG.SYS  <Enter>
  9246.       *#I  <Enter>
  9247.       *DEVICE=COMDVR.SYS  <Enter>
  9248.       *^Z  <Enter>
  9249.       *E  <Enter>
  9250.  
  9251.       Figure 6-2. Assembling, linking, and installing COMDVR.
  9252.  
  9253.  
  9254.       Because the devices installed by COMDVR do not use the standard MS-DOS
  9255.       device names, no conflict occurs with any program that uses
  9256.       conventional port references. Such a program will not use the driver,
  9257.       and no problems should result if the program is well behaved and
  9258.       restores all interrupt vectors before returning to MS-DOS.
  9259.  
  9260.  Device-driver debugging techniques
  9261.       The debugging of device drivers, like debugging for any part of MS-DOS
  9262.       itself, is more difficult than normal program checking because the
  9263.       debugging program, DEBUG.COM or DEBUG.EXE, itself uses MS-DOS
  9264.       functions to display output. When these functions are being checked,
  9265.       their use by DEBUG destroys the data being examined. And because
  9266.       MS-DOS always saves its return address in the same location, any call
  9267.       to a function from inside the operating system usually causes a system
  9268.       lockup that can be cured only by shutting the system down and powering
  9269.       up again.
  9270.  
  9271.       One way to overcome this difficulty is to purchase costly debugging
  9272.       tools. An easier way is to bypass the problem: Instead of using MS-DOS
  9273.       functions to track program operation, write data directly to video
  9274.       RAM, as in the macro DBG (lines 10 through 32 of COMDVR.ASM).
  9275.  
  9276.       This macro is invoked with a three-character parameter string at each
  9277.       point in the program a progress report is desired. Each invocation has
  9278.       its own unique three-character string so that the sequence of actions
  9279.       can be read from the screen. When invoked, DBG expands into code that
  9280.       saves all registers and then writes the three-character string to
  9281.       video RAM. Only the top 10 lines of the screen (800 characters, or
  9282.       1600 bytes) are used: The macro uses a single far pointer to the area
  9283.       and treats the video RAM like a ring buffer.
  9284.  
  9285.       The pointer, Dbgptr (line 215), is set up for use with the monochrome
  9286.       adapter and points to location B000:0000H; to use a CGA or EGA (in CGA
  9287.       mode), the location should be changed to B800:0000H.
  9288.  
  9289.       Most of the frequently used Request routines, such as Read and Write,
  9290.       have calls to DBG as their first lines (for example, lines 361 and
  9291.       422). As shown, these calls are commented out, but for debugging, the
  9292.       source file should be edited so that all the calls and the macro
  9293.       itself are enabled.
  9294.  
  9295.       With DBG active, the top 10 lines of the display are overwritten with
  9296.       a continual sequence of reports, such as RR Tx , put directly into
  9297.       video RAM. Because MS-DOS functions are not used, no interference with
  9298.       the driver itself can occur.
  9299.  
  9300.       Although this technique prevents normal use of the system during
  9301.       debugging, it greatly simplifies the problem of knowing what is
  9302.       happening in time-critical areas, such as hardware interrupt service.
  9303.       In addition, all invocations of DBG in the critical areas are in
  9304.       conditional code that is executed only when the driver is working as
  9305.       it should.
  9306.  
  9307.       Failure to display the pi message, for instance, indicates that the
  9308.       received-data hardware interrupt is not being serviced, and absence of
  9309.       go after an Ix report shows that data is not being sent out as it
  9310.       should.
  9311.  
  9312.       Of course, once debugging is complete, the calls to DBG should be
  9313.       deleted or commented out. Such calls are usually edited out of the
  9314.       source code before release. In this case, they remain to demonstrate
  9315.       the technique and, most particularly, to show placement of the calls
  9316.       to provide maximum information with minimal clutter on the screen.
  9317.  
  9318.  A simple modem engine
  9319.  
  9320.       The second part of this package is the modem engine itself
  9321.       (ENGINE.ASM), shown in the listing in Figure 6-3. The main loop of
  9322.       this program consists of only a dozen lines of code (lines 9 through
  9323.       20). Of these, five (lines 9 through 13) are devoted to establishing
  9324.       initial contact between the program and the serial-port driver and two
  9325.       (lines 19 and 20) are for returning to command level at the program's
  9326.       end.
  9327.  
  9328.       Thus, only five lines of code (lines 14 through 18) actually carry out
  9329.       the bulk of the program as far as the main loop is concerned. Four of
  9330.       these lines are calls to subroutines that get and put data from and to
  9331.       the console and the serial port; the fifth is the JMP that closes the
  9332.       loop. This structure underscores the fact that a basic modem engine is
  9333.       simply a data-transfer loop.
  9334.  
  9335.       ──────────────────────────────────────────────────────────────────────
  9336.  
  9337.       Figure 6-3. ENGINE.ASM.
  9338.  
  9339.       ──────────────────────────────────────────────────────────────────────
  9340.  
  9341.       Because the details of timing and data conversion are handled by the
  9342.       driver code, each of the four subroutines is--to show just how simple
  9343.       the whole process is--essentially a buffered interface to the MS-DOS
  9344.       Read File or Device or Write File or Device routine.
  9345.  
  9346.       For example, the getmdm procedure (lines 22 through 31) asks MS-DOS to
  9347.       read a maximum of 256 bytes from the serial device and then stores the
  9348.       number actually read in a word named mdlen. The driver returns
  9349.       immediately, without waiting for data, so the normal number of bytes
  9350.       returned is either 0 or 1. If screen scrolling causes the loop to be
  9351.       delayed, the count might be higher, but it should never exceed about a
  9352.       dozen characters.
  9353.  
  9354.       When called, the putcrt procedure (lines 63 through 72) checks the
  9355.       value in mdlen. If the value is zero, putcrt does nothing; otherwise,
  9356.       it asks MS-DOS to write that number of bytes from mbufr (where getmdm
  9357.       put them) to the display, and then it returns.
  9358.  
  9359.       Similarly, getkbd gets keystrokes from the keyboard, stores them in
  9360.       kbufr, and posts a count in kblen; putmdm checks kblen and, if the
  9361.       count is not zero, sends the required number of bytes from kbufr to
  9362.       the serial device.
  9363.  
  9364.       Note that getkbd does not use the Read File or Device function,
  9365.       because that would wait for a keystroke and the loop must never wait
  9366.       for reception. Instead, it uses the MS-DOS functions that test
  9367.       keyboard status (0BH) and read a key without echo (07H). In addition,
  9368.       special treatment is given to the Enter key (lines 45 through 48): A
  9369.       linefeed is inserted in kbufr immediately behind Enter and kblen is
  9370.       set to 2.
  9371.  
  9372.       A Ctrl-C keystroke ends program operation; it is detected in getkbd
  9373.       (line 41) and causes immediate transfer to the quit label (line 19) at
  9374.       the end of the main loop. Because ENGINE uses only permanently
  9375.       resident routines, there is no need for any uninstallation before
  9376.       returning to the MS-DOS command prompt.
  9377.  
  9378.       ENGINE.ASM is written to be used as a .COM file. Assemble and link it
  9379.       the same as COMDVR.SYS (Figure 6-2) but use the extension COM instead
  9380.       of SYS; no change to CONFIG.SYS is needed.
  9381.  
  9382.  The driver-status utility: CDVUTL.C
  9383.  
  9384.       The driver-status utility program CDVUTL.C, presented in Figure 6-4,
  9385.       permits either of the two drivers (ASY1 and ASY2) to be reconfigured
  9386.       after being installed, to suit different needs. After one of the
  9387.       drivers has been specified (port 1 or port 2), the baud rate, word
  9388.       length, parity, and number of stop bits can be changed; each change is
  9389.       made independently, with no effect on any of the other
  9390.       characteristics. Additionally, flow control can be switched between
  9391.       two types of hardware handshaking--the software XON/XOFF control or
  9392.       disabled--and error reporting can be switched between character-
  9393.       oriented and message-oriented operation.
  9394.  
  9395.       ──────────────────────────────────────────────────────────────────────
  9396.  
  9397.       Figure 6-4. CDVUTL.C
  9398.  
  9399.       ──────────────────────────────────────────────────────────────────────
  9400.  
  9401.  
  9402.       Although CDVUTL appears complicated, most of the complexity is
  9403.       concentrated in the routines that map driver bit settings into on-
  9404.       screen display text. Each such mapping requires several lines of
  9405.       source code to generate only a few words of the display report. Table
  9406.       6-10 summarizes the functions found in this program.
  9407.  
  9408.  
  9409.       Table 6-10. CDVUTL Program Functions.
  9410.  
  9411. ╓┌─────────────────────┌──────────┌──────────────────────────────────────────╖
  9412.       Lines            Name       Description
  9413.       ──────────────────────────────────────────────────────────────────
  9414.        42-45           main()     Conventional entry point.
  9415.        47-150          disp()     Main dispatching loop.
  9416.       152-158          center()   Centers text on CRT.
  9417.       160-166          iocwr()    Writes control string to driver with IOCTL
  9418.                                   Write.
  9419.       168-170          onoff()    Returns pointer to ON or OFF.
  9420.       172-233          report()   Reads driver status and reports it on
  9421.                                   display.
  9422.  
  9423.  
  9424.       The long list of #define operations at the start of the listing (lines
  9425.       11 through 33) helps make the bitmapping comprehensible by assigning a
  9426.       symbolic name to each significant bit in the four UART registers.
  9427.  
  9428.       The main() procedure of CDVUTL displays a banner line and then calls
  9429.       the dispatcher routine, disp(), to start operation. CDVUTL makes no
  9430.       use of either command-line parameters or the environment, so the usual
  9431.       argument declarations are omitted.
  9432.  
  9433.       Upon entry to disp(), the first action is to establish the default
  9434.       driver as ASY1 by setting u = 1 and opening ASY1 (line 50); the
  9435.       program then enters an apparent infinite loop (lines 51 through 149).
  9436.  
  9437.       With each repetition, the loop first prompts for a command (line 52)
  9438.       and then gets the next keystroke and uses it to control a huge
  9439.       switch() statement (lines 53 through 145). If no case matches the key
  9440.       pressed, the switch() statement does nothing; the program simply
  9441.       displays a report of all current conditions at the selected driver
  9442.       (lines 146 through 148) and then closes the loop back to issue a new
  9443.       prompt and get another keystroke.
  9444.  
  9445.       However, if the key pressed matches one of the cases in the switch()
  9446.       statement, the corresponding command is executed. The digits 1 (line
  9447.       55) and 2 (line 61) select the driver to be affected. The ? key (line
  9448.       105) causes the list of valid command keys to be displayed. The q key
  9449.       (line 142) causes the program to terminate by calling exit( 0 ) and is
  9450.       the only exit from the infinite loop. The other valid keys all change
  9451.       one or more bits in the IOCTL control string to modify corresponding
  9452.       attributes of the driver and then send the string to the driver by
  9453.       using the MS-DOS IOCTL Write function (Interrupt 21H Function 44H
  9454.       Subfunction 03H) via function iocwr() (lines 160 through 166).
  9455.  
  9456.       After the command is executed (except for the q command, which
  9457.       terminates operation of CDVUTL and returns to MS-DOS command level,
  9458.       and the ? command, which displays the command list), the report()
  9459.       function (lines 172 through 233) is called (at line 148) to display
  9460.       all of the driver's attributes, including those just changed. This
  9461.       function issues an IOCTL Read command (Interrupt 21H Function 44H
  9462.       Subfunction 02H, in lines 174 through 178) to get new status
  9463.       information into the control string and then uses a sequence of bit
  9464.       filtering (lines 179 through 232) to translate the obtained status
  9465.       information into words for display.
  9466.  
  9467.       The special console I/O routines provided in Microsoft C libraries
  9468.       have been used extensively in this routine. Other compilers may
  9469.       require changes in the names of such library routines as getch or
  9470.       dosint as well as in the names of #include files (lines 6 through 9).
  9471.  
  9472.       Each of the actual command sequences changes only a few bits in one of
  9473.       the 10 bytes of the command string and then writes the string to the
  9474.       driver. A full-featured communications program might make several
  9475.       changes at one time--for example, switching from 7-bit, even parity,
  9476.       XON/XOFF flow control to 8-bit, no parity, without flow control to
  9477.       prevent losing any bytes with values of 11H or 13H while performing a
  9478.       binary file transfer with error-correcting protocol. In such a case,
  9479.       the program could make all required changes to the control string
  9480.       before issuing a single IOCTL Write to put them into effect.
  9481.  
  9482.  
  9483.  The Traditional Approach
  9484.  
  9485.       Because the necessary device driver has never been a part of MS-DOS,
  9486.       most communications programs are written to provide and install their
  9487.       own port driver code and remove it before returning to MS-DOS. The
  9488.       second sample program package in this article illustrates this
  9489.       approach. Although the major part of the package is written in
  9490.       Microsoft C, three assembly-language modules are required to provide
  9491.       the hardware interrupt service routines, the exception handler, and
  9492.       faster video display. They are discussed first.
  9493.  
  9494.  The hardware ISR module
  9495.  
  9496.       The first module is a handler to service UART interrupts. Code for
  9497.       this handler, including routines to install it at entry and remove it
  9498.       on exit, appears in CH1.ASM, shown in Figure 6-5.
  9499.  
  9500.       ──────────────────────────────────────────────────────────────────────
  9501.  
  9502.       Figure 6-5. CH1.ASM
  9503.  
  9504.       ──────────────────────────────────────────────────────────────────────
  9505.  
  9506.       The routines in CH1 are set up to work only with port COM2; to use
  9507.       them with COM1, the three symbolic constants BPORT (base address),
  9508.       GETIV, and PUTIV must be changed to match the COM1 values. Also, as
  9509.       presented, this code is for use with the Microsoft C small memory
  9510.       model only; for use with other memory models, the C compiler manuals
  9511.       should be consulted for making the necessary changes. See also
  9512.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS:
  9513.       Structure of an Application Program.
  9514.  
  9515.       The parts of CH1 are listed in Table 6-11, as they occur in the
  9516.       listing. The leading underscore that is part of the name for each of
  9517.       the six functions is supplied by the C compiler; within the C program
  9518.       that calls the function, the underscore is omitted.
  9519.  
  9520.  
  9521.       Table 6-11. CH1 Module Functions.
  9522.  
  9523. ╓┌────────────────┌──────────────┌───────────────────────────────────────────╖
  9524.       Lines       Name           Description
  9525.       ──────────────────────────────────────────────────────────────────
  9526.         1-26                     Administrative details.
  9527.  
  9528.        27-46                     Data areas.
  9529.  
  9530.        48-84      _set_mdm       Initializes UART as specified by parameter
  9531.                                  passed from C.
  9532.  
  9533.        86-114     _wrtmdm        Outputs character to UART.
  9534.  
  9535.        87         _Send_Byte     Entry point for use if flow control is
  9536.       Lines       Name           Description
  9537.       87         _Send_Byte     Entry point for use if flow control is
  9538.                                  added to system.
  9539.  
  9540.       116-140     _rdmdm         Gets character from buffer where ISR put
  9541.                                  it, or signals that no character available.
  9542.  
  9543.       142-155     w_tmr          Wait timer; internal routine used to
  9544.                                  prevent infinite wait in case of problems.
  9545.  
  9546.       157-182     rts_m          Hardware ISR; installed by _i_m and removed
  9547.                                  by _u_m.
  9548.  
  9549.       184-240     _i_m           Installs ISR, saving old interrupt vector.
  9550.  
  9551.       242-265     _u_m           Uninstalls ISR, restoring saved interrupt
  9552.                                  vector.
  9553.  
  9554.  
  9555.       For simplest operation, the ISR used in this example (unlike the
  9556.       device driver) services only the received-data interrupt; the other
  9557.       three types of IRQ are disabled at the UART. Each time a byte is
  9558.       received by the UART, the ISR puts it into the buffer. The _rdmdm
  9559.       code, when called by the C program, gets a byte from the buffer if one
  9560.       is available. If not, _rdmdm returns the C EOF code (-1) to indicate
  9561.       that no byte can be obtained.
  9562.  
  9563.       To send a byte, the C program can call either _Send_Byte or _wrtmdm;
  9564.       in the package as shown, these are alternative names for the same
  9565.       routine. In the more complex program from which this package was
  9566.       adapted, _Send_Byte is called when flow control is desired and the
  9567.       flow-control routine calls _wrtmdm. To implement flow control, line 87
  9568.       should be deleted from CH1.ASM and a control function named
  9569.       Send_Byte() should be added to the main C program. Flow-control tests
  9570.       must occur in Send_Byte(); _wrtmdm performs the actual port
  9571.       interfacing.
  9572.  
  9573.       To set the modem baud rate, word length, and parity, _set_mdm is
  9574.       called from the C program, with a setup parameter passed as an
  9575.       argument. The format of this parameter is shown in Table 6-12 and is
  9576.       identical to the IBM BIOS Interrupt 14H Function 00H (Initialization).
  9577.  
  9578.  
  9579.       Table 6-12. set_mdm() Parameter Coding.
  9580.  
  9581. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  9582.       Binary           Meaning
  9583.       ──────────────────────────────────────────────────────────────────
  9584.       000xxxxx         Set to 110 bps
  9585.       001xxxxx         Set to 150 bps
  9586.       010xxxxx         Set to 300 bps
  9587.       011xxxxx         Set to 600 bps
  9588.       100xxxxx         Set to 1200 bps
  9589.       101xxxxx         Set to 2400 bps
  9590.       110xxxxx         Set to 4800 bps
  9591.       111xxxxx         Set to 9600 bps
  9592.       xxxx0xxx         No parity
  9593.       xxx01xxx         ODD Parity
  9594.       xxx11xxx         EVEN Parity
  9595.       xxxxx0xx         1 stop bit
  9596.       xxxxx1xx         2 stop bits (1.5 if WL = 5)
  9597.       xxxxxx00         Word length = 5
  9598.       xxxxxx01         Word length = 6
  9599.       Binary           Meaning
  9600.      xxxxxx01         Word length = 6
  9601.       xxxxxx10         Word length = 7
  9602.       xxxxxx11         Word length = 8
  9603.  
  9604.  
  9605.       The CH1 code provides a 512-byte ring buffer for incoming data; the
  9606.       buffer size should be adequate for reception at speeds up to 2400 bps
  9607.       without loss of data during scrolling.
  9608.  
  9609.  The exception-handler module
  9610.  
  9611.       For the ISR handler of CH1 to be usable, an exception handler is
  9612.       needed to prevent return of control to MS-DOS before _u_m restores the
  9613.       ISR vector to its original value. If a program using this code returns
  9614.       to MS-DOS without calling _u_m, the system is virtually certain to
  9615.       crash when line noise causes a received-data interrupt and the ISR
  9616.       code is no longer in memory.
  9617.  
  9618.       A replacement exception handler (CH1A.ASM), including routines for
  9619.       installation, access, and removal, is shown in Figure 6-6. Like the
  9620.       ISR, this module is designed to work with Microsoft C (again, the
  9621.       small memory model only).
  9622.  
  9623.       Note: This module does not provide for fatal disk errors; if one
  9624.       occurs, immediate restarting is necessary. See PROGRAMMING IN THE MS-
  9625.       DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Exception Handlers.
  9626.  
  9627.       ──────────────────────────────────────────────────────────────────────
  9628.  
  9629.       Figure 6-6. CH1A.ASM.
  9630.  
  9631.       ──────────────────────────────────────────────────────────────────────
  9632.  
  9633.       The three functions in CH1A are _set_int, which saves the old vector
  9634.       value for Interrupt 1BH (ROM BIOS Control-Break) and then resets both
  9635.       that vector and the one for Interrupt 23H (Control-C Handler Address)
  9636.       to internal ISR code; _rst_int, which restores the original value for
  9637.       the Interrupt 1BH vector; and _broke, which returns the present value
  9638.       of an internal flag (and always clears the flag, just in case it had
  9639.       been set). The internal flag is set to a nonzero value in response to
  9640.       either of the revectored interrupts and is tested from the main C
  9641.       program via the _broke function.
  9642.  
  9643.  The video display module
  9644.  
  9645.       The final assembly-language module (CH2.ASM) used by the second
  9646.       package is shown in Figure 6-7. This module provides convenient screen
  9647.       clearing and cursor positioning via direct calls to the IBM BIOS, but
  9648.       this can be eliminated with minor rewriting of the routines that call
  9649.       its functions. In the original, more complex program (DT115.EXE,
  9650.       available from DL6 in the CLMFORUM of CompuServe) from which CTERM was
  9651.       derived, this module provided windowing capability in addition to
  9652.       improved display speed.
  9653.  
  9654.       ──────────────────────────────────────────────────────────────────────
  9655.  
  9656.       Figure 6-7. CH2.ASM.
  9657.  
  9658.       ──────────────────────────────────────────────────────────────────────
  9659.  
  9660.  The sample smarter terminal emulator: CTERM.C
  9661.  
  9662.       Given the interrupt handler (CH1), exception handler (CH1A), and video
  9663.       handler (CH2), a simple terminal emulation program (CTERM.C) can be
  9664.       presented. The major functions of the program are written in Microsoft
  9665.       C; the listing is shown in Figure 6-8.
  9666.  
  9667.       ──────────────────────────────────────────────────────────────────────
  9668.  
  9669.       Figure 6-8. CTERM.C.
  9670.  
  9671.       ──────────────────────────────────────────────────────────────────────
  9672.  
  9673.  
  9674.       CTERM features file-capture capabilities, a simple yet effective
  9675.       script language, and a number of stub (that is, incompletely
  9676.       implemented) actions, such as emulation of the VT52 and VT100 series
  9677.       terminals, indicating various directions in which it can be developed.
  9678.  
  9679.       The names of a script file and a capture file can be passed to CTERM
  9680.       in the command line. If no filename extensions are included, the
  9681.       default for the script file is .SCR and that for the capture file is
  9682.       .CAP. If extensions are given, they override the default values. The
  9683.       capture feature can be invoked only if a filename is supplied in the
  9684.       command line, but a script file can be called at any time via the Esc
  9685.       command sequence, and one script file can call for another with the
  9686.       same feature.
  9687.  
  9688.       The functions included in CTERM.C are listed and summarized in Table
  9689.       6-13.
  9690.  
  9691.  
  9692.       Table 6-13. CTERM.C Functions.
  9693.  
  9694. ╓┌─────────────────────┌──────────────────────┌──────────────────────────────╖
  9695.       Lines            Name                   Description
  9696.       ──────────────────────────────────────────────────────────────────
  9697.       1-5                                     Program documentation.
  9698.  
  9699.       7-11                                    Include files.
  9700.  
  9701.       12-20                                   Definitions.
  9702.  
  9703.       22-43                                   Global data areas.
  9704.       Lines            Name                   Description
  9705.      22-43                                   Global data areas.
  9706.  
  9707.       45                                      External prototype
  9708.                                               declaration.
  9709.  
  9710.       47-49            Wants_To_Abort()       Checks for Ctrl-Break or Ctrl-
  9711.                                               C being pressed.
  9712.  
  9713.       52-165           main()                 Main program loop; includes
  9714.                                               modem engine and sequential
  9715.                                               state machine to decode
  9716.                                               remote commands.
  9717.  
  9718.       167-297          docmd()                Gets, interprets, and performs
  9719.                                               local (console or script)
  9720.                                               command.
  9721.  
  9722.       299-304          kbd_wait()             Waits for input from console
  9723.                                               or script file.
  9724.  
  9725.       Lines            Name                   Description
  9726. 
  9727.       306-334          kb_file()              Gets keystroke from console or
  9728.                                               script; returns EOF if no
  9729.                                               character available.
  9730.  
  9731.       336-362          esc()                  Translates script escape
  9732.                                               sequence.
  9733.  
  9734.       364-370          getfil()               Gets name of script file and
  9735.                                               opens the file.
  9736.  
  9737.       372-382          getnam()               Gets string from console or
  9738.                                               script into designated
  9739.                                               buffer.
  9740.  
  9741.       384-393          addext()               Checks buffer for extension;
  9742.                                               adds one if none given.
  9743.  
  9744.       395-398          put_cap()              Writes character to capture
  9745.                                               file if capture in effect.
  9746.       Lines            Name                   Description
  9747.                                              file if capture in effect.
  9748.  
  9749.       400-406          cap_flush()            Closes capture file and
  9750.                                               terminates capture mode if
  9751.                                               capture in effect.
  9752.  
  9753.       408-411                                 Timer data locations.
  9754.  
  9755.       413-425          getmr()                Returns time since midnight,
  9756.                                               in milliseconds.
  9757.  
  9758.       427-432          Delay()                Sleeps n milliseconds.
  9759.  
  9760.       434-436          Start_Timer()          Sets timer for n seconds.
  9761.  
  9762.       438-440          Timer_Expired()        Checks timer versus clock.
  9763.  
  9764.       442-445          Set_Vid()              Initializes video data.
  9765.  
  9766.       447-452          locate()               Positions cursor on display.
  9767.       Lines            Name                   Description
  9768.      447-452          locate()               Positions cursor on display.
  9769.  
  9770.       454-456          deol()                 Deletes to end of line.
  9771.  
  9772.       458-468          deos()                 Deletes to end of screen.
  9773.  
  9774.       470-472          cls()                  Clears screen.
  9775.  
  9776.       474-478          cursor()               Turns cursor on or off.
  9777.  
  9778.       480-485          revvid()               Toggles inverse/normal video
  9779.                                               display attributes.
  9780.  
  9781.       487-492          putchx()               Writes char to display using
  9782.                                               putch() (Microsoft C
  9783.                                               library).
  9784.  
  9785.       494-500          Read_Keyboard()        Gets keystroke from keyboard.
  9786.  
  9787.       502-504                                 Modem data areas.
  9788.       Lines            Name                   Description
  9789.      502-504                                 Modem data areas.
  9790.  
  9791.       506-512          Init_Comm()            Installs ISR and so forth and
  9792.                                               initializes modem.
  9793.  
  9794.       514-515                                 Baud-rate definitions.
  9795.  
  9796.       517-529          Set_Baud()             Changes bps rate of UART.
  9797.  
  9798.       531-537                                 Parity, WL definitions.
  9799.  
  9800.       539-557          Set_Parity()           Establishes UART parity mode.
  9801.  
  9802.       559-562          Write_Modem()          Sends character to UART.
  9803.  
  9804.       564-566          Read_Modem()           Gets character from ISR's
  9805.                                               buffer.
  9806.  
  9807.       568-570          Term_Comm()            Uninstalls ISR and so forth
  9808.                                               and restores original
  9809.       Lines            Name                   Description
  9810.                                              and restores original
  9811.                                               vectors.
  9812.  
  9813.  
  9814.       For communication with the console, CTERM uses the special Microsoft C
  9815.       library functions defined by CONIO.H, augmented with the functions in
  9816.       the CH2.ASM handler. Much of the code may require editing if used with
  9817.       other compilers. CTERM also uses the function prototype file CTERM.H,
  9818.       listed in Figure 6-9, to optimize function calling within the program.
  9819.  
  9820.       ──────────────────────────────────────────────────────────────────────
  9821.  
  9822.       Figure 6-9. CTERM.H.
  9823.  
  9824.       ──────────────────────────────────────────────────────────────────────
  9825.  
  9826.       Program execution begins at the entry to main(), line 52. CTERM first
  9827.       checks (lines 56 through 59) whether any filenames were passed in the
  9828.       command line; if they were, CTERM opens the corresponding files. Next,
  9829.       the program installs the exception handler (line 60), initializes the
  9830.       video handler (line 61), clears the display (line 62), and announces
  9831.       its presence (lines 63 and 64). The serial driver is installed and
  9832.       initialized to 1200 bps and no parity (lines 65 through 67), and the
  9833.       program enters its main modem-engine loop (lines 68 through 159).
  9834.  
  9835.       This loop is functionally the same as that used in ENGINE, but it has
  9836.       been extended to detect an Esc from the keyboard as signalling the
  9837.       start of a local command sequence (lines 70 through 73) and to include
  9838.       a state-machine technique (lines 80 through 153) to recognize incoming
  9839.       escape sequences, such as the VT52 or VT100 codes. To specify a local
  9840.       command from the keyboard, press the Escape (Esc) key, then the first
  9841.       letter of the local command desired. After the local command has been
  9842.       selected, press any key (such as Enter or the spacebar) to continue.
  9843.       To get a listing of all the commands available, press Esc-H.
  9844.  
  9845.       The kb_file() routine of CTERM (called in the main loop at line 69)
  9846.       can get its input from either a script file or the keyboard. If a
  9847.       script file is open (lines 308 through 330), it is used until EOF is
  9848.       reached or until the operator presses Ctrl-C to stop script-file
  9849.       input. Otherwise, input is taken from the keyboard (lines 331 and
  9850.       332). If a script file is in use, its input is echoed to the display
  9851.       (lines 325 through 329) if the V command has been given.
  9852.  
  9853.       To permit the Esc character itself to be placed in script files, the
  9854.       backslash (\) character serves as a secondary escape signal. When a
  9855.       backslash is detected (lines 323 and 324) in the input stream, the
  9856.       next character input is translated according to the following rules:
  9857.  
  9858. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  9859.       Character        Interpretation
  9860.       ──────────────────────────────────────────────────────────────────
  9861.       E or e           Translates to Esc.
  9862.       N or n           Translates to Linefeed.
  9863.       R or r           Translates to Enter (CR).
  9864.       T or t           Translates to Tab.
  9865.       ^                Causes the next character input to be converted into
  9866.                        a control character.
  9867.  
  9868.       Any other character, including another \, is not translated at all.
  9869.  
  9870.       When the Esc character is detected from either the console or a script
  9871.       file, the docmd() function (lines 167 through 297) is called to prompt
  9872.       for and decode the next input character as a command and to perform
  9873.       appropriate actions. Valid command characters, and the actions they
  9874.       invoke, are as follows:
  9875.  
  9876. ╓┌────────────────────────────┌──────────────────────────────────────────────╖
  9877.       Command Character       Action
  9878.       ──────────────────────────────────────────────────────────────────
  9879.       D                       Delay 0-9 seconds, then proceed. Must be
  9880.                               followed by a decimal digit that indicates
  9881.                               how long to delay.
  9882.       E                       Set EVEN parity.
  9883.       F                       Set (fast) 1200 baud.
  9884.       H                       Display list of valid commands.
  9885.       N                       Set no parity.
  9886.       O                       Set ODD parity.
  9887.       Q                       Quit; return to MS-DOS command prompt.
  9888.       R                       Reset modem.
  9889.       S                       Set (slow) 300 baud.
  9890.       U                       Use script file (CTERM prompts for filename).
  9891.       V                       Verify file input. Echoes each script-file
  9892.                               byte.
  9893.       Command Character       Action
  9894.                              byte.
  9895.       W                       Wait for character; the next input character
  9896.                               is the one that must be matched.
  9897.  
  9898.       Any other character input after an Esc and the resulting Command
  9899.       prompt generates the message Don't know X (where X stands for the
  9900.       actual input character) followed by the prompt Use `H' command for
  9901.       Help.
  9902.  
  9903.       If input is taken from a script and the V flag is off, docmd()
  9904.       performs its task quietly, with no output to the screen. If input is
  9905.       received from the console, however, the command letter, followed by a
  9906.       descriptive phrase, is echoed to the screen. Input, detection, and
  9907.       execution of the local commands are accomplished much as in CDVUTL, by
  9908.       way of a large switch() statement (lines 178 through 290).
  9909.  
  9910.       Although the listed commands are only a subset of the features
  9911.       available in CDVUTL for the device-driver program, they are more than
  9912.       adequate for creating useful scripts. The predecessor of CTERM
  9913.       (DT115.EXE), which included the CompuServe B-Protocol file-transfer
  9914.       capability but had no additional commands, has been in use since early
  9915.       1986 to handle automatic uploading and downloading of files from the
  9916.       CompuServe Information Service by means of script files. In
  9917.       conjunction with an auto-dialing modem, DT115.EXE handles the entire
  9918.       transaction, from login through logout, without human intervention.
  9919.  
  9920.       All the bits and pieces of CTERM are put together by assembling the
  9921.       three handlers with MASM, compiling CTERM with Microsoft C, and
  9922.       linking all four object modules into an executable file. Figure 6-10
  9923.       shows the complete sequence and also the three ways of using the
  9924.       finished program.
  9925.  
  9926.  
  9927.       Compiling:
  9928.  
  9929.       MASM CH1;
  9930.       MASM CH1A;
  9931.       MASM CH2;
  9932.       MSC CTERM;
  9933.  
  9934.       Linking:
  9935.  
  9936.       LINK CTERM+CH1+CH1A+CH2;
  9937.  
  9938.       Use:
  9939.       (no files)
  9940.  
  9941.       CTERM
  9942.  
  9943.       or
  9944.       (script only)
  9945.  
  9946.       CTERMscriptfile
  9947.  
  9948.       or
  9949.  
  9950.       CTERMscriptfile capturefile
  9951.  
  9952.       Figure 6-10. Putting CTERM together and using it.
  9953.  
  9954.                                                    Jim Kyle
  9955.                                                    Chip Rabinowitz
  9956.  
  9957.  
  9958.  
  9959.  Article 7:  File and Record Management
  9960.  
  9961.  
  9962.       The core of most application programs is the reading, processing, and
  9963.       writing of data stored on magnetic disks. This data is organized into
  9964.       files, which are identified by name; the files, in turn, can be
  9965.       organized by grouping them into directories. Operating systems provide
  9966.       application programs with services that allow them to manipulate these
  9967.       files and directories without regard to the hardware characteristics
  9968.       of the disk device. Thus, applications can concern themselves solely
  9969.       with the form and content of the data, leaving the details of the
  9970.       data's location on the disk and of its retrieval to the operating
  9971.       system.
  9972.  
  9973.       The disk storage services provided by an operating system can be
  9974.       categorized into file functions and record functions. The file
  9975.       functions operate on entire files as named entities, whereas the
  9976.       record functions provide access to the data contained within files.
  9977.       (In some systems, an additional class of directory functions allows
  9978.       applications to deal with collections of files as well.) This article
  9979.       discusses the MS-DOS function calls that allow an application program
  9980.       to create, open, close, rename, and delete disk files; read data from
  9981.       and write data to disk files; and inspect or change the information
  9982.       (such as attributes and date and time stamps) associated with disk
  9983.       filenames in disk directories. See also PROGRAMMING IN THE MS-DOS
  9984.       ENVIRONMENT: STRUCTURE OF MS-DOS: MS-DOS Storage Devices; PROGRAMMING
  9985.       FOR MS-DOS: Disk Directories and Volume Labels.
  9986.  
  9987.  
  9988.  Historical Perspective
  9989.  
  9990.       Current versions of MS-DOS provide two overlapping sets of file and
  9991.       record management services to support application programs: the handle
  9992.       functions and the file control block (FCB) functions. Both sets are
  9993.       available through Interrupt 21H (Table 7-1). See SYSTEM CALLS:
  9994.       INTERRUPT 21H. The reasons for this surprising duplication are
  9995.       strictly historical.
  9996.  
  9997.       The earliest versions of MS-DOS used FCBs for all file and record
  9998.       access because CP/M, which was the dominant operating system on 8-bit
  9999.       microcomputers, used FCBs. Microsoft chose to maintain compatibility
  10000.       with CP/M to aid programmers in converting the many existing CP/M
  10001.       application programs to the 16-bit MS-DOS environment; consequently,
  10002.       MS-DOS versions 1.x included a set of FCB functions that were a
  10003.       functional superset of those present in CP/M. As personal computers
  10004.       evolved, however, the FCB access method did not lend itself well to
  10005.       the demands of larger, faster disk drives.
  10006.  
  10007.       Accordingly, MS-DOS version 2.0 introduced the handle functions to
  10008.       provide a file and record access method similar to that found in
  10009.       UNIX/XENIX. These functions are easier to use and more flexible than
  10010.       their FCB counterparts and fully support a hierarchical (tree-like)
  10011.       directory structure. The handle functions also allow character
  10012.       devices, such as the console or printer, to be treated for some
  10013.       purposes as though they were files. MS-DOS version 3.0 introduced
  10014.       additional handle functions, enhanced some of the existing handle
  10015.       functions for use in network environments, and provided improved error
  10016.       reporting for all functions.
  10017.  
  10018.       The handle functions, which offer far more capability and performance
  10019.       than the FCB functions, should be used for all new applications.
  10020.       Therefore, they are discussed first in this article.
  10021.  
  10022.  
  10023.       Table 7-1. Interrupt 21H Function Calls for File and Record
  10024.                  Management.
  10025.  
  10026. ╓┌───────────────────────────────────────┌────────────┌──────────────────────╖
  10027.                                          Handle       FCB
  10028.       Operation                          Function     Function
  10029.       ──────────────────────────────────────────────────────────────────
  10030.       Create file.                       3CH          16H
  10031.       Create new file.                   5BH
  10032.       Create temporary file.             5AH
  10033.       Open file.                         3DH          0FH
  10034.       Close file.                        3EH          10H
  10035.       Delete file.                       41H          13H
  10036.       Rename file.                       56H          17H
  10037.       Perform sequential read.           3FH          14H
  10038.       Perform sequential write.          40H          15H
  10039.       Perform random record read.        3FH          21H
  10040.                                          Handle       FCB
  10041.       Operation                          Function     Function
  10042.      Perform random record read.        3FH          21H
  10043.       Perform random record write.       40H          22H
  10044.       Perform random block read.                      27H
  10045.       Perform random block write.                     28H
  10046.       Set disk transfer area address.                 1AH
  10047.       Get disk transfer area address.                 2FH
  10048.       Parse filename.                                 29H
  10049.       Position read/write pointer.       42H
  10050.       Set random record number.                       24H
  10051.       Get file size.                     42H          23H
  10052.       Get/Set file attributes.           43H
  10053.       Get/Set date and time stamp.       57H
  10054.       Duplicate file handle.             45H
  10055.       Redirect file handle.              46H
  10056.  
  10057.  
  10058.  Using the Handle Functions
  10059.  
  10060.       The initial link between an application program and the data stored on
  10061.       disk is the name of a disk file in the form
  10062.  
  10063.       drive:path\filename.ext
  10064.  
  10065.       where drive designates the disk on which the file resides, path
  10066.       specifies the directory on that disk in which the file is located, and
  10067.       filename.ext identifies the file itself. If drive and/or path is
  10068.       omitted, MS-DOS assumes the default disk drive and current directory.
  10069.       Examples of acceptable pathnames include
  10070.  
  10071.       C:\PAYROLL\TAXES.DAT
  10072.       LETTERS\MEMO.TXT
  10073.       BUDGET.DAT
  10074.  
  10075.       Pathnames can be hard-coded into a program as part of its data. More
  10076.       commonly, however, they are entered by the user at the keyboard,
  10077.       either as a command-line parameter or in response to a prompt from the
  10078.       program. If the pathname is provided as a commandline parameter, the
  10079.       application program must extract it from the other information in the
  10080.       command line. Therefore, to allow a program to distinguish between
  10081.       pathnames and other parameters when the two are combined in a command
  10082.       line, the other parameters, such as switches, usually begin with a
  10083.       slash (/) or dash (-) character.
  10084.  
  10085.       All handle functions that use a pathname require the name to be in the
  10086.       form of an ASCIIZ string--that is, the name must be terminated by a
  10087.       null (zero) byte. If the pathname is hard-coded into a program, the
  10088.       null byte must be part of the ASCIIZ string. If the pathname is
  10089.       obtained from keyboard input or from a command-line parameter, the
  10090.       null byte must be appended by the program. See Opening an Existing
  10091.       File, below.
  10092.  
  10093.       To use a disk file, a program opens or creates the file by calling the
  10094.       appropriate MS-DOS function with the ASCIIZ pathname. MS-DOS checks
  10095.       the pathname for invalid characters and, if the open or create
  10096.       operation is successful, returns a 16-bit handle, or identification
  10097.       code, for the file. The program uses this handle for subsequent
  10098.       operations on the file, such as record reads and writes.
  10099.  
  10100.       The total number of handles for simultaneously open files is limited
  10101.       in two ways. First, the per-process limit is 20 file handles. The
  10102.       process's first five handles are always assigned to  the standard
  10103.       devices, which default to the CON, AUX, and PRN character devices:
  10104.  
  10105. ╓┌──────────────┌───────────────────┌────────────────────────────────────────╖
  10106.       Handle    Service             Default
  10107.       ──────────────────────────────────────────────────────────────────
  10108.       0         Standard input      Keyboard (CON)
  10109.       1         Standard output     Video display (CON)
  10110.       2         Standard error      Video display (CON)
  10111.       3         Standard auxiliary  First communications port (AUX)
  10112.       4         Standard list       First parallel printer port (PRN)
  10113.  
  10114.       Ordinarily, then, a process has only 15 handles left from its initial
  10115.       allotment of 20; however, when necessary, the 5 standard device
  10116.       handles can be redirected to other files and devices or closed and
  10117.       reused.
  10118.  
  10119.       In addition to the per-process limit of 20 file handles, there is a
  10120.       system-wide limit. MS-DOS maintains an internal table that keeps track
  10121.       of all the files and devices opened with file handles for all
  10122.       currently active processes. The table contains such information as the
  10123.       current file pointer for read and write operations and the time and
  10124.       date of the last write to the file. The size of this table, which is
  10125.       set when MS-DOS is initially loaded into memory, determines the
  10126.       system-wide limit on how many files and devices can be open
  10127.       simultaneously. The default limit is 8 files and devices; thus, this
  10128.       system-wide limit usually overrides the per-process limit.
  10129.  
  10130.       To increase the size of MS-DOS's internal handle table, the statement
  10131.       FILES=nnn can be included in the CONFIG.SYS file. (CONFIG.SYS settings
  10132.       take effect the next time the system is turned on or restarted.) The
  10133.       maximum value for FILES is 99 in MS-DOS versions 2.x and 255 in
  10134.       versions 3.x. See USER COMMANDS: CONFIG.SYS: FILES.
  10135.  
  10136.  Error handling and the handle functions
  10137.  
  10138.       When a handle-based file function succeeds, MS-DOS returns to the
  10139.       calling program with the carry flag clear. If a handle function fails,
  10140.       MS-DOS sets the carry flag and returns an error code in the AX
  10141.       register. The program should check the carry flag after each operation
  10142.       and take whatever action is appropriate when an error is encountered.
  10143.       Table 7-2 lists the most frequently encountered error codes for file
  10144.       and record I/O (exclusive of network operations).
  10145.  
  10146.  
  10147.       Table 7-2. Frequently Encountered Error Diagnostics for File and
  10148.                  Record Management.
  10149.  
  10150. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  10151.       Code        Error
  10152.       ──────────────────────────────────────────────────────────────────
  10153.       02          File not found
  10154.       03          Path not found
  10155.       04          Too many open files (no handles left)
  10156.       05          Access denied
  10157.       06          Invalid handle
  10158.       11          Invalid format
  10159.       12          Invalid access code
  10160.       13          Invalid data
  10161.       15          Invalid disk drive letter
  10162.       17          Not same device
  10163.       18          No more files
  10164.  
  10165.  
  10166.       The error codes used by MS-DOS in versions 3.0 and later are a
  10167.       superset of the MS-DOS version 2.0 error codes. See APPENDIX B:
  10168.       CRITICAL ERROR CODES; APPENDIX C: EXTENDED ERROR CODES. Most MS-DOS
  10169.       version 3 error diagnostics relate to network operations, which
  10170.       provide the program with a greater chance for error than does a
  10171.       single-user system.
  10172.  
  10173.       Programs that are to run in a network environment need to anticipate
  10174.       network problems. For example, the server can go down while the
  10175.       program is using shared files.
  10176.  
  10177.       Under MS-DOS versions 3.x, a program can also use Interrupt 21H
  10178.       Function 59H (Get Extended Error Information) to obtain more details
  10179.       about the cause of an error after a failed handle function. The
  10180.       information returned by Function 59H includes the type of device that
  10181.       caused the error and a recommended recovery action.
  10182.  
  10183.       Warning: Many file and record I/O operations discussed in this article
  10184.       can result in or be affected by a hardware (critical) error. Such
  10185.       errors can be intercepted by the program if it contains a custom
  10186.       critical error exception handler (Interrupt 24H).See PROGRAMMING IN
  10187.       THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Exception Handlers.
  10188.  
  10189.  Creating a file
  10190.  
  10191.       MS-DOS provides three Interrupt 21H handle functions for creating
  10192.       files:
  10193.  
  10194. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  10195.       Function         Name
  10196.       ──────────────────────────────────────────────────────────────────
  10197.       3CH              Create File with Handle (versions 2.0 and later)
  10198.       5AH              Create Temporary File (versions 3.0 and later)
  10199.       5BH              Create New File (versions 3.0 and later)
  10200.  
  10201.       Each function is called with the segment and offset of an ASCIIZ
  10202.       pathname in the DS:DX registers and the attribute to be assigned to
  10203.       the new file in the CX register. The possible attribute values are
  10204.  
  10205. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  10206.       Code        Attribute
  10207.       ──────────────────────────────────────────────────────────────────
  10208.       Code        Attribute
  10209.       ──────────────────────────────────────────────────────────────────
  10210.       00H         Normal file
  10211.       01H         Read-only file
  10212.       02H         Hidden file
  10213.       04H         System file
  10214.  
  10215.       Files with more than one attribute can be created by combining the
  10216.       values listed above. For example, to create a file that has both the
  10217.       read-only and system attributes, the value 05H is placed in the CX
  10218.       register.
  10219.  
  10220.       If the file is successfully created, MS-DOS returns a file handle in
  10221.       AX that must be used for subsequent access to the new file and sets
  10222.       the file read/write pointer to the beginning of the file; if the file
  10223.       is not created, MS-DOS sets the carry flag (CF) and returns an error
  10224.       code in AX.
  10225.  
  10226.       Function 3CH is the only file-creation function available under MS-DOS
  10227.       versions 2.x. It must be used with caution, however, because if a file
  10228.       with the specified name already exists, Function 3CH will open it and
  10229.       truncate it to zero length, eradicating the previous contents of the
  10230.       file. This complication can be avoided by testing for the previous
  10231.       existence of the file with an open operation before issuing the create
  10232.       call.
  10233.  
  10234.       Under MS-DOS versions 3.0 and later, Function 5BH is the preferred
  10235.       function in most cases because it will fail if a file with the same
  10236.       name already exists. In networking environments, this function can be
  10237.       used to implement semaphores, allowing the synchronization of programs
  10238.       running in different network nodes.
  10239.  
  10240.       Function 5AH is used to create a temporary work file that is
  10241.       guaranteed to have a unique name. This capability is important in
  10242.       networking environments, where several copies of the same program,
  10243.       running in different nodes, may be accessing the same logical disk
  10244.       volume on a server. The function is passed the address of a buffer
  10245.       that can contain a drive and/or path specifying the location for the
  10246.       created file. MS-DOS generates a name for the created file that is a
  10247.       sequence of alphanumeric characters derived from the current time and
  10248.       returns the entire ASCIIZ pathname to the program in the same buffer,
  10249.       along with the file's handle in AX. The program must save the filename
  10250.       so that it can delete the file later, if necessary; the file created
  10251.       with Function 5AH is not destroyed when the program exits.
  10252.  
  10253.       Example: Create a file named MEMO.TXT in the \LETTERS directory on
  10254.       drive C using Function 3CH. Any existing file with the same name is
  10255.       truncated to zero length and opened.
  10256.  
  10257.       fname   db      'C:\LETTERS\MEMO.TXT',0
  10258.       fhandle dw      ?
  10259.               .
  10260.               .
  10261.               .
  10262.               mov     dx,seg fname    ; DS:DX = address of
  10263.               mov     ds,dx           ; pathname for file
  10264.               mov     dx,offset fname
  10265.               xor     cx,cx           ; CX = normal attribute
  10266.               mov     ah,3ch          ; Function 3CH = create
  10267.               int     21h             ; transfer to MS-DOS
  10268.               jc      error           ; jump if create failed
  10269.               mov     fhandle,ax      ; else save file handle
  10270.               .
  10271.               .
  10272.               .
  10273.  
  10274.       Example: Create a temporary file using Function 5AH and place it in
  10275.       the \TEMP directory on drive C. MS-DOS appends the filename it
  10276.       generates to the original path in the buffer named fname. The
  10277.       resulting file specification can be used later to delete the file.
  10278.  
  10279.       fname   db      'C:\TEMP\'      ; generated ASCIIZ filename
  10280.               db      13 dup (0)      ; is appended by MS-DOS
  10281.  
  10282.       fhandle dw      ?
  10283.               .
  10284.               .
  10285.               .
  10286.               mov     dx,seg fname    ; DS:DX = address of
  10287.               mov     ds,dx           ; path for temporary file
  10288.               mov     dx,offset fname
  10289.               xor     cx,cx           ; CX = normal attribute
  10290.               mov     ah,5ah          ; Function 5AH = create
  10291.                                       ; temporary file
  10292.               int     21h             ; transfer to MS-DOS
  10293.               jc      error           ; jump if create failed
  10294.               mov     fhandle,ax      ; else save file handle
  10295.               .
  10296.               .
  10297.               .
  10298.  
  10299.  Opening an existing file
  10300.  
  10301.       Function 3DH (Open File with Handle) opens an existing normal, system,
  10302.       or hidden file in the current or specified directory. When calling
  10303.       Function 3DH, the program supplies a pointer to the ASCIIZ pathname in
  10304.       the DS:DX registers and a 1-byte access code in the AL register. This
  10305.       access code includes the read/write permissions, the file-sharing
  10306.       mode, and an inheritance flag. The bits of the access code are
  10307.       assigned as follows:
  10308.  
  10309. ╓┌──────────────┌────────────────────────────────────────────────────────────╖
  10310.       Bit(s)    Description
  10311.       ──────────────────────────────────────────────────────────────────
  10312.       0-2       Read/write permissions (versions 2.0 and later)
  10313.       Bit(s)    Description
  10314.      0-2       Read/write permissions (versions 2.0 and later)
  10315.       3         Reserved
  10316.       4-6       File-sharing mode (versions 3.0 and later)
  10317.       7         Inheritance flag (versions 3.0 and later)
  10318.  
  10319.       The read/write permissions field of the access code specifies how the
  10320.       file will be used and can take the following values:
  10321.  
  10322. ╓┌──────────────┌────────────────────────────────────────────────────────────╖
  10323.       Bits 0-2  Description
  10324.       ──────────────────────────────────────────────────────────────────
  10325.       000       Read permission desired
  10326.       001       Write permission desired
  10327.       010       Read and write permission desired
  10328.  
  10329.       For the open to succeed, the permissions field must be compatible with
  10330.       the file's attribute byte in the disk directory. For example, if the
  10331.       program attempts to open an existing file that has the read-only
  10332.       attribute when the permissions field of the access code byte is set to
  10333.       write or read/write, the open function will fail and an error code
  10334.       will be returned in AX.
  10335.  
  10336.       The sharing-mode field of the access code byte is important in a
  10337.       networking environment. It determines whether other programs will also
  10338.       be allowed to open the file and, if so, what operations they will be
  10339.       allowed to perform. Following are the possible values of the file-
  10340.       sharing mode field:
  10341.  
  10342. ╓┌──────────────┌────────────────────────────────────────────────────────────╖
  10343.       Bits 4-6  Description
  10344.       ──────────────────────────────────────────────────────────────────
  10345.       000       Compatibility mode. Other programs can open the file and
  10346.                 perform read or write operations as long as no process
  10347.                 specifies any sharing mode other than compatibility mode.
  10348.  
  10349.       001       Deny all. Other programs cannot open the file.
  10350.  
  10351.       010       Deny write. Other programs cannot open the file in
  10352.                 compatibility mode or with write permission.
  10353.  
  10354.       011       Deny read. Other programs cannot open the file in
  10355.       Bits 4-6  Description
  10356.      011       Deny read. Other programs cannot open the file in
  10357.                 compatibility mode or with read permission.
  10358.  
  10359.       100       Deny none. Other programs can open the file and perform both
  10360.                 read and write operations but cannot open the file in
  10361.                 compatibility mode.
  10362.  
  10363.       When file-sharing support is active (that is, SHARE.EXE has previously
  10364.       been loaded), the result of any open operation depends on both the
  10365.       contents of the permissions and file-sharing fields of the access code
  10366.       byte and the permissions and file-sharing requested by other processes
  10367.       that have already successfully opened the file.
  10368.  
  10369.       The inheritance bit of the access code byte controls whether a child
  10370.       process will inherit that file handle. If the inheritance bit is
  10371.       cleared, the child can use the inherited handle to access the file
  10372.       without performing its own open operation. Subsequent operations
  10373.       performed by the child process on inherited file handles also affect
  10374.       the file pointer associated with the parent's file handle. If the
  10375.       inheritance bit is set, the child process does not inherit the handle.
  10376.  
  10377.       If the file is opened successfully, MS-DOS returns its handle in AX
  10378.       and sets the file read/write pointer to the beginning of the file; if
  10379.       the file is not opened, MS-DOS sets the carry flag and returns an
  10380.       error code in AX.
  10381.  
  10382.       Example: Copy the first parameter from the program's command tail in
  10383.       the program segment prefix (PSP) into the array fname and append a
  10384.       null character to form an ASCIIZ filename. Attempt to open the file
  10385.       with compatibility sharing mode and read/write access. If the file
  10386.       does not already exist, create it and assign it a normal attribute.
  10387.  
  10388.       cmdtail equ     80h             ; PSP offset of command tail
  10389.       fname   db      64 dup (?)
  10390.       fhandle dw      ?
  10391.  
  10392.               .
  10393.               .
  10394.               .
  10395.                                       ; assume that DS already
  10396.                                       ; contains segment of PSP
  10397.                                       ; prepare to copy filename...
  10398.               mov     si,cmdtail      ; DS:SI = command tail
  10399.               mov     di,seg fname    ; ES:DI = buffer to receive
  10400.               mov     es,di           ; filename from command tail
  10401.               mov     di,offset fname
  10402.               cld                     ; safety first!
  10403.  
  10404.               lodsb                   ; check length of command tail
  10405.               or      al,al
  10406.               jz      error           ; jump, command tail empty
  10407.  
  10408.       label1:                         ; scan off leading spaces
  10409.               lodsb                   ; get next character
  10410.               cmp     al,20h          ; is it a space?
  10411.               jz      label1          ; yes, skip it
  10412.  
  10413.       label2:
  10414.               cmp     al,0dh          ; look for terminator
  10415.               jz      label3          ; quit if return found
  10416.               cmp     al,20h
  10417.               jz      label3          ; quit if space found
  10418.               stosb                   ; else copy this character
  10419.               lodsb                   ; get next character
  10420.               jmp     label2
  10421.  
  10422.       label3:
  10423.               xor     al,al           ; store final NULL to
  10424.               stosb                   ; create ASCIIZ string
  10425.  
  10426.                                       ; now open the file...
  10427.               mov     dx,seg fname    ; DS:DX = address of
  10428.               mov     ds,dx           ; pathname for file
  10429.               mov     dx,offset fname
  10430.               mov     ax,3d02h        ; Function 3DH = open r/w
  10431.               int     21h             ; transfer to MS-DOS
  10432.               jnc     label4          ; jump if file found
  10433.  
  10434.               cmp     ax,2            ; error 2 = file not found
  10435.               jnz     error           ; jump if other error
  10436.                                       ; else make the file...
  10437.               xor     cx,cx           ; CX = normal attribute
  10438.               mov     ah,3ch          ; Function 3CH = create
  10439.               int     21h             ; transfer to MS-DOS
  10440.               jc      error           ; jump if create failed
  10441.  
  10442.       label4:
  10443.               mov     fhandle,ax      ; save handle for file
  10444.               .
  10445.               .
  10446.               .
  10447.  
  10448.  Closing a file
  10449.  
  10450.       Function 3EH (Close File) closes a file created or opened with a file
  10451.       handle function. The program must place the handle of the file to be
  10452.       closed in BX. If a write operation was performed on the file, MS-DOS
  10453.       updates the date, time, and size in the file's directory entry.
  10454.  
  10455.       Closing the file also flushes the internal MS-DOS buffers associated
  10456.       with the file to disk and causes the disk's file allocation table
  10457.       (FAT) to be updated if necessary.
  10458.  
  10459.       Good programming practice dictates that a program close files as soon
  10460.       as it finishes using them. This practice is particularly important
  10461.       when the file size has been changed, to ensure that data will not be
  10462.       lost if the system crashes or is turned off unexpectedly by the user.
  10463.       A method of updating the FAT without closing the file is outlined
  10464.       below under Duplicating and Redirecting Handles.
  10465.  
  10466.  Reading and writing with handles
  10467.  
  10468.       Function 3FH (Read File or Device) enables a program to read data from
  10469.       a file or device that has been opened with a handle. Before calling
  10470.       Function 3FH, the program must set the DS:DX registers to point to the
  10471.       beginning of a data buffer large enough to hold the requested
  10472.       transfer, put the file handle in BX, and put the number of bytes to be
  10473.       read in CX. The length requested can be a maximum of 65535 bytes. The
  10474.       program requesting the read operation is responsible for providing the
  10475.       data buffer.
  10476.  
  10477.       If the read operation succeeds, the data is read, beginning at the
  10478.       current position of the file read/write pointer, to the specified
  10479.       location in memory. MS-DOS then increments its internal read/write
  10480.       pointer for the file by the length of the data transferred and returns
  10481.       the length to the calling program in AX with the carry flag cleared.
  10482.       The only indication that the end of the file has been reached is that
  10483.       the length returned is less than the length requested. In contrast,
  10484.       when Function 3FH is used to read from a character device that is not
  10485.       in raw mode, the read will terminate at the requested length or at the
  10486.       receipt of a carriage return character, whichever comes first. See
  10487.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS:
  10488.       Character Device Input and Output. If the read operation fails, MS-DOS
  10489.       returns with the carry flag set and an error code in AX.
  10490.  
  10491.       Function 40H (Write File or Device) writes from a buffer to a file (or
  10492.       device) using a handle previously obtained from an open or create
  10493.       operation. Before calling Function 40H, the program must set DS:DX to
  10494.       point to the beginning of the buffer containing the source data, put
  10495.       the file handle in BX, and put the number of bytes to write in CX. The
  10496.       number of bytes to write can be a maximum of 65535.
  10497.  
  10498.       If the write operation is successful, MS-DOS puts the number of bytes
  10499.       written in AX and increments the read/write pointer by this value; if
  10500.       the write operation fails, MS-DOS sets the carry flag and returns an
  10501.       error code in AX.
  10502.  
  10503.       Records smaller than one sector (512 bytes) are not written directly
  10504.       to disk. Instead, MS-DOS stores the record in an internal buffer and
  10505.       writes it to disk when the internal buffer is full, when the file is
  10506.       closed, or when a call to Interrupt 21H Function 0DH (Disk Reset) is
  10507.       issued.
  10508.  
  10509.       Note: If the destination of the write operation is a disk file and the
  10510.       disk is full, the only indication to the calling program is that the
  10511.       length returned in AX is not the same as the length requested in CX.
  10512.       Disk full is not returned as an error with the carry flag set.
  10513.  
  10514.       A special use of the Write function is to truncate or extend a file.
  10515.       If Function 40H is called with a record length of zero in CX, the file
  10516.       size will be adjusted to the current location of the file read/write
  10517.       pointer.
  10518.  
  10519.       Example: Open the file MYFILE.DAT, create the file MYFILE.BAK, copy
  10520.       the contents of the .DAT file into the .BAK file using 512-byte reads
  10521.       and writes, and then close both files.
  10522.  
  10523.       file1   db      'MYFILE.DAT',0
  10524.       file2   db      'MYFILE.BAK',0
  10525.  
  10526.       handle1 dw      ?               ; handle for MYFILE.DAT
  10527.       handle2 dw      ?               ; handle for MYFILE.BAK
  10528.  
  10529.       buff    db      512 dup (?)     ; buffer for file I/O
  10530.               .
  10531.               .
  10532.               .
  10533.                                       ; open MYFILE.DAT...
  10534.               mov     dx,seg file1    ; DS:DX = address of filename
  10535.               mov     ds,dx
  10536.               mov     dx,offset file1
  10537.               mov     ax,3d00h        ; Function 3DH = open (read-only)
  10538.               int     21h             ; transfer to MS-DOS
  10539.               jc      error           ; jump if open failed
  10540.               mov     handle1,ax      ; save handle for file
  10541.  
  10542.                                       ; create MYFILE.BAK...
  10543.               mov     dx,offset file2 ; DS:DX = address of filename
  10544.               mov     cx,0            ; CX = normal attribute
  10545.               mov     ah,3ch          ; Function 3CH = create
  10546.               int     21h             ; transfer to MS-DOS
  10547.               jc      error           ; jump if create failed
  10548.               mov     handle2,ax      ; save handle for file
  10549.  
  10550.       loop:                           ; read MYFILE.DAT
  10551.               mov     dx,offset buff  ; DS:DX = buffer address
  10552.               mov     cx,512          ; CX = length to read
  10553.               mov     bx,handle1      ; BX = handle for MYFILE.DAT
  10554.               mov     ah,3fh          ; Function 3FH = read
  10555.               int     21h             ; transfer to MS-DOS
  10556.               jc      error           ; jump if read failed
  10557.               or      ax,ax           ; were any bytes read?
  10558.               jz      done            ; no, end of file reached
  10559.  
  10560.                                       ; write MYFILE.BAK
  10561.               mov     dx,offset buff  ; DS:DX = buffer address
  10562.               mov     cx,ax           ; CX = length to write
  10563.               mov     bx,handle2      ; BX = handle for MYFILE.BAK
  10564.               mov     ah,40h          ; Function 40H = write
  10565.               int     21h             ; transfer to MS-DOS
  10566.               jc      error           ; jump if write failed
  10567.               cmp     ax,cx           ; was write complete?
  10568.               jne     error           ; jump if disk full
  10569.               jmp     loop            ; continue to end of file
  10570.       done:                           ; now close files...
  10571.               mov     bx,handle1      ; handle for MYFILE.DAT
  10572.               mov     ah,3eh          ; Function 3EH = close file
  10573.               int     21h             ; transfer to MS-DOS
  10574.               jc      error           ; jump if close failed
  10575.  
  10576.               mov     bx,handle2      ; handle for MYFILE.BAK
  10577.               mov     ah,3eh          ; Function 3EH = close file
  10578.               int     21h             ; transfer to MS-DOS
  10579.               jc      error           ; jump if close failed
  10580.  
  10581.               .
  10582.               .
  10583.               .
  10584.  
  10585.  Positioning the read/write pointer
  10586.  
  10587.       Function 42H (Move File Pointer) sets the position of the read/write
  10588.       pointer associated with a given handle. The function is called with a
  10589.       signed 32-bit offset in the CX and DX registers (the most significant
  10590.       half in CX), the file handle in BX, and the positioning mode in AL:
  10591.  
  10592. ╓┌──────────────┌────────────────────────────────────────────────────────────╖
  10593.       Mode      Significance
  10594.       ──────────────────────────────────────────────────────────────────
  10595.       00        Supplied offset is relative to beginning of file.
  10596.       01        Supplied offset is relative to current position of
  10597.                 read/write pointer.
  10598.       02        Supplied offset is relative to end of file.
  10599.  
  10600.       If Function 42H succeeds, MS-DOS returns the resulting absolute offset
  10601.       (in bytes) of the file pointer relative to the beginning of the file
  10602.       in the DX and AX registers, with the most significant half in DX; if
  10603.       the function fails, MS-DOS sets the carry flag and returns an error
  10604.       code in AX.
  10605.  
  10606.       Thus, a program can obtain the size of a file by calling Function 42H
  10607.       with an offset of zero and a positioning mode of 2. The function
  10608.       returns a value in DX:AX that represents the offset of the end-of-file
  10609.       position relative to the beginning of the file.
  10610.  
  10611.       Example: Assume that the file MYFILE.DAT was previously opened and its
  10612.       handle is saved in the variable fhandle. Position the file pointer
  10613.       32768 bytes from the beginning of the file and then read 512 bytes of
  10614.       data starting at that file position.
  10615.  
  10616.       fhandle dw      ?               ; handle from previous open
  10617.       buff    db      512 dup (?)     ; buffer for data from file
  10618.  
  10619.               .
  10620.               .
  10621.               .
  10622.                                       ; position the file pointer...
  10623.               mov     cx,0            ; CX = high part of file offset
  10624.               mov     dx,32768        ; DX = low part of file offset
  10625.               mov     bx,fhandle      ; BX = handle for file
  10626.               mov     al,0            ; AL = positioning mode
  10627.               mov     ah,42h          ; Function 42H = position
  10628.               int     21h             ; transfer to MS-DOS
  10629.               jc      error           ; jump if function call failed
  10630.  
  10631.                                       ; now read 512 bytes from file
  10632.               mov     dx,offset buff  ; DS:DX = address of buffer
  10633.               mov     cx,512          ; CX = length of 512 bytes
  10634.               mov     bx,fhandle      ; BX = handle for file
  10635.               mov     ah,3fh          ; Function 3FH = read
  10636.               int     21h             ; transfer to MS-DOS
  10637.               jc      error           ; jump if read failed
  10638.               cmp     ax,512          ; was 512 bytes read?
  10639.               jne     error           ; jump if partial rec. or EOF
  10640.               .
  10641.               .
  10642.               .
  10643.  
  10644.       Example: Assume that the file MYFILE.DAT was previously opened and its
  10645.       handle is saved in the variable fhandle. Find the size of the file in
  10646.       bytes by positioning the file pointer to zero bytes relative to the
  10647.       end of the file. The returned offset, which is relative to the
  10648.       beginning of the file, is the file's size.
  10649.  
  10650.       fhandle dw      ?               ; handle from previous open
  10651.  
  10652.               .
  10653.               .
  10654.               .
  10655.                                       ; position the file pointer
  10656.                                       ; to the end of file...
  10657.               mov     cx,0            ; CX = high part of offset
  10658.               mov     dx,0            ; DX = low part of offset
  10659.               mov     bx,fhandle      ; BX = handle for file
  10660.               mov     al,2            ; AL = positioning mode
  10661.               mov     ah,42h          ; Function 42H = position
  10662.               int     21h             ; transfer to MS-DOS
  10663.               jc      error           ; jump if function call failed
  10664.  
  10665.                                       ; if call succeeded, DX:AX
  10666.                                       ; now contains the file size
  10667.               .
  10668.               .
  10669.               .
  10670.  
  10671.  Other handle operations
  10672.  
  10673.       MS-DOS provides other handle-oriented functions to rename (or move) a
  10674.       file, delete a file, read or change a file's attributes, read or
  10675.       change a file's date and time stamp, and duplicate or redirect a file
  10676.       handle. The first three of these are "file-handle-like" because they
  10677.       use an ASCIIZ string to specify the file; however, they do not return
  10678.       a file handle.
  10679.  
  10680.  Renaming a file
  10681.       Function 56H (Rename File) renames an existing file and/or moves the
  10682.       file from one location in the hierarchical file structure to another.
  10683.       The file to be renamed cannot be a hidden or system file or a
  10684.       subdirectory and must not be currently open by any process; attempting
  10685.       to rename an open file can corrupt the disk. MS-DOS renames a file by
  10686.       simply changing its directory entry; it moves a file by removing its
  10687.       current directory entry and creating a new entry in the target
  10688.       directory that refers to the same file. The location of the file's
  10689.       actual data on the disk is not changed.
  10690.  
  10691.       Both the current and the new filenames must be ASCIIZ strings and can
  10692.       include a drive and path specification; wildcard characters (* and ?)
  10693.       are not permitted in the filenames. The program calls Function 56H
  10694.       with the address of the current pathname in the DS:DX registers and
  10695.       the address of the new pathname in ES:DI. If the path elements of the
  10696.       two strings are not the same and both paths are valid, the file
  10697.       "moves" from the source directory to the target directory. If the
  10698.       paths match but the filenames differ, MS-DOS simply modifies the
  10699.       directory entry to reflect the new filename.
  10700.  
  10701.       If the function succeeds, MS-DOS returns to the calling program with
  10702.       the carry flag clear. The function fails if the new filename is
  10703.       already in the target directory; in that case, MS-DOS sets the carry
  10704.       flag and returns an error code in AX.
  10705.  
  10706.       Example: Change the name of the file MYFILE.DAT to MYFILE.OLD. In the
  10707.       same operation, move the file from the \WORK directory to the \BACKUP
  10708.       directory.
  10709.  
  10710.       file1   db      '\WORK\MYFILE.DAT',0
  10711.       file2   db      '\BACKUP\MYFILE.OLD',0
  10712.               .
  10713.               .
  10714.               .
  10715.               mov     dx,seg file1    ; DS:DX = old filename
  10716.               mov     ds,dx
  10717.               mov     es,dx
  10718.               mov     dx,offset file1
  10719.               mov     di,offset file2 ; ES:DI = new filename
  10720.               mov     ah,56h          ; Function 56H = rename
  10721.               int     21h             ; transfer to MS-DOS
  10722.               jc      error           ; jump if rename failed
  10723.               .
  10724.               .
  10725.               .
  10726.  
  10727.  Deleting a file
  10728.       Function 41H (Delete File) effectively deletes a file from a disk.
  10729.       Before calling the function, a program must set the DS:DX registers to
  10730.       point to the ASCIIZ pathname of the file to be deleted. The supplied
  10731.       pathname cannot specify a subdirectory or a read-only file, and the
  10732.       file must not be currently open by any process.
  10733.  
  10734.       If the function is successful, MS-DOS deletes the file by simply
  10735.       marking the first byte of its directory entry with a special character
  10736.       (0E5H), making the entry subsequently unrecognizable. MS-DOS then
  10737.       updates the disk's FAT so that the clusters that previously belonged
  10738.       to the file are "free" and returns to the program with the carry flag
  10739.       clear. If the delete function fails, MS-DOS sets the carry flag and
  10740.       returns an error code in AX.
  10741.  
  10742.       The actual contents of the clusters assigned to the file are not
  10743.       changed by a delete operation, so for security reasons sensitive
  10744.       information should be overwritten with spaces or some other constant
  10745.       character before the file is deleted with Function 41H.
  10746.  
  10747.       Example: Delete the file MYFILE.DAT, located in the \WORK directory on
  10748.       drive C.
  10749.  
  10750.       fname   db      'C:\WORK\MYFILE.DAT',0
  10751.               .
  10752.               .
  10753.               .
  10754.               mov     dx,seg fname    ; DS:DX = address of filename
  10755.               mov     ds,dx
  10756.               mov     dx,offset fname
  10757.               mov     ah,41h          ; Function 41H = delete
  10758.               int     21h             ; transfer to MS-DOS
  10759.               jc      error           ; jump if delete failed
  10760.               .
  10761.               .
  10762.               .
  10763.  
  10764.  Getting/setting file attributes
  10765.       Function 43H (Get/Set File Attributes) obtains or modifies the
  10766.       attributes of an existing file. Before calling Function 43H, the
  10767.       program must set the DS:DX registers to point to the ASCIIZ pathname
  10768.       for the file. To read the attributes, the program must set AL to zero;
  10769.       to set the attributes, it must set AL to 1 and place an attribute code
  10770.       in CX. See Creating a File, above.
  10771.  
  10772.       If the function is successful, MS-DOS reads or sets the attribute byte
  10773.       in the file's directory entry and returns with the carry flag clear
  10774.       and the file's attribute in CX. If the function fails, MS-DOS sets the
  10775.       carry flag and returns an error code in AX.
  10776.  
  10777.       Function 43H cannot be used to set the volume-label bit (bit 3) or the
  10778.       subdirectory bit (bit 4) of a file. It also should not be used on a
  10779.       file that is currently open by any process.
  10780.  
  10781.       Example: Change the attributes of the file MYFILE.DAT in the \BACKUP
  10782.       directory on drive C to read-only. This prevents the file from being
  10783.       accidentally deleted from the disk.
  10784.  
  10785.       fname   db      'C:\BACKUP\MYFILE.DAT',0
  10786.               .
  10787.               .
  10788.               .
  10789.               mov     dx,seg fname    ; DS:DX = address of filename
  10790.               mov     ds,dx
  10791.               mov     dx,offset fname
  10792.               mov     cx,1            ; CX = attribute (read-only)
  10793.               mov     al,1            ; AL = mode (0 = get, 1 = set)
  10794.               mov     ah,43h          ; Function 43H = get/set attr
  10795.               int     21h             ; transfer to MS-DOS
  10796.               jc      error           ; jump if set attrib. failed
  10797.               .
  10798.               .
  10799.               .
  10800.  
  10801.  Getting/setting file date and time
  10802.       Function 57H (Get/Set Date/Time of File) reads or sets the directory
  10803.       time and date stamp of an open file. To set the time and date to a
  10804.       particular value, the program must call Function 57H with the desired
  10805.       time in CX, the desired date in DX, the handle for the file (obtained
  10806.       from a previous open or create operation) in BX, and the value 1 in
  10807.       AL. To read the time and date, the function is called with AL
  10808.       containing 0 and the file handle in BX; the time is returned in the CX
  10809.       register and the date is returned in the DX register. As with other
  10810.       handle-oriented file functions, if the function succeeds, the carry
  10811.       flag is returned cleared; if the function fails, MS-DOS returns the
  10812.       carry flag set and an error code in AX.
  10813.  
  10814.       The formats used for the file time and date are the same as those used
  10815.       in disk directory entries and FCBs. See Structure of the File Control
  10816.       Block, below.
  10817.  
  10818.       The main uses of Function 57H are to force the time and date entry for
  10819.       a file to be updated when the file has not been changed and to
  10820.       circumvent MS-DOS's modification of a file date and time when the file
  10821.       has been changed. In the latter case, a program can use this function
  10822.       with AL = 0 to obtain the file's previous date and time stamp, modify
  10823.       the file, and then restore the original file date and time by re-
  10824.       calling the function with AL = 1 before closing the file.
  10825.  
  10826.  Duplicating and redirecting handles
  10827.       Ordinarily, the disk FAT and directory are not updated until a file is
  10828.       closed, even when the file has been modified. Thus, until the file is
  10829.       closed, any new data added to the file can be lost if the system
  10830.       crashes or is turned off unexpectedly. The obvious defense against
  10831.       such loss is simply to close and reopen the file every time the file
  10832.       is changed. However, this is a relatively slow procedure and in a
  10833.       network environment can cause the program to lose control of the file
  10834.       to another process.
  10835.  
  10836.       Use of a second file handle, created by using Function 45H (Duplicate
  10837.       File Handle) to duplicate the original handle of the file to be
  10838.       updated, can protect data added to a disk file before the file is
  10839.       closed. To use Function 45H, the program must put the handle to be
  10840.       duplicated in BX. If the operation is successful, MS-DOS clears the
  10841.       carry flag and returns the new handle in AX; if the operation fails,
  10842.       MS-DOS sets the carry flag and returns an error code in AX.
  10843.  
  10844.       If the function succeeds, the duplicate handle can simply be closed in
  10845.       the usual manner with Function 3EH. This forces the desired update of
  10846.       the disk directory and FAT. The original handle remains open and the
  10847.       program can continue to use it for file read and write operations.
  10848.  
  10849.       Note: While the second handle is open, moving the read/write pointer
  10850.       associated with either handle moves the pointer associated with the
  10851.       other.
  10852.  
  10853.       Example: Assume that the file MYFILE.DAT was previously opened and the
  10854.       handle for that file has been saved in the variable fhandle. Duplicate
  10855.       the handle and then close the duplicate to ensure that any data
  10856.       recently written to the file is saved on the disk and that the
  10857.       directory entry for the file is updated accordingly.
  10858.  
  10859.       fhandle dw      ?               ; handle from previous open
  10860.  
  10861.               .
  10862.               .
  10863.               .
  10864.                                       ; duplicate the handle...
  10865.               mov     bx,fhandle      ; BX = handle for file
  10866.               mov     ah,45h          ; Function 45H = dup handle
  10867.               int     21h             ; transfer to MS-DOS
  10868.               jc      error           ; jump if function call failed
  10869.  
  10870.                                       ; now close the new handle...
  10871.               mov     bx,ax           ; BX = duplicated handle
  10872.               mov     ah,3eh          ; Function 3EH = close
  10873.               int     21h             ; transfer to MS-DOS
  10874.               jc      error           ; jump if close failed
  10875.               mov     bx,fhandle      ; replace closed handle with
  10876.                                       ; active handle
  10877.               .
  10878.               .
  10879.               .
  10880.  
  10881.       Function 45H is sometimes also used in conjunction with Function 46H
  10882.       (Force Duplicate File Handle). Function 46H forces a handle to be a
  10883.       duplicate for another open handle--in other words, to refer to the
  10884.       same file or device at the same file read/write pointer location. The
  10885.       handle is then said to be redirected.
  10886.  
  10887.       The most common use of Function 46H is to change the meaning of the
  10888.       standard input and standard output handles before loading a child
  10889.       process with the EXEC function. In this manner, the input for the
  10890.       child program can be redirected to come from a file or its output can
  10891.       be redirected into a file, without any special knowledge on the part
  10892.       of the child program. In such cases, Function 45H is used to also
  10893.       create duplicates of the standard input and standard output handles
  10894.       before they are redirected, so that their original meanings can be
  10895.       restored after the child exits. See PROGRAMMING IN THE MS-DOS
  10896.       ENVIRONMENT: CUSTOMIZING MS-DOS: Writing MS-DOS Filters.
  10897.  
  10898.  
  10899.  Using the FCB Functions
  10900.  
  10901.       A file control block is a data structure, located in the application
  10902.       program's memory space, that contains relevant information about an
  10903.       open disk file: the disk drive, the filename and extension, a pointer
  10904.       to a position within the file, and so on. Each open file must have its
  10905.       own FCB. The information in an FCB is maintained cooperatively by both
  10906.       MS-DOS and the application program.
  10907.  
  10908.       MS-DOS moves data to and from a disk file associated with an FCB by
  10909.       means of a data buffer called the disk transfer area (DTA). The
  10910.       current address of the DTA is under the control of the application
  10911.       program, although each program has a 128-byte default DTA at offset
  10912.       80H in its program segment prefix (PSP). See PROGRAMMING IN THE MS-DOS
  10913.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: Structure of an Application
  10914.       Program.
  10915.  
  10916.       Under early versions of MS-DOS, the only limit on the number of files
  10917.       that can be open simultaneously with FCBs is the amount of memory
  10918.       available to the application to hold the FCBs and their associated
  10919.       disk buffers. However, under MS-DOS versions 3.0 and later, when file-
  10920.       sharing support (SHARE.EXE) is loaded, MS-DOS places some restrictions
  10921.       on the use of FCBs to simplify the job of maintaining network
  10922.       connections for files. If the application attempts to open too many
  10923.       FCBs, MS-DOS simply closes the least recently used FCBs to keep the
  10924.       total number within a limit.
  10925.  
  10926.       The CONFIG.SYS file directive FCBS allows the user to control the
  10927.       allowed maximum number of FCBs and to specify a certain number of FCBs
  10928.       to be protected against automatic closure by the system. The default
  10929.       values are a maximum of four files open simultaneously using FCBs and
  10930.       zero FCBs protected from automatic closure by the system. See USER
  10931.       COMMANDS: CONFIG.SYS: FCBS.
  10932.  
  10933.       Because the FCB operations predate MS-DOS version 2.0 and because FCBs
  10934.       have a fixed structure with no room to contain a path, the FCB file
  10935.       and record services do not support the hierarchical directory
  10936.       structure. Many FCB operations can be performed only on files in the
  10937.       current directory of a disk. For this reason, the use of FCB file and
  10938.       record operations should be avoided in new programs.
  10939.  
  10940.  Structure of the file control block
  10941.  
  10942.       Each FCB is a 37-byte array allocated from its own memory space by the
  10943.       application program that will use it. The FCB contains all the
  10944.       information needed to identify a disk file and access the data within
  10945.       it: drive identifier, filename, extension, file size, record size,
  10946.       various file pointers, and date and time stamps. The FCB structure is
  10947.       shown in Table 7-3.
  10948.  
  10949.  
  10950.       Table 7-3. Structure of a Normal File Control Block.
  10951.  
  10952. ╓┌──────────────────────┌───────────┌──────────────┌─────────────────────────╖
  10953.                         Offset      Size
  10954.       Maintained by     (bytes)     (bytes)        Description
  10955.       ──────────────────────────────────────────────────────────────────
  10956.       Program           00H         1              Drive identifier
  10957.       Program           01H         8              Filename
  10958.       Program           09H         3              File extension
  10959.       MS-DOS            0CH         2              Current block number
  10960.       Program           0EH         2              Record size (bytes)
  10961.       MS-DOS            10H         4              File size (bytes)
  10962.       MS-DOS            14H         2              Date stamp
  10963.       MS-DOS            16H         2              Time stamp
  10964.                         Offset      Size
  10965.       Maintained by     (bytes)     (bytes)        Description
  10966.      MS-DOS            16H         2              Time stamp
  10967.       MS-DOS            18H         8              Reserved
  10968.       MS-DOS            20H         1              Current record number
  10969.       Program           21H         4              Random record number
  10970.  
  10971.  
  10972.       Drive identifier: Initialized by the application to designate the
  10973.       drive on which the file to be opened or created resides. 0 = default
  10974.       drive, 1 = drive A, 2 = drive B, and so on. If the application
  10975.       supplies a zero in this byte (to use the default drive), MS-DOS alters
  10976.       the byte during the open or create operation to reflect the actual
  10977.       drive used; that is, after an open or create operation, this drive
  10978.       will always contain a value of 1 or greater.
  10979.  
  10980.       Filename: Standard eight-character filename; initialized by the
  10981.       application; must be left justified and padded with blanks if the name
  10982.       has fewer than eight characters. A device name (for example, PRN) can
  10983.       be used; note that there is no colon after a device name.
  10984.  
  10985.       File extension: Three-character file extension; initialized by the
  10986.       application; must be left justified and padded with blanks if the
  10987.       extension has fewer than three characters.
  10988.  
  10989.       Current block number: Initialized to zero by MS-DOS when the file is
  10990.       opened. The block number and the record number together make up the
  10991.       record pointer during sequential file access.
  10992.  
  10993.       Record size: The size of a record (in bytes) as used by the program.
  10994.       MS-DOS sets this field to 128 when the file is opened or created; the
  10995.       program can modify the field afterward to any desired record size. If
  10996.       the record size is larger than 128 bytes, the default DTA in the PSP
  10997.       cannot be used because it will collide with the program's own code or
  10998.       data.
  10999.  
  11000.       File size: The size of the file in bytes. MS-DOS initializes this
  11001.       field from the file's directory entry when the file is opened. The
  11002.       first 2 bytes of this 4-byte field are the least significant bytes of
  11003.       the file size.
  11004.  
  11005.       Date stamp: The date of the last write operation on the file. MS-DOS
  11006.       initializes this field from the file's directory entry when the file
  11007.       is opened. This field uses the same format used by file handle
  11008.       Function 57H (Get/Set/Date/Time of File):
  11009.  
  11010.  
  11011.                                       Date Format
  11012.  
  11013.      Bit:   15   14  13  12  11  10   9   8 ║ 7   6   5   4   3   2   1   0
  11014.                                             ║
  11015.  Content:   ┌───╥───╥───╥───╥───╥───╥───╥───╫───╥───╥───╥───╥───╥───╥───╥───┐
  11016.             │ Y ║ Y ║ Y ║ Y ║ Y ║ Y ║ Y ║ M ║ M ║ M ║ M ║ D ║ D ║ D ║ D ║ D │
  11017.             └───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───┘
  11018.  
  11019.  
  11020. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  11021.       Bits        Contents
  11022.       ──────────────────────────────────────────────────────────────────
  11023.       0-4         Day of month (1-31)
  11024.       5-8         Month (1-12)
  11025.       9-15        Year (relative to 1980)
  11026.  
  11027.       Time stamp: The time of the last write operation on the file. MS-DOS
  11028.       initializes this field from the file's directory entry when the file
  11029.       is opened. This field uses the same format used by file handle
  11030.       Function 57H (Get/Set/Date/Time of File):
  11031.  
  11032.  
  11033.                                       Time Format
  11034.  
  11035.      Bit:   15   14  13  12  11  10   9   8 ║ 7   6   5   4   3   2   1   0
  11036.                                             ║
  11037.  Content:   ┌───╥───╥───╥───╥───╥───╥───╥───╫───╥───╥───╥───╥───╥───╥───╥───┐
  11038.             │ H ║ H ║ H ║ H ║ H ║ M ║ M ║ M ║ M ║ M ║ M ║ S ║ S ║ S ║ S ║ S │
  11039.             └───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───╨───┘
  11040.  
  11041.  
  11042. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  11043.       Bits        Contents
  11044.       ──────────────────────────────────────────────────────────────────
  11045.        0-4        Number of 2-second increments (0-29)
  11046.        5-10       Minutes (0-59)
  11047.       11-15       Hours (0-23)
  11048.       Bits        Contents
  11049.      11-15       Hours (0-23)
  11050.  
  11051.       Current record number: Together with the block number, constitutes the
  11052.       record pointer used during sequential read and write operations. MS-
  11053.       DOS does not initialize this field when a file is opened. The record
  11054.       number is limited to the range 0 through 127; thus, there are 128
  11055.       records per block. The beginning of a file is record 0 of block 0.
  11056.  
  11057.       Random record pointer: A 4-byte field that identifies the record to be
  11058.       transferred by the random record functions 21H, 22H, 27H, and 28H. If
  11059.       the record size is 64 bytes or larger, only the first 3 bytes of this
  11060.       field are used. MS-DOS updates this field after random block reads and
  11061.       writes (Functions 27H and 28H) but not after random record reads and
  11062.       writes (Functions 21H and 22H).
  11063.  
  11064.       An extended FCB, which is 7 bytes longer than a normal FCB, can be
  11065.       used to access files with special attributes such as hidden, system,
  11066.       and read-only. The extra 7 bytes of an extended FCB are simply
  11067.       prefixed to the normal FCB format (Table 7-4). The first byte of an
  11068.       extended FCB always contains 0FFH, which could never be a legal drive
  11069.       code and therefore serves as a signal to MS-DOS that the extended
  11070.       format is being used. The next 5 bytes are reserved and must be zero,
  11071.       and the last byte of the prefix specifies the attributes of the file
  11072.       being manipulated. The remainder of an extended FCB has exactly the
  11073.       same layout as a normal FCB. In general, an extended FCB can be used
  11074.       with any MS-DOS function call that accepts a normal FCB.
  11075.  
  11076.  
  11077.       Table 7-4. Structure of an Extended File Control Block.
  11078.  
  11079. ╓┌──────────────────────┌─────────────┌───────────┌──────────────────────────╖
  11080.                         Offset        Size
  11081.       Maintained by     (bytes)       (bytes)     Description
  11082.       ──────────────────────────────────────────────────────────────────
  11083.       Program           00H           1           Extended FCB flag = 0FFH
  11084.       MS-DOS            01H           5           Reserved
  11085.       Program           06H           1           File attribute byte
  11086.       Program           07H           1           Drive identifier
  11087.       Program           08H           8           Filename
  11088.       Program           10H           3           File extension
  11089.       MS-DOS            13H           2           Current block number
  11090.                         Offset        Size
  11091.       Maintained by     (bytes)       (bytes)     Description
  11092.      MS-DOS            13H           2           Current block number
  11093.       Program           15H           2           Record size (bytes)
  11094.       MS-DOS            17H           4           File size (bytes)
  11095.       MS-DOS            1BH           2           Date stamp
  11096.       MS-DOS            1DH           2           Time stamp
  11097.       MS-DOS            1FH           8           Reserved
  11098.       MS-DOS            27H           1           Current record number
  11099.       Program           28H           4           Random record number
  11100.  
  11101.  
  11102.       Extended FCB flag: When 0FFH is present in the first byte of an FCB,
  11103.       it is a signal to MS-DOS that an extended FCB (44 bytes) is being used
  11104.       instead of a normal FCB (37 bytes).
  11105.  
  11106.       File attribute byte: Must be initialized by the application when an
  11107.       extended FCB is used to open or create a file. The bits of this field
  11108.       have the following significance:
  11109.  
  11110. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  11111.       Bit         Meaning
  11112.       ──────────────────────────────────────────────────────────────────
  11113.       0           Read-only
  11114.       1           Hidden
  11115.       2           System
  11116.       3           Volume label
  11117.       4           Directory
  11118.       5           Archive
  11119.       6           Reserved
  11120.       7           Reserved
  11121.  
  11122.  
  11123.  FCB functions and the PSP
  11124.  
  11125.       The PSP contains several items that are of interest when using the FCB
  11126.       file and record operations: two FCBs called the default FCBs, the
  11127.       default DTA, and the command tail for the program. The following table
  11128.       shows the size and location of these elements:
  11129.  
  11130. ╓┌──────────────────────────┌─────────────────┌──────────────────────────────╖
  11131.       PSP Offset            Size
  11132.       PSP Offset            Size
  11133.       (bytes)               (bytes)           Description
  11134.       ──────────────────────────────────────────────────────────────────
  11135.       5CH                    16               Default FCB #1
  11136.       6CH                    20               Default FCB #2
  11137.       80H                     1               Length of command tail
  11138.       81H                   127               Command-tail text
  11139.       80H                   128               Default disk transfer area
  11140.                                                (DTA)
  11141.  
  11142.       When MS-DOS loads a program into memory for execution, it copies the
  11143.       command tail into the PSP at offset 81H, places the length of the
  11144.       command tail in the byte at offset 80H, and parses the first two
  11145.       parameters in the command tail into the default FCBs at PSP offsets
  11146.       5CH and 6CH. (The command tail consists of the command line used to
  11147.       invoke the program minus the program name itself and any redirection
  11148.       or piping characters and their associated filenames or device names.)
  11149.       MS-DOS then sets the initial DTA address for the program to PSP:0080H.
  11150.  
  11151.       For several reasons, the default FCBs and the DTA are often moved to
  11152.       another location within the program's memory area. First, the default
  11153.       DTA allows processing of only very small records. In addition, the
  11154.       default FCBs overlap substantially, and the first byte of the default
  11155.       DTA and the last byte of the first FCB conflict. Finally, unless
  11156.       either the command tail or the DTA is moved beforehand, the first FCB-
  11157.       related file or record operation will destroy the command tail.
  11158.  
  11159.       Function 1AH (Set DTA Address) is used to alter the DTA address. It is
  11160.       called with the segment and offset of the new buffer to be used as the
  11161.       DTA in DS:DX. The DTA address remains the same until another call to
  11162.       Function 1AH, regardless of other file and record management calls; it
  11163.       does not need to be reset before each read or write.
  11164.  
  11165.       Note: A program can use Function 2FH (Get DTA Address) to obtain the
  11166.       current DTA address before changing it, so that the original address
  11167.       can be restored later.
  11168.  
  11169.  Parsing the filename
  11170.  
  11171.       Before a file can be opened or created with the FCB function calls,
  11172.       its drive, filename, and extension must be placed within the proper
  11173.       fields of the FCB. The filename can be coded into the program itself,
  11174.       or the program can obtain it from the command tail in the PSP or by
  11175.       prompting the user and reading it in with one of the several function
  11176.       calls for character device input.
  11177.  
  11178.       MS-DOS automatically parses the first two parameters in the program's
  11179.       command tail into the default FCBs at PSP:005CH and PSP:006CH. It does
  11180.       not, however, attempt to differentiate between switches and filenames,
  11181.       so the pre-parsed FCBs are not necessarily useful to the application
  11182.       program. If the filenames were preceded by any switches, the program
  11183.       itself has to extract the filenames directly from the command tail.
  11184.       The program is then responsible for determining which parameters are
  11185.       switches and which are filenames, as well as where each parameter
  11186.       begins and ends.
  11187.  
  11188.       After a filename has been located, Function 29H (Parse Filename) can
  11189.       be used to test it for invalid characters and separators and to insert
  11190.       its various components into the proper fields in an FCB. The filename
  11191.       must be a string in the standard form drive:filename.ext. Wildcard
  11192.       characters are permitted in the filename and/or extension; asterisk
  11193.       (*) wildcards are expanded to question mark (?) wildcards.
  11194.  
  11195.       To call Function 29H, the DS:SI registers must point to the candidate
  11196.       filename, ES:DI must point to the 37-byte buffer that will become the
  11197.       FCB for the file, and AL must hold the parsing control code. See
  11198.       SYSTEM CALLS: INTERRUPT 21H: Function 29H.
  11199.  
  11200.       If a drive code is not included in the filename, MS-DOS inserts the
  11201.       drive number of the current drive into the FCB. Parsing stops at the
  11202.       first terminator character encountered in the filename. Terminators
  11203.       include the following:
  11204.  
  11205.       ; , = +  / " [] | < > | space tab
  11206.  
  11207.       If a colon character (:) is not in the proper position to delimit the
  11208.       disk drive identifier or if a period (.) is not in the proper position
  11209.       to delimit the extension, the character will also be treated as a
  11210.       terminator. For example, the filename C:MEMO.TXT will be parsed
  11211.       correctly; however, ABC:DEF.DAY will be parsed as ABC.
  11212.  
  11213.       If an invalid drive is specified in the filename, Function 29H returns
  11214.       0FFH in AL; if the filename contains any wildcard characters, it
  11215.       returns 1. Otherwise, AL contains zero upon return, indicating a
  11216.       valid, unambiguous filename.
  11217.  
  11218.       Note that this function simply parses the filename into the FCB. It
  11219.       does not initialize any other fields of the FCB (although it does zero
  11220.       the current block and record size fields), and it does not test
  11221.       whether the specified file actually exists.
  11222.  
  11223.  Error handling and FCB functions
  11224.  
  11225.       The FCB-related file and record functions do not return much in the
  11226.       way of error information when a function fails. Typically, an FCB
  11227.       function returns a zero in AL if the function succeeded and 0FFH if
  11228.       the function failed. Under MS-DOS versions 2.x, the program is left to
  11229.       its own devices to determine the cause of the error. Under MS-DOS
  11230.       versions 3.x, however, a failed FCB function call can be followed by a
  11231.       call to Interrupt 21H Function 59H (Get Extended Error Information).
  11232.       Function 59H will return the same descriptive codes for the error,
  11233.       including the error locus and a suggested recovery strategy, as would
  11234.       be returned for the counterpart handle-oriented file or record
  11235.       function.
  11236.  
  11237.  Creating a file
  11238.  
  11239.       Function 16H (Create File with FCB) creates a new file and opens it
  11240.       for subsequent read/write operations. The function is called with
  11241.       DS:DX pointing to a valid, unopened FCB. MS-DOS searches the current
  11242.       directory for the specifed filename. If the filename is found, MS-DOS
  11243.       sets the file length to zero and opens the file, effectively
  11244.       truncating it to a zero-length file; if the filename is not found,
  11245.       MS-DOS creates a new file and opens it. Other fields of the FCB are
  11246.       filled in by MS-DOS as described below under Opening a File.
  11247.  
  11248.       If the create operation succeeds, MS-DOS returns zero in AL; if the
  11249.       operation fails, it returns 0FFH in AL. This function will not
  11250.       ordinarily fail unless the file is being created in the root directory
  11251.       and the directory is full.
  11252.  
  11253.       Warning: To avoid loss of existing data, the FCB open function should
  11254.       be used to test for file existence before creating a file.
  11255.  
  11256.  Opening a file
  11257.  
  11258.       Function 0FH opens an existing file. DS:DX must point to a valid,
  11259.       unopened FCB containing the name of the file to be opened. If the
  11260.       specified file is found in the current directory, MS-DOS opens the
  11261.       file, fills in the FCB as shown in the list below, and returns with AL
  11262.       set to 00H; if the file is not found, MS-DOS returns with AL set to
  11263.       0FFH, indicating an error.
  11264.  
  11265.       When the file is opened, MS-DOS
  11266.  
  11267.       ■  Sets the drive identifier (offset 00H) to the actual drive (01 = A,
  11268.          02 = B, and so on).
  11269.  
  11270.       ■  Sets the current block number (offset 0CH) to zero.
  11271.  
  11272.       ■  Sets the file size (offset 10H) to the value found in the directory
  11273.          entry for the file.
  11274.  
  11275.       ■  Sets the record size (offset 0EH) to 128.
  11276.  
  11277.       ■  Sets the date and time stamp (offsets 14H and 16H) to the values
  11278.          found in the directory entry for the file.
  11279.  
  11280.       The program may need to adjust the FCB--change the record size and the
  11281.       random record pointer, for example--before proceeding with record
  11282.       operations.
  11283.  
  11284.       Example: Display a prompt and accept a filename from the user. Parse
  11285.       the filename into an FCB, checking for an illegal drive identifier or
  11286.       the presence of wildcards. If a valid, unambiguous filename has been
  11287.       entered, attempt to open the file. Create the file if it does not
  11288.       already exist.
  11289.  
  11290.       kbuf    db      64,0,64 dup (0)
  11291.       prompt  db      0dh,0ah,'Enter filename: $'
  11292.       myfcb   db      37 dup (0)
  11293.  
  11294.               .
  11295.               .
  11296.               .
  11297.                                       ; display the prompt...
  11298.               mov     dx,seg prompt   ; DS:DX = prompt address
  11299.               mov     ds,dx
  11300.               mov     es,dx
  11301.               mov     dx,offset prompt
  11302.               mov     ah,09h          ; Function 09H = print string
  11303.               int     21h             ; transfer to MS-DOS
  11304.  
  11305.                                       ; now input filename...
  11306.               mov     dx,offset kbuf  ; DS:DX = buffer address
  11307.               mov     ah,0ah          ; Function 0AH = enter string
  11308.               int     21h             ; transfer to MS-DOS
  11309.  
  11310.                                       ; parse filename into FCB...
  11311.               mov     si,offset kbuf+2 ; DS:SI = address of filename
  11312.               mov     di,offset myfcb ; ES:DI = address of fcb
  11313.               mov     ax,2900h        ; Function 29H = parse name
  11314.               int     21h             ; transfer to MS-DOS
  11315.               or      al,al           ; jump if bad drive or
  11316.               jnz     error           ; wildcard characters in name
  11317.                                       ; try to open file...
  11318.               mov     dx,offset myfcb ; DS:DX = FCB address
  11319.               mov     ah,0fh          ; Function 0FH = open file
  11320.               int     21h             ; transfer to MS-DOS
  11321.               or      al,al           ; check status
  11322.               jz      proceed         ; jump if open successful
  11323.  
  11324.                                       ; else create file...
  11325.               mov     dx,offset myfcb ; DS:DX = FCB address
  11326.               mov     ah,16h          ; Function 16H = create
  11327.               int     21h             ; transfer to MS-DOS
  11328.               or      al,al           ; did create succeed?
  11329.               jnz     error           ; jump if create failed
  11330.  
  11331.       proceed:
  11332.               .                       ; file has been opened or
  11333.               .                       ; created, and FCB is valid
  11334.               .                       ; for read/write operations...
  11335.  
  11336.  Closing a file
  11337.  
  11338.       Function 10H (Close File with FCB) closes a file previously opened
  11339.       with an FCB. As usual, the function is called with DS:DX pointing to
  11340.       the FCB of the file to be closed. MS-DOS updates the directory, if
  11341.       necessary, to reflect any changes in the file's size and the date and
  11342.       time last written.
  11343.  
  11344.       If the operation succeeds, MS-DOS returns 00H in AL; if the operation
  11345.       fails, MS-DOS returns 0FFH.
  11346.  
  11347.  Reading and writing files with FCBs
  11348.  
  11349.       MS-DOS offers a choice of three FCB access methods for data within
  11350.       files: sequential, random record, and random block.
  11351.  
  11352.       Sequential operations step through the file one record at a time.
  11353.       MS-DOS increments the current record and current block numbers after
  11354.       each file access so that they point to the beginning of the next
  11355.       record. This method is particularly useful for copying or listing
  11356.       files.
  11357.  
  11358.       Random record access allows the program to read or write a record from
  11359.       any location in the file, without sequentially reading all records up
  11360.       to that point in the file. The program must set the random record
  11361.       number field of the FCB appropriately before the read or write is
  11362.       requested. This method is useful in database applications, in which a
  11363.       program must manipulate fixed-length records.
  11364.  
  11365.       Random block operations combine the features of sequential and random
  11366.       record access methods. The program can set the record number to point
  11367.       to any record within a file, and MS-DOS updates the record number
  11368.       after a read or write operation. Thus, sequential operations can
  11369.       easily be initiated at any file location. Random block operations with
  11370.       a record length of 1 byte simulate file-handle access methods.
  11371.  
  11372.       All three methods require that the FCB for the file be open, that
  11373.       DS:DX point to the FCB, that the DTA be large enough for the specified
  11374.       record size, and that the DTA address be previously set with Function
  11375.       1AH if the default DTA in the program's PSP is not being used.
  11376.  
  11377.       MS-DOS reports the success or failure of any FCB-related read
  11378.       operation (sequential, random record, or random block) with one of
  11379.       four return codes in register AL:
  11380.  
  11381. ╓┌──────────────┌────────────────────────────────────────────────────────────╖
  11382.       Code      Meaning
  11383.       ──────────────────────────────────────────────────────────────────────
  11384.       Code      Meaning
  11385.       ──────────────────────────────────────────────────────────────────────
  11386.       00H       Successful read
  11387.  
  11388.       01H       End of file reached; no data read into DTA
  11389.  
  11390.       02H       Segment wrap (DTA too close to end of segment); no data read
  11391.                 into DTA
  11392.  
  11393.       03H       End of file reached; partial record read into DTA
  11394.  
  11395.       MS-DOS reports the success or failure of an FCB-related write
  11396.       operation as one of three return codes in register AL:
  11397.  
  11398. ╓┌──────────────┌────────────────────────────────────────────────────────────╖
  11399.       Code      Meaning
  11400.       ──────────────────────────────────────────────────────────────────────
  11401.       00H       Successful write
  11402.       01H       Disk full; partial or no write
  11403.       02H       Segment wrap (DTA too close to end of segment); write failed
  11404.  
  11405.       For FCB write operations, records smaller than one sector (512 bytes)
  11406.       are not written directly to disk. Instead, MS-DOS stores the record in
  11407.       an internal buffer and writes the data to disk only when the internal
  11408.       buffer is full, when the file is closed, or when a call to Interrupt
  11409.       21H Function 0DH (Disk Reset) is issued.
  11410.  
  11411.  Sequential access: reading
  11412.       Function 14H (Sequential Read) reads records sequentially from the
  11413.       file to the current DTA address, which must point to an area at least
  11414.       as large as the record size specified in the file's FCB. After each
  11415.       read operation, MS-DOS updates the FCB block and record numbers
  11416.       (offsets 0CH and 20H) to point to the next record.
  11417.  
  11418.  Sequential access: writing
  11419.       Function 15H (Sequential Write) writes records sequentially from
  11420.       memory into the file. The length written is specified by the record
  11421.       size field (offset 0EH) in the FCB; the memory address of the record
  11422.       to be written is determined by the current DTA address. After each
  11423.       sequential write operation, MS-DOS updates the FCB block and record
  11424.       numbers (offsets 0CH and 20H) to point to the next record.
  11425.  
  11426.  Random record access: reading
  11427.       Function 21H (Random Read) reads a specific record from a file. Before
  11428.       requesting the read operation, the program specifies the record to be
  11429.       transferred by setting the record size and random record number fields
  11430.       of the FCB (offsets 0EH and 21H). The current DTA address must also
  11431.       have been previously set with Function 1AH to point to a buffer of
  11432.       adequate size if the default DTA is not large enough.
  11433.  
  11434.       After the read, MS-DOS sets the current block and current record
  11435.       number fields (offsets 0CH and 20H) to point to the same record. Thus,
  11436.       the program is set up to change to sequential reads or writes.
  11437.       However, if the program wants to continue with random record access,
  11438.       it must continue to update the random record field of the FCB before
  11439.       each random record read or write operation.
  11440.  
  11441.  Random record access: writing
  11442.       Function 22H (Random Write) writes a specific record from memory to a
  11443.       file. Before issuing the function call, the program must ensure that
  11444.       the record size and random record pointer fields at FCB offsets 0EH
  11445.       and 21H are set appropriately and that the current DTA address points
  11446.       to the buffer containing the data to be written.
  11447.  
  11448.       After the write, MS-DOS sets the current block and current record
  11449.       number fields (offsets 0CH and 20H) to point to the same record. Thus,
  11450.       the program is set up to change to sequential reads or writes. If the
  11451.       program wants to continue with random record access, it must continue
  11452.       to update the random record field of the FCB before each random record
  11453.       read or write operation.
  11454.  
  11455.  Random block access: reading
  11456.       Function 27H (Random Block Read) reads a block of consecutive records.
  11457.       Before issuing the read request, the program must specify the file
  11458.       location of the first record by setting the record size and random
  11459.       record number fields of the FCB (offsets 0EH and 21H) and must put the
  11460.       number of records to be read in CX. The DTA address must have already
  11461.       been set with Function 1AH to point to a buffer large enough to
  11462.       contain the group of records to be read if the default DTA was not
  11463.       large enough. The program can then issue the Function 27H call with
  11464.       DS:DX pointing to the FCB for the file.
  11465.  
  11466.       After the random block read operation, MS-DOS resets the FCB random
  11467.       record pointer (offset 21H) and the current block and current record
  11468.       number fields (offsets 0CH and 20H) to point to the beginning of the
  11469.       next record not read and returns the number of records actually read
  11470.       in CX.
  11471.  
  11472.       If the record size is set to 1 byte, Function 27H reads the number of
  11473.       bytes specified in CX, beginning with the byte position specified in
  11474.       the random record pointer. This simulates (to some extent) the handle
  11475.       type of read operation (Function 3FH).
  11476.  
  11477.  Random block access: writing
  11478.       Function 28H (Random Block Write) writes a block of consecutive
  11479.       records from memory to disk. The program specifies the file location
  11480.       of the first record to be written by setting the record size and
  11481.       random record pointer fields in the FCB (offsets 0EH and 21H). If the
  11482.       default DTA is not being used, the program must also ensure that the
  11483.       current DTA address is set appropriately by a previous call to
  11484.       Function 1AH. When Function 28H is called, DS:DX must point to the FCB
  11485.       for the file and CX must contain the number of records to be written.
  11486.  
  11487.       After the random block write operation, MS-DOS resets the FCB random
  11488.       record pointer (offset 21H) and the current block and current record
  11489.       number fields (offsets 0CH and 20H) to point to the beginning of the
  11490.       next block of data and returns the number of records actually written
  11491.       in CX.
  11492.  
  11493.       If the record size is set to 1 byte, Function 28H writes the number of
  11494.       bytes specified in CX, beginning with the byte position specified in
  11495.       the random record pointer. This simulates (to some extent) the handle
  11496.       type of write operation (Function 40H).
  11497.  
  11498.       Calling Function 28H with a record count of zero in register CX causes
  11499.       the file length to be extended or truncated to the current value in
  11500.       the FCB random record pointer field (offset 21H) multiplied by the
  11501.       contents of the record size field (offset 0EH).
  11502.  
  11503.       Example: Open the file MYFILE.DAT and create the file MYFILE.BAK on
  11504.       the current disk drive, copy the contents of the .DAT file into the
  11505.       .BAK file using 512-byte reads and writes, and then close both files.
  11506.  
  11507.       fcb1    db      0               ; drive = default
  11508.               db      'MYFILE  '      ; 8 character filename
  11509.               db      'DAT'           ; 3 character extension
  11510.               db      25 dup (0)      ; remainder of fcb1
  11511.       fcb2    db      0               ; drive = default
  11512.               db      'MYFILE  '      ; 8 character filename
  11513.               db      'BAK'           ; 3 character extension
  11514.               db      25 dup (0)      ; remainder of fcb2
  11515.       buff    db      512 dup (?)     ; buffer for file I/O
  11516.               .
  11517.               .
  11518.               .
  11519.                                       ; open MYFILE.DAT...
  11520.               mov     dx,seg fcb1     ; DS:DX = address of FCB
  11521.               mov     ds,dx
  11522.               mov     dx,offset fcb1
  11523.               mov     ah,0fh          ; Function 0FH = open
  11524.               int     21h             ; transfer to MS-DOS
  11525.               or      al,al           ; did open succeed?
  11526.               jnz     error           ; jump if open failed
  11527.                                       ; create MYFILE.BAK...
  11528.               mov     dx,offset fcb2  ; DS:DX = address of FCB
  11529.               mov     ah,16h          ; Function 16H = create
  11530.               int     21h             ; transfer to MS-DOS
  11531.               or      al,al           ; did create succeed?
  11532.               jnz     error           ; jump if create failed
  11533.                                       ; set record length to 512
  11534.               mov     word ptr fcb1+0eh,512
  11535.               mov     word ptr fcb2+0eh,512
  11536.                                       ; set DTA to our buffer...
  11537.               mov     dx,offset buff  ; DS:DX = buffer address
  11538.               mov     ah,1ah          ; Function 1AH = set DTA
  11539.               int     21h             ; transfer to MS-DOS
  11540.       loop:                           ; read MYFILE.DAT
  11541.               mov     dx,offset fcb1  ; DS:DX = FCB address
  11542.               mov     ah,14h          ; Function 14H = seq. read
  11543.               int     21h             ; transfer to MS-DOS
  11544.               or      al,al           ; was read successful?
  11545.               jnz     done            ; no, quit
  11546.                                       ; write MYFILE.BAK...
  11547.               mov     dx,offset fcb2  ; DS:DX = FCB address
  11548.               mov     ah,15h          ; Function 15H = seq. write
  11549.               int     21h             ; transfer to MS-DOS
  11550.               or      al,al           ; was write successful?
  11551.               jnz     error           ; jump if write failed
  11552.               jmp     loop            ; continue to end of file
  11553.       done:                           ; now close files...
  11554.               mov     dx,offset fcb1  ; DS:DX = FCB for MYFILE.DAT
  11555.               mov     ah,10h          ; Function 10H = close file
  11556.               int     21h             ; transfer to MS-DOS
  11557.               or      al,al           ; did close succeed?
  11558.               jnz     error           ; jump if close failed
  11559.               mov     dx,offset fcb2  ; DS:DX = FCB for MYFILE.BAK
  11560.               mov     ah,10h          ; Function 10H = close file
  11561.               int     21h             ; transfer to MS-DOS
  11562.               or      al,al           ; did close succeed?
  11563.               jnz     error           ; jump if close failed
  11564.               .
  11565.               .
  11566.               .
  11567.  
  11568.  Other FCB file operations
  11569.  
  11570.       As it does with file handles, MS-DOS provides FCB-oriented functions
  11571.       to rename or delete a file. Unlike the other FCB functions and their
  11572.       handle counterparts, these two functions accept wildcard characters.
  11573.       An additional FCB function allows the size or existence of a file to
  11574.       be determined without actually opening the file.
  11575.  
  11576.  Renaming a file
  11577.       Function 17H (Rename File) renames a file (or files) in the current
  11578.       directory. The file to be renamed cannot have the hidden or system
  11579.       attribute. Before calling Function 17H, the program must create a
  11580.       special FCB that contains the drive code at offset 00H, the old
  11581.       filename at offset 01H, and the new filename at offset 11H. Both the
  11582.       current and the new filenames can contain the ? wildcard character.
  11583.  
  11584.       When the function call is made, DS:DX must point to the special FCB
  11585.       structure. MS-DOS searches the current directory for the old filename.
  11586.       If it finds the old filename, MS-DOS then searches for the new
  11587.       filename and, if it finds no matching filename, changes the directory
  11588.       entry for the old filename to reflect the new filename. If the old
  11589.       filename field of the special FCB contains any wildcard characters,
  11590.       MS-DOS renames every matching file. Duplicate filenames are not
  11591.       permitted; the process will fail at the first duplicate name.
  11592.  
  11593.       If the operation is successful, MS-DOS returns zero in AL; if the
  11594.       operation fails, it returns 0FFH. The error condition may indicate
  11595.       either that no files were renamed or that at least one file was
  11596.       renamed but the operation was then terminated because of a duplicate
  11597.       filename.
  11598.  
  11599.       Example: Rename all the files with the extension .ASM in the current
  11600.       directory of the default disk drive to have the extension .COD.
  11601.  
  11602.       renfcb  db      0               ; default drive
  11603.               db      '????????'      ; wildcard filename
  11604.               db      'ASM'           ; old extension
  11605.               db      5 dup (0)       ; reserved area
  11606.               db      '????????'      ; wildcard filename
  11607.               db      'COD'           ; new extension
  11608.               db      15 dup (0)      ; remainder of FCB
  11609.  
  11610.               .
  11611.               .
  11612.               .
  11613.               mov     dx,seg renfcb   ; DS:DX = address of
  11614.               mov     ds,dx           ; "special" FCB
  11615.               mov     dx,offset renfcb
  11616.               mov     ah,17h          ; Function 17H = rename
  11617.               int     21h             ; transfer to MS-DOS
  11618.                or      al,al           ; did function succeed?
  11619.               jnz     error           ; jump if rename failed
  11620.               .
  11621.               .
  11622.               .
  11623.  
  11624.  Deleting a file
  11625.       Function 13H (Delete File) deletes a file from the current directory.
  11626.       The file should not be currently open by any process. If the file to
  11627.       be deleted has special attributes, such as read-only, the program must
  11628.       use an extended FCB to remove the file. Directories cannot be deleted
  11629.       with this function, even with an extended FCB.
  11630.  
  11631.       Function 13H is called with DS:DX pointing to an unopened, valid FCB
  11632.       containing the name of the file to be deleted. The filename can
  11633.       contain the ? wildcard character; if it does, MS-DOS deletes all files
  11634.       matching the specified name. If at least one file matches the FCB and
  11635.       is deleted, MS-DOS returns 00H in AL; if no matching filename is
  11636.       found, it returns 0FFH.
  11637.  
  11638.       Note: This function, if it succeeds, does not return any information
  11639.       about which and how many files were deleted. When multiple files must
  11640.       be deleted, closer control can be exercised by using the Find File
  11641.       functions (Functions 11H and 12H) to inspect candidate filenames. See
  11642.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: Disk
  11643.       Directories and Volume Labels. The files can then be deleted
  11644.       individually.
  11645.  
  11646.       Example: Delete all the files in the current directory of the current
  11647.       disk drive that have the extension .BAK and whose filenames have A as
  11648.       the first character.
  11649.  
  11650.       delfcb  db      0               ; default drive
  11651.               db      'A???????'      ; wildcard filename
  11652.               db      'BAK'           ; extension
  11653.               db      25 dup (0)      ; remainder of FCB
  11654.               .
  11655.               .
  11656.               .
  11657.               mov     dx,seg delfcb   ; DS:DX = FCB address
  11658.               mov     ds,dx
  11659.               mov     dx,offset delfcb
  11660.               mov     ah,13h          ; Function 13H = delete
  11661.               int     21h             ; transfer to MS-DOS
  11662.               or      al,al           ; did function succeed?
  11663.               jnz     error           ; jump if delete failed
  11664.               .
  11665.               .
  11666.               .
  11667.  
  11668.  Finding file size and testing for existence
  11669.       Function 23H (Get File Size) is used primarily to find the size of a
  11670.       disk file without opening it, but it may also be used instead of
  11671.       Function 11H (Find First File) to simply test for the existence of a
  11672.       file. Before calling Function 23H, the program must parse the filename
  11673.       into an unopened FCB, initialize the record size field of the FCB
  11674.       (offset 0EH), and set the DS:DX registers to point to the FCB.
  11675.  
  11676.       When Function 23H returns, AL contains 00H if the file was found in
  11677.       the current directory of the specified drive and 0FFH if the file was
  11678.       not found.
  11679.  
  11680.       If the file was found, the random record field at FCB offset 21H
  11681.       contains the number of records (rounded upward) in the target file, in
  11682.       terms of the value in the record size field (offset 0EH) of the FCB.
  11683.       If the record size is at least 64 bytes, only the first 3 bytes of the
  11684.       random record field are used; if the record size is less than 64
  11685.       bytes, all 4 bytes are used. To obtain the size of the file in bytes,
  11686.       the program must set the record size field to 1 before the call. This
  11687.       method is not any faster than simply opening the file, but it does
  11688.       avoid the overhead of closing the file afterward (which is necessary
  11689.       in a networking environment).
  11690.  
  11691.  
  11692.  Summary
  11693.  
  11694.       MS-DOS supports two distinct but overlapping sets of file and record
  11695.       management services. The handle-oriented functions operate in terms of
  11696.       null-terminated (ASCIIZ) filenames and 16-bit file identifiers, called
  11697.       handles, that are returned by MS-DOS after a file is opened or
  11698.       created. The filenames can include a full path specifying the file's
  11699.       location in the hierarchical directory structure. The information
  11700.       associated with a file handle, such as the current read/write pointer
  11701.       for the file, the date and time of the last write to the file, and the
  11702.       file's read/write permissions, sharing mode, and attributes, is
  11703.       maintained in a table internal to MS-DOS.
  11704.  
  11705.       In contrast, the FCB-oriented functions use a 37-byte structure called
  11706.       a file control block, located in the application program's memory
  11707.       space, to specify the name and location of the file. After a file is
  11708.       opened or created, the FCB is used by both MS-DOS and the application
  11709.       to hold other information about the file, such as the current
  11710.       read/write file pointer, while that file is in use. Because FCBs
  11711.       predate the hierarchical directory structure that was introduced in
  11712.       MS-DOS version 2.0 and do not have room to hold the path for a file,
  11713.       the FCB functions cannot be used to access files that are not in the
  11714.       current directory of the specified drive.
  11715.  
  11716.       In addition to their lack of support for pathnames, the FCB functions
  11717.       have much poorer error reporting capabilities than handle functions
  11718.       and are nearly useless in networking environments because they do not
  11719.       support file sharing and locking. Consequently, it is strongly
  11720.       recommended that the handle-related file and record functions be used
  11721.       exclusively in all new applications.
  11722.  
  11723.                                                          Robert Byers
  11724.                                                    Code by Ray Duncan
  11725.  
  11726.  
  11727.  
  11728.  Article 8:  Disk Directories and Volume Labels
  11729.  
  11730.  
  11731.       MS-DOS, being a disk operating system, provides facilities for
  11732.       cataloging disk files. The data structure used by MS-DOS for this
  11733.       purpose is the directory, a linear list of names in which each name is
  11734.       associated with a physical location on the disk. Directories are
  11735.       accessed and updated implicitly whenever files are manipulated, but
  11736.       both directories and their contents can also be manipulated explicitly
  11737.       using several of the MS-DOS Interrupt 21H service functions.
  11738.  
  11739.       MS-DOS versions 1.x support only one directory on each disk. Versions
  11740.       2.0 and later, however, support multiple directories linked in a two-
  11741.       way, hierarchical tree structure (Figure 8-1), and the complete
  11742.       specification of the name of a file or directory thus must describe
  11743.       the location in the directory hierarchy in which the name appears.
  11744.       This specification, or path, is created by concatenating a disk drive
  11745.       specifier (for example, A: or C:), the names of the directories in
  11746.       hierarchical order starting with the root directory, and finally the
  11747.       name of the file or directory. For example, in Figure 8-1, the
  11748.       complete pathname for FILE5.COM is C:\ALPHA\GAMMA\FILE5.COM. The two
  11749.       instances of FILE1.COM, in the root directory and in the directory
  11750.       EPSILON, are distinguished by their pathnames: C:\FILE1.COM in the
  11751.       first instance and C:\BETA\EPSILON\FILE1.COM in the second.
  11752.  
  11753.  
  11754.   C:\  (root directory)
  11755.  ┌─────────────────────┐
  11756.  │subdirect. ALPHA     │
  11757.  │subdirect. BETA      │
  11758.  │file       FILE1.COM │
  11759.  │file       FILE2.COM │
  11760.  │                     │
  11761.  └───────────┬─────────┘
  11762.              ├────────────────────────────────────────────────┐
  11763.           C:\ALPHA                                        C:\BETA
  11764.  ┌─────────────────────┐                           ┌─────────────────────┐
  11765.  │subdirect. ∙         │                           │subdirect. ∙         │
  11766.  │subdirect. ∙∙        │                           │subdirect. ∙∙        │
  11767.  │subdirect. GAMMA     │                           │file       EPSILON   │
  11768.  │subdirect. DELTA     │                           │file       FILE4.COM │
  11769.  │file       FILE3.COM │                           │                     │
  11770.  └───────────┬─────────┘                           └──────────┬──────────┘
  11771.              │                                                │
  11772.              ├───────────────────────┐                        │
  11773.              │                       │                        │
  11774.      C:\ALPHA\GAMMA           C:\ALPHA\DELTA           C:\BETA\EPSILON
  11775.  ┌─────────────────────┐  ┌─────────────────────┐  ┌─────────────────────┐
  11776.  │subdirect. ∙         │  │subdirect. ∙         │  │subdirect. ∙         │
  11777.  │subdirect. ∙∙        │  │subdirect. ∙∙        │  │subdirect. ∙∙        │
  11778.  │file       FILE5.COM │  │                     │  │file       FILE1.COM │
  11779.  │                     │  │                     │  │                     │
  11780.  │                     │  │                     │  │                     │
  11781.  └─────────────────────┘  └─────────────────────┘  └─────────────────────┘
  11782.  
  11783.       Figure 8-1. Typical hierarchical directory structure (MS-DOS versions
  11784.       2.0 and later).
  11785.  
  11786.  
  11787.       Note: If no drive is specified, the current drive is assumed. Also, if
  11788.       the first name in the specification is not preceded by a backslash,
  11789.       the specification is assumed to be relative to the current directory.
  11790.       For example, if the current directory is C:\BETA\EPSILON, the
  11791.       specification \FILE1.COM indicates the file FILE1.COM in the root
  11792.       directory and the specification FILE1.COM indicates the file FILE1.COM
  11793.       in the directory C:\BETA\EPSILON. See Figure 8-1.
  11794.  
  11795.       Although the casual user of MS-DOS need not be concerned with how this
  11796.       hierarchical directory structure is implemented, MS-DOS programmers
  11797.       should be familiar with the internal structure of directories and with
  11798.       the Interrupt 21H functions available for manipulating directory
  11799.       contents and maintaining the links between directories. This article
  11800.       provides that information.
  11801.  
  11802.  
  11803.  Logical Structure of MS-DOS Directories
  11804.  
  11805.       An MS-DOS directory consists of a list of 32-byte directory entries,
  11806.       each of which contains a name and descriptive information. In MS-DOS
  11807.       versions 1.x, each name must be a filename; in versions 2.0 and later,
  11808.       volume labels and directory names can also appear in directory
  11809.       entries.
  11810.  
  11811.  Directory searches
  11812.  
  11813.       Directory entries are not sorted, nor are they maintained as a linked
  11814.       list. Thus, when MS-DOS searches a directory for a name, the search
  11815.       must proceed linearly from the first name in the directory. In MS-DOS
  11816.       versions 1.x, a directory search continues until the specified name is
  11817.       found or until every entry in the directory has been examined. In
  11818.       versions 2.0 and later, the search continues until the specified name
  11819.       is found or until a null directory entry (that is, one whose first
  11820.       byte is zero) is encountered. This null entry indicates the logical
  11821.       end of the directory.
  11822.  
  11823.  Adding and deleting directory entries
  11824.  
  11825.       MS-DOS deletes a directory entry by marking it with 0E5H in the first
  11826.       byte rather than by erasing it or excising it from the directory. New
  11827.       names are added to the directory by reusing the first deleted entry in
  11828.       the list. If no deleted entries are available, MS-DOS appends the new
  11829.       entry to the list.
  11830.  
  11831.  The current directory
  11832.  
  11833.       When more than one directory exists on a disk, MS-DOS keeps track of a
  11834.       default search directory known as the current directory. The current
  11835.       directory is the directory used for all implicit directory searches,
  11836.       such as those occasioned by a request to open a file, if no
  11837.       alternative path is specified. At startup, MS-DOS makes the root
  11838.       directory the current directory, but any other directory can be
  11839.       designated later, either interactively by using the CHDIR command or
  11840.       from within an application by using Interrupt 21H Function 3BH (Change
  11841.       Current Directory).
  11842.  
  11843.  
  11844.  Directory Format
  11845.  
  11846.       The root directory is created by the MS-DOS FORMAT program. See USER
  11847.       COMMANDS: FORMAT. The FORMAT program places the root directory
  11848.       immediately after the disk's file allocation tables (FATs). FORMAT
  11849.       also determines the size of the root directory. The size depends on
  11850.       the capacity of the storage medium: FORMAT places larger root
  11851.       directories on high-capacity fixed disks and smaller root directories
  11852.       on floppy disks. In contrast, the size of subdirectories is limited
  11853.       only by the storage capacity of the disk because disk space for
  11854.       subdirectories is allocated dynamically, as it is for any MS-DOS file.
  11855.       The size and physical location of the root directory can be derived
  11856.       from data in the BIOS parameter block (BPB) in the disk boot sector.
  11857.       See PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: MS-DOS
  11858.       Storage Devices.
  11859.  
  11860.       Because space for the root directory is allocated only when the disk
  11861.       is formatted, the root directory cannot be deleted or moved.
  11862.       Subdirectories, whose disk space is allocated dynamically, can be
  11863.       added or deleted as needed.
  11864.  
  11865.  Directory entry format
  11866.  
  11867.       Each 32-byte directory entry consists of seven fields, including a
  11868.       name, an attribute byte, date and time stamps, and information that
  11869.       describes the file's size and physical location on the disk (Figure
  11870.       8-2). The fields are formatted as described in the following
  11871.       paragraphs.
  11872.  
  11873.  
  11874.  Byte   0     0BH        0CH         16H   18H   1AH               1CH   1FH
  11875.        ┌─────┬──────────┬───────────┬─────┬─────┬─────────────────┬─────────┐
  11876.        │Name │Attribute │(Reserved) │Time │Date │Starting cluster │File size│
  11877.        └─────┴──────────┴───────────┴─────┴─────┴─────────────────┴─────────┘
  11878.  
  11879.       Figure 8-2. Format of a directory entry.
  11880.  
  11881.  
  11882.       The name field (bytes 0-0AH) contains an 11-byte name unless the first
  11883.       byte of the field indicates that the directory entry is deleted or
  11884.       null. The name can be an 11-byte filename (8-byte name followed by a
  11885.       3-byte extension), an 11-byte subdirectory name (8-byte name followed
  11886.       by a 3-byte extension), or an 11-byte volume label. Names less than 8
  11887.       bytes and extensions less than 3 bytes are padded to the right with
  11888.       blanks so that the extension always appears in bytes 08-0AH of the
  11889.       name field. The first byte of the name field can contain certain
  11890.       reserved values that affect the way MS-DOS processes the directory
  11891.       entry:
  11892.  
  11893. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  11894.       Value       Meaning
  11895.       ──────────────────────────────────────────────────────────────────────
  11896.       0           Null directory entry (logical end of directory in MS-DOS
  11897.                   versions 2.0 and later)
  11898.  
  11899.       5           First character of name to be displayed as the character
  11900.                   represented by 0E5H (MS-DOS version 3.2 )
  11901.  
  11902.       0E5H        Deleted directory entry
  11903.  
  11904.       When MS-DOS creates a subdirectory, it always includes two aliases as
  11905.       the first two entries in the newly created directory. The name . (an
  11906.       ASCII period) is an alias for the name of the current directory; the
  11907.       name .. (two ASCII periods) is an alias for the directory's parent
  11908.       directory--that is, the directory in which the entry containing the
  11909.       name of the current directory is found.
  11910.  
  11911.       The attribute field (byte 0BH) is an 8-bit field that describes the
  11912.       way MS-DOS processes the directory entry (Figure 8-3). Each bit in the
  11913.       attribute field designates a particular attribute of that directory
  11914.       entry; more than one of the bits can be set at a time.
  11915.  
  11916.  
  11917.  Bit        7           6         5        4      3      2       1      0
  11918.       ┌───────────┬───────────┬────────┬───────┬─────┬───────┬───────┬─────┐
  11919.       │(Reserved) │(Reserved) │Archive │Sub-   │Vol- │System │Hidden │Read-│
  11920.       │           │           │        │direc- │ume  │file   │file   │only │
  11921.       │           │           │        │tory   │label│       │       │file │
  11922.       └───────────┴───────────┴────────┴───────┴─────┴───────┴───────┴─────┘
  11923.  
  11924.       Figure 8-3. Format of the attribute field in a directory entry.
  11925.  
  11926.  
  11927.       The read-only bit (bit 0) is set to 1 to mark a file read-only.
  11928.       Interrupt 21H Function 3DH (Open File with Handle) will fail if it is
  11929.       used in an attempt to open this file for writing. The hidden bit (bit
  11930.       1) is set to 1 to indicate that the entry is to be skipped in normal
  11931.       directory searches--that is, in directory searches that do not
  11932.       specifically request that hidden entries be included in the search.
  11933.       The system bit (bit 2) is set to 1 to indicate that the entry refers
  11934.       to a file used by the operating system. Like the hidden bit, the
  11935.       system bit excludes a directory entry from normal directory searches.
  11936.       The volume label bit (bit 3) is set to 1 to indicate that the
  11937.       directory entry represents a volume label. The subdirectory bit (bit
  11938.       4) is set to 1 when the directory entry contains the name and location
  11939.       of another directory. This bit is always set for the directory entries
  11940.       that correspond to the current directory (.) and the parent directory
  11941.       (..). The archive bit (bit 5) is set to 1 by MS-DOS functions that
  11942.       close a file that has been written to. Simply opening and closing a
  11943.       file is not sufficient to update the archive bit in the file's
  11944.       directory entry.
  11945.  
  11946.       The time and date fields (bytes 16-17H and 18-19H) are initialized by
  11947.       MS-DOS when the directory entry is created. These fields are updated
  11948.       whenever a file is written to. The formats of these fields are shown
  11949.       in Figures 8-4 and 8-5.
  11950.  
  11951.  
  11952.  Bit  15                      10                      4                  0
  11953.       ┌──────────────────────┬───────────────────────┬───────────────────┐
  11954.       │    Hours (0-23)      │     Minutes (0-59)    │     2-second      │
  11955.       │                      │                       │ increments (0-29) │
  11956.       └──────────────────────┴───────────────────────┴───────────────────┘
  11957.  
  11958.       Figure 8-4. Format of the time field in a directory entry.
  11959.  
  11960.  
  11961.  Bit  15                               8              4                  0
  11962.       ┌───────────────────────────────┬──────────────┬───────────────────┐
  11963.       │   Year (relative to 1980)     │ Month (1-12) │     Day (1-31)    │
  11964.       │                               │              │                   │
  11965.       └───────────────────────────────┴──────────────┴───────────────────┘
  11966.  
  11967.       Figure 8-5. Format of the date field in a directory entry.
  11968.  
  11969.  
  11970.       The starting cluster field (bytes 1A-1BH) indicates the disk location
  11971.       of the first cluster assigned to the file. This cluster number can be
  11972.       used as an entry point to the file allocation table (FAT) for the
  11973.       disk. (Cluster numbers can be converted to logical sector numbers with
  11974.       the aid of the information in the disk's BPB.)
  11975.  
  11976.       For the . entry (the alias for the directory that contains the entry),
  11977.       the starting cluster field contains the starting cluster number of the
  11978.       directory itself. For the .. entry (the alias for the parent
  11979.       directory), the value in the starting cluster field refers to the
  11980.       parent directory unless the parent directory is the root directory, in
  11981.       which case the starting cluster number is zero.
  11982.  
  11983.       The file size field (bytes 1C-1FH) is a 32-bit integer that indicates
  11984.       the file size in bytes.
  11985.  
  11986.  
  11987.  Volume Labels
  11988.  
  11989.       The generic term volume refers to a unit of auxiliary storage such as
  11990.       a floppy disk, a fixed disk, or a reel of magnetic tape. In computer
  11991.       environments where many different volumes might be used, the operating
  11992.       system can uniquely identify each volume by initializing it with a
  11993.       volume label.
  11994.  
  11995.       Volume labels are implemented in MS-DOS versions 2.0 and later as a
  11996.       specific type of directory entry specified by setting bit 3 in the
  11997.       attribute field to 1. In a volume label directory entry, the name
  11998.       field contains an 11-byte string specifying a name for the disk
  11999.       volume. A volume label can appear only in the root directory of a
  12000.       disk, and only one volume label can be present on any given disk.
  12001.  
  12002.       In MS-DOS versions 2.0 and later, the FORMAT command can be used with
  12003.       the /V switch to initialize a disk with a volume label. In versions
  12004.       3.0 and later, the LABEL command can be used to create, update, or
  12005.       delete a volume label. Several commands can display a disk's volume
  12006.       label, including VOL, DIR, LABEL, TREE, and CHKDSK. See USER COMMANDS.
  12007.  
  12008.       In MS-DOS versions 2.x, volume labels are simply a convenience for the
  12009.       user; no MS-DOS routine uses a volume label for any other purpose. In
  12010.       MS-DOS versions 3.x, however, the SHARE command examines a disk's
  12011.       volume label when it attempts to verify whether a disk volume has been
  12012.       inadvertently replaced in the midst of a file read or write operation.
  12013.       Removable disk volumes should therefore be assigned unique volume
  12014.       names if they are to contain shared files.
  12015.  
  12016.  
  12017.  Functional Support for MS-DOS Directories
  12018.  
  12019.       Several Interrupt 21H service routines can be useful to programmers
  12020.       who need to manipulate directories and their contents (Table 8-1). The
  12021.       routines can be broadly grouped into two categories: those that use a
  12022.       modified file control block (FCB) to pass filenames to and from the
  12023.       Interrupt 21H service routines (Functions 11H, 12H, 17H, and 23H) and
  12024.       those that use hierarchical path specifications (Functions 39H, 3AH,
  12025.       3BH, 43H, 47H, 4EH, 4FH, 56H, and 57H). See PROGRAMMING IN THE MS-DOS
  12026.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: File and Record Management;
  12027.       SYSTEM CALLS: INTERRUPT 21H.
  12028.  
  12029.       The functions that use an FCB require that the calling program
  12030.       reserve enough memory for an extended FCB before the Interrupt 21H
  12031.       function is called. The calling program initializes the filename and
  12032.       extension fields of the FCB and passes the address of the FCB to the
  12033.       MS-DOS service routine in DS:DX. The functions that use pathnames
  12034.       expect all pathnames to be in ASCIIZ format--that is, the last
  12035.       character of the name must be followed by a zero byte.
  12036.  
  12037.       Names in pathnames passed to Interrupt 21H functions can be separated
  12038.       by either a backslash (\) or a forward slash (/). (The forward slash
  12039.       is the separator character used in pathnames in UNIX/XENIX systems.)
  12040.       For example, the pathnames C:/MSP/SOURCE/ROSE.PAS and
  12041.       C:\MSP\SOURCE\ROSE.PAS are equivalent when passed to an Interrupt 21H
  12042.       function. The forward slash can thus be used in a pathname in a
  12043.       program that must run on both MSDOS and UNIX/XENIX. However, the MS-
  12044.       DOS comand processor (COMMAND.COM) recognizes only the backslash as a
  12045.       pathname separator character, so forward slashes cannot be used as
  12046.       separators in the command line.
  12047.  
  12048.  
  12049.       Table 8-1. MS-DOS Functions for Accessing Directories.
  12050.  
  12051. ╓┌────────────────────────┌───────────────────┌──────────────────────┌───────
  12052.       Function            Call With           Returns                Comment
  12053.       ────────────────────────────────────────────────────────────────────────
  12054.       Find First File     AH = 11H            AL = 0 (directory      If defaul
  12055.                           DS:DX = pointer       entry found) or        satisfa
  12056.       Function            Call With           Returns                Comment
  12057.                          DS:DX = pointer       entry found) or        satisfa
  12058.                             to unopened FCB     0FFH (not found)       DTA mus
  12059.                           INT 21H               DTA updated (if        set bef
  12060.                                                 directory entry        using t
  12061.                                                 found)                 functio
  12062.  
  12063.       Find Next File      AH = 12H            AL = 0 (directory      Use the s
  12064.                           DS:DX = pointer       entry found) or        FCB for
  12065.                             to unopened FCB     0FFH (not found)       tion 11
  12066.                           INT 21H             DTA updated (if          Functio
  12067.                                                 directory entry
  12068.                                                 found)
  12069.  
  12070.       Rename File         AH = 17H            AL = 0 (file renamed)
  12071.                           DS:DX = pointer       or 0FFH (no directory
  12072.                             to modified FCB     entry or duplicate
  12073.                           INT 21H               filename)
  12074.  
  12075.       Get File Size       AH = 23H            AL = 0 (directory
  12076.                           DS:DX = pointer       entry found) or
  12077.       Function            Call With           Returns                Comment
  12078.                          DS:DX = pointer       entry found) or
  12079.                             to unopened FCB     0FFH (not found)
  12080.                           INT 21H             FCB updated with
  12081.                                                 number of records
  12082.                                                 in file
  12083.  
  12084.       Create              AH = 39H            Carry flag set
  12085.       Directory           DS:DX = pointer       (if error)
  12086.                             to ASCIIZ         AX = error code
  12087.                             pathname            (if error)
  12088.                           INT 21H
  12089.  
  12090.       Remove              AH = 3AH            Carry flag set
  12091.       Directory           DS:DX = pointer       (if error)
  12092.                             to ASCIIZ         AX = error code
  12093.                             pathname            (if error)
  12094.                           INT 21H
  12095.  
  12096.       Change Current      AH = 3BH            Carry flag set
  12097.       Directory           DS:DX = pointer       (if error)
  12098.       Function            Call With           Returns                Comment
  12099.      Directory           DS:DX = pointer       (if error)
  12100.                             to ASCIIZ         AX = error code
  12101.                             pathname            (if error)
  12102.                           INT 21H
  12103.  
  12104.       Get/Set File        AH = 43H            Carry flag set         Cannot be
  12105.       Attributes          AL = 0 (get           (if error)             used to
  12106.                             attributes)       AX = error code          modify
  12107.                                1 (set           (if error)             volume
  12108.                             attributes)       CX = attribute           or subd
  12109.                           CX = attributes       field from direc-      tory bi
  12110.                             (if AL = 1)         tory entry (if
  12111.                           DS:DX = pointer       called with AL = 0)
  12112.                             to ASCIIZ
  12113.                             pathname
  12114.                           INT 21H
  12115.  
  12116.       Get Current         AH - 47H            Carry flag set
  12117.       Directory           DS:SI = pointer       (if error)
  12118.                             to 64-byte        AX = error code
  12119.       Function            Call With           Returns                Comment
  12120.                            to 64-byte        AX = error code
  12121.                             buffer              (if error)
  12122.                           DL = drive          Buffer updated with
  12123.                             number              pathname of current
  12124.                           INT 21H               directory
  12125.  
  12126.       Find First File     AH = 4EH            Carry flag set         If defaul
  12127.                           DS:DX = pointer       (if error)             not sat
  12128.                             to ASCIIZ         AX = error code          tory, D
  12129.                             pathname            (if error)             must be
  12130.                           CX = file           DTA updated              before
  12131.                             attributes to                              this
  12132.                             match                                      functio
  12133.                           INT 21H
  12134.  
  12135.       Find Next File      AH = 4FH            Carry flag set
  12136.                           INT 21H               (if error)
  12137.                                               AX = error code
  12138.                                                 (if error)
  12139.                                               DTA updated
  12140.       Function            Call With           Returns                Comment
  12141.                                              DTA updated
  12142.  
  12143.       Rename File         AH = 56H            Carry flag set
  12144.                           DS:DX = pointer      (if error)
  12145.                             to ASCIIZ         AX = error code
  12146.                             pathname            (if error)
  12147.                           ES:DI = pointer
  12148.                             to new ASCIIZ
  12149.                             pathname
  12150.                           INT 21H
  12151.  
  12152.       Get/Set Date        AH = 57H            Carry flag set
  12153.       /Time of File       AL = 0 (get           (if error)
  12154.                             date/time)        AX = error code
  12155.                                1 (set           (if error)
  12156.                             date/time)        CX = time
  12157.                           BX = handle           (if AL = 0)
  12158.                           CX = time           DX = date
  12159.                             (if AL = 1)         (if AL = 0)
  12160.                           DX = date
  12161.       Function            Call With           Returns                Comment
  12162.                          DX = date
  12163.                             (if AL = 1)
  12164.                           INT 21H
  12165.  
  12166.  
  12167.  Searching a directory
  12168.  
  12169.       Two pairs of Interrupt 21H functions are available for directory
  12170.       searches. Functions 11H and 12H use FCBs to transfer filenames to
  12171.       MS-DOS; these functions are available in all versions of MS-DOS, but
  12172.        they cannot be used with pathnames. Functions 4EH and 4FH support
  12173.       pathnames, but these functions are unavailable in MS-DOS versions 1.x.
  12174.       All four functions require the address of the disk transfer area (DTA)
  12175.       to be initialized appropriately before the function is invoked. When
  12176.       Function 12H or 4FH is used, the current DTA must be the same as the
  12177.       DTA for the preceding call to Function 11H or 4EH.
  12178.  
  12179.       The Interrupt 21H directory search functions are designed to be used
  12180.       in pairs. The Find First File functions return the first matching
  12181.       directory entry in the current directory (Function 11H) or in the
  12182.       specified directory (Function 4EH). The Find Next File functions
  12183.       (Functions 12H and 4FH) can be called repeatedly after a successful
  12184.       call to the corresponding Find First File function. Each call to one
  12185.       of the Find Next File functions returns the next directory entry that
  12186.       matches the name originally specified to the Find First File function.
  12187.       A directory search can thus be summarized as follows:
  12188.  
  12189.       call "find first file" function
  12190.  
  12191.       while ( matching directory entry returned )
  12192.           call "find next file" function
  12193.  
  12194.  Wildcard characters
  12195.  
  12196.       This search strategy is used because name specifications can include
  12197.       the wildcard characters ?, which matches any single character, and *
  12198.       (see below). When one or more wildcard characters appear in the name
  12199.       specified to one of the Find First File functions, only the
  12200.       nonwildcard characters in the name participate in the directory
  12201.       search. Thus, for example, the specification FOO? matches the
  12202.       filenames FOO1, FOO2, and so on; the specification FOO?????.???
  12203.       matches FOO4.COM, FOOBAR.EXE, and FOONEW.BAK, as well as FOO1 and
  12204.       FOO2; the specification ????????.TXT matches all files whose extension
  12205.       is .TXT; the specification ????????.??? matches all files in the
  12206.       directory.
  12207.  
  12208.       Function 4EH also recognizes the wildcard character *, which matches
  12209.       any remaining characters in a filename or extension. MS-DOS expands
  12210.       the * wildcard character internally to question marks. Thus, for
  12211.       example, the specification FOO* is the same as FOO?????; the
  12212.       specification FOO*.* is the same as FOO?????.???; and, of course, the
  12213.       specification *.* is the same as ????????.???.
  12214.  
  12215.  Examining a directory entry
  12216.  
  12217.       All four Interrupt 21H directory search functions return the name,
  12218.       attribute, file size, time, and date fields for each directory entry
  12219.       found during a directory search. The current DTA is used to return
  12220.       this data, although the format is different for the two pairs of
  12221.       functions: Functions 11H and 12H return a copy of the 32-byte
  12222.       directory entry--including the cluster number--in the DTA; Functions
  12223.       4EH and 4FH return a 43-byte data structure that does not include the
  12224.       starting cluster number. See SYSTEM CALLS: INTERRUPT 21H: Function
  12225.       4EH.
  12226.  
  12227.       The attribute field of a directory entry can be examined using
  12228.       Function 43H (Get/Set File Attributes). Also, Function 57H (Get/Set
  12229.       Date/Time of File) can be used to examine a file's time or date.
  12230.       However, unlike the other functions discussed here, Function 57H is
  12231.       intended only for files that are being actively used within an
  12232.       application--that is, Function 57H can be called to examine the file's
  12233.       time or date stamp only after the file has been opened or created
  12234.       using an Interrupt 21H function that returns a handle (Function 3CH,
  12235.       3DH, 5AH, or 5BH).
  12236.  
  12237.  Modifying a directory entry
  12238.  
  12239.       Four Interrupt 21H functions can modify the contents of a directory
  12240.       entry. Function 17H (Rename File) can be used to change the name field
  12241.       in any directory entry, including hidden or system files,
  12242.       subdirectories, and the volume label. Related Function 56H (Rename
  12243.       File) also changes the name field of a filename but cannot rename a
  12244.       volume label or a hidden or system file. However, it can be used to
  12245.       move a directory entry from one directory to another. (This capability
  12246.       is restricted to filenames only; subdirectory entries cannot be moved
  12247.       with Function 56H.)
  12248.  
  12249.       Functions 43H (Get/Set File Attributes) and 57H (Get/Set Date/Time of
  12250.       File) can be used to modify specific fields in a directory entry.
  12251.       Function 43H can mark a directory entry as a hidden or system file,
  12252.       although it cannot modify the volume label or subdirectory bits.
  12253.       Function 57H, as noted above, can be used only with a previously
  12254.       opened file; it provides a way to read or update a file's time and
  12255.       date stamps without writing to the file itself.
  12256.  
  12257.  Creating and deleting directories
  12258.  
  12259.       Function 39H (Create Directory) exists only to create directories--
  12260.       that is, directory entries with the subdirectory bit set to 1.
  12261.       (Interrupt 21H functions that create files, such as Function 3CH,
  12262.       cannot assign the subdirectory attribute to a directory entry.) The
  12263.       converse function, 3AH (Remove Directory), deletes a subdirectory
  12264.       entry from a directory. (The subdirectory must be completely empty.)
  12265.       Again, Interrupt 21H functions that delete files from directories,
  12266.       such as Function 41H, cannot be used to delete subdirectories.
  12267.  
  12268.  Specifying the current directory
  12269.  
  12270.       A call to Interrupt 21H Function 47H (Get Current Directory) returns
  12271.       the pathname of the current directory in use by MS-DOS to a user-
  12272.       supplied buffer. The converse operation, in which a new current
  12273.       directory can be specified to MS-DOS, is performed by Function 3BH
  12274.       (Change Current Directory).
  12275.  
  12276.  Programming examples: Searching for files
  12277.  
  12278.       The subroutines in Figure 8-6 below illustrate Functions 4EH and 4FH,
  12279.       which use path specifications passed as ASCIIZ strings to search for
  12280.       files. Figure 8-7 applies these assembly-language subroutines in a
  12281.       simple C program that lists the attributes associated with each entry
  12282.       in the current directory. Note how the directory search is performed
  12283.       in the WHILE loop in Figure 8-7 by using a global wildcard file
  12284.       specification (*.*) and by repeatedly executing FindNextFile() until
  12285.       no further matching filenames are found. (See Programming Example:
  12286.       Updating a Volume Label for examples of the FCB-related search
  12287.       functions, 11H and 21H.)
  12288.  
  12289.       ──────────────────────────────────────────────────────────────────────
  12290.  
  12291.       Figure 8-6. Subroutines illustrating Interrupt 21H Functions 4EH and
  12292.       4FH.
  12293.  
  12294.       ──────────────────────────────────────────────────────────────────────
  12295.  
  12296.       Figure 8-7. The complete DIRDUMP.C program.
  12297.  
  12298.       ──────────────────────────────────────────────────────────────────────
  12299.  
  12300.  Programming example: Updating a volume label
  12301.  
  12302.       To create, modify, or delete a volume-label directory entry, the
  12303.       Interrupt 21H functions that work with FCBs should be used. Figure 8-8
  12304.       contains four subroutines that show how to search for, rename, create,
  12305.       or delete a volume label in MS-DOS versions 2.0 and later.
  12306.  
  12307.       ──────────────────────────────────────────────────────────────────────
  12308.  
  12309.       Figure 8-8. Subroutines for manipulating volume labels.
  12310.  
  12311.       ──────────────────────────────────────────────────────────────────────
  12312.  
  12313.  
  12314.                                                    Richard Wilton
  12315.  
  12316.  
  12317.  
  12318.  Article 9:  Memory Management
  12319.  
  12320.  
  12321.       Personal computers that are MS-DOS compatible can be outfitted with as
  12322.       many as three kinds of random-access memory (RAM): conventional
  12323.       memory, expanded memory, and extended memory.
  12324.  
  12325.       All MS-DOS machines have at least some conventional memory, but the
  12326.       presence of expanded or extended memory depends on the installed
  12327.       hardware options and the model of microprocessor on which the computer
  12328.       is based. Each storage class has its own capabilities,
  12329.       characteristics, and limitations. Each also has its own management
  12330.       techniques, which are the subject of this chapter.
  12331.  
  12332.  
  12333.  Conventional Memory
  12334.  
  12335.       Conventional memory is the term for the up to 1 MB of memory that is
  12336.       directly addressable by an Intel 8086/8088 microprocessor or by an
  12337.       80286 or 80386 microprocessor running in real mode (8086-emulation
  12338.       mode). Physical addresses for references to conventional memory are
  12339.       generated by a 16-bit segment register, which acts as a base register
  12340.       and holds a paragraph address, combined with a 16-bit offset contained
  12341.       in an index register or in the instruction being executed.
  12342.  
  12343.       On IBM PCs and compatibles, MS-DOS and the programs that run under its
  12344.       control occupy the bottom 640 KB or less of the conventional memory
  12345.       space. The memory space above the 640 KB mark is partitioned among ROM
  12346.       (read-only memory) chips on the system board that contain various
  12347.       primitive device handlers and test programs and among RAM and ROM
  12348.       chips on expansion boards that are used for input and output buffers
  12349.       and for additional device-dependent routines.
  12350.  
  12351.       The bottom 640 KB of memory administered by MS-DOS is divided into
  12352.       three zones (Figure 9-1):
  12353.  
  12354.       ■  The interrupt vector table
  12355.       ■  The operating system area
  12356.       ■  The transient program area
  12357.  
  12358.  
  12359.       ┌────────────────────────┐  100000H  (1 MB)
  12360.       │       ROM BIOS         │
  12361.       │  additional ROM code   │
  12362.       │  on expansion boards,  │
  12363.       │   memory-mapped I/O    │
  12364.       └───┐   buffers          │
  12365.       ┌──┐└─────┐              │
  12366.       │  └─────┐└──────┐       │
  12367.       │        └──────┐└───────┘
  12368.       │               └────────┐
  12369.       ├────────────────────────┤  A0000H  (640 KB)
  12370.       │                        │
  12371.       │                        │
  12372.       │       Transient        │
  12373.       │     program area       │
  12374.       │                        │
  12375.       │                        │
  12376.       │                        │
  12377.       ├────────────────────────┤  Boundary varies
  12378.       │       MS-DOS and       │
  12379.       │  its buffers, tables,  │
  12380.       │   and device drivers   │
  12381.       ├────────────────────────┤  00400H  (1 KB)
  12382.       │ Interrupt vector table │
  12383.       └────────────────────────┘  00000H
  12384.  
  12385.       Figure 9-1. A diagram showing conventional memory in an IBM PC-
  12386.       compatible MS-DOS system. The bottom 1024 bytes of memory are used for
  12387.       the interrupt vector table. The memory above the vector table, up to
  12388.       the 640 KB boundary, is available for use by MS-DOS and the programs
  12389.       that run under its control. The top 384 KB are used for the ROM BIOS,
  12390.       other device-control and diagnostic routines, and memory-mapped input
  12391.       and output.
  12392.  
  12393.  
  12394.       The interrupt vector table occupies the lowest 1024 bytes of memory
  12395.       (locations 00000003FFH); its address and length are hard-wired into
  12396.       the processor and cannot be changed. Each doubleword position in the
  12397.       table is called an interrupt vector and contains the segment and
  12398.       offset of an interrupt handler routine for the associated hardware or
  12399.       software interrupt number. Interrupt handler routines are usually
  12400.       built into the operating system, but in special cases application
  12401.       programs can contain handler routines of their own. Vectors for
  12402.       interrupt numbers that are not used for software linkages or by some
  12403.       hardware device are usually initialized by the operating system to
  12404.       point to a simple interrupt return (IRET) instruction or to a routine
  12405.       that displays an error message.
  12406.  
  12407.       The operating-system area begins immediately above the interrupt
  12408.       vector table and holds the operating system proper, its tables and
  12409.       buffers, any additional installable device drivers specified in the
  12410.       CONFIG.SYS file, and the resident portion of the COMMAND.COM command
  12411.       interpreter. The amount of memory occupied by the operating-system
  12412.       area varies with the version of MS-DOS being used, the number of disk
  12413.       buffers, and the number and size of installed device drivers.
  12414.  
  12415.       The transient program area (TPA) is the remainder of RAM above the
  12416.       operating-system area, extending to the 640 KB limit or to the end of
  12417.       installed RAM (whichever is smaller). External MS-DOS commands (such
  12418.       as CHKDSK) and other programs are loaded into the TPA for execution.
  12419.       The transient portion of COMMAND.COM also runs in this area.
  12420.  
  12421.       The TPA is organized into a structure called the memory arena, which
  12422.       is divided into portions called arena entries (or memory blocks).
  12423.       These entries are allocated in paragraph (16-byte) multiples and can
  12424.       be as small as one paragraph or as large as the entire TPA. Each arena
  12425.       entry is preceded by a control structure called an arena entry header,
  12426.       which contains information indicating the size and status of the arena
  12427.       entry.
  12428.  
  12429.       MS-DOS inspects the arena entry headers whenever a function requesting
  12430.       a memory-block allocation, modification, or release is issued; when a
  12431.       program is loaded and executed with the EXEC function (Interrupt 21H
  12432.       Function 4BH); or when a program is terminated. If any of the arena
  12433.       entry headers appear to be damaged, MS-DOS returns an error to the
  12434.       calling process. If that process is COMMAND.COM, COMMAND.COM then
  12435.       displays the message Memory allocation error and halts the system.
  12436.  
  12437.  MS-DOS support for conventional memory management
  12438.  
  12439.       The MS-DOS kernel supports three memory-management functions, invoked
  12440.       with Interrupt 21H, that operate on the TPA:
  12441.  
  12442.       ■  Function 48H (Allocate Memory Block)
  12443.       ■  Function 49H (Free Memory Block)
  12444.       ■  Function 4AH (Resize Memory Block)
  12445.  
  12446.       These three functions (Table 9-1) can be called by application
  12447.       programs, by the command processor, and by MS-DOS itself to
  12448.       dynamically allocate, resize, and release arena entries as they are
  12449.       needed. See SYSTEM CALLS: INTERRUPT 21H: Functions 48H; 49H; 4AH.
  12450.  
  12451.  
  12452.       Table 9-1. MS-DOS Memory-Management Functions.
  12453.  
  12454. ╓┌───────────────────────────┌───────────────────────┌───────────────────────╖
  12455.       Function Name          Call With               Returns
  12456.       ──────────────────────────────────────────────────────────────────
  12457.       Allocate Memory Block  AH = 48H                AX = segment of
  12458.                              BX = paragraphs              allocated block
  12459.                                   needed             If failed:
  12460.                                                      BX = size of largest
  12461.                                                           available block in
  12462.                                                           paragraphs
  12463.  
  12464.       Free Memory Block      AH = 49H                nothing
  12465.                              ES = segment of block
  12466.                                   to release
  12467.  
  12468.       Resize (Allocated)     AH = 4AH                If failed:
  12469.       Memory Block           BX = new size of        BX = maximum size
  12470.                                   block in paragraphs     for block in para-
  12471.                              ES = segment of block        graphs
  12472.                                   to resize
  12473.  
  12474.       Get/Set Allocation     AH = 58H                If getting:
  12475.       Strategy1             AL = 00H (get strategy) AX = strategy code
  12476.       Function Name          Call With               Returns
  12477.      Strategy1             AL = 00H (get strategy) AX = strategy code
  12478.                                 = 01H (set strategy)
  12479.                              If setting:
  12480.                              BX = strategy:
  12481.                                   00H = first fit
  12482.                                   01H = best fit
  12483.                                   02H = last fit
  12484.  
  12485.  
  12486.       When the MS-DOS kernel receives a memory-allocation request, it
  12487.       inspects the chain of arena entry headers to find a free arena entry
  12488.       that can satisfy the request. The memory manager can use any of three
  12489.       allocation strategies:
  12490.  
  12491.       ■  First fit-the arena entry at the lowest address that is large
  12492.          enough to satisfy the request
  12493.  
  12494.       ■  Best fit-the smallest available arena entry that satisfies the
  12495.          request, regardless of its position
  12496.  
  12497.       ■  Last fit-the arena entry at the highest address that is large
  12498.          enough to satisfy the request
  12499.  
  12500.       If the arena entry selected is larger than the size needed to fulfill
  12501.       the request, the arena entry is divided and the program is given an
  12502.       arena entry exactly the size it requires. A new arena entry header is
  12503.       then created for the remaining portion of the original arena entry; it
  12504.       is marked "unowned" and can be used to satisfy subsequent allocation
  12505.       calls.
  12506.  
  12507.       Research on allocation strategies has demonstrated that the first-fit
  12508.       approach is most efficient, and this is the default strategy used by
  12509.       MS-DOS. However, in MS-DOS versions 3.0 and later, an application
  12510.       program can select a different strategy for the memory manager with
  12511.       Interrupt 21H Function 58H (Get/Set Allocation Strategy). See SYSTEM
  12512.       CALLS: INTERRUPT 21H: Function 58H.
  12513.  
  12514.  Using the memory-management functions
  12515.  
  12516.       When a program begins executing, it already owns two arena entries
  12517.       allocated on its behalf by the MS-DOS EXEC function (Interrupt 21H
  12518.       Function 4BH). The first entry holds the program's environment and is
  12519.       just large enough to contain this information; the second entry
  12520.       (called the program block in this article) contains the program's PSP,
  12521.       code, data, and stack.
  12522.  
  12523.       The amount of memory MS-DOS allocates to the program block for a newly
  12524.       loaded transient program depends on its type (.COM or .EXE). Under
  12525.       typical conditions, a .COM program is allocated all of the first arena
  12526.       entry that is large enough to hold the contents of its file, plus 256
  12527.       bytes for the PSP and at least 2 bytes for the stack. Because the TPA
  12528.       is seldom fragmented into more than one arena entry before a program
  12529.       is loaded, a .COM program usually ends up owning all the memory in the
  12530.       system that does not belong to the operating system itself--memory
  12531.       divided between a relatively small environment and a comparatively
  12532.       immense program block.
  12533.  
  12534.       The amount of memory allocated to a .EXE program, on the other hand,
  12535.       is controlled by two fields called MINALLOC and MAXALLOC in the .EXE
  12536.       program file header. The MINALLOC field tells the MS-DOS loader how
  12537.       many paragraphs of memory, in addition to the memory required to hold
  12538.       the initialized code and the data present in the file, must be
  12539.       available for the program to execute at all. The MAXALLOC field
  12540.       contains the maximum number of excess paragraphs, if available, to
  12541.       allocate to the program.
  12542.  
  12543.       The default value placed in MAXALLOC by the Microsoft Object Linker is
  12544.       FFFFH paragraphs, corresponding to 1 MB. Consequently, a .EXE program
  12545.       is typically allocated all of available memory when it is loaded, as
  12546.       is a .COM file. Although it is possible to set the MAXALLOC field to
  12547.       other, smaller values with the linker's /CPARMAXALLOC switch or with
  12548.       the EXEMOD utility supplied with Microsoft language compilers, few
  12549.       programmers bother to do so.
  12550.  
  12551.       In short, when a program begins executing, it usually owns all of
  12552.       available memory-frequently much more memory than it needs. If the
  12553.       program wants to be well behaved in its use of memory and, possibly,
  12554.       load child programs as well, it should immediately release any extra
  12555.       memory. In assembly-language programs, the extra memory is released by
  12556.       calling Interrupt 21H Function 4AH (Resize Memory Block) with the
  12557.       segment of the program's PSP in the ES register and the number of
  12558.       paragraphs of memory to retain for the program's use in the BX
  12559.       register. (See Figures 9-2 and 9-3.) In most high-level languages,
  12560.       such as Microsoft C, excess memory is released by the run-time
  12561.       library's startup module.
  12562.  
  12563.       ──────────────────────────────────────────────────────────────────────
  12564.  
  12565.       Figure 9-2. An example of a .COM program releasing excess memory after
  12566.       it receives control from MS-DOS. Interrupt 21H Function 4AH is called
  12567.       with the segment address of the program's PSP in register ES and the
  12568.       number of paragraphs of memory to retain in register BX.
  12569.  
  12570.       ──────────────────────────────────────────────────────────────────────
  12571.  
  12572.       Figure 9-3. An example of a .EXE program releasing excess memory after
  12573.       it receives control from MS-DOS. This particular code sequence depends
  12574.       on the segment order shown. When a .EXE program is linked from many
  12575.       different object modules, other techniques may be needed to determine
  12576.       the amount of memory occupied by the program at run time.
  12577.  
  12578.       ──────────────────────────────────────────────────────────────────────
  12579.  
  12580.       Later, if the transient program needs additional memory for a buffer,
  12581.       table, or other work area, it can call Interrupt 21H Function 48H
  12582.       (Allocate Memory Block) with the desired number of paragraphs. If a
  12583.       sufficiently large block of memory is available, MS-DOS creates a new
  12584.       arena entry of the requested size and returns a pointer to its base in
  12585.       the form of a segment address in the AX register. If an arena entry of
  12586.       the requested size cannot be created, MS-DOS returns an error code in
  12587.       the AX register and the size in paragraphs of the largest available
  12588.       block of memory in the BX register. The application program can
  12589.       inspect this value to determine whether it can continue in a degraded
  12590.       fashion with a smaller amount of memory.
  12591.  
  12592.       When a program finishes using an allocated arena entry, it should
  12593.       promptly call Interrupt 21H Function 49H to release it. This allows
  12594.       MS-DOS to collect small blocks of freed memory into contiguous arena
  12595.       entries and reduces the chance that future allocation requests by the
  12596.       same program will fail because of memory fragmentation. In any case,
  12597.       all arena entries owned by a program are released when the program
  12598.       terminates with Interrupt 20H or with Interrupt 21H Function 00H or
  12599.       4CH.
  12600.  
  12601.       A program skeleton demonstrating the use of dynamic memory allocation
  12602.       services is shown in Figure 9-4.
  12603.  
  12604.       ──────────────────────────────────────────────────────────────────────
  12605.  
  12606.       Figure 9-4. A skeleton example of dynamic memory allocation. The
  12607.       program requests a 32 KB memory block, uses it to copy its working
  12608.       file to a backup file, and then releases the memory block. Note the
  12609.       use of ASSUME directives to force the assembler to generate proper
  12610.       segment overrides on references to variables containing file handles.
  12611.  
  12612.       ──────────────────────────────────────────────────────────────────────
  12613.  
  12614.  Expanded Memory
  12615.  
  12616.       The original Expanded Memory Specification (EMS) version 3.0 was
  12617.       developed as a joint effort of Lotus Development Corporation and Intel
  12618.       Corporation and was announced at the Spring COMDEX in 1985. The EMS
  12619.       was designed to provide a uniform means for applications running on
  12620.       8086/8088-based personal computers, or on 80286/80386-based computers
  12621.       in real mode, to circumvent the 1 MB limit on conventional memory,
  12622.       thus providing such programs with much larger amounts of fast random-
  12623.       access storage. The EMS version 3.2, modified from 3.0 to add support
  12624.       for multitasking operating systems, was released shortly afterward as
  12625.       a joint effort of Lotus, Intel, and Microsoft.
  12626.  
  12627.       The EMS is a functional definition of a bank-switched memory
  12628.       subsystem; it consists of user-installable boards that plug into the
  12629.       IBM PC's expansion bus and a resident driver program called the
  12630.       Expanded Memory Manager (EMM) that is provided by the board
  12631.       manufacturer. As much as 8 MB of expanded memory can be installed in a
  12632.       single machine. Expanded memory is made available to application
  12633.       software in 16 KB pages, which are mapped by the EMM into a contiguous
  12634.       64 KB area called the page frame somewhere above the conventional
  12635.       memory area used by MS-DOS (0-640 KB). An application program can thus
  12636.       access as many as four 16 KB expanded memory pages simultaneously. The
  12637.       location of the page frame is user configurable so that it will not
  12638.       conflict with other hardware options (Figure 9-5).
  12639.  
  12640.  
  12641.                                                     Expanded memory
  12642.                                                    ┌────────────────┐ 8 MB
  12643.                            Conventional memory  ┌──├────────────────┤
  12644.                        1 MB ┌────────────────┐  │  ├────────────────┤
  12645.                             │                │  │  ├───────────┬────┘
  12646.                             │ ROM BIOS etc.  │  │  ├────┬──────┘┌───┐
  12647.                             ├────────────────┤  │  └────┘┌──────┴───┤
  12648.                             │                │  │┌─┌─────┴──────────┤
  12649.                             ├────────────────┤  ││ ├────────────────┤
  12650.                            ▒├────────────────┤─┘│ ├────────────────┤
  12651.          EMS page frame  ─▒├────────────────┤──┘ ├────────────────┤
  12652.       (four 16 KB pages)   ▒├────────────────┤──┐ ├────────────────┤
  12653.                             ├────────────────┤─┐│ ├────────────────┤
  12654.                             │                │  │└─├────────────────┤
  12655.                      640 KB ├────────────────┤  │  ├────────────────┤
  12656.                             │   Transient    │  │  ├────────────────┤
  12657.                             │  program area  │  │  ├────────────────┤
  12658.                             │                │  │  ├────────────────┤
  12659.                             ├────────────────┤  │  ├────────────────┤
  12660.                             │                │  │  ├────────────────┤
  12661.                             │     MS-DOS     │  │  ├────────────────┤
  12662.                      00400H ├────────────────┤  │  ├────────────────┤
  12663.                             │   Interrupt    │  └──├────────────────┤
  12664.                             │  vector table  │     ├────────────────┤
  12665.                           0 └────────────────┘     └────────────────┘ 0
  12666.  
  12667.       Figure 9-5. A sketch of the relationship of expanded memory to
  12668.       conventional memory; 16 KB pages of expanded memory are mapped into a
  12669.       64 KB area, called the page frame, above the 640 KB boundary. The
  12670.       location of the page frame can be configured by the user to eliminate
  12671.       conflicts with ROMs or I/O buffers on expansion boards.
  12672.  
  12673.  
  12674.  The Expanded Memory Manager
  12675.  
  12676.       The Expanded Memory Manager provides a hardware-independent interface
  12677.       between application programs and the expanded memory board(s). The EMM
  12678.       is supplied by the board manufacturer in the form of an installable
  12679.       character-device driver and is linked into MS-DOS by a DEVICE
  12680.       directive added to the CONFIG.SYS file on the system startup disk.
  12681.  
  12682.       Internally, the EMM is divided into two distinct components that can
  12683.       be referred to as the driver and the manager. The driver portion
  12684.       mimics some of the actions of a genuine installable device driver, in
  12685.       that it includes Initialization and Output Status subfunctions and a
  12686.       valid device header. See PROGRAMMING IN THE MS-DOS ENVIRONMENT:
  12687.       CUSTOMIZING MS-DOS: Installable Device Drivers.
  12688.  
  12689.       The second, and major, element of the EMM is the true interface
  12690.       between application software and the expanded memory hardware. Several
  12691.       classes of services provide
  12692.  
  12693.       ■  Status of the expanded memory subsystem
  12694.       ■  Allocation of expanded memory pages
  12695.       ■  Mapping of logical pages into physical memory
  12696.       ■  Deallocation of expanded memory pages
  12697.       ■  Support for multitasking operating systems
  12698.       ■  Diagnostic routines
  12699.  
  12700.       Application programs communicate with the EMM directly by means of a
  12701.       software interrupt (Interrupt 67H). The MS-DOS kernel does not take
  12702.       part in expanded memory manipulations and does not use expanded memory
  12703.       for its own purposes.
  12704.  
  12705.  Checking for expanded memory
  12706.       Before it attempts to use expanded memory for storage, an application
  12707.       program must establish that the EMM is present and functional, and
  12708.       then it must use the manager portion of the EMM to check the status of
  12709.       the memory boards themselves. There are two methods a program can use
  12710.       to test for the existence of the EMM.
  12711.  
  12712.       The first method is to issue an Open File or Device request (Interrupt
  12713.       21H Function 3DH) using the guaranteed device name of the EMM driver:
  12714.       EMMXXXX0. If the open operation succeeds, one of two conditions is
  12715.       indicated--either the driver is present or a file with the same name
  12716.       exists in the current directory of the default disk drive. To rule out
  12717.       the latter possibility, the application can issue IOCTL Get Device
  12718.       Information (Interrupt 21H Function 44H Subfunction 00H) and Check
  12719.       Output Status (Interrupt 21H Function 44H Subfunction 07H) requests to
  12720.       determine whether the handle returned by the open operation is
  12721.       associated with a file or with a device. In either case, the handle
  12722.       that was obtained from the open function should then be closed
  12723.       (Interrupt 21H Function 3EH) so that it can be reused for another file
  12724.       or device.
  12725.  
  12726.       The second method of testing for the driver is to use the address that
  12727.       is found in the vector for Interrupt 67H to inspect the device header
  12728.       of the presumed EMM. (The contents of the vector can be obtained
  12729.       conveniently with Interrupt 21H Function 35H.) If the EMM is present,
  12730.       the name field at offset 0AH of the device header contains the string
  12731.       EMMXXXX0. This method is nearly foolproof, and it avoids the
  12732.       relatively high overhead of an MS-DOS open function. However, it is
  12733.       somewhat less well behaved because it involves inspection of memory
  12734.       that does not belong to the application.
  12735.  
  12736.       The two methods of testing for the existence of the EMM are
  12737.       illustrated in Figures 9-6 and 9-7.
  12738.  
  12739.       ──────────────────────────────────────────────────────────────────────
  12740.  
  12741.       Figure 9-6. Testing for the presence of the Expanded Memory
  12742.       Manager with the MS-DOS Open File or Device (Interrupt 21H Function
  12743.       3DH) and IOCTL (Interrupt 21H Function 44H) functions.
  12744.  
  12745.       ──────────────────────────────────────────────────────────────────────
  12746.  
  12747.       Figure 9-7. Testing for the presence of the Expanded Memory
  12748.       Manager by inspecting the name field in the device driver header.
  12749.  
  12750.       ──────────────────────────────────────────────────────────────────────
  12751.  
  12752.  Using expanded memory
  12753.       After establishing that the EMM is present, the application program
  12754.       can bypass MS-DOS and communicate with the EMM directly by means of
  12755.       software Interrupt 67H. The calling sequence is as follows:
  12756.  
  12757.            mov     ah,function       ; AH selects EMM function
  12758.  
  12759.            .                         ; Load other registers with
  12760.            .                         ; values specific to the
  12761.            .                         ; requested service
  12762.  
  12763.            int     67h               ; Transfer to EMM
  12764.  
  12765.       In general, the ES:DI registers are used to pass the address of a
  12766.       buffer or an array, and the DX register is used to hold an expanded
  12767.       memory "handle." Some EMM functions also use other registers (chiefly
  12768.       AL and BX) to pass such information as logical and physical page
  12769.       numbers. Table 9-2 summarizes the services available from the EMM.
  12770.  
  12771.       Upon return from an EMM function call, the AH register contains zero
  12772.       if the function was successful; otherwise, AH contains an error code
  12773.       with the most significant bit set (Table 9-3). Other values are
  12774.       typically returned in the AL and BX registers or in a user-specified
  12775.       buffer.
  12776.  
  12777.  
  12778.       Table 9-2. MS-DOS Summary of the Software Interface to
  12779.       Application Programs Provided by the EMM.1
  12780.  
  12781. ╓┌───────────────────────┌────────────────────────┌─────────────────────┌────
  12782.       Function                                    Call
  12783.       Name               Action                   With                  Return
  12784.       ────────────────────────────────────────────────────────────────────────
  12785.       Get Manager        Test whether the         AH - 40H              AH = s
  12786.       Status             expanded memory
  12787.                          software and hardware
  12788.                          are functional.
  12789.  
  12790.       Get Page           Obtain the segment       AH = 41H              AH = s
  12791.       Function                                    Call
  12792.       Name               Action                   With                  Return
  12793.      Get Page           Obtain the segment       AH = 41H              AH = s
  12794.       Frame Segment      address of the EMM page                        BX = s
  12795.                          frame.                                              f
  12796.  
  12797.       Get Expanded       Obtain an EMM handle     AH = 43H              AH = s
  12798.       Memory Pages       of logical expanded                            BX = u
  12799.                          memory pages present                                p
  12800.                          in the system and the                          DX = t
  12801.                          number of pages that are                            s
  12802.                          not already allocated.
  12803.  
  12804.       Allocate           Obtain an EMM handle     AH = 43H              AH = s
  12805.       Expanded           and allocate logical     BX = logical pages    DX = h
  12806.       Memory             pages to be controlled        to allocate           A
  12807.                          by that handle.
  12808.  
  12809.  
  12810.  
  12811.  
  12812.       Function                                    Call
  12813.       Name               Action                   With                  Return
  12814. 
  12815.  
  12816.  
  12817.  
  12818.  
  12819.       Map Memory         Map one of the logical   AH = 44H              AH = s
  12820.                          pages of expanded        AL = physical page
  12821.                          memory assigned to a          (0-3)
  12822.                          handle onto one of the   BX = logical page
  12823.                          four physical pages           (0...n-1)
  12824.                          within the EMM's page    DX = EMM handle
  12825.                          frame.
  12826.  
  12827.  
  12828.       Release Handle     Deallocate the logical   AH = 45H              AH = s
  12829.       and Memory         pages of expanded        DX = EMM handle
  12830.                          memory currently
  12831.                          assigned to a handle
  12832.                          and then release the
  12833.       Function                                    Call
  12834.       Name               Action                   With                  Return
  12835.                         and then release the
  12836.                          handle itself for reuse.
  12837.  
  12838.       Get EMM            Return the version       AH = 46H              AH = s
  12839.       Version            number of the EMM                              AL = E
  12840.                          software.                                           i
  12841.  
  12842.  
  12843.       Save Mapping       Save the contents of     AH = 47H              AH = s
  12844.       Context            the expanded memory      DX = EMM handle
  12845.                          page-mapping registers
  12846.                          on the expanded memory
  12847.                          boards, associating
  12848.                          those contents with a
  12849.                          specific EMM handle.
  12850.  
  12851.       Restore            Restore the contents     AH = 48H              AH = s
  12852.       Mapping            of all expanded memory   DX = EMM handle
  12853.       Context            hardware page-mapping
  12854.       Function                                    Call
  12855.       Name               Action                   With                  Return
  12856.      Context            hardware page-mapping
  12857.                          registers to the values
  12858.                          associated with the
  12859.                          given handle.
  12860.  
  12861.       Get Number of      Return the number of     AH = 4BH              AH = s
  12862.       EMM Handles        active EMM handles.                            BX = n
  12863.                                                                              h
  12864.                                                                              A
  12865.  
  12866.  
  12867.  
  12868.       Get Pages          Return the number        AH = 4CH              AH = s
  12869.       Owned by           of logical expanded      DX = EMM handle       BX = l
  12870.       Handle             memory pages allocated                              i
  12871.                          to a specific handle.
  12872.  
  12873.       Get Pages for      Return an array that     AH = 4DH              AH = s
  12874.       All Handles        contains all the active  DI = offset of array  BX = n
  12875.       Function                                    Call
  12876.       Name               Action                   With                  Return
  12877.      All Handles        contains all the active  DI = offset of array  BX = n
  12878.                          handles and the number        to receive            E
  12879.                          of logical expanded           information
  12880.                          memory pages associated  ES = array segment    If AH
  12881.                          with each handle.                                   f
  12882.                                                                              d
  12883.                                                                              c
  12884.  
  12885.       Get/Set            Save or set the          AH = 4EH              AH = s
  12886.       Page Map           contents of the EMM      AL = subfunction      AL = b
  12887.                          page-mapping registers        number                m
  12888.                          on the expanded memory   DS:SI = array              (
  12889.                          boards.                       holding mapping
  12890.                                                        information      Array
  12891.                                                        (Subfunctions    ES:DI
  12892.                                                        01H, 02H)        ping i
  12893.                                                   ES:DI = array to      Subfun
  12894.                                                   receive information   02H
  12895.                                                   (Subfunctions 00H,
  12896.       Function                                    Call
  12897.       Name               Action                   With                  Return
  12898.                                                  (Subfunctions 00H,
  12899.                                                   02H)
  12900.  
  12901.  
  12902.  
  12903.  
  12904.  
  12905.       Table 9-3. The Expanded Memory Manager (EMM) Error Codes.
  12906.  
  12907. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  12908.       Error Code       Significance
  12909.       ──────────────────────────────────────────────────────────────────
  12910.       00H              Function was successful.
  12911.  
  12912.       80H              Internal error in the EMM software. Possible causes
  12913.                        include an error in the driver itself or damage to
  12914.                        its memory image.
  12915.  
  12916.       81H              Malfunction in the expanded memory hardware.
  12917.       Error Code       Significance
  12918.      81H              Malfunction in the expanded memory hardware.
  12919.  
  12920.       82H              EMM is busy.
  12921.  
  12922.       83H              Invalid expanded memory handle.
  12923.  
  12924.       84H              Function requested by the application is not
  12925.                        supported by the EMM.
  12926.  
  12927.       85H              No more expanded memory handles available.
  12928.  
  12929.       86H              Error in save or restore of mapping context.
  12930.  
  12931.       87H              Allocation request specified more logical pages than
  12932.                        are available in the system; no pages were
  12933.                        allocated.
  12934.  
  12935.       88H              Allocation request specified more logical pages than
  12936.                        are currently available in the system (the request
  12937.                        does not exceed the physical pages that exist, but
  12938.       Error Code       Significance
  12939.                       does not exceed the physical pages that exist, but
  12940.                        some are already allocated to other handles); no
  12941.                        pages were allocated.
  12942.  
  12943.       89H              Zero pages cannot be allocated.
  12944.  
  12945.       8AH              Logical page requested for mapping is outside the
  12946.                        range of pages assigned to the handle.
  12947.  
  12948.       8BH              Illegal physical page number in mapping request (not
  12949.                        in the range 0-3).
  12950.  
  12951.       8CH              Save area for mapping contexts is full.
  12952.  
  12953.       8DH              Save of mapping context failed because save area
  12954.                        already contains a context associated with the
  12955.                        requested handle.
  12956.  
  12957.       8EH              Restore of mapping context failed because save area
  12958.                        does not contain a context for the requested handle.
  12959.       Error Code       Significance
  12960.                       does not contain a context for the requested handle.
  12961.  
  12962.       8FH              Subfunction parameter not defined.
  12963.  
  12964.  
  12965.       An application program that uses expanded memory should regard that
  12966.       memory as a system resource, such as a file or a device, and use only
  12967.       the documented EMM services to allocate, access, and release expanded
  12968.       memory pages. Here is the general strategy that can be used by such a
  12969.       program:
  12970.  
  12971.       1. Establish the presence of the EMM by one of the two methods
  12972.          demonstrated in Figures 9-6 and 9-7.
  12973.  
  12974.       2. After the driver is known to be present, check its operational
  12975.          status with EMM Function 40H.
  12976.  
  12977.       3. Check the version number of the EMM with EMM Function 46H to ensure
  12978.          that all services the application will request are available.
  12979.  
  12980.       4. Obtain the segment of the page frame used by the EMM with EMM
  12981.          Function 41H.
  12982.  
  12983.       5. Allocate the desired number of expanded memory pages with EMM
  12984.          Function 43H. If the allocation is successful, the EMM returns a
  12985.          handle in DX that is used by the application to refer to the
  12986.          expanded memory pages it owns. This step is exactly analogous to
  12987.          opening a file and using the handle obtained from the open function
  12988.          for subsequent read/write operations on the file.
  12989.  
  12990.       6. If the requested number of pages is not available, query the EMM
  12991.          for the actual number of pages available (EMM Function 42H) and
  12992.          determine whether the program can continue.
  12993.  
  12994.       7. After successfully allocating the number of expanded memory pages
  12995.          needed, use EMM Function 44H to map logical pages in and out of the
  12996.          physical page frame, to store and retrieve data in expanded memory.
  12997.  
  12998.       8. When finished using the expanded memory pages, release them by
  12999.          calling EMM Function 45H. Otherwise, the pages will not be
  13000.          available for use by other programs until the system is restarted.
  13001.  
  13002.       A program skeleton that illustrates this general approach to the use
  13003.       of expanded memory is shown in Figure 9-8.
  13004.  
  13005.       ──────────────────────────────────────────────────────────────────────
  13006.  
  13007.       Figure 9-8. A program skeleton for the use of expanded memory. This
  13008.       code assumes that the presence of the Expanded Memory Manager has
  13009.       already been verified with one of the techniques shown in Figures 9-6
  13010.       and 9-7.
  13011.  
  13012.       ──────────────────────────────────────────────────────────────────────
  13013.  
  13014.       An interrupt handler or resident driver that uses the EMM follows the
  13015.       same general procedure outlined in steps 1 through 8, with a few minor
  13016.       variations. It may need to acquire an EMM handle and allocate pages
  13017.       before the operating system is fully functional; in particular, the
  13018.       MS-DOS services Open File or Device (Interrupt 21H Function 3DH),
  13019.       IOCTL (Interrupt 21H Function 44H), and Get Interrupt Vector
  13020.       (Interrupt 21H Function 35H) cannot be assumed to be available. Thus,
  13021.       such a handler or driver must use a modified version of the "get
  13022.       interrupt vector" technique to test for the existence of the EMM,
  13023.       fetching the contents of the Interrupt 67H vector directly instead of
  13024.       using MS-DOS Interrupt 21H Function 35H.
  13025.  
  13026.       A device driver or interrupt handler typically owns its expanded
  13027.       memory pages on a permanent basis (until the system is restarted) and
  13028.       never deallocates them. Such a program must also take care to save
  13029.       (EMM Function 47H) and restore (EMM Function 48H) the EMM's page-
  13030.       mapping context (the EMM pages mapped into the page frame at the time
  13031.       the device driver or interrupt handler takes control of the system) so
  13032.       that use of the expanded memory by a foreground program will not be
  13033.       disturbed.
  13034.  
  13035.       The EMM relies heavily on the good behavior of application software to
  13036.       avoid the corruption of expanded memory. If several applications that
  13037.       use expanded memory are running under a multitasking manager, such as
  13038.       Microsoft Windows, and one or more of those applications does not
  13039.       abide strictly by the EMM's conventions, the data stored in expanded
  13040.       memory can be corrupted.
  13041.  
  13042.  
  13043.  Extended Memory
  13044.  
  13045.       Extended memory is that storage at addresses above 1 MB (100000H) that
  13046.       can be accessed by an 80286 or 80386 microprocessor running in
  13047.       protected mode. IBM PC/AT-compatible machines can (theoretically) have
  13048.       as much as 15 MB of extended memory installed, in addition to the
  13049.       usual 1 MB of conventional memory address space. Unlike expanded
  13050.       memory, extended memory is linearly addressable: The address of each
  13051.       memory cell is fixed, so no special manager program is required.
  13052.  
  13053.       Protected-mode operating systems, such as Microsoft XENIX and MS OS/2,
  13054.       can use extended memory for execution of programs. MS-DOS, on the
  13055.       other hand, runs in real mode on an 80286 or 80386, and programs
  13056.       running under its control cannot ordinarily execute from extended
  13057.       memory or even address that memory for storage of data.
  13058.  
  13059.       To provide some access to extended memory for real-mode programs, IBM
  13060.       PC/ATcompatible machines contain two routines in their ROM BIOS
  13061.       (Tables 9-4 and 9-5) that allow the amount of extended memory present
  13062.       to be determined (Interrupt 15H Function 88H) and that transfer blocks
  13063.       of data between conventional memory and extended memory (Interrupt
  13064.       15H Function 87H). These routines can be used by electronic disks
  13065.       (RAMdisks) and by other programs that wish to use extended memory for
  13066.       fast storage and retrieval of information that would otherwise have to
  13067.       be written to a slower physical disk drive.
  13068.  
  13069.  
  13070.       Table 9-4. IBM PC/AT ROM BIOS Interrupt 15H Functions for
  13071.       Access to Extended Memory.
  13072.  
  13073. ╓┌─────────────────────────────┌─────────────────────────┌───────────────────╖
  13074.       Interrupt 15H Function   Call With                 Returns
  13075.       ──────────────────────────────────────────────────────────────────────
  13076.       Move Extended            AH = 87H1                Carry flag =
  13077.       Memory Block             CX = length (words)         0 if successful
  13078.                                                            1 if error
  13079.                                ES:SI = address of block  AH = status:
  13080.                                      = move descriptor     00H no error
  13081.                                      = table               01H RAM parity
  13082.                                                            error
  13083.                                                            02H exception
  13084.                                                            interrupt error
  13085.       Interrupt 15H Function   Call With                 Returns
  13086.                                                           interrupt error
  13087.                                                            03H gate address
  13088.                                                            line 20 failed
  13089.       Obtain Size of           AH = 88H                  AX = kilobytes of
  13090.       Extended Memory                                      memory installed
  13091.                                                            above 1 MB
  13092.  
  13093.  
  13094.       Table 9-5. Block Move Descriptor Table Format for IBM PC/AT ROM BIOS
  13095.       Interrupt 15H Function 87H (Move Extended Memory Block).
  13096.  
  13097. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  13098.       Bytes       Contents
  13099.       ──────────────────────────────────────────────────────────────────
  13100.       00-0FH      Zero
  13101.       10-11H      Segment length in bytes (2*CX-1 or greater)
  13102.       12-14H      24-bit source address
  13103.       15H         Access rights byte (93H)
  13104.       16-17H      Zero
  13105.       18-19H      Segment length in bytes (2*CX-1 or greater)
  13106.       Bytes       Contents
  13107.      18-19H      Segment length in bytes (2*CX-1 or greater)
  13108.       1A-1CH      24-bit destination address
  13109.       1DH         Access rights byte (93H)
  13110.       1E-1FH      Zero
  13111.       20-2FH      Zero
  13112.  
  13113.  
  13114.       Note: This data structure actually constitutes a global descriptor
  13115.       table (GDT) to be used by the CPU while it is running in protected
  13116.       mode; the zero bytes at offsets 0-0FH and 20-2FH are filled in by the
  13117.       ROM BIOS code before the mode transition. The supplied 24-bit address
  13118.       is a linear address in the range 000000-FFFFFFH (not a segment and
  13119.       offset), with the least significant byte first and the most
  13120.       significant byte last.
  13121.  
  13122.       Programmers should use these ROM BIOS routines with caution. Data
  13123.       stored in extended memory is volatile; it is lost if the machine is
  13124.       turned off. The transfer of data to or from extended memory involves a
  13125.       switch from real mode to protected mode and back again. This is a
  13126.       relatively slow process on 80286-based machines; in some cases it is
  13127.       only marginally faster than actually reading the data from a fixed
  13128.       disk. In addition, programs that use the ROM BIOS extended memory
  13129.       functions are not compatible with the MS-DOS 3.x Compatibility Box of
  13130.       MS OS/2, nor are they reliable if used for communications or
  13131.       networking.
  13132.  
  13133.       Finally, a major deficit in these ROM BIOS functions is that they do
  13134.       not make any attempt to arbitrate between two or more programs or
  13135.       device drivers that are using extended memory for temporary storage.
  13136.       For example, if an application program and an installed RAMdisk driver
  13137.       attempt to put data in the same area of extended memory, no error is
  13138.       returned to either program, but the data belonging to one or both may
  13139.       be destroyed.
  13140.  
  13141.       Figure 9-9 demonstrates the use of the ROM BIOS routines to transfer a
  13142.       block of data from extended memory to conventional memory.
  13143.  
  13144.       ──────────────────────────────────────────────────────────────────────
  13145.  
  13146.       Figure 9-9. Demonstration of a block move from extended memory to
  13147.       conventional memory using the ROM BIOS routine. The procedure
  13148.       getblk accepts a source address in extended memory, a destination
  13149.       address in conventional memory, a length in bytes, and the segment
  13150.       and offset of a block move descriptor table. The extended-memory
  13151.       address is a linear 32-bit address, of which only the lower 24 bits
  13152.       are significant; the conventional-memory address is a segment and
  13153.       offset. The getblk routine converts the destination segment and offset
  13154.       to a linear address, builds the appropriate fields in the block move
  13155.       descriptor table, invokes the ROM BIOS routine to perform the
  13156.       transfer, and returns the status in the AH register.
  13157.  
  13158.       ──────────────────────────────────────────────────────────────────────
  13159.  
  13160.  Summary
  13161.  
  13162.       Personal computers that run MS-DOS can support as many as three
  13163.       different types of fast, random-access memory (RAM). Each type has
  13164.       specific characteristics and requires different techniques for its
  13165.       management.
  13166.  
  13167.       Conventional memory is the term used for the 1 MB of linear address
  13168.       space that can be accessed by an 8086 or 8088 microprocessor or by an
  13169.       80286 or 80386 microprocessor running in real mode. MS-DOS and the
  13170.       programs that execute under its control run in this address space.
  13171.       MS-DOS provides application programs with services to dynamically
  13172.       allocate and release blocks of conventional memory.
  13173.  
  13174.       As much as 8 MB of expanded memory can be installed in a PC and used
  13175.       for electronic disks, disk caching, and storage of application program
  13176.       data. The memory is made available in 16 KB pages and is administered
  13177.       by a driver program called the Expanded Memory Manager, which provides
  13178.       allocation, mapping, deallocation, and multitasking support.
  13179.  
  13180.       Extended memory refers to the memory at addresses above 1 MB that can
  13181.       be accessed by an 80286-based or 80386-based microprocessor running in
  13182.       protected mode; it is not available in PCs based on the 8086 or 8088
  13183.       microprocessors. As much as 15 MB of extended memory can be installed;
  13184.       however, the ROM BIOS services to access the memory are primitive and
  13185.       slow, and no manager is provided to arbitrate between multiple
  13186.       programs that attempt to use the same extended memory addresses for
  13187.       storage.
  13188.  
  13189.                                                     Ray Duncan
  13190.  
  13191.  
  13192.  
  13193.  Article 10: The MS-DOS EXEC Function
  13194.  
  13195.  
  13196.       The MS-DOS system loader, which brings .COM or .EXE files from disk
  13197.       into memory and executes them, can be invoked by any program with the
  13198.       MS-DOS EXEC function (Interrupt 21H Function 4BH). The default MS-DOS
  13199.       command interpreter, COMMAND.COM, uses the EXEC function to load and
  13200.       run its external commands, such as CHKDSK, as well as other
  13201.       application programs. Many popular commercial programs, such as
  13202.       databases and word processors, use EXEC to load and run subsidiary
  13203.       programs (spelling checkers, for example) or to load and run a second
  13204.       copy of COMMAND.COM. This allows a user to run subsidiary programs or
  13205.       enter MS-DOS commands without losing his or her current working
  13206.       context.
  13207.  
  13208.       When EXEC is used by one program (called the parent) to load and run
  13209.       another (called the child), the parent can pass certain information to
  13210.       the child in the form of a set of strings called the environment, a
  13211.       command line, and two file control blocks. The child program also
  13212.       inherits the parent program's handles for the MS-DOS standard devices
  13213.       and for any other files or character devices the parent has opened
  13214.       (unless the open operation was performed with the "noninheritance"
  13215.       option). Any operations performed by the child on inherited handles,
  13216.       such as seeks or file I/O, also affect the file pointers associated
  13217.       with the parent's handles. A child program can, in turn, load another
  13218.       program, and the cycle can be repeated until the system's memory area
  13219.       is exhausted.
  13220.  
  13221.       Because MS-DOS is not a multitasking operating system, a child program
  13222.       has complete control of the system until it has finished its work; the
  13223.       parent program is suspended. This type of processing is sometimes
  13224.       called synchronous execution. When the child terminates, the parent
  13225.       regains control and can use another system function call (Interrupt
  13226.       21H Function 4DH) to obtain the child's return code and determine
  13227.       whether the program terminated normally, because of a critical
  13228.       hardware error, or because the user entered a Control-C.
  13229.  
  13230.       In addition to loading a child program, EXEC can also be used to load
  13231.       subprograms and overlays for application programs written in assembly
  13232.       language or in a high-level language that does not include an overlay
  13233.       manager in its run-time library. Such overlays typically cannot be run
  13234.       as self-contained programs; most require "helper" routines or data in
  13235.       the application's root segment.
  13236.  
  13237.       The EXEC function is available only with MS-DOS versions 2.0 and
  13238.       later. With MS-DOS versions 1.x, a parent program can use Interrupt
  13239.       21H Function 26H to create a program segment prefix for a child but
  13240.       must carry out the loading, relocation, and execution of the child's
  13241.       code and data itself, without any assistance from the operating
  13242.       system.
  13243.  
  13244.  
  13245.  How EXEC Works
  13246.  
  13247.       When the EXEC function receives a request to execute a program, it
  13248.       first attempts to locate and open the specified program file. If the
  13249.       file cannot be found, EXEC fails immediately and returns an error code
  13250.       to the caller.
  13251.  
  13252.       If the file exists, EXEC opens the file, determines its size, and
  13253.       stop inspects the first block of the file. If the first 2 bytes of the
  13254.       block are the ASCII characters MZ, the file is assumed to contain a
  13255.       .EXE load module, and the sizes of the program's code, data, and stack
  13256.       segments are obtained from the .EXE file header. Otherwise, the entire
  13257.       file is assumed to be an absolute load image (a .COM program). The
  13258.       actual filename extension (.COM or .EXE) is ignored in this
  13259.       determination.
  13260.  
  13261.       At this point, the amount of memory needed to load the program is
  13262.       known, so EXEC attempts to allocate two blocks of memory: one to hold
  13263.       the new program's environment and one to contain the program's code,
  13264.       data, and stack segments. Assuming that enough memory is available to
  13265.       hold the program itself, the amount actually allocated to the program
  13266.       varies with its type. Programs of the .COM type are usually given all
  13267.       the free memory in the system (unless the memory area has previously
  13268.       become fragmented), whereas the amount assigned to a .EXE program is
  13269.       controlled by two fields in the file header, MINALLOC and MAXALLOC,
  13270.       that are set by the Microsoft Object Linker (LINK). See PROGRAMMING IN
  13271.       THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: Structure of an
  13272.       Application Program; PROGRAMMING TOOLS: The Microsoft Object Linker;
  13273.       PROGRAMMING UTILITIES: LINK.
  13274.  
  13275.       EXEC then copies the environment from the parent into the memory
  13276.       allocated for child's environment, builds a program segment prefix
  13277.       (PSP) at the base of the child's program memory block, and copies into
  13278.       the child's PSP the command tail and the two default file control
  13279.       blocks passed by the parent. The previous contents of the terminate
  13280.       (Interrupt 22H), Control-C (Interrupt 23H), and critical error
  13281.       (Interrupt 24H) vectors are saved in the new PSP, and the terminate
  13282.       vector is updated so that control will return to the parent program
  13283.       when the child terminates or is aborted.
  13284.  
  13285.       The actual code and data portions of the child program are then read
  13286.       from the disk file into the program memory block above the newly
  13287.       constructed PSP. If the child is a .EXE program, a relocation table in
  13288.       the file header is used to fix up segment references within the
  13289.       program to reflect its actual load address.
  13290.  
  13291.       Finally, the EXEC function sets up the CPU registers and stack
  13292.       according to the program type and transfers control to the program.
  13293.       The entry point for a .COM file is always offset 100H within the
  13294.       program memory block (the first byte following the PSP). The entry
  13295.       point for a .EXE file is specified in the file header and can be
  13296.       anywhere within the program. See also PROGRAMMING IN THE MS-DOS
  13297.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: Structure of an Application
  13298.       Program.
  13299.  
  13300.       When EXEC is used to load and execute an overlay rather than a child
  13301.       program, its operation is much simpler than described above. For an
  13302.       overlay, EXEC does not attempt to allocate memory or build a PSP or
  13303.       environment. It simply loads the contents of the file at the address
  13304.       specified by the calling program and performs any necessary
  13305.       relocations (if the overlay file has a .EXE header), using a segment
  13306.       value that is also supplied by the caller. EXEC then returns to the
  13307.       program that invoked it, rather than transferring control to the code
  13308.       in the newly loaded file. The requesting program is responsible for
  13309.       calling the overlay at the appropriate location.
  13310.  
  13311.  
  13312.  Using EXEC to Load a Program
  13313.  
  13314.       When one program loads and executes another, it must follow these
  13315.       steps:
  13316.  
  13317.       1. Ensure that enough free memory is available to hold the code, data,
  13318.          and stack of the child program.
  13319.  
  13320.       2. Set up the information to be passed to EXEC and the child program.
  13321.  
  13322.       3. Call the MS-DOS EXEC function to run the child program.
  13323.  
  13324.       4. Recover and examine the child program's termination and return
  13325.          codes.
  13326.  
  13327.  Making memory available
  13328.  
  13329.       MS-DOS typically allocates all available memory to a .COM or .EXE
  13330.       program when it is loaded. (The infrequent exceptions to this rule
  13331.       occur when the transient program area is fragmented by the presence of
  13332.       resident data or programs or when a .EXE program is loaded that was
  13333.       linked with the /CPARMAXALLOC switch or modified with EXEMOD.)
  13334.       Therefore, before a program can load another program, it must free any
  13335.       memory it does not need for its own code, data, and stack.
  13336.  
  13337.       The extra memory is released with a call to the MS-DOS Resize Memory
  13338.       Block function (Interrupt 21H Function 4AH). In this case, the segment
  13339.       address of the parent's PSP is passed in the ES register, and the BX
  13340.       register holds the number of paragraphs of memory the program must
  13341.       retain for its own use. If the prospective parent is a .COM program,
  13342.       it must be certain to move its stack to a safe area if it is reducing
  13343.       its memory allocation to less than 64 KB.
  13344.  
  13345.  Preparing parameters for EXEC
  13346.  
  13347.       When used to load and execute a program, the EXEC function must be
  13348.       supplied with two principal parameters:
  13349.  
  13350.       ■  The address of the child program's pathname
  13351.       ■  The address of a parameter block
  13352.  
  13353.       The parameter block, in turn, contains the addresses of information to
  13354.       be passed to the child program.
  13355.  
  13356.  The program name
  13357.  
  13358.       The pathname for the child program must be an unambiguous, null-
  13359.       terminated (ASCIIZ) file specification (no wildcard characters). If
  13360.       a path is not included, the current directory is searched for the
  13361.       program; if a drive specifier is not present, the default drive is
  13362.       used.
  13363.  
  13364.  The parameter block
  13365.  
  13366.       The parameter block contains the addresses of four data items
  13367.       Figure 10-1):
  13368.  
  13369.       ■  The environment block
  13370.       ■  The command tail
  13371.       ■  The two default file control blocks (FCBs)
  13372.  
  13373.       The position reserved in the parameter block for the pointer to an
  13374.       environment is only 2 bytes and contains a segment address, because an
  13375.       environment is always paragraph aligned (its address is always evenly
  13376.       divisible by 16); a value of 0000H indicates the parent program's
  13377.       environment should be inherited unchanged. The remaining three
  13378.       addresses are all doubleword addresses in the standard Intel format,
  13379.       with an offset value in the lower word and a segment value in the
  13380.       upper word.
  13381.  
  13382.  
  13383.               ╔══════════════════════════════════════════╗
  13384.               ║                                          ║
  13385.               ║    Figure 10-1 is found on page 324      ║
  13386.               ║    in the printed version of the book.   ║
  13387.               ║                                          ║
  13388.               ╚══════════════════════════════════════════╝
  13389.  
  13390.       Figure 10-1. Synopsis of calling conventions for the MS-DOS EXEC
  13391.       function (Interrupt 21H Function 4BH), which can be used to load and
  13392.       execute child processes or overlays.
  13393.  
  13394.  
  13395.       The environment
  13396.       An environment always begins on a paragraph boundary and is composed
  13397.       of a series of null-terminated (ASCIIZ) strings of the form:
  13398.  
  13399.       name = variable
  13400.  
  13401.       The end of the entire set of strings is indicated by an additional
  13402.       null byte.
  13403.  
  13404.       If the environment pointer in the parameter block supplied to an EXEC
  13405.       call contains zero, the child simply acquires a copy of the parent's
  13406.       environment. The parent can, however, provide a segment pointer to a
  13407.       different or expanded set of strings. In either case, under MS-DOS
  13408.       versions 3.0 and later, EXEC appends the child program's fully
  13409.       qualified pathname to its environment block. The maximum size of an
  13410.       environment is 32 KB, so very large amounts of information can be
  13411.       passed between programs by this mechanism.
  13412.  
  13413.       The original, or master, environment for the system is owned by the
  13414.       command processor that is loaded when the system is turned on or
  13415.       restarted (usually COMMAND.COM). Strings are placed in the system's
  13416.       master environment by COMMAND.COM as a result of PATH, SHELL, PROMPT,
  13417.       and SET commands, with default values always present for the first
  13418.       two. For example, if an MS-DOS version 3.2 system is started from
  13419.       drive C and a PATH command is not present in the AUTOEXEC.BAT file nor
  13420.       a SHELL command in the CONFIG.SYS file, the master environment will
  13421.       contain the two strings:
  13422.  
  13423.       PATH =
  13424.       COMSPEC = C:\COMMAND.COM
  13425.  
  13426.       These specifications are used by COMMAND.COM to search for executable
  13427.       "external" commands and to find its own executable file on the disk so
  13428.       that it can reload its transient portion when necessary. When the
  13429.       PROMPT string is present (as a result of a previous PROMPT or SET
  13430.       PROMPT command), COMMAND.COM uses it to tailor the prompt displayed to
  13431.       the user.
  13432.  
  13433.  
  13434.        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F 0123456789ABCDEF
  13435.  0000 43 4F 4D 53 50 45 43 3D 43 3A 5C 43 4F 4D 4D 41 COMSPEC=C:\COMMA
  13436.  0010 4E 44 2E 43 4F 4D 00 50 52 4F 4D 50 54 3D 24 70 ND.COM.PROMPT=$p
  13437.  0020 24 5F 24 64 20 20 20 24 74 24 68 24 68 24 68 24 $$d   $t$h$h$h$
  13438.  0030 68 24 68 24 68 20 24 71 24 71 24 67 00 50 41 54 h$h$h $q$q$g.PAT
  13439.  0040 48 3D 43 3A 5C 53 59 53 54 45 4D 3B 43 3A 5C 41 H=C:\SYSTEM;C:\A
  13440.  0050 53 4D 3B 43 3A 5C 57 53 3B 43 3A 5C 45 54 48 45 SM;C:\WS;C:\ETHE
  13441.  0060 52 4E 45 54 3B 43 3A 5C 46 4F 52 54 48 5C 50 43 RNET;C:\FORTH\PC
  13442.  0070 33 31 3B 00 00 01 00 43 3A 5C 46 4F 52 54 48 5C 31;....C:\FORTH\
  13443.  0080 50 43 33 31 5C 46 4F 52 54 48 2E 43 4F 4D 00    PC31\FORTH.COM.
  13444.  
  13445.       Figure 10-2. Dump of a typical environment under MS-DOS version
  13446.       3.2. This particular example contains the default COMSPEC parameter
  13447.       and two relatively complex PATH and PROMPT control strings that were
  13448.       set up by entries in the user's AUTOEXEC file. Note the two null bytes
  13449.       at offset 73H, which indicate the end of the environment. These bytes
  13450.       are followed by the pathname of the program that owns the environment.
  13451.  
  13452.  
  13453.       Other strings in the environment are used only for informational
  13454.       purposes by transient programs and do not affect the operation of the
  13455.       operating system proper. For example, the Microsoft C Compiler and the
  13456.       Microsoft Object Linker look in the environment for INCLUDE, LIB, and
  13457.       TMP strings that specify the location of include files, library files,
  13458.       and temporary working files. Figure 10-2 contains a hex dump of a
  13459.       typical environment block.
  13460.  
  13461.       The command tail
  13462.       The command tail to be passed to the child program takes the form of a
  13463.       byte indicating the length of the remainder of the command tail,
  13464.       followed by a string of ASCII characters terminated with an ASCII
  13465.       carriage return (0DH); the carriage return is not included in the
  13466.       length byte. The command tail can include switches, filenames, and
  13467.       other parameters that can be inspected by the child program and used
  13468.       to influence its operation. It is copied into the child program's PSP
  13469.       at offset 80H.
  13470.  
  13471.       When COMMAND.COM uses EXEC to run a program, it passes a command tail
  13472.       that includes everything the user typed in the command line except the
  13473.       name of the program and any redirection parameters. I/O redirection is
  13474.       processed within COMMAND.COM itself and is manifest in the behavior of
  13475.       the standard device handles that are inherited by the child program.
  13476.       Any other program that uses EXEC to run a child program must try to
  13477.       perform any necessary redirection on its own and must supply an
  13478.       appropriate command tail so that the child program will behave as
  13479.       though it had been loaded by COMMAND.COM.
  13480.  
  13481.       The default file control blocks
  13482.       The two default FCBs pointed to by the EXEC parameter block are copied
  13483.       into the child program's PSP at offsets 5CH and 6CH. See also
  13484.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: File
  13485.       and Record Management.
  13486.  
  13487.       Few of the currently popular application programs use FCBs for file
  13488.       and record I/O because FCBs do not support the hierarchical directory
  13489.       structure. But some programs do inspect the default FCBs as a quick
  13490.       way to isolate the first two switches or other parameters from the
  13491.       command tail. Therefore, to make its own identity transparent to the
  13492.       child program, the parent should emulate the action of COMMAND.COM by
  13493.       parsing the first two parameters of the command tail into the default
  13494.       FCBs. This can be conveniently accomplished with the MS-DOS function
  13495.       Parse Filename (Interrupt 21H Function 29H).
  13496.  
  13497.       If the child program does not require one or both of the default FCBs,
  13498.       the corresponding address in the parameter block can be initialized to
  13499.       point to two dummy FCBs in the application's memory space. These dummy
  13500.       FCBs should consist of 1 zero byte followed by 11 bytes containing
  13501.       ASCII blank characters (20H).
  13502.  
  13503.  Running the child program
  13504.  
  13505.       After the parent program has constructed the necessary parameters, it
  13506.       can invoke the EXEC function by issuing Interrupt 21H with the
  13507.       registers set as follows:
  13508.  
  13509.       AH          = 4BH
  13510.       AL          = 00H (EXEC subfunction to load and execute program)
  13511.       DS:DX       = segment:offset of program pathname
  13512.       ES:BX       = segment:offset of parameter block
  13513.  
  13514.       Upon return from the software interrupt, the parent must test the
  13515.       carry flag to determine whether the child program did, in fact, run.
  13516.       If the carry flag is clear, the child program was successfully loaded
  13517.       and given control. If the carry flag is set, the EXEC function failed,
  13518.       and the error code returned in AX can be examined to determine why.
  13519.       The usual reasons are
  13520.  
  13521.       ■  The specified file could not be found.
  13522.       ■  The file was found, but not enough memory was free to load it.
  13523.  
  13524.       Other causes are uncommon and can be symptoms of more severe problems
  13525.       in the system as a whole (such as damage to disk files or to the
  13526.       memory image of MS-DOS). With MS-DOS versions 3.0 and later,
  13527.       additional details about the cause of an EXEC failure can be obtained
  13528.       by subsequently calling Interrupt 21H Function 59H (Get Extended Error
  13529.       Information).
  13530.  
  13531.       In general, supplying either an invalid address for an EXEC parameter
  13532.       block or invalid addresses within the parameter block itself does not
  13533.       cause a failure of the EXEC function, but may result in the child
  13534.       program behaving in unexpected ways.
  13535.  
  13536.  Special considerations
  13537.  
  13538.       With MS-DOS versions 2.x, the previous contents of all the parent
  13539.       registers except for CS:IP can be destroyed after an EXEC call,
  13540.       including the stack pointer in SS:SP. Consequently, before issuing the
  13541.       EXEC call, the parent must push onto the stack the contents of any
  13542.       registers that it needs to preserve, and then it must save the stack
  13543.       segment and offset in a location that is addressable with the CS
  13544.       segment register. Upon return, the stack segment and offset can be
  13545.       loaded into SS:SP with code segment overrides, and then the other
  13546.       registers can be restored by popping them off the stack. With MS-DOS
  13547.       versions 3.0 and later, registers are preserved across an EXEC call in
  13548.       the usual fashion.
  13549.  
  13550.       Note: The code segments of Windows applications that use this
  13551.       technique should be given the IMPURE attribute.
  13552.  
  13553.       In addition, a bug in MS-DOS version 2.0 and in PC-DOS versions 2.0
  13554.       and 2.1 causes an arbitrary doubleword in the parent's stack segment
  13555.       to be destroyed during an EXEC call. When the parent is a .COM program
  13556.       and SS = PSP, the damaged location falls within the PSP and does no
  13557.       harm; however, in the case of a .EXE parent where DS = SS, the
  13558.       affected location may overlap the data segment and cause aberrant
  13559.       behavior or even a crash after the return from EXEC. This bug was
  13560.       fixed in MS-DOS versions 2.11 and later and in PC-DOS versions 3.0
  13561.       and later.
  13562.  
  13563.  Examining the child program's return codes
  13564.  
  13565.       If the EXEC function succeeds, the parent program can call Interrupt
  13566.       21H Function 4DH (Get Return Code of Child Process) to learn whether
  13567.       the child executed normally to completion and passed back a return
  13568.       code or was terminated by the operating system because of an external
  13569.       event. Function 4DH returns
  13570.  
  13571.       AH   = termination type:
  13572.  
  13573.            = 00H   Child terminated normally (that is, exited via
  13574.                    Interrupt 20H or Interrupt 21H Function 00H or Function
  13575.                    4CH).
  13576.  
  13577.            = 01H   Child was terminated by user's entry of a Ctrl-C.
  13578.  
  13579.            = 02H   Child was terminated by critical error handler (either
  13580.                    the user responded with A to the Abort, Retry, Ignore
  13581.                    prompt from the system's default Interrupt 24H handler,
  13582.                    or a custom Interrupt 24H handler returned to MS-DOS with
  13583.                    action code = 02H in register AL).
  13584.  
  13585.            = 03H   Child terminated normally and stayed resident (that is,
  13586.                    exited via Interrupt 21H Function 31H or Interrupt 27H).
  13587.  
  13588.       AL   = return code:
  13589.  
  13590.            = Value passed by the child program in register AL when it
  13591.              terminated with Interrupt 21H Function 4CH or 31H.
  13592.  
  13593.            = 00H if the child terminated using Interrupt 20H, Interrupt
  13594.              27H, or Interrupt 21H Function 00H.
  13595.  
  13596.       These values are only guaranteed to be returned once by Function 4DH.
  13597.       Thus, a subsequent call to Function 4DH, without an intervening EXEC
  13598.       call, does not necessarily return any useful information.
  13599.       Additionally, if Function 4DH is called without a preceding successful
  13600.       EXEC call, the returned values are meaningless.
  13601.  
  13602.  Using COMMAND.COM with EXEC
  13603.  
  13604.       An application program can "shell" to MS-DOS--that is, provide the
  13605.       user with an MS-DOS prompt without terminating--by using EXEC to load
  13606.       and execute a secondary copy of COMMAND.COM with an empty command
  13607.       tail. The application can obtain the location of the COMMAND.COM disk
  13608.       file by inspecting its own environment for the COMSPEC string. The
  13609.       user returns to the application from the secondary command processor
  13610.       by typing exit at the COMMAND.COM prompt.
  13611.  
  13612.       Batch-file interpretation is carried out by COMMAND.COM, and a batch
  13613.       (.BAT) file cannot be called using the EXEC function directly.
  13614.       Similarly, the sequential search for .COM, .EXE, and .BAT files in all
  13615.       the locations specified in the environment's PATH variable is a
  13616.       function of COMMAND.COM, rather than of EXEC. To execute a batch file
  13617.       or search the system path for a program, an application program can
  13618.       use EXEC to load and execute a secondary copy of COMMAND.COM to use as
  13619.       an intermediary. The application finds the location of COMMAND.COM as
  13620.       described in the preceding paragraph, but it passes a command tail in
  13621.       the form:
  13622.  
  13623.       /C program parameter1 parameter2 ...
  13624.  
  13625.       where program is the .EXE, .COM, or .BAT file to be executed. When
  13626.       program terminates, the secondary copy of COMMAND.COM exits and
  13627.       returns control to the parent.
  13628.  
  13629.  A parent and child example
  13630.  
  13631.       The source programs PARENT.ASM in Figure 10-3 and CHILD.ASM in Figure
  13632.       10-4 illustrate how one program uses EXEC to load another.
  13633.  
  13634.       ──────────────────────────────────────────────────────────────────────
  13635.  
  13636.       Figure 10-3. PARENT.ASM, source code for PARENT.EXE.
  13637.  
  13638.       ──────────────────────────────────────────────────────────────────────
  13639.  
  13640.       Figure 10-4. CHILD.ASM, source code for CHILD.EXE.
  13641.  
  13642.       ──────────────────────────────────────────────────────────────────────
  13643.  
  13644.       PARENT.ASM can be assembled and linked into the executable program
  13645.       PARENT.EXE with the following commands:
  13646.  
  13647.       C>MASM PARENT;  <Enter>
  13648.       C>LINK PARENT;  <Enter>
  13649.  
  13650.       Similarly, CHILD.ASM can be assembled and linked into the file
  13651.       CHILD.EXE as follows:
  13652.  
  13653.       C>MASM CHILD;  <Enter>
  13654.       C>LINK CHILD;  <Enter>
  13655.  
  13656.       When PARENT.EXE is executed with the command
  13657.  
  13658.       C>PARENT  <Enter>
  13659.  
  13660.       PARENT reduces the size of its main memory block with a call to
  13661.       Interrupt 21H Function 4AH, to maximize the amount of free memory in
  13662.       the system, and then calls the EXEC function to load and execute
  13663.       CHILD.EXE.
  13664.  
  13665.       CHILD.EXE runs exactly as though it had been loaded directly by
  13666.       COMMAND.COM. CHILD resets the DS segment register to point to its own
  13667.       data segment, uses Interrupt 21H Function 40H to display a message on
  13668.       standard output, and then terminates using Interrupt 21H Function 4CH,
  13669.       passing a return code of zero.
  13670.  
  13671.       When PARENT.EXE regains control, it first checks the carry flag to
  13672.       determine whether the EXEC call succeeded. If the EXEC call failed,
  13673.       PARENT displays an error message and terminates with Interrupt 21H
  13674.       Function 4CH, itself passing a nonzero return code to COMMAND.COM to
  13675.       indicate an error.
  13676.  
  13677.       Otherwise, PARENT uses Interrupt 21H Function 4DH to obtain
  13678.       CHILD.EXE's termination type and return code, which it converts
  13679.       to ASCII and displays. PARENT then terminates using Interrupt 21H
  13680.       Function 4CH and passes a return code of zero to COMMAND.COM to
  13681.       indicate success. COMMAND.COM in turn receives control and displays
  13682.       a new user prompt.
  13683.  
  13684.  
  13685.  Using EXEC to Load Overlays
  13686.  
  13687.       Loading overlays with the EXEC function is much less complex than
  13688.       using EXEC to run another program. The main program, called the root
  13689.       segment, must carry out the following steps to load and execute an
  13690.       overlay:
  13691.  
  13692.       1. Make a memory block available to receive the overlay.
  13693.  
  13694.       2. Set up the overlay parameter block to be passed to the EXEC
  13695.          function.
  13696.  
  13697.       3. Call the EXEC function to load the overlay.
  13698.  
  13699.       4. Execute the code within the overlay by transferring to it with a
  13700.          far call.
  13701.  
  13702.       The overlay itself can be constructed as either a memory image (.COM)
  13703.       or a relocatable (.EXE) file and need not be the same type as the root
  13704.       program. In either case, the overlay should be designed so that the
  13705.       entry point (or a pointer to the entry point) is at the beginning of
  13706.       the module after it is loaded. This allows the root and overlay mod-
  13707.       ules to be maintained separately and avoids a need for the root
  13708.       to have "magical" knowledge of addresses within the overlay.
  13709.  
  13710.       To prevent users from inadvertently running an overlay directly from
  13711.       the command line, overlay files should be assigned an extension other
  13712.       than .COM or .EXE. The most convenient method relates overlays to
  13713.       their root segment by assigning them the same filename but an
  13714.       extension such as .OVL or .OV1, .OV2, and so on.
  13715.  
  13716.  Making memory available
  13717.  
  13718.       If EXEC is to load a child program successfully, the parent must
  13719.       release memory. In contrast, EXEC loads an overlay into memory that
  13720.       belongs to the calling program. If the root segment is a .COM program
  13721.       and has not explicitly released extra memory, the root segment program
  13722.       need only ensure that the system contains enough memory to load the
  13723.       overlay and that the overlay load address does not conflict with its
  13724.       own code, data, or stack areas.
  13725.  
  13726.       If the root segment program was loaded from a .EXE file, no
  13727.       straightforward way exists for it to determine unequivocally how much
  13728.       memory it already owns. The simplest course is for the program to
  13729.       release all extra memory, as discussed earlier in the section on
  13730.       loading a child program, and then use the MS-DOS memory allocation
  13731.       function (Interrupt 21H Function 48H) to obtain a new block of memory
  13732.       that is large enough to hold the overlay.
  13733.  
  13734.  Preparing overlay parameters
  13735.  
  13736.       When it is used to load an overlay, the EXEC function requires two
  13737.       major parameters:
  13738.  
  13739.       ■  The address of the pathname for the overlay file
  13740.       ■  The address of an overlay parameter block
  13741.  
  13742.       As for a child program, the pathname for the overlay file must be an
  13743.       unambiguous ASCIIZ file specification (again, no wildcard characters),
  13744.       and it must include an explicit extension. As before, if a path and/or
  13745.       drive are not included in the pathname, the current directory and
  13746.       default drive are used.
  13747.  
  13748.       The overlay parameter block contains the segment address at which the
  13749.       overlay should be loaded and a fixup value to be applied to any
  13750.       relocatable items within the overlay file. If the overlay file is in
  13751.       .EXE format, the fixup value is typically the same as the load
  13752.       address; if the overlay is in memory-image (.COM) format, the fixup
  13753.       value should be zero. The EXEC function does not attempt to validate
  13754.       the load address or the fixup value or to ensure that the load address
  13755.       actually belongs to the calling program.
  13756.  
  13757.  Loading and executing the overlay
  13758.  
  13759.       After the root segment program has prepared the filename of the
  13760.       overlay file and the overlay parameter block, it can invoke the EXEC
  13761.       function to load the overlay by issuing an Interrupt 21H with the
  13762.       registers set as follows:
  13763.  
  13764.       AH          = 4BH
  13765.       AL          = 03H (EXEC subfunction to load overlay)
  13766.       DS:DX       = segment:offset of overlay file pathname
  13767.       ES:BX       = segment:offset of overlay parameter block
  13768.  
  13769.       Upon return from Interrupt 21H, the root segment must test the carry
  13770.       flag to determine whether the overlay was loaded. If the carry flag is
  13771.       clear, the overlay file was located and brought into memory at the
  13772.       requested address. The overlay can then be entered by a far call and
  13773.       should exit back to the root segment with a far return.
  13774.  
  13775.       If the carry flag is set, the overlay file was not found or some other
  13776.       (probably severe) system problem was encountered, and the AX register
  13777.       contains an error code. With MS-DOS versions 3.0 and later, Interrupt
  13778.       21H Function 59H can be used to get more information about the EXEC
  13779.       failure. An invalid load address supplied in the overlay parameter
  13780.       block does not (usually) cause the EXEC function itself to fail but
  13781.       may result in the disconcerting message Memory Allocation Error,
  13782.       System Halted when the root program terminates.
  13783.  
  13784.  An overlay example
  13785.  
  13786.       The source programs ROOT.ASM in Figure 10-5 and OVERLAY.ASM in Figure
  13787.       10-6 demonstrate the use of EXEC to load a program overlay. The
  13788.       program ROOT.EXE is executable from the MS-DOS prompt; it represents
  13789.       the root segment of an application. OVERLAY is constructed as a .EXE
  13790.       file (although it is named OVERLAY.OVL because it cannot be run alone)
  13791.       and represents a subprogram that can be loaded by the root segment
  13792.       when and if it is needed.
  13793.  
  13794.       ──────────────────────────────────────────────────────────────────────
  13795.  
  13796.       Figure 10-5. ROOT.ASM, source code for ROOT.EXE.
  13797.  
  13798.       ──────────────────────────────────────────────────────────────────────
  13799.  
  13800.       Figure 10-6. OVERLAY.ASM, source code for OVERLAY.OVL.
  13801.  
  13802.       ──────────────────────────────────────────────────────────────────────
  13803.  
  13804.       ROOT.ASM can be assembled and linked into the executable program
  13805.       ROOT.EXE with the following commands:
  13806.  
  13807.       C>MASM ROOT;  <Enter>
  13808.       C>LINK ROOT;  <Enter>
  13809.  
  13810.       OVERLAY.ASM can be assembled and linked into the file OVERLAY.OVL by
  13811.       typing
  13812.  
  13813.       C>MASM OVERLAY;  <Enter>
  13814.       C>LINK OVERLAY,OVERLAY.OVL;  <Enter>
  13815.  
  13816.       The Microsoft Object Linker will display the message
  13817.  
  13818.       Warning: no stack segment
  13819.  
  13820.       but this message can be ignored.
  13821.  
  13822.       When ROOT.EXE is executed with the command
  13823.  
  13824.       C>ROOT  <Enter>
  13825.  
  13826.       it first shrinks its main memory block with a call to Interrupt 21H
  13827.       Function 4AH and then allocates a separate block for the overlay with
  13828.       Interrupt 21H Function 48H. Next, ROOT calls the EXEC function to load
  13829.       the file OVERLAY.OVL into the newly allocated memory block. If the
  13830.       EXEC function fails, ROOT displays an error message and terminates
  13831.       with Interrupt 21H Function 4CH, passing a nonzero return code to
  13832.       COMMAND.COM to indicate an error. If the EXEC function succeeds, ROOT
  13833.       saves the contents of its DS segment register and then enters the
  13834.       overlay through an indirect far call.
  13835.  
  13836.       The overlay resets the DS segment register to point to its own data
  13837.       segment, displays a message using Interrupt 21H Function 40H, and then
  13838.       returns. Note that the main procedure of the overlay is declared with
  13839.       the far attribute to force the assembler to generate the opcode for a
  13840.       far return.
  13841.  
  13842.       When ROOT regains control, it restores the DS segment register to
  13843.       point to its own data segment again and displays an additional
  13844.       message, also using Interrupt 21H Function 40H, to indicate that the
  13845.       overlay executed successfully. ROOT then terminates using Interrupt
  13846.       21H Function 4CH, passing a return code of zero to indicate success,
  13847.       and control returns to COMMAND.COM.
  13848.  
  13849.                                                    Ray Duncan
  13850.  
  13851.  
  13852.  
  13853.  ───────────────────────────────────────────────────────────────────────────
  13854.  
  13855.  Part C  Customizing MS-DOS
  13856.  
  13857.  
  13858.  
  13859.  Article 11: Terminate-and-Stay-Resident Utilities
  13860.  
  13861.  
  13862.       The MS-DOS Terminate and Stay Resident system calls (Interrupt 21H
  13863.       Function 31H and Interrupt 27H) allow the programmer to install
  13864.       executable code or program data in a reserved block of RAM, where it
  13865.       resides while other programs execute. Global data, interrupt handlers,
  13866.       and entire applications can be made RAM-resident in this way. Programs
  13867.       that use the MS-DOS terminate-and-stay-resident capability are
  13868.       commonly known as TSR programs or TSRs.
  13869.  
  13870.       This article describes how to install a TSR in RAM, how to communicate
  13871.       with the resident program, and how the resident program can interact
  13872.       with MS-DOS. The discussion proceeds from a general description of the
  13873.       MS-DOS functions useful to TSR programmers to specific details about
  13874.       certain MS-DOS structural elements necessary to proper functioning of
  13875.       a TSR utility and concludes with two programming examples.
  13876.  
  13877.       Note: Microsoft cannot guarantee that the information in this article
  13878.       will be valid for future versions of MS-DOS.
  13879.  
  13880.  
  13881.  Structure of a Terminate-and-Stay-Resident Utility
  13882.  
  13883.       The executable code and data in TSRs can be separated into RAM-
  13884.       resident and transient portions (Figure 11-1). The RAM-resident
  13885.       portion of a TSR contains executable code and data for an application
  13886.       that performs some useful function on demand. The transient portion
  13887.       installs the TSR; that is, it initializes data and interrupt handlers
  13888.       contained in the RAM-resident portion of the program and executes an
  13889.       MS-DOS Terminate and Stay Resident function call that leaves the RAM-
  13890.       resident portion in memory and frees the memory used by the transient
  13891.       portion. The code in the transient portion of a TSR runs when the .EXE
  13892.       or .COM file containing the program is executed; the code in the RAM-
  13893.       resident portion runs only when it is explicitly invoked by a fore-
  13894.       ground program or by execution of a hardware or software interrupt.
  13895.  
  13896.  
  13897.       Higher addresses ┌───────────────────────────┐
  13898.                        │                           │▒
  13899.                        │Initialization code & data │▒─ Transient portion
  13900.                        │                           │▒   (executed when
  13901.                        ├───────────────────────────┤    .EXE file runs)
  13902.                        │                           │▒
  13903.                        │  Application code & data  │▒
  13904.                        │                           │▒
  13905.                        ├───────────────────────────┤▒─ RAM-resident portion
  13906.                        │                           │▒
  13907.                        │     Monitor routines      │▒
  13908.                        │                           │▒
  13909.                        ├───────────────────────────┤
  13910.                        │  Program segment prefix   │
  13911.        Lower addresses └───────────────────────────┘
  13912.  
  13913.       Figure 11-1. Organization of a TSR program in memory.
  13914.  
  13915.  
  13916.       TSRs can be broadly classified as passive or active, depending on the
  13917.       method by which control is transferred to the RAM-resident program. A
  13918.       passive TSR executes only when another program explicitly transfers
  13919.       control to it, either through a software interrupt or by means of a
  13920.       long JMP or CALL. The calling program is not interrupted by the TSR,
  13921.       so the status of MS-DOS, the system BIOS, and the hardware is well
  13922.       defined when the TSR program starts to execute.
  13923.  
  13924.       In contrast, an active TSR is invoked by the occurrence of some event
  13925.       external to the currently running (foreground) program, such as a
  13926.       sequence of user keystrokes or a predefined hardware interrupt.
  13927.       Therefore, when it is invoked, an active TSR almost always
  13928.       interrupts some other program and suspends its execution. To avoid
  13929.       disrupting the interrupted program, an active TSR must monitor the
  13930.       status of MS-DOS, the ROM BIOS, and the hardware and take control of
  13931.       the system only when it is safe to do so.
  13932.  
  13933.       Passive TSRs are generally simpler in their construction than active
  13934.       TSRs because a passive TSR runs in the context of the calling program;
  13935.       that is, when the TSR executes, it assumes that it can use the calling
  13936.       program's program segment prefix (PSP), open files, current directory,
  13937.       and so on. See PROGRAMMING IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR
  13938.       MS-DOS: Structure of an Application Program. It is the calling
  13939.       program's responsibility to ensure that the hardware and MS-DOS are in
  13940.       a stable state before it transfers control to a passive TSR.
  13941.  
  13942.       An active TSR, on the other hand, is invoked asynchronously; that is,
  13943.       the status of the hardware, MS-DOS, and the executing foreground
  13944.       program is indeterminate when the event that invokes the TSR occurs.
  13945.       Therefore, active TSRs require more complex code. The RAM-resident
  13946.       portion of an active TSR must contain modules that monitor the
  13947.       operating system to determine when control can safely be transferred
  13948.       to the application portion of the TSR. The monitor routines typically
  13949.       test the status of keyboard input, ROM BIOS interrupt processing,
  13950.       hardware interrupt processing, and MS-DOS function processing. The TSR
  13951.       activates the application (the part of the RAM-resident portion that
  13952.       performs the TSR's main task) only when it detects the appropriate
  13953.       keyboard input and determines that the application will not interfere
  13954.       with interrupt and MS-DOS function processing.
  13955.  
  13956.  Keyboard input
  13957.  
  13958.       An active TSR usually contains a RAM-resident module that examines
  13959.       keyboard input for a predetermined keystroke sequence called a "hot-
  13960.       key" sequence. A user executes the RAM-resident application by
  13961.       entering this hot-key sequence at the keyboard.
  13962.  
  13963.       The technique used in the TSR to monitor keyboard input depends on the
  13964.       keyboard hardware implementation. On computers in the IBM PC and PS/2
  13965.       families, the keyboard coprocessor generates an Interrupt 09H for each
  13966.       keypress. Therefore, a TSR can monitor user keystrokes by installing
  13967.       an interrupt handler (interrupt service routine, or ISR) for Interrupt
  13968.       09H. This handler can thus detect a specified hot-key sequence.
  13969.  
  13970.  ROM BIOS interrupt processing
  13971.  
  13972.       The ROM BIOS routines in IBM PCs and PS/2s are not reentrant. An
  13973.       active TSR that calls the ROM BIOS must ensure that its code does not
  13974.       attempt to execute a ROM BIOS function that was already being executed
  13975.       by the foreground process when the TSR program took control of the
  13976.       system.
  13977.  
  13978.       The IBM ROM BIOS routines are invoked through software interrupts, so
  13979.       an active TSR can monitor the status of the ROM BIOS by replacing the
  13980.       default interrupt handlers with custom interrupt handlers that
  13981.       intercept the appropriate BIOS interrupts. Each of these interrupt
  13982.       handlers can maintain a status flag, which it increments before
  13983.       transferring control to the corresponding ROM BIOS routine and
  13984.       decrements when the ROM BIOS routine has finished executing. Thus, the
  13985.       TSR monitor routines can test these flags to determine when non-
  13986.       reentrant BIOS routines are executing.
  13987.  
  13988.  Hardware interrupt processing
  13989.  
  13990.       The monitor routines of an active TSR, which may themselves be
  13991.       executed as the result of a hardware interrupt, should not activate
  13992.       the application portion of the TSR if any other hardware interrupt is
  13993.       being processed. On IBM PCs, for example, hardware interrupts are
  13994.       processed in a prioritized sequence determined by an Intel 8259A
  13995.       Programmable Interrupt Controller. The 8259A does not allow a hardware
  13996.       interrupt to execute if a previous interrupt with the same or higher
  13997.       priority is being serviced. All hardware interrupt handlers include
  13998.       code that signals the 8259A when interrupt processing is completed.
  13999.       (The programming interface to the 8259A is described in IBM's
  14000.       Technical Reference manuals and in Intel's technical literature.)
  14001.  
  14002.       If a TSR were to interrupt the execution of another hardware interrupt
  14003.       handler before the handler signaled the 8259A that it had completed
  14004.       its interrupt servicing, subsequent hardware interrupts could be
  14005.       inhibited indefinitely. Inhibition of high-priority hardware
  14006.       interrupts such as the timer tick (Interrupt 08H) or keyboard
  14007.       interrupt (Interrupt 09H) could cause a system crash. For this reason,
  14008.       an active TSR must monitor the status of all hardware interrupt
  14009.       processing by interrogating the 8259A to ensure that control is
  14010.       transferred to the RAM-resident application only when no other
  14011.       hardware interrupts are being serviced.
  14012.  
  14013.  MS-DOS function processing
  14014.  
  14015.       Unlike the IBM ROM BIOS routines, MS-DOS is reentrant to a limited
  14016.       extent. That is, there are certain times when MS-DOS's servicing of an
  14017.       Interrupt 21H function call invoked by a foreground process can be
  14018.       suspended so that the RAM-resident application can make an Interrupt
  14019.       21H function call of its own. For this reason, an active TSR must
  14020.       monitor operating system activity to determine when it is safe for the
  14021.       TSR application to make its calls to MS-DOS.
  14022.  
  14023.  MS-DOS Support for Terminate-and-Stay-Resident Programs
  14024.  
  14025.       Several MS-DOS system calls are useful for supporting terminate-and-
  14026.       stay-resident utilities. These are listed in Table 11-1. See SYSTEM
  14027.       CALLS.
  14028.  
  14029.  
  14030.       Table 11-1. MS-DOS Functions Useful in TSR Programs.
  14031.  
  14032. ╓┌─────────────────────┌─────────────────────┌───────────────┌───────────────╖
  14033.       Function Name    Call With             Returns         Comment
  14034.       ──────────────────────────────────────────────────────────────────
  14035.       Terminate and    AH = 31H              Nothing         Preferred over
  14036.       Stay Resident    AL = return code                        Interrupt 27H
  14037.                        DX = size of resident                   with MS-DOS
  14038.                          program (in 16-byte                   versions 2.x
  14039.                          paragraphs)                           and later
  14040.                        INT 21H
  14041.  
  14042.       Terminate and    CS = PSP              Nothing         Provided for
  14043.       Stay Resident    DX = size of resident                   compatibility
  14044.                          program (bytes)                       with MS-DOS
  14045.                                                                versions 1.x
  14046.                        INT 27H
  14047.  
  14048.       Set Interrupt    AH = 25H              Nothing
  14049.       Vector           AL = interrupt number
  14050.                        DS:DX = address of
  14051.       Function Name    Call With             Returns         Comment
  14052.                       DS:DX = address of
  14053.                          interrupt handler
  14054.                        INT 21H
  14055.  
  14056.       Get Interrupt    AH = 35H              ES:BX = address
  14057.       Vector           AL = interrupt number   of interrupt
  14058.                        INT 21H                 handler
  14059.  
  14060.       Set PSP Address  AH = 50H              Nothing
  14061.                        BX = PSP segment
  14062.                        INT 21H
  14063.  
  14064.       Get PSP Address  AH = 51H              BX = PSP segment
  14065.                        INT 21H
  14066.  
  14067.       Set Extended     AX = 5D0AH            Nothing         MS-DOS versions
  14068.       Error            DS:DX = address of 11-                  3.1 and
  14069.       Information        word data structure:                  later
  14070.                          word 0: register AX
  14071.                            as returned by
  14072.       Function Name    Call With             Returns         Comment
  14073.                           as returned by
  14074.                            Function 59H
  14075.                          word 1: register BX
  14076.                          word 2: register CX
  14077.                          word 3: register DX
  14078.                          word 4: register SI
  14079.                          word 5: register DI
  14080.                          word 6: register DS
  14081.                          word 7: register ES
  14082.                          words 8-0AH: reserved;
  14083.                            should be 0
  14084.                        INT 21H
  14085.  
  14086.       Get Extended     AH = 59H              AX = extended
  14087.       Error            BX = 0                  error code
  14088.       Information      INT 21H               BH = error class
  14089.                                              BL = suggested
  14090.                                                action
  14091.                                              CH = error locus
  14092.  
  14093.       Function Name    Call With             Returns         Comment
  14094. 
  14095.       Set Disk         AH = 1AH              Nothing
  14096.       Transfer Area    DS:DX = address
  14097.       Address            of DTA
  14098.  
  14099.       Get Disk         AH = 2FH              ES:BX = address
  14100.       Transfer Area    INT 21H                 of current DTA
  14101.       Address
  14102.  
  14103.       Get InDOS Flag   AH = 34H              ES:BX = address
  14104.       Address          INT 21H                 of InDOS flag
  14105.  
  14106.  
  14107.  Terminate-and-stay-resident functions
  14108.  
  14109.       MS-DOS provides two mechanisms for terminating the execution of a
  14110.       program while leaving a portion of it resident in RAM. The preferred
  14111.       method is to execute Interrupt 21H Function 31H.
  14112.  
  14113.  Interrupt 21H Function 31H
  14114.       When this Interrupt 21H function is called, the value in DX specifies
  14115.       the amount of RAM (in paragraphs) that is to remain allocated after
  14116.       the program terminates, starting at the program segment prefix (PSP).
  14117.       The function is similar to Function 4CH (Terminate Process with Return
  14118.       Code) in that it passes a return code in AL, but it differs in that
  14119.       open files are not automatically closed by Function 31H.
  14120.  
  14121.  Interrupt 27H
  14122.       When Interrupt 27H is executed, the value passed in DX specifies the
  14123.       number of bytes of memory required for the RAM-resident program. MS-
  14124.       DOS converts the value passed in DX from bytes to paragraphs, sets AL
  14125.       to zero, and jumps to the same code that would be executed for
  14126.       Interrupt 21H Function 31H. Interrupt 27H is less flexible than
  14127.       Interrupt 21H Function 31H because it limits the size of the program
  14128.       that can remain resident in RAM to 64 KB, it requires that CS point to
  14129.       the base of the PSP, and it does not pass a return code. Later
  14130.       versions of MS-DOS support Interrupt 27H primarily for compatibility
  14131.       with versions 1.x.
  14132.  
  14133.  TSR RAM management
  14134.       In addition to the RAM explicitly allocated to the TSR by means of the
  14135.       value in DX, the RAM allocated to the TSR's environment remains
  14136.       resident when the installation portion of the TSR program terminates.
  14137.       (The paragraph address of the environment is found at offset 2CH in
  14138.       the TSR's PSP.) Moreover, if the installation portion of a TSR program
  14139.       has used Interrupt 21H Function 48H (Allocate Memory Block) to
  14140.       allocate additional RAM, this memory also remains allocated when the
  14141.       program terminates. If the RAM-resident program does not need this
  14142.       additional RAM, the installation portion of the TSR program should
  14143.       free it explicitly by using Interrupt 21H Function 49H (Free Memory
  14144.       Block) before executing Interrupt 21H Function 31H.
  14145.  
  14146.  Set and Get Interrupt Vector functions
  14147.  
  14148.       Two Interrupt 21H function calls are available to inspect or update
  14149.       the contents of a specified 8086-family interrupt vector. Function 25H
  14150.       (Set Interrupt Vector) updates the vector of the interrupt number
  14151.       specified in the AL register with the segment and offset values
  14152.       specified in DS:DX. Function 35H (Get Interrupt Vector) performs the
  14153.       inverse operation: It copies the current vector of the interrupt
  14154.       number specified in AL into the ES:BX register pair.
  14155.  
  14156.       Although it is possible to manipulate interrupt vectors directly, the
  14157.       use of Interrupt 21H Functions 25H and 35H is generally more
  14158.       convenient and allows for upward compatibility with future versions of
  14159.       MS-DOS.
  14160.  
  14161.  Set and Get PSP Address functions
  14162.  
  14163.       MS-DOS uses a program's PSP to keep track of certain data unique to
  14164.       the program, including command-line parameters and the segment address
  14165.       of the program's environment. See PROGRAMMING IN THE MS-DOS
  14166.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: Structure of an Application
  14167.       Program. To access this information, MS-DOS maintains an internal
  14168.       variable that always contains the location of the PSP associated with
  14169.       the foreground process. When a RAM-resident application is activated,
  14170.       it should use Interrupt 21H Functions 50H (Set Program Segment Prefix
  14171.       Address) and 51H (Get Program Segment Prefix Address) to preserve the
  14172.       current contents of this variable and to update the variable with the
  14173.       location of its own PSP. Function 50H (Set Program Segment Prefix
  14174.       Address) updates an internal MS-DOS variable that locates the PSP
  14175.       currently in use by the foreground process. Function 51H (Get Program
  14176.       Segment Prefix Address) returns the contents of the internal MS-DOS
  14177.       variable to the caller.
  14178.  
  14179.  Set and Get Extended Error Information functions
  14180.  
  14181.       In MS-DOS versions 3.1 and later, the RAM-resident program should
  14182.       preserve the foreground process's extended error information so that,
  14183.       if the RAM-resident application encounters an MS-DOS error, the
  14184.       extended error information pertaining to the foreground process will
  14185.       still be available and can be restored. Interrupt 21H Functions 59H
  14186.       and 5D0AH provide a mechanism for the RAM-resident program to save and
  14187.       restore this information during execution of a TSR application.
  14188.  
  14189.       Function 59H (Get Extended Error Information), which became available
  14190.       in version 3.0, returns detailed information on the most recently
  14191.       detected MS-DOS error. The inverse operation is performed by Function
  14192.       5D0AH (Set Extended Error Information), which can be used only in
  14193.       MS-DOS versions 3.1 and later. This function copies extended error
  14194.       information to MS-DOS from a data structure defined in the calling
  14195.       program.
  14196.  
  14197.  Set and Get Disk Transfer Area Address functions
  14198.  
  14199.       Several MS-DOS data transfer functions, notably Interrupt 21H
  14200.       Functions 21H, 22H, 27H, and 28H (the Random Read and Write functions)
  14201.       and Interrupt 21H Functions 14H and 15H (the Sequential Read and Write
  14202.       functions), require a program to specify a disk transfer area (DTA).
  14203.       By default, a program's DTA is located at offset 80H in its program
  14204.       segment prefix. If a RAM-resident application calls an MS-DOS function
  14205.       that uses a DTA, the TSR should save the DTA address belonging to the
  14206.       interrupted program by using Interrupt 21H Function 2FH (Get Disk
  14207.       Transfer Area Address), supply its own DTA address to MS-DOS using
  14208.       Interrupt 21H Function 1AH (Set Disk Transfer Area Address), and then,
  14209.       before terminating, restore the interrupted program's DTA.
  14210.  
  14211.  The MS-DOS idle interrupt (Interrupt 28H)
  14212.  
  14213.       Several of the first 12 MS-DOS functions (01H through 0CH) must wait
  14214.       for the occurrence of an expected event such as a user keypress. These
  14215.       functions contain an "idle loop" in which looping continues until the
  14216.       event occurs. To provide a mechanism for other system activity to take
  14217.       place while the idle loop is executing, these MS-DOS functions execute
  14218.       an Interrupt 28H from within the loop.
  14219.  
  14220.       The default MS-DOS handler for Interrupt 28H is only an IRET
  14221.       instruction. By supplying its own handler for Interrupt 28H, a TSR can
  14222.       perform some useful action at times when MS-DOS is otherwise idle.
  14223.       Specifically, a custom Interrupt 28H handler can be used to examine
  14224.       the current status of the system to determine whether or not it is
  14225.       safe to activate the RAM-resident application.
  14226.  
  14227.  
  14228.  Determining MS-DOS Status
  14229.  
  14230.       A TSR can infer the current status of MS-DOS from knowledge of its
  14231.       internal use of stacks and from a pair of internal status flags. This
  14232.       status information is essential to the proper execution of an active
  14233.       TSR because a RAM-resident application can make calls to MS-DOS only
  14234.       when those calls will not disrupt an earlier call made by the
  14235.       foreground process.
  14236.  
  14237.  MS-DOS internal stacks
  14238.  
  14239.       MS-DOS versions 2.0 and later may use any of three internal stacks:
  14240.       the I/O stack (IOStack), the disk stack (DiskStack), and the auxiliary
  14241.       stack (AuxStack). In general, IOStack is used for Interrupt 21H
  14242.       Functions 01H through 0CH and DiskStack is used for the remaining
  14243.       Interrupt 21H functions; AuxStack is normally used only when MS-DOS
  14244.       has detected a critical error and subsequently executed an Interrupt
  14245.       24H. See PROGRAMMING IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS:
  14246.       Exception Handlers. Specifically, MS-DOS's internal stack use depends
  14247.       on which MS-DOS function is being executed and on the value of the
  14248.       critical error flag.
  14249.  
  14250.  The critical error flag
  14251.  
  14252.       The critical error flag (ErrorMode) is a 1-byte flag that MS-DOS uses
  14253.       to indicate whether or not a critical error has occurred. During
  14254.       normal, errorless execution, the value of the critical error flag
  14255.       is zero. Whenever MS-DOS detects a critical error, it sets this flag
  14256.       to a nonzero value before it executes Interrupt 24H. If an Interrupt
  14257.       24H handler subsequently invokes an MS-DOS function by using Interrupt
  14258.       21H, the nonzero value of the critical error flag tells MS-DOS to use
  14259.       its auxiliary stack for Interrupt 21H Functions 01H through 0CH
  14260.       instead of using the I/O stack as it normally would.
  14261.  
  14262.       In other words, when control is transferred to MS-DOS through
  14263.       Interrupt 21H, the function number and the critical error flag
  14264.       together determine MS-DOS stack use for the function. Figure 11-2
  14265.       outlines the internal logic used on entry to an MS-DOS function to
  14266.       select which stack is to be used during processing of the function.
  14267.       AS stated above, for Functions 01H through 0CH, MS-DOS uses IOStack if
  14268.       the critical error flag is zero and AuxStack if the flag is nonzero.
  14269.       For function numbers greater than 0CH, MS-DOS usually uses DiskStack,
  14270.       but Functions 50H, 51H, and 59H are important exceptions. Functions
  14271.       50H and 51H use either IOStack (in versions 2.x) or the stack supplied
  14272.       by the calling program (in versions 3.x). In version 3.0, Function 59H
  14273.       uses either IOStack or AuxStack, depending on the value of the
  14274.       critical error flag, but in versions 3.1 and later, Function 59H
  14275.       always uses AuxStack.
  14276.  
  14277.  
  14278.       MS-DOS versions 2.x
  14279.  
  14280.       if   (FunctionNumber >= 01H and FunctionNumber <= 0CH)
  14281.            or
  14282.            FunctionNumber = 50H
  14283.            or
  14284.            FunctionNumber = 51H
  14285.  
  14286.       then if   ErrorMode = 0
  14287.            then use IOStack
  14288.            else use AuxStack
  14289.  
  14290.       else ErrorMode = 0
  14291.            use DiskStack
  14292.  
  14293.       MS-DOS version 3.0
  14294.  
  14295.       if   FunctionNumber = 50H
  14296.            or
  14297.            FunctionNumber = 51H
  14298.            or
  14299.            FunctionNumber = 62H
  14300.  
  14301.       then use caller's stack
  14302.  
  14303.       else if   (FunctionNumber >= 01H and FunctionNumber <= 0CH)
  14304.                 or
  14305.                 Function Number = 59H
  14306.  
  14307.            then if   ErrorMode = 0
  14308.                 then use IOStack
  14309.                 else use AuxStack
  14310.  
  14311.            else ErrorMode = 0
  14312.                 use DiskStack
  14313.  
  14314.       MS-DOS versions 3.1 and later
  14315.  
  14316.       if   FunctionNumber = 33H
  14317.            or
  14318.            FunctionNumber = 50H
  14319.            or
  14320.            FunctionNumber = 51H
  14321.            or
  14322.            FunctionNumber = 62H
  14323.  
  14324.       then use caller's stack
  14325.  
  14326.       else if   (FunctionNumber >= 01H and FunctionNumber <= 0CH)
  14327.  
  14328.            then if   ErrorMode = 0
  14329.                 then use IOStack
  14330.                 else use AuxStack
  14331.  
  14332.            else if   FunctionNumber = 59H
  14333.                 then use AuxStack
  14334.                 else ErrorMode = 0
  14335.                      use DiskStack
  14336.  
  14337.       Figure 11-2. Strategy for use of MS-DOS internal stacks.
  14338.  
  14339.  
  14340.       This scheme makes Functions 01H through 0CH reentrant in a limited
  14341.       sense, in that a substitute critical error (Interrupt 24H) handler
  14342.       invoked while the critical error flag is nonzero can still use these
  14343.       Interrupt 21H functions. In this situation, because the flag is
  14344.       nonzero, AuxStack is used for Functions 01H through 0CH instead of
  14345.       IOStack. Thus, if IOStack is in use when the critical error is
  14346.       detected, its contents are preserved during the handler's subsequent
  14347.       calls to these functions.
  14348.  
  14349.       The stack-selection logic differs slightly between MS-DOS versions 2
  14350.       and 3. In versions 3.x, a few functions--notably 50H and 51H--avoid
  14351.       using any of the MS-DOS stacks. These functions perform uncomplicated
  14352.       tasks that make minimal demands for stack space, so the calling
  14353.       program's stack is assumed to be adequate for them.
  14354.  
  14355.  The InDOS flag
  14356.  
  14357.       InDOS is a 1-byte flag that is incremented each time an Interrupt 21H
  14358.       function is invoked and decremented when the function terminates. The
  14359.       flag's value remains nonzero as long as code within MS-DOS is being
  14360.       executed. The value of InDOS does not indicate which internal stack
  14361.       MS-DOS is using.
  14362.  
  14363.       Whenever MS-DOS detects a critical error, it zeros InDOS before it
  14364.       executes Interrupt 24H. This action is taken to accommodate substitute
  14365.       Interrupt 24H handlers that do not return control to MS-DOS. If InDOS
  14366.       were not zeroed before such a handler gained control, its value would
  14367.       never be decremented and would therefore be incorrect during
  14368.       subsequent calls to MS-DOS.
  14369.  
  14370.       The address of the 1-byte InDOS flag can be obtained from MS-DOS by
  14371.       using Interrupt 21H Function 34H (Return Address of InDOS Flag). In
  14372.       versions 3.1 and later, the 1-byte critical error flag is located in
  14373.       the byte preceding InDOS, so, in effect, the address of both flags can
  14374.       be found using Function 34H. Unfortunately, there is no easy way to
  14375.       find the critical error flag in other versions. The recommended
  14376.       technique is to scan the MS-DOS segment, which is returned in the ES
  14377.       register by Function 34H, for one of the following sequences of
  14378.       instructions:
  14379.  
  14380.               test    ss:[CriticalErrorFlag],0FFH      ;(versions 3.1 and
  14381.                                                        ;later)
  14382.               jne     NearLabel
  14383.               push    ss:[NearWord]
  14384.               int     28H
  14385.  
  14386.       or
  14387.  
  14388.               cmp     ss:[CriticalErrorFlag],00        ;(versions earlier
  14389.                                                        ;than 3.1)
  14390.               jne     NearLabel
  14391.               int     28H
  14392.  
  14393.       When the TEST or CMP instruction has been identified, the offset of
  14394.       the critical error flag can be obtained from the instruction's operand
  14395.       field.
  14396.  
  14397.  
  14398.  The Multiplex Interrupt
  14399.  
  14400.       The MS-DOS multiplex interrupt (Interrupt 2FH) provides a general
  14401.       mechanism for a program to verify the presence of a TSR and
  14402.       communicate with it. A program communicates with a TSR by placing an
  14403.       identification value in AH and a function number in AL and issuing an
  14404.       Interrupt 2FH. The TSR's Interrupt 2FH handler compares the value in
  14405.       AH to its own predetermined ID value. If they match, the TSR's handler
  14406.       keeps control and performs the function specified in the AL register.
  14407.       If they do not match, the TSR's handler relinquishes control to the
  14408.       previously installed Interrupt 2FH handler. (Multiplex ID values 00H
  14409.       through 7FH are reserved for use by MS-DOS; therefore, user multiplex
  14410.       numbers should be in the range 80H through 0FFH.)
  14411.  
  14412.       The handler in the following example recognizes only one function,
  14413.       corresponding to AL = 00H. In this case, the handler returns the value
  14414.       0FFH in AL, signifying that the handler is indeed resident in RAM.
  14415.       Thus, a program can detect the presence of the handler by executing
  14416.       Interrupt 2FH with the handler's ID value in H and 00H in AL.
  14417.  
  14418.               mov     ah,MultiplexID
  14419.               mov     al,00H
  14420.               int     2FH
  14421.               cmp     al,0FFH
  14422.               je      AlreadyInstalled
  14423.  
  14424.       To ensure that the identification byte is unique, its value should be
  14425.       determined at the time the TSR is installed. One way to do this is to
  14426.       pass the value to the TSR program as a command-line parameter when the
  14427.       TSR program is installed. Another approach is to place the
  14428.       identification value in an environment variable. In this way, the
  14429.       value can be found in the environment of both the TSR and any other
  14430.       program that calls Interrupt 2FH to verify the TSR's presence.
  14431.  
  14432.       In practice, the multiplex interrupt can also be used to pass
  14433.       information to and from a RAM-resident program in the CPU registers,
  14434.       thus providing a mechanism for a program to share control or status
  14435.       information with a TSR.
  14436.  
  14437.  
  14438.  TSR Programming Examples
  14439.  
  14440.       One effective way to become familiar with TSRs is to examine
  14441.       functional programs. Therefore, the subsequent pages present two
  14442.       examples: a simple passive TSR and a more complex active TSR.
  14443.  
  14444.  HELLO.ASM
  14445.  
  14446.       The "bare-bones" TSR in Figure 11-3 is a passive TSR. The RAM-resident
  14447.       application, which simply displays the message Hello, World, is
  14448.       invoked by executing a software interrupt. This example illustrates
  14449.       the fundamental interactions among a RAM-resident program, MS-DOS, and
  14450.       programs that execute after the installation of the RAM-resident
  14451.       utility.
  14452.  
  14453.       ──────────────────────────────────────────────────────────────────────
  14454.  
  14455.       Figure 11-3. HELLO.ASM, a passive TSR.
  14456.  
  14457.       ──────────────────────────────────────────────────────────────────────
  14458.  
  14459.       The transient portion of the program (in the segments TRANSIENT_TEXT
  14460.       and TRANSIENT_STACK) runs only when the file HELLO.EXE is executed.
  14461.       This installation code updates an interrupt vector to point to the
  14462.       resident application (the procedure TSRAction) and then calls
  14463.       Interrupt 21H Function 31H to terminate execution, leaving the
  14464.       segments RESIDENT_TEXT and RESIDENT_DATA in RAM.
  14465.  
  14466.       The order in which the code and data segments appear in the listing is
  14467.       important. It ensures that when the program is executed as a .EXE
  14468.       file, the resident code and data are placed in memory at lower
  14469.       addresses than the transient code and data. Thus, when Interrupt 21H
  14470.       Function 31H is called, the memory occupied by the transient portion
  14471.       of the program is freed without disrupting the code and data in the
  14472.       resident portion.
  14473.  
  14474.       The RAM containing the resident portion of the utility is left intact
  14475.       by MS-DOS during subsequent execution of other programs. Thus, after
  14476.       the TSR has been installed, any program that issues the software
  14477.       interrupt recognized by the TSR (in this example, Interrupt 64H) will
  14478.       transfer control to the routine TSRAction, which uses Interrupt 21H
  14479.       Function 40H to display a simple message on standard output.
  14480.  
  14481.       Part of the reason this example is so short is that it performs no
  14482.       error checking. A truly reliable version of the program would check
  14483.       the version of MS-DOS in use, verify that the program was not already
  14484.       installed in memory, and chain to any previously installed interrupt
  14485.       handlers that use the same interrupt vector. (The next program,
  14486.       SNAP.ASM, illustrates these techniques.)  However, the primary reason
  14487.       the program is small is that it makes the basic assumption that MS-
  14488.       DOS, the ROM BIOS, and the hardware interrupts are all stable at the
  14489.       time the resident utility is executed.
  14490.  
  14491.  SNAP.ASM
  14492.  
  14493.       The preceding assumption is a reliable one in the case of the passive
  14494.       TSR in Figure 11-3, which executes only when it is explicitly invoked
  14495.       by a software interrupt. However, the situation is much more
  14496.       complicated in the case of the active TSR in Figure 11-4. This program
  14497.       is relatively long because it makes no assumptions about the stability
  14498.       of the operating environment. Instead, it monitors the status of
  14499.       MS-DOS, the ROM BIOS, and the hardware interrupts to decide when the
  14500.       RAM-resident application can safely execute.
  14501.  
  14502.       ──────────────────────────────────────────────────────────────────────
  14503.  
  14504.  
  14505.       Figure 11-4. SNAP.ASM, a video snapshot TSR.
  14506.  
  14507.       ──────────────────────────────────────────────────────────────────────
  14508.  
  14509.       When installed, the SNAP program monitors keyboard input until the
  14510.       user types the hot-key sequence Alt-Enter. When the hot-key sequence
  14511.       is detected, the monitoring routine waits until the operating
  14512.       environment is stable and then activates the RAM-resident application,
  14513.       which dumps the current contents of the computer's video buffer into
  14514.       the file SNAP.IMG. Figure 11-5 is a block diagram of the RAM-resident
  14515.       and transient components of this TSR.
  14516.  
  14517.  
  14518.  Higher addresses ┌─────────────────────────────┐
  14519.                   │       Transient data        │ TRANSIENT _DATA segment
  14520.                   ├─────────────────────────────┤
  14521.                   │       InstallSnapTSR        │ TRANSIENT _TEXT segment
  14522.                   │ Initialization code & data  │
  14523.                   ├─────────────────────────────┤
  14524.                   │     RAM-resident stack      │ RESIDENT _STACK segment
  14525.                   ├─────────────────────────────┤
  14526.                   │      RAM-resident data      │ RESIDENT _DATA segment
  14527.                   ├─────────────────────────────┤
  14528.                   │           TSRapp            │▒
  14529.                   │  RAM-resident application   │▒
  14530.                   ├─────────────────────────────┤▒
  14531.                   │       ISR2F$--INT 2FH       │▒
  14532.                   │(multiplex interrupt) handler│▒
  14533.                   ├─────────────────────────────┤▒
  14534.                   │       ISR28--INT 28H        │▒
  14535.                   │(DOS idle interrupt) handler │▒
  14536.                   ├─────────────────────────────┤▒
  14537.                   │       ISR24--INT 24H        │▒
  14538.                   │  (critical error) handler   │▒
  14539.                   ├─────────────────────────────┤▒
  14540.                   │       ISR23--INT 23H        │▒
  14541.  Middle addresses │     (Control-C) handler     │▒ RESIDENT _TEXT segment
  14542.                   ├─────────────────────────────┤▒
  14543.                   │       ISR1B--INT 1BH        │▒
  14544.                   │   (Control-Break) handler   │▒
  14545.                   ├─────────────────────────────┤▒
  14546.                   │       ISR13--INT 13H        │▒
  14547.                   │(BIOS fixed-disk I/O) handler│▒
  14548.                   ├─────────────────────────────┤▒
  14549.                   │       ISR10--INT 10H        │▒
  14550.                   │  (BIOS video I/O) handler   │▒
  14551.                   ├─────────────────────────────┤▒
  14552.                   │        ISR9--INT 09H        │▒
  14553.                   │(keyboard interrupt) handler │▒
  14554.                   ├─────────────────────────────┤▒
  14555.                   │        ISR8--INT 08H        │▒
  14556.                   │  (timer interrupt) handler  │▒
  14557.                   ├─────────────────────────────┤▒
  14558.                   │        ISR5--INT 05H        │▒
  14559.                   │ (BIOS print screen) handler │▒
  14560.   Lower addresses └─────────────────────────────┘
  14561.  
  14562.       Figure 11-5. Block structure of the TSR program SNAP.EXE when loaded
  14563.       into memory. (Compare with Figure 11-1.)
  14564.  
  14565.  
  14566.  Installing the program
  14567.       When SNAP.EXE is run, only the code in the transient portion of the
  14568.       program is executed. The transient code performs several operations
  14569.       before it finally executes Interrupt 21H Function 31H (Terminate and
  14570.       Stay Resident). First it determines which MS-DOS version is in use.
  14571.       Then it executes the multiplex interrupt (Interrupt 2FH) to discover
  14572.       whether the resident portion has already been installed. If an MS-DOS
  14573.       version earlier than 2.0 is in use or if the resident portion has
  14574.       already been installed, the program aborts with an error message.
  14575.  
  14576.       Otherwise, installation continues. The addresses of the InDOS and
  14577.       critical error flags are saved in the resident data segment. The
  14578.       interrupt service routines in the RAM-resident portion of the program
  14579.       are installed by updating all relevant interrupt vectors. The
  14580.       transient code then frees the RAM occupied by the program's
  14581.       environment, because the resident portion of this program never uses
  14582.       the information contained there. Finally, the transient portion of the
  14583.       program, which includes the TRANSIENT_TEXT and TRANSIENT_DATA
  14584.       segments, is discarded and the program is terminated using Interrupt
  14585.       21H Function 31H.
  14586.  
  14587.  Detecting a hot key
  14588.       The SNAP program detects the hot-key sequence (Alt-Enter) by
  14589.       monitoring each keypress. On IBM PCs and PS/2s, each keystroke
  14590.       generates a hardware interrupt on IRQ1 (Interrupt 09H). The TSR's
  14591.       Interrupt 09H handler compares the keyboard scan code corresponding to
  14592.       each keypress with a predefined sequence. The TSR's handler also
  14593.       inspects the shift-key status flags maintained by the ROM BIOS
  14594.       Interrupt 09H handler. When the predetermined sequence of keypresses
  14595.       is detected at the same time as the proper shift keys are pressed, the
  14596.       handler sets a global status flag (HotFlag).
  14597.  
  14598.       Note how the TSR's handler transfers control to the previous Interrupt
  14599.       09H ISR before it performs its own work. If the TSR's Interrupt 09H
  14600.       handler did not chain to the previous handler(s), essential system
  14601.       processing of keystrokes (particularly in the ROM BIOS Interrupt 09H
  14602.       handler) might not be performed.
  14603.  
  14604.  Activating the application
  14605.       The TSR monitors the status of HotFlag by regularly testing its value
  14606.       within a timer-tick handler. On IBM PCs and PS/2s, the timer-tick
  14607.       interrupt occurs on IRQ0 (Interrupt 08H) roughly 18.2 times per
  14608.       second. This hardware interrupt occurs regardless of what else the
  14609.       system is doing, so an Interrupt 08H ISR a convenient place to check
  14610.       whether HotFlag has been set.
  14611.  
  14612.       As in the case of the Interrupt 09H handler, the TSR's Interrupt 08H
  14613.       handler passes control to previous Interrupt 08H handlers before it
  14614.       proceeds with its own work. This procedure is particularly important
  14615.       with Interrupt 08H because the ROM BIOS Interrupt 08H handler, which
  14616.       maintains the system's time-of-day clock and resets the system's Intel
  14617.       8259A Programmable Interrupt Controller, must execute before the next
  14618.       timer tick can occur. The TSR's handler therefore defers its own work
  14619.       until control has returned after previous Interrupt 08H handlers have
  14620.       executed.
  14621.  
  14622.       The only function of the TSR's Interrupt 08H handler is to attempt to
  14623.       transfer control to the RAM-resident application. The routine
  14624.       VerifyTSRState performs this task. It first examines the contents of
  14625.       HotFlag to determine whether a hot-key sequence has been detected. If
  14626.       so, it examines the state of the MS-DOS InDOS and critical error
  14627.       flags, the current status of hardware interrupts, and the current
  14628.       status of any non-reentrant ROM BIOS routines that might be executing.
  14629.  
  14630.       If HotFlag is nonzero, the InDOS and critical error flags are both
  14631.       zero, no hardware interrupts are currently being serviced, and no non-
  14632.       reentrant ROM BIOS code has been interrupted, the Interrupt 08H
  14633.       handler activates the RAM-resident utility. Otherwise, nothing happens
  14634.       until the next timer tick, when the handler executes again.
  14635.  
  14636.       While HotFlag is nonzero, the Interrupt 08H handler continues to
  14637.       monitor system status until MS-DOS, the ROM BIOS, and the hardware
  14638.       interrupts are all in a stable state. Often the system status is
  14639.       stable at the time the hot-key sequence is detected, so the RAM-
  14640.       resident application runs immediately. Sometimes, however, system
  14641.       activities such as prolonged disk reads or writes can preclude the
  14642.       activation of the RAM-resident utility for several seconds after the
  14643.       hot-key sequence has been detected. The handler could be designed to
  14644.       detect this situation (for example, by decrementing HotFlag on each
  14645.       timer tick) and return an error status or display a message to the
  14646.       user.
  14647.  
  14648.       A more serious difficulty arises when the MS-DOS default command
  14649.       processor (COMMAND.COM) is waiting for keyboard input. In this
  14650.       situation, Interrupt 21H Function 01H (Character Input with Echo) is
  14651.       executing, so InDOS is nonzero and the Interrupt 08H handler can never
  14652.       detect a state in which it can activate the RAM-resident utility. This
  14653.       problem is solved by providing a custom handler for Interrupt 28H (the
  14654.       MS-DOS idle interrupt), which is executed by Interrupt 21H Function
  14655.       01H each time it loops as it waits for a keypress. The only difference
  14656.       between the Interrupt 28H handler and the Interrupt 08H handler is
  14657.       that the Interrupt 28H handler can activate the RAM-resident
  14658.       application when the value of InDOS is 1, which is reasonable because
  14659.       InDOS must have been incremented when Interrupt 21H Function 01H
  14660.       started to execute.
  14661.  
  14662.       The interrupt service routines for ROM BIOS Interrupts 05H, 10H, and
  14663.       13H do nothing more than increment and decrement flags that indicate
  14664.       whether these interrupts are being processed by ROM BIOS routines.
  14665.       These flags are inspected by the TSR's Interrupt 08H and 28H handlers.
  14666.  
  14667.  Executing the RAM-resident application
  14668.       When the RAM-resident application is first activated, it runs in the
  14669.       context of the program that was interrupted; that is, the contents of
  14670.       the registers, the video display mode, the current PSP, and the
  14671.       current DTA all belong to the interrupted program. The resident
  14672.       application is responsible for preserving the registers and updating
  14673.       MS-DOS with its PSP and DTA values.
  14674.  
  14675.       The RAM-resident application preserves the previous contents of the
  14676.       CPU registers on its own stack to avoid overflowing the interrupted
  14677.       program's stack. It then installs its own handlers for Control-Break
  14678.       (Interrupt 1BH), Control-C (Interrupt 23H), and critical error
  14679.       (Interrupt 24H). (Otherwise, the interrupted program's handlers would
  14680.       take control if the user pressed Ctrl-Break or Ctrl-C or if an MS-DOS
  14681.       critical error occurred.) These handlers perform no action other than
  14682.       setting flags that can be inspected later by the RAM-resident
  14683.       application, which could then take appropriate action.
  14684.  
  14685.       The application uses Interrupt 21H Functions 50H and 51H to update MS-
  14686.       DOS with the address of its PSP. If the application is running under
  14687.       MS-DOS versions 2.x, the critical error flag is set before Functions
  14688.       50H and 51H are executed so that AuxStack is used for the call instead
  14689.       of IOStack, to avoid corrupting IOStack in the event that InDOS is 1.
  14690.  
  14691.       The application preserves the current extended error information with
  14692.       a call to Interrupt 21H Function 59H. Otherwise, the RAM-resident
  14693.       application might be activated immediately after a critical error
  14694.       occurred in the interrupted program but before the interrupted program
  14695.       had executed Function 59H and, if a critical error occurred in the TSR
  14696.       application, the interrupted program's extended error information
  14697.       would inadvertently be destroyed.
  14698.  
  14699.       This example also shows how to update the MS-DOS default DTA using
  14700.       Interrupt 21H Functions 1AH and 2FH, although in this case this step
  14701.       is not necessary because the DTA is never used within the application.
  14702.       In practice, the DTA should be updated only if the RAM-resident
  14703.       application includes calls to Interrupt 21H functions that use a DTA
  14704.       (Functions 11H, 12H, 14H, 15H, 21H, 22H, 27H, 28H, 4EH, and 4FH).
  14705.  
  14706.       After the resident interrupt handlers are installed and the PSP, DTA,
  14707.       and extended error information have been set up, the RAM-resident
  14708.       application can safely execute any Interrupt 21H function calls except
  14709.       those that use IOStack (Functions 01H through 0CH). These functions
  14710.       cannot be used within a RAM-resident application even if the
  14711.       application sets the critical error flag to force the use of the
  14712.       auxiliary stack, because they also use other non-reentrant data
  14713.       structures such as input/output buffers. Thus, a RAM-resident utility
  14714.       must rely either on user-written console input/output functions or, as
  14715.       in the example, on ROM BIOS functions.
  14716.  
  14717.       The application terminates by returning the interrupted program's
  14718.       extended error information, DTA, and PSP to MS-DOS, restoring the
  14719.       previous Interrupt 1BH, 23H, and 24H handlers, and restoring the
  14720.       previous CPU registers and stack.
  14721.  
  14722.                                                    Richard Wilton
  14723.  
  14724.  
  14725.  
  14726.  Article 12: Exception Handlers
  14727.  
  14728.  
  14729.       Exceptions are system events directly related to the execution of an
  14730.       application program; they ordinarily cause the operating system to
  14731.       abort the program. Exceptions are thus different from errors, which
  14732.       are minor unexpected events (such as failure to find a file on disk)
  14733.       that the program can be expected to handle appropriately. Likewise,
  14734.       they differ from external hardware interrupts, which are triggered by
  14735.       events (such as a character arriving at the serial port) that are not
  14736.       directly related to the program's execution.
  14737.  
  14738.       The computer hardware assists MS-DOS in the detection of some
  14739.       exceptions, such as an attempt to divide by zero, by generating an
  14740.       internal hardware interrupt. Exceptions related to peripheral devices,
  14741.       such as an attempt to read from a disk drive that is not ready or does
  14742.       not exist, are called critical errors. Instead of causing a hardware
  14743.       interrupt, these exceptions are typically reported to the operating
  14744.       system by device drivers. MS-DOS also supports a third type of
  14745.       exception, which is triggered by the entry of a Control-C or
  14746.       ControlBreak at the keyboard and allows the user to signal that the
  14747.       current program should be terminated immediately.
  14748.  
  14749.       MS-DOS contains built-in handlers for each type of exception and so
  14750.       guarantees a minimum level of system stability that requires no effort
  14751.       on the part of the application programmer. For some applications,
  14752.       however, these default handlers are inadequate. For example, if a
  14753.       communications program that controls the serial port directly with
  14754.       custom interrupt handlers is terminated by the operating system
  14755.       without being given a chance to turn off serial-port interrupts, the
  14756.       next character that arrives on the serial line will trigger an
  14757.       interrupt for which a handler is no longer present in memory. The
  14758.       result will be a system crash. Accordingly, MS-DOS allows application
  14759.       programs to install custom exception handlers so that they can shut
  14760.       down operations in an orderly way when an exception occurs.
  14761.  
  14762.       This article examines the default exception handlers provided by
  14763.       MS-DOS and discusses methods programmers can use to replace those
  14764.       routines with handlers that are more closely matched to specific
  14765.       application requirements.
  14766.  
  14767.  
  14768.  Overview
  14769.  
  14770.       Two major exception handlers of importance to application programmers
  14771.       are supported under all versions of MS-DOS. The first, the Control-C
  14772.       exception handler, terminates the program and is invoked when the user
  14773.       enters a Ctrl-C or Ctrl-Break keystroke; the address of this handler
  14774.       is found in the vector for Interrupt 23H. The second, the critical
  14775.       error exception handler, is invoked if MS-DOS detects a critical error
  14776.       while servicing an I/O request. (A critical error is a hardware error
  14777.       that makes normal completion of the request impossible.) This
  14778.       exception handler displays the familiar Abort, Retry, Ignore prompt;
  14779.       its address is saved in the vector for Interrupt 24H.
  14780.  
  14781.       When a program begins executing, the addresses in the Interrupt 23H
  14782.       and 24H vectors usually point to the system's default Control-C and
  14783.       critical error handlers. If the program is a child process, however,
  14784.       the vectors might point to exception handlers that belong to the
  14785.       parent process, if the immediate parent is not COMMAND.COM. In any
  14786.       case, the application program can install its own custom handler for
  14787.       Control-C or critical error exceptions simply by changing the address
  14788.       in the vector for Interrupt 23H or Interrupt 24H so that the vector
  14789.       points to the application's own routine. When the program performs a
  14790.       final exit by means of Interrupt 21H Function 00H (Terminate Process),
  14791.       Function 31H (Terminate and Stay Resident), Function 4CH (Terminate
  14792.       Process with Return Code), Interrupt 20H (Terminate Process), or
  14793.       Interrupt 27H (Terminate and Stay Resident), MS-DOS restores the
  14794.       previous contents of the Interrupt 23H and 24H vectors.
  14795.  
  14796.       Note that Interrupts 23H and 24H never occur as externally generated
  14797.       hardware interrupts in an MS-DOS system. The vectors for these
  14798.       interrupts are used simply as storage areas for the addresses of the
  14799.       exception handlers.
  14800.  
  14801.       MS-DOS also contains default handlers for the Control-Break event
  14802.       detected by the ROM BIOS in IBM PCs and compatible computers and for
  14803.       some of the Intel microprocessor exceptions that generate actual
  14804.       hardware interrupts. These exception handlers are not replaced by
  14805.       application programs as often as the Control-C and critical error
  14806.       handlers. The interrupt vectors that contain the addresses of these
  14807.       handlers are not restored by MS-DOS when a program exits.
  14808.  
  14809.       The address of the Control-Break handler is saved in the vector for
  14810.       Interrupt 1BH and is invoked by the ROM BIOS whenever the Ctrl-Break
  14811.       key combination is detected. The default MS-DOS handler normally
  14812.       flushes the keyboard input buffer and substitutes Control-C for
  14813.       Control-Break, and the Control-C is later handled by the Control-C
  14814.       exception handler. The default handlers for exceptions that generate
  14815.       hardware interrupts either abort the current program (as happens with
  14816.       Divide by Zero) or bring the entire system to a halt (as for a memory
  14817.       parity error).
  14818.  
  14819.  
  14820.  The Control-C Handler
  14821.  
  14822.       The vector for Interrupt 23H points to code that is executed whenever
  14823.       MS-DOS detects a Control-C character in the keyboard input buffer.
  14824.       When the character is detected, MS-DOS executes a software Interrupt
  14825.       23H.
  14826.  
  14827.       In response to Interrupt 23H, the default Control-C exception handler
  14828.       aborts the current process. Files that were opened with handles are
  14829.       closed (FCB-based files are not), but no other cleanup is performed.
  14830.       Thus, unsaved data can be left in buffers, some files might not be
  14831.       processed, and critical addresses, such as the vectors for custom
  14832.       interrupt handlers, might be left pointing into free RAM. If more
  14833.       complete control over process termination is wanted, the application
  14834.       should replace the default Control-C handler with custom code. See
  14835.       Customizing Control-C Handling below.
  14836.  
  14837.       The Control-Break exception handler, pointed to by the vector for
  14838.       Interrupt 1BH, is closely related to the Control-C exception handler
  14839.       in MS-DOS systems on the IBM PC and close compatibles but is called by
  14840.       the ROM BIOS keyboard driver on detection of the Ctrl-Break keystroke
  14841.       combination. Because the Control-Break exception is generated by the
  14842.       ROM BIOS, it is present only on IBM PC-compatible machines and is not
  14843.       a standard feature of MS-DOS. The default ROM BIOS handler for
  14844.       Control-Break is a simple interrupt return--in other words, no action
  14845.       is taken to handle the keystroke itself, other than converting the
  14846.       Ctrl-Break scan code to an extended character and passing it through
  14847.       to MS-DOS as normal keyboard input.
  14848.  
  14849.       To account for as many hardware configurations as possible, MS-DOS
  14850.       redirects the ROM BIOS Control-Break interrupt vector to its own
  14851.       Control-Break handler during system initialization. The MS-DOS
  14852.       Control-Break handler sets an internal flag that causes the Ctrl-Break
  14853.       keystroke to be interpreted as a Ctrl-C keystroke and thus causes
  14854.       Interrupt 23H to occur.
  14855.  
  14856.  Customizing Control-C handling
  14857.  
  14858.       The exception handlers most often neglected by application
  14859.       programmers--and most often responsible for major program failures--
  14860.       are the default exception handlers invoked by the Ctrl-C and Ctrl-
  14861.       Break keystrokes. Although the user must be able to recover from a
  14862.       runaway condition (the reason for Ctrl-C capability in the first
  14863.       place), any exit from a complex program must also be orderly, with
  14864.       file buffers flushed to disk, directories and indexes updated, and so
  14865.       on. The default Control-C and Control-Break handlers do not provide
  14866.       for such an orderly exit.
  14867.  
  14868.       The simplest and most direct way to deal with Ctrl-C and Ctrl-Break
  14869.       keystrokes is to install new exception handlers that do nothing more
  14870.       than an IRET and thus take MS-DOS out of the processing loop entirely.
  14871.       This move is not as drastic as it sounds: It allows an application to
  14872.       check for and handle the Ctrl-C and Ctrl-Break keystrokes at its
  14873.       convenience when they arrive through the normal keyboard input
  14874.       functions and prevents MS-DOS from terminating the program
  14875.       unexpectedly.
  14876.  
  14877.       The following example sets the Interrupt 23H and Interrupt 1BH vectors
  14878.       to point to an IRET instruction. When the user presses Ctrl-C or Ctrl-
  14879.       Break, the keystroke combination is placed into the keyboard buffer
  14880.       like any other keystroke. When it detects the Ctrl-C or Ctrl-Break
  14881.       keystroke, the executing program should exit properly (if that is the
  14882.       desired action) after an appropriate shutdown procedure.
  14883.  
  14884.       To install the new exception handlers, the following procedure (set_
  14885.       int) should be called while the main program is initializing:
  14886.  
  14887.       _DATA   segment para public 'DATA'
  14888.       oldint1b dd     0               ; original INT 1BH vector
  14889.       oldint23 dd     0               ; original INT 23H vector
  14890.       _DATA   ends
  14891.       _TEXT   segment byte public 'CODE'
  14892.               assume cs:_TEXT,ds:_DATA,es:NOTHING
  14893.       myint1b:                        ; handler for Ctrl-Break
  14894.       myint23:                        ; handler for Ctrl-C
  14895.               iret
  14896.  
  14897.       set_int proc    near
  14898.               mov     ax,351bh        ; get current contents of
  14899.               int     21h             ; Int 1BH vector and save it
  14900.               mov     word ptr oldint1b,bx
  14901.               mov     word ptr oldint1b+2,es
  14902.               mov     ax,3523h        ; get current contents of
  14903.               int     21h             ; Int 23H vector and save it
  14904.               mov     word ptr oldint23,bx
  14905.               mov     word ptr oldint23+2,es
  14906.               push    ds              ; save our data segment
  14907.               push    cs              ; let DS point to our
  14908.               pop     ds              ; code segment
  14909.               mov     dx,offset myint1b
  14910.               mov     ax,251bh        ; set interrupt vector 1BH
  14911.               int     21h             ; to point to new handler
  14912.               mov     dx,offset myint23
  14913.               mov     ax,2523h        ; set interrupt vector 23H
  14914.               int     21h             ; to point to new handler
  14915.               pop     ds              ; restore our data segment
  14916.               ret                     ; back to caller
  14917.       set_int endp
  14918.       _TEXT   ends
  14919.  
  14920.       The application can use the following routine to restore the original
  14921.       contents of the vectors pointing to the Control-C and Control-Break
  14922.       exception handlers before making a final exit back to MS-DOS. Note
  14923.       that, although MS-DOS restores the Interrupt 23H vector to its
  14924.       previous contents, the application must restore the Interrupt 1BH
  14925.       vector itself.
  14926.  
  14927.       rest_int proc   near
  14928.               push    ds              ; save our data segment
  14929.               mov     dx,word ptr oldint23
  14930.               mov     ds,word ptr oldint23+2
  14931.               mov     ax,2523h        ; restore original contents
  14932.               int     21h             ; of Int 23H vector
  14933.               pop     ds              ; restore our data segment
  14934.               push    ds              ; then save it again
  14935.               mov     dx,word ptr oldint1B
  14936.               mov     ds,word ptr oldint1B+2
  14937.               mov     ax,251Bh        ; restore original contents
  14938.               int     21h             ; of Int 1BH vector
  14939.               pop     ds              ; get back our data segment
  14940.               ret                     ; return to caller
  14941.       rest_int endp
  14942.  
  14943.       The preceding example simply prevents MS-DOS from terminating an
  14944.       application when a Ctrl-C or Ctrl-Break keystroke is detected. Program
  14945.       termination is still often the ultimate goal, but after a more orderly
  14946.       shutdown than is provided by the MS-DOS default Control-C handler. The
  14947.       following exception handler allows the program to exit more
  14948.       gracefully:
  14949.  
  14950.       myint1b:                        ; Control-Break exception handler
  14951.               iret                    ; do nothing
  14952.       myint23:                        ; Control-C exception handler
  14953.               call    safe_shut_down  ; release interrupt vectors,
  14954.                                       ; close files, etc.
  14955.               jmp     program_exit_point
  14956.  
  14957.       Note that because the Control-Break handler is invoked by the ROM BIOS
  14958.       keyboard driver and MS-DOS is not reentrant, MS-DOS services (such as
  14959.       closing files and terminating with return code) cannot be invoked
  14960.       during processing of a Control-Break exception. In contrast, any
  14961.       MS-DOS Interrupt 21H function call can be used during the processing
  14962.       of a Control-C exception. Thus, the Control-Break handler in the
  14963.       preceding example does nothing, whereas the Control-C handler performs
  14964.       orderly shutdown of the application.
  14965.  
  14966.       Most often, however, neither a handler that does nothing nor a handler
  14967.       that shuts down and terminates is sufficient for processing a Ctrl-C
  14968.       (or Ctrl-Break) keystroke. Rather than simply prevent Control-C
  14969.       processing, software developers usually prefer to have a Ctrl-C
  14970.       keystroke signal some important action without terminating the
  14971.       program. Using methods similar to those above, the programmer can
  14972.       replace Interrupts 1BH and 23H with a routine like the following:
  14973.  
  14974.       myint1b:                        ; Control-Break exception handler
  14975.       myint23:                        ; Control-C exception handler
  14976.               call    control_c_happened
  14977.               iret
  14978.  
  14979.  Notes on processing Control-C
  14980.  
  14981.       The preceding examples assume the programmer wants to treat Control-C
  14982.       and Control-Break the same way, but this is not always desirable.
  14983.       Control-C and Control-Break are not the same, and the difference
  14984.       between the two should be kept in mind: The Control-Break handler is
  14985.       invoked by a keyboard-input interrupt and can be called at any time;
  14986.       the Control-C handler is called only at "safe" points during the
  14987.       processing of MS-DOS Interrupt 21H functions. Also, even though MS-DOS
  14988.       restores the Interrupt 23H vector on exit from a program, the
  14989.       application must restore the previous contents of the Interrupt 1BH
  14990.       vector before exiting. If this interrupt vector is not restored, the
  14991.       next Ctrl-Break keystroke will cause the machine to attempt to execute
  14992.       an undetermined piece of code or data and will probably crash the
  14993.       system.
  14994.  
  14995.       Although it is generally desirable to take control of the Control-C
  14996.       and Control-Break interrupts, control should be retained only as long
  14997.       as necessary. For example, a RAM-resident pop-up application should
  14998.       take over Control-C and Control-Break handling only when it is
  14999.       activated, and it should restore the previous contents of the
  15000.       Interrupt 1BH and Interrupt 23H vectors before it returns control to
  15001.       the foreground process.
  15002.  
  15003.  
  15004.  The Critical Error Handler
  15005.  
  15006.       When MS-DOS detects a critical error--an error that prevents
  15007.       successful completion of an I/O operation--it calls the exception
  15008.       handler whose address is stored in the vector for Interrupt 24H.
  15009.       Information about the operation in progress and the nature of the
  15010.       error is passed to the exception handler in the CPU registers. In
  15011.       addition, the contents of all the registers at the point of the
  15012.       original MS-DOS call are pushed onto the stack for inspection by the
  15013.       exception handler.
  15014.  
  15015.       The action of MS-DOS's default critical error handler is to present a
  15016.       message such as
  15017.  
  15018.       Error type error action device
  15019.       Abort, Retry, Ignore?
  15020.  
  15021.       This message signals a hardware error from which MS-DOS cannot recover
  15022.       without user intervention. For example, if the user enters the command
  15023.  
  15024.       C>DIR A:  <ENTER>
  15025.  
  15026.       but drive A either does not contain a disk or the disk drive door is
  15027.       open, the MS-DOS critical error handler displays the message
  15028.  
  15029.       Not ready error reading drive A
  15030.       Abort, Retry, Ignore?
  15031.  
  15032.       I (Ignore) simply tells MS-DOS to forget that an error occurred and
  15033.       continue on its way. (Of course, if the error occurred during the
  15034.       writing of a file to disk, the file is generally corrupted; if the
  15035.       error occurred during reading, the data might be incorrect.)
  15036.  
  15037.       R (Retry) gives the application a second chance to access the device.
  15038.       The critical error handler returns information to MS-DOS that says, in
  15039.       effect, "Try again; maybe it will work this time." Sometimes, the
  15040.       attempt succeeds (as when the user closes an open drive door), but
  15041.       more often the same or another critical error occurs.
  15042.  
  15043.       A (Abort) is the problem child of Interrupt 24H. If the user responds
  15044.       with A, the application is terminated immediately. The directory
  15045.       structure is not updated for open files, interrupt vectors are left
  15046.       pointing to inappropriate locations, and so on. In many cases,
  15047.       restarting the system is the only safe thing to do at this point.
  15048.  
  15049.       Note: Beginning with version 3.3, an F (Fail) option appears in the
  15050.       message displayed by MS-DOS's default critical error handler. When
  15051.       Fail is selected, the current MS-DOS function is terminated and an
  15052.       error condition is returned to the calling program. For example, if a
  15053.       program calls Interrupt 21H Function 3DH to open a file on drive A but
  15054.       the drive door is open, choosing F in response to the error message
  15055.       causes the function call to return with the carry flag set, indicating
  15056.       that an error occurred but processing continues.
  15057.  
  15058.       Like the Control-C exception handler, the default critical error
  15059.       exception handler can and should be replaced by an application program
  15060.       when complete control of the system is desired. The program installs
  15061.       its own handler simply by placing the address of the new handler in
  15062.       the vector for Interrupt 24H; MS-DOS restores the previous contents of
  15063.       the Interrupt 24H vector when the program terminates.
  15064.  
  15065.       Unlike the Control-C handler, however, the critical error handler must
  15066.       be kept within carefully defined limits to preserve the stability of
  15067.       the operating system. Programmers must rigidly adhere to the structure
  15068.       described in the following pages for passing information to and from
  15069.       an Interrupt 24H handler.
  15070.  
  15071.  Mechanics of critical error handling
  15072.  
  15073.       MS-DOS critical error handling has two components: the exception
  15074.       handler, whose address is saved in the Interrupt 24H vector and which
  15075.       can be replaced by an application program; and an internal routine
  15076.       inside MS-DOS. The internal routine sets up the information to be
  15077.       passed to the exception handler on the stack and in registers and, in
  15078.       turn, calls the exception handler itself. The internal routine also
  15079.       responds to the values returned by the critical error handler when
  15080.       that handler executes an IRET to return to the MS-DOS kernel.
  15081.  
  15082.       Before calling the exception handler, MS-DOS arranges the stack
  15083.       (Figure 12-1) so the handler can inspect the location of the error
  15084.       and register contents at the point in the original MS-DOS function
  15085.       call that led to the critical error.
  15086.  
  15087.  
  15088.       ┌───────────────┐
  15089.       │     Flags     │▒
  15090.       ├───────────────┤▒
  15091.       │      CS       │▒ Flags and CS:IP pushed on stack
  15092.       ├───────────────┤▒  by original Interrupt 21H call
  15093.       │      IP       │▒
  15094.       ├───────────────┤──SP on entry to Interrupt 21H handler
  15095.       │      ES       │▒
  15096.       ├───────────────┤▒
  15097.       │      DS       │▒
  15098.       ├───────────────┤▒
  15099.       │      BP       │▒
  15100.       ├───────────────┤▒
  15101.       │      DI       │▒
  15102.       ├───────────────┤▒ Registers at point of
  15103.       │      SI       │▒  original Interrupt 21H call
  15104.       ├───────────────┤▒
  15105.       │      DX       │▒
  15106.       ├───────────────┤▒
  15107.       │      CX       │▒
  15108.       ├───────────────┤▒
  15109.       │      BX       │▒
  15110.       ├───────────────┤▒
  15111.       │      AX       │▒
  15112.       ├───────────────┤
  15113.       │     Flags     │▒
  15114.       ├───────────────┤▒
  15115.       │      CS       │▒ Return address from
  15116.       ├───────────────┤▒  Interrupt 24H handler
  15117.       │      IP       │▒
  15118.       └───────────────┘──SP on entry to Interrupt 24H handler
  15119.  
  15120.       Figure 12-1. The stack contents at entry to a critical error exception
  15121.       handler.
  15122.  
  15123.  
  15124.       When the critical error handler is called by the internal routine,
  15125.       four registers may contain important information: AX, DI, BP, and SI.
  15126.       (With MS-DOS versions 1.x, only the AX and DI registers contain
  15127.       significant information.) The information passed to the handler in the
  15128.       registers differs somewhat, depending on whether a character device or
  15129.       a block device is causing the error.
  15130.  
  15131.  Block-device (disk-based) errors
  15132.  
  15133.       If the critical error handler is entered in response to a block-device
  15134.       (disk-based) error, registers BP:SI contain the segment:offset of the
  15135.       device driver header for the device causing the error and bit 7 (the
  15136.       high-order bit) of the AH register is zero. The remaining bits of the
  15137.       AH register contain the following information (bits 3 through 5 apply
  15138.       only to MS-DOS versions 3.1 and later):
  15139.  
  15140. ╓┌────────────────┌───────────┌──────────────────────────────────────────────╖
  15141.       Bit         Value       Meaning
  15142.       ──────────────────────────────────────────────────────────────────
  15143.       Bit         Value       Meaning
  15144.       ──────────────────────────────────────────────────────────────────
  15145.       0            0          Read operation
  15146.                    1          Write operation
  15147.       1-2                     Indicate the affected disk area:
  15148.                   00              MS-DOS
  15149.                   01              File allocation table
  15150.                   10              Root directory
  15151.                   11              Files area
  15152.       3            0          Fail response not allowed
  15153.                    1          Fail response allowed
  15154.       4            0          Retry response not allowed
  15155.                    1          Retry response allowed
  15156.       5            0          Ignore response not allowed
  15157.                    1          Ignore response allowed
  15158.       6            0          Undefined
  15159.  
  15160.       The AL register contains the designation of the drive where the error
  15161.       occurred; for example, AL = 00H (drive A), AL = 01H (drive B), and so
  15162.       on.
  15163.  
  15164.       The lower half of the DI register contains the following error codes
  15165.       (the upper half of this register is undefined):
  15166.  
  15167. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  15168.       Error Code       Meaning
  15169.       ──────────────────────────────────────────────────────────────────
  15170.       00H              Write-protected disk
  15171.       01H              Unknown unit
  15172.       02H              Drive not ready
  15173.       03H              Invalid command
  15174.       04H              Data error (CRC)
  15175.       05H              Length of request structure invalid
  15176.       06H              Seek error
  15177.       07H              Non-MS-DOS disk
  15178.       08H              Sector not found
  15179.       09H              Printer out of paper
  15180.       0AH              Write fault
  15181.       0BH              Read fault
  15182.       0CH              General failure
  15183.       0FH              Invalid disk change (version 3.0 or later)
  15184.  
  15185.       Note: With versions 1.x, the only valid error codes are 00H, 02H, 04H,
  15186.       06H, 08H, 0AH, and 0CH.
  15187.  
  15188.       Before calling the critical error handler for a disk-based error, MS-
  15189.       DOS tries from one to five times to perform the requested read or
  15190.       write operation, depending on the type of operation. Critical disk
  15191.       errors result only from Interrupt 21H operations, not from failed
  15192.       sector-read and sector-write operations attempted with Interrupts 25H
  15193.       and 26H.
  15194.  
  15195.  Character-device errors
  15196.  
  15197.       If the critical error handler is called from the MS-DOS kernel with
  15198.       bit 7 of the AH register set to 1, either an error occurred on a
  15199.       character device or the memory image of the file allocation table is
  15200.       bad (a rare occurrence). Again, registers BP:SI contain the segment
  15201.       and offset of the device driver header for the device causing the
  15202.       critical error. The exception handler can inspect bit 15 of the device
  15203.       attribute word at offset 04H in the device header to confirm that the
  15204.       error was caused by a character device--this bit is 0 for block
  15205.       devices and 1 for character devices. See also PROGRAMMING IN THE MS-
  15206.       DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Installable Device Drivers.
  15207.  
  15208.       If the error was caused by a character device, the lower half of the
  15209.       DI register contains error codes as described above and the contents
  15210.       of the AL register are undefined. The exception handler can inspect
  15211.       the other fields of the device header to obtain the logical name of
  15212.       the character device; to determine whether that device is the standard
  15213.       input, standard output, or both; and so on.
  15214.  
  15215.  Critical error processing
  15216.  
  15217.       The critical error exception handler is entered from MS-DOS with
  15218.       interrupts disabled. Because an MS-DOS system call is already in
  15219.       progress and MS-DOS is not reentrant, the handler cannot request any
  15220.       MS-DOS system services other than Interrupt 21H Functions 01 through
  15221.       0CH (character I/O functions), Interrupt 21H Function 30H (Get MS-DOS
  15222.       Version Number), and Interrupt 21H Function 59H (Get Extended Error
  15223.       Information). These functions use a special stack so that they can be
  15224.       called during error processing.
  15225.  
  15226.       In general, the critical error handler must preserve all but the AL
  15227.       register. It must not change the contents of the device header pointed
  15228.       to by BP:SI. The handler must return to the MS-DOS kernel with an
  15229.       IRET, passing an action code in register AL as follows:
  15230.  
  15231. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  15232.       Value in AL      Meaning
  15233.       ──────────────────────────────────────────────────────────────────
  15234.       00H              Ignore
  15235.       01H              Retry
  15236.       02H              Terminate process
  15237.       03H              Fail current system call
  15238.  
  15239.       These values correspond to the options presented by the MS-DOS default
  15240.       critical error handler. The default handler prompts the user for
  15241.       input, places the appropriate return information in the AL register,
  15242.       and immediately issues an IRET instruction.
  15243.  
  15244.       Note: Although the Fail option is displayed by the MS-DOS default
  15245.       critical error handler in versions 3.3 and later, the Fail option
  15246.       inside the handler was added in version 3.1.
  15247.  
  15248.       With MS-DOS versions 3.1 and later, if the handler returns an action
  15249.       code in AL that is not allowed for the error in question (bits 3
  15250.       through 5 of the AH register at the point of call), MS-DOS reacts
  15251.       according to the following rules:
  15252.  
  15253.       If Ignore is specified by AL = 00H but is not allowed because bit 5 of
  15254.       AH = 0, the response defaults to Fail (AL = 03H).
  15255.  
  15256.       If Retry is specified by AL = 01H but is not allowed because bit 4 of
  15257.       AH = 0, the response defaults to Fail (AL = 03H).
  15258.  
  15259.       If Fail is specified by AL = 03H but is not allowed because bit 3 of
  15260.       AH = 0, the response defaults to Abort.
  15261.  
  15262.  Custom critical error handlers
  15263.  
  15264.       Each time it receives control, COMMAND.COM restores the Interrupt 24H
  15265.       vector to point to the system's default critical error handler and
  15266.       displays a prompt to the user. Consequently, a single custom handler
  15267.       cannot terminate and stay resident to provide critical error handling
  15268.       services for subsequent application programs. Each program that needs
  15269.       better critical error handling than MS-DOS provides must contain its
  15270.       own critical error handler.
  15271.  
  15272.       Figure 12-2 contains a simple critical error handler, INT24.ASM,
  15273.       written in assembly language. In the form shown, INT24.ASM is no more
  15274.       than a functional replacement for the MS-DOS default critical error
  15275.       handler, but it can be used as the basis for more sophisticated
  15276.       handlers that can be incorporated into application programs.
  15277.  
  15278.       ──────────────────────────────────────────────────────────────────────
  15279.  
  15280.       Figure 12-2. INT24.ASM, a replacement Interrupt 24 handler.
  15281.  
  15282.       ──────────────────────────────────────────────────────────────────────
  15283.  
  15284.       INT24.ASM contains three routines:
  15285.  
  15286. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  15287.       Routine          Action
  15288.       ──────────────────────────────────────────────────────────────────
  15289.       get24            Saves the previous contents of the Interrupt 24H
  15290.       Routine          Action
  15291.      get24            Saves the previous contents of the Interrupt 24H
  15292.                        critical error handler vector and stores the address
  15293.                        of the new critical error handler into the vector.
  15294.  
  15295.       res24            Restores the address of the previous critical error
  15296.                        handler, which was saved by a call to get24, into
  15297.                        the Interrupt 24 vector.
  15298.  
  15299.       int24            Replaces the MS-DOS critical error handler.
  15300.  
  15301.       A program wishing to substitute the new critical error handler for the
  15302.       system's default handler should call the get24 routine during its
  15303.       initialization sequence. If the program wishes to revert to the
  15304.       system's default handler during execution, it can accomplish this with
  15305.       a call to the res24 routine. Otherwise, a call to res24 (and the
  15306.       presence of the routine itself in the program) is not necessary,
  15307.       because MS-DOS automatically restores the Interrupt 24H vector to its
  15308.       previous value when the program exits, from information stored in the
  15309.       program segment prefix (PSP).
  15310.  
  15311.       The replacement critical error handler, int24, is simple. First it
  15312.       saves all registers; then it displays a message that a critical error
  15313.       has occurred and prompts the user to enter a key selecting one of the
  15314.       four possible options: Abort, Retry, Ignore, or Fail. If an illegal
  15315.       key is entered, the prompt is displayed again; otherwise, the action
  15316.       code corresponding to the key is extracted from a table and placed in
  15317.       the AL register, the other registers are restored, and control is
  15318.       returned to the MS-DOS kernel with an IRET instruction.
  15319.  
  15320.       Note that the handle read and write functions (Interrupt 21H Functions
  15321.       3FH and 40H), which would normally be preferred for interaction with
  15322.       the display and keyboard, cannot be used in a critical error handler.
  15323.  
  15324.  
  15325.  Hardware-generated Exception Interrupts
  15326.  
  15327.       Intel reserved the vectors for Interrupts 00H through 1FH (Table 12-1)
  15328.       for exceptions generated by the execution of various machine
  15329.       instructions. Handling of these chip-dependent internal interrupts can
  15330.       vary from one make of MS-DOS machine to another; some such differences
  15331.       are mentioned in the discussion.
  15332.  
  15333.  
  15334.       Table 12-1. Intel Reserved Exception Interrupts.
  15335.  
  15336. ╓┌──────────────────────┌────────────────────────────────────────────────────╖
  15337.       Interrupt Number  Definition
  15338.       ──────────────────────────────────────────────────────────────────
  15339.       00H               Divide by Zero
  15340.       01H               Single-Step
  15341.       02H               Nonmaskable Interrupt (NMI)
  15342.       03H               Breakpoint Trap
  15343.       04H               Overflow Trap
  15344.       05H               BOUND Range Exceeded1
  15345.       06H               Invalid Opcode1
  15346.       07H               Coprocessor not Available2
  15347.       08H               Double-Fault Exception2
  15348.       09H               Coprocessor Segment Overrun2
  15349.       0AH               Invalid Task State Segment (TSS)2
  15350.       0BH               Segment not Present2
  15351.       0CH               Stack Exception2
  15352.       0DH               General Protection Exception2
  15353.       Interrupt Number  Definition
  15354.      0DH               General Protection Exception2
  15355.       0EH               Page Fault3
  15356.       0FH               (Reserved)
  15357.       10H               Coprocessor Error2
  15358.       11-1FH            (Reserved)
  15359.  
  15360.  
  15361.       Note: A number of these reserved exception interrupts generally do not
  15362.       occur in MS-DOS because they are generated only when the 80286 or
  15363.       80386 microprocessor is operating in protected mode. The following
  15364.       discussions do not cover these interrupts.
  15365.  
  15366.  Divide by Zero (Interrupt 00H)
  15367.  
  15368.       An Interrupt 00H occurs whenever a DIV or IDIV operation fails to
  15369.       terminate within a reasonable period of time. The interrupt is
  15370.       triggered by a mathematical anomaly: Division by zero is inherently
  15371.       undefined. To handle such situations, Intel built special processing
  15372.       into the DIV and IDIV instructions to ensure that the condition does
  15373.       not cause the processor to lock up. Although the assumption underlying
  15374.       Interrupt 00H is an attempt to divide by zero (a condition that will
  15375.       never terminate), the interrupt can also be triggered by other error
  15376.       conditions, such as a quotient that is too large to fit in the
  15377.       designated register (AX or AL).
  15378.  
  15379.       The ROM BIOS handler for Interrupt 00H in the IBM PC and close
  15380.       compatibles is a simple IRET instruction. During the MS-DOS startup
  15381.       process, however, MS-DOS modifies the interrupt vector to point to its
  15382.       own handler--a routine that issues the warning message Divide by Zero
  15383.       and aborts the current application. This abort procedure can leave the
  15384.       computer and operating system in an extremely unstable state. If the
  15385.       default handler is used, the system should be restarted immediately
  15386.       and an attempt should be made to find and eliminate the cause of the
  15387.       error. A better approach, however, is to provide a replacement handler
  15388.       that treats Interrupt 00H much as MS-DOS treats Interrupt 24H.
  15389.  
  15390.  Single-Step (Interrupt 01H)
  15391.  
  15392.       If the trap flag (bit 8 of the microprocessor's 16-bit flags register)
  15393.       is set, Interrupt 01H occurs at the end of every instruction executed
  15394.       by the processor. By default, Interrupt 01H points to a simple IRET
  15395.       instruction, so the net effect is as if nothing happened. However,
  15396.       debugging programs, which are the only applications that use this
  15397.       interrupt, modify the interrupt vector to point to their own handlers.
  15398.       The interrupt can then be used to allow a debugger to single-step
  15399.       through the machine instructions of the program being debugged, as
  15400.       DEBUG does with its T (Trace) command.
  15401.  
  15402.  Nonmaskable Interrupt, or NMI (Interrupt 02H)
  15403.  
  15404.       In the hardware architecture of IBM PCs and close compatibles,
  15405.       Interrupt 02H is invoked whenever a memory parity error is detected.
  15406.       MS-DOS provides no handler, because this error, as a hardware-related
  15407.       problem, is in the domain of the ROM BIOS.
  15408.  
  15409.       In response to the Interrupt 02H, the default ROM BIOS handler
  15410.       displays a message and locks the machine, on the assumption that bad
  15411.       memory prevents reliable system operation. Many programmers, however,
  15412.       prefer to include code that permits orderly shutdown of the system.
  15413.       Replacing the ROM BIOS parity trap routine can be dangerous, though,
  15414.       because a parity error detected in memory means the contents of RAM
  15415.       are no longer reliable--even the memory locations containing the NMI
  15416.       handler itself might be defective.
  15417.  
  15418.  Breakpoint Trap (Interrupt 03H)
  15419.  
  15420.       Interrupt 03H, which is used in conjunction with Interrupt 01H for
  15421.       debugging, is invoked by a special 1-byte opcode (0CCH). During a
  15422.       debugging session, a debugger modifies the vector for Interrupt 03H to
  15423.       point to its own handler and then replaces 1 byte of program opcode
  15424.       with the 0CCH opcode at any location where a breakpoint is needed.
  15425.  
  15426.       When a breakpoint is reached, the 0CCH opcode triggers Interrupt 03H
  15427.       and the debugger regains control. The debugger then restores the
  15428.       original opcode in the program being debugged and issues a prompt so
  15429.       that the user can display or alter the contents of memory or
  15430.       registers. The use of Interrupt 03H is illustrated by DEBUG and
  15431.       SYMDEB's breakpoint capabilities.
  15432.  
  15433.  Overflow Trap (Interrupt 04H)
  15434.  
  15435.       If the overflow bit (bit 11) in the microprocessor's flags register is
  15436.       set, Interrupt 04H occurs when the INTO (Interrupt on Overflow)
  15437.       instruction is executed. The overflow bit can be set during prior
  15438.       execution of any arithmetic instruction (such as MUL or IMUL) that can
  15439.       produce an overflow error.
  15440.  
  15441.       The ROM BIOS of the IBM PC and close compatibles initializes the
  15442.       Interrupt 04H vector to point to an IRET, so this interrupt becomes
  15443.       invisible to the user if it is executed. MS-DOS does not have its own
  15444.       handler for Interrupt 04H. However, because the Intel microprocessors
  15445.       also include JO (Jump if Overflow) and JNO (Jump if No Overflow)
  15446.       instructions, applications rarely need the INTO instruction and,
  15447.       hence, seldom have to provide their own Interrupt 04H handlers.
  15448.  
  15449.  BOUND Range Exceeded (Interrupt 05H)
  15450.  
  15451.       Interrupt 05H is generated on 80186, 80286, and 80386 microprocessors
  15452.       if a BOUND instruction is executed to test the value of an array index
  15453.       and the index falls outside the limits specified by the instruction's
  15454.       operand. The exception handler is expected to alter the index so that
  15455.       it is correct--when the handler performs an interrupt return (IRET),
  15456.       the CPU reexecutes the BOUND instruction that caused the interrupt.
  15457.  
  15458.       On IBM PC/AT-compatible machines, the ROM BIOS assignment of the PrtSc
  15459.       (print screen) routine to Interrupt 05H is in conflict with the CPU's
  15460.       use of Interrupt 05H for BOUND exceptions.
  15461.  
  15462.  Invalid opcode (Interrupt 06H)
  15463.  
  15464.       Interrupt 06H is generated by the 80186, 80286, and 80386
  15465.       microprocessors if the current instruction is not a valid opcode--for
  15466.       example, if the machine tries to execute a data statement.
  15467.  
  15468.       On IBM PC/ATs, Interrupt 06H simply points to an IRET instruction. The
  15469.       ROM BIOS routines of some IBM PC/AT-compatibles, however, provide an
  15470.       interrupt handler that reports an unexpected software Interrupt 06H
  15471.       and asks if the user wants to continue. A Y response causes the
  15472.       interrupt handler to skip over the invalid opcode. Unfortunately,
  15473.       because the succeeding opcode is often invalid as well, the user may
  15474.       have the feeling of being trapped in a loop.
  15475.  
  15476.  
  15477.  Extended Error Information
  15478.  
  15479.       Under MS-DOS versions 1.x, the operating system provided limited
  15480.       information about errors that occurred during calls to the Interrupt
  15481.       21H system functions. For example, if a program called Function 0FH to
  15482.       open a file, there were only two possible results: On return, the AL
  15483.       register either contained 00H for a successful open or 0FFH for
  15484.       failure. No further detail was available from the operating system.
  15485.       Although some of these early system calls (such as the read and write
  15486.       functions) returned somewhat more information, the 1.x versions of MS-
  15487.       DOS were essentially limited to success/failure return codes.
  15488.  
  15489.       Beginning with version 2.0 and the introduction of the handle concept,
  15490.       additional error information became available. See PROGRAMMING IN THE
  15491.       MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: File and Record
  15492.       Management. For example, if a program attempts to open a file with
  15493.       Interrupt 21H Function 3DH (Open File with Handle), it can check the
  15494.       status of the carry flag on return to detect whether an error
  15495.       occurred. If the carry flag is not set, the call was successful and
  15496.       the AX register contains the file handle. If the carry flag is set,
  15497.       the AX register contains one of the following possible error codes:
  15498.  
  15499. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  15500.       Error Code       Meaning
  15501.       ──────────────────────────────────────────────────────────────────
  15502.       01H              Invalid function code
  15503.       02H              File not found
  15504.       03H              Path not found
  15505.       04H              Too many open files (no more handles available)
  15506.       05H              Access denied
  15507.       0CH              Invalid access code
  15508.  
  15509.       In some circumstances, however, even these error codes do not provide
  15510.       enough information. Therefore, beginning with version 3.0, MS-DOS made
  15511.       extended error information available through Interrupt 21H Function
  15512.       59H (Get Extended Error Information). This function can be called
  15513.       after any other Interrupt 21H function fails, or it can be called from
  15514.       a critical error handler. The extended error codes, briefly described
  15515.       below, maintain compatibility with the MS-DOS versions 2.x error
  15516.       returns and are grouped as follows:
  15517.  
  15518. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  15519.       Error Code       Error Group
  15520.       ──────────────────────────────────────────────────────────────────────
  15521.       Error Code       Error Group
  15522.       ──────────────────────────────────────────────────────────────────────
  15523.       00H              No error encountered.
  15524.  
  15525.       01-12H           MS-DOS versions 2.x and 3.x Interrupt 21H errors.
  15526.                        These error codes are identical to those returned in
  15527.                        the AX register by Functions 38H through 57H if the
  15528.                        carry flag is set on return from the function call.
  15529.  
  15530.       13-1FH           MS-DOS versions 2.x and 3.x Interrupt 24H errors.
  15531.                        These error codes are 13H (19) greater than the
  15532.                        codes passed to a critical error handler in the
  15533.                        lower half of the DI register; that is, if the
  15534.                        critical error handler receives error code 04H (CRC
  15535.                        error), Interrupt 21H Function 59H returns 17H.
  15536.  
  15537.       20-58H           Extended error codes, many related to networking and
  15538.                        file sharing, for MS-DOS versions 3.0 and later.
  15539.  
  15540.       Note: The contents of the CPU registers (except CS:IP and SS:SP) are
  15541.       destroyed by a call to Function 59H. Also, as mentioned earlier, this
  15542.       function is available only with MS-DOS versions 3.x, even though it
  15543.       maintains compatibility with error returns in versions 2.x.
  15544.  
  15545.       On return, Function 59H provides the extended error code in the AX
  15546.       register, the error class (type) in the BH register, a code for the
  15547.       suggested corrective action in the BL register, and the locus of the
  15548.       error in the CH register. These values are defined in the following
  15549.       paragraphs. With MS-DOS or PC-DOS versions 3.x, if an error 22H
  15550.       (invalid disk change) occurs and if the capability is supported by the
  15551.       system's block-device drivers, ES:DI points to an ASCIIZ volume label
  15552.       that designates the disk to be inserted in the drive before the
  15553.       operation is retried.
  15554.  
  15555.       Error Code (AX register). This value is defined as follows:
  15556.  
  15557. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  15558.       Value in AX      Meaning
  15559.       ──────────────────────────────────────────────────────────────────
  15560.       Interrupt 21H errors (MS-DOS versions 2.0 and later):
  15561.       01H              Invalid function number
  15562.       02H              File not found
  15563.       Value in AX      Meaning
  15564.      02H              File not found
  15565.       03H              Path not found
  15566.       04H              Too many open files (no handles available)
  15567.       05H              Access denied
  15568.       06H              Invalid handle
  15569.       07H              Memory control blocks destroyed
  15570.       08H              Insufficient memory
  15571.       09H              Invalid memory-block address
  15572.       0AH              Invalid environment
  15573.       0BH              Invalid format
  15574.       0CH              Invalid access code
  15575.       0DH              Invalid data
  15576.       0EH              Reserved
  15577.       0FH              Invalid disk drive specified
  15578.       10H              Attempt to remove the current directory
  15579.       11H              Not same device
  15580.       12H              No more files
  15581.       ──────────────────────────────────────────────────────────────────
  15582.       Interrupt 24H errors (MS-DOS versions 2.0 and later):
  15583.       13H              Attempt to write on write-protected disk
  15584.       Value in AX      Meaning
  15585.      13H              Attempt to write on write-protected disk
  15586.       14H              Unknown unit
  15587.       15H              Drive not ready
  15588.       16H              Invalid command
  15589.       17H              Data error based on cyclic redundancy check (CRC)
  15590.       18H              Length of request structure invalid
  15591.       19H              Seek error
  15592.       1AH              Unknown media type (non-MS-DOS disk)
  15593.       1BH              Sector not found
  15594.       1CH              Printer out of paper
  15595.       10H              Write fault
  15596.       1EH              Read fault
  15597.       1FH              General failure
  15598.       ──────────────────────────────────────────────────────────────────
  15599.       MS-DOS versions 3.x extended errors:
  15600.       20H              Sharing violation
  15601.       21H              Lock violation
  15602.       22H              Invalid disk change
  15603.       23H              FCB unavailable
  15604.       24H              Sharing buffer exceeded
  15605.       Value in AX      Meaning
  15606.      24H              Sharing buffer exceeded
  15607.       25H-31H          Reserved
  15608.       32H              Network request not supported
  15609.       33H              Remote computer not listening
  15610.       34H              Duplicate name on network
  15611.       35H              Network name not found
  15612.       36H              Network busy
  15613.       37H              Device no longer exists on network
  15614.       38H              Net BIOS command limit exceeded
  15615.       39H              Error in network adapter hardware
  15616.       3AH              Incorrect response from network
  15617.       3BH              Unexpected network error
  15618.       3CH              Incompatible remote adapter
  15619.       3DH              Print queue full
  15620.       3EH              Queue not full
  15621.       3FH              Not enough room for print file
  15622.       40H              Network name deleted
  15623.       41H              Access denied
  15624.       42H              Incorrect network device type
  15625.       43H              Network name not found
  15626.       Value in AX      Meaning
  15627.      43H              Network name not found
  15628.       44H              Network name limit exceeded
  15629.       45H              Net BIOS session limit exceeded
  15630.       46H              Temporary pause
  15631.       47H              Network request not accepted
  15632.       48H              Print or disk redirection paused
  15633.       49H-4FH          Reserved
  15634.       50H              File already exists
  15635.       51H              Reserved
  15636.       52H              Cannot make directory
  15637.       53H              Failure on Interrupt 24H
  15638.       54H              Out of structures
  15639.       55H              Already assigned
  15640.       56H              Invalid password
  15641.       57H              Invalid parameter
  15642.       58H              Network write fault
  15643.  
  15644.       Locus (CH register). This value provides information on the location
  15645.       of the error:
  15646.  
  15647. ╓┌────────────────────────┌──────────────────────────────────────────────────╖
  15648.       Value in CH         Meaning
  15649.       ──────────────────────────────────────────────────────────────────
  15650.       01H                 Location unknown
  15651.       02H                 Block device; generally caused by a disk error
  15652.       03H                 Network
  15653.       04H                 Serial device; generally caused by a timeout from
  15654.                           a character device
  15655.       05H                 Memory; caused by an error in RAM
  15656.  
  15657.       Error Class (BH register). This value gives the general category of
  15658.       the error:
  15659.  
  15660. ╓┌────────────────────────┌──────────────────────────────────────────────────╖
  15661.       Value in BH         Meaning
  15662.       ──────────────────────────────────────────────────────────────────
  15663.       01H                 Out of resource; out of storage space or I/O
  15664.                           channels.
  15665.  
  15666.       02H                 Temporary situation; expected to clear, as in a
  15667.                           file or record lock--generally occurs only in a
  15668.       Value in BH         Meaning
  15669.                          file or record lock--generally occurs only in a
  15670.                           network environment.
  15671.  
  15672.       03H                 Authorization; a problem with permission to access
  15673.                           the requested device.
  15674.  
  15675.       04H                 Internal error in system software; generally
  15676.                           reflects a system software bug rather than an
  15677.                           application or system failure.
  15678.  
  15679.       05H                 Hardware failure; a serious hardware-related
  15680.                           problem not the fault of the user program.
  15681.  
  15682.       06H                 System failure; a serious failure of the system
  15683.                           software, not directly the fault of the
  15684.                           application--generally occurs if configuration
  15685.                           files are missing or incorrect.
  15686.  
  15687.       07H                 Application-program error; generally caused by
  15688.                           inconsistent function requests from the user
  15689.       Value in BH         Meaning
  15690.                          inconsistent function requests from the user
  15691.                           program.
  15692.  
  15693.       08H                 File or item not found.
  15694.  
  15695.       09H                 File or item of invalid format or type detected,
  15696.                           or an otherwise unsuitable or invalid item
  15697.                           requested.
  15698.  
  15699.       0AH                 File or item interlocked by the system.
  15700.  
  15701.       0BH                 Media failure; generally occurs with a bad disk in
  15702.                           a drive, a bad spot on the disk, or the like.
  15703.  
  15704.       0CH                 Already exists; generally occurs when application
  15705.                           tries to declare a machine name or device that
  15706.                           already exists.
  15707.  
  15708.       0DH                 Unknown.
  15709.  
  15710.       Suggested Action (BL register). One of the most useful returns from
  15711.       Function 59H, this value suggests a corrective action to try:
  15712.  
  15713. ╓┌────────────────────────┌──────────────────────────────────────────────────╖
  15714.       Value in BL         Meaning
  15715.       ──────────────────────────────────────────────────────────────────
  15716.       01H                 Retry a few times before prompting the user to
  15717.                           choose Ignore for the program to continue or
  15718.                           Abort to terminate.
  15719.  
  15720.       02H                 Pause for a few seconds between retries and then
  15721.                           prompt user as above.
  15722.  
  15723.       03H                 Ask user to reenter the input. In most cases, this
  15724.                           solution applies when an incorrect drive
  15725.                           specifier or filename was entered. Of course, if
  15726.                           the value was hard-coded into the program, the
  15727.                           user should not be prompted for input.
  15728.  
  15729.       04H                 Clean up as well as possible, then abort the
  15730.                           application. This solution applies when the error
  15731.       Value in BL         Meaning
  15732.                          application. This solution applies when the error
  15733.                           is destructive enough that the application cannot
  15734.                           safely proceed, but the system is healthy enough
  15735.                           to try an orderly shutdown of the application.
  15736.  
  15737.       05H                 Exit from the application as soon as possible,
  15738.                           without trying to close files and clean up. This
  15739.                           means something is seriously wrong with either
  15740.                           the application or the system.
  15741.  
  15742.       06H                 Ignore; error is informational.
  15743.  
  15744.       07H                 Prompt user to perform some action, such as
  15745.                           changing floppy disks in a drive and then retry.
  15746.  
  15747.  
  15748.  Function 59H and older system calls
  15749.  
  15750.       The Interrupt 21H functions--primarily the FCB-related file and record
  15751.       calls--that return 0FFH in the AL register to indicate that an error
  15752.       has occurred but provide no further information about the type of
  15753.       error include
  15754.  
  15755. ╓┌─────────────────┌─────────────────────────────────────────────────────────╖
  15756.       Function     Name
  15757.       ──────────────────────────────────────────────────────────────────
  15758.       0FH          Open File with FCB
  15759.       10H          Close File with FCB
  15760.       11H          Find First File
  15761.       12H          Find Next File
  15762.       13H          Delete File
  15763.       16H          Create File with FCB
  15764.       17H          Rename File
  15765.       23H          Get File Size
  15766.  
  15767.       These function calls now exist only to maintain compatibility with
  15768.       MS-DOS versions 1.x. The preferred choices are the handle-style calls
  15769.       available in MS-DOS versions 2.0 and later, which offer full path
  15770.       support and much better error reporting. See also SYSTEM CALLS.
  15771.  
  15772.       If the older calls must be used, the program can use Function 59H to
  15773.       obtain more detailed information under MS-DOS version 3.0 or later.
  15774.       For example:
  15775.  
  15776.       myfcb   db      0               ; drive = default
  15777.               db      'MYFILE  '      ; filename, 8 chars
  15778.               db      'DAT'           ; extension, 3 chars
  15779.               db      25 dup (0)      ; remainder of FCB
  15780.               .
  15781.               .
  15782.               .
  15783.               mov     dx,seg myfcb    ; DS:DX = FCB
  15784.               mov     ds,dx
  15785.               mov     dx,offset myfcb
  15786.               mov     ah,0fh          ; function 0FH = Open FCB
  15787.  
  15788.               int     21h             ; transfer to MS-DOS
  15789.               or      al,al           ; test status
  15790.               jz      success         ; jump, open succeeded
  15791.                                       ; open failed, get
  15792.                                       ; extended error info
  15793.               mov     bx,0            ; BX = 00H for ver. 2.x-3.x
  15794.               mov     ah,59h          ; function 59H = Get Info
  15795.               int     21h             ; transfer to MS-DOS
  15796.               or      ax,ax           ; really an error?
  15797.               jz      success         ; no error, jump
  15798.                                       ; test recommended actions
  15799.               cmp     bl,01h
  15800.               jz      retry           ; if BL = 01H retry operation
  15801.               cmp     bl,04h
  15802.               jz      cleanup         ; if BL = 04H clean up and exit
  15803.               cmp     bl,05h
  15804.               jz      panic           ; if BL = 05H exit immediately
  15805.               .
  15806.               .
  15807.               .
  15808.  
  15809.  Function 59H and newer system calls
  15810.  
  15811.       The function calls listed below were added in MS-DOS versions 2.0 and
  15812.       later. These calls return with the carry flag set if an error occurs;
  15813.       in addition, the AX register contains an error value corresponding to
  15814.       error codes 01H through 12H of the extended error return codes:
  15815.  
  15816. ╓┌─────────────────┌─────────────────────────────────────────────────────────╖
  15817.       Function     Name
  15818.       ──────────────────────────────────────────────────────────────────
  15819.       MS-DOS versions 2.0 and later:
  15820.       38H          Get/Set Current Country
  15821.       39H          Create Directory
  15822.       3AH          Remove Directory
  15823.       3BH          Change Current Directory
  15824.       3CH          Create File with Handle
  15825.       3DH          Open File with Handle
  15826.       3EH          Close File
  15827.       3FH          Read File or Device
  15828.       40H          Write File or Device
  15829.       41H          Delete File
  15830.       42H          Move File Pointer
  15831.       43H          Get/Set File Attributes
  15832.       44H          IOCTL (I/O Control for Devices)
  15833.       45H          Duplicate File Handle
  15834.       46H          Force Duplicate File Handle
  15835.       47H          Get Current Directory
  15836.       Function     Name
  15837.      47H          Get Current Directory
  15838.       48H          Allocate Memory Block
  15839.       49H          Free Memory Block
  15840.       4AH          Resize Memory Block
  15841.       4BH          Load and Execute Program (EXEC)
  15842.       4EH          Find First File
  15843.       4FH          Find Next File
  15844.       56H          Rename File
  15845.       57H          Get/Set Date/Time of File
  15846.       ──────────────────────────────────────────────────────────────────
  15847.       MS-DOS versions 3.0 and later:
  15848.       58H          Get/Set Allocation Strategy
  15849.       5AH          Create Temporary File
  15850.       5BH          Create New File
  15851.       5CH          Lock/Unlock File Region
  15852.       ──────────────────────────────────────────────────────────────────
  15853.       MS-DOS versions 3.1 and later:
  15854.       5EH          Network Machine Name/Printer Setup
  15855.       5FH          Get/Make Assign List Entry
  15856.  
  15857.       Although these newer functions have much better error reporting than
  15858.       the older FCB functions, Function 59H is still useful. Regardless of
  15859.       the version of MS-DOS that is running, the error code returned in the
  15860.       AX register from an Interrupt 21H function call is always in the range
  15861.       0-12H. If a program is running under MS-DOS versions 3.x and wants to
  15862.       obtain one or more of the more specific error codes in the range 20-
  15863.       58H, the program must follow the failed Interrupt 21H call with a
  15864.       subsequent call to Interrupt 21H Function 59H. The program can then
  15865.       use the code returned by Function 59H in the BL register as a guide to
  15866.       the action to take in response to the error. For example:
  15867.  
  15868.       myfile  db      'MYFILE.DAT',0  ; ASCIIZ filename
  15869.               .
  15870.               .
  15871.               .
  15872.               mov     dx,seg myfile   ; DS:DX = ASCIIZ filename
  15873.               mov     ds,dx
  15874.               mov     dx,offset myfile
  15875.               mov     ax,3d02h        ; open, read/write
  15876.               int     21h             ; transfer to MS-DOS
  15877.               jnc     success         ; jump, open succeeded
  15878.                                       ; open failed, get
  15879.                                       ; extended error info
  15880.               mov     bx,0            ; BX = 00H for ver. 2.x-3.x
  15881.               mov     ah,59h          ; function 59H = Get Info
  15882.               int     21h             ; transfer to MS-DOS
  15883.               or      ax,ax           ; really an error?
  15884.               jz      success         ; no error, jump
  15885.                                       ; test recommended actions
  15886.               cmp     bl,01h
  15887.               jz      retry           ; if BL = 01H retry operation
  15888.               .
  15889.               .
  15890.               .
  15891.  
  15892.       If the standard critical error handler is replaced with a customized
  15893.       critical handler, Function 59H can also be used to obtain more
  15894.       detailed information about an error inside the handler before either
  15895.       returning control to the application or aborting. The value in the BL
  15896.       register should be used to determine the appropriate action to take or
  15897.       the message to display to the user.
  15898.  
  15899.                                                    Jim Kyle
  15900.                                                    Chip Rabinowitz
  15901.  
  15902.  
  15903.  
  15904.  Article 13: Hardware Interrupt Handlers
  15905.  
  15906.  
  15907.       Unlike software interrupts, which are service requests initiated by a
  15908.       program, hardware interrupts occur in response to electrical signals
  15909.       received from a peripheral device such as a serial port or a disk
  15910.       controller, or they are generated internally by the microprocessor
  15911.       itself. Hardware interrupts, whether external or internal to the
  15912.       microprocessor, are given prioritized servicing by the Intel CPU
  15913.       architecture.
  15914.  
  15915.       The 8086 family of microprocessors (which includes the 8088, 8086,
  15916.       80186, 80286, and 80386) reserves the first 1024 bytes of memory
  15917.       (addresses 0000:0000H through 0000:03FFH) for a table of 256 interrupt
  15918.       vectors, each a 4-byte far pointer to a specific interrupt service
  15919.       routine (ISR) that is carried out when the corresponding interrupt is
  15920.       processed. The design of the 8086 family requires certain of these
  15921.       interrupt vectors to be used for specific functions (Table 13-1).
  15922.       Although Intel actually reserves the first 32 interrupts, IBM, in the
  15923.       original PC, redefined usage of Interrupts 05H to 1FH. Most, but not
  15924.       all, of these reserved vectors are used by software, rather than
  15925.       hardware, interrupts; the redefined IBM uses are listed in Table 13-2.
  15926.  
  15927.  
  15928.       Table 13-1. Intel Reserved Exception Interrupts.
  15929.  
  15930. ╓┌────────────────────────┌──────────────────────────────────────────────────╖
  15931.       Interrupt Number    Definition
  15932.       ──────────────────────────────────────────────────────────────────
  15933.       00H                 Divide by zero
  15934.       01H                 Single step
  15935.       02H                 Nonmaskable interrupt (NMI)
  15936.       03H                 Breakpoint trap
  15937.       04H                 Overflow trap
  15938.       05H                 BOUND range exceeded1
  15939.       06H                 Invalid opcode1
  15940.       07H                 Coprocessor not available2
  15941.       Interrupt Number    Definition
  15942.      07H                 Coprocessor not available2
  15943.       08H                 Double-fault exception2
  15944.       09H                 Coprocessor segment overrun2
  15945.       0AH                 Invalid task state segment (TSS)2
  15946.       0BH                 Segment not present2
  15947.       0CH                 Stack exception2
  15948.       0DH                 General protection exception2
  15949.       0EH                 Page fault3
  15950.       0FH                 (Reserved)
  15951.       10H                 Coprocessor error2
  15952.  
  15953.  
  15954.       Table 13-2. IBM Interrupt Usage.
  15955.  
  15956. ╓┌────────────────────────┌──────────────────────────────────────────────────╖
  15957.       Interrupt Number    Definition
  15958.       ──────────────────────────────────────────────────────────────────
  15959.       05H                 Print screen
  15960.       06H                 Unused
  15961.       07H                 Unused
  15962.       Interrupt Number    Definition
  15963.      07H                 Unused
  15964.       08H                 Hardware IRQ0 (timer-tick)1
  15965.       09H                 Hardware IRQ1 (keyboard)
  15966.       0AH                 Hardware IRQ2 (reserved)2
  15967.       0BH                 Hardware IRQ3 (COM2)
  15968.       0CH                 Hardware IRQ4 (COM1)
  15969.       0DH                 Hardware IRQ5 (fixed disk)
  15970.       0EH                 Hardware IRQ6 (floppy disk)
  15971.       0FH                 Hardware IRQ7 (printer)
  15972.       10H                 Video service
  15973.       11H                 Equipment information
  15974.       12H                 Memory size
  15975.       13H                 Disk I/O service
  15976.       14H                 Serial-port service
  15977.       15H                 Cassette/network service
  15978.       16H                 Keyboard service
  15979.       17H                 Printer service
  15980.       18H                 ROM BASIC
  15981.       19H                 Restart system
  15982.       1AH                 Get/Set time/date
  15983.       Interrupt Number    Definition
  15984.      1AH                 Get/Set time/date
  15985.       1BH                 Control-Break (user defined)
  15986.       1CH                 Timer tick (user defined)
  15987.       1DH                 Video parameter pointer
  15988.       1EH                 Disk parameter pointer
  15989.       1FH                 Graphics character table
  15990.  
  15991.  
  15992.       Nestled in the middle of Table 13-2 are the eight hardware interrupt
  15993.       vectors (08-0FH) IBM implemented in the original PC design. These
  15994.       eight vectors provide the maskable interrupts for the IBM PC-family
  15995.       and close compatibles. Additional IRQ lines built into the IBM PC/AT
  15996.       are discussed under The IRQ Levels below.
  15997.  
  15998.       The conflicting uses of the interrupts listed in Tables 13-1 and 13-2
  15999.       have created compatibility problems as the 8086 family of
  16000.       microprocessors has developed. For complete compatibility with IBM
  16001.       equipment, the IBM usage must be followed even when it conflicts with
  16002.       the chip design. For example, a BOUND error occurs if an array index
  16003.       exceeds the specified upper and lower limits (bounds) of the array,
  16004.       causing an Interrupt 05H to be generated. But the 80286 processor used
  16005.       in all AT-class computers will, if a BOUND error occurs, send the
  16006.       contents of the display to the printer, because IBM uses Interrupt 05H
  16007.       for the Print Screen function.
  16008.  
  16009.  
  16010.  Hardware Interrupt Categories
  16011.  
  16012.       The 8086 family of microprocessors can handle three types of hardware
  16013.       interrupts. First are the internal, microprocessor-generated exception
  16014.       interrupts (Table 13-1). Second is the nonmaskable interrupt, or NMI
  16015.       (Interrupt 02H), which is generated when the NMI line (pin 17 on the
  16016.       8088 and 8086, pin 59 on the 80286, pin B8 on the 80386) goes high
  16017.       (active). In the IBM PC family (except the PCjr and the Convertible),
  16018.       the nonmaskable interrupt is designated for memory parity errors.
  16019.       Third are the maskable interrupts, which are usually generated by
  16020.       external devices.
  16021.  
  16022.       Maskable interrupts are routed to the main processor through a chip
  16023.       called the 8259A Programmable Interrupt Controller (PIC). When it
  16024.       receives an interrupt request, the PIC signals the microprocessor that
  16025.       an interrupt needs service by driving the interrupt request (INTR)
  16026.       line of the main processor to high voltage level. This article focuses
  16027.       on the maskable interrupts and the 8259A because it is through the PIC
  16028.       that external I/O devices (disk drives, serial communication ports,
  16029.       and so forth) gain access to the interrupt system.
  16030.  
  16031.  Interrupt priorities in the 8086 family
  16032.  
  16033.       The Intel microprocessors have a built-in priority system for handling
  16034.       interrupts that occur simultaneously. Priority goes to the internal
  16035.       instruction exception interrupts, such as Divide by Zero and Invalid
  16036.       Opcode, because priority is determined by the interrupt number:
  16037.       Interrupt 00H takes priority over all others, whereas the last
  16038.       possible interrupt, 0FFH, would, if present, never be allowed to break
  16039.       in while another interrupt was being serviced. However, if interrupt
  16040.       service is enabled (the microprocessor's interrupt flag is set), any
  16041.       hardware interrupt takes priority over any software interrupt (INT
  16042.       instruction).
  16043.  
  16044.       The priority sequencing by interrupt number must not be confused with
  16045.       the priority resolution performed by hardware external to the
  16046.       microprocessor. The numeric priority discussed here applies only to
  16047.       interrupts generated within the 8086 family of microprocessor chips
  16048.       and is totally independent of system interrupt priorities established
  16049.       for components external to the microprocessor itself.
  16050.  
  16051.  Interrupt service routines
  16052.  
  16053.       For the most part, programmers need not write hardware-specific
  16054.       program routines to service the hardware interrupts. The IBM PC BIOS
  16055.       routines, together with MS-DOS services, are usually sufficient. In
  16056.       some cases, however, MS-DOS and the ROM BIOS do not provide enough
  16057.       assistance to ensure adequate performance of a program. Most notable
  16058.       in this category is communications software, for which programmers
  16059.       usually must access the 8259A and the 8250 Universal Asynchronous
  16060.       Receiver and Transmitter (UART) directly. See PROGRAMMING IN THE
  16061.       MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: Interrupt-Driven
  16062.       Communications.
  16063.  
  16064.  
  16065.  Characteristics of Maskable Interrupts
  16066.  
  16067.       Two major characteristics distinguish maskable interrupts from all
  16068.       other events that can occur in the system: They are totally
  16069.       unpredictable, and they are highly volatile. In general, a hardware
  16070.       interrupt occurs when a peripheral device requires the full attention
  16071.       of the system and data will be irretrievably lost unless the system
  16072.       responds rapidly.
  16073.  
  16074.       All things are relative, however, and this is especially true of the
  16075.       speed required to service an interrupt request. For example, assume
  16076.       that two interrupt requests occur at essentially the same time. One is
  16077.       from a serial communications port receiving data at 300 bps; the other
  16078.       is from a serial port receiving data at 9600 bps. Data from the first
  16079.       serial port will not change for at least 30 milliseconds, but the
  16080.       second serial port must be serviced within one millisecond to avoid
  16081.       data loss.
  16082.  
  16083.  Unpredictability
  16084.  
  16085.       Because maskable interrupts generally originate in response to
  16086.       external physical events, such as the receipt of a byte of data over a
  16087.       communications line, the exact time at which such an interrupt will
  16088.       occur cannot be predicted. Even the timer interrupt request, which by
  16089.       default occurs approximately 18.2 times per second, cannot be
  16090.       predicted by any program that happens to be executing when the
  16091.       interrupt request occurs.
  16092.  
  16093.       Because of this unpredictability, the system must, if it allows any
  16094.       interrupts to be recognized, be prepared to service all maskable
  16095.       interrupt requests. Conversely, if interrupts cannot be serviced, they
  16096.       must all be disabled. The 8086 family of microprocessors provides the
  16097.       Set Interrupt Flag (STI) instruction to enable maskable interrupt
  16098.       response and the Clear Interrupt Flag (CLI) instruction to disable it.
  16099.       The interrupt flag is also cleared automatically when a hardware
  16100.       interrupt response begins; the interrupt handler should execute STI as
  16101.       quickly as possible to allow higher priority interrupts to be
  16102.       serviced.
  16103.  
  16104.  Volatility
  16105.  
  16106.       As noted earlier, a maskable interrupt request must normally be
  16107.       serviced immediately to prevent loss of data, but the concept of
  16108.       immediacy is relative to the data transfer rate of the device
  16109.       requesting the interrupt. The rule is that the currently available
  16110.       unit of data must be processed (at least to the point of being stored
  16111.       in a buffer) before the next such item can arrive. Except for such
  16112.       devices as disk drives, which always require immediate response,
  16113.       interrupts for devices that receive data are normally much more
  16114.       critical than interrupts for devices that transmit data.
  16115.  
  16116.       The problems imposed by data volatility during hardware interrupt
  16117.       service are solved by establishing service priorities for interrupts
  16118.       generated outside the microprocessor chip itself. Devices with the
  16119.       slowest transfer rates are assigned lower interrupt service
  16120.       priorities, and the most time-critical devices are assigned the
  16121.       highest priority of interrupt service.
  16122.  
  16123.  
  16124.  Handling Maskable Interrupts
  16125.  
  16126.       The microprocessor handles all interrupts (maskable, nonmaskable, and
  16127.       software) by pushing the contents of the flags register onto the
  16128.       stack, disabling the interrupt flag, and pushing the current contents
  16129.       of the CS:IP registers onto the stack.
  16130.  
  16131.       The microprocessor then takes the interrupt number from the data bus,
  16132.       multiplies it by 4 (the size of each vector in bytes), and uses the
  16133.       result as an offset into the interrupt vector table located in the
  16134.       bottom 1 KB (segment 0000H) of system RAM. The 4-byte address at that
  16135.       location is then used as the new CS:IP value (Figure 13-1).
  16136.  
  16137.  
  16138.       ┌────────────────────┐
  16139.       │     Push flags     │
  16140.       └─────────┬──────────┘
  16141.       ┌───────────────────┐
  16142.       │ Disable interrupts │
  16143.       └─────────┬──────────┘
  16144.       ┌───────────────────┐
  16145.       │     Push CS:IP     │
  16146.       └─────────┬──────────┘
  16147.       ┌───────────────────┐
  16148.       │ Get address of ISR │
  16149.       │    from table;     │
  16150.       │   place in CS:IP   │
  16151.       └─────────┬──────────┘
  16152.       ┌───────────────────┐
  16153.       │ Process interrupt  │
  16154.       └─────────┬──────────┘
  16155.       ┌───────────────────┐
  16156.       │        IRET        │
  16157.       └─────────┬──────────┘
  16158.       ┌───────────────────┐
  16159.       │Restore CS:IP, flags│
  16160.       └────────────────────┘
  16161.  
  16162.       Figure 13-1. General interrupt sequence.
  16163.  
  16164.  
  16165.       External devices are assigned dedicated interrupt request lines (IRQs)
  16166.       associated with the 8259A. See The IRQ Levels below. When a device
  16167.       requires attention, it sends a signal to the PIC via its IRQ line. The
  16168.       PIC, which functions as an "executive secretary" for the external
  16169.       devices, operates as shown in Figure 13-2. It evaluates the service
  16170.       request and, if appropriate, causes the microprocessor's INTR line to
  16171.       go high. The microprocessor then checks whether interrupts are enabled
  16172.       (whether the interrupt flag is set). If they are, the flags are pushed
  16173.       onto the stack, the interrupt flag is disabled, and CS:IP is pushed
  16174.       onto the stack.
  16175.  
  16176.  
  16177.            DEVICE                    8259A       MICROPROCESSOR
  16178.                                    ┌────────┐
  16179.                                            │    ┌────────┐
  16180.                                            │    │Process │────┐
  16181.                                  /   \      │    └────┬───┘     │
  16182.          ┌───────────────┐IRQ  /  Any  \ No │                  │
  16183.          │Signals request├───  IRQs   ───┘                  │
  16184.          └───────────────┘     \active?/           /   \       │
  16185.                                  \   /      │     / INTR  \  No │
  16186.                                            │ ┌─  high?  ────┘
  16187.                                     Yes    │ │   \       /     
  16188.                                            │ │     \   /       │
  16189.                                  /   \      │ │                │
  16190.                                /Is this\ Yes│ │        Yes     │
  16191.                                  INT   ───┘ │                │
  16192.                                \masked off?  │     /   \       │
  16193.                                  \   /      │ │   / INTs  \  No │
  16194.                                            │ │   enabled?────┘
  16195.                                     No     │ │   \       /
  16196.                                            │ │     \   /
  16197.                                  /   \      │ │       
  16198.                                / INT   \ Yes│ │        Yes
  16199.                                 being  ───┘ │ ┌────────────┐
  16200.                                \serviced?     │ │ Push flags │
  16201.                                  \   /        │ └────────────┘
  16202.                                     No       │        
  16203.                                              │ ┌─────────────┐
  16204.                            ┌──────────────┐   │ │ Disable INTs│
  16205.                            │Signal request├───┘ └──────┬──────┘
  16206.                            └──────────────┘INTR        
  16207.                                                 ┌─────────────┐
  16208.                                                 │  Push CS:IP │
  16209.                                                 └──────┬──────┘
  16210.                                                        
  16211.                                                 ┌─────────────┐
  16212.                                       ────      │ Acknowledge │
  16213.                                       INTA      │     INT     │
  16214.                 ┌────────────────┐─────────────┴─────────────┘
  16215.                 │Place INT number│
  16216.                 │   on data bus  ├─────────────┌─────────────┐
  16217.                 └────────────────┘  Data bus    │  Get INT    │
  16218.                                                 │   number    │
  16219.                                                 └──────┬──────┘
  16220.                                                        
  16221.                                                 ┌─────────────┐
  16222.                                                 │  Calculate  │
  16223.                                                 │  new CS:IP  │
  16224.                                                 └─────────────┘
  16225.  
  16226.       Figure 13-2. Maskable interrupt service.
  16227.  
  16228.  
  16229.       The microprocessor acknowledges the interrupt request by signaling the
  16230.       8259A via the interrupt acknowledge (INTA) line. The 8259A then places
  16231.       the interrupt number on the data bus. The microprocessor gets the
  16232.       interrupt number from the data bus and services the interrupt. Before
  16233.       issuing the IRET instruction, the interrupt service routine must issue
  16234.       an end-of-interrupt (EOI) sequence to the 8259A so that other
  16235.       interrupts can be processed. This is done by sending 20H to port 20H.
  16236.       (The similarity of numbers is pure coincidence.) The EOI sequence is
  16237.       covered in greater detail elsewhere. See PROGRAMMING IN THE MS-DOS
  16238.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: Interrupt-Driven Communications.
  16239.  
  16240.  The 8259A Programmable Interrupt Controller
  16241.  
  16242.       The 8259A (Figure 13-3) has a number of internal components, many of
  16243.       them under software control. Only the default settings for the IBM PC
  16244.       family are covered here.
  16245.  
  16246.       Three registers influence the servicing of maskable interrupts: the
  16247.       interrupt request register (IRR), the in-service register (ISR), and
  16248.       the interrupt mask register (IMR).
  16249.  
  16250.       The IRR is used to keep track of the devices requesting attention.
  16251.       When a device causes its IRQ line to go high to signal the 8259A that
  16252.       it needs service, a bit is set in the IRR that corresponds to the
  16253.       interrupt level of the device.
  16254.  
  16255.       The ISR specifies which interrupt levels are currently being serviced;
  16256.       an ISR bit is set when an interrupt has been acknowledged by the CPU
  16257.       (via INTA) and the interrupt number has been placed on the data bus.
  16258.       The ISR bit associated with a particular IRQ remains set until an EOI
  16259.       sequence is received.
  16260.  
  16261.       The IMR is a read/write register (at port 21H) that masks (disables)
  16262.       specific interrupts. When a bit is set in this register, the
  16263.       corresponding IRQ line is masked and no servicing for it is performed
  16264.       until the bit is cleared. Thus, a particular IRQ can be disabled while
  16265.       all others continue to be serviced.
  16266.  
  16267.       The fourth major block in Figure 13-3, labeled Priority resolver, is a
  16268.       complex logical circuit that forms the heart of the 8259A. This
  16269.       component combines the statuses of the IMR, the ISR, and the IRR to
  16270.       determine which, if any, pending interrupt request should be serviced
  16271.       and then causes the microprocessor's INTR line to go high. The
  16272.       priority resolver can be programmed in a number of modes, although
  16273.       only the mode used in the IBM PC and close compatibles is described
  16274.       here.
  16275.  
  16276.  
  16277.   <────────────────────────────────────────────────────────>
  16278.   <                                                        >
  16279.   <                        DATA BUS                        >
  16280.   <                                                        >
  16281.   <───────────────────────────────────────────────────────>
  16282.          ║
  16283.          ║
  16284.   <──────╨─────────────────────────────────────────────────>
  16285.   <                                                        >
  16286.   <                      CONTROL BUS                       >
  16287.   <                                                        >
  16288.   <──────╥──────────┬─────────────────────────────────────>
  16289.          ║          │ ────                        │
  16290.          ║          │ INTA                        │ INT
  16291.   - - - -║- - - - - │  - - - - - - - - - - - - - -│- - - - - -
  16292.  |       ║     ┌─────────────────────────────────┴───┐       |
  16293.  |       ║     │            Control logic             │       |
  16294.  |       ║     │                                      │       |
  16295.  |            └┬───────────────────────────────────┘       |
  16296.  | <────────────┴──────────────────┴─────────────────┴──────> |
  16297.  | <                          INTERNAL BUS                  > |
  16298.  | <──────────┬──────────────────┬─────────────────┬─────> |
  16299.  |    ║  ┌───╨────────┐    ┌────────────┐   ┌──────┴──╨───┐ |
  16300.  |    ║  │             │    │             │   │             │--IRQ0 ▒
  16301.  |    ║  │             │    │             │   │             │--IRQ1 ▒
  16302.  |    ║  │ In-service  │    │  Priority   │   │  Interrupt  │--IRQ2 ▒
  16303.  |    ║  │  register   │══│  resolver   │══╡   request   │--IRQ3 ▒IRQ
  16304.  |    ║  │    (ISR)    │    │             │   │  register   │--IRQ4 ▒ lines
  16305.  |    ║  │             │    │             │   │    (IRR)    │--IRQ5 ▒
  16306.  |    ║  │             │    │             │   │             │--IRQ6 ▒
  16307.  |    ║  │             │    │             │   │             │--IRQ7 ▒
  16308.  |    ║  └─────────────┘    └─────────────┘   └─────────────┘ |
  16309.  |    ║                                                    |
  16310.  |    ║         ┌───┴──────────────┴─────────────┴───┐        |
  16311.  |    ║         │      Interrupt mask register       │        |
  16312.  |    ╚════════│               (IMR)                │        |
  16313.  |              └────────────────────────────────────┘        |
  16314.   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  16315.  
  16316.       Figure 13-3. Block diagram of the 8259A Programmable Interrupt
  16317.       Controller.
  16318.  
  16319.  
  16320.  The IRQ levels
  16321.  
  16322.       When two or more unserviced hardware interrupts are pending, the 8259A
  16323.       determines which should be serviced first. The standard mode of
  16324.       operation for the PIC is the fully nested mode, in which IRQ lines are
  16325.       prioritized in a fixed sequence. Only IRQ lines with higher priority
  16326.       than the one currently being serviced are permitted to generate new
  16327.       interrupts.
  16328.  
  16329.       The highest priority is IRQ0, and the lowest is IRQ7. Thus, if an
  16330.       Interrupt 09H (signaled by IRQ1) is being serviced, only an Interrupt
  16331.       08H (signaled by IRQ0) can break in. All other interrupt requests are
  16332.       delayed until the Interrupt 09H service routine is completed and has
  16333.       issued an EOI sequence.
  16334.  
  16335.  Eight-level designs
  16336.       The IBM PC, PCjr, and PC/XT (and port-compatible computers) have eight
  16337.       IRQ lines to the PIC chip--IRQ0 through IRQ7. These lines are mapped
  16338.       into interrupt vectors for Interrupts 08H through 0FH (that is, 8 +
  16339.       IRQ level). These eight IRQ lines and their associated interrupts are
  16340.       listed in Table 13-3.
  16341.  
  16342.  
  16343.       Table 13-3. Eight-Level Interrupt Map.
  16344.  
  16345. ╓┌─────────────────────┌─────────────────┌───────────────────────────────────╖
  16346.       IRQ Line         Interrupt         Description
  16347.       ──────────────────────────────────────────────────────────────────────
  16348.       IRQ0             08H               Timer tick, 18.2 times per second
  16349.       IRQ1             09H               Keyboard service required
  16350.       IRQ2             0AH               I/O channel (unused on IBM PC/XT)
  16351.       IRQ3             0BH               COM1 service required
  16352.       IRQ4             0CH               COM2 service required
  16353.       IRQ5             0DH               Fixed-disk service required
  16354.       IRQ6             0EH               Floppy-disk service required
  16355.       IRQ7             0FH               Data request from parallel printer1
  16356.  
  16357.  
  16358.  Sixteen-level designs
  16359.       In the IBM PC/AT, 8 more IRQ levels have been added by using a second
  16360.       8259A PIC (the "slave") and a cascade effect, which gives 16 priority
  16361.       levels.
  16362.  
  16363.       The cascade effect is accomplished by connecting the INT line of the
  16364.       slave to the IRQ2 line of the first, or "master," 8259A instead of to
  16365.       the microprocessor. When a device connected to one of the slave's IRQ
  16366.       lines makes an interrupt request, the INT line of the slave goes high
  16367.       and causes the IRQ2 line of the master 8259A to go high, which, in
  16368.       turn, causes the INT line of the master to go high and thus interrupts
  16369.       the microprocessor.
  16370.  
  16371.       The microprocessor, ignorant of the second 8259A's presence, simply
  16372.       generates an interrupt acknowledge signal on receipt of the interrupt
  16373.       from the master 8259A. This signal initializes both 8259As and also
  16374.       causes the master to turn control over to the slave. The slave then
  16375.       completes the interrupt request.
  16376.  
  16377.       On the IBM PC/AT, the eight additional IRQ lines are mapped to
  16378.       Interrupts 70H through 77H (Table 13-4). Because the eight additional
  16379.       lines are effectively connected to the master 8259A's IRQ2 line, they
  16380.       take priority over the master's IRQ3 through IRQ7 events. The cascade
  16381.       effect is graphically represented in Figure 13-4.
  16382.  
  16383.  
  16384.       Table 13-4. Sixteen-Level Interrupt Map.
  16385.  
  16386. ╓┌─────────────────────┌─────────────────┌───────────────────────────────────╖
  16387.       IRQ Line         Interrupt         Description
  16388.       ──────────────────────────────────────────────────────────────────
  16389.       IRQ0             08H               Timer tick, 18.2 times per second
  16390.       IRQ1             09H               Keyboard service required
  16391.       IRQ2             0AH               INT from slave 8259A:
  16392.       IRQ8             70H                   Real-time clock service
  16393.       IRQ9             71H                   Software redirected to IRQ2
  16394.       IRQ10            72H                   Reserved
  16395.       IRQ11            73H                   Reserved
  16396.       IRQ12            74H                   Reserved
  16397.       IRQ13            75H                   Numeric coprocessor
  16398.       IRQ14            76H                   Fixed-disk controller
  16399.       IRQ15            77H                   Reserved
  16400.       IRQ3             0BH               COM2 service required
  16401.       IRQ4             0CH               COM1 service required
  16402.       IRQ5             0DH               Data request from LPT2
  16403.       IRQ Line         Interrupt         Description
  16404.      IRQ5             0DH               Data request from LPT2
  16405.       IRQ6             0EH               Floppy-disk service required
  16406.       IRQ7             0FH               Data request from LPT1
  16407.  
  16408.  
  16409.  <───────────────────────────────────────────────────────────────>
  16410.  <                                                               >
  16411.  <                            DATA BUS                           >
  16412.  <                                                               >
  16413.  <─────────────────────────────────────────────────────────────>
  16414.             ║                              ║
  16415.             ║                              ║
  16416.  <──────────╨──────────────────────────────╨─────────────────────>
  16417.  <                                                               >
  16418.  <                          CONTROL BUS                          >
  16419.  <                                                               >
  16420.  <──────────╥──────┬───────────────────────╥────────┬───────────>
  16421.             ║      │                       ║        │        │
  16422.             ║      │     ┌───────┐         ║        │        │
  16423.   ┌────────────────────┴───┐   │   ┌─────────────────────┴──┐
  16424.   │              ────        │   │   │             ────         │
  16425.   │              INTA   INT  ═══╪═══╡             INTA   INT   │
  16426.   │       Slave 8259A        │Control│       Master 8259A       │
  16427.   └──────────────────────────┘ lines └──────────────────────────┘
  16428.                          │                    
  16429.      │  │  │  │  │  │  │  │      │      │  │  │  │  │  │  │  │
  16430.    IRQ15│IRQ13│IRQ11│IRQ9 │      │    IRQ7 │IRQ5 │IRQ3 │IRQ1 │
  16431.         │     │     │     │      │         │     │     │     │
  16432.      IRQ14 IRQ12 IRQ10 IRQ8      │      IRQ6  IRQ4     │  IRQ0
  16433.                                  └─────────────────────┘
  16434.  
  16435.       Figure 13-4. A graphic representation of the cascade effect for IRQ
  16436.       priorities.
  16437.  
  16438.  
  16439.       Note: During the INTA sequence, the corresponding bit in the ISR
  16440.       register of both 8259As is set, so two EOIs must be issued to complete
  16441.       the interrupt service--one for the slave and one for the master.
  16442.  
  16443.  
  16444.  Programming for the Hardware Interrupts
  16445.  
  16446.       Any program that modifies an interrupt vector must restore the vector
  16447.       to its original condition before returning control to MS-DOS (or to
  16448.       its parent process). Any program that totally replaces an existing
  16449.       hardware interrupt handler with one of its own must perform all the
  16450.       handshaking and terminating actions of the original--reenable
  16451.       interrupt service, signal EOI to the interrupt controller, and so
  16452.       forth. Failure to follow these rules has led to many hours of
  16453.       programmer frustration. See also PROGRAMMING IN THE MS-DOS
  16454.       ENVIRONMENT: CUSTOMIZING MS-DOS: Exception Handlers.
  16455.  
  16456.       When an existing interrupt handler is completely replaced with a new,
  16457.       customized routine, the existing vector must be saved so it can be
  16458.       restored later. Although it is possible to modify the 4-byte vector by
  16459.       directly addressing the vector table in low RAM (and many published
  16460.       programs have followed this practice), any program that does so runs
  16461.       the risk of causing system failure when the program is used with
  16462.       multitasking or multiuser enhancements or with future versions of MS-
  16463.       DOS. The only technique that can be recommended for either obtaining
  16464.       the existing vector values or changing them is to use the MS-DOS
  16465.       functions provided for this purpose: Interrupt 21H Functions 25H (Set
  16466.       Interrupt Vector) and 35H (Get Interrupt Vector).
  16467.  
  16468.       After the existing vector has been saved, it can be replaced with a
  16469.       far pointer to the replacement routine. The new routine must end with
  16470.       an IRET instruction. It should also take care to preserve all
  16471.       microprocessor registers and conditions at entry and restore them
  16472.       before returning.
  16473.  
  16474.  A sample replacement handler
  16475.  
  16476.       Suppose a program performs many mathematical calculations of random
  16477.       values. To prevent abnormal termination of the program by the default
  16478.       MS-DOS Interrupt 00H handler when a DIV or IDIV instruction is
  16479.       attempted and the divisor is zero, a programmer might want to replace
  16480.       the Interrupt 00H (Divide by Zero) routine with one that informs the
  16481.       user of what has happened and then continues operation without
  16482.       abnormal termination. The .COM program DIVZERO.ASM (Figure 13-5) does
  16483.       just that. (Another example is included in the article on interrupt-
  16484.       driven communications. See PROGRAMMING IN THE MS-DOS ENVIRONMENT:
  16485.       PROGRAMMING FOR MS-DOS: Interrupt-Driven Communications.)
  16486.  
  16487.       ──────────────────────────────────────────────────────────────────────
  16488.  
  16489.       Figure 13-5. The Divide by Zero replacement handler, DIVZERO.ASM. This
  16490.       code is specific to 80286 and 80386 microprocessors. (See Appendix M:
  16491.       8086/8088 Software Compatibility Issues.)
  16492.  
  16493.       ──────────────────────────────────────────────────────────────────────
  16494.  
  16495.  Supplementary handlers
  16496.  
  16497.       In many cases, a custom interrupt handler augments, rather than
  16498.       replaces, the existing routine. The added routine might process some
  16499.       data before passing the data to the existing routine, or it might do
  16500.       the processing afterward. These cases require slightly different
  16501.       coding for the handler.
  16502.  
  16503.       If the added routine is to process data before the existing handler
  16504.       does, the routine need only jump to the original handler after
  16505.       completing its processing. This jump can be done indirectly, with the
  16506.       same pointer used to save the original content of the vector for
  16507.       restoration at exit. For example, a replacement Interrupt 08H handler
  16508.       that merely increments an internal flag at each timer tick can look
  16509.       something like the following:
  16510.  
  16511.               .
  16512.               .
  16513.               .
  16514.       myflag  dw      ?                       ; variable to be incremented
  16515.                                               ; on each timer-tick interrupt
  16516.  
  16517.       oldint8 dd      ?                       ; contains address of previous
  16518.                                               ; timer-tick interrupt handler
  16519.               .
  16520.               .                               ; get the previous contents
  16521.               .                               ; of the Interrupt O8H
  16522.                                               ; vector...
  16523.               mov     ax,3508h                ; AH = 35H (Get Interrupt
  16524.                                               ; Vector)
  16525.               int     21h                     ; AL = Interrupt number (08H)
  16526.               mov     word ptr oldint8,bx     ; save the address of
  16527.               mov     word ptr oldint8+2,es   ; the previous Int 08H Handler
  16528.               mov     dx,seg myint8           ; put address of the new
  16529.               mov     ds,dx                   ; interrupt handler into DS:DX
  16530.               mov     dx,offset myint8        ; and call MS-DOS to set
  16531.                                               ; vector
  16532.               mov     ax,2508h                ; AH = 25H (Set Interrupt
  16533.                                               ; Vector)
  16534.               int     21h                     ; AL = Interrupt number (08H)
  16535.               .
  16536.               .
  16537.               .
  16538.       myint8:                                 ; this is the new handler
  16539.                                               ; for Interrupt 08H
  16540.  
  16541.               inc     cs:myflag               ; increment variable on each
  16542.                                               ; timer-tick interrupt
  16543.  
  16544.               jmp     dword ptr cs:[oldint8]  ; then chain to the
  16545.                                               ; previous interrupt handler
  16546.  
  16547.       The added handler must preserve all registers and machine conditions,
  16548.       except those machine conditions it will modify, such as the value of
  16549.       myflag in the example (and the flags register, which is saved by the
  16550.       interrupt action), and it must restore those registers and conditions
  16551.       before performing the jump to the original handler.
  16552.  
  16553.       A more complex situation arises when a replacement handler does some
  16554.       processing after the original routine executes, especially if the
  16555.       replacement handler is not reentrant. To allow for this processing,
  16556.       the replacement handler must prevent nested interrupts, so that even
  16557.       if the old handler (which is chained to the replacement handler by a
  16558.       CALL instruction) issues an EOI, the replacement handler will not be
  16559.       interrupted during postprocessing. For example, instead of using the
  16560.       preceding Interrupt 08H example routine, the programmer could use the
  16561.       following code to implement myflag as a semaphore and use the XCHG
  16562.       instruction to test it:
  16563.  
  16564.       myint8:                                 ; this is the new handler
  16565.                                               ; for Interrupt 08H
  16566.  
  16567.               mov     ax,1                    ; test and set interrupt-
  16568.               xchg    cs:myflag,ax            ; handling-in-progress
  16569.                                               ; semaphore
  16570.  
  16571.               push    ax                      ; save the semaphore
  16572.  
  16573.               pushf                           ; simulate interrupt, allowing
  16574.               call    dword ptr cs:oldint8    ; the previous handler for the
  16575.                                               ; Interrupt 08H vector to run
  16576.  
  16577.               pop     ax                      ; get the semaphore back
  16578.               or      ax,ax                   ; is our interrupt handler
  16579.                                               ; already running?
  16580.  
  16581.               jnz     myint8x                 ; yes, skip this one
  16582.  
  16583.               .                               ; now perform our interrupt
  16584.               .                               ; processing here...
  16585.               .
  16586.  
  16587.               mov     cs:myflag,0             ; clear the interrupt-
  16588.                                               ; handling-
  16589.                                               ; in-progress flag
  16590.  
  16591.       myint8x:
  16592.               iret                            ; return from interrupt
  16593.  
  16594.       Note that an interrupt handler of this type must simulate the original
  16595.       call to the interrupt routine by first doing a PUSHF, followed by a
  16596.       far CALL via the saved pointer to execute the original handler
  16597.       routine. The flags register pushed onto the stack is restored by the
  16598.       IRET of the original handler. Upon return from the original code, the
  16599.       new routine can preserve the machine state and do its own processing,
  16600.       finally returning to the caller by means of its own IRET.
  16601.  
  16602.       The flags inside the new routine need not be preserved, as they are
  16603.       automatically restored by the IRET instruction. Because of the nature
  16604.       of interrupt servicing, the service routine should not depend on any
  16605.       information in the flags register, nor can it return any information
  16606.       in the flags register. Note also that the previous handler (invoked by
  16607.       the indirect CALL) will almost certainly have dismissed the interrupt
  16608.       by sending an EOI to the 8259A PIC. Thus, the machine state is not the
  16609.       same as in the first myint8 example.
  16610.  
  16611.       To remove the new vector and restore the original, the program simply
  16612.       replaces the new vector (in the vector table) with the saved copy. If
  16613.       the substituted routine is part of an application program, the
  16614.       original vector must be restored for every possible method of exiting
  16615.       from the program (including Control-Break, Control-C, and critical-
  16616.       error Abort exits). Failure to observe this requirement invariably
  16617.       results in system failure. Even though the system failure might be
  16618.       delayed for some time after the exit from the offending program, when
  16619.       some subsequent program overlays the interrupt handler code the crash
  16620.       will be imminent.
  16621.  
  16622.  
  16623.  Summary
  16624.  
  16625.       Hardware interrupt handler routines, although not strictly a part of
  16626.       MS-DOS, form an integral part of many MS-DOS programs and are tightly
  16627.       constrained by MS-DOS requirements. Routines of this type play
  16628.       important roles in the functioning of the IBM personal computers, and,
  16629.       with proper design and programming, significantly enhance product
  16630.       reliability and performance. In some instances, no other practical
  16631.       method exists for meeting performance requirements.
  16632.  
  16633.                                                    Jim Kyle
  16634.                                                    Chip Rabinowitz
  16635.  
  16636.  
  16637.  
  16638.  Article 14: Writing MS-DOS Filters
  16639.  
  16640.  
  16641.       A filter is, essentially, a program that operates on a stream of
  16642.       characters. The source and destination of the character stream can be
  16643.       files, another program, or almost any character device. The
  16644.       transformation applied by the filter to the character stream can range
  16645.       from an operation as simple as substituting a character set to an
  16646.       operation as elaborate as generating splines from sets of coordinates.
  16647.  
  16648.       The standard MS-DOS package includes three simple filters: SORT, which
  16649.       alphabetically sorts text on a line-by-line basis; FIND, which
  16650.       searches a text stream to match a specified string; and MORE, which
  16651.       displays text one screenful at a time. This article describes how
  16652.       filters work and how new ones can be constructed. See also USER
  16653.       COMMANDS: FIND; MORE; SORT.
  16654.  
  16655.  
  16656.  System Support for Filters
  16657.  
  16658.       The operation of a filter program relies on two features that appeared
  16659.       in MS-DOS version 2.0:  standard devices and redirectable I/O.
  16660.  
  16661.       The standard devices are represented by five handles that are
  16662.       originally established when the system is initialized. Each process
  16663.       inherits these handles from its immediate parent. Thus, the standard
  16664.       device handles are already opened when a process acquires control of
  16665.       the system, and the process can use the handles with Interrupt 21H
  16666.       Functions 3FH and 40H for read and write operations without further
  16667.       preliminaries. The default assignments of the standard device handles
  16668.       are
  16669.  
  16670. ╓┌────────────────┌──────────────────────────────────┌───────────────────────╖
  16671.       Handle      Name                               Default Device
  16672.       ──────────────────────────────────────────────────────────────────
  16673.       0           stdin  (standard input)            CON
  16674.       1           stdout (standard output)           CON
  16675.       2           stderr (standard error)            CON
  16676.       Handle      Name                               Default Device
  16677.      2           stderr (standard error)            CON
  16678.       3           stdaux (standard auxiliary)        AUX
  16679.       4           stdlst (standard list)             PRN
  16680.  
  16681.       The CON device is assigned by default to the system's keyboard and
  16682.       video display. AUX is assigned by default to COM1 (the first physical
  16683.       serial port), and PRN is assigned by default to LPT1 (the first
  16684.       physical parallel printer port); in some systems these assignments can
  16685.       be altered with the MODE command. See PROGRAMMING IN THE MS-DOS
  16686.       ENVIRONMENT: PROGRAMMING FOR MS-DOS: Character Device Input and
  16687.       Output; USER COMMANDS: MODE; CTTY.
  16688.  
  16689.       When a program is executed by entering its name at the system
  16690.       (COMMAND.COM) prompt, the user can redirect either or both of the
  16691.       standard input and standard output handles from their default device
  16692.       (CON) to another file, a character device, or a process. This
  16693.       redirection is accomplished by including one of the special characters
  16694.       <, >, >>, or  in the command line, in the following form:
  16695.  
  16696. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  16697.       Redirection      Result
  16698.       ──────────────────────────────────────────────────────────────────
  16699.       < file           Contents of the specified file are used instead of
  16700.                        the keyboard as the program's standard input.
  16701.  
  16702.       < device         Program takes its standard input from the named
  16703.                        device instead of from the keyboard.
  16704.  
  16705.       > device         Program sends its standard output to the named device
  16706.                        instead of to the video display.
  16707.  
  16708.       > file           Program sends its standard output to the specified
  16709.                        file instead of to the video display.
  16710.  
  16711.       >> file          Program appends its standard output to the current
  16712.                        contents of the specified file instead of to the
  16713.                        video display.
  16714.  
  16715.       p1 | p2          Standard output of program p1 is routed to become the
  16716.                        standard input of program p2 (output of p1 is said
  16717.                        to be piped to p2).
  16718.       Redirection      Result
  16719.                       to be piped to p2).
  16720.  
  16721.       For example, the command
  16722.  
  16723.       C>SORT < MYFILE.TXT > PRN  <Enter>
  16724.  
  16725.       causes the SORT filter to read its input from the file MYFILE.TXT,
  16726.       sort the lines alphabetically, and write resulting text to the
  16727.       character device PRN (the logical name for the system's list device).
  16728.  
  16729.       The redirection requested by the <, >, >>, or  characters takes place
  16730.       at the level of COMMAND.COM and is invisible to the program it
  16731.       affects. Such redirection can also be put into effect by another
  16732.       process. See Using a Filter as a Child Process, below.
  16733.  
  16734.       Note that if a program "goes around" MS-DOS to perform its input and
  16735.       output, either by calling ROM BIOS functions or by manipulating the
  16736.       keyboard or video controller directly, redirection commands placed in
  16737.       the program's command line do not have the expected effect.
  16738.  
  16739.  
  16740.  How Filters Work
  16741.  
  16742.       By convention, a filter program reads its text from standard input and
  16743.       writes the results of its operations to standard output. When the end
  16744.       of the input stream is reached, the filter simply terminates,
  16745.       optionally writing an end-of-file mark (1AH) to the output stream. As
  16746.       a result, filters are both flexible and simple.
  16747.  
  16748.       Filter programs are flexible because they do not know, and do not
  16749.       care, about the source of the data they process or the destination of
  16750.       their output. Any redirection that the user specifies in the command
  16751.       line is invisible to the filter. Thus, any character device that has a
  16752.       logical name within the system (CON, AUX, COM1, COM2, PRN, LPT1, LPT2,
  16753.       LPT3, and so on), any file on any block device (local or network)
  16754.       known to the system, or any other program can supply a filter's input
  16755.       or accept its output. If necessary, several functionally simple
  16756.       filters can be concatenated with pipes to perform very complex
  16757.       operations.
  16758.  
  16759.       Although flexible, filters are also simple because they rely on their
  16760.       parent process to supply standard input and standard output handles
  16761.       that have already been appropriately redirected. The parent is
  16762.       responsible for opening or creating any necessary files, checking the
  16763.       validity of logical character device names, and loading and executing
  16764.       the preceding or following process in a pipe. The filter need only
  16765.       concern itself with the transformation it will apply to the data; it
  16766.       can leave the I/O details to the operating system and to its parent.
  16767.  
  16768.  
  16769.  Building a Filter
  16770.  
  16771.       Creating a new filter for MS-DOS is a straightforward process. In its
  16772.       simplest form, a filter need only use the handle-oriented read
  16773.       (Interrupt 21H Function 3FH) and write (Interrupt 21H Function 40H)
  16774.       functions to get characters or lines from standard input and send them
  16775.       to standard output, performing any desired alterations on the text
  16776.       stream on a character-by-character or line-by-line basis.
  16777.  
  16778.       Figures 14-1 through 14-4 contain template character-oriented and
  16779.       line-oriented filters in both assembly language and C. The C version
  16780.       of the character filter runs much faster than the assembly-language
  16781.       version, because the C run-time library provides hidden blocking and
  16782.       deblocking (buffering) of character reads and writes; the assembly-
  16783.       language program actually makes two calls to MS-DOS for each character
  16784.       processed. (Of course, if buffering is added to the assembly-language
  16785.       version it will be both faster and smaller than the C filter.) The C
  16786.       and assembly-language versions of the line-oriented filter run at
  16787.       roughly the same speed.
  16788.  
  16789.       ──────────────────────────────────────────────────────────────────────
  16790.  
  16791.       Figure 14-1. Assembly-language template for a character-oriented
  16792.       filter (file PROTOC.ASM).
  16793.  
  16794.       ──────────────────────────────────────────────────────────────────────
  16795.  
  16796.       Figure 14-2. C template for a character-oriented filter (file
  16797.       PROTOC.C).
  16798.  
  16799.       ──────────────────────────────────────────────────────────────────────
  16800.  
  16801.       Figure 14-3. Assembly-language template for a line-oriented filter
  16802.       (file PROTOL.ASM).
  16803.  
  16804.       ──────────────────────────────────────────────────────────────────────
  16805.  
  16806.       Figure 14-4. C template for a line-oriented filter (file PROTOL.C).
  16807.  
  16808.       ──────────────────────────────────────────────────────────────────────
  16809.  
  16810.       Each of the four template filters can be assembled or compiled,
  16811.       linked, and run exactly as they are shown in Figures 14-1 through
  16812.       14-4. Of course, in this form they function like an incredibly slow
  16813.       COPY command.
  16814.  
  16815.       To obtain a filter that does something useful, a routine that performs
  16816.       some modification of the text stream that is flowing by must be
  16817.       inserted between the reads and writes. For example, Figures 14-5 and
  16818.       14-6 contain the assembly-language and C source code for a character-
  16819.       oriented filter named LC. This program converts all uppercase input
  16820.       characters (A-Z) to lowercase (a-z) output, leaving other characters
  16821.       unchanged. The only difference between LC and the template character
  16822.       filter is the translation subroutine that operates on the text stream.
  16823.  
  16824.       ──────────────────────────────────────────────────────────────────────
  16825.  
  16826.       Figure 14-5. Assembly-language source code for the LC filter (file
  16827.       LC.ASM).
  16828.  
  16829.       ──────────────────────────────────────────────────────────────────────
  16830.  
  16831.       Figure 14-6. C source code for the LC filter (file LC.C).
  16832.  
  16833.       ──────────────────────────────────────────────────────────────────────
  16834.  
  16835.       As another example, Figure 14-7 contains the C source code for a line-
  16836.       oriented filter called FIND. This simple filter is invoked with a
  16837.       command line in the form
  16838.  
  16839.       FIND "pattern" < source > destination
  16840.  
  16841.       FIND searches the input stream for lines containing the pattern
  16842.       specified in the command line. The line number and text of any line
  16843.       containing a match is sent to standard output, with any tabs expanded
  16844.       to eight-column tab stops.
  16845.  
  16846.       ──────────────────────────────────────────────────────────────────────
  16847.  
  16848.       Figure 14-7. C source code for a new FIND filter (file FIND.C).
  16849.  
  16850.       ──────────────────────────────────────────────────────────────────────
  16851.  
  16852.       This sample FIND filter differs from the FIND filter supplied by
  16853.       Microsoft with MS-DOS in several respects. It is not case sensitive,
  16854.       so the pattern "foobar" will match "FOOBAR", "FooBar", and so forth.
  16855.       Second, this filter supports no switches; these are left as an
  16856.       exercise for the reader. Third, unlike the Microsoft version of FIND,
  16857.       this program always reads from standard input; it is not able to open
  16858.       its own files.
  16859.  
  16860.  
  16861.  Using a Filter as a Child Process
  16862.  
  16863.       Instead of incorporating all the code necessary to do the job itself,
  16864.       an application program can load and execute a filter as a child
  16865.       process to carry out a specific task. Before the child filter is
  16866.       loaded, the parent must arrange for the standard input and standard
  16867.       output handles that will be inherited by the child to be attached to
  16868.       the files or character devices that will supply the filter's input and
  16869.       receive its output. This redirection is accomplished with the
  16870.       following steps using Interrupt 21H functions:
  16871.  
  16872.       1. The parent process uses Function 45H (Duplicate File Handle) to
  16873.          create duplicates of its standard input and standard output handles
  16874.          and then saves the duplicates.
  16875.  
  16876.       2. The parent opens (with Function 3DH) or creates (with Function 3CH)
  16877.          the files or devices that the child process will use for input and
  16878.          output.
  16879.  
  16880.       3. The parent uses Function 46H (Force Duplicate File Handle) to force
  16881.          its own standard device handles to track the new file or device
  16882.          handles acquired in step 2.
  16883.  
  16884.       4. The parent uses Function 4B00H (Load and Execute Program [EXEC]) to
  16885.          load and execute the child process. The child inherits the
  16886.          redirected standard input and standard output handles and uses them
  16887.          to do its work. The parent regains control after the child filter
  16888.          terminates.
  16889.  
  16890.       5. The parent uses the duplicate handles created in step 1, together
  16891.          with Function 46H (Force Duplicate File Handle), to restore its own
  16892.          standard input and standard output handles to their original
  16893.          meanings.
  16894.  
  16895.       6. The parent closes (with Function 3EH) the duplicate handles created
  16896.          in step 1, because they are no longer needed.
  16897.  
  16898.       It might seem as though the parent process could just as easily close
  16899.       its own standard input and standard output (handles 0 and 1), open the
  16900.       input and output files needed by the child, load and execute the
  16901.       child, close the files upon regaining control, and then reopen the CON
  16902.       device twice. Because the open operation always assigns the first free
  16903.       handle, this approach would have the desired effect as far as the
  16904.       child process is concerned. However, it would throw away any
  16905.       redirection that had been established for the parent process by its
  16906.       parent. Thus, the need to preserve any preexisting redirection of the
  16907.       parent's standard input and standard output, along with the desire to
  16908.       preserve the parent's usual output channel for informational messages
  16909.       right up to the actual point of the EXEC call, is the reason for the
  16910.       elaborate procedure outlined above in steps 1 through 6.
  16911.  
  16912.       The program EXECSORT.ASM in Figure 14-8 demonstrates this redirection
  16913.       of input and output for a filter run as a child process. The parent,
  16914.       which is called EXECSORT, saves duplicates of its current standard
  16915.       input and standard output handles and then redirects those handles
  16916.       respectively to the files MYFILE.DAT (which it opens) and MYFILE.SRT
  16917.       (which it creates). EXECSORT then uses Interrupt 21H Function 4BH
  16918.       (EXEC) to run the SORT.EXE filter that is supplied with MS-DOS (this
  16919.       file must be in the current drive and directory for the demonstration
  16920.       to work correctly).
  16921.  
  16922.       ──────────────────────────────────────────────────────────────────────
  16923.  
  16924.       Figure 14-8. Assembly-language source code demonstrating use of a
  16925.       filter as a child process. This code redirects the standard input and
  16926.       standard output handles to files, invokes the EXEC function (Interrupt
  16927.       21H Function 4BH) to run the SORT.EXE program, and then restores the
  16928.       original meaning of the standard input and standard output handles
  16929.       (file EXECSORT.ASM).
  16930.  
  16931.       ──────────────────────────────────────────────────────────────────────
  16932.  
  16933.       The MS-DOS SORT program reads the file MYFILE.DAT via its standard
  16934.       input handle, sorts the file alphabetically, and writes the sorted
  16935.       data to MYFILE.SRT via its standard output handle. When SORT
  16936.       terminates, MS-DOS closes SORT's inherited handles for standard input
  16937.       and standard output, which forces an update of the directory entries
  16938.       for the associated files. The program EXECSORT then resumes execution,
  16939.       restores its own standard input and standard output handles (which are
  16940.       still open) to their original meanings, displays a success message on
  16941.       standard output, and exits to MS-DOS.
  16942.  
  16943.                                                         Ray Duncan
  16944.  
  16945.  
  16946.  
  16947.  Article 15: Installable Device Drivers
  16948.  
  16949.  
  16950.       The software that runs on modern computer systems is, by convention,
  16951.       organized into layers with varied degrees of independence from the
  16952.       underlying computer hardware. The purpose of this layering is
  16953.       threefold:
  16954.  
  16955.       ■  To minimize the impact on programs of differences between hardware
  16956.          devices or changes in the hardware.
  16957.  
  16958.       ■  To allow the code for common operations to be centralized and
  16959.          optimized.
  16960.  
  16961.       ■  To ease the task of moving programs and their data from one machine
  16962.          to another.
  16963.  
  16964.       The top and most hardware-independent layer is usually the transient,
  16965.       or application, program, which performs a specific job and deals with
  16966.       data in terms of files and records within those files. Such programs
  16967.       are called transient because they are brought into RAM for execution
  16968.       when needed and are discarded from memory when their job is finished.
  16969.       Examples of such programs are Microsoft Word, various programming
  16970.       tools such as the Microsoft Macro Assembler (MASM) and the Microsoft
  16971.       Object Linker (LINK), and even some of the standard MS-DOS utility
  16972.       programs such as CHKDSK and FORMAT.
  16973.  
  16974.       The middle layer is the operating-system kernel, which manages the
  16975.       allocation of system resources such as memory and disk storage,
  16976.       provides a battery of services to application programs, and implements
  16977.       disk directories and the other housekeeping details of disk storage.
  16978.       The MS-DOS kernel is brought into memory from the file MSDOS.SYS (or
  16979.       IBMDOS.COM with PC-DOS) when the system is turned on or restarted and
  16980.       remains fixed in memory until the system is turned off. The system's
  16981.       default command processor, COMMAND.COM, and system manager programs
  16982.       such as Microsoft Windows bridge the categories of application program
  16983.       and operating system: Parts of them remain resident in memory at all
  16984.       times, but they rely on the MS-DOS kernel for services such as file
  16985.       I/O. See PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS:
  16986.       Components of MS-DOS.
  16987.  
  16988.       The modules in the lowest layer are called device drivers. These
  16989.       drivers are the components of the operating system that manage the
  16990.       controller, or adapter, of a peripheral device--a piece of hardware
  16991.       that the computer uses for such purposes as storage or communicating
  16992.       with the outside world. Thus, device drivers are responsible for
  16993.       transferring data between a peripheral device and the computer's RAM
  16994.       memory, where other programs can work on it. Drivers shield the
  16995.       operating-system kernel from the need to deal with hardware I/O port
  16996.       addresses, operating characteristics, and the peculiarities of a
  16997.       particular peripheral device, just as the kernel, in turn, shields
  16998.       application programs from the details of file management.
  16999.  
  17000.       In MS-DOS versions 1.x, device drivers were integrated into the
  17001.       operating system and could be extended or replaced only by patching
  17002.       the files that contained the operating system itself. Because every
  17003.       third-party peripheral manufacturer evolved a different method of
  17004.       modifying these files to get its product to work, conflicts between
  17005.       products from different manufacturers were frequent and expansion of a
  17006.       PC with new disk drives and other devices (especially fixed disks) was
  17007.       often a chancy proposition.
  17008.  
  17009.       In MS-DOS versions 2.0 and later, there is a clean separation between
  17010.       device drivers and the MS-DOS kernel. Device drivers have a
  17011.       straightforward structure and are interfaced to the kernel through a
  17012.       simple and clearly defined scheme that consists of far calls, function
  17013.       codes, and data packets. Given adequate information about the
  17014.       hardware, a programmer can write a new device driver that follows this
  17015.       structure and interface for almost any conceivable peripheral device;
  17016.       such a driver can subsequently be installed and used without any
  17017.       changes to the underlying operating system.
  17018.  
  17019.       This article explains the anatomy, operation, and creation of drivers
  17020.       for MS-DOS versions 2.0 and later. Device drivers for versions 1.x are
  17021.       not discussed further here.
  17022.  
  17023.  
  17024.  Resident and Installable Drivers
  17025.  
  17026.       Every MS-DOS system contains built-in device drivers for the console
  17027.       (keyboard and video display), the serial port, the parallel printer
  17028.       port, the real-time clock, and at least one disk storage device (the
  17029.       system boot device). These drivers, known as the resident drivers, are
  17030.       loaded as a set from the file IO.SYS (or IBMBIO.COM with PC-DOS) when
  17031.       the system is turned on or restarted.
  17032.  
  17033.       Drivers for additional peripheral devices occupy individual files on
  17034.       the disk. These drivers, called installable drivers, are loaded and
  17035.       linked into the system during its initialization as a result of DEVICE
  17036.       directives in the CONFIG.SYS file. See PROGRAMMING IN THE MS-DOS
  17037.       ENVIRONMENT: STRUCTURE OF MS-DOS: Components of MS-DOS. Examples of
  17038.       such drivers are the ANSI.SYS and RAMDISK.SYS files included with MS-
  17039.       DOS version 3.2. In all other respects, installable drivers have the
  17040.       same structure and relationship to the MS-DOS kernel as the resident
  17041.       drivers. All drivers in the system are chained together so that MS-DOS
  17042.       can rapidly search the entire set to find a specific block or
  17043.       character device when an I/O operation is requested.
  17044.  
  17045.       Device drivers as a whole are categorized into two groups: block-
  17046.       device drivers and character-device drivers. A driver's membership in
  17047.       one of these two groups determines how the associated device is viewed
  17048.       by MS-DOS and what functions the driver itself must support.
  17049.  
  17050.  Character-device drivers
  17051.  
  17052.       Character-device drivers control peripheral devices, such as a
  17053.       terminal or a printer, that perform input and output one character (or
  17054.       byte) at a time. Each character-device driver ordinarily supports a
  17055.       single hardware unit. The device has a one-character to eight-
  17056.       character logical name that can be used by an application program to
  17057.       "open" the device for input or output as though it were a file. The
  17058.       logical name is strictly a means of identifying the driver to MS-DOS
  17059.       and has no physical equivalent on the device (unlike a volume label
  17060.       for block devices).
  17061.  
  17062.       The three resident character-device drivers for the console, serial
  17063.       port, and printer carry the logical device names CON, AUX, and PRN,
  17064.       respectively. These three drivers receive special treatment by MS-DOS
  17065.       that allows application programs to address the associated devices in
  17066.       three different ways:
  17067.  
  17068.       ■  They can be opened by name for input and output (like any other
  17069.          character device).
  17070.  
  17071.       ■  They are supported by special-purpose MS-DOS function calls
  17072.          (Interrupt 21H Functions 01-0CH).
  17073.  
  17074.       ■  They are assigned to default handles (standard input, standard
  17075.          output, standard error, standard auxiliary, and standard list) that
  17076.          need not be opened to be used.
  17077.  
  17078.       See PROGRAMMING IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS:
  17079.       Character Device Input and Output.
  17080.  
  17081.       Other character devices can be supported by simply installing
  17082.       additional character-device drivers. The only significant restriction
  17083.       on the total number of devices that can be supported, other than the
  17084.       memory required to hold the drivers, is that each driver must have a
  17085.       unique logical name. When MS-DOS receives an open request for a
  17086.       character device, it searches the chain of device drivers in order
  17087.       from the last driver loaded to the first. Thus, if more than one
  17088.       driver uses the same logical name, the last driver to be loaded
  17089.       supersedes any others and receives all I/O requests addressed to that
  17090.       logical name. This behavior can be used to advantage in some
  17091.       situations. For example, it allows the more powerful ANSI.SYS display
  17092.       driver to supersede the system's default console driver, which does
  17093.       not support cursor positioning and character attributes.
  17094.  
  17095.       The MS-DOS kernel's buffering and filtering of the characters that
  17096.       pass between it and a character-device driver are affected by whether
  17097.       MS-DOS regards the device to be in cooked mode or raw mode. During
  17098.       cooked mode input, MS-DOS requests characters one at a time from the
  17099.       driver and places them in its own internal buffer, echoing each
  17100.       character to the screen (if the input device is the keyboard) and
  17101.       checking each character for a Control-C (03H) or a Return (0DH). When
  17102.       either the number of characters requested by the application program
  17103.       has been received or a Return is detected, the input is terminated and
  17104.       the data is copied from MS-DOS's internal buffer into the requesting
  17105.       program's buffer. When a Control-C is detected, MS-DOS aborts the
  17106.       input operation and transfers to the routine whose address is stored
  17107.       in the Interrupt 23H (Control-C Handler Address) vector. See
  17108.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: CUSTOMIZING MS-DOS: Exception
  17109.       Handlers. Similarly, during output in cooked mode, MS-DOS checks
  17110.       between each character for a Control-C pending at the keyboard and
  17111.       aborts the output operation if one is detected.
  17112.  
  17113.       In raw mode, the exact number of bytes requested by the application
  17114.       program is read or written, without regard to any control characters
  17115.       such as Return or Control-C. MS-DOS passes the entire I/O request to
  17116.       the driver in a single operation, instead of breaking the request into
  17117.       single-character reads or writes, and the characters are transferred
  17118.       directly to or from the requesting program's buffer.
  17119.  
  17120.       The mode for a specific device can be queried by an application
  17121.       program with the IOCTL Get Device Data function (Interrupt 21H
  17122.       Function 44H Subfunction 00H); the mode can be selected with the Set
  17123.       Device Data function (Interrupt 21H Function 44H Subfunction 01H). See
  17124.       SYSTEM CALLS: INTERRUPT 21H: Function 44H. The driver itself is not
  17125.       usually aware of its mode and the mode does not affect its operation.
  17126.  
  17127.  Block-Device Drivers
  17128.  
  17129.       Block-device drivers control peripheral devices that transfer data in
  17130.       chunks rather than 1 byte at a time. Block devices are usually
  17131.       randomly addressable devices such as floppy- or fixed-disk drives, but
  17132.       they can also be sequential devices such as magnetic-tape drives. A
  17133.       block driver can support more than one physical unit and can also map
  17134.       two or more logical units onto a single physical unit, as with a
  17135.       partitioned fixed disk.
  17136.  
  17137.       MS-DOS assigns single-letter drive identifiers (A, B, and so forth) to
  17138.       block devices, instead of logical names. The first letter assigned to
  17139.       a block-device driver is determined solely by the driver's position in
  17140.       the chain of all drivers--that is, by the number of units supported by
  17141.       the block drivers loaded before it; the total number of letters
  17142.       assigned to the driver is determined by the number of logical drive
  17143.       units the driver supports.
  17144.  
  17145.       MS-DOS does not associate a mode (cooked or raw) with block-device
  17146.       drivers. A block-device driver always reads or writes exactly the
  17147.       number of sectors requested (barring hardware or addressing errors)
  17148.       and never filters or otherwise manipulates the contents of the blocks
  17149.       being transferred.
  17150.  
  17151.  
  17152.  Structure of an MS-DOS Device Driver
  17153.  
  17154.       A device driver has three major components (Figure 15-1):
  17155.  
  17156.       ■  The device header
  17157.       ■  The Strategy routine (Strat)
  17158.       ■  The Interrupt routine (Intr)
  17159.  
  17160.  
  17161.       ┌─────────────────────────┬─────────────────────────────┐
  17162.       │                         │       Initialization        │
  17163.       │                         ├─────────────────────────────┤
  17164.       │                         │         Media Check         │
  17165.       │                         ├─────────────────────────────┤
  17166.       │                         │          Build BPB          │
  17167.       │                         ├─────────────────────────────┤
  17168.       │                         │    IOCTL Read and Write     │
  17169.       │                         ├─────────────────────────────┤
  17170.       │                         │           Status            │
  17171.       │                         ├─────────────────────────────┤
  17172.       │      Interrupt routine  │            Read             │
  17173.       │                         ├─────────────────────────────┤
  17174.       │                         │     Write, Write/Verify     │
  17175.       │                         ├─────────────────────────────┤
  17176.       │                         │      Output Until Busy      │
  17177.       │                         ├─────────────────────────────┤
  17178.       │                         │        Flush Buffers        │
  17179.       │                         ├─────────────────────────────┤
  17180.       │                         │         Device Open         │
  17181.       │                         ├─────────────────────────────┤
  17182.       │                         │        Device Close         │
  17183.       │                         ├─────────────────────────────┤
  17184.       │                         │     Check if Removable      │
  17185.       │                         ├─────────────────────────────┤
  17186.       │                         │        Generic IOCTL        │
  17187.       │                         ├─────────────────────────────┤
  17188.       │                         │   Get/Set Logical Device    │
  17189.       │                         └─────────────────────────────┤
  17190.       │                                                       │
  17191.       ├───────────────────────────────────────────────────────┤
  17192.       │                                                       │
  17193.       │                   Strategy routine                    │
  17194.       │                                                       │
  17195.       ├───────────────────────────────────────────────────────┤
  17196.       │                 Device-driver header                  │
  17197.       └───────────────────────────────────────────────────────┘
  17198.  
  17199.       Figure 15-1. General structure of an MS-DOS installable device driver.
  17200.  
  17201.  
  17202.  The device header
  17203.  
  17204.       The device header (Figure 15-2) always lies at the beginning of the
  17205.       driver. It contains a link to the next driver in the chain, a word (16
  17206.       bits) of device attribute flags, offsets to the executable Strategy
  17207.       and Interrupt routines for the device, and the logical device name if
  17208.       it is a character device such as PRN or COM1 or the number of logical
  17209.       units if it is a block device.
  17210.  
  17211.  
  17212.       Offset
  17213.          00H  ┌────────────────────────────────────────────┐
  17214.               │        Link to next driver, offset         │
  17215.          02H  ├────────────────────────────────────────────┤
  17216.               │        Link to next driver, segment        │
  17217.          04H  ├────────────────────────────────────────────┤
  17218.               │           Device attribute word            │
  17219.          06H  ├────────────────────────────────────────────┤
  17220.               │        Offset, Strategy entry point        │
  17221.          08H  ├────────────────────────────────────────────┤
  17222.               │       Offset, Interrupt entry point        │
  17223.          0AH  ├────────────────────────────────────────────┤
  17224.               │ Logical name (8 bytes) if character device │
  17225.               │                     or                     │
  17226.               │    Number of units (1 byte) followed by    │
  17227.               │ 7 bytes of reserved space if block device  │
  17228.          12H  └────────────────────────────────────────────┘
  17229.  
  17230.       Figure 15-2. Device header. The offsets to the Strat and Intr routines
  17231.       are offsets from the same segment used to point to the device header.
  17232.  
  17233.  
  17234.       The device attribute flags word (Table 15-1) defines whether a driver
  17235.       controls a character or a block device, which of the optional
  17236.       subfunctions added in MS-DOS versions 3.0 and 3.2 are supported by the
  17237.       driver, and, in the case of block drivers, whether the driver supports
  17238.       IBM-compatible disk media. The least significant 4 bits of the device
  17239.       attribute flags word control whether MS-DOS should use the driver as
  17240.       the standard input, standard output, clock, or NUL device; each of
  17241.       these 4 bits should be set on only one driver in the system at a time.
  17242.  
  17243.  
  17244.       Table 15-1. Device Attribute Word in Device Header.
  17245.  
  17246. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  17247.       Bit         Setting
  17248.       ──────────────────────────────────────────────────────────────────
  17249.       151        1 if character device, 0 if block device
  17250.       141        1 if IOCTL Read and Write supported
  17251.       131        1 if non-IBM format (block device)
  17252.                   1 if Output Until Busy supported (character device)
  17253.       12          0 (reserved)
  17254.       111        1 if Open/Close/Removable Media supported (versions 3.0
  17255.                   and later)
  17256.       10          0 (reserved)
  17257.        9          0 (reserved)
  17258.        8          0 (reserved)
  17259.        7          0 (reserved)
  17260.        61        1 if Generic IOCTL and Get/Set Logical Drive supported
  17261.                   (version 3.2)
  17262.        5          0 (reserved)
  17263.        4          1 if special fast output function for CON device supported
  17264.       Bit         Setting
  17265.       4          1 if special fast output function for CON device supported
  17266.        3          1 if current CLOCK device
  17267.        2          1 if current NUL device
  17268.        1          1 if current standard output (stdout)
  17269.        0          1 if current standard input (stdin)
  17270.  
  17271.  
  17272.       The information in the device header is ordinarily used only by the
  17273.       MS-DOS kernel and is not available to application programs. However,
  17274.       the IOCTL subfunctions Get and Set Device Data (Interrupt 21H Function
  17275.       44H Subfunctions 00H and 01H) can be used to inspect or modify some of
  17276.       the bits in the device attribute flags word. Note that there is not a
  17277.       one-to-one correspondence between the bits defined for those functions
  17278.       and the bits in the device header. For example, in the device
  17279.       information word used by the IOCTL subfunctions, bit 7 indicates a
  17280.       block or character device; in the device attribute word of the device
  17281.       header, bit 15 indicates a block or character device.
  17282.  
  17283.  The Strategy routine (Strat)
  17284.  
  17285.       MS-DOS calls the driver's Strategy routine as the first step of any
  17286.       operation, passing it the segment and offset of a data structure
  17287.       called a request header in registers ES:BX. The Strategy routine saves
  17288.       this pointer for subsequent processing by the Interrupt routine and
  17289.       returns to MS-DOS.
  17290.  
  17291.       A request header is essentially a small buffer used for private
  17292.       communication between MS-DOS and the device driver. Both MS-DOS and
  17293.       the device driver read and write information in the request header.
  17294.  
  17295.       The first 13 bytes of a request header are the same for all device-
  17296.       driver functions and are therefore referred to as the static portion
  17297.       of the header. The number and contents of the subsequent bytes vary
  17298.       according to the type of operation being requested by the MS-DOS
  17299.       kernel (Figure 15-3). The request header's most important component is
  17300.       the command code passed in its third byte; this code selects a driver
  17301.       function such as Read or Write. Other information passed to the driver
  17302.       in the request header includes unit numbers, transfer addresses, and
  17303.       sector or byte counts.
  17304.  
  17305.  
  17306.       OOH  ┌──────────────────────────────────────┐
  17307.            │        Request header length         │▒
  17308.       01H  ├──────────────────────────────────────┤▒
  17309.            │       Block-device unit number       │▒
  17310.       02H  ├──────────────────────────────────────┤▒
  17311.            │  Command code (driver subfunction)   │▒
  17312.       03H  ├──────────────────────────────────────┤▒
  17313.            │                                      │▒
  17314.            │           Returned status            │▒ Static portion
  17315.            │                                      │▒  of request header
  17316.       05H  ├──────────────────────────────────────┤▒
  17317.            │                                      │▒
  17318.            │                                      │▒
  17319.            │                                      │▒
  17320.            │               Reserved               │▒
  17321.            │                                      │▒
  17322.            │                                      │▒
  17323.            │                                      │▒
  17324.       0DH  ├──────────────────────────────────────┤
  17325.            │            Media ID byte             │▒
  17326.       0EH  ├──────────────────────────────────────┤▒
  17327.            │                                      │▒
  17328.            │                Offset                │▒
  17329.            │                                      │▒
  17330.       10H  ├──────────────────────────────────────┤▒
  17331.            │                                      │▒
  17332.            │  Segment of data to be transferred   │▒ Variable portion
  17333.            │                                      │▒  of request header
  17334.       12H  ├──────────────────────────────────────┤▒
  17335.            │                                      │▒
  17336.            │          Byte/sector count           │▒
  17337.            │                                      │▒
  17338.       14H  ├──────────────────────────────────────┤▒
  17339.            │                                      │▒
  17340.            │        Starting sector number        │▒
  17341.            │                                      │▒
  17342.            └──────────────────────────────────────┘
  17343.  
  17344.       Figure 15-3. A typical driver request header. The bytes following the
  17345.       static portion are the format used for driver Read, Write, Write with
  17346.       Verify, IOCTL Read, and IOCTL Write operations.
  17347.  
  17348.  
  17349.  The Interrupt routine (Intr)
  17350.  
  17351.       The last and most complex part of a device driver is the Interrupt
  17352.       routine, which is called by MS-DOS immediately after the call to the
  17353.       Strategy routine. The bulk of the Interrupt routine is a collection of
  17354.       functions or subroutines, sometimes called command-code routines, that
  17355.       carry out each of the various operations the MS-DOS kernel requires a
  17356.       driver to support.
  17357.  
  17358.       When the Interrupt routine receives control from MS-DOS, it saves any
  17359.       affected registers, examines the request header whose address was
  17360.       previously passed in the call to the Strategy routine, determines
  17361.       which command-code routine is needed, and branches to the appropriate
  17362.       function. When the operation is completed, the Interrupt routine
  17363.       stores the status (Table 15-2), error (Table 15-3), and any other
  17364.       applicable information into the request header, restores the previous
  17365.       contents of the affected registers, and returns to the MS-DOS kernel.
  17366.  
  17367.  
  17368.       Table 15-2. The Request Header Status Word.
  17369.  
  17370. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  17371.       Bits        Meaning
  17372.       ──────────────────────────────────────────────────────────────────
  17373.       15          Error
  17374.       12-14       Reserved
  17375.       9           Busy
  17376.       8           Done
  17377.       0-7         Error code if bit 15 = 1
  17378.  
  17379.  
  17380.       Table 15-3. Device-Driver Error Codes.1
  17381.  
  17382. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  17383.       Code        Meaning
  17384.       ──────────────────────────────────────────────────────────────────
  17385.       00H         Write-protect violation
  17386.       01H         Unknown unit
  17387.       02H         Drive not ready
  17388.       03H         Unknown command
  17389.       04H         CRC error
  17390.       Code        Meaning
  17391.      04H         CRC error
  17392.       05H         Bad drive request structure length
  17393.       06H         Seek error
  17394.       07H         Unknown media
  17395.       08H         Sector not found
  17396.       09H         Printer out of paper
  17397.       0AH         Write fault
  17398.       0BH         Read fault
  17399.       0CH         General failure
  17400.       0DH         Reserved
  17401.       0EH         Reserved
  17402.       0FH         Invalid disk change (versions 3.x)
  17403.  
  17404.  
  17405.       The Interrupt routine's name is misleading in that it is never entered
  17406.       asynchronously as a hardware interrupt. The division of function
  17407.       between the Strategy and Interrupt routines is present for symmetry
  17408.       with UNIX/XENIX and MS OS/2 drivers but is essentially meaningless in
  17409.       single-tasking MS-DOS because there is never more than one I/O request
  17410.       in progress at a time.
  17411.  
  17412.  The command-code functions
  17413.       A total of twenty command codes are defined for MS-DOS device drivers.
  17414.       The command codes and the names of their associated Interrupt routines
  17415.       are shown in the following list:
  17416.  
  17417. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  17418.       Code        Routine
  17419.       ──────────────────────────────────────────────────────────────────
  17420.        0          Init (initialization)
  17421.        1          Media Check (block devices only)
  17422.        2          Build BIOS Parameter Block (block devices only)
  17423.        3          IOCTL Read
  17424.        4          Read (Input)
  17425.        5          Nondestructive Read (character devices only)
  17426.        6          Input Status (character devices only)
  17427.        7          Flush Input Buffers (character devices only)
  17428.        8          Write (Output)
  17429.        9          Write with Verify
  17430.       10          Output Status (character devices only)
  17431.       11          Flush Output Buffers (character devices only)
  17432.       Code        Routine
  17433.      11          Flush Output Buffers (character devices only)
  17434.       12          IOCTL Write
  17435.       131        Device Open
  17436.       141        Device Close
  17437.       151        Removable Media (block devices only)
  17438.       161        Output Until Busy (character devices only)
  17439.       192        Generic IOCTL Request
  17440.       232        Get Logical Device (block devices only)
  17441.       242        Set Logical Device (block devices only)
  17442.  
  17443.       Functions 0 through 12 must be supported by a driver's Interrupt
  17444.       section under all versions of MS-DOS. Drivers tailored for versions
  17445.       3.0 and 3.1 can optionally support an additional 4 functions defined
  17446.       under those versions of the operating system and drivers designed for
  17447.       version 3.2 can support 3 more, for a total of 20. MS-DOS inspects the
  17448.       bits in the device attribute word of the device header to determine
  17449.       which of the optional version 3.x functions a driver supports, if any.
  17450.  
  17451.       As noted in the list above, some of the functions are relevant only
  17452.       for character drivers, some only for block drivers, and some for both.
  17453.       In any case, there must be an executable routine present for each
  17454.       function, even if the routine does nothing but set the done flag in
  17455.       the status word of the request header. The general requirements for
  17456.       each function routine are described below.
  17457.  
  17458.       The Init function
  17459.       The Init (initialization) function (command code 0) for a driver is
  17460.       called only once, when the driver is loaded (Figure 15-4). Init is
  17461.       responsible for checking that the hardware device controlled by the
  17462.       driver is present and functional, performing any necessary hardware
  17463.       initialization (such as a reset on a printer or a seek to the home
  17464.       track on a disk device), and capturing any interrupt vectors that the
  17465.       driver will need later.
  17466.  
  17467.       The Init function is passed a pointer in the request header to the
  17468.       text of the DEVICE line in CONFIG.SYS that caused the driver to be
  17469.       loaded--specifically, the address of the next byte after the equal
  17470.       sign (=). The line is read-only and is terminated by a linefeed or
  17471.       carriage-return character; it can be scanned by the driver for
  17472.       switches or other parameters that might influence the driver's
  17473.       operation. (Alphabetic characters in the line are folded to
  17474.       uppercase.) With versions 3.0 and later, block drivers are also passed
  17475.       the drive number that will be assigned to their first unit (0 = A, 1 =
  17476.       B, and so on).
  17477.  
  17478.  
  17479.               Driver called with                   Driver returns
  17480.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  17481.           │ Request header length   │        │                         │
  17482.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  17483.           │                         │        │                         │
  17484.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  17485.           │      Command code       │        │                         │
  17486.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  17487.           │                         │        │                         │
  17488.           │                         │        │         Status          │
  17489.           │                         │        │                         │
  17490.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  17491.           │                         │        │                         │
  17492.           │                         │        │                         │
  17493.           │        Reserved         │        │        Reserved         │
  17494.           │                         │        │                         │
  17495.           │                         │        │                         │
  17496.       0DH ├─────────────────────────┤    0DH ├─────────────────────────┤
  17497.           │                         │        │    Units supported1    │
  17498.       0EH ├─────────────────────────┤    0EH ├─────────────────────────┤
  17499.           │                         │        │                         │
  17500.           │                         │        │ Offset of free memory   │
  17501.           │                         │        │      above driver       │
  17502.       10H ├─────────────────────────┤    10H ├─────────────────────────┤
  17503.           │                         │        │                         │
  17504.           │                         │        │ Segment of free menory  │
  17505.           │                         │        │      above driver       │
  17506.       12H ├─────────────────────────┤    12H ├─────────────────────────┤
  17507.           │                         │        │                         │
  17508.           │Offset of CONFIG.SYS     │        │        Offset of        │
  17509.           │line loading driver2    │        │   BPB pointer array1   │
  17510.       14H ├─────────────────────────┤    14H ├─────────────────────────┤
  17511.           │                         │        │                         │
  17512.           │Segment of CONFIG.SYS    │        │       Segment of        │
  17513.           │line loading driver2    │        │   BPB pointer array1   │
  17514.       16H ├─────────────────────────┤    16H ├─────────────────────────┤
  17515.           │First unit number1,3    │        │                         │
  17516.           └─────────────────────────┘        └─────────────────────────┘
  17517.  
  17518.       Figure 15-4. Initialization request header (command code 0).
  17519.  
  17520.  
  17521.       When it returns to the kernel, the Init function must set the done
  17522.       flag in the status word of the request header and return the address
  17523.       of the start of free memory after the driver (sometimes called the
  17524.       break address). This address tells the kernel where it can build
  17525.       certain control structures of its own associated with the driver and
  17526.       then load the next driver. The Init routine of a block-device driver
  17527.       must also return the number of logical units supported by the driver
  17528.       and the address of a BPB pointer array.
  17529.  
  17530.       The number of units returned by a block driver is used to assign
  17531.       device identifiers. For example, if at the time the driver is loaded
  17532.       there are already drivers present for four block devices (drive codes
  17533.       0-3, corresponding to drive identifiers A through D) and the driver
  17534.       being initialized supports four units, it will be assigned the drive
  17535.       numbers 4 through 7 (corresponding to the drive names E through H).
  17536.       (Although there is also a field in the device header for the number of
  17537.       units, it is not inspected by MS-DOS; rather, it is set by MS-DOS from
  17538.       the information returned by the Init function.)
  17539.  
  17540.       The BPB pointer array is an array of word offsets to BIOS parameter
  17541.       blocks. See The Build BIOS Parameter Block Function, below;
  17542.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: MS-DOS
  17543.       Storage Devices. The array must contain one entry for each unit
  17544.       defined by the driver, although all entries can point to the same BPB
  17545.       to conserve memory. During the operating-system boot sequence, MS-DOS
  17546.       scans all the BPBs defined by all the units in all the resident block-
  17547.       device drivers to determine the largest sector size that exists on any
  17548.       device in the system; this information is used to set MS-DOS's cache
  17549.       buffer size. Thus, the sector size in the BPB of any installable block
  17550.       driver must be no larger than the largest sector size used by the
  17551.       resident block drivers.
  17552.  
  17553.       If the Init routine finds that its hardware device is missing or
  17554.       defective, it can bypass the installation of the driver completely by
  17555.       returning the following values in the request header:
  17556.  
  17557. ╓┌────────────────────────────────┌──────────────────────────────────────────╖
  17558.       Item                        Value
  17559.       ──────────────────────────────────────────────────────────────────
  17560.       Number of units             0
  17561.       Address of free memory      Segment and offset of the driver's own
  17562.                                   device header
  17563.  
  17564.       A character-device driver must also clear bit 15 of the device
  17565.       attribute word in the device header so that MS-DOS will load the next
  17566.       driver in the same location as the one that just terminated itself.
  17567.  
  17568.       The operating-system services that can be invoked by the Init routine
  17569.       are very limited. Only MS-DOS Interrupt 21H Functions 01-0CH (various
  17570.       character input and output services), 25H (Set Interrupt Vector), 30H
  17571.       (Get MS-DOS Version Number), and 35H (Get Interrupt Vector) can be
  17572.       called by the Init code. These functions assist the driver in
  17573.       configuring itself for the version of the host operating system it is
  17574.       to run under, capturing vectors for hardware interrupts, and
  17575.       displaying informational or error messages.
  17576.  
  17577.       The amount of RAM required by a device driver can be reduced by
  17578.       positioning the Init routine at the end of the driver and returning
  17579.       that routine's starting address as the location of the first free
  17580.       memory.
  17581.  
  17582.       The Media Check function
  17583.       The Media Check function (command code 1) is used only in block-device
  17584.       drivers. It is called by the MS-DOS kernel when there is a pending
  17585.       drive access call other than a simple file read or write (for example,
  17586.       a file open, close, rename, or delete), passing the media ID byte
  17587.       (Figure 15-5) for the disk that MS-DOS assumes is in the drive:
  17588.  
  17589. ╓┌────────────────────────────┌──────────────────────────────────────────────╖
  17590.       Description             Medium
  17591.       ──────────────────────────────────────────────────────────────────
  17592.       0F9H                    5.25-inch double-sided, 15 sectors
  17593.       0FCH                    5.25-inch single-sided, 9 sectors
  17594.       0FDH                    5.25-inch double-sided, 9 sectors
  17595.       0FEH                    5.25-inch single-sided, 8 sectors
  17596.       0FFH                    5.25-inch double-sided, 8 sectors
  17597.       0F9H                    3.5-inch double-sided, 9 sectors
  17598.       0F0H                    3.5-inch double-sided, 18 sectors
  17599.       0F8H                    Fixed disk
  17600.       Description             Medium
  17601.      0F8H                    Fixed disk
  17602.  
  17603.       The function returns a code indicating whether the medium has been
  17604.       changed since the last transfer:
  17605.  
  17606. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  17607.       Code        Meaning
  17608.       ──────────────────────────────────────────────────────────────────
  17609.       -1          Medium changed
  17610.       -0          Don't know if medium changed
  17611.       -1          Medium not changed
  17612.  
  17613.  
  17614.               Driver called with                   Driver returns
  17615.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  17616.           │  Request header length  │        │                         │
  17617.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  17618.           │       Unit number       │        │                         │
  17619.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  17620.           │      Command code       │        │                         │
  17621.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  17622.           │                         │        │                         │
  17623.           │                         │        │         Status          │
  17624.           │                         │        │                         │
  17625.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  17626.           │                         │        │                         │
  17627.           │                         │        │                         │
  17628.           │        Reserved         │        │        Reserved         │
  17629.           │                         │        │                         │
  17630.           │                         │        │                         │
  17631.       0DH ├─────────────────────────┤    0DH ├─────────────────────────┤
  17632.           │      Media ID byte      │        │                         │
  17633.       0EH ├─────────────────────────┤    0EH ├─────────────────────────┤
  17634.           │                         │        │    Media change code    │
  17635.       0FH ├─────────────────────────┤    10H ├─────────────────────────┤
  17636.           │                         │        │                         │
  17637.           │                         │        │    Offset of volume     │
  17638.           │                         │        │    (if error OFH)1     │
  17639.       11H ├─────────────────────────┤    11H ├─────────────────────────┤
  17640.           │                         │        │                         │
  17641.           │                         │        │ Segment of volume label │
  17642.           │                         │        │    (if error OFH)1     │
  17643.           └─────────────────────────┘        └─────────────────────────┘
  17644.  
  17645.       Figure 15-5. Media Check request header (command code 1).
  17646.  
  17647.  
  17648.       If the Media Check routine asserts that the disk has not been changed,
  17649.       MS-DOS bypasses rereading the FAT and proceeds with the disk access.
  17650.       If the returned code indicates that the disk has been changed, MS-DOS
  17651.       invalidates all buffers associated with the drive, including buffers
  17652.       containing data waiting to be written (this data is simply lost),
  17653.       performs a Build BPB call, and then reads the disk's FAT and
  17654.       directory.
  17655.  
  17656.       The action taken by MS-DOS when Don't know is returned depends on the
  17657.       state of its internal buffers. If data that needs to be written out is
  17658.       present in the buffers associated with the drive, MS-DOS assumes that
  17659.       no disk change has occurred. If the buffers are empty or have all been
  17660.       previously flushed to the disk, MS-DOS assumes that the disk was
  17661.       changed and proceeds as described above for the Medium changed return
  17662.       code.
  17663.  
  17664.       If bit 11 of the device attribute word is set (that is, the driver
  17665.       supports the optional Open/Close/Removable Media functions), the host
  17666.       system is MS-DOS version 3.0 or later, and the function returns the
  17667.       Medium changed code (-1), the function must also return the segment
  17668.       and offset of the ASCIIZ volume label for the previous disk in the
  17669.       drive. (If the driver does not have the volume label, it can return a
  17670.       pointer to the ASCIIZ string NO NAME.) If MS-DOS determines that the
  17671.       disk was changed with unwritten data still present in the buffers, it
  17672.       issues a critical error 0FH (Invalid Disk Change). Application
  17673.       programs can trap this critical error and prompt the user to replace
  17674.       the original disk.
  17675.  
  17676.       In character-device drivers, the Media Change function should simply
  17677.       set the done flag in the status word of the request header and return.
  17678.  
  17679.       The Build BIOS Parameter Block function
  17680.       The Build BPB function (command code 2) is supported only on block
  17681.       devices. MS-DOS calls this function when the Medium changed code has
  17682.       been returned by the Media Check routine or when the Don't know code
  17683.       has been returned and there are no dirty buffers (buffers that have
  17684.       not yet been written to disk). Thus, a call to this function indicates
  17685.       that the disk has been legally changed.
  17686.  
  17687.       The Build BPB call receives a pointer to a one-sector buffer in the
  17688.       request header (Figure 15-6). If the non-IBM-format bit (bit 13) in
  17689.       the device attribute word in the device header is zero, the buffer
  17690.       contains the first sector of the disk's FAT, with the media ID byte in
  17691.       the first byte of the buffer. In this case, the contents of the buffer
  17692.       should not be modified by the driver. However, if the non-IBM-format
  17693.       bit is set, the buffer can be used by the driver as scratch space.
  17694.  
  17695.       The Build BPB function must return the segment and offset of a BIOS
  17696.       parameter block (Table 15-4) for the disk format indicated by the
  17697.       media ID byte and set the done flag in the status word of the request
  17698.       header. The information in the BPB is used by the kernel to interpret
  17699.       the disk structure and is also used by the driver itself to translate
  17700.       logical sector addresses into physical track, sector, and head
  17701.       addresses. If bit 11 of the device attribute word is set (that is, the
  17702.       driver supports the optional Open/Close/Removable Media functions) and
  17703.       the host system is MS-DOS version 3.0 or later, this routine should
  17704.       also read the volume label from the disk and save it.
  17705.  
  17706.  
  17707.               Driver called with                   Driver returns
  17708.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  17709.           │  Request header length  │        │                         │
  17710.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  17711.           │       Unit number       │        │                         │
  17712.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  17713.           │      Command code       │        │                         │
  17714.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  17715.           │                         │        │                         │
  17716.           │                         │        │         Status          │
  17717.           │                         │        │                         │
  17718.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  17719.           │                         │        │                         │
  17720.           │                         │        │                         │
  17721.           │        Reserved         │        │        Reserved         │
  17722.           │                         │        │                         │
  17723.           │                         │        │                         │
  17724.       0DH ├─────────────────────────┤    0DH ├─────────────────────────┤
  17725.           │      Media ID byte      │        │                         │
  17726.       0EH ├─────────────────────────┤    0EH ├─────────────────────────┤
  17727.           │                         │        │                         │
  17728.           │  Offset of FAT buffer   │        │                         │
  17729.           │     or scratch area     │        │                         │
  17730.       10H ├─────────────────────────┤    10H ├─────────────────────────┤
  17731.           │                         │        │                         │
  17732.           │  Segment of FAT buffer  │        │                         │
  17733.           │     or scratch area     │        │                         │
  17734.       12H ├─────────────────────────┤    12H ├─────────────────────────┤
  17735.           │                         │        │                         │
  17736.           │                         │        │     Offset of BIOS      │
  17737.           │                         │        │     parameter block     │
  17738.       14H ├─────────────────────────┤    14H ├─────────────────────────┤
  17739.           │                         │        │                         │
  17740.           │                         │        │     Segment of BIOs     │
  17741.           │                         │        │     parameter block     │
  17742.           └─────────────────────────┘        └─────────────────────────┘
  17743.  
  17744.       Figure 15-6. Build BPB request header (command code 2).
  17745.  
  17746.  
  17747.       Table 15-4. Format of a BIOS Parameter Block (BPB).
  17748.  
  17749. ╓┌────────────────┌──────────────────────────────────────────────────────────╖
  17750.       Bytes       Contents
  17751.       ──────────────────────────────────────────────────────────────────
  17752.       00-01H      Bytes per sector
  17753.       02H         Sectors per allocation unit (must be power of 2)
  17754.       03-04H      Number of reserved sectors (starting at sector 0)
  17755.       05H         Number of file allocation tables (FATs)
  17756.       06-07H      Maximum number of root-directory entries
  17757.       08-09H      Total number of sectors in medium
  17758.       0AH         Media ID byte
  17759.       0B-0CH      Number of sectors occupied by a single FAT
  17760.       0D-0EH      Sectors per track (versions 3.0 and later)
  17761.       0F-10H      Number of heads (versions 3.0 and later)
  17762.       11-12H      Number of hidden sectors (versions 3.0 and later)
  17763.       13-14H      High-order word of number of hidden sectors (version 3.2)
  17764.       15-18H      If bytes 8-9 are zero, total number of sectors in medium
  17765.                   (version 3.2)
  17766.  
  17767.  
  17768.       In character-device drivers, the Build BPB function should simply set
  17769.       the done flag in the status word of the request header and return.
  17770.  
  17771.       The Read, Write, and Write with Verify functions
  17772.       The Read (Input) function (command code 4) transfers data from the
  17773.       device into a specified memory buffer. The Write (Output) function
  17774.       (command code 8) transfers data from a specified memory buffer to the
  17775.       device. The Write with Verify function (command code 9) works like the
  17776.       Write function but, if feasible, also performs a read-after-write
  17777.       verification that the data was transferred correctly. The MS-DOS
  17778.       kernel calls the Write with Verify function, instead of the Write
  17779.       function, whenever the system's global verify flag has been turned on
  17780.       with the VERIFY command or with Interrupt 21H Function 2EH (Set Verify
  17781.       Flag).
  17782.  
  17783.       All three of these driver functions are called by the MS-DOS kernel
  17784.       with the address and length of the buffer for the data to be
  17785.       transferred. In the case of block-device drivers, the kernel also
  17786.       passes the drive unit code, the starting logical sector number, and
  17787.       the media ID byte for the disk (Figure 15-7).
  17788.  
  17789.  
  17790.               Driver called with                   Driver returns
  17791.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  17792.           │  Request header length  │        │                         │
  17793.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  17794.           │       Unit number1     │        │                         │
  17795.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  17796.           │      Command code       │        │                         │
  17797.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  17798.           │                         │        │                         │
  17799.           │                         │        │         Status          │
  17800.           │                         │        │                         │
  17801.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  17802.           │                         │        │                         │
  17803.           │                         │        │                         │
  17804.           │        Reserved         │        │        Reserved         │
  17805.           │                         │        │                         │
  17806.           │                         │        │                         │
  17807.       0DH ├─────────────────────────┤    0DH ├─────────────────────────┤
  17808.           │      Media ID byte1    │        │                         │
  17809.       0EH ├─────────────────────────┤    0EH ├─────────────────────────┤
  17810.           │                         │        │                         │
  17811.           │     Offset of data      │        │                         │
  17812.           │                         │        │                         │
  17813.       10H ├─────────────────────────┤    10H ├─────────────────────────┤
  17814.           │                         │        │                         │
  17815.           │     Segment of data     │        │                         │
  17816.           │                         │        │                         │
  17817.       12H ├─────────────────────────┤    12H ├─────────────────────────┤
  17818.           │                         │        │                         │
  17819.           │ Bytes/sectors requested │        │Bytes/sectors transferred│
  17820.           │                         │        │                         │
  17821.       14H ├─────────────────────────┤    14H ├─────────────────────────┤
  17822.           │                         │        │                         │
  17823.           │Starting sector number1 │        │                         │
  17824.           │                         │        │                         │
  17825.       16H ├─────────────────────────┤    16H ├─────────────────────────┤
  17826.           │                         │        │                         │
  17827.           │                         │        │ Offset of volume label  │
  17828.           │                         │        │   (if error OFH)1,2    │
  17829.       18H ├─────────────────────────┤    18H ├─────────────────────────┤
  17830.           │                         │        │                         │
  17831.           │                         │        │ Segment of volume label │
  17832.           │                         │        │   (if error OFH)1,2    │
  17833.           └─────────────────────────┘        └─────────────────────────┘
  17834.  
  17835.       Figure 15-7. The request header for IOCTL Read (command code 3), Read
  17836.       (command code 4), Write (command code 8), Write with Verify (command
  17837.       code 9), IOCTL Write (command code 12), and Output Until Busy (command
  17838.       code 16).
  17839.  
  17840.  
  17841.       The Read and Write functions must perform the requested I/O, first
  17842.       translating each logical sector number for a block device into a
  17843.       physical track, head, and sector with the aid of the BIOS parameter
  17844.       block. Then the functions must return the number of bytes or sectors
  17845.       actually transferred in the appropriate field of the request header
  17846.       and also set the done flag in the request header status word. If an
  17847.       error is encountered during an operation, the functions must set the
  17848.       done flag, the error flag, and the error type in the status word and
  17849.       also report the number of bytes or sectors successfully transferred
  17850.       before the error; it is not sufficient to simply report the error.
  17851.  
  17852.       Under MS-DOS versions 3.0 and later, the Read and Write functions can
  17853.       optionally use the reference count of open files maintained by the
  17854.       driver's Device Open and Device Close functions, together with the
  17855.       media ID byte, to determine whether the medium has been illegally
  17856.       changed. If the medium was changed with files open, the driver can
  17857.       return the error code 0FH and the segment and offset of the volume
  17858.       label for the correct disk so that the user can be prompted to replace
  17859.       the disk.
  17860.  
  17861.       The Nondestructive Read function
  17862.       The Nondestructive Read function (command code 5) is supported only on
  17863.       character devices. It allows MS-DOS to look ahead in the character
  17864.       stream by one character and is used to check for Control-C characters
  17865.       pending at the keyboard.
  17866.  
  17867.       The function is called by the kernel with no parameters other than the
  17868.       command code itself (Figure 15-8). It must set the done bit in the
  17869.       status word of the request header and also set the busy bit in the
  17870.       status word to reflect whether the device's input buffer is empty
  17871.       (busy bit = 1) or contains at least one character (busy bit = 0). If
  17872.       the latter, the function must also return the next character that
  17873.       would be obtained by a kernel call to the Read function, without
  17874.       removing that character from the buffer (hence the term
  17875.       nondestructive).
  17876.  
  17877.       In block-device drivers, the Nondestructive Read function should
  17878.       simply set the done flag in the status word of the request header and
  17879.       return.
  17880.  
  17881.  
  17882.               Driver called with                   Driver returns
  17883.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  17884.           │  Request header length  │        │                         │
  17885.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  17886.           │                         │        │                         │
  17887.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  17888.           │      Command code       │        │                         │
  17889.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  17890.           │                         │        │                         │
  17891.           │                         │        │         Status          │
  17892.           │                         │        │                         │
  17893.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  17894.           │                         │        │                         │
  17895.           │                         │        │                         │
  17896.           │        Reserved         │        │        Reserved         │
  17897.           │                         │        │                         │
  17898.           │                         │        │                         │
  17899.       0DH ├─────────────────────────┤    0DH ├─────────────────────────┤
  17900.           │                         │        │        Character        │
  17901.           └─────────────────────────┘        └─────────────────────────┘
  17902.  
  17903.       Figure 15-8. The Nondestructive Read request header.
  17904.  
  17905.  
  17906.       The Input Status and Output Status functions
  17907.       The Input Status and Output Status functions (command codes 6 and 10)
  17908.       are defined only for character devices. They are called with no
  17909.       parameters in the request header other than the command code itself
  17910.       and return their results in the busy bit of the request header status
  17911.       word (Figure 15-9). These functions constitute the driver-level
  17912.       support for the services the MS-DOS kernel provides to application
  17913.       programs by means of Interrupt 21H Function 44H Subfunctions 06H and
  17914.       07H (Check Input Status and Check Output Status).
  17915.  
  17916.       MS-DOS calls the Input Status function to determine whether there are
  17917.       characters waiting in a type-ahead buffer. The function sets the done
  17918.       bit in the status word of the request header and sets the busy bit to
  17919.       0 if at least one character is already in the input buffer or to 1 if
  17920.       no characters are in the buffer and a read request would wait on a
  17921.       character from the physical device. If the character device does not
  17922.       have a type-ahead buffer, the Input Status routine should always
  17923.       return the busy bit set to 0 so that MS-DOS will not wait for
  17924.       something to arrive in the buffer before calling the Read function.
  17925.  
  17926.  
  17927.               Driver called with                   Driver returns
  17928.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  17929.           │  Request header length  │        │                         │
  17930.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  17931.           │                         │        │                         │
  17932.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  17933.           │      Command code       │        │                         │
  17934.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  17935.           │                         │        │                         │
  17936.           │                         │        │         Status          │
  17937.           │                         │        │                         │
  17938.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  17939.           │                         │        │                         │
  17940.           │                         │        │                         │
  17941.           │        Reserved         │        │        Reserved         │
  17942.           │                         │        │                         │
  17943.           │                         │        │                         │
  17944.       0DH └─────────────────────────┘    0DH └─────────────────────────┘
  17945.  
  17946.       Figure 15-9. The request header for Input Status (command code 6),
  17947.       Flush Input Buffers (command code 7), Output Status (command code 10),
  17948.       and Flush Output Buffers (command code 11).
  17949.  
  17950.  
  17951.       MS-DOS uses the Output Status function to determine whether a write
  17952.       operation is already in progress for the device. The function must set
  17953.       the done bit and the busy bit (0 if the device is idle and a write
  17954.       request would start immediately; 1 if a write is already in progress
  17955.       and a new write request would be delayed) in the status word of the
  17956.       request header.
  17957.  
  17958.       In block-device drivers, the Input Status and Output Status functions
  17959.       should simply set the done flag in the status word of the request
  17960.       header and return.
  17961.  
  17962.       The Flush Input Buffer and Flush Output Buffer functions
  17963.       The Flush Input Buffer and Flush Output Buffer functions (command
  17964.       codes 7 and 11) are defined only for character devices. They simply
  17965.       terminate any read (for Flush Input) or write (for Flush Output)
  17966.       operations that are in progress and empty the associated buffer. The
  17967.       Flush Input Buffer function is used by MS-DOS to discard characters
  17968.       waiting in the type-ahead queue. This driver action corresponds to the
  17969.       MS-DOS service provided to application programs by means of Interrupt
  17970.       21H Function 0CH (Flush Buffer, Read Keyboard).
  17971.  
  17972.       These functions are called with no parameters in the request header
  17973.       other than the command code itself (see Figure 15-9) and return only
  17974.       the status word.
  17975.  
  17976.       In block-device drivers, the Flush Buffer functions have no meaning.
  17977.       They should simply set the done flag in the status word of the request
  17978.       header and return.
  17979.  
  17980.       The IOCTL Read and IOCTL Write functions
  17981.       The IOCTL (I/O Control) Read and IOCTL Write functions (command codes
  17982.       3 and 12) allow control information to be passed directly between a
  17983.       device driver and an application program. The IOCTL Read and Write
  17984.       driver functions are called by the MS-DOS kernel only if the IOCTL
  17985.       flag (bit 14) is set in the device attribute word of the device
  17986.       header.
  17987.  
  17988.       The MS-DOS kernel passes the address and length of the buffer that
  17989.       contains or will receive the IOCTL information (see Figure 15-7). The
  17990.       driver must return the actual count of bytes transferred and set the
  17991.       done flag in the request header status word. Any error code returned
  17992.       by the driver is ignored by the kernel.
  17993.  
  17994.       IOCTL Read and IOCTL Write operations are typically used to configure
  17995.       a driver or device or to report driver or device status and do not
  17996.       usually result in the transfer of data to or from the physical device.
  17997.       These functions constitute the driver support for the services
  17998.       provided to application programs by the MS-DOS kernel through
  17999.       Interrupt 21H Function 44H Subfunctions 02H, 03H, 04H, and 05H
  18000.       (Receive Control Data from Character Device, Send Control Data to
  18001.       Character Device, Receive Control Data from Block Device, and Send
  18002.       Control Data to Block Device).
  18003.  
  18004.       The Device Open and Device Close functions
  18005.       The Device Open and Device Close functions (command codes 13 and 14)
  18006.       are supported only in MS-DOS versions 3.0 and later and are called
  18007.       only if the open/close/removable media flag (bit 11) is set in the
  18008.       device attribute word of the device header. The Device Open and Device
  18009.       Close functions have no parameters in the request header other than
  18010.       the unit code for block devices and return nothing except the done
  18011.       flag and, if applicable, the error flag and number in the request
  18012.       header status word (Figure 15-10).
  18013.  
  18014.  
  18015.               Driver called with                   Driver returns
  18016.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  18017.           │  Request header length  │        │                         │
  18018.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  18019.           │      Unit number1      │        │                         │
  18020.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  18021.           │      Command code       │        │                         │
  18022.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  18023.           │                         │        │                         │
  18024.           │                         │        │         Status          │
  18025.           │                         │        │                         │
  18026.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  18027.           │                         │        │                         │
  18028.           │                         │        │                         │
  18029.           │        Reserved         │        │        Reserved         │
  18030.           │                         │        │                         │
  18031.           │                         │        │                         │
  18032.       0DH └─────────────────────────┘    0DH └─────────────────────────┘
  18033.  
  18034.       Figure 15-10. The request header for Device Open (command code 13),
  18035.       Device Close (command code 14), and Removable Media (command code 15).
  18036.  
  18037.  
  18038.       Each Interrupt 21H request by an application to open or create a file
  18039.       or to open a character device for input or output results in a Device
  18040.       Open call by the kernel to the corresponding device driver. Similarly,
  18041.       each Interrupt 21H call by an application to close a file or device
  18042.       results in a Device Close call by the kernel to the appropriate device
  18043.       driver. These Device Open and Device Close calls are in addition to
  18044.       any directory read or write calls that may be necessary.
  18045.  
  18046.       On block devices, the Device Open and Device Close functions can be
  18047.       used to manage local buffering and to maintain a reference count of
  18048.       the number of open files on a device. Whenever this reference count is
  18049.       decremented to zero, all files on the disk have been closed and the
  18050.       driver should flush any internal buffers so that data is not lost, as
  18051.       the user may be about to change disks. The reference count can also be
  18052.       used together with the media ID byte by the Read and Write functions
  18053.       to determine whether the disk has been changed while files are still
  18054.       open.
  18055.  
  18056.       The reference count should be forced to zero when a Media Check call
  18057.       that returns the Medium changed code is followed by a Build BPB call,
  18058.       to provide for those programs that use FCBs to open files and then
  18059.       never close them. This problem does not arise with programs that use
  18060.       the handle functions for file management, because all handles are
  18061.       always closed automatically by MS-DOS on behalf of the program when it
  18062.       terminates. See PROGRAMMING IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR
  18063.       MS-DOS: File and Record Management.
  18064.  
  18065.       On character devices, the Device Open and Device Close functions can
  18066.       be used to send hardware-dependent initialization and post-I/O strings
  18067.       to the associated device (for example, a reset sequence or formfeed
  18068.       character to precede new output and a formfeed to follow it). Although
  18069.       these strings can be written directly by an application using ordinary
  18070.       write function calls, they can also be previously passed to the driver
  18071.       by application programs with IOCTL Write calls (Interrupt 21H Function
  18072.       44H Subfunction 05H), which in turn are translated by the MS-DOS
  18073.       kernel into driver command code 12 (IOCTL Write) requests. The latter
  18074.       method makes the driver responsible for sending the proper control
  18075.       strings to the device each time a Device Open or Device Close is
  18076.       executed, but this method can be used only with drivers specifically
  18077.       written to support it.
  18078.  
  18079.       The Removable Media function
  18080.       The Removable Media function (command code 15) is defined only for
  18081.       block devices. It is supported in MS-DOS versions 3.0 and later and is
  18082.       called by MS-DOS only if the open/ close/removable media flag (bit 11)
  18083.       is set in the device attribute word of the device header. This
  18084.       function constitutes the driver-level support for the service provided
  18085.       to application programs by MS-DOS by means of Interrupt 21H Function
  18086.       44H Subfunction 08H (Check If Block Device Is Removable).
  18087.  
  18088.       The only parameter for the Removable Media function is the unit code
  18089.       (see Figure 15-10). The function sets the done bit in the request
  18090.       header status word and sets the busy bit to 1 if the disk is not
  18091.       removable or to 0 if the disk is removable. This information can be
  18092.       used by MS-DOS to optimize its accesses to the disk and to eliminate
  18093.       unnecessary FAT and directory reads.
  18094.  
  18095.       In character-device drivers, the Removable Media function should
  18096.       simply set the done flag in the status word of the request header and
  18097.       return.
  18098.  
  18099.       The Output Until Busy function
  18100.       The Output Until Busy function (command code 16) is defined only for
  18101.       character devices under MS-DOS versions 3.0 and later and is called by
  18102.       the MS-DOS kernel only if the corresponding flag (bit 13) is set in
  18103.       the device attribute word of the device header. This function is an
  18104.       optional driver-optimization function included specifically for the
  18105.       benefit of background print spoolers driving printers that have
  18106.       internal memory buffers. Such printers can accept data at a rapid rate
  18107.       until the buffer is full.
  18108.  
  18109.       The Output Until Busy function is called with the address and length
  18110.       of the data to be written to the device (see Figure 15-7). It
  18111.       transfers data continuously to the device until the device indicates
  18112.       that it is busy or until the data is exhausted. The function then must
  18113.       set the done flag in the request header status word and return the
  18114.       actual number of bytes transferred in the appropriate field of the
  18115.       request header.
  18116.  
  18117.       For this function to return a count of bytes transferred that is less
  18118.       than the number of bytes requested is not an error. MS-DOS will adjust
  18119.       the address and length of the data passed in the next Output Until
  18120.       Busy function request so that all characters are sent.
  18121.  
  18122.       In block-device drivers, the Output Until Busy function should simply
  18123.       set the done flag in the status word of the request header and return.
  18124.  
  18125.       The Generic IOCTL function
  18126.       The Generic IOCTL function (command code 19) is defined under MS-DOS
  18127.       version 3.2 and is called only if the 3.2-functions-supported flag
  18128.       (bit 6) is set in the device attribute word of the device header. This
  18129.       driver function corresponds to the MS-DOS generic IOCTL service
  18130.       supplied to application programs by means of Interrupt 21H Function
  18131.       44H Subfunctions 0CH (Generic I/O Control for Handles) and 0DH
  18132.       (Generic I/O Control for Block Devices).
  18133.  
  18134.       In addition to the usual information in the static portion of the
  18135.       request header, the Generic IOCTL function is passed a category
  18136.       (major) code, a function (minor) code, the contents of the SI and DI
  18137.       registers at the point of the IOCTL call, and the segment and offset
  18138.       of a data buffer (Figure 15-11). This buffer in turn contains other
  18139.       information whose format depends on the major and minor IOCTL codes
  18140.       passed in the request header. The driver must interpret the major and
  18141.       minor codes in the request header and the contents of the additional
  18142.       buffer to determine which operation it will carry out and then set the
  18143.       done flag in the request header status word and return any other
  18144.       applicable information in the request header or the data buffer.
  18145.  
  18146.       Services that can be invoked by the Generic IOCTL function, if the
  18147.       driver supports them, include configuring the driver for nonstandard
  18148.       disk formats, reading and writing entire disk tracks of data, and
  18149.       formatting and verifying tracks. The Generic IOCTL function has been
  18150.       designed to be open-ended so that it can be used to easily extend the
  18151.       device driver definition in future versions of MS-DOS.
  18152.  
  18153.  
  18154.               Driver called with                   Driver returns
  18155.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  18156.           │  Request header length  │        │                         │
  18157.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  18158.           │       Unit number1     │        │                         │
  18159.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  18160.           │      Command code       │        │                         │
  18161.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  18162.           │                         │        │                         │
  18163.           │                         │        │         Status          │
  18164.           │                         │        │                         │
  18165.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  18166.           │                         │        │                         │
  18167.           │                         │        │                         │
  18168.           │        Reserved         │        │        Reserved         │
  18169.           │                         │        │                         │
  18170.           │                         │        │                         │
  18171.       0DH ├─────────────────────────┤    0DH ├─────────────────────────┤
  18172.           │ Category (major) code   │        │                         │
  18173.       0EH ├─────────────────────────┤    0EH ├─────────────────────────┤
  18174.           │ Function (minor) code   │        │                         │
  18175.       0FH ├─────────────────────────┤    0FH ├─────────────────────────┤
  18176.           │                         │        │                         │
  18177.           │  SI register contents   │        │                         │
  18178.           │                         │        │                         │
  18179.       11H ├─────────────────────────┤    11H ├─────────────────────────┤
  18180.           │                         │        │                         │
  18181.           │  DI register contents   │        │                         │
  18182.           │                         │        │                         │
  18183.       13H ├─────────────────────────┤    13H ├─────────────────────────┤
  18184.           │                         │        │                         │
  18185.           │    Offset of generic    │        │                         │
  18186.           │    IOCTL data packet    │        │                         │
  18187.       15H ├─────────────────────────┤    15H ├─────────────────────────┤
  18188.           │                         │        │                         │
  18189.           │   Segment of generic    │        │                         │
  18190.           │    IOCTL data packet    │        │                         │
  18191.           └─────────────────────────┘        └─────────────────────────┘
  18192.  
  18193.       Figure 15-11. Generic IOCTL request header.
  18194.  
  18195.  
  18196.       The Get Logical Device and Set Logical Device functions
  18197.       The Get and Set Logical Device functions (command codes 23 and 24) are
  18198.       defined only for block devices under MS-DOS version 3.2 and are called
  18199.       only if the 3.2-functions-supported flag (bit 6) is set in the device
  18200.       attribute word of the device header. They correspond to the Get and
  18201.       Set Logical Drive Map services supplied by MS-DOS to application
  18202.       programs by means of Interrupt 21H Function 44H Subfunctions 0EH and
  18203.       0FH.
  18204.  
  18205.       The Get and Set Logical Device functions are called with a drive unit
  18206.       number in the request header (Figure 15-12). Both functions return a
  18207.       status word for the operation in the request header; the Get Logical
  18208.       Device function also returns a unit number.
  18209.  
  18210.       The Get Logical Device function is called to determine whether more
  18211.       than one drive letter is assigned to the same physical device. It
  18212.       returns a code for the last drive letter used to reference the device
  18213.       (1 = A, 2 = B, and so on); if only one drive letter is assigned to the
  18214.       device, the returned unit code should be 0.
  18215.  
  18216.       The Set Logical Device function is called to inform the driver of the
  18217.       next logical drive identifier that will be used to reference the
  18218.       device. The unit code passed by the MS-DOS kernel in this case is zero
  18219.       based relative to the logical drives supported by this particular
  18220.       driver. For example, if the driver supports two logical floppy-disk-
  18221.       drive units (A and B), only one physical disk drive exists in the
  18222.       system, and Set Logical Device is called with a unit number of 1, the
  18223.       driver is being informed that the next read or write request from the
  18224.       MS-DOS kernel will be directed to drive B.
  18225.  
  18226.  
  18227.               Driver called with                   Driver returns
  18228.       00H ┌─────────────────────────┐    00H ┌─────────────────────────┐
  18229.           │  Request header length  │        │                         │
  18230.       01H ├─────────────────────────┤    01H ├─────────────────────────┤
  18231.           │       Unit number       │        │  Last device driver1   │
  18232.       02H ├─────────────────────────┤    02H ├─────────────────────────┤
  18233.           │      Command code       │        │                         │
  18234.       03H ├─────────────────────────┤    03H ├─────────────────────────┤
  18235.           │                         │        │                         │
  18236.           │                         │        │         Status          │
  18237.           │                         │        │                         │
  18238.       05H ├─────────────────────────┤    05H ├─────────────────────────┤
  18239.           │                         │        │                         │
  18240.           │                         │        │                         │
  18241.           │        Reserved         │        │        Reserved         │
  18242.           │                         │        │                         │
  18243.           │                         │        │                         │
  18244.       0DH └─────────────────────────┘    0DH └─────────────────────────┘
  18245.  
  18246.       Figure 15-12. Get Logical Device and Set Logical Device request
  18247.       header.
  18248.  
  18249.  
  18250.       In character-device drivers, the Get Logical Device and Set Logical
  18251.       Device functions should simply set the done flag in the status word of
  18252.       the request header and return.
  18253.  
  18254.  
  18255.  The Processing of a Typical I/O Request
  18256.  
  18257.       An application program requests an I/O operation from MS-DOS by
  18258.       loading registers with the appropriate values and addresses and
  18259.       executing a software Interrupt 21H. MS-DOS inspects its internal
  18260.       tables, searches the chain of device headers if necessary, and
  18261.       determines which device driver should receive the I/O request.
  18262.  
  18263.       MS-DOS then creates a request header data packet in a reserved area of
  18264.       memory. Disk I/O requests are transformed from file and record
  18265.       information into logical sector requests by MS-DOS's interpretation of
  18266.       the disk directory and file allocation table. (MS-DOS locates these
  18267.       disk structures using the information returned by the driver from a
  18268.       previous Build BPB call and issues additional driver read requests, if
  18269.       necessary, to bring their sectors into memory.)
  18270.  
  18271.       After the request header is prepared, MS-DOS calls the device driver's
  18272.       Strategy entry point, passing the address of the request header in
  18273.       registers ES:BX. The Strategy routine saves the address of the request
  18274.       header and performs a far return to MS-DOS.
  18275.  
  18276.       MS-DOS then immediately calls the device driver's Interrupt entry
  18277.       point. The Interrupt routine saves all registers, retrieves the
  18278.       address of the request header that was saved by the Strategy routine,
  18279.       extracts the command code, and branches to the appropriate function to
  18280.       perform the operation requested by MS-DOS. When the requested function
  18281.       is complete, the Interrupt routine sets the done flag in the status
  18282.       word and places any other required information into the request
  18283.       header, restores all registers to their state at entry, and performs a
  18284.       far return.
  18285.  
  18286.       MS-DOS translates the driver's returned status into the appropriate
  18287.       carry flag status, register values, and (possibly) error code for the
  18288.       MS-DOS Interrupt 21H function that was requested and returns control
  18289.       to the application program. Figure 15-13 sketches this entire flow of
  18290.       control and data.
  18291.  
  18292.  
  18293.                    ┌─────────────────────────────────────────┐
  18294.                    │           Application program           │
  18295.                    └─────────────────┬──────────────────────┘
  18296.                                      │       │
  18297.          Interrupt 21H Function 3FH, │       │ Read status returned
  18298.                  Read File or Device │       │ in carry flag and AX register
  18299.                                      │       │
  18300.                    ┌────────────────────────┴───────────────┐
  18301.                    │              MS-DOS kernel              │
  18302.                    └─────────────────┬──────────────────────┘
  18303.       Calls to driver Strategy, then │       │ Status returned to MS-DOS
  18304.           Interrupt routine, passing │       │ kernel in request header,
  18305.          request header with command │       │ data placed in buffer
  18306.                 code 4, Read (Input) │       │ indicated by kernel
  18307.                    ┌────────────────────────┴───────────────┐
  18308.                    │              Device driver              │
  18309.                    └─────────────────┬──────────────────────┘
  18310.            Device commands issued to │       │ Data transferred from
  18311.        adapter I/O ports, requesting │       │ device to memory
  18312.       read sector at physical track, │       │
  18313.              head, and sector number │       │
  18314.                    ┌────────────────────────┴───────────────┐
  18315.                    │             Physical device             │
  18316.                    └─────────────────────────────────────────┘
  18317.  
  18318.       Figure 15-13. The processing of a typical I/O request from an
  18319.       application program.
  18320.  
  18321.  
  18322.       Note that a single Interrupt 21H function request by an application
  18323.       program can result in many operation requests by MS-DOS to the device
  18324.       driver. For example, if the application invokes Interrupt 21H Function
  18325.       3DH (Open File with Handle) to open a file, MS-DOS may have to issue
  18326.       multiple sector read requests to the driver while searching the
  18327.       directory for the filename. Similarly, an application program's
  18328.       request to write a string to the screen in cooked mode with Interrupt
  18329.       21H Function 40H (Write File or Device) will result in a write request
  18330.       to the driver for each character in the string, because MS-DOS filters
  18331.       the characters and polls the keyboard for a pending Control-C between
  18332.       each character output.
  18333.  
  18334.  
  18335.  Writing Device Drivers
  18336.  
  18337.       Device drivers are traditionally coded in assembly language, both
  18338.       because of the rigid structural requirements and because of the need
  18339.       to keep driver execution speed high and memory overhead low. Although
  18340.       MS-DOS versions 3.0 and later are capable of loading drivers in .EXE
  18341.       format, versions 2.x can load only pure memory-image device drivers
  18342.       that do not require relocation. Therefore, drivers are typically
  18343.       written as though they were .COM programs with an "origin" of zero and
  18344.       converted with EXE2BIN to .BIN or .SYS files so that they will be
  18345.       compatible with any version of MS-DOS (2.0 or later). See PROGRAMMING
  18346.       IN THE MS-DOS ENVIRONMENT: PROGRAMMING FOR MS-DOS: Structure of an
  18347.       Application Program.
  18348.  
  18349.       The device header must be located at the beginning of the file (offset
  18350.       0). Both words in the header's link field should be set to -1, thus
  18351.       allowing MS-DOS to fix up the link field when the driver is loaded
  18352.       during system initialization so that it points to the next driver in
  18353.       the chain. When a single file contains more than one driver, the
  18354.       offset portion of each header link field should point to the next
  18355.       header in that file, all using the same segment base of zero, and only
  18356.       the link field of the last header in the file should be set to -1, -1.
  18357.  
  18358.       The device attribute word must reflect the device-driver type
  18359.       (character or block) and the bits that indicate support for the
  18360.       various optional command codes must have appropriate values. The
  18361.       device header's offsets to the Strategy and Interrupt routines must be
  18362.       relative to the same segment base as the device header itself. If the
  18363.       driver is for a character device, the name field should be filled in
  18364.       properly with the device's logical name, which can be any legal eight-
  18365.       character uppercase filename padded with spaces and without a colon.
  18366.       Duplication of existing character-device names or existing disk-file
  18367.       names should be avoided (unless a resident character-device driver is
  18368.       being intentionally superseded).
  18369.  
  18370.       The Strategy and Interrupt routines for the device are called by MS-
  18371.       DOS by means of an intersegment call (CALL FAR) and must return to MS-
  18372.       DOS with a far return. Both routines must preserve all CPU registers
  18373.       and flags. The MS-DOS kernel's stack has room for 40 to 50 bytes when
  18374.       the driver is called; if the driver makes heavy use of the stack, it
  18375.       should switch to an internal stack of adequate depth.
  18376.  
  18377.       The Strategy routine is, of course, very simple. It need only save the
  18378.       address of the request header that is passed to it in registers ES:BX
  18379.       and exit back to the kernel.
  18380.  
  18381.       The logic of the Interrupt routine is necessarily more complex. It
  18382.       must save the CPU registers and flags, extract the command code from
  18383.       the request header whose address was previously saved by the Strategy
  18384.       routine, and dispatch the appropriate command-code function. When that
  18385.       function is finished, the Interrupt routine must ensure that the
  18386.       appropriate status and other information is placed in the request
  18387.       header, restore the CPU registers and flags, and return control to the
  18388.       kernel.
  18389.  
  18390.       Although the interface between the MS-DOS kernel and the command-code
  18391.       routines is fairly simple, it is also strict. The command-code
  18392.       functions must behave exactly as they are defined or the system will
  18393.       behave erratically. Even a very subtle discrepancy in the action of a
  18394.       driver function can have unexpectedly large global effects. For
  18395.       example, if a block driver Read function returns an error but does not
  18396.       return a correct value for the number of sectors successfully
  18397.       transferred, the MS-DOS kernel will be misled in its attempts to retry
  18398.       the read for only the failing sectors and disk data might be
  18399.       corrupted.
  18400.  
  18401.  Example character driver: TEMPLATE
  18402.  
  18403.       Figure 15-14 contains the source code for a skeleton character-device
  18404.       driver called TEMPLATE.ASM. This driver does nothing except display a
  18405.       sign-on message when it is loaded, but it demonstrates all the
  18406.       essential driver components, including the device header, Strategy
  18407.       routine, and Interrupt routine. The command-code functions take no
  18408.       action other than to set the done flag in the request header status
  18409.       word.
  18410.  
  18411.       ──────────────────────────────────────────────────────────────────────
  18412.  
  18413.       Figure 15-14. TEMPLATE.ASM, the source file for the TEMPLATE.SYS
  18414.       driver.
  18415.  
  18416.       ──────────────────────────────────────────────────────────────────────
  18417.  
  18418.       TEMPLATE.ASM can be assembled, linked, and converted into a loadable
  18419.       driver with the following commands:
  18420.  
  18421.       C>MASM TEMPLATE;  <Enter>
  18422.       C>LINK TEMPLATE;  <Enter>
  18423.       C>EXE2BIN TEMPLATE.EXE TEMPLATE.SYS  <Enter>
  18424.  
  18425.       The Microsoft Object Linker (LINK) will display the warning message No
  18426.       Stack Segment; this message can be ignored. The driver can then be
  18427.       installed by adding the line
  18428.  
  18429.       DEVICE=TEMPLATE.SYS
  18430.  
  18431.       to the CONFIG.SYS file and restarting the system. The fact that the
  18432.       TEMPLATE.SYS driver also has the logical character-device name
  18433.       TEMPLATE allows the demonstration of an interesting MS-DOS effect:
  18434.       After the driver is installed, the file that contains it can no longer
  18435.       be copied, renamed, or deleted. The reason for this limitation is that
  18436.       MS-DOS always searches its list of character-device names first when
  18437.       an open request is issued, before it inspects the disk directory. The
  18438.       only way to erase the TEMPLATE.SYS file is to modify the CONFIG.SYS
  18439.       file to remove the associated DEVICE statement and then restart the
  18440.       system.
  18441.  
  18442.       For a complete example of a character-device driver for interrupt-
  18443.       driven serial communications, See PROGRAMMING IN THE MS-DOS
  18444.       ENVIRONMENT: STRUCTURE OF MS-DOS: Interrupt-Driven Communications.
  18445.  
  18446.  Example block driver: TINYDISK
  18447.  
  18448.       Figure 15-15 contains the source code for a simple 64 KB virtual disk
  18449.       (RAMdisk) called TINYDISK.ASM. This code provides a working example of
  18450.       a simple block-device driver. When its Initialization routine is
  18451.       called by the kernel, TINYDISK allocates itself 64 KB of RAM and maps
  18452.       a disk structure onto the RAM in the form of a boot sector containing
  18453.       a valid BPB, a FAT, a root directory, and a files area. See
  18454.       PROGRAMMING IN THE MS-DOS ENVIRONMENT: STRUCTURE OF MS-DOS: MS-DOS
  18455.       Storage Devices.
  18456.  
  18457.       ──────────────────────────────────────────────────────────────────────
  18458.  
  18459.       Figure 15-15. TINYDISK.ASM, the source file for the TINYDISK.SYS
  18460.       driver.
  18461.  
  18462.       ──────────────────────────────────────────────────────────────────────
  18463.  
  18464.       Subsequent driver Read and Write calls by the kernel to TINYDISK
  18465.       function as though they were transferring sectors to and from a
  18466.       physical storage device but actually only copy data from one area in
  18467.       memory to another. A programmer can learn a great deal about the
  18468.       operation of block-device drivers and MS-DOS's relationship to those
  18469.       drivers (such as the order and frequency of Media Change, Build BPB,
  18470.       Read, Write, and Write With Verify calls) by inserting software probes
  18471.       into TINYDISK at appropriate locations and monitoring its behavior.
  18472.  
  18473.       TINYDISK.ASM can be assembled, linked, and converted into a loadable
  18474.       driver with the following commands:
  18475.  
  18476.       MASM TINYDISK;
  18477.       LINK TINYDISK;
  18478.       EXE2BIN TINYDISK.EXE TINYDISK.SYS
  18479.  
  18480.       The linker will display the warning message No Stack Segment; this
  18481.       message can be ignored. The driver can then be installed by adding the
  18482.       line
  18483.  
  18484.       DEVICE=TINYDISK.SYS
  18485.  
  18486.       to the CONFIG.SYS file and restarting the system. When it is loaded,
  18487.       TINYDISK displays a sign-on message and the drive letter that it was
  18488.       assigned if it is running under MS-DOS version 3.0 or later. (If the
  18489.       host system is MS-DOS version 2.x, this information is not provided to
  18490.       the driver.) Files can then be copied to the RAMdisk as though it were
  18491.       a small but extremely fast disk drive.
  18492.  
  18493.                                                    Ray Duncan
  18494.  
  18495.  
  18496.  
  18497.  ───────────────────────────────────────────────────────────────────────────
  18498.  
  18499.  Part D  Directions of MS-DOS
  18500.  
  18501.  
  18502.  
  18503.  Article 16: Writing Applications for Upward Compatibility
  18504.  
  18505.  
  18506.       One of the major concerns of the designers of Microsoft OS/2 was that
  18507.       it be backwardly compatible--that is, that programs written to run
  18508.       under MS-DOS versions 2 and 3 be able to run on MS OS/2. A major
  18509.       concern for present application programmers is that their programs run
  18510.       not only on current versions of MS-DOS (and MS OS/2) but also on
  18511.       future versions of MS-DOS. Ensuring such upward compatibility involves
  18512.       both hardware issues and operating-system issues.
  18513.  
  18514.  
  18515.  Hardware Issues
  18516.  
  18517.       A basic requirement for ensuring upward compatibility is hardware-
  18518.       independent code. If you bypass system services and directly program
  18519.       the hardware--such as the system interrupt controller, the system
  18520.       clock, and the enhanced graphics adapter (EGA) registers--your
  18521.       application will not run on future versions of MS-DOS.
  18522.  
  18523.  Protected mode compatibility
  18524.  
  18525.       The 80286 and the 80386 microprocessors can operate in two
  18526.       incompatible modes: real mode and protected mode. When either chip is
  18527.       operating in real mode, it is perceived by the operating system and
  18528.       programs as a fast 8088 chip. Applications written for the 8086 and
  18529.       8088 run the same on the 80286 and the 80386--only faster. They
  18530.       cannot, however, take advantage of 80286 and 80386 features unless
  18531.       they can run in protected mode.
  18532.  
  18533.       Following the guidelines below will minimize the work necessary to
  18534.       convert a real mode program to protected mode and will also allow a
  18535.       program to use a special subset of the MS OS/2 Applications Program
  18536.       Interface (API)--Family API. A binary program (.EXE) that uses the
  18537.       family API can run in either protected mode or real mode under MS OS/2
  18538.       and subsequent systems, but it can run only in real mode under MS-DOS
  18539.       version 3.
  18540.  
  18541.  Family API
  18542.  
  18543.       The Family API requires that the application use a subset of the MS
  18544.       OS/2 Dynamic Link System API. Special tools link the application with
  18545.       a special library that implements the subset MS OS/2 system services
  18546.       in the MS-DOS version 3 environment. Many of these services are
  18547.       implemented by calling the appropriate Interrupt 21H subfunction; some
  18548.       are implemented in the special library itself.
  18549.  
  18550.       When a Family API application is loaded under MS OS/2 protected mode,
  18551.       MS OS/2 ignores the special library code and loads only the
  18552.       application itself. MS OS/2 then provides the requested services in
  18553.       the normal fashion. However, MS-DOS version 3 loads the entire
  18554.       package--the application and the special library--because the Family
  18555.       API.EXE file is constructed to look like an MS-DOS 3.EXE file.
  18556.  
  18557.  Linear vs segmented memory
  18558.  
  18559.       The protected mode and the real mode of the 80286 and the 80386 are
  18560.       compatible except in the area of segmentation. The 8086 has been
  18561.       described as a segmented machine, but it is actually a linear memory
  18562.       machine with offset registers. When a memory address is generated, the
  18563.       value in one of the "segment" registers is multiplied by 16 and added
  18564.       as a displacement to the offset value supplied by the instruction's
  18565.       addressing mode. No length information is associated with each
  18566.       "segment"; the "segment" register supplies only a 20-bit addressing
  18567.       offset. Programs routinely use this by computing a 20-bit address and
  18568.       then decomposing it into a 16-bit "segment" value and a 16-bit
  18569.       displacement value so that the address can be referenced.
  18570.  
  18571.       The protected mode of the 80286 and the 80386, however, is truly
  18572.       segmented. A value placed in a segment register selects an entry from
  18573.       a descriptor table; that entry contains the addressing offset, a
  18574.       segment length, and permission bits. On the 8086, the so-called
  18575.       segment component of an address is multiplied by 16 and added to the
  18576.       offset component, producing a 20-bit physical address. Thus, if you
  18577.       take an address in the segment:offset form, add 4 to the segment
  18578.       value, and subtract 64 (that is, 4 * 16) from the offset value, the
  18579.       new address references exactly the same location as the old address.
  18580.       On the 80286 and the 80386 in protected mode, however, segment values,
  18581.       called segment selectors, have no direct correspondence to physical
  18582.       addresses. In other words, in 8086 mode, the two address forms
  18583.  
  18584.       1000(sub 16):0345(sub 16)
  18585.  
  18586.       and
  18587.  
  18588.       1004(sub 16):0305(sub 16)
  18589.  
  18590.       reference the same memory location, but in protected mode these two
  18591.       forms reference totally different locations.
  18592.  
  18593.  Creating segment values
  18594.       This architectural difference gives rise to the most common cause of
  18595.       incompatibility--the program performs addressing arithmetic to compute
  18596.       "segment" values. Any program that uses the 20-bit addressing scheme
  18597.       to create or to compute a value to be loaded in a segment register
  18598.       cannot be converted to run in protected mode. To be protected mode
  18599.       compatible, a program must treat the 8086's so-called segments as true
  18600.       segments.
  18601.  
  18602.       To create a program that does this, write according to the following
  18603.       guidelines:
  18604.  
  18605.       1. Do not generate any segment values. Use only the segment values
  18606.          supplied by MS-DOS calls and those placed in the segment registers
  18607.          when MS-DOS loaded your program. The exception is "huge objects"--
  18608.          memory objects larger than 64 KB. In this case, MS OS/2 provides a
  18609.          base segment number and a "segment offset value." The returned
  18610.          segment number selects the first 64 KB of the object and the
  18611.          segment number, plus the segment offset value address the second
  18612.          64 KB of the object. Likewise, the returned segment value plus
  18613.          N*(segment offset value) selects the N+1 64 KB piece of the huge
  18614.          object. Write real mode code in this same fashion, using 4096 as
  18615.          the segment offset value. When you convert your program, you can
  18616.          substitute the value provided by MS OS/2.
  18617.  
  18618.       2. Do not address beyond the allocated length of a segment.
  18619.  
  18620.       3. Do not use segment registers as scratch registers by placing
  18621.          general data in them. Place only valid segment values, supplied by
  18622.          MS-DOS, in a segment register. The one exception is that you can
  18623.          place a zero value in a segment register, perhaps to indicate "no
  18624.          address." You can place the zero in the segment register, but you
  18625.          cannot reference memory using that register; you can only
  18626.          load/store or push/pop it.
  18627.  
  18628.       4. Do not use CS: overrides on instructions that store into memory. It
  18629.          is impossible to store into a code segment in protected mode.
  18630.  
  18631.  CPU speed
  18632.  
  18633.       Because various microprocessors and machine configurations execute at
  18634.       different speeds, a program should not contain timing loops that
  18635.       depend on CPU speed. Specifically, a program should not establish CPU
  18636.       speed during initialization and then use that value for timing loops
  18637.       because the preemptive scheduling of MS OS/2 and future operating
  18638.       systems can "take away" the CPU at any time for arbitrary and
  18639.       unpredictable lengths of time. (In any case, time should not be wasted
  18640.       in a timing loop when other processes could be using system
  18641.       resources.)
  18642.  
  18643.  Program timing
  18644.  
  18645.       Programs must measure the passage of time carefully. They can use the
  18646.       system clock-tick interrupt while directly interfacing with the user,
  18647.       but no clock ticks will be seen by real mode programs when the user
  18648.       switches the screen interface to another program.
  18649.  
  18650.       It is recommended that applications use the time-of-day system
  18651.       interface to determine elapsed time. To facilitate conversion to MS
  18652.       OS/2 protected mode, programs should encapsulate time-of-day or
  18653.       elapsed-time functions into subroutines.
  18654.  
  18655.  BIOS
  18656.  
  18657.       Avoid BIOS interrupt interfaces except for Interrupt 10H (the screen
  18658.       display functions) and Interrupt 16H (the keyboard functions).
  18659.       Interrupt 10H functions are contained in the MS OS/2 VIO package, and
  18660.       Interrupt 16H functions are in the MS OS/2 KBD package. Other BIOS
  18661.       interrupts provide functions that are available under MS OS/2 only in
  18662.       considerably modified forms.
  18663.  
  18664.  Special operations
  18665.  
  18666.       Uncommon, or special, operations and instructions can produce varied
  18667.       results, depending on the microprocessor. For example, when a "divide
  18668.       by 0" trap is taken on an 8086, the stack frame points to the
  18669.       instruction after the fault; when such action is taken on the 80286
  18670.       and 80386, the return address points to the instruction that caused
  18671.       the fault. The effect of pushing the SP register is different between
  18672.       the 80286 and the 80386 as well. See Appendix M: 8086/8088 Software
  18673.       Compatibility Issues. Write your program to avoid these problem areas.
  18674.  
  18675.  
  18676.  Operating-System Issues
  18677.  
  18678.       Basic to writing programs that will run on future operating systems is
  18679.       writing code that is not version specific. Incorporating special
  18680.       version-specific features in a program will virtually ensure that the
  18681.       program will be incompatible with future versions of MS-DOS and MS
  18682.       OS/2.
  18683.  
  18684.       Following the guidelines below will not necessarily ensure your
  18685.       program's compatibility, but it will facilitate converting the program
  18686.       or using the Family API to produce a dual-mode binary program.
  18687.  
  18688.  Filenames
  18689.  
  18690.       MS-DOS versions 2 and 3 silently truncate a filename that is longer
  18691.       than eight characters or an extension that is longer than three
  18692.       characters. MS-DOS generates no error message when performing this
  18693.       task. In real mode, MS OS/2 also silently truncates a filename or
  18694.       extension that exceeds the maximum length; in protected mode, however,
  18695.       it does not. Therefore, a real mode application program needs to
  18696.       perform this truncating function. The program should check the length
  18697.       of the filenames that it generates or that it obtains from a user and
  18698.       refuse names that are longer than the eight-character maximum. This
  18699.       prevents improperly formatted names from becoming embedded in data and
  18700.       control files--a situation that could cause a protected mode version
  18701.       of the application to fail when it presents that invalid name to the
  18702.       operating system.
  18703.  
  18704.       When you convert your program to protected mode API, remove the
  18705.       length-checking code; MS OS/2 will check the length and return an
  18706.       error code as appropriate. Future file systems will support longer
  18707.       filenames, so it's important that protected mode programs simply
  18708.       present filenames to the operating system, which is then responsible
  18709.       for judging their validity.
  18710.  
  18711.       Other MS-DOS version 2 and 3 elements have fixed lengths, including
  18712.       the current directory path. To be upwardly compatible, your program
  18713.       should accept whatever length is provided by the user or returned from
  18714.       a system call and rely on MS OS/2 to return an error message if a
  18715.       length is inappropriate. The exception is filename length in real mode
  18716.       non-Family API programs: These programs should enforce the eight-
  18717.       character maximum because MS-DOS versions 2 and 3 fail to do so.
  18718.  
  18719.  File truncation
  18720.       Files are truncated by means of a zero-length write under MS-DOS
  18721.       versions 2 and 3; under MS OS/2 in protected mode, files are truncated
  18722.       with a special API. File truncation operations should be encapsulated
  18723.       in a special routine to facilitate conversion to MS OS/2 protected
  18724.       mode or the Family API.
  18725.  
  18726.  File searches
  18727.       MS-DOS versions 2 and 3 never close file-system searches (Find First
  18728.       File/Find Next File). The returned search contains the information
  18729.       necessary for MS-DOS to continue the search later, and if the search
  18730.       is never continued, no harm is done.
  18731.  
  18732.       MS OS/2, however, retains the necessary search continuation
  18733.       information in an internal structure of limited size. For this reason,
  18734.       your program should not depend on more than about 10 simultaneous
  18735.       searches and it should be able to close searches when it is done. If
  18736.       your program needs to perform more than about 10 searches
  18737.       simultaneously, it should be able to close a search, restart it later,
  18738.       and advance to the place where the program left off, rather than
  18739.       depending on MS OS/2 to continue the search.
  18740.  
  18741.       MS OS/2 further provides a Find Close function that releases the
  18742.       internal search information. Protected mode programs should use this
  18743.       call at the end of every search sequence. Because MS-DOS versions 2
  18744.       and 3 have no such call, your program should call a dummy procedure by
  18745.       this name at the appropriate locations. Then you can convert your
  18746.       program to the protected mode API or to the Family API without
  18747.       reexamining your algorithms.
  18748.  
  18749.        Note: Receiving a "No more files" return code from a search does not
  18750.       implicitly close the search; all search closes must be explicit.
  18751.  
  18752.       The Family API allows only a single search at a time. To circumvent
  18753.       this restriction, code two different Find Next File routines in your
  18754.       program--one for MS OS/2 protected mode and one for MS-DOS real mode--
  18755.       and use the Family API function that determines the program's current
  18756.       environment to select the routine to execute.
  18757.  
  18758.  MS-DOS calls
  18759.  
  18760.       A program that uses only the Interrupt 21H functions listed below is
  18761.       guaranteed to work in the Compatibility Box of MS OS/2 and will be
  18762.       relatively easy to modify for MS OS/2 protected mode.
  18763.  
  18764. ╓┌─────────────────────┌─────────────────────────────────────────────────────╖
  18765.       Function         Name
  18766.       ──────────────────────────────────────────────────────────────────
  18767.       0DH              Disk Reset
  18768.       0EH              Select Disk
  18769.       19H              Get Current Disk
  18770.       1AH              Set DTA Address
  18771.       25H              Set Interrupt Vector
  18772.       2AH              Get Date
  18773.       2BH              Set Date
  18774.       2CH              Get Time
  18775.       2EH              Set/Reset Verify Flag
  18776.       Function         Name
  18777.      2EH              Set/Reset Verify Flag
  18778.       2FH              Get DTA Address
  18779.       30H              Get MS-DOS Version Number
  18780.       33H              Get/Set Control-C Check Flag
  18781.       35H              Get Interrupt Vector
  18782.       36H              Get Disk Free Space
  18783.       38H              Get/Set Current Country
  18784.       39H              Create Directory
  18785.       3AH              Remove Directory
  18786.       3BH              Change Current Directory
  18787.       3CH              Create File with Handle
  18788.       3DH              Open File with Handle
  18789.       3EH              Close File
  18790.       3FH              Read File or Device
  18791.       40H              Write File or Device
  18792.       41H              Delete File
  18793.       42H              Move File Pointer
  18794.       43H              Get/Set File Attributes
  18795.       44H              IOCTL (all subfunctions)
  18796.       45H              Duplicate File Handle
  18797.       Function         Name
  18798.      45H              Duplicate File Handle
  18799.       46H              Force Duplicate File Handle
  18800.       47H              Get Current Directory
  18801.       48H              Allocate Memory Block
  18802.       49H              Free Memory Block
  18803.       4AH              Resize Memory Block
  18804.       4BH              Load and Execute Program (EXEC)
  18805.       4CH              Terminate Process with Return Code
  18806.       4DH              Get Return Code of Child Process
  18807.       4EH              Find First File
  18808.       4FH              Find Next File
  18809.       54H              Get Verify Flag
  18810.       56H              Rename File
  18811.       57H              Get/Set Date/Time of File
  18812.       59H              Get Extended Error Information
  18813.       5AH              Create Temporary File
  18814.       5BH              Create New File
  18815.       5CH              Lock/Unlock File Region
  18816.  
  18817.  FCBs
  18818.       FCBs are not supported in MS OS/2 protected mode. Use handle-based
  18819.       calls instead.
  18820.  
  18821.  Interrupt calls
  18822.       MS-DOS versions 2 and 3 use an interrupt-based interface; MS OS/2
  18823.       protected mode uses a procedure-call interface. Write your code to
  18824.       accommodate this difference by encapsulating the interrupt-based
  18825.       interfaces into individual subroutines that can then easily be
  18826.       modified to use the MS OS/2 procedure-call interface.
  18827.  
  18828.  System call register usage
  18829.       The MS OS/2 procedure-call interface preserves all registers except AX
  18830.       and FLAGS. Write your program to assume that the contents of AX and
  18831.       the contents of any register modified by MS-DOS version 2 and 3
  18832.       interrupt interfaces are destroyed at each system call, regardless of
  18833.       the success or failure of that call.
  18834.  
  18835.  Flush/Commit calls
  18836.       Your program should issue Flush/Commit calls where necessary--for
  18837.       example, after writing out the user's work file--but no more than
  18838.       necessary. Because MS OS/2 is multitasking, the floppy disk that
  18839.       contains the files to be flushed may not be in the drive. In such a
  18840.       case, MS OS/2 prompts the user to insert the proper floppy disk. As a
  18841.       result, too frequent flushes could generate a great many Insert disk
  18842.       messages and degrade the system's usability.
  18843.  
  18844.  Seeks
  18845.  
  18846.       Seeks to negative offsets and to devices also create compatibility
  18847.       issues.
  18848.  
  18849.  To negative offsets
  18850.       Your program should not attempt to seek to a negative file location. A
  18851.       negative seek offset is permissible as long as the sum of the seek
  18852.       offset and the current file position is positive. MS-DOS versions 2
  18853.       and 3 allow seeking to a negative offset as long as you do not attempt
  18854.       to read or write the file at that offset. MS OS/2 and subsequent
  18855.       systems return an error code for negative net offsets.
  18856.  
  18857.  On devices
  18858.       Your program should not issue seeks to devices (such as AUX, COM, and
  18859.       so on). Doing so produces an error under MS OS/2.
  18860.  
  18861.  Error codes
  18862.  
  18863.       Because future releases of the operating system may return new error
  18864.       codes to system calls, you should write code that is open-ended about
  18865.       error codes--that is, write your program to deal with error codes
  18866.       beyond those currently defined. You can generally do this by including
  18867.       special handling for any codes that require special treatment, such as
  18868.       "File not found," and by taking a generic course of action for all
  18869.       other errors. The MS OS/2 protected mode API and the Family API have
  18870.       an interface that contains a message describing the error; this
  18871.       message can be displayed to the user. The interface also returns error
  18872.       classification information and a recommended action.
  18873.  
  18874.  Multitasking concerns
  18875.  
  18876.       Multitasking is a feature of MS OS/2 and will be a feature of all
  18877.       future versions of MS-DOS. The following guidelines apply to all
  18878.       programs, even to those written for MS-DOS version 3, because they may
  18879.       run in compatibility mode under MS OS/2.
  18880.  
  18881.  Disabling interrupts
  18882.       Do not disable interrupts, typically with the CLI instruction. The
  18883.       consequences of doing so depend on the environment.
  18884.  
  18885.       In real mode programs under MS OS/2, disabling interrupts works
  18886.       normally but has a negative impact on the system's ability to maintain
  18887.       proper system throughput. Communications programs or networking
  18888.       applications might lose data. In a future version of real mode MS
  18889.       OS/2-80386, the operating system will disregard attempts to disable
  18890.       interrupts.
  18891.  
  18892.       Protected mode programs under MS OS/2 can disable interrupts only in
  18893.       special Ring 2 segments. Disabling interrupts for longer than 100
  18894.       microseconds might cause communications programs or networking
  18895.       applications to lose data or break connection. A future 80386-specific
  18896.       version of MS OS/2 will ignore attempts to disable interrupts in
  18897.       protected mode programs.
  18898.  
  18899.  Measuring system resources
  18900.       Do not attempt to measure system resources by exhausting them, and do
  18901.       not assume that because a resource is available at one time it will be
  18902.       available later. Remember: System resources are being shared with
  18903.       other programs.
  18904.  
  18905.       For example, it is common for an MS-DOS version 3 application to
  18906.       request 1 MB of memory. The system cannot fulfill this request, so it
  18907.       returns the largest amount of memory available. The application then
  18908.       requests that amount of memory. Typically, applications do not even
  18909.       check for an error code from the second request. They routinely
  18910.       request all available memory because their creators knew that no other
  18911.       application could be in the system at the same time. This practice
  18912.       will work in real mode MS OS/2, although it is inefficient because MS
  18913.       OS/2 must allocate memory to a program that has no effective use for
  18914.       it. However, this practice will not work under MS OS/2 protected mode
  18915.       or under the Family API.
  18916.  
  18917.       Another typical resource-exhaustion technique is opening files until
  18918.       an open is refused and then closing unneeded file handles. All
  18919.       applications, even those that run only in an MS OS/2 real mode
  18920.       environment, must use only the resources they need and not waste
  18921.       system resources; in a multitasking environment, other programs in the
  18922.       system usually need those resources.
  18923.  
  18924.  Sharing rules
  18925.       Because multiple programs can run under MS OS/2 simultaneously and
  18926.       because the system can be networked, conflicts can occur when two
  18927.       programs try to access the same file. MS OS/2 handles this situation
  18928.       with special file-sharing support. Although programs ignorant of file-
  18929.       sharing rules can run in real mode, you should explicitly specify
  18930.       file-sharing rules in your program. This will reduce the number of
  18931.       file-access conflicts the user will encounter.
  18932.  
  18933.  Miscellaneous guidelines
  18934.  
  18935.       Do not use undocumented features of MS-DOS or undocumented fields such
  18936.       as those in the Find First File buffer. Also, do not modify or store
  18937.       your own values in such areas.
  18938.  
  18939.       Maintain at least 2048 free bytes on the stack at all times. Future
  18940.       releases of MS-DOS may require extra stack space at system call and at
  18941.       interrupt time.
  18942.  
  18943.       Print using conventional handle writes to the LPT device(s). For
  18944.       example:
  18945.  
  18946.       fd = open("LPT1");
  18947.       write(fd, data, datalen);
  18948.  
  18949.       Do not use Interrupt 17H (the IBM ROM BIOS printer services), writes
  18950.       to the stdprn handle (handle 3), or special-purpose Interrupt 21H
  18951.       functions such as 05H (Printer Output). These methods are not
  18952.       supported under MS OS/2 protected mode or in the Family API.
  18953.  
  18954.       Do not use the MS-DOS standard handles stdaux and stdprn (handles 3
  18955.       and 4); these handles are not supported in MS OS/2 protected mode. Use
  18956.       only stdin (handle 0), stdout (handle 1), and stderr (handle 2). Do
  18957.       use these latter handles where appropriate and avoid opening the CON
  18958.       device directly. Avoid Interrupt 21H Functions 03H (Auxiliary Input)
  18959.       and 04H (Auxiliary Output), which are polling operations on stdaux.
  18960.  
  18961.  
  18962.  Summary
  18963.  
  18964.       A tenet of MS OS/2 design was flexibility: Each component was
  18965.       constructed in anticipation of massive changes in a future release and
  18966.       with an eye toward existing versions of MS-DOS. Writing applications
  18967.       that are upwardly and backwardly compatible in such an environment is
  18968.       essential--and challenging. Following the guidelines in this article
  18969.       will ensure that your programs function appropriately in the
  18970.       MS-DOS/OS/2 operating system family.
  18971.  
  18972.                                                         Gordon Letwin
  18973.  
  18974.  
  18975.  
  18976.  Article 17: Windows
  18977.  
  18978.  
  18979.       Microsoft Windows is an operating environment that runs under MS-DOS
  18980.       versions 2.0 and later. The current version of Windows, version 2.0,
  18981.       requires either a fixed disk or two double-sided floppy-disk drives,
  18982.       at least 320 KB of memory, and a video display board and monitor
  18983.       capable of graphics and a screen resolution of at least 640
  18984.       (horizontal) by 200 (vertical) pixels. A fixed disk and 640 KB of
  18985.       memory provide the best environment for running Windows; a mouse or
  18986.       other pointing device is optional but recommended.
  18987.  
  18988.       For the user, Windows provides a multitasking, graphics-based
  18989.       windowing environment for running programs. In this environment, users
  18990.       can easily switch among several programs and transfer data between
  18991.       them. Because programs specially designed to run under Windows usually
  18992.       have a consistent user interface, the time spent learning a new
  18993.       program is greatly diminished. Furthermore, the user can carry out
  18994.       command functions using only the keyboard, only the mouse, or some
  18995.       combination of the two. In some cases, Windows (and Windows
  18996.       applications) provides several different ways to execute the same
  18997.       command.
  18998.  
  18999.       For the program developer, Windows provides a wealth of high-level
  19000.       routines that make it easy to incorporate menus, scroll bars, and
  19001.       dialog boxes (which contain controls, such as push buttons and list
  19002.       boxes) into programs. Windows' graphics interface is device
  19003.       independent, so programs developed for Windows work with every video
  19004.       display adapter and printer that has a Windows driver (usually
  19005.       supplied by the hardware manufacturer). Windows also includes features
  19006.       that facilitate the translation of programs into foreign languages for
  19007.       international markets.
  19008.  
  19009.       When Windows is running, it shares responsibility for managing system
  19010.       resources with MS-DOS. Thus, programs that run under Windows continue
  19011.       to use MS-DOS function calls for all file input and output and for
  19012.       executing other programs, but they do not use MS-DOS for display or
  19013.       printer output, keyboard or mouse input, or memory management.
  19014.       Instead, they use functions provided by Windows.
  19015.  
  19016.  
  19017.  Program Categories
  19018.  
  19019.       Programs that run under Windows can be divided into three categories:
  19020.  
  19021.       1. Programs specially designed for the Windows environment. Examples
  19022.          of such programs include Clock and Calculator, which come with
  19023.          Windows. Microsoft Excel is also specially designed for Windows.
  19024.          Other programs of this type (such as Aldus's Pagemaker) are
  19025.          available from software vendors other than Microsoft. Programs in
  19026.          this category cannot run under MS-DOS without Windows.
  19027.  
  19028.       2. Programs designed to run under MS-DOS but that can usually be run
  19029.          in a window along with programs designed specially for Windows.
  19030.          These programs do not require large amounts of memory, do
  19031.          not write directly to the display, do not use graphics, and do not
  19032.          alter the operation of the keyboard interrupt. They cannot use the
  19033.          mouse, the Windows application-program interface (such as menus and
  19034.          dialog boxes), or the graphics services that Windows provides.
  19035.          MS-DOS utilities, such as EDLIN and CHKDSK, are examples of
  19036.          programs in this category.
  19037.  
  19038.       3. Programs designed to run under MS-DOS but that require large
  19039.          amounts of memory, write directly to the display, use graphics, or
  19040.          alter the operation of the keyboard interrupt. When Windows runs
  19041.          such a program, it must suspend operation of all other programs
  19042.          running in Windows and allow the program to use the full screen. In
  19043.          some cases, Windows cannot switch back to its normal display until
  19044.          the program terminates. Microsoft Word and Lotus 1-2-3 are examples
  19045.          of programs in this category.
  19046.  
  19047.       The programs in categories 2 and 3 are sometimes called standard
  19048.       applications. To run one of these programs in Windows, the user must
  19049.       create a PIF file (Program Information File) that describes how much
  19050.       memory the program requires and how it uses the computer's hardware.
  19051.  
  19052.       Although the ability to run existing MS-DOS programs under Windows
  19053.       benefits the user, the primary purpose of Windows is to provide an
  19054.       environment for specially designed programs that take full advantage
  19055.       of the Windows interface. This discussion therefore concentrates
  19056.       almost exclusively on programs written for the Windows 2.0
  19057.       environment.
  19058.  
  19059.  
  19060.  The Windows Display
  19061.  
  19062.       Figure 17-1 shows a typical Windows display running several programs
  19063.       that are included with the retail version of Windows 2.0.
  19064.  
  19065.       The display is organized as a desktop, with each program occupying one
  19066.       or more rectangular windows that, unlike the tiled (juxtaposed)
  19067.       windows typical of earlier versions, can be overlapped. Only one
  19068.       program is active at any time--usually the program that is currently
  19069.       receiving keyboard input. Windows displays the currently active
  19070.       program on top of (overlying) the others. Programs such as CLOCK and
  19071.       TERMINAL that are not active continue to run normally, but do not
  19072.       receive keyboard input.
  19073.  
  19074.       The user can make another program active by pressing and releasing
  19075.       (clicking) the mouse button when the mouse cursor is positioned in the
  19076.       new program's window or by pressing either the Alt-Tab or Alt-Esc key
  19077.       combination. Windows then brings the new active program to the top.
  19078.  
  19079.       Most Windows programs allow their windows to be moved to another part
  19080.       of the display or to be resized to occupy smaller or larger areas.
  19081.       Most of these programs can also be maximized to fill the entire screen
  19082.       or minimized--generally as a small icon displayed at the bottom of the
  19083.       screen--to occupy a small amount of display space.
  19084.  
  19085.  
  19086.               ╔══════════════════════════════════════════╗
  19087.               ║                                          ║
  19088.               ║    Figure 17-1 is found on page 501      ║
  19089.               ║    in the printed version of the book.   ║
  19090.               ║                                          ║
  19091.               ╚══════════════════════════════════════════╝
  19092.  
  19093.       Figure 17-1. A typical Windows display.
  19094.  
  19095.  
  19096.  Parts of the window
  19097.  
  19098.       Figure 17-2 shows the Windows NOTEPAD program, with the different
  19099.       parts of the window identified. NOTEPAD is a small ASCII text editor
  19100.       limited to files of 16 KB. The various parts of the NOTEPAD window
  19101.       (similar to all Windows programs) are described in this section.
  19102.  
  19103.  
  19104.               ╔══════════════════════════════════════════╗
  19105.               ║                                          ║
  19106.               ║    Figure 17-2 is found on page 502      ║
  19107.               ║    in the printed version of the book.   ║
  19108.               ║                                          ║
  19109.               ╚══════════════════════════════════════════╝
  19110.  
  19111.       Figure 17-2. The Windows NOTEPAD program, with different parts of the
  19112.       display labeled.
  19113.  
  19114.  
  19115.       Title bar (or caption bar). The title bar identifies the program and,
  19116.       if applicable, the data file currently loaded into the program. For
  19117.       example, the NOTEPAD window shown in Figure 17-2 has the file WIN.INI
  19118.       loaded into memory. Windows uses different title-bar colors to distin-
  19119.       guish the active window from inactive windows. The user can move a
  19120.       window to another part of the display by pressing the mouse button
  19121.       when the mouse pointer is positioned anywhere on the title bar and
  19122.       dragging (moving) the mouse while the button is pressed.
  19123.  
  19124.       System-menu icon. When the user clicks a system-menu icon with the
  19125.       mouse (or presses Alt-Spacebar), Windows displays a system menu like
  19126.       that shown in Figure 17-3. (Most Windows programs have identical
  19127.       system menus.) The user selects a menu item in one of several ways:
  19128.       clicking on the item; moving the highlight bar to the item with the
  19129.       cursor-movement keys and then pressing Enter; or pressing the letter
  19130.       that is underlined in the menu item (for example, n for
  19131.       Minimimize).
  19132.  
  19133.       The keyboard combinations (Alt plus function key) at the right of the
  19134.       system menu are keyboard accelerators. Using a keyboard accelerator,
  19135.       the user can select system-menu options without first displaying the
  19136.       system menu.
  19137.  
  19138.       The six options on the standard system menu are
  19139.  
  19140.       ■  Restore: Return the window to its previous position and size after
  19141.          it has been minimized or maximized.
  19142.  
  19143.       ■  Move: Allow the window to be moved with the cursor-movement keys.
  19144.  
  19145.       ■  Size: Allow the window to be resized with the cursor-movement keys.
  19146.  
  19147.       ■  Minimize: Display the window in its iconic form.
  19148.  
  19149.       ■  Maximize: Allow the window to occupy the full screen.
  19150.  
  19151.       ■  Close: End the program.
  19152.  
  19153.       Windows displays an option on the system menu in grayed text to
  19154.       indicate that the option is not currently valid. In the system menu
  19155.       shown in Figure 17-3, for example, the Restore option is grayed
  19156.       because the window is not in a minimized or maximized form.
  19157.  
  19158.  
  19159.               ╔══════════════════════════════════════════╗
  19160.               ║                                          ║
  19161.               ║    Figure 17-3 is found on page 502      ║
  19162.               ║    in the printed version of the book.   ║
  19163.               ║                                          ║
  19164.               ╚══════════════════════════════════════════╝
  19165.  
  19166.       Figure 17-3. A system menu, displayed either when the user clicks the
  19167.       system-menu icon (top left corner) or presses Alt-Spacebar.
  19168.  
  19169.  
  19170.       Minimize icon. When the user clicks on the minimize icon with the
  19171.       mouse, Windows displays the program in its iconic form.
  19172.  
  19173.       Maximize icon. Clicking on the maximize icon expands the window to
  19174.       fill the full screen. Windows then replaces the maximize icon with a
  19175.       restore icon (shown in Figure 17-4). Clicking on the restore icon
  19176.       restores the window to its previous size and position.
  19177.  
  19178.  
  19179.               ╔══════════════════════════════════════════╗
  19180.               ║                                          ║
  19181.               ║    Figure 17-4 is found on page 503      ║
  19182.               ║    in the printed version of the book.   ║
  19183.               ║                                          ║
  19184.               ╚══════════════════════════════════════════╝
  19185.  
  19186.       Figure 17-4. The restore icon, which replaces the maximize icon when a
  19187.       window is expanded to fill the entire screen.
  19188.  
  19189.  
  19190.       Programs that use a window of a fixed size (such as the CALC.EXE
  19191.       calculator program included with Windows) do not have a maximize icon.
  19192.  
  19193.       Menu bar. The menu bar, sometimes called the program's main or top-
  19194.       level menu, displays keywords for several sets of commands that differ
  19195.       from program to program.
  19196.  
  19197.       When the user clicks on a main-menu item with the mouse or presses the
  19198.       Alt key and the underlined letter in the menu text, Windows displays a
  19199.       pop-up menu for that item. The pop-up menu for NOTEPAD's keyword File
  19200.       is shown in Figure 17-5. Items are selected from a pop-up menu in the
  19201.       same way they are selected from the system menu.
  19202.  
  19203.  
  19204.               ╔══════════════════════════════════════════╗
  19205.               ║                                          ║
  19206.               ║    Figure 17-5 is found on page 503      ║
  19207.               ║    in the printed version of the book.   ║
  19208.               ║                                          ║
  19209.               ╚══════════════════════════════════════════╝
  19210.  
  19211.       Figure 17-5. The NOTEPAD program's pop-up file menu.
  19212.  
  19213.  
  19214.       A Windows program can display options on the menu in grayed text to
  19215.       indicate that they are not currently valid. The program can also
  19216.       display checkmarks to the left of pop-up menu items to indicate which
  19217.       of several options have been selected by the user.
  19218.  
  19219.       In addition, items on a pop-up menu can be followed by an ellipsis
  19220.       (...) to indicate that selecting the item invokes a dialog box that
  19221.       prompts the user for additional information-more than can be provided
  19222.       by the menu.
  19223.  
  19224.       Client area. The client area of the window is where the program
  19225.       displays data. In the case of the NOTEPAD program shown in Figure
  19226.       17-2, the client area displays the file currently being edited. A
  19227.       program's handling of keyboard and mouse input within the client area
  19228.       depends on the type of work it does.
  19229.  
  19230.       Scroll bars. Programs that cannot display all the data in a file
  19231.       within the client area of the window often have a horizontal scroll
  19232.       bar across the bottom and a vertical scroll bar down the right edge.
  19233.       Both types of scroll bars have a small, boxed arrow at each end to
  19234.       indicate the direction in which to scroll. In the NOTEPAD window in
  19235.       Figure 17-2, for example, clicking on the up arrow of the vertical
  19236.       scroll bar moves the data within the window down one line. Clicking
  19237.       on the shaded part of the vertical scroll bar above the thumb (the
  19238.       box near the middle moves the data within the client area of the
  19239.       window down one screen; clicking below the thumb moves the data up one
  19240.       screen. The user can also drag the thumb with the mouse to move to
  19241.       a relative position within the file.
  19242.  
  19243.       Windows programs often include a keyboard interface (generally relying
  19244.       on the cursor-movement keys) to duplicate the mouse-based scroll-bar
  19245.       commands.
  19246.  
  19247.       Window border. The window border is a thick frame surrounding the
  19248.       entire window. It is segmented into eight sections that represent the
  19249.       four sides and four corners of the window. The user can change the
  19250.       size of a window by dragging the window border with the mouse.
  19251.       Dragging a corner section moves two adjacent sides of the border.
  19252.  
  19253.       When a program is maximized to fill the full screen, Windows does not
  19254.       draw the window border. Programs that use a window of a fixed size do
  19255.       not have a window border either.
  19256.  
  19257.  Dialog boxes
  19258.  
  19259.       When a pop-up menu is not adequate for all the command options a
  19260.       program requires, the program can display a dialog box. A dialog box
  19261.       is a pop-up window that contains various controls in the form of push
  19262.       buttons, check boxes, radio buttons, list boxes, and text and edit
  19263.       fields. Programmers can also design their own controls for use in
  19264.       dialog boxes. A user fills in a dialog box and then clicks on a
  19265.       button, such as OK, or presses Enter to indicate that the information
  19266.       can be processed by the program.
  19267.  
  19268.       Most Windows programs use a dialog box to open an existing data file
  19269.       and load it into the program. The program displays the dialog box when
  19270.       the user selects the Open option on the File pop-up menu. The sample
  19271.       dialog box shown in Figure 17-6 is from the NOTEPAD program.
  19272.  
  19273.       The list box displays a list of all valid disk drives, the
  19274.       subdirectories of the current directory, and all the filenames in the
  19275.       current directory, including the filename extension used by the
  19276.       program. (NOTEPAD uses the extension .TXT for its data files.) The
  19277.       user can scroll through this list box and change the current drive or
  19278.       subdirectory or select a filename with the keyboard or the mouse. The
  19279.       user can also perform these actions by typing the name directly into
  19280.       the edit field.
  19281.  
  19282.  
  19283.               ╔══════════════════════════════════════════╗
  19284.               ║                                          ║
  19285.               ║    Figure 17-6 is found on page 504      ║
  19286.               ║    in the printed version of the book.   ║
  19287.               ║                                          ║
  19288.               ╚══════════════════════════════════════════╝
  19289.  
  19290.       Figure 17-6. A dialog box from the NOTEPAD program, with parts
  19291.       labeled.
  19292.  
  19293.  
  19294.       Clicking the Open button (or pressing Enter) indicates to NOTEPAD that
  19295.       a file has been selected or that a new drive or subdirectory has been
  19296.       chosen (in this case, the program displays the files on the new drive
  19297.       or subdirectory). Clicking the Cancel button (or pressing Esc) tells
  19298.       NOTEPAD to close the dialog box without loading a new file.
  19299.  
  19300.       Figure 17-7 shows a different dialog box--this one from the Windows
  19301.       TERMINAL communications program. The check boxes turn options on
  19302.       (indicated by an X) and off. The circular radio buttons allow the user
  19303.       to select from a set of mutually exclusive options.
  19304.  
  19305.  
  19306.               ╔══════════════════════════════════════════╗
  19307.               ║                                          ║
  19308.               ║    Figure 17-7 is found on page 505      ║
  19309.               ║    in the printed version of the book.   ║
  19310.               ║                                          ║
  19311.               ╚══════════════════════════════════════════╝
  19312.  
  19313.       Figure 17-7. A dialog box from the TERMINAL program, with parts
  19314.       labeled.
  19315.  
  19316.  
  19317.       Another, simple form of a dialog box is called a message box. This box
  19318.       displays one or more lines of text, an optional icon such as an
  19319.       exclamation point or an asterisk, and one or more buttons containing
  19320.       the words OK, Yes, No, or Cancel. Programs sometimes use message boxes
  19321.       for warnings or error messages.
  19322.  
  19323.  
  19324.  The MS-DOS Executive
  19325.  
  19326.       Within Windows, the MS-DOS Executive program (shown in Figure 17-8)
  19327.       serves much the same function as the COMMAND.COM program in the MS-DOS
  19328.       environment.
  19329.  
  19330.  
  19331.               ╔══════════════════════════════════════════╗
  19332.               ║                                          ║
  19333.               ║    Figure 17-8 is found on page 506      ║
  19334.               ║    in the printed version of the book.   ║
  19335.               ║                                          ║
  19336.               ╚══════════════════════════════════════════╝
  19337.  
  19338.       Figure 17-8. The MS-DOS Executive.
  19339.  
  19340.  
  19341.       The top of the MS-DOS Executive client area displays all valid disk
  19342.       drives. The current disk drive is highlighted. Below or to the right
  19343.       of the disk drives is a display of the full path of the current
  19344.       directory. Below this is an alphabetic listing of all subdirectories
  19345.       in the current directory, followed by an alphabetic listing of all
  19346.       files in the current directory. Subdirectory names are displayed in
  19347.       boldface to distinguish them from filenames.
  19348.  
  19349.       The user can change the current drive by clicking on the disk drive
  19350.       with the mouse or by pressing Ctrl and the key corresponding to the
  19351.       disk drive letter.
  19352.  
  19353.       To change to one of the parent directories, the user double-clicks
  19354.       (clicks the mouse button twice in succession) on the part of the text
  19355.       string corresponding to the directory name. Pressing the Backspace key
  19356.       moves up one directory level toward the root directory. The user can
  19357.       also change the current directory to a child subdirectory by double-
  19358.       clicking on the subdirectory name in the list or by pressing the Enter
  19359.       key when the cursor highlight is on the subdirectory name. In
  19360.       addition, the menu also contains an option for changing the current
  19361.       directory.
  19362.  
  19363.       The user can run a program by double-clicking on the program filename,
  19364.       by pressing the Enter key when the highlight is on the program name,
  19365.       or by selecting it from a menu.
  19366.  
  19367.       Other menu options allow the user to display the file and subdirectory
  19368.       lists in a variety of ways. A long format includes the same
  19369.       information displayed by the MS-DOS DIR command, or the user can
  19370.       choose to display a select group of files. Menu options also enable
  19371.       the user to specify whether the files should be listed in alphabetic
  19372.       order by filename, by filename extension, or by date or size.
  19373.  
  19374.       The remaining options on the MS-DOS Executive menu allow the user to
  19375.       run programs; copy, rename, and delete files; format a floppy disk;
  19376.       change a volume name; make a system disk; create a subdirectory; and
  19377.       print a text file.
  19378.  
  19379.  
  19380.  Other Windows Programs
  19381.  
  19382.       Windows 2.0 also includes a number of application and utility
  19383.       programs. The application programs are CALC (a calculator), CALENDAR,
  19384.       CARDFILE (a database arranged as a series of index cards), CLOCK,
  19385.       NOTEPAD, PAINT (a drawing and painting program), REVERSI (a game),
  19386.       TERMINAL, and WRITE (a word processor).
  19387.  
  19388.       The utility programs include:
  19389.  
  19390.       CLIPBRD. This program displays the current contents of the Clipboard,
  19391.       which is a storage facility that allows users to transfer data from
  19392.       one program to another.
  19393.  
  19394.       CONTROL. The Control Panel utility allows the user to add or delete
  19395.       font files and printer drivers and to change the following: current
  19396.       printer, printer output port, communications parameters, date and
  19397.       time, cursor blink rate, screen colors, border width, mouse double-
  19398.       click time and options, and country-specific information, such
  19399.       as time and date formats. The Control Panel stores much of this
  19400.       information in the file named WIN.INI (Windows Initialization), so
  19401.       the information is available to other Windows programs.
  19402.  
  19403.       PIFEDIT. The PIF editor allows the user to create or modify the PIFs
  19404.       that contain information about standard applications that have not
  19405.       been specially designed to run under Windows. This information allows
  19406.       Windows to adjust the environment in which the program runs.
  19407.  
  19408.       SPOOLER. Windows uses the print-spooler utility to print files without
  19409.       suspending the operation of other programs. Most printer-directed
  19410.       output from Windows programs goes to the print spooler, which then
  19411.       prints the files while other programs run. SPOOLER enables the user to
  19412.       change the priority of print jobs or to cancel them.
  19413.  
  19414.  
  19415.  The Structure of Windows
  19416.  
  19417.       When programs run under MS-DOS, they make requests of the operating
  19418.       system through MS-DOS software interrupts (such as Interrupt 21H),
  19419.       through BIOS software interrupts, or by directly accessing the machine
  19420.       hardware.
  19421.  
  19422.       When programs run under Windows, they use MS-DOS function calls only
  19423.       for file input and output and (more rarely) for executing other
  19424.       programs. Windows programs do not use MS-DOS function calls for memory
  19425.       management, keyboard input, display or printer output, or RS232
  19426.       communications. Nor do Windows programs use BIOS routines or direct
  19427.       access to the hardware.
  19428.  
  19429.       Instead, Windows provides application programs with access to more
  19430.       than 450 functions that allow programs to create and manipulate
  19431.       windows on the display; use menus, dialog boxes, and scroll bars;
  19432.       display text and graphics within the client area of a window; use the
  19433.       printer and RS232 communications port; and allocate memory.
  19434.  
  19435.  The Windows modules
  19436.  
  19437.       The functions provided by Windows are largely handled by three main
  19438.       modules named KERNEL, GDI, and USER. The KERNEL module is responsible
  19439.       for scheduling and multitasking, and it provides functions for memory
  19440.       management and some file I/O. The GDI module provides Windows'
  19441.       Graphics Device Interface functions, and the USER module does
  19442.       everything else.
  19443.  
  19444.       The USER and GDI modules, in turn, call functions in various driver
  19445.       modules that are also included with Windows. Drivers control the
  19446.       display, printer, keyboard, mouse, sound, RS232 port, and timer. In
  19447.       most cases, these driver modules access the hardware of the computer
  19448.       directly. Windows includes different driver files for various hardware
  19449.       configurations. Hardware manufacturers can also develop Windows
  19450.       drivers specifically for their products.
  19451.  
  19452.       A block diagram showing the relationships of an application program,
  19453.       the KERNEL, USER, and GDI modules, and the driver modules is shown in
  19454.       Figure 17-9. The figure shows each of these modules as a separate
  19455.       file--KERNEL, USER, and GDI have the extension .EXE; the driver files
  19456.       have the extension .DRV. Some program developers install Windows with
  19457.       these modules in separate files, as in Figure 17-9, but most users
  19458.       install Windows by running the SETUP program included with Windows.
  19459.  
  19460.       SETUP combines most of these modules into two larger files called
  19461.       WIN200.BIN and WIN200.OVL. Printer drivers are a little different from
  19462.       the other driver files, however, because the Windows SETUP program
  19463.       does not include them in WIN200.BIN and WIN200.OVL. The name of the
  19464.       driver file identifies the printer. For example, IBMGRX.DRV is a
  19465.       printer driver file for the IBM Personal Computer Graphics Printer.
  19466.  
  19467.  
  19468.                          ┌────────────┐   ┌──────────────┐
  19469.                      ┌──│            ├──│ DISPLAY.DRV  ├──Display
  19470.                      │   │            │   └──────────────┘
  19471.                      │   │  GDI.EXE   │   ┌──────────────┐
  19472.                      │ ┌│            ├──│Printer driver├──Printer
  19473.                      │ │ └────────────┘   └──────────────┘
  19474.                      │ └────────────────┐
  19475.                      │   ┌────────────┐ │
  19476.                      │   │            ├─┘
  19477.                      │   │            │   ┌──────────────┐
  19478.                      │   │            ├──│ KEYBOARD.DRV ├──Keyboard
  19479.                      │   │            │   └──────────────┘
  19480.                      │   │            │   ┌──────────────┐
  19481.                      │   │            ├──│  MOUSE.DRV   ├──Mouse
  19482.                      │   │            │   └──────────────┘
  19483.                      │   │            │   ┌──────────────┐
  19484.                      │   │            ├──│  SOUND.DRV   ├──Sound hardware
  19485.       ┌────────────┐ │   │            │   └──────────────┘
  19486.       │  Windows   ├─┘   │            │   ┌──────────────┐
  19487.       │application ├────│  USER.EXE  ├──│   COMM.DRV   ├──RS-232 hardware
  19488.       │  program   ├─┐   │            │   └──────────────┘
  19489.       └────────────┘ │   │            │   ┌──────────────┐
  19490.                      │   │            ├──│  SYSTEM.DRV  ├──Timer hardware
  19491.                      │   │            │   └──────────────┘
  19492.                      │   │            │
  19493.                      │   │            │
  19494.                      │   │            │
  19495.                      │   │            ├─┐
  19496.                      │   └────────────┘ │
  19497.                      │┌─────────────────┘
  19498.                      ││  ┌────────────┐
  19499.                      │└─│            ├──MS-DOS file I/O
  19500.                      │   │ KERNEL.EXE │
  19501.                      └──│            ├──Memory management
  19502.                          └────────────┘
  19503.  
  19504.       Figure 17-9. A simplified block diagram showing the relationships of
  19505.       an application program, Windows modules (GDI, USER, and KERNEL),
  19506.       driver modules, and system hardware.
  19507.  
  19508.  
  19509.       The diagram in Figure 17-9 is somewhat simplified. In reality, a
  19510.       Windows application program can also make direct calls to the
  19511.       KEYBOARD.DRV and SOUND.DRV modules, and USER.EXE calls the DISPLAY.DRV
  19512.       and printer driver modules directly. The GDI.EXE module and driver
  19513.       modules can also call routines in KERNEL.EXE, and drivers sometimes
  19514.       call routines in SYSTEM.DRV.
  19515.  
  19516.       Also, Figure 17-9 omits the various font files provided with Windows,
  19517.       the WIN.INI file that contains Windows initialization information and
  19518.       user preferences, and the files WINOLDAP.MOD and WINOLDAP.GRB, which
  19519.       Windows uses to run standard MS-DOS applications.
  19520.  
  19521.  Libraries and programs
  19522.  
  19523.       The USER.EXE, GDI.EXE, and KERNEL.EXE files, all driver files with the
  19524.       extension .DRV, and all font files with the extension .FON are called
  19525.       Windows libraries or, sometimes, dynamic link libraries to distinguish
  19526.       them from Windows programs. Programs and libraries both use a file
  19527.       format called the New Executable format.
  19528.  
  19529.       From the user's perspective, a Windows program and a Windows library
  19530.       are very different. The user cannot run a Windows library directly:
  19531.       Windows loads a part of a library into memory only when a program
  19532.       needs to use a function that the library provides.
  19533.  
  19534.       The user can also run multiple instances of the same Windows program.
  19535.       Windows uses the same code segments for the different instances but
  19536.       creates a unique data segment for each. Windows never runs multiple
  19537.       instances of a Windows library.
  19538.  
  19539.       From the programmer's perspective, a Windows program is a task that
  19540.       creates and manages windows on the display. Libraries are modules that
  19541.       assist the task. A programmer can write additional library modules,
  19542.       which one or more programs can use. For the developer, one important
  19543.       distinction between programs and libraries is that a Windows library
  19544.       does not have its own stack; instead, the library uses the stack of
  19545.       the program that calls the routine in the library.
  19546.  
  19547.       The New Executable format used for both programs and libraries gives
  19548.       Windows much more information about the module than is provided by the
  19549.       current MS-DOS .EXE format. In particular, the module contains
  19550.       information that allows Windows to make links between program modules
  19551.       and library modules when a program is run.
  19552.  
  19553.       When a module (such as a library) contains functions that can be
  19554.       called from another module (such as a program), the functions are said
  19555.       to be exported from the module that contains them. Each exported
  19556.       function in a module is identified either by a name (generally the
  19557.       name of the function) or by an ordinal (positive) number. A list of
  19558.